热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

vue+elementUI实现自定义表单模板组件(一)

前言如下图,实现一个可以自定义的表单。本文以实现思路为主,并未提供完整代码。思路1、页面布局为左中右布局:左边显示可以定义的表单控件&

前言

如下图,实现一个可以自定义的表单。本文以实现思路为主,并未提供完整代码。

在这里插入图片描述


思路

1、页面布局为左中右布局:左边显示可以定义的表单控件,中间显示预览效果,右边则为选中某个控件后可以编辑的属性。如下图,先择单选项后,可以编辑选项。

在这里插入图片描述

2、使用 vuedraggable 拖拽组件,直接拖动左边的控件到中间生成表单。vuedraggable 文档可查阅:
https://github.com/SortableJS/Vue.Draggable

(你也可以不使用该组件,直接利用点击事件,点击左边控件后在中间生成表单)


主要实现

以文本和选项为例,其他控件可自行拓展。

html 部分

<template><div><el-row :gutter&#61;"20"><el-col :span&#61;"3"><h4>基础控件h4><draggable :options&#61;"dragOptions" v-model&#61;"compList" &#64;end&#61;"end1" :move&#61;"onMove1"><div v-for&#61;"(item, index) in compList" :key&#61;"index" class&#61;"comp-item pointer"><i :class&#61;"item.icon">i>{{item.label}}div>draggable>el-col><el-col :span&#61;"16" style&#61;"border-left:1px solid #DCDFE6;border-right:1px solid #DCDFE6"><el-row><el-col :span&#61;"12"><h4>表单内容h4>el-col>el-row><template v-if&#61;" 0 &#61;&#61; (formList &&formList.length)"><divstyle&#61;"line-height: 50px;height: 50px;border: 1px dashed #d9d9d9;padding-left:20px;margin-top:10px">拖动左边的控件进行自定义字段编辑div>template><draggablestyle&#61;"height:calc(100vh - 220px);overflow-y:auto"group&#61;"comp"v-model&#61;"formList"&#64;start&#61;"start2"&#64;end&#61;"end2":move&#61;"onMove2"><divclass&#61;"temp-content"&#64;click&#61;"activeIndex&#61;index":class&#61;"activeIndex&#61;&#61;index?&#39;temp-active&#39;:&#39;&#39;"v-for&#61;"(item, index) in formList":key&#61;"index"><div style&#61;"padding:10px"><el-row><el-col :span&#61;"20"><inputplaceholder&#61;"请输入字段标题&#xff0c;8个字内"maxlength&#61;"8"v-model&#61;"item.label"style&#61;"border:none;width:100%;outline: none;"/>el-col><el-col :span&#61;"3" class&#61;"text-right pointer"><template v-if&#61;"activeIndex&#61;&#61;index"><i class&#61;"el-icon-delete text-red" title&#61;"删除" &#64;click.stop&#61;"delItem(index)">i>template>el-col>el-row>div><div><template v-if&#61;"item.type&#61;&#61;&#39;radio&#39;"><el-radio-group disabled><el-radio v-for&#61;"(it, idx) in item.options" :key&#61;"idx" :label&#61;"idx">{{it}}el-radio>el-radio-group>template><template v-else-if&#61;"item.type&#61;&#61;&#39;checkbox&#39;"><el-checkbox-group disabled><el-checkbox v-for&#61;"(it, idx) in item.options" :key&#61;"idx" :label&#61;"idx">{{it}}el-checkbox>el-checkbox-group>template><template v-else><el-input disabled :placeholder&#61;"item.placeholder?item.placeholder:&#39;待填写者输入&#39;">el-input>template>div>div>draggable>el-col><el-col :span&#61;"5"><template v-if&#61;"formList&&formList.length>0"><h4><i :class&#61;"formList[activeIndex].icon">i>{{formList[activeIndex].typeName}}h4><el-form style&#61;"margin-top:10px" label-suffix&#61;"&#xff1a;"><el-form-item label&#61;"标题"><el-input v-model&#61;"formList[activeIndex].label">el-input>el-form-item><templatev-if&#61;"formList[activeIndex].type !&#61; &#39;radio&#39; && formList[activeIndex].type !&#61; &#39;checkbox&#39; && formList[activeIndex].type !&#61; &#39;file&#39; && formList[activeIndex].type !&#61; &#39;rate&#39; "><el-form-item label&#61;"提示文字"><el-input v-model&#61;"formList[activeIndex].placeholder">el-input>el-form-item>template><templatev-if&#61;"formList[activeIndex].type &#61;&#61; &#39;radio&#39; || formList[activeIndex].type &#61;&#61; &#39;checkbox&#39;"><el-form-item label&#61;"选项"><el-rowstyle&#61;"margin-top:10px"v-for&#61;"(item, index) in formList[activeIndex].options":key&#61;"index"><el-col :span&#61;"22"><el-input v-model&#61;"formList[activeIndex].options[index]">el-input>el-col><el-col :span&#61;"2" class&#61;"text-center"><i class&#61;"el-icon-delete text-red" &#64;click&#61;"delOption(index)">i>el-col>el-row><div style&#61;"margin-top:10px"><el-button type&#61;"text" &#64;click&#61;"addOption">添加选项el-button>div>el-form-item>template><el-form-item label&#61;"必填"><el-switch v-model&#61;"formList[activeIndex].required">el-switch>el-form-item>el-form>template>el-col>el-row>div>
template>

