說明
作項目的時候要使用到一個自定義的樹形控件來構建表格樹,在github上搜了一下沒有搜索到合適的(好看的)能夠直接用的,查看Element的組件說明時發現它的Tree控件能夠使用render來自定義節點樣式,因而基於它封裝了一個能夠增、刪、改的樹形組件,如今分享一下它的使用與實現。vue
控件演示
控件使用
概要
- 基於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-DBMnode