赞
踩
设想业务逻辑是拖拽控件生成表单 动手做了一个简单的demo 业务的原型图设想如下所示
其中使用的技术主要是vuedragger
做控件区的时候首先我们要有确定的配置项 其实也很简单 就是 把所有的选项罗列开来能够正常显示就行了
如图所示 可以去换成图标 什么的 但是是做demo 没有细节所以比较丑陋 后面的也是 将就看吧嘻嘻
配置项如下代码所示:(这一部分还是要看自己具体的业务逻辑)
[ { type: 'image', name: '上传照片', updata_data: [] }, { type: 'radio-multi', values: ['option1', 'option2', 'option3'], name: '多选选择', updata_data: [] }, { type: 'radio-single', values: ['是', '否'], name: '单选选择', updata_data: '' }, { type: 'text', name: '文本输入', updata_data: '' } ],
表单区用border做了一个丑丑的类似手机的边框 如下图所示
如上两张图 我们已经有了控件区和表单区,现在要处理拖拽事件 我们的页面逻辑为 1左边到右边为复制 2右边不可到左边 3左边不可排序 4右边生成的表单内容可以进行排序
实现这个业务逻辑主要使用了vuedraggable 这个库,这是一个很好用的Js拖拽库
任务点1和3可以通过定义一个不被修改的配置项 控件区的end自定义事件里 替换绑定值实现
任务点2 通过配置拖拽组的时候另外加配置项实现
任务点4 插件本身支持这个功能
业务分析完毕
当前完整代码如下:
<template> <div class="TemplateEditor-container"> <div class="btn-list"> <draggable :group="grpupA" :animation="50" key="optionList" v-model="optionList" :move="onmove" @end="end1"> <transition-group style="min-height:600px;display: block;"> <div v-for="(item, idx) in optionList" :key="idx" class="btn"> {{ item.type }} </div> </transition-group> </draggable> </div> <div class="phonelist-con"> <div class="phonelist"> <draggable group="site" :animation="50" key="ttt" v-model="ttt"> <transition-group style="min-height:600px;display: block;"> <div v-for="(item, idx) in ttt" :key="idx" class="phoneinner" @dblclick="changejson"> <div v-if="item.type == 'text'"> <div class="labletit" :class="item.required ? 'requiredval' : ''"> {{ item.name }} </div> <el-input class="info" type="textarea" :autosize="{ minRows: 4 }" :placeholder="item.hint" disabled> </el-input> </div> <div v-if="item.type == 'image'"> <div class="labletit" :class="item.required ? 'requiredval' : ''"> {{ item.name }} </div> <div class="imgbox"> <div class="inputbox"> <i class="ri-camera-fill"></i> <span>点击上传图片</span> </div> </div> </div> <div v-if="item.type == 'radio-multi'"> <div class="labletit" :class="item.required ? 'requiredval' : ''"> {{ item.name }} </div> <el-checkbox-group v-model="item.updata_data"> <el-checkbox disabled v-for="inner in item.values" :label="inner" :key="inner">{{ inner }}</el-checkbox> </el-checkbox-group> </div> <div v-if="item.type == 'radio-single'"> <div class="labletit" :class="item.required ? 'requiredval' : ''"> {{ item.name }} </div> <el-radio-group> <el-radio disabled v-for="(innerite, idx) in item.values" :key="idx" :label="innerite">{{ innerite }}</el-radio> </el-radio-group> </div> </div> </transition-group> </draggable> </div> </div> <div class="json"> </div> </div> </template> <script> import draggable from 'vuedraggable' export default { components: { draggable }, data() { return { grpupA: { name: 'site', pull: true, put: false }, ttt: [], tempoptions: [ { type: 'image', name: '上传照片', updata_data: [] }, { type: 'radio-multi', values: ['option1', 'option2', 'option3'], name: '多选选择', updata_data: [] }, { type: 'radio-single', values: ['是', '否'], name: '单选选择', updata_data: '' }, { type: 'text', name: '文本输入', updata_data: '' } ], optionList: [ { type: 'image', name: '上传照片' }, { type: 'radio-multi', values: ['option1', 'option2', 'option3'], name: '多选选择' }, { type: 'radio-single', values: ['是', '否'], name: '单选选择' }, { type: 'text', name: '文本输入' } ] } }, methods: { changejson(){ }, onmove() { //return false }, end1(e) { console.log(e, '111') this.optionList = this.tempoptions }, } } </script> <style lang="scss" scoped> .inputbox { width: 100%; height: 4.125rem; line-height: unset; background-color: #F2F6F8; border-radius: 6px; border-color: #f2f6f8; display: flex; flex-direction: column; align-items: center; justify-content: center; position: relative; box-sizing: border-box; i { font-size: 24px; color: #4E5969; } span { font-weight: 400; font-size: 12px; color: #86909C; } } .TemplateEditor-container { border: 2px solid #333; width: 100vw; height: 100vh; box-sizing: border-box; display: flex; align-items: center; .btn-list { width: 10%; height: 60vh; //padding: 20%; box-sizing: border-box; .btn { display: block; padding: 10px 20px; margin-left: 10px; margin-top: 10px; border: 1px solid #333; } } .phonelist-con { height: 80vh; width: 375px; padding-left: 20px; .phonelist { max-height: 80vh; overflow: auto; border: 10px solid #333; border-top-width: 120px; border-bottom-width: 100px; box-sizing: border-box; border-radius: 40px; .phoneinner { width: 100%; margin-bottom: 10px; padding: 2px 10px; box-sizing: border-box; } } } .json{ flex: 1; height: 80vh; margin-left: 10px; margin-right: 10px; border:1px solid #d8d8d8; } .labletit { color: #888; font-size: 14px; padding-top: 10px; padding-bottom: 4px; } .requiredval { position: relative; width: auto; } .requiredval::after { right: -6px; top: 0px; padding-left: 4px; content: "*"; color: #f56c6c; margin-right: 4px; } } </style>
实现效果如下图所示:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。