vue中實(shí)現(xiàn)拖拽排序功能的詳細(xì)教程
原生拖拽 API 實(shí)現(xiàn)拖拽
設(shè)置元素 dragable
將元素的 dragable 屬性設(shè)置 為 true (文本 圖片 鏈接 的draggable 屬性默認(rèn)為 true)則元素可拖放
<div :draggable="true">拖拽</div>
拖放事件
在拖放的過(guò)程中涉及到兩種元素,一種是被拖拽元素(源對(duì)象),一種是放置區(qū)元素(目標(biāo)對(duì)象),不同的對(duì)象有不同的拖放事件。
| 觸發(fā)對(duì)象 | 事件名稱 | 說(shuō)明 |
|---|---|---|
| 源對(duì)象 | dragstart | 源對(duì)象開(kāi)始被拖動(dòng)時(shí)觸發(fā) |
| drag | 源對(duì)象被拖動(dòng)過(guò)程中反復(fù)觸發(fā) | |
| dragend | 源對(duì)象拖動(dòng)結(jié)束時(shí)觸發(fā) | |
| 目標(biāo)對(duì)象 | dragenter | 源對(duì)象開(kāi)始進(jìn)入目標(biāo)對(duì)象范圍內(nèi)觸發(fā) 使用 pereventDefault 來(lái)阻止瀏覽器默認(rèn)的拒絕拖拽 |
| dragover | 源對(duì)象在目標(biāo)對(duì)象范圍內(nèi)移動(dòng)時(shí)觸發(fā) 使用 pereventDefault 來(lái)阻止瀏覽器默認(rèn)的拒絕拖拽 | |
| dragleave | 源對(duì)象離開(kāi)目標(biāo)對(duì)象范圍時(shí)觸發(fā) | |
| drop | 源對(duì)象在目標(biāo)對(duì)象范圍內(nèi)被釋放時(shí)觸發(fā) |
dragenter和dragover事件的默認(rèn)行為是拒絕接受任何被拖放的元素。因此,我們要在這兩個(gè)拖放事件中使用preventDefault來(lái)阻止瀏覽器的默認(rèn)行為;而且目標(biāo)對(duì)象想要變成可釋放區(qū)域,必須設(shè)置dragover和drop事件處理程序?qū)傩浴?/p>
拖拽排序
利用拖放API來(lái)實(shí)現(xiàn)列表的拖拽排序
- 由于拖動(dòng)是實(shí)時(shí)的,所以沒(méi)有使用drop而是使用了dragenter觸發(fā)排序。
- 在源對(duì)象開(kāi)始被拖拽時(shí)記錄其索引dragIndex,當(dāng)它進(jìn)入目標(biāo)對(duì)象時(shí)(對(duì)應(yīng)dragenter事件),將其插入到目標(biāo)對(duì)象的位置。
- 其中dragenter方法中有一個(gè)判斷this.dragIndex !== index(index為當(dāng)前目標(biāo)對(duì)象的索引),這是因?yàn)樵磳?duì)象同時(shí)也是目標(biāo)對(duì)象,當(dāng)沒(méi)有這個(gè)判斷時(shí),源對(duì)象開(kāi)始被拖拽時(shí)就會(huì)立刻觸發(fā)自身的dragenter事件,這是不合理的。
拖拽API + 防抖實(shí)現(xiàn)
<template>
<transition-group class="list">
<ul
@dragstart="dragstart(index)"
@dragenter="dragenter($event, index)"
@dragover="dragover($event, index)"
draggable= "true"
v-for="(item, index) in list"
:key="item.label"
class="list-item"
>
{{item.label}}
</ul>
</transition-group>
</template>
<script>
export default {
data() {
return {
list: [
{ label: '列表1' },
{ label: '列表2' },
{ label: '列表3' },
{ label: '列表4' },
{ label: '列表5' },
{ label: '列表6' },
],
// 源對(duì)象的下標(biāo)
dragIndex: '',
// 目標(biāo)對(duì)象的下標(biāo)
enterIndex: '',
timeout: null,
}
},
destroyed() {
// 每次離開(kāi)當(dāng)前界面時(shí),清除定時(shí)器
clearInterval(this.timeout)
this.timeout = null
},
methods: {
dragstart(index) {
console.log('start index ===>>> ',index)
this.dragIndex = index
},
// dragenter 和 dragover 事件的默認(rèn)行為是拒絕接受任何被拖放的元素。
// 因此,我們要在這兩個(gè)拖放事件中使用`preventDefault`來(lái)阻止瀏覽器的默認(rèn)行為
dragenter(e,index) {
e.preventDefault();
this.enterIndex = index
if( this.timeout !== null) {
clearTimeout(this.timeout)
}
// 拖拽事件的防抖
this.timeout = setTimeout(() => {
if( this.dragIndex !== index){
const source = this.list[this.dragIndex]
this.list.splice(this.dragIndex,1)
this.list.splice(index, 0 , source )
// 排序變化后目標(biāo)對(duì)象的索引變成源對(duì)象的索引
this.dragIndex = index;
}
}, 100);
},
dragover(e, index) {
e.preventDefault();
}
},
}
</script>
<style lang='scss' scoped>
.list {
list-style: none;
.list-item {
// 設(shè)置 動(dòng)畫效果
transition: transform .3s;
cursor: move;
width: 300px;
background: #EA6E59;
border-radius: 4px;
color: #FFF;
margin-bottom: 6px;
height: 50px;
line-height: 50px;
text-align: center;
}
}
</style>vue awe-dnd 拖拽組件
安裝 awe-dnd 組件庫(kù)
yarn add awe-dnd -S
在 main.js 中將 awe 掛載到全局
// 引入拖拽排序插件 import VueDND from 'awe-dnd' Vue.use(VueDND)
實(shí)現(xiàn)案例
<template>
<div class="title-list">
<div
v-dragging="{item: item, list:list}"
v-for="item in list"
:key="item.id"
class="title-item">
<div class="title-child">
<span>{{item.id +"--"+ item.name }}</span>
</div>
</div>
</div>
</template>
<script>
export default {
name: "titleList",
data() {
return {
list: [
{id:1,name:"這是第一個(gè)標(biāo)題名稱"},
{id:2,name:"這是第二個(gè)標(biāo)題名稱"},
{id:3,name:"這是第三個(gè)標(biāo)題名稱"},
{id:4,name:"這是第四個(gè)標(biāo)題名稱"},
{id:5,name:"這是第五個(gè)標(biāo)題名稱"},
],
};
},
mounted() {
// 拖拽事件
this.$dragging.$on("dragged", (result) => {
// 將排序后的結(jié)果重新賦值
this.list = result.value.list;
});
},
};
</script>
<style lang="scss" scoped>
.title-list {
width: 350px;
background:#fff;
margin:100px auto 0;
border: 1px solid red;
.title-item {
width: 350px;
cursor: pointer;
border: 1px solid #ededed;
.title-child {
width: 330px;
height: 60px;
margin: 0 auto;
position: relative;
span {
width: 100%;
font-size: 14px;
color: red;
line-height: 30px;
// 只顯示兩行,多余的以省略號(hào)顯示
white-space: normal;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
// 無(wú)論一行還是兩行均居中顯示
position: absolute;
left: 0;
top: 50%;
transform: translate(0, -50%);
}
}
}
}
</style>

