在ElementUI-Tree,有個屬性可讓選項拖曳,預設是false的,可以讓選項用滑鼠拖曳改變位置

加上去後就可以讓選項自由移動位置,但因為目前最多只有三層選單,而如果在第三層將選項移動進去就會變成第四層,這是不被允許的,幸好ElementUI有提供一個函數allow-drop來阻止這樣的行為

可以看到這個Function(draggingNode, dropNode, type),有三個參數
draggingNode:目前正在拖曳的節點
dropNode:放置的節點
type:要放置節點裡面或前後位置
在<el-tree>標籤中加入屬性:allow-drop="allowDrop",:allow-drop="allowDrop"
methods加入此函數,然後裡面回傳false,拖曳時就是全部禁止,那這部分需要做些邏輯判斷
allowDrop(draggingNode, dropNode, type) {
return false;
},
首先不能將節點變成第四層,被拖曳的節點和目前所在的節點總層數不能大於3,例如手機通訊這個節點有兩層(本身節點加上點開還有一層節點的意思),然後想要將手機拖曳到下一層的節點時是不允許的,因為這樣會變成四層節點
在方法中寫console.log先觀察一下參數的內容,當我要拖曳手機通訊中的對講機看會發生什麼事
allowDrop(draggingNode, dropNode, type) {
console.log("allowDrop", draggingNode, dropNode, type);
return false;
},

可以看到有prev、inner、next,在移動的過程中有出現的東西,第一個節點顯示的名稱是對講機,這是我拖曳的選項,然後下個節點是手機,這是我想放進去的節點,這時候要算出目前節點的總層數
假設目前拖曳的節點有子節點,則再繼續判斷是否有子節點,一直查到沒有子節點為止,這樣的邏輯可以使用遞迴來計算,假設最深的層級為3,而目前節點層級是2,公式就是(3-2)+1,總共為2,再加上父節點的層級,而父節點的層級可以在draggingNode中找到parnet中的level找到,只要這些合起來不大於3就可以完成拖曳

寫一個計算深度的方法countNodeLevel(node),傳進去的參數是(draggingNode.data)這就是目前拖曳的節點資料,先找出是否有子節點,而傳進來的參數(node)有一個屬性children,只要他長度大於0且不為空,就表示有子節點,有子節點就可以用for迴圈來判斷每一個節點中是否還有子節點

我現在拖曳「手機通訊」這個節點,可以看到Node > data (這個就是目前被拖曳的節點)而這個節點底下有個children也就是子節點,一共有三個(手機、對講機、手機通訊)然後catLevel表示分類的節點中為第三層了,將這個節點給定一個變數maxLevel(這個變數要另外再加在data中,預設需為節點的最深層級3,因為如果一開始就先選擇最裡面的節點,深度會變成負數),然後再查找其他節點時就再呼叫自身方法(countNodeLevel)
countNodeLevel(node) {
// 找到所有子節點,求出最大深度
if (node.children != null && node.children.length > 0) {
for (let i = 0; i < node.children.length; i++) {
if (node.children[i].catLevel > this.maxLevel) {
this.maxLevel = node.children[i].catLevel;
}
this.countNodeLevel(node.children[i]); // 記得加上this否則vue會找不到方法
}
}
},
這樣找最深度的層級的方法大致上是這樣,這方法是會改變data中的maxLevel,所以先在data中加上去
maxLevel: 0,
然後一樣console.log顯示來看看是否正確
allowDrop(draggingNode, dropNode, type) {
console.log("allowDrop", draggingNode, dropNode, type);
this.countNodeLevel(draggingNode.data);
console.log("deep:", this.maxLevel);
return false;
},

當我不管拖曳哪個地方,都是計算出深度為3的總層數,這是最大的總層數,套用公式上必需要在判斷,最大總層數 – 目前拖曳節點的層數 + 1,只要不大於3,表示可以拖曳,所以再修改一下方法
allowDrop(draggingNode, dropNode, type) {
console.log("allowDrop", draggingNode, dropNode, type);
this.countNodeLevel(draggingNode.data);
// 目前正在拖曳的節點加上父節點所在的深度不能大於3
let deep = this.maxLevel - draggingNode.data.catLevel + 1;
console.log("深度:", deep);
return false;
},

當我拖曳對講機時,已經計算出此節點的深度層級是1,而拖曳手機通訊時,計算出的深度層級是2

接下來
判斷拖曳到目標的節點裡面(inner)時是否可以拖曳,也就是dropNode這個參數的data,裡面有個層級level,當我拖曳數位節點到家用電器節點裡面時,是不允許的,因為深度+層級會大於等於3,所以只能在家用電器的節點上下移動而已

而只要拖曳到目標節點的前或後時,要判斷目標節點的父節點是否層級大於等於3,一樣在dropNode中的parent父節點有個層級level,只要不大於等於3,就是允許拖曳

最後修改的allowDrop方法
allowDrop(draggingNode, dropNode, type) {
// 被拖曳的節點和目前所在的父節點總層數不能大於3
console.log("allowDrop", draggingNode, dropNode, type);
this.countNodeLevel(draggingNode.data);
// 目前正在拖曳的節點加上父節點所在的深度不能大於3
let deep = this.maxLevel - draggingNode.data.catLevel + 1;
console.log("深度:", deep);
if (type == "inner") {
return deep + dropNode.level <= 3;
} else {
return deep + dropNode.parent.level <= 3;
}
},
讓方法返回true或false,這樣就完成了拖曳的效果