vue drag实现v-for循环出来的dom元素拖拽改变位置、排序

vue实现v-for循环出来的dom元素拖拽改变位置、排序


初始效果
初始效果
实现添加路线效果,点击√,完成添加
在这里插入图片描述
路线5已经添加成功
在这里插入图片描述
实现拖拽效果,更改路线3和5的位置
在这里插入图片描述

代码如下:

<template>
	<div class="right-wrap">
	    <!-- 路线展示区 -->
	    <div class="all-item-wrap">
	        <div class="item-wrap" 
	            v-for="(item, index) in lineItems" 
	            :key="`${item.name}-${index}`"
	            @click="choosedItem(index)"
	            draggable="true" 
	            ondragstart="event.dataTransfer.setData('text/plain',null)"
	            :class="{'active-item': currentIndex === index}"
	        >
	            <div class="item-info">
	                {{item.name}}-{{item.interval}}
	            </div>
	            <Button class="item-opera" type="primary" size="small">跳转</Button>
	        </div>
	    </div>
        <!-- 添加路线区 -->
        <div class="add-item-wrap" v-if="isAddItem">
            <Input class="name" v-model="item.name" placeholder="名称" />
            <Input class="interval" v-model="item.interval" placeholder="停留时间(s)" />
            <Icon 
                class="confirm-add" 
                :size="22" 
                color="#61beff" 
                type="md-checkmark" 
                @click="confirmAddItem()"
            />
        </div>
	   	<!-- 添加按钮与删除按钮区 -->
		<div class="option-wrap">
	       <div class="add-icon" @click="isAddItem = true">
	           <img :src="addIcon">
	       </div>
	      <div class="delete-icon" @click="deleteItem()">
	           <img :src="deleteIcon">
	       </div>
		</div>
	</div>
</template>

ts部分

<script lang="ts">
    import { Component, Vue, Watch, Prop } from "vue-property-decorator"

    @Component({})
    export default class autoCruise extends Vue {
    	// 添加和删除的图标
		addIcon: string = require('@/assets/add-icon.png')
        deleteIcon: string = require('@/assets/delete-icon.png')
        // 控制添加的input框是否出现
        isAddItem: boolean = false
        // 用来存放路线的数组
		lineItems = [
            { id: 1, name: '路线1', interval: 3 },
            { id: 2, name: '路线2', interval: 3 },
            { id: 3, name: '路线3', interval: 3 },
            { id: 4, name: '路线4', interval: 3 },
        ]
		// 单个添加路线的对象
        item: {name: string, interval: number} = {
            name: '',
            interval: 0
        }
		// 当前index
        currentIndex: number = -1
        //拖拽的目标对象
		dragged!: any
		
		mounted() {
            let self = this
            // this.getPatrolByStation()
            /* 拖动目标元素时触发drag事件 */
            // document.addEventListener("drag", function( event ) {
                
            // }, false);
            // 当拖拽开始的时候,拖拽目标变成半透明
            document.addEventListener("dragstart", function( event: any ) {
                // 保存拖动元素的引用(ref.)
                self.dragged = event.target;
                // 使其半透明
                (event.target as any).style.opacity = .5;
            }, false);
			
            document.addEventListener("dragend", function( event: any ) {
                // 重置透明度
                event.target.style.opacity = "";
            }, false);

            /* 放置目标元素时触发事件 */
            document.addEventListener("dragover", function( event ) {
                // 阻止默认动作以启用drop
                event.preventDefault();
            }, false);

            document.addEventListener("dragenter", function( event: any ) {
                // 当可拖动的元素进入可放置的目标时高亮目标节点
                if ( event.target.className == "item-wrap" ) {
                    event.target.style.background = "purple";
                }

            }, false);

            document.addEventListener("dragleave", function( event: any ) {
                // 当拖动元素离开可放置目标节点,重置其背景
                if ( event.target.className == "item-wrap" ) {
                    event.target.style.background = "";
                }

            }, false);

            document.addEventListener("drop", function( event: any ) {
                // 阻止默认动作(如打开一些元素的链接)
                event.preventDefault();
                // 将拖动的元素到所选择的放置目标节点中
                if ( event.target.className == "item-wrap" ) {
                    event.target.style.background = ""; 
                    // 要被替换元素的索引
                    let targetIndex = self.getIndex(event.target)
                    // 拖拽元素的目标索引
                    let draggedIndex = self.getIndex(self.dragged)
                    // 拖拽元素对应的数组中的数据
                    let arrItem = self.lineItems[draggedIndex]
                    // 删除原位置的拖拽元素对应的数据
                    self.lineItems.splice(draggedIndex, 1)
                    // 添加到指定位置
                    self.lineItems.splice(targetIndex, 0, arrItem)
                    // 减少对dom的操作,所以下面这边不不推荐,但是这两步也可以实现与上面同样的效果
                    // self.dragged.parentNode.removeChild(self.dragged);
                    // event.target.parentNode.insertBefore(self.dragged, event.target)
                }
                
            }, false);
        }
		获取dom元素的index值
        getIndex(element) {
            return Array.prototype.slice.call(element.parentNode.children).indexOf(element)
        }
        // 添加巡航路线
        confirmAddItem() {
            this.isAddItem = false
            let temp = {
                id: this.lineItems.length + 1,
                name: this.item.name,
                interval: this.item.interval
            }
            this.lineItems.push(temp)
            this.item.name = ''
            this.item.interval = 0
        }
		// 选中当前item
        choosedItem(index) {
            this.currentIndex = index
        }
		// 删除选中的item
        deleteItem() {
            if (this.currentIndex === -1) {
                this.$Message.warning('请选择你要删除的路线')
            } else {
                this.lineItems.splice(this.currentIndex, 1)
            }
        }
	}

css部分,使用的less

<style lang="less">
	.right-wrap {
        flex: 2;
        position: relative;
        .all-item-wrap {
            max-height: 220px;
            overflow-y: auto;
            .item-wrap {
                line-height: 40px;
                border: 1px solid #eee;
                border-radius: 4px;
                margin: 5px;
                padding: 0 5px;
                .item-info {
                    display: inline-block;
                    width: 75%;
                }
                .item-opera {
                    display: inline-block;
                }
            }
            .active-item {
                border: 1px solid red;
            }
        }
        .option-wrap {
            position: absolute;
            bottom: 0px;
            right: 2px;
            .add-icon,
            .delete-icon {
                cursor: pointer;
                display: inline-block;
            }
        }
        .add-item-wrap {
            position: absolute;
            bottom: 2.9rem;
            display: flex;
            align-items: center;
            .name,
            .interval {
                flex: 3;
            }
            .confirm-add {
                flex: 1;
                cursor: pointer;
            }
        }
    }
</style>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值