v-dragging=“{ item: item, list: colors, group: ‘item’,otherData:‘whatever u want’, comb: ‘isComb’}”
list: 列表的遍歷數(shù)據(jù),
item: 是當(dāng)前循環(huán)值 , 遍歷后需要拖拽功能的元素
group: “unique key of dragable list”即拖拽列表的獨(dú)特key值
// 拖拽事件
this.$dragging.$on("dragged", (result) => {
debugger // console.log('result===>',result)
// result 拖拽后的信息 將排序后console.log的結(jié)果重新賦值
this.list = result.value.list;
});
項(xiàng)目中-- 拖拽的效果 不理想
功能能夠?qū)崿F(xiàn),但拖拽的效果不是很好,無(wú)法修改拖拽圖層的透明度
vue-smooth-DnD
Vue Smooth DnD 是一個(gè)快速、輕量級(jí)的拖放、可排序的 Vue.js 庫(kù),封裝了 smooth-dnd 庫(kù)。
vue-smooth-DnD 文檔 : https://github.com/kutlugsahin/vue-smooth-dnd
安裝 smooth-dnd
yarn add vue-smooth-dnd -S
API: container
| 屬性 | 類型 | 默認(rèn)值 | 描述 |
|---|---|---|---|
| :orientation | string | vertical | 容器的方向,可以為 horizontal 或 vertical |
| :behaviour | string | move | 描述被拖動(dòng)的元素被移動(dòng)或復(fù)制到目標(biāo)容器。 可以為 move (容器間相互移動(dòng)) 或 copy(將元素復(fù)制到其他容器,但本容器內(nèi)元素不變) 或 drop-zone(在容器間移動(dòng),但是容器內(nèi)元素的順序是固定的) 或 contain (只能在容器內(nèi)移動(dòng)。) |
| :tag | string, NodeDescription | div | 容器的元素標(biāo)簽,默認(rèn)是 div ,可以是字符串如 tag=“table” 也可以是包含 value和 props 屬性的對(duì)象 :tag=“{value: ‘table’, props: {class: ‘my-table’}}” |
| :group-name | string | undefined | 可拖動(dòng)元素可以在具有相同組名的容器之間移動(dòng)。如果未設(shè)置組名容器將不接受來(lái)自外部的元素。 這種行為可以被 shouldAcceptDrop 函數(shù)覆蓋。 |
| :lock-axis | string | undefined | 鎖定拖動(dòng)的移動(dòng)軸??捎弥?x, y 或 undefined。 |
| :drag-handle-selector | string | undefined | 用于指定可以開(kāi)啟拖拽的 CSS 選擇器,如果不指定的話則元素內(nèi)部任意位置都可抓取。 例如 drag-handle-selector=“.column-drag-handle” |
| :non-drag-area-selector | string | undefined | 禁止拖動(dòng)的 CSS 選擇器,優(yōu)先于 dragHandleSelector. |
| :drag-begin-delay | number | 0(觸控設(shè)備為 200) | 單位毫秒。表示點(diǎn)擊元素持續(xù)多久后可以開(kāi)始拖動(dòng)。在此之前移動(dòng)光標(biāo)超過(guò) 5px 將取消拖動(dòng)。 |
| :animation-duration | number | 250 | 單位毫秒。表示放置元素和重新排序的動(dòng)畫持續(xù)時(shí)間。 |
| :auto-scroll-enabled | boolean | true | 如果拖動(dòng)項(xiàng)目接近邊界,第一個(gè)可滾動(dòng)父項(xiàng)將自動(dòng)滾動(dòng) |
| :drag-class | string | undefined | 元素被拖動(dòng)中的添加的類(不會(huì)影響拖拽結(jié)束后元素的顯示) |
| :drop-class | string | undefined | 從拖拽元素被放置到被添加到頁(yè)面過(guò)程中添加的類。 |
| :remove-on-drop-out | boolean | undefined | 如果設(shè)置為 true,在被拖拽元素沒(méi)有被放置到任何相關(guān)容器時(shí),使用元素索引作為 removedIndex 調(diào)用 onDrop() |
| :drop-placeholder | boolean,object | undefined | 占位符的選項(xiàng)。包含 className, animationDuration, showOnTop 例如 dropPlaceholderOptions: { className: “drop-preview”, animationDuration: “150”, showOnTop: true, }, |
Container 屬性的使用
<Container
group-name="col"
@drop="(e) => onCardDrop(column.id, e)"
:get-child-payload="getCardPayload(column.id)"
drag-class="card-ghost"
drop-class="card-ghost-drop"
:drop-placeholder="dropPlaceholderOptions"
class="draggable-container"
>
<Draggable v-for="task in column.list" :key="task.id">
<div class="task-card">
<div class="task-title">{{ task.name }}</div>
<div
class="task-priority"
:style="{ background: priorityMap[task.priority].color }"
>
{{ priorityMap[task.priority].label }}
</div>
</div>
</Draggable>
</Container>
data() {
/// 拖拽時(shí)占位符樣式
dropPlaceholderOptions: {
className: "drop-preview",
animationDuration: "150",
showOnTop: true,
},
}
smooth-dnd 生命周期
一次拖動(dòng)的生命周期通過(guò)一系列回調(diào)和事件進(jìn)行描述和控制,下面以包含 3 個(gè)容器的示例為例進(jìn)行說(shuō)明
Mouse Calls Callback / Event Parameters Notes
down o Initial click
move o Initial drag
|
| get-child-payload() index Function should return payload // 自定義傳給 onDrop() 的payload對(duì)象。
|
| 3 x should-accept-drop() srcOptions, payload Fired for all containers // 用來(lái)確定容器是否可被放置,會(huì)覆蓋group-name屬性。
|
| 3 x drag-start dragResult Fired for all containers
|
| drag-enter
vmove o Drag over containers
|
| n x drag-leave Fired as draggable leaves container
| n x drag-enter Fired as draggable enters container
vup o Finish drag
should-animate-drop() srcOptions, payload Fires once for dropped container // 返回 false 則阻止放置動(dòng)畫
3 x drag-end dragResult Fired for all containers
n x drop dropResult Fired only for droppable containers
在每次拖動(dòng)開(kāi)始 (drag-start) 之前和每次拖動(dòng)結(jié)束 (drag-end)之前觸發(fā)should-accept-drop。
dragResult 參數(shù)配置 來(lái)源于 事件對(duì)象
(在事件處理函數(shù)中,可以傳遞一個(gè)參數(shù)e,這個(gè)參數(shù)我們叫做事件對(duì)象,也叫事件參數(shù)。事件對(duì)象e是系統(tǒng)傳遞過(guò)去,事件函數(shù)也是系統(tǒng)調(diào)用的。系統(tǒng)調(diào)用事件函數(shù)的時(shí)候,會(huì)給事件函數(shù)傳遞一個(gè)參數(shù),傳遞的參數(shù)具有具體值,可以在事件函數(shù)執(zhí)行時(shí)獲取e中攜帶的值。)
drag-start 中的 dragResult 參數(shù)格式
dragResult: {
payload, // 負(fù)載 可以理解為用來(lái)記錄被拖動(dòng)的對(duì)象
isSource, // 是否是被拖動(dòng)的容器本身
willAcceptDrop, // 是否可以被放置
}
drag-end 中的 dragResult 參數(shù)格式
dragResult: {
addedIndex, // 被放置的新添加元素的下標(biāo),沒(méi)有則為 null
removedIndex, // 將被移除的元素下標(biāo),沒(méi)有則為 null
payload, // 拖動(dòng)的元素對(duì)象,可通過(guò) getChildPayload 指定
droppedElement, // 放置的 DOM 元素
}
回調(diào)
回調(diào)在用戶交互之前和期間提供了額外的邏輯和檢查。
- get-child-payload(index)
自定義傳給 onDrop() 的 payload 對(duì)象。
<Container :get-child-payload="getChildPayload">
getChildPayload (index) {
return {
// generate custom payload data here
}
}
- should-accept-drop(sourceContainerOptions, payload)
在開(kāi)始拖放之前,所有容器都要調(diào)用的函數(shù)用來(lái)確定容器是否可被放置,會(huì)覆蓋 group-name 屬性。
<Container :should-accept-drop="shouldAcceptDrop">
shouldAcceptDrop (sourceContainerOptions, payload) {
return true;
}
- should-animate-drop(sourceContainerOptions, payload) 返回 false 則阻止放置動(dòng)畫。
<Container :should-animate-drop="shouldAnimateDrop">
shouldAnimateDrop (sourceContainerOptions, payload) {
return false;
}
- get-ghost-parent() 返回幽靈元素(拖動(dòng)時(shí)顯示的元素)應(yīng)該添加到的元素,默認(rèn)是父元素,某些情況定位會(huì)出現(xiàn)問(wèn)題,則可以選擇自定義,如返回 document.body。
<Container :get-ghost-parent="getGhostParent">
getGhostParent() {
// i.e return document.body;
}
事件
- @drag-start 在拖動(dòng)開(kāi)始時(shí)由所有容器發(fā)出的事件。參數(shù) dragResult。
<Container @drag-start="onDragStart">
onDragStart (dragResult) {
const { isSource, payload, willAcceptDrop } = dragResult
}
- @drag-end 所有容器在拖動(dòng)結(jié)束時(shí)調(diào)用的函數(shù)。 在 @drop 事件之前調(diào)用。參數(shù) dragResult。
- @drag-enter 每當(dāng)拖動(dòng)的項(xiàng)目在拖動(dòng)時(shí)進(jìn)入其邊界時(shí),相關(guān)容器要發(fā)出的事件。
- @drag-leave 每當(dāng)拖動(dòng)的項(xiàng)目在拖動(dòng)時(shí)離開(kāi)其邊界時(shí),相關(guān)容器要發(fā)出的事件。
- @drop-ready 當(dāng)容器中可能放置位置的索引發(fā)生變化時(shí),被拖動(dòng)的容器將調(diào)用的函數(shù)?;旧希看稳萜髦械目赏蟿?dòng)對(duì)象滑動(dòng)以打開(kāi)拖動(dòng)項(xiàng)目的空間時(shí)都會(huì)調(diào)用它。參數(shù) dropResult。
- @drop 放置結(jié)束時(shí)所有相關(guān)容器會(huì)發(fā)出的事件(放置動(dòng)畫結(jié)束后)。源容器和任何可以接受放置的容器都被認(rèn)為是相關(guān)的。參數(shù) dropResult。
API: Draggable
Draggable 容器子組件的包裝器。每個(gè)子元素都應(yīng)該用可拖動(dòng)組件包裝。
tag
同容器的 tag 指定可拖拽元素的 DOM 元素標(biāo)簽。 標(biāo)記名稱或節(jié)點(diǎn)定義來(lái)呈現(xiàn)Draggable的根元素。默認(rèn)值為’div’。
<Draggable v-for="column in taskColumnList" :key="column.name" :tag="{value: 'tr', props: {class: 'my-table-row'}}">
</Draggable>
// --------------或者-----------------
<Draggable v-for="column in taskColumnList" :key="column.name" tag="tr">
</Draggable>效果實(shí)現(xiàn)
Vue Smooth DnD 主要包含了兩個(gè)組件,Container 和 Draggable,Container 包含可拖動(dòng)的元素或組件,它的每一個(gè)子元素都應(yīng)該被 Draggable 包裹。
每一個(gè)要被設(shè)置為可拖動(dòng)的元素都需要被 Draggable 包裹
<template>
<div>
<div class="simple-page">
<Container @drop="onDrop">
<Draggable v-for="item in items" :key="item.id">
<div class="draggable-item">
{{ item.data }}
</div>
</Draggable>
</Container>
</div>
</div>
</template>
<script>
import { Container, Draggable } from "vue-smooth-dnd";
const applyDrag = (arr, dragResult) => {
const { removedIndex, addedIndex, payload } = dragResult;
console.log(removedIndex, addedIndex, payload);
if (removedIndex === null && addedIndex === null) return arr;
const result = [...arr];
let itemToAdd = payload;
if (removedIndex !== null) {
itemToAdd = result.splice(removedIndex, 1)[0];
}
if (addedIndex !== null) {
result.splice(addedIndex, 0, itemToAdd);
}
return result;
};
const generateItems = (count, creator) => {
const result = [];
for (let i = 0; i < count; i++) {
result.push(creator(i));
}
return result;
};
export default {
name: "Simple",
components: { Container, Draggable },
data() {
return {
items: generateItems(50, (i) => ({ id: i, data: "Draggable " + i })),
};
},
methods: {
onDrop(dropResult) {
this.items = applyDrag(this.items, dropResult);
},
},
};
</script>
<style>
.draggable-item {
height: 50px;
line-height: 50px;
text-align: center;
display: block;
background-color: #fff;
outline: 0;
border: 1px solid rgba(0, 0, 0, 0.125);
margin-bottom: 2px;
margin-top: 2px;
cursor: default;
user-select: none;
}
</style>