script 部分

<script>
export default {name: &#39;formBuilder&#39;,props: {templateHtml: {type: String,default: &#39;&#39; // 初始化}},data() {return {activeIndex: 0, // 当前编辑的 indexfutureIndex: 0, // 插入的数组 indexisRight: false, // 是否拖动到右边formList: [],dragOptions: { group: { name: &#39;comp&#39;, pull: &#39;clone&#39; }, sort: true },compList: [{label: &#39;单选项&#39;,icon: &#39;el-icon-s-tools&#39;,type: &#39;radio&#39;},{label: &#39;多选项&#39;,icon: &#39;el-icon-s-tools&#39;,type: &#39;checkbox&#39;},{label: &#39;文本&#39;,icon: &#39;el-icon-document-remove&#39;,type: &#39;text&#39;}]}},mounted() {this.renderForm(this.templateHtml)},watch: {templateHtml(newVal) {this.renderForm(newVal)}},methods: {renderForm(newVal) {if (newVal &#61;&#61; &#39;[]&#39; || newVal &#61;&#61; &#39;&#39; || newVal &#61;&#61; null) {this.formList &#61; []} else {this.formList &#61; JSON.parse(newVal)}},// 获取字段数据getFields() {if (0 &#61;&#61; this.formList.length) {this.$message.error(&#39;必须增加模板字段&#xff01;&#39;)return false}let pass &#61; truelet formList &#61; this.formListfor (let i &#61; 0; i < formList.length; i&#43;&#43;) {formList[i]._vModel &#61; &#39;field&#39; &#43; iif (!formList[i].label) {this.$message.error(&#39;请输入字段标题&#xff01;&#39;)pass &#61; falsebreak}}//if (pass) {return this.formList} else {return false}},// 新增选项addOption() {let idx &#61; this.formList[this.activeIndex].options.length &#43; 1this.formList[this.activeIndex].options.push(&#39;选项&#39; &#43; idx)},// 删除选项delOption(index) {this.formList[this.activeIndex].options.splice(index, 1)},// 删除模板字段delItem(index) {this.formList.splice(index, 1)let leg &#61; this.formList.lengthif (leg &#61;&#61; index && leg > 0) {this.activeIndex &#61; index - 1}},// 根据类型获取字段getFormByType(data) {let item &#61; {label: data.label,required: false,type: data.type,icon: data.icon,typeName: data.label,placeholder: &#39;&#39;}// 是否选项if (data.type &#61;&#61; &#39;radio&#39; || data.type &#61;&#61; &#39;checkbox&#39;) {item.options &#61; [&#39;选项1&#39;, &#39;选项2&#39;, &#39;选项3&#39;]}return item},end1(e) {if (this.isRight) {let data &#61; this.getFormByType(this.compList[e.oldIndex])this.formList.splice(this.futureIndex, 0, data)this.activeIndex &#61; this.futureIndex}},start2(e) {},end2(e) {// 判断移动的项目是否为编辑行if (e.oldIndex !&#61; e.newIndex && this.activeIndex &#61;&#61; e.oldIndex) {this.activeIndex &#61; e.newIndex}},onMove1(e, originalEvent) {this.futureIndex &#61; e.draggedContext.futureIndexif (e.relatedContext.component.$attrs.group &#61;&#61; &#39;comp&#39;) {this.isRight &#61; true} else {this.isRight &#61; false}return false},onMove2(e, originalEvent) {if (e.relatedContext.component.$attrs.group &#61;&#61; &#39;comp&#39;) {return true} else {return false}}}
}
</script>

推荐阅读
author-avatar
全球时_尚热门焦点吧
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有