阅读之前
你应该:
- 了解自定义组件相关内容。
弹出层组件
我们内置了两个弹出层组件,弹窗(Dialog)
和抽屉(Drawer)
,以下所有内容全部围绕弹窗(Dialog)
进行描述,抽屉相关内容与弹窗完全一致。
下面这个对照表格可以帮助你区分两个弹出层组件的异同:
弹出层相关功能 | 弹窗(Dialog) | 抽屉(Drawer) |
---|---|---|
API方法 | Dialog#create | Drawer#create |
内置组件 | DialogWidget | DrawerWidget |
内置插槽 | header, default, footer | header, default, footer |
渲染弹出层的方式
我们提供了三种渲染弹出层组件的方式,根据不同的情况使用不同的方式可以让实现变得更简单。
- 使用
Dialog#create
API方法创建弹窗:一般用于简单场景,动作区无法进行自定义。 - 使用
DSL渲染能力
创建弹窗- 调用
ActionWidget#click
方法打开弹窗(适用于自动渲染场景) - 使用
createWidget
创建DialogWidget
并打开弹窗(适用于手动渲染场景)
- 调用
- 使用第三方组件创建弹窗:一般用于弹窗需要自定义的场景中,性能最优,可用于任何场景。
使用Dialog#create
API方法创建弹窗
以下是一个自定义组件的完整示例,其使用ViewCache#compule
方法获取视图。
view.ts
export const template = `<view>
<field data="id" invisible="true" />
<field data="code" label="编码" />
<field data="name" label="名称" />
</view>`;
ManualDemoWidget.ts
import {
BaseElementWidget,
createRuntimeContextForWidget,
Dialog,
FormWidget,
MessageHub,
RuntimeView,
SPI,
ViewCache,
ViewType,
Widget
} from '@kunlun/dependencies';
import ManualDemo from './ManualDemo.vue';
import { template } from './view';
@SPI.ClassFactory(BaseElementWidget.Token({ widget: 'ManualDemo' }))
export class ManualDemoWidget extends BaseElementWidget {
public initialize(props) {
super.initialize(props);
this.setComponent(ManualDemo);
return this;
}
@Widget.Method()
public async openPopup() {
// 获取运行时视图
const view = await this.fetchViewByCompile();
if (!view) {
console.error('Invalid view');
return;
}
// 创建运行时上下文
const runtimeContext = createRuntimeContextForWidget(view);
const runtimeContextHandle = runtimeContext.handle;
// 获取初始化数据
const formData = await runtimeContext.getInitialValue();
// 创建弹窗
const dialogWidget = Dialog.create();
// 设置弹窗属性
dialogWidget.setTitle('这是一个演示弹窗');
// 创建所需组件
dialogWidget.createWidget(FormWidget, undefined, {
metadataHandle: runtimeContextHandle,
rootHandle: runtimeContextHandle,
dataSource: formData,
activeRecords: formData,
template: runtimeContext.viewTemplate,
inline: true
});
dialogWidget.on('ok', () => {
MessageHub.info('click ok');
// 关闭弹窗
dialogWidget.onVisibleChange(false);
});
dialogWidget.on('cancel', () => {
MessageHub.info('click cancel');
// 关闭弹窗
dialogWidget.onVisibleChange(false);
});
// 打开弹窗
dialogWidget.onVisibleChange(true);
}
public async fetchViewByCompile(): Promise<RuntimeView | undefined> {
// 模型编码
const model = ${model};
// 通过编译获取视图(非完整视图数据)
const view = await ViewCache.compile(model, '$$popup_demo', template);
if (!view) {
return;
}
// 补充视图类型
view.type = ViewType.Form;
return view;
}
}
ManualDemo.vue
<template>
<div class="manual-demo">
<oio-button @click="openPopup">打开弹窗</oio-button>
</div>
</template>
<script lang="ts">
import { OioButton } from '@kunlun/vue-ui-antd';
import { defineComponent } from 'vue';
export default defineComponent({
name: 'ManualDemo',
components: {
OioButton
},
props: {
openPopup: {
type: Function
}
}
});
</script>
视图DSL
<view type="FORM">
<template slot="form">
<field data="id" invisible="true" />
<field data="code" />
<field data="name" />
<element widget="ManualDemo" />
</template>
</view>
关键点详解
......
使用DSL渲染能力创建弹窗(调用ActionWidget#click方法)
以下是一个自定义组件的完整示例,视图被定义在DSL模板中。
ManualDemoWidget.ts
import { ActionWidget, BaseElementWidget, DslDefinitionWidget, SPI, Widget } from '@kunlun/dependencies';
import ManualDemo from './ManualDemo.vue';
@SPI.ClassFactory(BaseElementWidget.Token({ widget: 'ManualDemo' }))
export class ManualDemoWidget extends BaseElementWidget {
public initialize(props) {
super.initialize(props);
this.setComponent(ManualDemo);
return this;
}
@Widget.Method()
public async openPopup() {
const actionWidget = this.getChildren().find((v) => {
if (v instanceof DslDefinitionWidget) {
const slotName = v.getSlotName();
if (slotName === 'popupAction' && v instanceof ActionWidget) {
return v;
}
}
return false;
}) as ActionWidget;
if (actionWidget) {
await actionWidget.click();
actionWidget.forceUpdate();
}
}
}
ManualDemo.vue
<template>
<div class="manual-demo">
<oio-button @click="openPopup">打开弹窗</oio-button>
<div style="display: none">
<slot name="popupAction" />
</div>
</div>
</template>
<script lang="ts">
import { OioButton } from '@kunlun/vue-ui-antd';
import { defineComponent } from 'vue';
export default defineComponent({
name: 'ManualDemo',
components: {
OioButton
},
props: {
openPopup: {
type: Function
}
}
});
</script>
视图DSL
<view type="FORM">
<template slot="form">
<field data="id" invisible="true" />
<field data="code" />
<field data="name" />
<element widget="ManualDemo">
<template slot="popupAction">
<action name="$$popup_action_demo" actionType="VIEW" contextType="CONTEXT_FREE" target="DIALOG" resModel="${model}">
<template slot="default" title="这是一个演示弹窗">
<view type="FORM">
<template slot="actionBar">
<action name="$$internal_DialogCancel" type="default" />
<action name="create" />
</template>
<template slot="form">
<field data="id" invisible="true" />
<field data="code" />
<field data="name" />
</template>
</view>
</template>
</action>
</template>
</element>
</template>
</view>
关键点详解
......
使用DSL渲染能力创建弹窗(创建DialogWidget
组件)
以下是一个自定义组件的完整示例,其使用ViewCache#compule
方法获取视图,该视图对应的是弹窗组件的渲染模板。
view.ts
export const template = `<view title="这是一个演示弹窗">
<template slot="default">
<view type="FORM">
<element widget="form">
<field data="id" invisible="true" />
<field data="code" />
<field data="name" />
</element>
</view>
</template>
<template slot="footer">
<element widget="actionBar">
<action name="$$internal_DialogCancel" type="default" />
<action name="create" />
</element>
</template>
</view>`;
ManualDemoWidget.ts
import {
BaseElementWidget,
createRuntimeContextForWidget,
DialogWidget,
RuntimeView,
SPI,
ViewCache,
ViewType,
Widget
} from '@kunlun/dependencies';
import ManualDemo from './ManualDemo.vue';
import { template } from './view';
@SPI.ClassFactory(BaseElementWidget.Token({ widget: 'ManualDemo' }))
export class ManualDemoWidget extends BaseElementWidget {
public initialize(props) {
super.initialize(props);
this.setComponent(ManualDemo);
return this;
}
@Widget.Method()
public async openPopup() {
// 获取运行时视图
const view = await this.fetchViewByCompile();
if (!view) {
console.error('Invalid view');
return;
}
// 创建运行时上下文
const runtimeContext = createRuntimeContextForWidget(view);
const runtimeContextHandle = runtimeContext.handle;
// 获取初始化数据
const formData = await runtimeContext.getInitialValue();
const dialogWidget = this.createWidget(new DialogWidget(), 'popupWidget', {
metadataHandle: runtimeContextHandle,
rootHandle: runtimeContextHandle,
dataSource: formData,
activeRecords: formData,
template: runtimeContext.viewTemplate,
inline: true,
mountedVisible: true
});
dialogWidget.on('ok', async () => {
dialogWidget.onVisibleChange(false);
});
dialogWidget.on('cancel', () => {
dialogWidget.onVisibleChange(false);
});
this.forceUpdate();
}
public async fetchViewByCompile(): Promise<RuntimeView | undefined> {
// 模型编码
const model = ${model};
// 通过编译获取视图(非完整视图数据)
const view = await ViewCache.compile(model, '$$popup_demo', template);
if (!view) {
return;
}
// 补充视图类型
view.type = ViewType.Form;
return view;
}
}
ManualDemo.vue
<template>
<div class="manual-demo">
<oio-button @click="openPopup">打开弹窗</oio-button>
<div style="display: none">
<slot name="popupWidget" />
</div>
</div>
</template>
<script lang="ts">
import { OioButton } from '@kunlun/vue-ui-antd';
import { defineComponent } from 'vue';
export default defineComponent({
name: 'ManualDemo',
components: {
OioButton
},
props: {
openPopup: {
type: Function
}
}
});
</script>
视图DSL
<view type="FORM">
<template slot="form">
<field data="id" invisible="true" />
<field data="code" />
<field data="name" />
<element widget="ManualDemo" />
</template>
</view>
关键点详解
......
使用第三方组件创建弹窗
以下是一个自定义组件的完整示例,其使用ViewCache#compule
方法获取视图。
view.ts
export const template = `<view>
<field data="id" invisible="true" />
<field data="code" label="编码" />
<field data="name" label="名称" />
</view>`;
ManualDemoWidget.ts
import {
BaseElementWidget,
createRuntimeContextForWidget,
FormWidget,
MessageHub,
RuntimeView,
SPI,
ViewCache,
ViewType,
Widget
} from '@kunlun/dependencies';
import ManualDemo from './ManualDemo.vue';
import { template } from './view';
@SPI.ClassFactory(BaseElementWidget.Token({ widget: 'ManualDemo' }))
export class ManualDemoWidget extends BaseElementWidget {
private formWidget: FormWidget | undefined;
public initialize(props) {
super.initialize(props);
this.setComponent(ManualDemo);
return this;
}
@Widget.Method()
public async openPopup(): Promise<void> {
// 获取运行时视图
const view = await this.fetchViewByCompile();
if (!view) {
console.error('Invalid view');
return;
}
// 销毁旧组件
this.formWidget?.dispose();
this.formWidget = undefined;
// 创建运行时上下文
const runtimeContext = createRuntimeContextForWidget(view);
const runtimeContextHandle = runtimeContext.handle;
// 获取初始化数据
const formData = await runtimeContext.getInitialValue();
// 创建所需组件
this.formWidget = this.createWidget(FormWidget, 'formWidget', {
metadataHandle: runtimeContextHandle,
rootHandle: runtimeContextHandle,
dataSource: formData,
activeRecords: formData,
template: runtimeContext.viewTemplate,
inline: true
});
this.forceUpdate();
}
@Widget.Method()
public onEnter() {
MessageHub.info('click ok');
return true;
}
@Widget.Method()
public onCancel() {
MessageHub.info('click cancel');
return true;
}
public async fetchViewByCompile(): Promise<RuntimeView | undefined> {
// 模型编码
const model = ${model};
// 通过编译获取视图(非完整视图数据)
const view = await ViewCache.compile(model, '$$popup_demo', template);
if (!view) {
return;
}
// 补充视图类型
view.type = ViewType.Form;
return view;
}
}
ManualDemo.vue
<template>
<div class="manual-demo">
<oio-button @click="openModal">打开弹窗</oio-button>
<oio-modal v-model:visible="visible" title="这是一个演示弹窗" :enter-callback="onEnter" :cancel-callback="onCancel">
<slot name="formWidget" />
</oio-modal>
</div>
</template>
<script lang="ts">
import { ManualWidget } from '@kunlun/dependencies';
import { OioButton, OioModal } from '@kunlun/vue-ui-antd';
import { defineComponent, nextTick, ref } from 'vue';
export default defineComponent({
name: 'ManualDemo',
mixins: [ManualWidget],
components: {
OioButton,
OioModal
},
props: {
openPopup: {
type: Function
},
onEnter: {
type: Function
},
onCancel: {
type: Function
}
},
setup(props) {
const visible = ref(false);
const openModal = async () => {
await props.openPopup?.();
nextTick(() => {
visible.value = true;
});
};
return {
visible,
openModal
};
}
});
</script>
视图DSL
<view type="FORM">
<template slot="form">
<field data="id" invisible="true" />
<field data="code" />
<field data="name" />
<element widget="ManualDemo" />
</template>
</view>
关键点详解
......
Oinone社区 作者:nation原创文章,如若转载,请注明出处:https://doc.oinone.top/frontend/42.html
访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验