vue-draggable實現(xiàn)拖拽表單的示例代碼
draggable在項目中的實際應(yīng)用
這個功能為公司做的項目中的一個功能,要求能拖拽配置表單,并且能實現(xiàn)實時計算,本文講述的是拖拽表單組件,配置出對應(yīng)的算法的實現(xiàn)
1. 介紹及配置項
1.1 特性
使用版本: vue.draggable.next
vue.draggable.next
是一款vue3
的拖拽插件,是vue.draggable
升級版本。Vue.Draggable
是一款基于Sortable.js
實現(xiàn)的vue
拖拽插件。
特性:
- 支持移動設(shè)備
- 拖拽和選擇文本
- 智能滾動
- 可以在不同列表間拖拽
- 不依賴jQuery為基礎(chǔ)
- vue 2過渡動畫兼容
- 支持撤銷操作
1.2 配置項
屬性說明:
屬性名稱 | 說明 |
---|---|
modelValue | 傳入數(shù)組到可拖動組件。通常與內(nèi)部元素v-for指令引用的數(shù)組相同。 |
list | 與modelValue類似,主要的區(qū)別是list拖動組件是使用splice方法更新的,而modelValue是不可變的。 |
group | 如果一個頁面有多個拖拽區(qū)域,通過設(shè)置group名稱可以實現(xiàn)多個區(qū)域之間相互拖拽 或者 { name: "...", pull: [true, false, 'clone', array , function], put: [true, false, array , function] } |
sort | 是否開啟排序,如果設(shè)置為false,它所在組無法排序 |
delay | 鼠標按下多少秒之后可以拖拽元素 |
touchStartThreshold | 鼠標按下移動多少px才能拖動元素 |
disabled | :disabled= "true",是否啟用拖拽組件 |
animation | 拖動時的動畫效果,如設(shè)置animation=1000表示1秒過渡動畫效果 |
handle | :handle=".mover" 只有當鼠標在class為mover類的元素上才能觸發(fā)拖到事件 |
filter | :filter=".unmover" 設(shè)置了unmover樣式的元素不允許拖動 |
draggable | :draggable=".item" 樣式類為item的元素才能被拖動 |
ghost-class | :ghost-class="ghostClass" 設(shè)置拖動元素的占位符類名,你的自定義樣式可能需要加!important才能生效,并把forceFallback屬性設(shè)置成true |
chosen-class | :ghost-class="hostClass" 被選中目標的樣式,你的自定義樣式可能需要加!important才能生效,并把forceFallback屬性設(shè)置成true |
drag-class | :drag-class="dragClass"拖動元素的樣式,你的自定義樣式可能需要加!important才能生效,并把forceFallback屬性設(shè)置成true |
force-fallback | 默認false,忽略HTML5的拖拽行為,因為h5里有個屬性也是可以拖動,你要自定義ghostClass chosenClass dragClass樣式時,建議forceFallback設(shè)置為true |
fallback-class | 默認false,克隆選中元素的樣式到跟隨鼠標的樣式 |
fallback-on-body | 默認false,克隆的元素添加到文檔的body中 |
fallback-tolerance | 按下鼠標移動多少個像素才能拖動元素,:fallback-tolerance="8" |
scroll | 默認true,有滾動區(qū)域是否允許拖拽 |
scroll-fn | 滾動回調(diào)函數(shù) |
scroll-fensitivity | 距離滾動區(qū)域多遠時,滾動滾動條 |
scroll-speed | 滾動速度 |
1.3 示例
安裝
npm i -S vuedraggable@next
普通拖拽
<template> ?<div class="itxst"> ? ?<div> ? ? ?<draggable ? ? ? ?:list="state.list" ? ? ? ?ghost-class="ghost" ? ? ? ?chosen-class="chosenClass" ? ? ? ?animation="300" ? ? ? ?@start="onStart" ? ? ? ?@end="onEnd" ? ? ?> ? ? ? ?<template #item="{ element }"> ? ? ? ? ?<div class="item"> ? ? ? ? ? ?{{ element.name }} ? ? ? ? ?</div> ? ? ? ?</template> ? ? ?</draggable> ? ?</div> ? ?<div>{{ state.list }}</div> ?</div> </template> <script setup> import { ref, reactive } from "vue"; import draggable from "vuedraggable"; /* draggable 對CSS樣式?jīng)]有什么要求萬物皆可拖拽 :list="state.list" ? ? ? ? //需要綁定的數(shù)組 ghost-class="ghost" ? ? ? //被替換元素的樣式 chosen-class="chosenClass" //選中元素的樣式 animation="300" ? ? ? ? ? //動畫效果 @start="onStart" ? ? ? ? ? //拖拽開始的事件 @end="onEnd" ? ? ? ? ? ? ? //拖拽結(jié)束的事件 */ const state = reactive({ ?//需要拖拽的數(shù)據(jù),拖拽后數(shù)據(jù)的順序也會變化 ?list: [ ? { name: "www.itxst.com", id: 0 }, ? { name: "www.baidu.com", id: 1 }, ? { name: "www.google.com", id: 2 }, ], }); ? //拖拽開始的事件 const onStart = () => { ?console.log("開始拖拽"); }; ? //拖拽結(jié)束的事件 const onEnd = () => { ?console.log("結(jié)束拖拽"); }; </script> <style scoped> .itxst { ?width: 600px; ?display: flex; } .itxst > div:nth-of-type(1) { ?flex: 1; } .itxst > div:nth-of-type(2) { ?width: 270px; ?padding-left: 20px; } .item { ?border: solid 1px #eee; ?padding: 6px 10px; ?text-align: left; } ? .item:hover { ?cursor: move; } .item + .item { ?margin-top: 10px; } .ghost { ?border: solid 1px rgb(19, 41, 239); } .chosenClass { ?background-color: #f1f1f1; } </style>
在表格中的拖拽
<template> ?<div> ? ?<div class="title">鼠標放到ID列和行上試試 可以拖拽行和列</div> ? ?<table class="tb"> ? ? ?<thead> ? ? ? ?<draggable ? ? ? ? ?v-model="state.headers" ? ? ? ? ?animation="200" ? ? ? ? ?tag="tr" ? ? ? ? ?:item-key="(key) => key" ? ? ? ?> ? ? ? ? ?<template #item="{ element: header }"> ? ? ? ? ? ?<th class="move"> ? ? ? ? ? ? ?{{ header }} ? ? ? ? ? ?</th> ? ? ? ? ?</template> ? ? ? ?</draggable> ? ? ?</thead> ? ? ?<draggable ? ? ? ?:list="state.list" ? ? ? ?handle=".move" ? ? ? ?animation="300" ? ? ? ?@start="onStart" ? ? ? ?@end="onEnd" ? ? ? ?tag="tbody" ? ? ? ?item-key="name" ? ? ?> ? ? ? ?<template #item="{ element }"> ? ? ? ? ?<tr> ? ? ? ? ? ?<td ? ? ? ? ? ? ?class="move" ? ? ? ? ? ? ?v-for="(header, index) in state.headers" ? ? ? ? ? ? ?:key="header" ? ? ? ? ? ?> ? ? ? ? ? ? ?{{ element[header] }} ? ? ? ? ? ?</td> ? ? ? ? ?</tr> ? ? ? ?</template> ? ? ?</draggable> ? ?</table> ?</div> </template> <script setup> import { ref, reactive } from "vue"; import draggable from "vuedraggable"; /* draggable 對CSS樣式?jīng)]有什么要求萬物皆可拖拽 :list="state.list" ? ? ? ? //需要綁定的數(shù)組 animation="300" ? ? ? ? ? //動畫效果 @start="onStart" ? ? ? ? ? //拖拽開始的事件 @end="onEnd" ? ? ? ? ? ? ? //拖拽結(jié)束的事件 */ const state = reactive({ ?//列的名稱 ?headers: ["id", "name", "intro"], ?//需要拖拽的數(shù)據(jù),拖拽后數(shù)據(jù)的順序也會變化 ?list: [ ? { name: "www.itxst.com", id: 0, intro: "慢吞吞的蝸牛" }, ? { name: "www.baidu.com", id: 1, intro: "中文搜索引擎" }, ? { name: "www.google.com", id: 3, intro: "安卓操作系統(tǒng)" }, ], }); ? //拖拽開始的事件 const onStart = () => { ?console.log("開始拖拽"); }; ? //拖拽結(jié)束的事件 const onEnd = () => { ?console.log("結(jié)束拖拽"); }; </script> <style scoped> .title { ?padding: 3px; ?font-size: 13px; } .itxst { ?width: 600px; } ? .move { ?cursor: move; } ? table.tb { ?color: #333; ?border: solid 1px #999; ?font-size: 13px; ?border-collapse: collapse; ?min-width: 500px; ?user-select: none; } table.tb th { ?background: rgb(168 173 217); ?border-width: 1px; ?padding: 8px; ?border-style: solid; ?border-color: #999; ?text-align: left; } table.tb th:nth-of-type(1) { ?text-align: center; } table.tb td { ?background: #d6c8c8; ?border-width: 1px; ?padding: 8px; ?border-style: solid; ?border-color: #999; } table.tb td:nth-of-type(1) { ?text-align: center; } </style>
2. Vue3項目應(yīng)用
示例:
基礎(chǔ)工具拖拽部分實現(xiàn)
<template> ? ?<div class="list-title"><span>基礎(chǔ)工具</span></div> ? ?<draggable ? ? ? ? ? ? ? :list="componentsList.base" ? ? ? ? ? ? ? :group="{ name: 'people', pull: 'clone', put: false }" ? ? ? ? ? ? ? :sort="false" // 不排序 ? ? ? ? ? ? ? :clone="cloneElement" // 克隆事件 ? ? ? ? ? ? ? :move="onMove" // 移動事件 ? ? ? ? ? ? ? item-key="id" ? ? ? ? ? ? ? class="draggable-list" ? ? ? ? ? ? ? :forceFallback="true" ? ? ? ? ? ? ? > ? ? ? ?<template #item="{ element }"> ? ? ? ? ? ?<div ? ? ? ? ? ? ? ? class="list-group-item" ? ? ? ? ? ? ? ? @click="onChooseComponent(element)" ? ? ? ? ? ? ? ? :class="{ 'active-element': currentSelectElement.id === element.id }" ? ? ? ? ? ? ? ? > ? ? ? ? ? ? ? ?<i :class="['iconfont', element.icon]"></i>{{ element.name }} ? ? ? ? ? ?</div> ? ? ? ?</template> ? ?</draggable> </template> ? <script setup> /** * 復制元素 * @param {Object} param0 */ let cloneId = '' const cloneElement = ({ id, type, name }) => { ?let ele = createNewElement(type) ?cloneId = ele.id ?console.log(ele) ?return ele } ? ? /** * 組件移動時,判斷移動位置是否為最外層 */ const onMove = (evt, originalEvent) => { ?if ( ? (evt.draggedContext.element.type === 1 || evt.draggedContext.element.type === 2) && ? ?props.computeUnitList.findIndex((item) => item.type === evt.draggedContext.element.type) === -1 ) { ? ?// 外部數(shù)據(jù)或公共數(shù)據(jù)拖向最外層 ? ?emit('handleListChange') ? ?return true } ? ?if ( ? (evt.draggedContext.element.type === 1 || evt.draggedContext.element.type === 2) && ? ?evt.to.className.indexOf('dragUnitArea') === -1 ) { ? ?// 外部數(shù)據(jù)或公共數(shù)據(jù)不是拖向最外層 ? ?return false } ?console.log(evt) ?if ( ? ?evt.to.className.indexOf('dragUnitArea') != -1 || ? (evt.to.className.indexOf('table-draggable') != -1 && evt.draggedContext.element.type === 6) || ? (evt.to.className.indexOf('table-draggable') != -1 && ? ? ?evt.draggedContext.element.type === 'energy_table') ) { ? ?// 拖向最外層,類型為外部數(shù)據(jù)或者公共數(shù)據(jù),或者將表格組件拖到表格內(nèi) ? ?return false } } </script>
中間部分拖拽組件主要實現(xiàn)
<template> ?<div> ? ?<draggable ? ? ?class="dragArea" ? ? ?tag="div" ? ? ?:list="components" ? ? ?:group="{ name: 'g1', put: true }" ? ? ?item-key="id" ? ? ?:move="onMove" ? ? ?:animation="200" ? ? ?ghost-class="ghost" ? ? ?:forceFallback="true" ? ?> ? ? ?<template #item="{ element }"> ? ? ? ?<div ? ? ? ? ?:class="{ 'list-group-item': true, 'active-area': activeArea?.id === element.id }" ? ? ? ? ?:style="{ ? ? ? ? ? ?width: !element.ratio ? ? ? ? ? ? ?? element.type === 6 ? ? ? ? ? ? ? ?? '100% !important' ? ? ? ? ? ? ? ?: '50% !important' ? ? ? ? ? ? ?: element.ratio + '% !important' ? ? ? ? ?}" ? ? ? ? ?v-if="element.type != 0" ? ? ? ? ?@click.stop="onChooseArea(element)" ? ? ? ?> ? ? ? ? ?<!-- <CSingleText ? ? ? ? ? ?v-if="element.type === 'single_text'" ? ? ? ? ? ?:activeArea="activeArea" ? ? ? ? ? ?:elementData="element" ? ? ? ? ?></CSingleText> --> ? ? ? ? ?<component ? ? ? ? ? ?:is="componentNameList[element.type]" ? ? ? ? ? ?:activeArea="activeArea" ? ? ? ? ? ?:elementData="element" ? ? ? ? ? ?@onCopyElement="$emit('onCopyElement')" ? ? ? ? ? ?@onDelElement="$emit('onDelElement')" ? ? ? ? ? ?@onChooseArea="onChooseArea" ? ? ? ? ?> ? ? ? ? ? ?<div class="base-title"> ? ? ? ? ? ? ?<div class="mask"></div> ? ? ? ? ? ? ?<el-icon ? ? ? ? ? ? ? ?v-if=" ? ? ? ? ? ? ? ? ?element.defaultValueType === 1 && ? ? ? ? ? ? ? ? ?element.dataLinkages[0]?.associationRules && ? ? ? ? ? ? ? ? ?element.dataLinkages[0].associationRules[0]?.targetField ? ? ? ? ? ? ? ?" ? ? ? ? ? ? ?> ? ? ? ? ? ? ? ?<Link /> ? ? ? ? ? ? ?</el-icon> ? ? ? ? ? ? ?<i v-if="element.isRequired">*</i> ? ? ? ? ? ? ?{{ element.name }} ? ? ? ? ? ?</div> ? ? ? ? ?</component> ? ? ? ? ?<p class="operate" v-if="activeArea?.id === element.id"> ? ? ? ? ? ?<i class="iconfont iconcopy" @click.stop="$emit('onCopyElement')"></i> ? ? ? ? ? ?<i class="iconfont icondel" @click.stop="$emit('onDelElement')"></i> ? ? ? ? ?</p> ? ? ? ?</div> ? ? ? ?<template v-else> ? ? ? ? ?<ComputeUnit ? ? ? ? ? ?@onCopyElement="$emit('onCopyElement')" ? ? ? ? ? ?@onDelElement="$emit('onDelElement')" ? ? ? ? ? ?@addBrotherUnit="$emit('addBrotherUnit')" ? ? ? ? ? ?@addChildUnit="$emit('addChildUnit')" ? ? ? ? ? ?@onShowAlCenter="$emit('onShowAlCenter')" ? ? ? ? ? ?class="drag-children" ? ? ? ? ? ?:activeArea="activeArea" ? ? ? ? ? ?:computeUnit="element" ? ? ? ? ? ?@onChooseArea="onChooseArea" ? ? ? ? ?></ComputeUnit> ? ? ? ?</template> ? ? ?</template> ? ? ?<template #footer> ? ? ? ?<slot></slot> ? ? ?</template> ? ?</draggable> ?</div> </template> <script setup> import draggable from 'vuedraggable' import ComputeUnit from '../ComputeUnit/ComputeUnit.vue' import { componentNameList } from '../../utils/element' import { Link } from '@element-plus/icons-vue' ? const props = defineProps({ ?components: { ? ?required: true, ? ?type: Array }, ?activeArea: { ? ?type: Object, ? ?default() { ? ? ?return { ? ? ? ?id: '-1' ? ? } ? } } }) const emits = defineEmits([ ?'addBrotherUnit', ?'addChildUnit', ?'onChooseArea', ?'onCopyElement', ?'onDelElement', ?'onShowAlCenter' ]) ? const onChooseArea = (ele) => { ?emits('onChooseArea', ele) } ? /** * 組件移動時,判斷移動位置是否正確 */ const onMove = (evt, originalEvent) => { ?if ( ? (evt.to.className === 'dragUnitArea' && evt.draggedContext.element.type != 0) || ? ?evt.to.className.indexOf('table-draggable') != -1 ) { ? ?return false } } </script>
到此這篇關(guān)于vue-draggable實現(xiàn)拖拽表單的示例代碼的文章就介紹到這了,更多相關(guān)vue draggable拖拽表單內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VUE實現(xiàn)一個Flappy Bird游戲的示例代碼
這篇文章主要介紹了VUE實現(xiàn)一個Flappy Bird的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-04-04