html 樹形圖可拖拽,HTML5拖拽API實現vue樹形拖拽組件

因業務場景需要一個可拖拽修改節點位置的樹形組件,因此動手擼了一個,乘此機會摸了一把html5原生拖拽。近期有時間將核心部分代碼抽出,簡單說下實現方式。

1.樹形結構-組件遞歸使用

樹形結構非常簡單,tree組件作為父組件,結構如下

tree.vue

復制代碼

vue組件允許在它們自己的模板中調用自身,因此可以形成樹形結構,在組件中必須填寫唯一的name。

tree-node.vue

復制代碼

2.HTML5拖拽api

1.draggable屬性規定元素是否可拖動,目前Internet Explorer 9+, Firefox, Opera, Chrome, and Safari 支持 draggable 屬性

2.HTML 5 拖放api

ondragstart: 元素開始被拖動時觸發 作用在拖拽元素上

ondragenter:當拖曳元素進入目標元素的時候觸發的事件,作用在目標元素上

ondragover:拖拽元素在目標元素上移動的時候觸發的事件,作用在目標元素上

ondragleave:拖拽元素拖離開了目標元素時觸發,作用在目標元素上

ondrop:被拖拽的元素在目標元素上同時鼠標放開觸發的事件,作用在目標元素上

ondragend:當拖拽完成后觸發的事件,作用在被拖曳元素上

3.拖拽節點

定義變量

處理拖拽節點需要幾個關鍵變量

當前拖拽的節點

拖拽時經過的節點

最終放置的節點

因此定義了一個用于保存拖拽信息的對象

dragOverStatus: {

overNodeKey: "",

dropPosition: "",

dragNode: {}

}

復制代碼

綁定拖拽事件

這里將ondragstart事件綁定在子元素上,將其他事件綁定在父元素上,因為在測試真機IE10的時候,發現ondragstart和其他事件綁定在同一個元素上,無法觸發ondragenter等事件。

復制代碼mounted() {

//綁定拖拽事件

if (this.root.draggable) {

this.$refs.draggAbleDom.draggable = !this.nodeData.noDrag;

this.$refs.draggAbleDom.ondragstart = this.onDragStart;

this.$refs.dropTarget.ondragenter = this.onDragEnter;

this.$refs.dropTarget.ondragover = this.onDragOver;

this.$refs.dropTarget.ondragleave = this.onDragLeave;

this.$refs.dropTarget.ondrop = this.onDrop;

this.$refs.dropTarget.ondragend = this.onDragEnd;

}

}

復制代碼

觸發某節點的拖拽事件時,就可以從拖拽事件里拿到當前節點實例。

使用HTML5提供的專門的拖拽與拖放API,原生的實現了復雜的操作,不需要自己用鼠標事件模擬,因此實現拖拽效果非常簡單。

(1).開始拖拽:在拖拽元素上觸發,事件內只需要保存當前拖拽節點的信息即可

onDragStart(e, treeNode) {

this.dragOverStatus.dragNode = {

nodeData: treeNode.nodeData,

parentNode: treeNode.parentNodeData

};

this.$emit("on-dragStart", {

treeNode: treeNode.nodeData,

parentNode: treeNode.parentNodeData,

event: e

});

}

復制代碼

(2).進入目標節點:在目標元素上觸發,主要保存當前經過的節點的key,然后向外層發出事件,供組件調用者做其他操作。為了避免拖拽一個元素快速經過許多個節點時頻繁發出事件,設置定時器當停留一定時間后觸發。

onDragEnter(e, treeNode) {

//當沒有設置拖拽節點時,禁止作為目標節點

if (!this.hasDragNode()) {

return;

}

this.dragOverStatus.overNodeKey = "";

//拖拽節點與目標節點是同一個,return掉

if (

treeNode.nodeData._hash === this.dragOverStatus.dragNode.nodeData._hash

) {

return;

}

this.dragOverStatus.overNodeKey = treeNode.nodeData._hash; //當前經過的可放置的節點的key

//當前節點禁止做為放置節點時

if (treeNode.nodeData.noDrop) {

return;

}

//設置dragEnter定時器,停留250毫秒后觸發事件

if (!this.delayedDragEnterLogic) {

this.delayedDragEnterLogic = {};

}

Object.keys(this.delayedDragEnterLogic).forEach(key => {

clearTimeout(this.delayedDragEnterLogic[key]);

});

this.delayedDragEnterLogic[

treeNode.nodeData._hash

] = setTimeout(() => {

if (!treeNode.nodeData.isExpand) {

treeNode.toggleCollapseStatus();

}

this.$emit("on-dragEnter", {

treeNode: treeNode.nodeData,

parentNode: treeNode.parentNodeData,

event: e

});

}, 250);

}

