本文所用組件傳送門:vue-org-tree
本文基於antd (其他前端組件框架操作基本都類似的: iview,elementui,boostrap-vue...)
當然,github上還有其他類似的組件,實現方法各有不同,顯示效果也有差異,但都是很方便的組件。
看到網上有很多相關的使用教程,github上也寫得很清楚,這里恕不在重復,本文主要實現增刪節點。
場景:我們通常展示部門樹的時候,簡單的直接就是一個下拉框展示,為了顯示明顯,可能會使用一些樹。
圖片截至:(antd vue文檔)
但是簡單的樹形已經很難滿足變態的需求了。盡管做到tree已經很自然的顯示了組織架構關系了。這個時候就需要更好看,更直接的顯示方式了。
先預覽一下vue2-org-tree 組件的樣式:
顯示效果非常不錯了。層級關系清晰明了,而且支持節點開閉,手動配置樣式等功能。
立馬上手,照着官方案例搞了一個,嗯嗯,很不錯,確實是大佬們想要的。
把玩一番,頗為得意,很輕松的解決了煩人的需求。果然天道酬勤,報應不爽啊,才懶一會兒,就被潑了涼水,因為我發現一個很讓人絕望的問題。這個組件不支持擴展子節點。
是的,它只支持你把數據傳進來,然后渲染出效果。然后點兩下開關,橫排豎排顯示,沒了。。。。。。剛開始認為這個組件不夠全面,是的,至少支持增刪的話。但是現在的前端開發,完全組件式開發。你需要飛機,就給你飛機,但是發動機,座位,機組人員,配套設施,都需要你自己去添加,因為你無法開發出一個完全適配所有配置的組件,如果你開發出來了,首先很牛,但是這個組件的庫一定非常巨大,你需要適配的各種設施都在你的庫里,你需要下載半小時的庫包(雖然開玩笑,但確實庫比較大加載是很費時的)。所以大家都趨於開發出一個小巧輕便的組件。
失望歸失望,研究一番,發現組件提供的API里面有自定義渲染方式的prop:renderContent
既然支持自定義渲染方式,我傳入一個jsx會怎么樣呢?迅速找到antd的下拉菜單組件:
附上官方源碼:
<template> <a-dropdown :trigger="['click']"> <a class="ant-dropdown-link" href="#"> Click me <a-icon type="down" /> </a> <a-menu slot="overlay"> <a-menu-item key="0"> <a href="http://www.alipay.com/">1st menu item</a> </a-menu-item> <a-menu-item key="1"> <a href="http://www.taobao.com/">2nd menu item</a> </a-menu-item> <a-menu-divider /> <a-menu-item key="3">3rd menu item</a-menu-item> </a-menu> </a-dropdown> </template>
通過鼠標點擊展開下拉菜單。點擊子菜單可以實現不同的功能。我讓每一個節點都是一個下拉菜單,不就可以了嗎?把上面的代碼改寫成jsx形式,並寫入renderContent 方法里,記得定義組件renderContent 屬性哦。
renderContent (h, data) { return (<span><a-dropdown trigger={['click']}> <a>{data.title}</a> <a-menu slot="overlay" onclick={(key) => this.onClick(key, data)}> <a-menu-item v-show={data.level !== 0} key={'add'}>添加同級部門</a-menu-item> <a-menu-item key={'addChild'}>添加下級部門</a-menu-item> <a-menu-item key={'edit'}>修改部門</a-menu-item> <a-menu-item key={'del'} >刪除部門</a-menu-item ></a-menu ></a-dropdown ></span >) }
h不解釋啦,就是jsx對象。data是我的數據,title是名稱。onclick就是a元素的js事件,這里傳遞了下拉菜單的key,並用箭頭函數指向自定義的onClick函數。
onClick (keyObj, node) { if (keyObj.key === 'del') { if (node.children && node.children.length > 0) { this.$message.info('當前部門存在子部門,請先刪除子部門') } else { this.$http.get('/rdDept/del', { params: { id: node.value } }) .then(res => { if (res.success && res.data) { this.$message.success('刪除成功') this.loadTree() } else { this.$message.error(res.errorMessage) } }) } } else { this.$refs.modifyDept.showModal(keyObj.key, node) } }
onclick里只處理了刪除操作,並且存在子節點,就不進行刪除。
先看下目前的效果:
視圖完全沒問題。操作下拉菜單:
正確響應。
寫到這里,已經實現刪除操作了。新增,修改操作其實已經呼之欲出了,定義一個輸入框彈出層,這里就不貼具體代碼了。
顯示效果如下:
現在我們回到onClick方法的最后一行代碼:
this.$refs.modifyDept.showModal(keyObj.key, node)
modifyDept是我新建的組件,showModal是組件的方法,key就是組件的下拉菜單key,node就是當前節點。我們來看下showModal方法:
showModal (key, data) {switch (key) { case 'edit': this.setDept(data.title, data.value, data.parentId, data.level, `修改[${data.title}]`, data.identity) break case 'add': this.setDept('', -1, data.parentId, data.level, `添加同級部門[${data.title}]`, data.identity) break case 'addChild': data.identity = data.identity === '' ? data.value : `${data.identity}:${data.value}` this.setDept('', -1, data.value, data.level + 1, `添加下級部門[${data.title}]`, data.identity) break default: this.setDept('', -1, -1, 0, '添加研發部門', '') break } }, setDept (name, id, parentId, level, title, identity) { this.form.setFieldsValue({ deptName: name }) this.params.id = id this.params.parentId = parentId this.params.level = level this.params.thisIdentity = identity this.title = title }
根據傳遞過來的key確定操作,setDept方法設置當前操作的部門的樹形。
this.params對象是傳遞到后台的對象。就是你想操作的對象。
this.form.setFieldsValue({ deptName: name }) 該方法來自antd form表單api,設置輸入框deptName 的值。
輸入框代碼如下:
<a-form :form="form"> <a-form-item :label-col="{ span: 0 }" :wrapper-col="{ span: 24 }"> <a-input v-decorator="['deptName',{rules: [{ required: true, message: '請輸入研發部門' }]}]" /> </a-form-item> </a-form>
接下來,你只需要寫一個form的提交操作。把params對象傳遞了后台,然后由后台進行更新插入操作。然后刷新你的部門樹,就實現增刪功能了。
關鍵操作其實還是在jsx那段代碼。你可以用jsx 做到你想要的任何效果。
The end!