wbfc-vs-tpl-editor
v0.2.3
Published
一个基于Element UI的可视化模版编辑器框架
Readme
wbfc-vs-tpl-editor
wbfc-vs-tpl-editor是一个基于 Element UI 制作的可视化模板编辑器框架。(如果你不喜欢EL,当然也可以全部自定义UI组件) 它是由Wisea base framework cloud - visual templete editor的缩写而命名的。
它可以使用模板数据来自动生成并绑定el的表单。将数据模型驱动显示这种所见即得的功能更好的发挥。
想象一下,你可以提供一套制作好的模板给别人,他们不需要自己制作样式,制作配色,他们只要根据模板中的功能填写数据就可以得到想要的结果!这更接近真实的项目使用方案,毕竟全部动态的代码是很危险的,很容易造成XSS攻击。如果我们有现成的模板,只把数据做动态处理,就安全的多了。于是便有了本项目。
下载安装
npm install wbfc-vs-tpl-editorimport WbfcVsTplEditor from 'wbfc-vs-tpl-editor';
Vue.use(WbfcVsTplEditor);使用流程
- 制作你自己需要的vue组件
- 为该组件制作一个对应的模板
- 保存模板所需要的数据
- 完成
以上流程可以查看 Demo 或者 下载源码后 npm run dev 打开对应网页也可见到默认的demo页面
如何制作一个编辑器
在你的模板Vue文件中引入templete-binder和templete-editor(binder负责数据模型绑定,editor负责页面渲染), 模板Vue需要mixins(混入)binder。在页面中使用TempleteEditor, 绑定v-model="tplModel" :tpl-form-elems="tplFormElems", 设置tplFormElems对应的表单元素数据,然后再将editor的插槽showComponent部分写入你的插件并绑定v-model="componentModel"即可。例:
MyComponent.vue
<template>
<div>InputTextVal:{{value.textVal}}</div>
</template>
<script type="text/javascript">
export default {
name: 'MyComponent',
props: {
value: {
type: Object,
default () { return {}; }
}
}
}
</script>MyEditor.vue
<template>
<div>
<TempleteEditor :tpl-form-elems="tplFormElems" v-model="tplModel" ref="tpl">
<template v-slot:showComponent>
<MyComponent v-model="componentModel"/>
</template>
</TempleteEditor>
</div>
</template>
<script type="text/javascript">
import MyComponent from './MyComponent'
import TempleteBinder from 'wbfc-vs-tpl-editor/components/templete-binder'
import TempleteEditor from 'wbfc-vs-tpl-editor/components/templete-editor'
export default {
name: 'MyEditor',
mixins: [TempleteBinder],
components: {
TempleteEditor,
MyComponent
},
data() {
return {
tplFormElems: [{
type: 'input',
name: 'textVal',
label: 'TestTplInput',
}]
};
}
}
</script>TempleteBinder
Attributes
参数|说明|类型|必填|可选值|默认值 ---|---|---|---|---|--- tplModel|模板数据模型|Object|true|-|{} tplFormElems|模板元素列表|Array|false|-|[] componentModel|组件数据模型|Object|true|-|{}
TempleteEditor
用于渲染模板页面
Attributes
参数|说明|类型|必填|可选值|默认值 ---|---|---|---|---|--- isEdit|是否为编辑模式。true=显示组件(slot:showComponent)和表单编辑器。false=仅显示组件模板(slot:showTemplete)|boolean|否|true/false|true value|编辑器的值 可以直接设置,也可以使用v-model绑定|Object|是|-|{} tplForm|编辑器的表单属性,具体参数说明请参考 Element UI - 表单|Object|否|-|{labelWidth : '30%', bottomBtns:[]} tplFormElems|编辑器的表单元素|Array|否|-|[]
TplFormElems
参数|说明|类型|必填|可选值|默认值
---|---|---|---|---|---
group|分组 设置了group的会在编辑器侧显示分割线|TplFormElems-Group|否|-|-
elems|组元素(分组时有效,仅支持一层分组)|TplFormElems|否|-|-
type|元素类型 默认为输入框 custom为自定义元素,可以通过该元素的插槽 v-slot:"form_item_" + name 进行自定义替换 |String|否|input/hidden/radio/radio-group/checkbox/checkbox-group/select/cascader/switch/slider/time-select/time-picker/date-picker/date-time-picker/rate/color-picker/transfer/custom 父元素.type = radio-group / checkbox-group时,子元素.type = radio-button/checkbox-button 有效|input
name|元素名称 默认会按照name映射绑定组件模型 例:{name:'textVal'} 将会绑定 TempleteBinder.componentModel.textVal|String|是|-|-
bind|绑定名称 若带有'.'则会绝对匹配,不带'.'则会相对匹配 例:{name:'textVal', bind: 'act'} 将会绑定 TempleteBinder.componentModel.act.textVal {name:'textVal', bind: 'act.text'} 将会绑定 TempleteBinder.componentModel.act.text|String|否|-|-
label|元素显示标签|String|否|-|-
visible|元素是否显示 String会按照表达式处理 可以指定为模型的其他属性 例: tplFormElems = [{type: 'switch', name:'textFlag', label:'开关', defVal: true}, {name:'textVal', label:'文字显示联动开关属性', visible: 'textFlag'}]|[String:expression]/boolean/function|否|-|true
defVal|元素默认值 如果模型(value)不指定默认值,也可以通过tplFormElems的这个属性设置|Object|否|-|-
formItemAttrs|表单项属性 EL组件具体参数说明请参考 Element UI|Object|否|-|-
notMapping|编辑器表单组件模型值不需要映射到显示组件component中|boolean|否|true/false|false
attrs|元素属性 EL组件具体参数说明请参考 Element UI|Object|否|-|-
events|元素事件|Object|否|请参考HTML的基础事件和自定义事件|-
items|子元素列表 type=radio/radio-group/checkbox-group/select 时有效|TplFormElems|否|-|-
text| 子元素显示标签 type=radio/radio-group/checkbox/checkbox-group/ 时有效|String|否|-|-
helps|元素帮助文档|String|否|-|-
helpsType|元素帮助文档类型 如果填写为md 则会使用mavon-editor作为显示器 此时helps可以写为markdown格式文档|String|否|md|-
autoBind|自动绑定模型|boolean|否|true/false|true
bindType|绑定类型 当autoBind=false时必填|String|否|'static'/'dynamic'|-
bindFunc|自定义绑定函数 当autoBind=false时,bindType != 'static'/'dynamic'时必填|function|否|-|-
invisibleNoBindType|不显示时的绑定模式 all-既删除表单模型也删除组件模型 holdTplModel-只删除组件模型|String|否|all/holdTplModel,|all
slots|插槽列表 默认插槽["xxx"\] 具名插槽[{name:'xid', ....}]|Array|否|-|-
TplFormElems-Group
参数|说明|类型|必填|可选值|默认值
---|---|---|---|---|---
name|分组的标识|String|是|-|null
label|分组的文字显示,会在分割线正中间显示的提示文字|String|是|-|null
visible|分组是否显示(如果该项为false,其组内子项也不会显示)|boolean|否|true/false|true
invisibleNoBindType|不显示时的绑定模式 all-既删除表单模型也删除组件模型 holdTplModel-只删除组件模型|String|否|all/holdTplModel,|all
TplFormElems-slots
参数|说明|类型|必填|可选值|默认值
---|---|---|---|---|---
name|具名插槽使用的名称,如果不填就是默认的default插槽|String|否|-|-
component|组件 {template: ''} 模板字符串对应<template>节点 详情参考Vue.js|new Vue()|否|-|-
params|组件的数据对象 详情参考Vue.js - createElement-参数|Object|否|-|-
VNodes|组件的子节点 一般为默认的插槽(this.$slots.default) 详情参考Vue.js - 完整示例|Object|否|-|-
TempleteEditor - Methods
函数名|说明|参数|示例 ---|---|---|--- addTplFormElems|添加一个tplFormElems的节点|item(一个节点), model(默认模型值)|vm.addTplFormElems({type: 'input', name: 'test', label:'测试输入框', bind: 'wbfc.test'}, '测试字符串'); deleteElem|删除一个tplFormElems的节点|elem(节点), groupElem(elem的父节点,没有填为null))|vm.deleteElem({type: 'input', name: 'test', label:'测试输入框', bind: 'wbfc.test'}) removeWatch|移除模型绑定|elem(节点非group), holeModelVal(是否保留表单模型值)|vm.removeWatch({type: 'input', name: 'test', label:'测试输入框', bind: 'wbfc.test'})
TempleteEditor - Slotes
插槽名|说明|参数
---|---|---
showTemplete|非编辑模式下显示的组件|-
showComponent|编辑模式下显示的组件|-
'form_group_' + name|分组模块的头分割线|data:tplFormElems[index]
'form_group_' + name + '_bottom'|分组模块的尾分割线 默认不显示|data:tplFormElems[index]
'bottomBtns_' + index|编辑器最底部按钮|data:bottomBtns
'form_item_' + name|元素组件|data:TplFormElems[index]
'form_item_label_' + name|元素标签|data:TplFormElems[index]
自定义组件
在一些更为复杂的页面中,可能el提供的这些UI组件无法满足你的需求,这样的情况可以使用自定义组件。自定义组件分为:全局组件、编辑器全局组件、局部组件和局部完全自定义组件。
全局组件
直接可以使用Vue原生的全局组件设置Vue.component('component-a', { /* ... */ }) 详细文档请参考 Vue 组件注册
编辑器全局组件
这种组件是在TempleteEditor标签**包裹的范围内均可以使用**的全局组件。你可以在加载wbfc-vs-tpl-editor前,用use函数注册这些组件。组件要包裹在components下 例: {components: {你import的组件名}}
import WbfcVsTplEditor from 'wbfc-vs-tpl-editor';
import testComp from '../components/testComp';
Vue.use(WbfcVsTplEditor, {
components: {
testComp
}
});
局部组件
通常的场景下,局部组件的使用场景最多。这种组件只在当前页面和当前页面的TempleteEditor包裹的TplFormElems元素下生效。你需要在自己的页面中使用import,然后再在覆盖beforeCreate函数中使用Vue.$formItemComponentsManager.addComponent({组件名});。
<template>
<div>
<TempleteEditor :tpl-form-elems="tplFormElems" v-model="tplModel" ref="tpl" :childComp="childComp">
<template v-slot:showComponent>
<MyComponent v-model="componentModel" />
</template>
</TempleteEditor>
</div>
</template>
<script type="text/javascript">
import Vue from 'vue'
import MyComponent from './MyComponent'
import TempleteBinder from '../src/components/templete-binder'
import TempleteEditor from '../src/components/templete-editor'
import test2 from './test2'
export default {
name: 'MyEditor',
mixins: [TempleteBinder],
components: {
TempleteEditor,
MyComponent,
},
beforeCreate(){
Vue.$formItemComponentsManager.addComponent({test2});
}
...
}局部完全自定义组件
当TplFormElems[index].type = 'custom'时,编辑器表单的元素渲染会变成完全自定义的模式,在这样的模式下,必须使用对应的插槽'form_item_' + name才能正确的渲染出结果。_这种组件通常会在只有一个功能使用到了,没有必要制作一个组件的情况下使用__。
<template>
<div>
<TempleteEditor :tpl-form-elems="tplFormElems" v-model="tplModel" ref="tpl" :childComp="childComp">
<template v-slot:showComponent>
<MyComponent v-model="componentModel" />
</template>
<template v-slot:form_item_bgColor="sc">
<div class="color-schemes-line">
<div class="color-schemes-line-text">
<span>{{sc.data.attrs.text}}</span>
</div>
<el-color-picker v-model="tplModel.bgColor"></el-color-picker>
</div>
</template>
</TempleteEditor>
</div>
</template>
<script type="text/javascript">
import Vue from 'vue'
import MyComponent from './MyComponent'
import TempleteBinder from '../src/components/templete-binder'
import TempleteEditor from '../src/components/templete-editor'
export default {
name: 'MyEditor',
mixins: [TempleteBinder],
components: {
TempleteEditor,
MyComponent,
},
data() {
return {
tplFormElems: [{
type: 'custom',
name: 'bgColor',
label: '局部',
attrs:{
text: '完全自定义组件'
}
}]
};
},
...
}
特有组件库
link-editor 链接编辑器
它是一个弹出层式的表单交互式组件,必须在弹出的对话框点击确定按钮时手动处理value。当编辑器元素中包含有链接,可以直接使用链接编辑器组件。它必须要实现一个submitDialog函数,用来处理对话框关闭时的操作,一般这个函数可以做编辑器中组件的回显,如果需要默认值,只要实现events的open事件,调用setValue函数即可。
export default {
data() {
return {
tplFormElems: [{
type: 'link-editor',
name: 'linkVal',
label: '链接',
defVal: {href: 'https://github.com/xudl33/wbfc-vs-tpl-editor', label: '链接文字', target: '_blank'},
attrs: {
submitDialog: (val) => {
// 回显
this.$set(this.tplModel, 'linkVal', val);
}
},
events:{
open: (e, linkEditor) => {
// 默认赋值
linkEditor.setValue(this.tplModel.linkVal);
}
}
}]
};
},
...
}Attributes
参数|说明|类型|必填|可选值|默认值
---|---|---|---|---|---
dialogProps|编辑对话框属性 具体参数请参考 Element UI Dialog|Object|false|-|{width: '40%'}
editorView|编辑器链接属性 它会映射为编辑器的表单元素显示出来 具体参数请参考 Element UI Link|Object|false|-|{type: 'primary', underline: false, href: '#'}
viewLabel|编辑器链接文字|String|false|-|'编辑'
dialogTitle|编辑对话框标题 (独立属性,即使设置了dialogProps.title也无效)|String|false|-|'-编辑链接-'
propMapping|编辑器表单映射 默认的表单属性为{label: '显示文字', href: '超链接', target: '跳转类型'} 如果你的模型并不是这种结构,可以设置该项进行映射转换|Object|false|-|{label: 'label',href: 'href',target: 'target'}
defVal|表单默认值 每次弹出对话框时的初始值,它只是一个Object,不会直接绑定到编辑器模型中,如果需要从编辑器模型中传递默认值,必须要实现open事件,再调用setValue函数手动赋值|Object|false|-|{}
formProps|编辑器表单属性 Element UI - 表单|Object|false|-|{rules: {label: [{ required: true, message: '请输入显示文字', trigger: 'blur' }],href: [{ required: true, message: '请输入链接', trigger: 'blur' }],target: [{ required: true, message: '请选择跳转类型', trigger: 'blur' }]}}
submitDialog|对话框点击确定按钮的回调函数 必须通过改函数手动处理编辑器表单值的对应关系|Function|true|-|() => {}
Slotes
插槽名|说明|参数 ---|---|--- view-label|显示文字|linkEditor:this footer|底部按钮|linkEditor:this
propMapping 编辑器表单映射
export default {
data() {
return {
tplFormElems: [{
type: 'link-editor',
name: 'linkVal',
label: '链接',
defVal: {link: 'https://github.com/xudl33/wbfc-vs-tpl-editor', text: '链接文字', type: '_blank'},
attrs: {
propMapping: { // 不是默认结构的数据,需要对表单进行映射转换
href: 'link',
label: 'text',
target: 'type'
}
},
events:{
open: (e, linkEditor) => {
// 默认赋值
linkEditor.setValue(this.tplModel.linkVal);
}
}
}]
};
},
...
list-sort-editor 列表排序编辑器
它是一个可以直接对列表进行排序操作的编辑器。默认四个按钮,【向上移动】【向下移动】【移动到最前】【移动到最后】。它不是默认的编辑器全局组件,使用前需要import到你的vue中。
<template>
<div>
<el-table ref="multipleTable" :data="tplModel.categoryList" style="width:100%">
<el-table-column type="index">
</el-table-column>
<el-table-column prop="text" label="分类名">
</el-table-column>
<el-table-column label="排序">
<template slot-scope="scope">
<ListSortEditor v-model="tplModel.categoryList" :index="scope.$index"/>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script type="text/javascript">
import ListSortEditor from 'wbfc-vs-tpl-editor/components/list-sort-editor'
export default {
components: {
ListSortEditor,
},
data:{
return {
tplModel: {
categoryList: [{
text: '分类1',
href: '/'
},
{
text: '分类2',
href: '/'
},
{
text: '分类3',
href: '/'
},
{
text: '分类4',
href: '/'
},
{
text: '分类5',
href: '/'
}
]
}
};
}
...
}
</script>Attributes
参数|说明|类型|必填|可选值|默认值 ---|---|---|---|---|--- value|需要排序的列表|Array|true|-|- index|当前数据的索引值,上下排序是会根据索引值计算,因此必须为大于等于0的正数,一般会传入列表的index属性,详情可以参考示例。|int|true|+[0-Number.MAX_SAFE_INTEGER]|- btns|排序按钮|Object|false|-|{up: {type: 'text',icon: 'el-icon-arrow-up',title: '向上移动',enabled: true},down: {type: 'text',title: '向下移动',icon: "el-icon-arrow-down",enabled: true},top: {type: 'text',title: '移动到最前',icon: "el-icon-top",enabled: true},bottom: {type: 'text',title: '移动到最后',icon: "el-icon-bottom",enabled: true}} loop|是否循环排序 默认列表的第一个点击【向上移动】不会有效果,列表的最后一个点击【向下移动】也不会有效果。 如果开启该项,列表的第一个点击【向上移动】会变成最后一个,列表的最后一个点击【向下移动】会变成第一个|Boolean|false|true/false|false
btns
参数|说明|类型|必填|可选值|默认值 ---|---|---|---|---|--- type|按钮类型 具体参数请参考 Element UI Button|String|true|-|text icon|按钮图标 具体参数请参考 Element UI Icon|String|true|-|- title|按钮鼠标悬停提示|String|false|-|- enabled|按钮是否可用 如果为false则该按钮不可见|Boolean|true|true/false|true
Slotes
插槽名|说明|参数 ---|---|--- up|向上移动|index:index down|向下移动|index:index top|移动到最前|index:index bottom|移动到最后|index:index
事件
参数|说明 ---|--- change|四个按钮,【向上移动】【向下移动】【移动到最前】【移动到最后】中的任何一个按钮执行操作后,均会触发change事件。
不显示按钮
设置btns属性可以控制按钮是否可见。例: 不显示【移动到最前】【移动到最后】两个按钮。
<template>
<div>
<el-table ref="multipleTable" :data="tplModel.categoryList" style="width:100%">
<el-table-column type="index">
</el-table-column>
<el-table-column prop="text" label="分类名">
</el-table-column>
<el-table-column label="排序">
<template slot-scope="scope">
<ListSortEditor v-model="tplModel.categoryList" :index="scope.$index" :btns="{top:{enabled:false}, bottom:{enabled:false}}"/>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script type="text/javascript">
import ListSortEditor from 'wbfc-vs-tpl-editor/components/list-sort-editor'
export default {
components: {
ListSortEditor,
}
...
}
</script>自定义按钮
在一些特殊场合下,默认的样式并不能满足需求,这时可以自定义操作按钮。例:自定义【向上移动】和【向下移动】同时不显示【移动到最前】【移动到最后】两个按钮。
<template>
<div>
<el-table ref="multipleTable" :data="tplModel.categoryList" style="width:100%">
<el-table-column type="index">
</el-table-column>
<el-table-column prop="text" label="分类名">
</el-table-column>
<el-table-column label="排序">
<template slot-scope="scope">
<ListSortEditor v-model="tplModel.categoryList" :index="scope.$index" :btns="{top:{enabled:false}, bottom:{enabled:false}}">
<template v-slot:up="sc">
<div><span>UP</span></div>
</template>
<template v-slot:down="sc">
<div><span>DOWN</span></div>
</template>
</ListSortEditor>
</template>
</el-table-column>
</el-table>
</div>
</template>
<script type="text/javascript">
import ListSortEditor from 'wbfc-vs-tpl-editor/components/list-sort-editor'
export default {
components: {
ListSortEditor,
}
...
}
</script>Build Setup
# install dependencies
npm install
# serve with hot reload at localhost:8080
npm run dev
# build for production with minification
npm run build
# build for production and view the bundle analyzer report
npm run build --reportFor a detailed explanation on how things work, check out the guide and docs for vue-loader.