復制代碼

(3).在目標節點上經過:在目標元素上觸發,即時計算鼠標在目標節點上的位置,用于判斷最終的放置位置,0(作為目標節點的子節點),-1(放置在目標節點的前面),1(放置在目標節點的后面),顯示相應的樣式。

onDragOver(e, treeNode) {

//當沒有設置拖拽節點時,禁止作為目標節點

if (!this.hasDragNode()) {

return;

}

if (

this.dragOverStatus.overNodeKey === treeNode.nodeData._hash

) {

this.dragOverStatus.dropPosition = this.calDropPosition(e); //放置標識0,-1,1

}

this.$emit("on-dragOver", {

treeNode: treeNode.nodeData,

parentNode: treeNode.parentNodeData,

event: e

});

this.dragOverClass = this.setDragOverClass();//設置鼠標經過樣式

},

復制代碼

當鼠標處于目標節點內目標節點偏上方(1/5處),則意為放在目標節點前面-同級,當鼠標處于目標節點內目標節點偏下方(1/5處),意為放在目標節點后面-同級,否則作為目標節點的子節點

calDropPosition(e) {

var offsetTop = this.getOffset(e.target).top;

var offsetHeight = e.target.offsetHeight;

var pageY = e.pageY;

var gapHeight = 0.2 * offsetHeight;

if (pageY > offsetTop + offsetHeight - gapHeight) {

//放在目標節點后面-同級

return 1;

}

if (pageY < offsetTop + gapHeight) {

//放在目標節點前面-同級

return -1;

}

//放在目標節點里面-作為子節點

return 0;

}

復制代碼

(4).放置節點:在目標元素上觸發,此時將拖拽的信息變量作為參數將事件發射到外層,其余操作由外層來決定即可。

onDrop(e, treeNode) {

//當沒有設置拖拽節點時,禁止作為目標節點

if (!this.hasDragNode()) {

return;

}

//當前節點禁止拖拽時

if (treeNode.nodeData.noDrop) {

return;

}

//拖拽節點與目標節點是同一個,不做任何操作

if (

this.dragOverStatus.dragNode.nodeData._hash === treeNode.nodeData._hash

) {

return;

}

var res = {

event: e,

dragNode: this.dragOverStatus.dragNode,

dropNode: {

nodeData: treeNode.nodeData,

parentNode: treeNode.parentNodeData

},

dropPosition: this.dragOverStatus.dropPosition

};

this.$emit("on-drop", res);

}

復制代碼

(5).拖拽結束:作用在拖拽元素上,拖拽結束后將清除變量,恢復樣式。

onDragEnd(e, treeNode) {

//當沒有設置拖拽節點時,禁止作為目標節點

if (!this.hasDragNode()) {

return;

}

//當前節點禁止拖拽時

if (treeNode.nodeData.noDrop) {

return true;

}

this.dragOverStatus.dragNode = null;

this.dragOverStatus.overNodeKey = "";

this.$emit("on-dragEnd", {

treeNode: treeNode.nodeData,

parentNode: treeNode.parentNodeData,

event: e

});

}

復制代碼

4.應用

調用樹形拖拽組件,獲取拖拽過程中的拖拽節點,目標節點,以及放置位置,具體處理拖拽結果由調用方決定,可以是通過調接口更新樹結構,也可以由前端處理輸入數據,更新視圖。

復制代碼getDropData(info) {

var dragData = info.dragNode.nodeData;

var dragParent = info.dragNode.parentNode;

var dropData = info.dropNode.nodeData;

var dropParent = info.dropNode.parentNode;

var dropPosition = info.dropPosition; //0作為子級,-1放在目標節點前面,1放在目標節點后面

//把拖拽元素從父節點中刪除

dragParent.children.splice(dragParent.children.indexOf(dragData), 1);

if (dropPosition === 0) {

dropData.children.push(dragData);

} else {

var index = dropParent.children.indexOf(dropData);

if (dropPosition === -1) {

dropParent.children.splice(index, 0, dragData);

} else {

dropParent.children.splice(index + 1, 0, dragData);

}

}

}

復制代碼

作為子節點,改變層級991fe97359d9bd5a07e850aac379a862.png

2e904c39ae48be32ebe924396d2c8392.png

