sortable.js,它可以用来实现这个拖拽的功能。

Sortable.js —是一个JavaScript库,用于在现代浏览器和触摸设备上对拖放列表进行重新排序,无需jQuery。 特点有:

  • 轻量级但功能强大

  • 移动列表项时有动画

  • 支持触屏设备和大多数浏览器(IE9及以下除外)

  • 支持单个列表容器内部拖拽排序,也支持两个列表容器互相拖拽排序

  • 支持拖放操作和可选择的文本

  • 非常友善的滚动效果

  • 基于原生HTML5中的拖放API

  • 支持多种框架(Angular、Vue、React等)

  • 支持所有的CSS框架,如:Bootstrap

  • 简单的API,方便调用

  • CDN

  • 不依赖于jQuery

步骤

安装sortable.js

npm install sortablejs --save-dev 

获取节点

这里获取的节点是需要拖拽列表的父节点

// 使用DOM id 获取DOM
let el = document.getElementById('list')

或者

// 使用类名
let el = document.querySelector('.list')

通过Sortable()构建函数,接收容器元素和配置项

let el = document.querySelector('.list')
​
sortable = Sortable.create(this.dragData, {
                    sort: true, //是否可进行拖拽排序
                    animation: 500,
                    
                    // 允许被拖拽的类名
                    draggable: '.data',
​
                    // 元素被选中
                    onChoose: (/**Event*/evt) => {
                        console.log("元素被选中,事件对象",evt)
                        // element index within parent
                    },
                    // 开始拖拽的时候 
                    onStart: (/**Event*/evt) => { 
                        evt.oldIndex; 
                    // element index within parent 
                    },
                    
                    // 列表内元素顺序更新的时候触发
                    onUpdate: (/**Event*/evt) => {
                        // same properties as onEnd
                        console.log("顺序更新",evt)
                    },
                    
                    onEnd: (evt) => {
                        // h5使用此方式修改数组顺序
                        const val = this.list[evt.oldIndex]
                        this.list.splice(evt.oldIndex, 1)
                        this.list.splice(evt.newIndex, 0, val)
                        
                    }
}

拖动时会触发各种事件

可以选择 onUpdate 或 onEnd 事件被触发时改变数组顺序

需要把 用Sortable()构建函数创建 sortable 对象 这一操作封装到 methods 中,然后在 mounted 中调用 完整代码

<template>
    <view>
        <view class="list" :list="list" :change:list="Sortable.getListData">
            <view 
              v-for="text of list" 
              :key="text.id"
              class="data">
                <view class="name">{{text.name}}</view>
                <view class="id">{{text.id}}</view>
                <view class="url">{{text.url}}</view>
            </view>
            <view class="block"></view>
        </view>
    </view>
</template>
​
​
<script>
    export default {
        data() {
            return {
                list: [{
                        name: '啊啊啊',
                        id: 1,
                        url: '',
                    },
                    {
                        name: '不不不',
                        id: 2,
                        url: '',
                    },
                    {
                        name: '陈琛琛',
                        id: 3,
                        url: '',
                    },
                    {
                        name: '顶顶顶',
                        id: 4,
                        url: '',
                    },
                    {
                        name: '烦烦烦',
                        id: 5,
                        url: '',
                    }],
            }
        },
​
        mounted() {
            this.initSortable()
        },
        methods: {
            initSortable() {
                this.el = document.querySelector('.list')
                console.log("被选中的DOM",this.el)
                this.sortable = Sortable.create(this.dragData, {
                    sort: true, //是否可进行拖拽排序
                    animation: 500, //动画时间
                    
                    // 允许被拖拽的类名
                    draggable: '.data',
                    
                    onEnd: (evt) => {
                        // h5使用此方式修改数组数据
                        const val = this.list[evt.oldIndex]
                        this.list.splice(evt.oldIndex, 1)
                        this.list.splice(evt.newIndex, 0, val)
                        
                    },
                    
                })
            },
            
        }
    }
</script>

但是此方式只能用于h5 无法在APP使用,原因为 APP中无法使用 document对象 ,更不能通过document对象获取元素DOM,需要结合 renderjs 使用才能实现

结合 renderjs 使用方法

使用renderjs 关于使用renderjs[]

// 在<script>中添加 module='' lang="renderjs"
// module='' 中内容为自己设置的名称 ,相当于命名空间,之后会根据这个名字调用其中的方法
//例如
<script module="Sortable" lang="renderjs">
</script>

但是在 renderjs 中 无法直接获取到 service层 的 vue 中的数据,也无法直接把数据返回到 service层的 vue 中,需要在 renderjs与vue建立通信

在 renderjs与vue建立通信

数据从service层传输到 renderjs :

在template中的父节点绑定一个service中定义的值,然后在同样的位置增加:change:(属性名)=(触发的方法)来实现通信。 例如在父节点上添加 :list="list" :change:list="Sortable.getListData"

// prop是个名字,可以随意改,注意:change:[name]这两个名字需要相同就行了
<view class="list" :prop="list" :change:prop="Sortable.getListData">
    <view v-for="text of list" :key="text.id" class="data">
        <view class="name">{{text.name}}</view>
        <view class="id">{{text.id}}</view>
        <view class="url">{{text.url}}</view>
    </view>
</view>
​
<script lang="renderjs" module="Sortable"> 
export default {
    methods: { 
        getListData(newValue, oldValue, ownerInstance, instance) {
            console.log('service层中的options发生变化') 
            console.log('新值', newValue) 
            console.log('旧值', oldValue) 
            // 通过this.prop看可以直接使用
            console.log(this.prop)
            // ownerInstance和this.$ownerInstance一样,可用来向service层通信 
            // instance和ownerInstance的区别是: 
            // instance.$el指向的是触发事件的那个节点;ownerInstance.$el指向当前vue文件中的根节点; 
            // instance的作用目前尚不明确,官方没有给出用法 
        },
​
    } 
} 
</script>
​

数据从renderjs层传递到service层

直接在renderjs层层修改数据是无法在service层提现,需要传输到service层 通过this.$ownerInstance.callMethod()方法可以调用service中的方法,第一个参数是方法名,第二个参数是传过去的参数

methods: {
    initSortable() {
        this.dragData = document.querySelector('.list')
        console.log("被选中的DOM",this.dragData)
        this.sortable = Sortable.create(this.dragData, {
            sort: true, //是否可进行拖拽排序
            animation: 500,
            // 允许被拖拽的类名
            draggable: '.data',
            
            // 结束拖拽时触发此函数
            onEnd: (evt) => {
                
                let returnDate = {
                    oldIndex : evt.oldIndex,
                    newIndex : evt.newIndex,
                    oldV : this.list[evt.oldIndex],
                    newV : this.list[evt.newIndex]
                }
                
                
                // APP中需要把数据返回到service层再修改数组顺序
                this.$ownerInstance.callMethod('setDataList', returnDate);
            },
            
        })
    },
}

然后在service层修改数组顺序

methods:{
	setDataList(returnDate){
		
		// 修改数组顺序
		let tempVal = this.list[returnDate.oldIndex]
		this.list.splice(returnDate.oldIndex, 1)
		this.list.splice(returnDate.newIndex, 0, tempVal)
		
	}
}

至此整个功能完成实现

Logo

前往低代码交流专区

更多推荐