說明
做專案的時候要使用到一個自定義的樹形控制元件來構建表格樹,在github上搜了一下沒有搜尋到合適的(好看的)可以直接用的,檢視Element的元件說明時發現它的Tree控制元件可以使用render來自定義節點樣式,於是基於它封裝了一個可以增、刪、改的樹形元件,現在分享一下它的使用與實現。
控制元件演示
控制元件使用
概要
- 基於element-ui樹形控制元件的二次封裝
- 提供編輯、刪除節點的介面
- 提供一個next鉤子,在業務處理失敗時可使用next(false)回滾操作
- 控制元件原始碼見 github
文件
屬性 |
說明 |
型別 |
value |
源資料,可使用v-model雙向繫結 |
Array |
事件名 |
說明 |
引數 |
SaveEdit |
點選編輯或者新增樹節點後的儲存事件 |
(父節點資料、當前節點資料、next) |
DelNode |
刪除節點事件 |
(父節點資料、當前節點資料、next) |
NodeClick |
節點點選事件 |
(當前節點資料) |
屬性 |
說明 |
value |
樹節點的唯一標識 |
label |
樹節點的顯示名稱 |
status |
(1:編輯狀態)(0:顯示狀態)(-1不可編輯狀態) |
children |
子節點資料 |
<m-tree
v-model="tableTree"
@SaveEdit="SaveEdit"
@DelNode="DelNode"
@NodeClick="handleNodeClick"></m-tree>
SaveEdit(parentNode,data,next){
var param = {
parentNode:parentNode,
node:data
}
this.$http.post(URL,param).then((response) => {
if(response.status == 200){
next(true,response.body.data.nodeId)
}else{
next(false)
}
})
}複製程式碼
實現方式
- 構建子節點的模板
<span class="span_item">
<span @click="Expanded">
<Input v-if="node.status == 1" style="width: 100px;" v-model="node.label" size="small" ></Input>
<Icon v-if="node.status == 0" type="asterisk"></Icon>
<Icon v-if="node.status == -1" type="ios-keypad-outline"></Icon>
<span v-if="node.status != 1">{{node.label}}</span>
</span>
<span v-if="node.status == 1">
<Button style="margin-left: 8px;" size="small" type="success" icon="checkmark-circled" @click="SaveEdit">確認</Button>
<Button style="margin-left: 8px;" size="small" type="ghost" icon="checkmark-circled" @click="CancelEdit">取消</Button>
</span>
<span class="span_icon">
<Icon v-if="node.status == 0" style="margin-left: 8px" color="gray" type="edit" size="16" @click.native="OpenEdit"></Icon>
<Icon v-if="node.status == 0" style="margin-left: 8px" type="plus-round" color="gray" size="16" @click.native="Append"></Icon>
<Icon v-if="node.status == 0&&node.children.length < 1" style="margin-left: 8px" type="ios-trash" color="red" size="18" @click.native="Delete"></Icon>
</span>
</span>複製程式碼
- 子節點通過$emit通知父節點事件
SaveEdit(){
//儲存節點事件
this.$emit('SaveEdit',this.nodeData)
},複製程式碼
- 父節點核心實現,使用renderContent函式載入子節點模板,點選儲存節點時將業務引數儲存在runParam中用於在業務操作失敗(網路請求失敗、服務端異常等情況)的資料回滾
<el-tree
class="filter-tree"
style="overflow:auto;"
:data="treeData"
:filter-node-method="filterNode"
@node-click="handleNodeClick"
ref="tree"
node-key="value"
:expand-on-click-node="false"
:render-content="renderContent"
default-expand-all>
</el-tree>
//子節點模板
renderContent(h, { node, data, store }) {
return h(TreeItem,{
props:{
value:data,
treeNode:node
},
on:{
input:(node)=>{
data = node
},
Append: () => {
node.expanded = true
data.children.push({ value: this.$utilHelper.generateUUID(), label: '請輸入模組名稱', children: [],status:1,isAdd:true })
},
//儲存節點
SaveEdit:(nodeData)=> {
//遞迴查詢父節點
var parentNode = this.$utilHelper.getNode(this.treeData,data.value).parentNode
this.runParam.parentNode = parentNode
this.runParam.data = data
this.runParam.nodeData = nodeData
this.$emit('SaveEdit',parentNode,data,this.CanSaveNext)
}
}
})
}複製程式碼
- 操作結果鉤子,如果next函式傳入false則判定操作失敗,使用runParam中的引數進行回滾,該節點的編輯儲存操作將無效
CanSaveNext(isNext,nodeId){
let parentNode = this.runParam.parentNode
let nodeData = this.runParam.nodeData
let data = this.runParam.data
if(isNext){
parentNode.children.forEach((v,i)=>{
if(v.value == data.value){
if(this.HOST != "static"&&data.isAdd){
data.value = nodeId
}
data.status = 0
parentNode.children.splice(i,1,data)
}
})
}else{
if(!data.isAdd){
parentNode.children.forEach((v,i)=>{
if(v.value == nodeData.value){
data.label = nodeData.label
parentNode.children.splice(i,1,data)
}
})
}
}
this.runParam = {}
}複製程式碼
如果覺得有用,歡迎star calebman/vue-DBM