【问题标题】:How do I improve the precision of Vue Draggable nesting?如何提高 Vue Draggable 嵌套的精度?
【发布时间】:2020-03-11 20:53:01
【问题描述】:

我一直在使用 Vue 2 组件和 Vue.Draggable 库开发表单构建器。这很好用,除了一个持续存在的问题——对于最终用户来说,嵌套块实际上很难嵌套。让一个块缩进另一个块需要大量的精确度和反复试验。

如何解决此问题并使其更易于使用?看起来几乎是因为缺少拖放区。

(链接到 Imgur,因为无法嵌入动画图像)

请注意,由于多文件的性质,我无法在 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>

【问题讨论】:

  • 我也在找这个。由于它使用 SortableJS 作为其基础,因此 sortable 确实有一个称为 swapThreshold 的阈值选项,但是,在搜索 Vue-Draggable 存储库时,我根本找不到引用此选项。可排序选项:github.com/SortableJS/Sortable#options

标签: javascript vue.js vuejs2 draggable vue.draggable


【解决方案1】:

对我来说 :emptyInsertThreshold='20' 参数确实很神奇。您必须稍微调整一下值,但它解决了我的嵌套问题。

【讨论】:

    【解决方案2】:

    这可以通过 options 属性实现。 Vue Draggable 使用 SortableJS。现在它仍然通过 options 属性传递选项。

    <template>
    <draggable :options="{swapThreshold: 0.5}">
        <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>
    

    在我上面展示的示例中,我将阈值降低了一半。

    https://github.com/SortableJS/Sortable#swapthreshold-option

    swapThreshold 选项

    交换区将占用的目标百分比,作为 0 到 1 之间的浮点数。

    注意

    option 属性已弃用,将在未来版本中删除。我假设它在那里作为它尚未实施的其他选项的后备,例如swapThreshold

    有关弃用通知的更多详细信息请点击此处: https://github.com/SortableJS/Vue.Draggable/blob/master/documentation/migrate.md#options-props

    如果您想使用 Vue Draggable 文档中没有的其他选项,您可以查看 SortableJS 的选项页面以了解您仍然可以使用哪些选项:

    https://github.com/SortableJS/Sortable#options

    【讨论】:

      猜你喜欢
      • 2014-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多