項(xiàng)目中實(shí)現(xiàn) – 拖拽位置無(wú)法確定
smooth 的 :orientation 屬性限制了容器拖拽的方式,占位為一行默認(rèn)為 vertical ,默認(rèn)占位容器的一行
vuedraggable
安裝
yarn add vuedraggable
引入
import draggable from 'vuedraggable'
demo
<template>
<div class="app-container">
<div :class="canEdit? 'dargBtn-lock el-icon-unlock': 'dargBtn-lock el-icon-lock' " @click="removeEvent()">{{canEdit? '調(diào)整':'鎖定'}}</div>
<ul class="projset-content">
<draggable
:forceFallback="true"
:move="onMove"
:list="imgList"
handle=".dargBtn"
:animation="1000"
filter=".undraggable"
fallbackClass="fallbackStyle"
ghostClass="item_ghost"
chosenClass="chosenStyle"
dragClass="dragStyle"
>
<li v-for="(item, index) in imgList" :key="index" :class="canEdit ? 'draggable' : 'undraggable'">
<div class="dargBtn">
<svg-icon icon-class="drag" />
</div>
<img :src="item.path" alt="">
<span>{{item.name}}</span>
</li>
</draggable>
</ul>
</div>
</template>
<script>
import draggable from 'vuedraggable';
export default {
components: { draggable},
data(){
return{
canEdit:true,
imgList: [
{
path: 'https://lupic.cdn.bcebos.com/20210629/3000005161_14.jpg',
name: '1',
},
{
path: 'https://lupic.cdn.bcebos.com/20210629/26202931_14.jpg',
name: '2',
},
{
path: 'https://lupic.cdn.bcebos.com/20210629/27788166_14.jpg',
name: '3',
}
]
}
},
created() {
},
mounted(){},
methods:{
onMove(relatedContext, draggedContext){
console.log(relatedContext.relatedContext.list);
},
removeEvent (item) {
if(this.canEdit){
this.canEdit = false;
}else{
this.canEdit = true;
}
console.log(this.canEdit);
}
}
}
</script>
<style scoped lang="scss">
.app-container{
background: #ffffff;
height: 100%;
.dargBtn-lock{
margin: 0px 50px;
color: #2ea9df;
}
.dragStyle {
padding: 10px;
border-radius: 4px;
opacity: 1;
}
.fallbackStyle{
padding: 10px;
border-radius: 4px;
opacity: 1;
}
.chosenStyle {
padding: 10px;
border-radius: 4px;
opacity: 1 !important;
}
.item_ghost {
opacity: 0 !important;
}
.projset-content{
list-style-type: none;
position: relative;
li{
display: inline-block;
margin: 10px;
}
img{
width: 141px;
height: 100px;
}
span{
justify-content: center;
display: flex;
}
.dargBtn{
position: absolute;
line-height: 100px;
text-align: center;
width: 141px;
height: 100px;
display: none;
color: white;
// background: rgba(101, 101, 101, 0.6);
}
.draggable{
cursor: pointer;
width: 141px;
height: 100px;
}
.draggable:hover .dargBtn{
display: block;
}
}
}
</style>

