vue图片拖动排序实现

4 篇文章 0 订阅
1 篇文章 0 订阅

原理:现有一个图片的列表,拖动其中一个图片(触发dragstart),当拖动的图片移动到其他图片的位置(触发dragover),则将拖动的图片从原位置移动到该位置(触发dragend)。

dragstart当用户开始拖动一个元素或者一个选择文本的时候 dragstart 事件就会触发。

dragover当元素或者选择的文本被拖拽到一个有效的放置目标上时,触发 dragover 事件(每几百毫秒触发一次)。

dragend拖放事件在拖放操作结束时触发。(我们这里可以不用)


(1)图片列表HTML结构。给需要拖动的元素添加属性draggable。这里要注意:模板for循环的key值需要唯一,因为vue在渲染的时候会采用就地复用的方式,如果key值唯一,重新排序后渲染的列表节点不会复用,这样可以避免一些问题。(我们在插入的时候会根据序号向数组中插入某个数据)

        <ul class="drag-container" 
            @dragstart="onDragStart"
            @dragover="onDragOver"
            @dragend="onDragEnd"
            ref="imgList">
            <li 
            v-for="(item,idx) in list" 
            :key='item.path'
            class="drag-list" 
            draggable="true" 
            >
                <img :src="item.path" alt="" />
            </li>
        </ul>

(2)事件: dragstart、dragover绑定事件onDragStart、onDragOver

  1. onDragStart:识别需要拖动的元素,保存到状态中,供拖动过程中dragover的绑定事件使用。
     

            onDragStart(event){
                console.log("start");
                this.draging = event.target;
            },  

     

  2. onDragOver:拖动过程中处于有效目标上的时候触发事件,识别的是目标元素,而不是拖动的元素。首先识别目标元素是否是我们需要的目标元素,我们例子判断是否是li元素,并判断图片是否与拖动的相同,则进行插入拖动元素的操作。
    识别拖动元素与目标元素的位置序号,将拖动元素插入到目标元素前,再将拖动元素原位置的数据删除,在vue中,则只需要进行数据操作即可。

            onDragOver(event){
                console.log('drag move')
                event.preventDefault();
                let target = event.target;
                    //因为dragover会发生在ul上,所以要判断是不是li
                if (target.nodeName === "LI" && 
                    target.childNodes[0].src !== this.draging.childNodes[0].src) {
                    let idx_drag = this._index(this.draging)
                    let idx_target = this._index(target)
                    let _list = this.list
                    let _drag = this.list[idx_drag]
                    if(idx_drag>idx_target){
                        _list.splice(idx_target,0,_list[idx_drag]);
                        _list.splice(idx_drag+1,1)
                    }else{
                        _list.splice(idx_target+1,0,_list[idx_drag]);
                        _list.splice(idx_drag,1)
                    }
                    console.log(_list[0].path)
                    this.$emit("change", _list)
                }
            },

     

完整代码如下:

<template>
    <div class="image-list" v-if="list && list.length">
        <ul class="drag-container" 
        @dragstart="onDragStart"
        @dragover="onDragOver"
        @dragend="onDragEnd"
        ref="imgList">
            <li 
            v-for="(item,idx) in list" 
            :key='item.path'
            class="drag-list" 
            draggable="true" 
            >
                <img :src="item.path" alt="" />
            </li>
        </ul>
    </div>
</template>
<script>
export default {
    name:"drag-image-list",
    props:{
        list: Array,
    },
    data(){
        return {
            draging:null,//被拖拽的对象
        }
    },
    methods:{
        onDragStart(event){
            console.log("start");
            this.draging = event.target;
        },   
        onDragOver(event){
            console.log('drag move')
            event.preventDefault();
            let target = event.target;
                //因为dragover会发生在ul上,所以要判断是不是li
            if (target.nodeName === "LI" && target.childNodes[0].src !== this.draging.childNodes[0].src) {
                let idx_drag = this._index(this.draging)
                let idx_target = this._index(target)
                let _list = this.list
                let _drag = this.list[idx_drag]
                if(idx_drag>idx_target){
                    _list.splice(idx_target,0,_list[idx_drag]);
                    _list.splice(idx_drag+1,1)
                }else{
                    _list.splice(idx_target+1,0,_list[idx_drag]);
                    _list.splice(idx_drag,1)
                }
                console.log(_list[0].path)
            }
        },
        onDragEnd(event){
            console.log('end event')
        },
        _index(el){
            var index = 0;
            if (!el || !el.parentNode) {
                return -1;
            }
            while (el && (el = el.previousElementSibling)) {
                index++;
            }
            return index;
        },
    }
}
</script>

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是实现Vue触屏拖拽排序的步骤: 1. 使用flex布局和v-for指令来创建卡片列表。 2. 绑定触摸事件,包括touchstart、touchmove和touchend。 3. 在touchstart事件中,记录手指初始位置和卡片的初始位置。 4. 在touchmove事件中,计算手指移动的距离,并将卡片相应地移动。 5. 在touchend事件中,根据手指的最终位置和移动距离,确定卡片的最终位置。 6. 根据移动的距离和方向,判断是否需要删除或插入卡片,并更新卡片列表。 7. 完整的代码示例如下: ```html <template> <div class="card-list"> <div v-for="(card, index) in cards" :key="card.id" :style="{ transform: `translateY(${card.position}px)` }" @touchstart="onTouchStart(index)" @touchmove="onTouchMove($event, index)" @touchend="onTouchEnd(index)" > {{ card.name }} </div> </div> </template> <script> export default { data() { return { cards: [ { id: 1, name: 'Card 1', position: 0 }, { id: 2, name: 'Card 2', position: 100 }, { id: 3, name: 'Card 3', position: 200 }, ], touchStartY: 0, touchStartPos: 0, }; }, methods: { onTouchStart(index) { this.touchStartY = event.touches[0].clientY; this.touchStartPos = this.cards[index].position; }, onTouchMove(event, index) { const touchY = event.touches[0].clientY; const moveY = touchY - this.touchStartY; this.cards[index].position = this.touchStartPos + moveY; }, onTouchEnd(index) { const touchY = event.changedTouches[0].clientY; const moveY = touchY - this.touchStartY; const threshold = 50; // 移动距离阈值 if (moveY > threshold) { // 向下移动,插入到下一个位置 this.cards.splice(index + 1, 0, this.cards[index]); this.cards.splice(index, 1); } else if (moveY < -threshold) { // 向上移动,插入到上一个位置 this.cards.splice(index - 1, 0, this.cards[index]); this.cards.splice(index + 1, 1); } else { // 没有超过阈值,恢复原始位置 this.cards[index].position = this.touchStartPos; } }, }, }; </script> ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值