我一直在使用 Vue 2 组件和 Vue.Draggable 库开发表单构建器。这很好用,除了一个持续存在的问题——对于最终用户来说,嵌套块实际上很难嵌套。要让一个块缩进另一个块,需要大量的精确度和反复试验。
如何解决此问题并使其更易于使用?看起来几乎是因为缺少放置区。
请注意,由于多文件性质,我无法在 CodePen 中运行代码。该代码还依赖于 UI 的 TailwindCSS。
/FormBuilder.vue
<style>
.wrapper {
margin-bottom: -1rem;
}
.group.templates {
display: flex;
flex-direction: row;
margin: 0 -0.5em;
}
.group.templates .field {
margin: 0 0.5rem;
}
.group.elements {
margin-top: 1rem;
}
.group.elements .field {
margin: 1rem 0;
}
.group.elements .field + div {
margin-left: 1rem;
}
.group.elements .ghost {
opacity: 0.5;
}
</style>
<template>
<div>
<div>
<draggable :list="templates" :group="{ name: 'form-builder', pull: 'clone', put: false }" :clone="cloneTemplate" :component-data="getComponentData()">
<div v-for="element in templates" :key="element.name">
<div class="field bg-white rounded shadow rounded font-bold text-gray-700 px-4 py-2">
<h4 class="font-bold"><i class="fas mr-2" :class="[ 'fa-' + element.icon ]"></i> {{ element.name }}</h4>
</div>
</div>
</draggable>
</div>
<div class="wrapper">
<nested-draggable :items="elements" name="form-builder"></nested-draggable>
</div>
</div>
</template>
<script>
import Draggable from 'vuedraggable'
import NestedDraggable from './FormBuilder/NestedDraggable'
export default {
components: {
Draggable,
NestedDraggable,
},
data() {
return {
id: 6,
templates: [
{
name: 'Field',
icon: 'heading',
type: 'field'
}
],
elements: [
{
id: 1,
type: 'test',
locked: true,
options: {
text: "field"
},
children: []
},
{
id: 2,
type: 'paragraph',
locked: false,
options: {
text: "field"
},
children: []
},
{
id: 3,
type: 'field',
locked: false,
options: {
text: "field"
},
children: [
{
id: 4,
type: 'field',
locked: false,
options: {
text: "field"
},
children: []
},
{
id: 5,
type: 'field',
locked: false,
options: {
text: "field"
},
children: []
}
]
}
]
}
},
methods: {
cloneTemplate(object) {
return {
id: this.id++,
type: object.type,
locked: false,
options: {},
children: []
}
},
getComponentData() {
return {
attrs: {
class: 'group templates'
}
}
}
}
}
</script>
/FormBuilder/NestedDraggable.vue
<template>
<draggable ghost-class="ghost" :list="items" :group="name" :component-data="getComponentData()">
<div v-for="element in items" :key="element.id">
<field v-if="element.type == 'field'" :locked="element.locked" :options="element.options"></field>
<nested-draggable v-if="element.children" :items="element.children" :name="name"></nested-draggable>
</div>
</draggable>
</template>
<script>
import draggable from 'vuedraggable'
import field from "./Fields/Field"
export default {
name: 'nested-draggable',
components: {
draggable,
field
},
props: {
name: {
type: String,
required: true
},
items: {
type: Array,
required: true
}
},
methods: {
getComponentData() {
return {
attrs: {
class: 'group elements'
}
}
}
}
}
</script>
/FormBuilder/Fields/Field.vue
<template>
<div class="field bg-white rounded shadow rounded">
<div class="px-4 py-2 border-b flex flex-row items-center text-gray-700">
<h4 class="font-bold mr-4"><i class="fas fa-heading mr-2"></i> Field</h4>
</div>
<div class="p-4 pt-2">
<label for="content" class="form-label">Content</label>
<input type="text" id="content" class="form-control">
</div>
</div>
</template>
<script>
export default {
props: {
locked: {
type: Boolean,
default: false
},
options: {
type: Object,
default: () => {
return {
content: ''
}
}
}
}
}
</script>