參數(shù)說(shuō)明
| 參數(shù) | 類型 | 說(shuō)明 |
|---|---|---|
| group | String/ Array group=“name” | 用于分組, 同一組的不同list可以相互拖動(dòng) |
| list | Array | 設(shè)置拖拽元素 |
| sort | Boolean :sort=“true” | 是否開(kāi)啟內(nèi)部排序, 如果設(shè)為 false 則它所在的組無(wú)法排序 |
| delay | Number :delay=“0” | 鼠標(biāo)選中后可以開(kāi)始拖拽的延遲時(shí)間 |
| touchStartThreshold | Number :touchStartThreshold=“5” | 鼠標(biāo)移動(dòng)多少px才可以拖動(dòng)元素 |
| disabled | Boolean :disabled=“true” | 是否啟用拖拽組件 |
| animation | Number :animation="1000"單位 ms | 拖動(dòng)時(shí)過(guò)渡動(dòng)畫效果 |
| handle | Selector handle=“.card-title” | 拖動(dòng)手柄,鼠標(biāo)移動(dòng)到 css 名為 card-title 的選擇器時(shí)才能成為拖動(dòng)手柄進(jìn)行拖動(dòng) |
| filter | Selector filter=“.unmover” | 通過(guò)選擇器設(shè)置哪些樣式的元素不能被拖動(dòng) 多個(gè)選擇器用 ‘,’ 分隔 |
| preventOnFilter | Boolean :preventOnFilter="true"默認(rèn)觸發(fā) | 當(dāng)拖動(dòng)filter時(shí)是否觸發(fā) event.preventDefault() |
| draggable | Selector draggable=“.item” | 哪些元素時(shí)可以進(jìn)行拖動(dòng)的 |
| ghostClass | ghostClass=“ghost-style” | 設(shè)置拖拽元素的占位符樣式 模擬被拖動(dòng)元素的排序情況,自定義樣式可能需要添加 !important 才能生效(forceFallback 屬性設(shè)置味 true) |
| chosenClass | chosenClass=“chosen-style” | 設(shè)置目標(biāo)被選中時(shí)的樣式(包括拖拽時(shí)鼠標(biāo)附著的樣式)自定義樣式可能需要添加 !important 才能生效(forceFallback 屬性設(shè)置味 true) |
| dragClass | dragClass=“drag-style” | 拖動(dòng)元素過(guò)程中添加的樣式,自定義樣式可能需要添加 !important 才能生效(forceFallback 屬性設(shè)置味 true) |
| dataIdAttr | Selector dataIdAttr=”data-id“ | 不太清楚 |
| forceFallback | forceFallback=“true” 默認(rèn)為false | 設(shè)為 true 時(shí)將不使用原生的html5 的拖放,可修改拖放過(guò)程中的樣式 |
| fallbackClass | fallback-class=“dragging_style” | forceFallback=“true” 時(shí),克隆出新的DOM元素類名,可修改拖放過(guò)程中鼠標(biāo)附著的樣式 |
| allbackOnBody | Boolean 默認(rèn)為false | allbackOnBody=“true” 時(shí)將克隆的元素添加到文檔的body中 |
| fallbackTolerance | Number 單位 px | 拖拽之前應(yīng)該移動(dòng)的距離 |
| scroll | Boolean 默認(rèn)為true | 當(dāng)排序的容器是個(gè)可滾動(dòng)的區(qū)域,拖放是否能引起區(qū)域滾動(dòng) |
| scrollFn | Function | 滾動(dòng)回調(diào)函數(shù),用于自定義滾動(dòng)條的適配 |
| scrollSensitivity | Number 默認(rèn)30 | 距離滾動(dòng)區(qū)域多遠(yuǎn)時(shí)滾動(dòng)條滾動(dòng),鼠標(biāo)靠近邊緣多遠(yuǎn)時(shí)開(kāi)始滾動(dòng) |
| scorllSpeed | Number | 滾動(dòng)速度 |
事件
| 參數(shù) | 說(shuō)明 | 回調(diào)參數(shù) |
|---|---|---|
| start | 開(kāi)始拖動(dòng)時(shí) | function({ to, from, item, clone, oldIndex, newIndex }) |
| add | 往列表中移入(添加)單元時(shí) | function({ to, from, item, clone, oldIndex, newIndex }) |
| remove | 單元被移動(dòng)到另一個(gè)列表(從當(dāng)前的列表移處)時(shí) | function({ to, from, item, clone, oldIndex, newIndex }) |
| update | 排序發(fā)生變化時(shí) | function({ to, from, item, clone, oldIndex, newIndex }) |
| end | 拖拽結(jié)束時(shí) | function({ to, from, item, clone, oldIndex, newIndex }) |
| choose | 選擇單元格時(shí) | function({ to, from, item, clone, oldIndex, newIndex }) |
| sort | 排序發(fā)生變化時(shí) | function({ to, from, item, clone, oldIndex, newIndex }) |
| filter | 嘗試選擇一個(gè)被filter過(guò)濾的單元時(shí) | function({ to, from, item, clone, oldIndex, newIndex }) |
| clone | clone 復(fù)制出單元格時(shí)觸發(fā) | function({ to, from, item, clone, oldIndex, newIndex }) |
最佳事件
<transition>
<draggable
:delay="300"
:fallback-tolerance="0"
:list="dragList"
:force-fallback="true"
fallback-class="dragging_style"
handle=".card-title"
drag-class="drag-style"
ghost-class="ghost-style"
chosen-class="chosen-style"
@update="handleUpdateDrag"
class="home-drag-wrapper">
<div v-for=" item in dragList" :key="item.id" :class="item.className" class="home-part">
<component :is="item.name" :ref="item.name" class="drag-handle " :class=" item.id !== 1? (item.id !== 2? 'card': ''):''"> </component>
</div>
</draggable>
</transition>
.ghost-style {
opacity: 0;
cursor: grabbing !important;
}
.chosen-style {
background-color: rgba(242, 245, 250, .5);
border-radius: 8px;
z-index: 1000;
box-shadow: 0px 3px 28px #BAC4D4;
cursor: grabbing !important;
}
.dragging-style {
border: 1px solid yellow;
}
.drag-style {
background-color: rgba(242, 245, 250, .5);
border-radius: 8px;
z-index: 1000;
box-shadow: 0px 3px 28px #BAC4D4;
opacity: 1 !important;
}
ghost-class 為排序中的占位樣式。
chosen-class 占位符、拖動(dòng)過(guò)程中鼠標(biāo)附著的副本樣式的共同樣式。
設(shè)置 :force-fallback=“true” 可修改拖放過(guò)程中的樣式
fallback-class 設(shè)置鼠標(biāo)附著的副本樣式, 通過(guò) !important 提升樣式優(yōu)先級(jí)。
drag-class 拖拽過(guò)程中的樣式(鼠標(biāo)附著樣式 opacity: 1 !important; 設(shè)置副本的透明度)。
在拖拽過(guò)程中配置的類名作用的相應(yīng)區(qū)域:


