Vue3+vuedraggable实现动态配置页面
作者:喵森
1、首先放上最终效果图,整个页面由三个区域组成:
- 组件列表存放可以配置的组件名称。
- 放置列表为最终展现的视觉效果。
- 组件输入则可以动态配置内容,最终的配置数据为此处的数据。
1、框架搭建
1.1、安装指定版本的vuedraggable
首先安装支持vue3版本的vuedraggable
注意:默认安装的vuedraggable版本为vue2.0版本,并不通用。
npm install vuedraggable@4.1.0 --save
vue3版本vuedraggable示例地址sortablejs.github.io/vue.draggable.next
vue3版本vuedraggable Git地址 github.com/SortableJS/vue.draggable.next
1.2、布局搭建
安装完4.0版本的vuedraggable以后,就可以按下面的写法来进行一个简单的布局了。
<template> <div> <div class="section-container"> <h4>组件列表</h4> <draggable class="components-view" item-key="index" :list="sectionList" :sort="false" :forceFallback="true" ghost-class="ghost" dragClass="dragClass" group="vehicle-station" > <template #item="{ element, index }"> <div class="section">{{ element.type }}</div> </template> </draggable> </div> <div class="components-container"> <h4>放置列表</h4> <draggable item-key="index" :list="componentsList" animation="300" :scroll="true" :forceFallback="false" ghost-class="ghost" dragClass="dragClass" group="vehicle-station"> <template #item="{ element, index }"> <transition name="el-fade-in-linear"> <div> <div v-if="element.type === 'input'" class="section">输入框{{ element.data }}</div> <div v-if="element.type === 'textarea'" class="section">文本域</div> </div> </transition> </template> </draggable> </div> <!-- 这里存放组件 --> <div class="operate-container"> <h4>组件输入</h4> </div> </div> </template>
需要注意的是vue3版本不再需要v-for来渲染组件,直接使用template来渲染元素,并且需要指定唯一的item-key值。
1.2、使用到的参数介绍
属性名称 | 说明 |
---|---|
group | name相同的可以互相拖拽 |
list | 拖拽的数组 |
item-key | 唯一key值,不能重复 |
sort | 控制列表是否可以排序 |
forceFallback | 默认false,忽略HTML5的拖拽行为,因为设置了拖拽样式,需要开启 |
ghost-class | 目标位置占位符的样式 |
dragClass | 拖拽对象移动样式 |
animation | 拖拽动画时间 |
pull | clone,拖拽的元素不会从列表消失,直接克隆这条数据 |
put | false,禁止元素拖入 |
函数部分目前只需要定义数据结构
<script setup lang="ts"> import { ref } from 'vue'; import draggable from 'vuedraggable' interface list { type: string, name: string, data: any } const sectionList = ref<list[]>([ { type: 'input', data: '', name: 'input' }, { data: '', type: 'textarea', name: 'textarea' } ]) const componentsList = ref<list[]>([]) </script>
css定义一下分栏布局和拖动、占位样式
<style scoped> .components-view, .components-wrap { height: 100%; } .dragClass { border: 1px solid red; border-radius: 8px; } .ghost { background-color: red !important; } .operate-container, .section-container, .components-container { float: left; padding-top: 30px; text-align: center; width: 300px; height: 800px; } .section-container { background-color: blanchedalmond; } .components-container { margin-left: 30px; background-color: rgb(184, 205, 178); } .operate-container { margin-left: 30px; background-color: rgb(125, 176, 228); } .section { text-align: center; width: 150px; height: 80px; line-height: 80px; margin-bottom: 30px; background-color: cadetblue; cursor: pointer; } </style>
至此页面就可以正常拖拽了,仅拖拽页面不需要用到函数操作,只需要根据配置项把页面布局完成即可。
2、数据接入
目前只是完成了组件的添加,接下来要把组件接入。
思路是单独定义组件数据,当输入完成以后,根据当前拖动的放置列表下标来存储数据。
2.1、为两列拖拽元素添加拖拽结束事件
2.2、设置组件数据
组件数据和放置列表的数据是联动的,在编辑完组件以后,数据会存储到放置列表内。 此时需要在拖动结束时获取当前拖动的放置列表下标,再把数据赋值给组件数据
<div class="operate-container"> <h4>组件输入</h4> <div> <!-- TODO:输入数据的时候要双向绑定,赋值给editorData --> <input v-if="editorData.type === 'input'" type="text" v-model="editorData.data" @change="setEditorData"> <textarea v-if="editorData.type === 'textarea'" rows="4" cols="30" v-model="editorData.data" @change="setEditorData"></textarea> </div> </div> const onEnd = (evt: any) => { setCurrent(evt.newIndex) } ----- const setCurrent = (idx: number) => { // 设置当前编辑的组件数据 editorData.value = { ...componentsList.value[idx] } editorIndex.value = idx } const setEditorData = () => { // 将编辑的组件数据赋值给放置列表数据 componentsList.value[editorIndex.value] = editorData.value }
最终实现效果如下,可以根据拖动的组件展示不同的组件,并且可以输入。
2.3、处理数据重复
上一步完成以后,组件数据已经可以保留下来了,但是无法做到数据互不冲突,无论是新添加组件,还是编辑其中一个组件,数据都是相同的。
这是因为在拖拽的时候数据都是复制的,在修改完数据以后,最左侧的组件列表会接收到最新修改的数据,在下一次拖动的时候就会把已经修改的数据再次拿来使用。
目前想到的解决方案是获取当前拖动的组件列表下标,和当前放置列表的下标,手动清除数据。
const onEnd = (evt: any) => { if (evt.target.className === 'components-view' && evt.to.className === 'components-wrap') { // 左侧组件列表的下标 sectionIndex.value = evt.oldIndex } setCurrent(evt.newIndex) } const setCurrent = (idx: number) => { // 设置当前编辑的组件数据 editorData.value = { ...componentsList.value[idx] } editorIndex.value = idx } const setEditorData = () => { // 填完值以后两侧数据都发生了改变,需要重新修改数据 // 把上一次拖动的左侧列表数据清空 sectionList.value[sectionIndex.value].data = '' // 将编辑的组件数据赋值给放置列表数据 componentsList.value[editorIndex.value] = editorData.value }
完成上述步骤以后,简单的动态配置组件就已经完成了,处理框架的代码量并不大,后续可以在上面拓展新的组件,最终可以呈现出一个可以动态配置的页面。
以上就是Vue3+vuedraggable实现动态配置页面的详细内容,更多关于Vue3 vuedraggable动态配置页面的资料请关注脚本之家其它相关文章!