draggable 是个非常不错,而且很方便的拖拽组件,但是你在项目中可能会遇到被包裹的拖拽元素对象的点击事件失效的问题,事件冲突了.先看代码示例,再看解决思路及方法.

安装使用:

yarn add vuedraggable

或者

npm i -S vuedraggable

github: https://github.com/SortableJS/Vue.Draggable

 

1. 被拖拽组件的父组件 Warp.vue

<template>
    <draggable v-model="sendData.template" class="app-form-items" @change="handleDraggableFormItemChange">
        <template v-for="(item,index) in sendData.template">
            <app-form-item
                :key="index"
                :active="formItemActiveIndex == index"
                @selected="handleControlSelected(item,index)"
                @delete="handleControlDelete(item,index)"
            >
                {{ item.name }}
            </app-form-item>
        </template>
    </draggable>
</template>
<script>
import draggable from 'vuedraggable';
import AppFormItem from './AppFormItem';
export default {
    components: {
        draggable,
        AppFormItem
    },
    data() {
        return {
            sendData: {
                template: [{name:'拖拽对象1'},{name:'拖拽对象2'},{name:'拖拽对象3'}] //模板列表
            }
        };
    },
    methods: {

        /**
         * 拖拽控件
         */
        handleDraggableFormItemChange(e) {
            console.log(`拖拽回调:`, e);
        },

        /**
         * 选中控件
         */
        handleControlSelected(data, index) {
            console.log(`handleControlSelected 选中控件:`, data, index);
        },

        /**
         * 移除控件
         */
        handleControlDelete(data, index) {
            console.log(`handleControlDelete 移除控件:`, data, index);
        }
    }
};
</script>
<style lang="less" scoped>
.app-create-form{
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100%;
    .create-edit{
        flex: 1;
        .app-mobile-editor{
            margin: 0 auto;
            .app-form-warp{
                height: 100%;
                .app-form-items{
                    height: calc(100% - 46px) ;
                    overflow: auto;
                    .app-form-item{
                        cursor: move;
                        font-size: 14px;
                    }
                }
            }
        }
    }
}
</style>

2. 拖拽的组件对象 AppFormItem.vue

<template>
    <div class="app-form-item" :class="{'app-item-selected': active}" @click.stop.prevent="handleClick()">
        <span class="del-btn" title="移除控件" @click.stop.prevent="handleDel()">
            <i class="iconfont iconquxiao" />
        </span>
        <slot />
    </div>
</template>
<script>
export default {
    name: 'AppFormItem',
    props: {
        active: {
            type: Boolean,
            required: false,
            default: false
        }
    },
    methods: {
        handleClick() {
            this.$emit('selected');
        },
        handleDel() {
            this.$emit('delete');
        }
    }
};
</script>
<style lang="less" scoped>
.app-form-item{
    background: #fff;
    padding: 16px 20px;
    border: 1px solid #fff;
    & + .app-form-item{
        margin-top: 10px;
    }
    .del-btn{
        display: none;
    }
}
.app-item-selected{
    position: relative;
    border: 1px solid #f00;
    .del-btn{
        display: flex;
        width: 18px;
        height: 18px;
        align-items: center;
        justify-content: center;
        position: absolute;
        right: 0;
        top: 0;
        color: #fff;
        background: #f00;
        cursor: pointer;
        border-radius: 0 0 0 2px;
        z-index: 99;
        &:hover{
            opacity: .8;
        }
        i{
            font-size: 12px;
        }
    }
}
</style>

实际应用效果:

 

重点来了:

解决直接绑定点击事件与拖拽事件冲突,可以使用封装子组件的形式,在子组件触发点击事件,然后在父组件使用子组件触发事件的回调即可.如果你的被拖拽对象上面有很多个元素有绑定事件,那么你需要使用.stop和.prevent修饰符来禁止默认事件和冒泡.

如果你有更好的方法,可留言分享交流.

 

网友的其它解决方案分享留言:

qq_34854119:这个拖动插件有一个属性distance, 默认值是0, 把点击事件识别成了拖动事件了, 如果把它的值设置成>0的数, 自己的组件就可以响应点击事件了.

1.这个拖动插件有一个属性distance, 默认值是0, 把点击事件识别成了拖动事件了, 如果把它的值设置成>0的数, 自己的组件就可以响应点击事件了

<slick-list lockAxis="y" v-model="allData" @input="sortResult" :distance="1">

 

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