vue3使用拖拽組件draggable.next的保姆級(jí)教程
環(huán)境:vue3+setup語(yǔ)法
首先放官方文檔的鏈接:
中文版本: https://www.itxst.com/vue-draggable-next/tutorial.html (民間翻譯)
英文版本:https://github.com/SortableJS/vue.draggable.next
因?yàn)樽约簩?xiě)的過(guò)程中,官方文檔和網(wǎng)上的資料都非常不明,使用版本各不相同,極易踩坑,自己寫(xiě)完后就總結(jié)一下,與諸位共勉。
(一)首先,明確需求:
做一個(gè)可重復(fù)拖拽生成的表格設(shè)計(jì)器,效果圖如下:
(二)搭一個(gè)基本的可互相拖拽的框架
(1)在終端使用npm命令下載插件
npm i -S vuedraggable@next //導(dǎo)入 import draggable from 'vuedraggable'
(2)拖拽插件大致可分為兩種使用方式——分組拖拽與單組拖拽
單組拖拽為只有一組數(shù)據(jù),而拖拽是交換此組數(shù)據(jù)內(nèi)部的位置,如下圖所示:
而互相拖拽是有兩組數(shù)據(jù),兩組數(shù)據(jù)可以各自內(nèi)部換順序,可以相互拖拽到對(duì)方的數(shù)組中。
本文需求只用到了互相拖拽,互相拖拽的代碼形式如下:
//需要克隆的數(shù)據(jù),A組 <draggable :list="dragList" ghost-class="ghost" :force-fallback="true" :group="{ name: 'list', pull: 'clone' }" :sort="false" itemKey="id"> <template #item="{ element }"> <div class="item move"> <label class="move">{{ element.name }}</label> </div> </template> </draggable> //拖拽的結(jié)果,B組 <draggable :list="widgetList" ghost-class="ghost" itemKey="id" :force-fallback="true" group="list" :fallback-class="true" :fallback-on-body="true"> <template #item="{ element }"> <div class="item move"> <label class="move">{{ element.name }}</label> </div> </template> </draggable> <script lang="ts" setup> import draggable from 'vuedraggable' interface type { name: string, id: number } const dragList: type[] = reactive<type[]>([ { name: "單行文本", id: 1 }, { name: "多行文本", id: 2 }, { name: "計(jì)數(shù)器", id: 3 }, { name: "單選框組", id: 4 }, ]) const widgetList = reactive<type[]>([ { name: "多行文本", id: 2 }, ])
draggable的一些常用的屬性我作了整理,方便根據(jù)不同的需求取用,可核對(duì)表格填寫(xiě):
屬性 | 說(shuō)明 | 類型 | 是否必填 |
group | 如果是分組拖拽,可通過(guò)設(shè)置group的name來(lái)實(shí)現(xiàn)分類。 pull屬性代表拖出,put為拖入, :group="{ name :'list',pull : true, put: false }" 代表這個(gè)分組與其他name為list的分組可實(shí)現(xiàn)分組拖拽,此分組允許拖出,不允許拖入,pull為‘clone’則代表clone模式,pull與put可寫(xiě)可不寫(xiě),默認(rèn)值都為true | Object / string | 否 (分組拖拽時(shí)必填) |
list | 綁定的數(shù)據(jù) | Array | 是 |
sort | 是否開(kāi)啟排序功能,默認(rèn)為true,如果設(shè)置為false,它所在組無(wú)法排序 | Boolean | 否 |
force-fallback | 默認(rèn)false,忽略HTML5的拖拽行為,因?yàn)閔5里有個(gè)屬性也是可以拖動(dòng),你要自定義ghostClass chosenClass dragClass樣式時(shí),建議forceFallback設(shè)置為true | Boolean | 否 (設(shè)置ghost-class或drag-class時(shí)為必填) |
ghost-class | :ghostClass=“ghostClass” 設(shè)置拖動(dòng)元素的占位符類名,可以將拖動(dòng)時(shí)的元素設(shè)置為不同的樣式。自定義樣式可能需要加!important才能生效,并把forceFallback屬性設(shè)置成true。 | String | 否 |
disabled | 是否禁用,默認(rèn)false | Boolean | 否 |
drag-class | :drag-class="dragClass"拖動(dòng)元素的樣式,你的自定義樣式可能需要加!important才能生效,并把forceFallback屬性設(shè)置成true | Boolean | 否 |
item-key | 每個(gè)元素唯一的標(biāo)識(shí),建議使用id itemKey='id',注意,此處無(wú)需寫(xiě)成變量形式 | String | 是 (不填也能運(yùn)行,但控制臺(tái)會(huì)報(bào)警告) |
到現(xiàn)在為止,這已經(jīng)是個(gè)互相拖拽的組件了。
(3)如果發(fā)現(xiàn)自己寫(xiě)的組件 不能進(jìn)行拖拽,或者網(wǎng)頁(yè)上不顯示組件 ,或者出現(xiàn)紅色報(bào)錯(cuò)信息,則檢查以下注意點(diǎn) :
- group中name是否一致,group為變量,需要 :group =‘{name:'' }’的形式
- AB組的元素要實(shí)現(xiàn)互相拖拽,元素的數(shù)據(jù)結(jié)構(gòu)必須完全一致,如果不放心,可以使用interface來(lái)定義一個(gè)類型諸如 interface itemType { name : string , id:number }
- AB組綁定的數(shù)組是否為響應(yīng)式,如非響應(yīng)式,會(huì)發(fā)生拖拽成功,但不能及時(shí)響應(yīng)的情況,可以用這個(gè)方法自檢-->先進(jìn)行拖拽,然后在代碼的html部分隨便加個(gè)東西,然后保存,觀察網(wǎng)頁(yè)上是否顯示剛才拖拽的內(nèi)容,如果出現(xiàn),那就是數(shù)組非響應(yīng)式的問(wèn)題。
改正:const arr = reactive<itemType[]>([ { name : 'name ' , id : 1 } ]) - 在新版vue3中,item插槽是必寫(xiě)的部分,不能使用v-for循環(huán)替代。
<draggable> <template #item="{ element }"> <div class="item move"> <label class="move">{{ element.name }}</label> </div> </template> </draggable>
5.item插槽中只允許有一個(gè)子元素,此處有個(gè)坑,就是如果有兩個(gè)子元素,但注釋掉了一個(gè),也會(huì)報(bào)錯(cuò)。哪怕實(shí)際上這只有一個(gè)子元素。
//正確的 <template #item="{ element }"> <div class="item move"> <label class="move">{{ element.name }}</label> </div> </template> //會(huì)報(bào)錯(cuò)的情況! <template #item="{ element }"> <!-- <div class="class"></div> --> <div class="item move"> <label class="move">{{ element.name }}</label> </div> </template>
到此為止,已經(jīng)實(shí)現(xiàn)拖拽成功。有些人可能會(huì)碰到這個(gè)問(wèn)題————如果B組為空,向B組內(nèi)拖第一個(gè)組件的時(shí)候,會(huì)出現(xiàn)拖拽困難,只能往拖拽區(qū)的最頂部拖才能成功 / 根本無(wú)法拖拽成功。
原因:因?yàn)锽組的draggable渲染時(shí)為一個(gè)高度為auto的div,當(dāng)前組如果為空,高度也為0,可拖拽區(qū)就會(huì)變得很小或不存在。
解決方法:為B組的draggable設(shè)計(jì)高度,具體代碼為添加類名,在css中設(shè)置
<draggable :list="widgetList" ghost-class="ghost" itemKey="id" :force-fallback="true" group="list" :fallback-class="true" :fallback-on-body="true" class="drag-content"> <template #item="{ element }"> <div class="item move"> <label class="move">{{ element.name }}</label> </div> </template> </draggable> <style lang="less" scoped> .drag-content { height:500px; //建議是外層嵌套一層div,div固定高,此處再設(shè)為100% } </style>
(三)將拖拽后的內(nèi)容替換為element組件/其它指定內(nèi)容
我們發(fā)現(xiàn),拖拽后顯示的內(nèi)容可自由定義,在B組的draggable中設(shè)置
此時(shí),我們需要完善dragList的數(shù)組結(jié)構(gòu),來(lái)映射拖拽后所形成的不同組件
(在組件少的情況下可以這么做)
interface itemType { name: string, id: number, element:string } const dragList: type[] = reactive<type[]>([ { name: "單行文本", id: 1, element: 'Input' }, { name: "多行文本", id: 2, element: 'Textarea' }, { name: "計(jì)數(shù)器", id: 3, element: 'InputNumber' }, { name: "單選框組", id: 4, element: 'Radio' }, ]) const widgetList = reactive<type[]>([ ])
// A組 <draggable :list="dragList" ghost-class="ghost" :force-fallback="true" :group="{ name: 'list', pull: 'clone' }" :sort="false" itemKey="id"> <template #item="{ element }"> <div class="item move"> <label class="move">{{ element.name }}</label> </div> </template> </draggable> // B組 <draggable :list="widgetList" ghost-class="ghost" itemKey="id" :force-fallback="true" group="list" :fallback-class="true" :fallback-on-body="true" class="drag-content"> <template #item="{ element }"> <div class="item move"> <label class="move title">{{ element.name }}</label> <div> <el-input v-model="input" placeholder="Please input" v-if="element.element === 'input'" /></div> <div><el-input v-model="textarea" :rows="2" type="textarea" placeholder="Please input" v-if="element.element === 'textarea'" /> </div> </div> </template> </draggable>
點(diǎn)擊控件拖過(guò)去,就可以實(shí)現(xiàn)如下的效果,如果不想要標(biāo)題,可以把label部分去掉,其他控件如法炮制即可:
在組件數(shù)量少的時(shí)候,可以這么做,但數(shù)量多時(shí),建議使用component標(biāo)簽來(lái)映射
(1)先更改一下文件的結(jié)構(gòu)
(2)寫(xiě)一個(gè)公共的函數(shù)去返回當(dāng)前widgets文件夾下的所有文件
// getWidget.ts const gets = {} as any const modules = import.meta.glob('./*.vue', {eager:true}) for (let each in modules) { const name = (modules[each] as any).default.__name gets[name] = (modules[each] as any).default } console.log(gets); export default gets
也可使用globEager方法,編譯器會(huì)報(bào)錯(cuò):函數(shù)已經(jīng)棄用,不過(guò)不影響使用。
(3)分別把每個(gè)組件的部分寫(xiě)好
// Input.vue <template> <div> <el-input v-model="input" placeholder="Please input" /> </div> </template> <script lang="ts" setup> const input=ref('') </script> <style lang="less" scoped> </style>
(四)使用component標(biāo)簽映射
<draggable :list="widgetList" ghost-class="ghost" itemKey="id" :force-fallback="true" group="list" :fallback-class="true" :fallback-on-body="true" class="drag-content"> <template #item="{ element }"> <div class="item move"> <label class="move title">{{ element.name }}</label> <div> <component :is="getWidget(element.element)"></component> </div> </div> </template> </draggable> // 使用函數(shù)映射 <script lang="ts" setup> import draggable from 'vuedraggable' //要注意導(dǎo)入 import getName from './widgets/getWidget' const getWidget = (name: string) => { //寫(xiě)的時(shí)候,組件的起名一定要與dragList中的element名字一模一樣,不然會(huì)映射不上 return getName[name] }
(五)最終效果
成功實(shí)現(xiàn)!
總結(jié)
到此這篇關(guān)于vue3使用拖拽組件draggable.next的保姆級(jí)教程的文章就介紹到這了,更多相關(guān)vue3拖拽組件draggable.next內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決vue中對(duì)象屬性改變視圖不更新的問(wèn)題
下面小編就為大家分享一篇解決vue中對(duì)象屬性改變視圖不更新的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-02-02一文帶你了解threejs在vue項(xiàng)目中的基本使用
three.js是一個(gè)用于在Web上創(chuàng)建三維圖形的JavaScript庫(kù),它可以用于創(chuàng)建各種類型的三維場(chǎng)景,包括游戲、虛擬現(xiàn)實(shí)、建筑和產(chǎn)品可視化等,下面這篇文章主要給大家介紹了關(guān)于如何通過(guò)一文帶你了解threejs在vue項(xiàng)目中的基本使用,需要的朋友可以參考下2023-04-04vscode搭建vue環(huán)境完整圖文教程(適合新手小白)
Vue框架的優(yōu)秀設(shè)計(jì)和強(qiáng)大的生態(tài)系統(tǒng)成為了越來(lái)越多開(kāi)發(fā)者選擇Vue的原因,在實(shí)際項(xiàng)目過(guò)程中一個(gè)高效的開(kāi)發(fā)環(huán)境能夠大大提高開(kāi)發(fā)效率,這篇文章主要給大家介紹了關(guān)于vscode搭建vue環(huán)境的相關(guān)資料,需要的朋友可以參考下2023-10-10vue子組件通過(guò).sync修飾符修改props屬性方式
這篇文章主要介紹了vue子組件通過(guò).sync修飾符修改props屬性方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08vue實(shí)現(xiàn)子路由調(diào)用父路由的方法
這篇文章主要介紹了vue實(shí)現(xiàn)子路由調(diào)用父路由的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06vue實(shí)力踩坑?當(dāng)前頁(yè)push當(dāng)前頁(yè)無(wú)效的解決
這篇文章主要介紹了vue實(shí)力踩坑?當(dāng)前頁(yè)push當(dāng)前頁(yè)無(wú)效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04