總結(jié)
通過(guò)試用多個(gè)不同的組件庫(kù),恍惚比較總結(jié),最后在項(xiàng)目重采用vuedraggable,因?yàn)樵摻M件的實(shí)現(xiàn)方式簡(jiǎn)單,并且能夠靈活控制拖拽的樣式,達(dá)到所需的效果。
到此這篇關(guān)于vue中實(shí)現(xiàn)拖拽排序功能的文章就介紹到這了,更多相關(guān)vue實(shí)現(xiàn)拖拽排序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
參考
smooth- dnd 參考自 : https://blog.51cto.com/u_15127632/4038149
vuedraggable 參考自:https://blog.csdn.net/Kiruthika/article/details/123903706
相關(guān)文章
Vue數(shù)據(jù)驅(qū)動(dòng)表單渲染,輕松搞定form表單
這篇文章主要介紹了Vue數(shù)據(jù)驅(qū)動(dòng)表單渲染,輕松搞定form表單,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07
淺談 Vue v-model指令的實(shí)現(xiàn)原理
vue的v-model是一個(gè)十分強(qiáng)大的指令,它可以自動(dòng)讓原生表單組件的值自動(dòng)和你選擇的值綁定,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
淺談Vue內(nèi)置component組件的應(yīng)用場(chǎng)景
這篇文章主要介紹了淺談Vue內(nèi)置component組件的應(yīng)用場(chǎng)景,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-03-03
詳解vue-cli 3.0 build包太大導(dǎo)致首屏過(guò)長(zhǎng)的解決方案
這篇文章主要介紹了詳解vue-cli 3.0 build包太大導(dǎo)致首屏過(guò)長(zhǎng)的解決方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-11-11
vue3使用localStorage實(shí)現(xiàn)登錄注冊(cè)功能實(shí)例
這篇文章主要給大家介紹了關(guān)于vue3使用localStorage實(shí)現(xiàn)登錄注冊(cè)功能的相關(guān)資料, localStorage這個(gè)特性主要是用來(lái)作為本地存儲(chǔ)來(lái)使用的,解決了cookie存儲(chǔ)空間不足的問(wèn)題,需要的朋友可以參考下2023-06-06
vue中想要mock數(shù)據(jù)在線上環(huán)境生效如何操作
本文主要介紹了在配置了mock數(shù)據(jù)之后在線上環(huán)境使用,主要通過(guò)在main.ts文件中注冊(cè)和vite.config.ts文件夾中配置插件來(lái)實(shí)現(xiàn),感興趣的可以了解一下2025-01-01