修改排序,將拖拽節點放在目標節點后面8ebb0e0fd53c1394777e199c0cead02a.png

b380713f024f410f3ba5adbeb94c745b.png

修改排序,將拖拽節點放在目標節點前面

f5678cd5d9059b1fd35fb765052c2c53.png

71f69858902bcd408b7610b96d0c56bb.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/272984.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/272984.shtml
英文地址,請注明出處:http://en.pswp.cn/news/272984.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

navicat 或者workbench 無法連接127.0.0.1(61)的解決方法

1、輸入mysql -uroot 進入命令行模式, 2、輸入"show variables like %sock%;"查看sock文件所在位置 如&#xff1a; 3、配置客戶端&#xff08;以navicat為例&#xff09; &#xff08;1&#xff09;打開mac 下的navicat&#xff08;2&#xff09;建立相應的連接&…

jmeter如何定位網絡延時_JMeter用戶定義變量和properties變量高級使用

Jmeter有個配置元素叫做用戶自定義變量(英文名稱是UserDefinedVariables)而我們提到的vars即是Variables的簡寫。 之前我們也說到過Jmeter的腳本中(jsr223sampler或者beanshell編寫的腳本)使用varsput和varsget的操作(varsget和put的操作僅在threadgroup測試組線程中執行&#…

html5與跨平臺開發,HTML5應用與跨平臺應用開發

本課程將總體講解開發HTML5應用和跨平臺應用的方法&#xff0c;共分成三部分。第一部分為HTML5開發基礎&#xff0c;帶你分析并掌握多種移動開發技術和設計方式&#xff1b;第二部分為HTML5高級應用&#xff0c;講解在HTML5中調用其它應用或服務的方法&#xff1b;第三部分為跨…

jQuery中的幾個模塊總結

Query插件&#xff0c;以備并希望在前端方面有所長進。請批評指正。 一&#xff0c;類型判斷全解 JQuery判斷類型擴展方法&#xff1a;$.type() 1 /*type: function( obj ) { 2 if ( obj null ) { 3 return obj ""; 4 } …

python實現連續數列相加_技術 | Python經典面試題解析實現斐波那契數列

黑馬程序員微信號&#xff1a;heiniu526傳智播客旗下互聯網資訊&#xff0c;學習資源免費分享平臺大家在面試過程中經常會考到斐波那契數列&#xff0c;斐波那契數列(Fibonacci)最早由印度數學家Gopala提出&#xff0c;而第一個真正研究斐波那契數列的是意大利數學家 Leonardo …

廣西2021高考成績位次查詢,2020年廣西高考一分一段表及高考位次成績排名查詢(理科+文科)...

一、2020年廣西高考一分一段表查詢排名方法廣西招辦(考試院)會公布的省市高考每一分分數的考生數額統計表就是我們所說的——高考“一分一段表”&#xff0c;其顯示出每一分的分數值全省考生有多少名&#xff0c;就可以讓考生估算出自己的排名位次。2020年廣西高考一分一段表排…

PV公式

IP(獨立IP)&#xff1a; 即Internet Protocol,指獨立IP數。00:00-24:00內相同IP地址之被計算一次。PV(訪問量)&#xff1a; 即Page View, 即頁面瀏覽量或點擊量&#xff0c;用戶每次刷新即被計算一次。UV(獨立訪客)&#xff1a;即Unique Visitor,訪問您網站的一臺電腦客戶端為…

csv文件 內容轉義_CSV文件如何同時轉義逗號和雙引號?

小編典典有幾個庫。這是兩個示例&#xff1a;阿帕奇共享郎包括一類特殊的逃避或UNESCAPE字符串(CSV&#xff0c;EcmaScript的&#xff0c;HTML&#xff0c;Java和JSON&#xff0c;XML)org.apache.commons.lang3.StringEscapeUtils 。轉義 為CSVString escaped StringEscapeUti…

臺式計算機單核與雙核,什么是單核cpu、雙核cpu 單核cpu和雙核cpu的區別是什么...

在買電腦的時候&#xff0c;我們經常會發愁&#xff0c;究竟是買單核cpu好&#xff0c;還是買雙核cpu比較好&#xff0c;尤其是面對售貨員把單核cpu電腦和雙核cpu電腦都可以夸的天花亂墜的時候&#xff0c;我們更糊涂了&#xff0c;究竟買哪種好呢?針對這種情況&#xff0c;小…

當用DJANGO的migrate不成功時。。。。

URL:http://my.oschina.net/u/862582/blog/355421 因為操作SQL數據庫時不規范&#xff0c;或是多人開發時產生了同步問題&#xff0c;就可能導致正規的MIGRATE時不能完成。 已其修改&#xff0c;不如直接生成SQL之后運行。。 記住語法即可。。。 python manage.py sqlmigrate a…

R語言seqm_R語言seq()函數用法

1、seq()用來生成一組數字的函數。Usage&#xff1a;## Default S3 method:seq(from 1, to 1, by ((to - from)/(length.out - 1)),length.out NULL, along.with NULL, ...)seq.int(from, to, by, length.out, along.with, ...)seq_along(along.with)seq_len(length.out)A…

美國計算機生物學要求,美國大學CS專業分支生物信息學和計算生物學專業 Bioinformatics and Computational Biology介紹...

美國留學申請美國大學計算機專業(CS)的學生非常多。美國大學CS專業的研究分支也非常 多&#xff0c;不同分支對學生的要求也會不同&#xff0c;因此&#xff0c;學生們要根據自己的條件選擇適合自己的研究方向。下面主要為大家介紹的是美國大學CS專業分支生物信息學和計算生物學…

Spark入門實戰系列--8.Spark MLlib(上)--機器學習及SparkMLlib簡介

【注】該系列文章以及使用到安裝包/測試數據 可以在《傾情大奉送--Spark入門實戰系列》獲取 1、機器學習概念 1.1 機器學習的定義 在維基百科上對機器學習提出以下幾種定義&#xff1a; l“機器學習是一門人工智能的科學&#xff0c;該領域的主要研究對象是人工智能&#xff0c…

cadz軸歸零命令_CAD圖形Z軸坐標歸零方法

AutoCAD2012 64位精簡版中文免安裝版軟件大小&#xff1a;561.5M授權方式&#xff1a;免費軟件立即下載CAD軟件怎樣將圖形坐標Z軸歸零?當我們遇到CAD圖形標高一致的時候&#xff0c;如果想要讓圖形統一標高&#xff0c;就需要先將圖形坐標Z軸歸零。本次小編為您整理了CAD軟件里…

net以execl做數據庫_[原創]Net實現Excel導入導出到數據庫(附源碼)

關于數據庫導出到Excel和SQLServer數據導出到Excel的例子&#xff0c;在博客園有很多的例子&#xff0c;自己根據網上搜集資料&#xff0c;自己做了亦歌簡單的demo&#xff0c;現在分享出來供初學者學習交流使用。一、數據庫導入導出到Excel&#xff0c;比較流行的有兩種方式&a…

計算機基礎cpu知識,CPU基礎知識: DIY裝機小白必看的CPU知識掃盲

CPU也就是中央處理器&#xff0c;全拼為Central Processing Unit&#xff0c;在計算機中可以比喻成人的大腦。它是一塊超大規模的集成電路&#xff0c;是一臺計算機的運算核心和控制核心。它的功能主要是解釋計算機指令以及處理計算機軟件中的數據。下面華強電子網的小編分享一…

const 用法

static NSString * const testString "google"; //表示testString這個指針不能被修改&#xff0c;如若對testString賦值則會報錯&#xff1a;testString &#xff1d; "hello";編譯器會報錯 static NSString const *testString "google"; //表…

mvc html validator,ASP.NET MVC實現Validation驗證器擴展

今天介紹在ASP.NET MVC實現Validation驗證器擴展,通過使用Controller驗證并不是最好的方法&#xff1a;驗證過于分散&#xff0c;容易造成重復代碼&#xff0c;不利于維護與擴展,因此本節將使用MVC默認綁定器(DefaultModelBinder)中包含了驗證架構,并實現Validation驗證器擴展&…

git 幾種還原版本_Git恢復之前版本的兩種方法reset、revert(圖文詳解)

一、問題描述在利用github實現多人合作程序開發的過程中&#xff0c;我們有時會出現錯誤提交的情況&#xff0c;此時我們希望能撤銷提交操作&#xff0c;讓程序回到提交前的樣子&#xff0c;本文總結了兩種解決方法&#xff1a;回退(reset)、反做(revert)。二、背景知識git的版…

自定義列表視圖

通過繼承BaseAdapter寫一個子類&#xff0c;可以創建自定義列表視圖&#xff1a; public class MyListAdapter extends BaseAdapter { private LayoutInflater mInflater;//聲明一個LayoutInflater類變量 private Context mContext;//聲明一個Context類變量 priva…