Vue組件設(shè)計(jì)之多列表拖拽交換排序功能實(shí)現(xiàn)
在前端開(kāi)發(fā)中,拖拽排序是一種提升用戶體驗(yàn)非常好的方式,常見(jiàn)的場(chǎng)景有單列表拖拽排序,多列表拖拽交換排序,比如以下這種效果:

下面將以這種效果為例,設(shè)計(jì)一個(gè)組件。
1. 安裝所需依賴
npm install vuedraggable --save
本例中目前所用的版本為:2.20.0
2. 組件設(shè)計(jì)實(shí)現(xiàn)
<template>
<div class="dnd-list">
<div class="dnd-list-aside" :style="{width:width1 }" >
<h3>{{ list1Title }}</h3>
<draggable :list="list1" group="article" class="drag-area" :set-data="setData">
<div :key="element.id" v-for="element in list1" class="list-complete-item">
<div class="list-complete-item-handle1">
{{ element.id }} {{ element.title }} [{{ element.author }}]
</div>
<div style="position:absolute;right:0px">
<span style="float:right;margin-top:-20px;margin-right:5px;" @click="deleteItem(element)">
<i style="color: #ff4949" class="el-icon-delete" />
</span>
</div>
</div>
</draggable>
</div>
<div class="dnd-list-aside" :style="{width:width2}">
<h3>{{ list2Title }}</h3>
<draggable :list="list2" group="article" class="drag-area">
<div :key="element.id" v-for="element in list2" class="list-complete-item">
<div class="list-complete-item-handle2" @click="pushItem(element)">
{{ element.id }} {{ element.title }} [{{ element.author }}]
</div>
</div>
</draggable>
</div>
</div>
</template>
<script>
import draggable from "vuedraggable";
export default {
name: "DndList",
components: { draggable },
props: {
list1: {
type: Array,
default() {
return [];
},
},
list2: {
type: Array,
default() {
return [];
},
},
list1Title: {
type: String,
default: "list1",
},
list2Title: {
type: String,
default: "list2",
},
width1: {
type: String,
default: "48%",
},
width2: {
type: String,
default: "48%",
},
},
methods: {
// 是否在列表一
isNotInList1(v) {
return this.list1.every((k) => v.id !== k.id);
},
// 是否在列表二
isNotInList2(v) {
return this.list2.every((k) => v.id !== k.id);
},
// 刪除列表項(xiàng)
deleteItem(element) {
for (const item of this.list1) {
if (item.id === element.id) {
const index = this.list1.indexOf(item);
this.list1.splice(index, 1);
break;
}
}
if (this.isNotInList2(element)) {
this.list2.unshift(element);
}
},
// 點(diǎn)擊切換列表項(xiàng)
pushItem(element) {
for (const item of this.list2) {
if (item.id === element.id) {
const index = this.list2.indexOf(item);
this.list2.splice(index, 1);
break;
}
}
if (this.isNotInList1(element)) {
this.list1.push(element);
}
},
// 拖拽交換時(shí)
setData(dataTransfer) {
// 解決火狐問(wèn)題
// 詳見(jiàn) : https://github.com/RubaXa/Sortable/issues/1012
dataTransfer.setData("Text", "");
},
},
};
</script>
<style lang="scss" scoped>
.dnd-list {
background: #fff;
padding-bottom: 40px;
&:after {
content: "";
display: table;
clear: both;
}
.dnd-list-aside {
float:left;
padding-bottom: 30px;
&:first-of-type {
margin-right: 2%;
}
.drag-area{
margin-top: 15px;
min-height: 50px;
padding-bottom: 30px;
}
}
}
.list-complete-item {
cursor: pointer;
position: relative;
font-size: 14px;
padding: 5px 12px;
margin-top: 4px;
border: 1px solid #bfcbd9;
transition: all 1s;
}
.list-complete-item-handle1 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 50px;
}
.list-complete-item-handle2 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 20px;
}
.list-complete-item.sortable-chosen {
background: #4ab7bd;
}
.list-complete-item.sortable-ghost {
background: #30b08f;
}
.list-complete-enter,.list-complete-leave-active {
opacity: 0;
}
</style>3. 組件使用示例
<template>
<div class="box">
<DndList :list1="list1" :list2="list2" :list1Title="list1Title" :list2Title="list2Title"></DndList>
</div>
</template>
<script>
import DndList from "@/components/DndList";
export default {
components:{
DndList:DndList
},
data() {
return {
list1:[
{id:1,title:"《西游記》",author:"吳承恩"},
{id:2,title:"《紅樓夢(mèng)》",author:"曹雪芹"},
{id:3,title:"《水滸傳》",author:"施耐庵"},
{id:4,title:"《三國(guó)演義》",author:"羅貫中"},
{id:5,title:"《名人傳》",author:"羅曼羅蘭"},
{id:6,title:"《鋼鐵是怎樣煉成的》",author:"奧斯特洛夫斯基"},
],
list2:[
{id:7,title:"《魯賓遜漂流記》",author:"笛福"},
{id:8,title:"《格列佛游記》",author:"約翰斯威夫特"},
{id:9,title:"《繁星春水》",author:"冰心"},
],
list1Title:"我的圖書(shū)收藏",
list2Title:"已讀完的圖書(shū)"
};
}
}
</script>
<style scoped>
.box{
width:600px;
margin:20px;
padding:10px;
background:#fff;
}
</style>到此這篇關(guān)于Vue組件設(shè)計(jì)之多列表拖拽交換排序的文章就介紹到這了,更多相關(guān)vue拖拽交換排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue與django(drf)實(shí)現(xiàn)文件上傳下載功能全過(guò)程
最近簡(jiǎn)單的學(xué)習(xí)了django和drf上傳文件(主要是圖片),做一個(gè)記錄,下面這篇文章主要給大家介紹了關(guān)于vue與django(drf)實(shí)現(xiàn)文件上傳下載功能的相關(guān)資料,需要的朋友可以參考下2023-02-02
vue2滾動(dòng)條加載更多數(shù)據(jù)實(shí)現(xiàn)代碼
本篇文章主要介紹了vue2滾動(dòng)條加載更多數(shù)據(jù)實(shí)現(xiàn)代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01
vue下拉刷新組件的開(kāi)發(fā)及slot的使用詳解
這篇文章主要介紹了vue下拉刷新組件的開(kāi)發(fā)及slot的使用詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
Vue.js 中 ref 和 reactive 的區(qū)別及用法解析
在Vue.js中,ref主要用于創(chuàng)建響應(yīng)式的引用,通過(guò).value屬性來(lái)訪問(wèn)和修改值,特別適用于需要頻繁更改整個(gè)值的場(chǎng)景,而reactive則用于創(chuàng)建深度響應(yīng)的對(duì)象或數(shù)組,本文給大家介紹Vue.js 中 ref 和 reactive 的區(qū)別及用法,感興趣的朋友跟隨小編一起看看吧2024-09-09
詳解Vue自定義過(guò)濾器的實(shí)現(xiàn)
這篇文章主要介紹了詳解Vue自定義過(guò)濾器的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧。2017-01-01
vue引入子組件命名不規(guī)范錯(cuò)誤的解決方案
這篇文章主要介紹了vue引入子組件命名不規(guī)范錯(cuò)誤的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
Vue express鑒權(quán)零基礎(chǔ)入門(mén)
這篇文章主要介紹了詳解express鑒權(quán),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02

