vjdesign 是一个具有高扩展性的动态表单设计器,本示例实现一个自定以属性编辑器例子
说明
自定义组件
首先做一个 vue 自定义组件
Vue.component("custom-number", {
template: `<div><button type="button" @click="mut">-</button> {{value}} <button type="button" @click="plus">+</button></div>`,
props: { value: Number, default: 0 },
methods: {
plus() {
this.$emit("input", (this.value || 0) + 1);
},
mut() {
this.$emit("input", Math.max((this.value || 0) - 1, 0));
}
}
});
editor 方法用于注册属性编辑器,第一个参数就是设计器配置文件中 editor 要设置的值
然后定义一个属性编辑器,是一个方法返回一个对象,该对象的定义方法同 jformer 里定义一样也是动态表单组件的定义,component 是组件名这里使用刚才定义的组件, 参数传递了一个 path,这个 path 就是组件在设计器编辑的时候正在编辑的属性名,将这个 path 设置到组件数据 model 上实现更新组件相应属性
window.vjdesign.default.use(({ editor }) => {
editor("customNumber", (path) => {
return {
component: "custom-number",
model: [path]
};
});
});
在配置文件中组件属性上使用自定义的属性编辑器
{
name: "el-row",
label: "行",
group: "element",
properties: [
{
name: "fieldOptions.props.gutter",
label: "间隔",
group: "组件",
// 这里就是注册的属性编辑器名称
editor: "customNumber"
}
],
designer: "classContainer"
}
要想使用自定义组件或第三方组件作为属性编辑器,在 vue 项目中要先引用这个组件
使用已有组件并传递参数
实现将 el-silder 作为属性编辑器,并传递参数限制值的范围和步长
首先定义一个组件属性编辑器并注册,除了 path 参数,options 是配置文件里定义的额外配置信息,通常作为编辑器组件属性
window.vjdesign.default.use(({ editor }) => {
editor("elSilder", (path, options) => {
return {
component: "el-slider",
model: [path],
fieldOptions: { props: options }
};
});
});
设计器配置文件里使用这个属性编辑器
{
name: "el-col",
label: "列",
group: "element",
properties: [
{
name: "fieldOptions.props.span",
label: "列宽",
group: "组件",
default: 12,
editor: {
// 属性编辑器名称
name: "elSilder",
// 属性编辑器属性
options: { step: 1, min: 1, max: 24 }
}
}
],
designer: "classContainer"
}
完整示例
html 页
直接将以下实现存成 html 就可以查看效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Static Template</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/vjdesign"></script>
<script src="https://cdn.jsdelivr.net/npm/element-ui/lib/index.js"></script>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/vjdesign/dist/vjdesign.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/element-ui/lib/theme-chalk/index.css"
/>
<style>
html {
font-size: 14px;
}
#app {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
</style>
</head>
<body>
<div id="app">
<v-jdesign v-model="config" v-bind:profile="profile"></v-jdesign>
</div>
<script>
const Vue = window.Vue;
Vue.component("custom-number", {
template: `<div><button type="button" @click="mut">-</button> {{value}} <button type="button" @click="plus">+</button></div>`,
props: { value: Number, default: 0 },
methods: {
plus() {
this.$emit("input", (this.value || 0) + 1);
},
mut() {
this.$emit("input", Math.max((this.value || 0) - 1, 0));
}
}
});
window.vjdesign.default.use(({ editor }) => {
editor("customNumber", (path) => {
return {
component: "custom-number",
model: [path]
};
});
editor("elSilder", (path, options) => {
return {
component: "el-slider",
model: [path],
fieldOptions: { props: options }
};
});
});
new Vue({
data() {
return {
config: {
datasource: {},
listeners: [],
fields: [
{
component: "div",
children: [
{
component: "el-row",
children: [
{
component: "el-col",
fieldOptions: {
props: {
span: 10
}
}
},
{
component: "el-col",
fieldOptions: {
props: {
span: 12
}
}
},
{
component: "el-col",
fieldOptions: {
props: {
span: 12
}
}
},
{
component: "el-col",
fieldOptions: {
props: {
span: 16
}
}
}
]
}
]
}
],
model: {}
},
profile: {
components: [
{
name: "el-row",
label: "行",
group: "element",
properties: [
{
name: "fieldOptions.props.gutter",
label: "间隔",
group: "组件",
editor: "customNumber"
}
],
designer: "classContainer"
},
{
name: "el-col",
label: "列",
group: "element",
properties: [
{
name: "fieldOptions.props.span",
label: "列宽",
group: "组件",
default: 12,
editor: {
name: "elSilder",
options: { step: 1, min: 1, max: 24 }
}
}
],
designer: "classContainer"
}
]
}
};
}
}).$mount("#app");
</script>
</body>
</html>