目錄
1.簡介
2.安裝及使用
下載包
main.js全局引用
頁面使用? ?
數(shù)據(jù)要求
配合使用
3.基礎(chǔ)使用
4.較深入使用
5.修改后的代碼如下
1.簡介
一個(gè)不算太簡易的簡易版組織架構(gòu)圖,組件依賴于vue-org-tree, 在此基礎(chǔ)上將部分源代碼進(jìn)行優(yōu)化修改。增加鼠標(biāo)拖拽和鼠標(biāo)滾輪縮放,并支持節(jié)點(diǎn)拖拽,以及節(jié)點(diǎn)編輯等功能。
優(yōu)勢:
1.支持整體拖拽、自定義展開組織樹展開層級(jí);
2.可進(jìn)行節(jié)點(diǎn)搜索,顯示搜索節(jié)點(diǎn)相關(guān)的組織樹;
3.支持自定義節(jié)點(diǎn)樣式,自定義新增、編輯、刪除、節(jié)點(diǎn)是否拖拽、拖拽節(jié)點(diǎn)副本/節(jié)點(diǎn);
做demo進(jìn)行測試時(shí)發(fā)現(xiàn)一個(gè)缺點(diǎn):當(dāng)數(shù)據(jù)從1800條左右開始時(shí),拖拽合并速度太快且頻繁拖拽合并時(shí),會(huì)報(bào)錯(cuò)數(shù)據(jù)找不到(感覺是上一輪拖拽數(shù)據(jù)還沒有處理完,下一輪數(shù)據(jù)處理不了了,希望有大佬能解惑,能有好的解決辦法)。
vue2的版本:zm-tree-org (gitee.io)
vue3的版本:Home | vue3-tree-org (sangtian152.github.io)
?git源碼:GitHub - sangtian152/zm-tree-org: 一個(gè)簡易版組織架構(gòu)圖,組件依賴于vue-org-tree, 在此基礎(chǔ)上將部分源代碼進(jìn)行優(yōu)化修改。支持鼠標(biāo)拖動(dòng),鼠標(biāo)滾輪縮放,節(jié)點(diǎn)拖拽。
?
2.安裝及使用
以vue2的版本示例。
下載包
npm i zm-tree-org -S
main.js全局引用
import Vue from 'vue';
import ZmTreeOrg from 'zm-tree-org';
import "zm-tree-org/lib/zm-tree-org.css";
Vue.use(ZmTreeOrg);
頁面使用? <zm-tree-org></zm-tree-org>?
//使用示例:修改背景色/文字顏色 ?
<zm-tree-org :label-style="style">
</zm-tree-org>
數(shù)據(jù)要求
最外層(公司級(jí))是Object,其子級(jí)及以下為Array。
orgData:{ id: 1, ? ? //組織id,必須
? label: "xxx科技有限公司", ?//組織名稱,必須
? disabled: true, ? //是否可編輯
? children: [ ? ? ?//子級(jí)
? ? ?{
? ? ? id: 2, ? ?//子級(jí)組織id,必須
? ? ? pid: 1, ? //父級(jí)組織id,必須
? ? ? label: "產(chǎn)品研發(fā)部", ? //組織名稱,必須
? ? ? expand: false, ?//當(dāng)前節(jié)點(diǎn)下的節(jié)點(diǎn)是否默認(rèn)展開
? ? ? noDragging: true, ?//當(dāng)前節(jié)點(diǎn)是夠允許拖拽
? ? ? children: []
? ? ?}
? }
配合使用
頁面部分功能需結(jié)合elementUI使用。
下載
npm i element-ui -S
?main.js全局引用
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
3.基礎(chǔ)使用
(1)樹形結(jié)構(gòu)橫向/縱向展開;
(2)樹形結(jié)構(gòu)展開/收起;
(3)組織樹默認(rèn)展開層級(jí) or 單一某節(jié)點(diǎn)的子節(jié)點(diǎn)樹展開/收起;
單一某節(jié)點(diǎn)的詳細(xì)說明:
需對數(shù)據(jù)做處理,單一節(jié)點(diǎn)的子節(jié)點(diǎn)樹不填寫默認(rèn)跟隨:default-expand-level。
示例:{id: 6,pid: 2,label: "展開當(dāng)前節(jié)點(diǎn)的組織樹",expand: true}。
如組件綁定 :default-expand-level="num" ?
且 num+1 < 當(dāng)前設(shè)置的層級(jí) 上述設(shè)置不生效;
num+1 >= 當(dāng)前設(shè)置的層級(jí) 上述設(shè)置生效。
num+1舉例:expand:false,即使 num+1 >= 當(dāng)前設(shè)置的層級(jí),當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)樹也會(huì)收起。
文中最開始的示例圖全部展開后共為 2級(jí)子節(jié)點(diǎn)(num) + 1 級(jí)根節(jié)點(diǎn)(所以num需要加1)。:default-expand-level="1"時(shí),代表展開到第一級(jí)子節(jié)點(diǎn),即“產(chǎn)品研發(fā)部”及它的同層級(jí)。
(4)組織樹? 可編輯/不可編輯 or 單一某節(jié)點(diǎn)? 可編輯/不可編輯;
單一某節(jié)點(diǎn)的詳細(xì)說明:
需對數(shù)據(jù)做處理,子節(jié)點(diǎn)不填寫默認(rèn)為false(可編輯)。
子節(jié)點(diǎn)示例:{id: 6,pid: 2,label: "禁止編輯節(jié)點(diǎn)",disabled: true}。
如組件綁定 :disabled="true" ?上述設(shè)置被覆蓋;:disabled="false",上述設(shè)置生效。
(5)節(jié)點(diǎn)樹整體 可拖拽/不可拖拽 or?單一某節(jié)點(diǎn) 可拖拽/不可拖拽
單一某節(jié)點(diǎn)的詳細(xì)說明:
需對數(shù)據(jù)做處理,子組件不填寫默認(rèn)為false(可拖拽)。
示例:{id: 6,pid: 2,label: "禁止拖拽節(jié)點(diǎn)",noDragging: true}。
如組件綁定 :node-draggable="true" 上述設(shè)置也生效; :node-draggable="false",上述設(shè)置被覆蓋。
(6)拖拽節(jié)點(diǎn)副本、當(dāng)前位置保留節(jié)點(diǎn)本身 / 拖拽節(jié)點(diǎn)本身;
(7)僅拖動(dòng)當(dāng)前節(jié)點(diǎn)、子節(jié)點(diǎn)添加到當(dāng)前節(jié)點(diǎn) / 當(dāng)前節(jié)點(diǎn)及子節(jié)點(diǎn)一起拖動(dòng);
(8)在線調(diào)整組織結(jié)構(gòu)任意背景色;
(9)在線調(diào)整文字任意顏色;
//color為string類型 :label-style="style"
<el-color-picker v-model="style.color" size="small"></el-color-picker>
(10)搜索組織,同時(shí)顯示當(dāng)前組織的上級(jí)所有組織;
<input type="text" v-model="keyword" placeholder="請輸入搜索內(nèi)容" @keydown.enter="filter" />
filter(){ this.$refs.tree.filter(this.keyword) }
4.較深入使用
(1)自定義節(jié)點(diǎn)右鍵點(diǎn)擊事件修改;
如僅修改name,則僅修改顯示的文字,插件自帶的【編輯】樣式依然顯示;
如修改command值,則綁定右鍵菜單彈出和【復(fù)制】【新增】【編輯】【刪除】4個(gè)可自定義的綁定事件失效,需重寫寫入事件。
例如:僅將command:'edit'修改為command:'edit1',如果某子節(jié)點(diǎn)為不可編輯狀態(tài),點(diǎn)擊右鍵,依然會(huì)顯示菜單【復(fù)制】【編輯】,但點(diǎn)擊【編輯】事件無反應(yīng)。如果不想【編輯】功能顯示,可以綁定vue的@contextmenu.prevent,對menus進(jìn)行動(dòng)態(tài)賦值。
// data值
menus: [{ name: '復(fù)制文本', command: 'copy' }, { name: '新增節(jié)點(diǎn)', command: 'add' }, { name: '編輯節(jié)點(diǎn)', command: 'edit1' }, { name: '刪除節(jié)點(diǎn)', command: 'delete' }],
disaled: false,
//自定義節(jié)點(diǎn)綁定方法
<div class="tree-org-node__text node-label node" @contextmenu.prevent="terFun(node)"></div>
//動(dòng)態(tài)賦值
terFun(node) {
console.log(node)
if (node.disabled || this.disaled) {
this.menus = [{ name: '復(fù)制文本', command: 'copy' }]
} else {
this.menus = [
{ name: '復(fù)制文本', command: 'copy' },
{ name: '新增節(jié)點(diǎn)', command: 'add' },
{ name: '編輯節(jié)點(diǎn)', command: 'edit1' },
{ name: '刪除節(jié)點(diǎn)', command: 'delete' }
]
}
},
(2)自定義節(jié)點(diǎn)及自定義編輯節(jié)點(diǎn)。
在4-(1)的基礎(chǔ)上去做,需要修改自定義點(diǎn)擊右鍵事件的edit值,否則插件自帶的【編輯節(jié)點(diǎn)】樣式依然會(huì)閃爍顯示。
———————— ?Html說明 ?————————
<template slot-scope="{node}"> ? ? // 插件的自定義節(jié)點(diǎn)插槽
// 此處可修改組織樹的節(jié)點(diǎn)樣式,當(dāng)前為默認(rèn)
? <div class="tree-org-node__text node-label node">
? ? {{ node.label }} ? ? ? ?// 組織名稱
?// 此處的class為late的 div為自定義的【編輯節(jié)點(diǎn)】card
? ? <div v-if="treeScope && !node.disabled && node.open" class="late">
? ? <el-input type="textarea" placeholder="請輸入內(nèi)容" v-model="cardOne.label" maxlength="30" show-word-limit></el-input>
? ? ? <div @click="close(node)">確定</div>
? </div>
? </div>
</template>
———————— ?data說明 除node.disabled外,可自定義————————
treeScope: false, //是否顯示【自定義編輯】card
node.disabled: ?查找當(dāng)前節(jié)點(diǎn)可編輯/不可編輯的屬性
cardOne: {}, //【自定義編輯】card組件信息
node.open: //自定義的節(jié)點(diǎn)【編輯屬性值】
———————— ?function說明 ————————
@on-contextmenu="onMenus" //右鍵菜單點(diǎn)擊事件
如修改【4、自定義節(jié)點(diǎn)右鍵點(diǎn)擊菜單修改的command:'edit'值,則插件自帶編輯事件失效,需自定義,自定義如下】
onMenus({ node, command }) {
? // 自定義編輯
? if (command === 'edit1' && !node.disabled) {
? ? ? //顯示【自定義編輯】card,將node賦值給cardOne
? ? ? //自定義編輯--card
? }
},
?組件自帶的默認(rèn)編輯節(jié)點(diǎn)樣式:
修改后的實(shí)現(xiàn)效果:
彈窗自定義編輯節(jié)點(diǎn)
標(biāo)簽自定義編輯節(jié)點(diǎn)
文章來源:http://www.zghlxwxcb.cn/news/detail-651453.html
5.修改后的代碼如下
<template>
<div class="all" @click="closeO">
<div style="display: flex; padding: 10px 0">
<div style="margin-right: 10px">
<el-switch v-model="horizontal"></el-switch> {{ horizontal? "橫向": "縱向" }}
</div>
<div style="margin-right: 10px">
<el-switch v-model="collapsable"></el-switch> {{ collapsable? "可收起": "僅展開" }}
</div>
<div style="margin-right: 10px">
<el-switch v-model="disaled"></el-switch> {{ disaled? "禁止編輯": "可編輯" }}
</div>
<div style="margin-right: 10px">
<el-switch v-model="onlyOneNode"></el-switch> {{ onlyOneNode? "僅拖動(dòng)當(dāng)前節(jié)點(diǎn)": "拖動(dòng)當(dāng)前節(jié)點(diǎn)樹" }}
</div>
<div style="margin-right: 10px">
<el-switch v-model="cloneNodeDrag"></el-switch> {{ cloneNodeDrag? "拖動(dòng)節(jié)點(diǎn)副本": "拖動(dòng)節(jié)點(diǎn)本身" }}
</div>
<div style="margin-right: 10px">
<el-switch v-model="pop"></el-switch> {{ pop? "彈窗修改節(jié)點(diǎn)": "標(biāo)簽修改節(jié)點(diǎn)" }}
</div>
</div>
<div style="padding-bottom: 10px" class="pickers">
背景色:
<el-color-picker v-model="style.background" size="small"></el-color-picker> 文字顏色:
<el-color-picker v-model="style.color" size="small"></el-color-picker>
搜索:
<input type="text" v-model="keyword" placeholder="請輸入搜索內(nèi)容" @keydown.enter="filter" />
</div>
<div class="lll">
<div ref="nodeOne" class="nodeOne">
<zm-tree-org ref="tree" :data="data" :disabled="disaled" :horizontal="horizontal" :collapsable="collapsable"
:label-style="style" :node-draggable="true" :default-expand-level="1" :only-one-node="onlyOneNode"
:clone-node-drag="cloneNodeDrag" :node-draging="nodeDragMove" :node-drag-end="nodeDragEnd" :toolBar="toolBar"
:filterNodeMethod="filterNodeMethod" @on-contextmenu="onMenus" @on-expand="onExpand"
@on-node-click="onNodeClick" @on-node-dblclick="onNodeDblclick" @on-node-copy="onNodeCopy"
:define-menus="menus">
<!-- 自定義節(jié)點(diǎn)內(nèi)容 -->
<template slot-scope="{node}">
<div class="tree-org-node__text node-label node" @contextmenu.prevent="terFun(node)">
{{ node.label }}
<div v-if="treeScope && !node.disabled && node.open" class="late" id="lateId">
<el-input type="textarea" placeholder="請輸入內(nèi)容" v-model="cardOne.label" maxlength="30" show-word-limit>
</el-input>
<div @click="close(cardOne)" class="onCloseCss">確定</div>
</div>
</div>
</template>
<!-- 自定義展開按鈕 -->
<template v-slot:expand="{ node }">
<div>{{ node.children.length }}</div>
</template>
</zm-tree-org>
</div>
</div>
</div>
</template>
<script>
import allList from '../../public/orgTree.json'
export default {
data() {
return {
toolBar: {
scale: false,
},
keyword: "",
menus: [{ name: '復(fù)制文本', command: 'copy' }, { name: '新增節(jié)點(diǎn)', command: 'add' }, { name: '編輯節(jié)點(diǎn)', command: 'edit1' }, { name: '刪除節(jié)點(diǎn)', command: 'delete' }],
data: {},
horizontal: false,
collapsable: true,
onlyOneNode: false,//僅拖動(dòng)當(dāng)前節(jié)點(diǎn)
cloneNodeDrag: false,//是否拷貝節(jié)點(diǎn)拖拽 false僅拖拽 true拷貝+保留原位
expandAll: true,
disaled: false,
style: { color: "#fff", background: "#108ffe" },
treeScope: false,
//彈窗
pop: false,
//card組件信息
cardOne: {},
};
},
created() {
this.data = allList.orgAll
},
methods: {
//動(dòng)態(tài)賦值
terFun(node) {
console.log(node)
if (node.disabled || this.disaled) { this.menus = [{ name: '復(fù)制文本', command: 'copy' }] } else {
this.menus = [{ name: '復(fù)制文本', command: 'copy' }, { name: '新增節(jié)點(diǎn)', command: 'add' }, { name: '編輯節(jié)點(diǎn)', command: 'edit1' }, { name: '刪除節(jié)點(diǎn)', command: 'delete' }]
}
},
//右側(cè)菜單點(diǎn)擊事件
onMenus({ node, command }) {
//自定義編輯--彈窗編輯
let labelOld = node.label
if (command === 'edit1' && this.pop && !node.disabled) {
this.$prompt('修改當(dāng)前信息', '編輯', {
confirmButtonText: '確定',
cancelButtonText: '取消',
inputValue: labelOld
}).then((val) => {
this.$message({
type: 'success',
message: '修改成功'
});
// this.editFun(this.data.children, node, val.value)
this.$set(node, 'label', val.value)
}).catch(action => {
if (action === 'cancel') {
this.$message({
type: 'info',
message: '取消輸入'
});
}
});
//當(dāng)前不允許編輯
} else if (node.disabled && command === 'edit1') {
this.$message({
type: 'info',
message: '當(dāng)前內(nèi)容不可編輯'
});
//自定義編輯--card
} else if (command === 'edit1' && !this.pop && !node.disabled) {
this.$set(node, 'open', true)
this.cardOne = node
this.treeScope = true
}
},
//自定義修改屬性值
editFun(data, node, val) {
if (!data || !data.length) {
return;
}
for (let i = 0; i < data.length; i++) {
if (data[i].id === node.id) {
data[i].label = val;
break;
}
this.editFun(data[i].children, node, val);
}
},
//確定 關(guān)閉car界面
close(val) {
this.$delete(val, 'open')
this.treeScope = false
},
//顛倒編輯外區(qū)域,關(guān)閉
closeO(event) {
var currentCli = document.getElementById("lateId");
if (currentCli) {
if (!currentCli.contains(event.target)) {
this.treeScope = false;
}
}
},
//自定義card顯示
filter() {
this.$refs.tree.filter(this.keyword);
},
filterNodeMethod(value, data) {
if (!value) return true;
return data.label.indexOf(value) !== -1;
},
//展開事件
onExpand(e, data) {
},
nodeDragMove(data) {
},
nodeDragEnd(data, isSelf) {
// isSelf && this.$Message.info("移動(dòng)到自身");
},
//點(diǎn)擊節(jié)點(diǎn)
onNodeClick(e, data) {
// this.$Message.info(data.label);
},
onNodeDblclick() {
// this.$Message.info("雙擊節(jié)點(diǎn)");
},
onNodeCopy() {
// this.$Message.success("復(fù)制成功");
},
handleNodeAdd(node) {
// this.$Message.info("新增節(jié)點(diǎn)");
},
expandChange() {
this.toggleExpand(this.data, this.expandAll);
},
//遞歸創(chuàng)建節(jié)點(diǎn)樹
toggleExpand(data, val) {
if (Array.isArray(data)) {
data.forEach((item) => {
this.$set(item, "expand", val);
if (item.children) {
this.toggleExpand(item.children, val);
}
});
} else {
this.$set(data, "expand", val);
if (data.children) {
this.toggleExpand(data.children, val);
}
}
},
},
};
</script>
<style scoped>
.pickers {
display: flex;
}
.node {
position: relative;
}
.nodeOne {
height: 800px;
}
.late {
position: absolute;
top: 20px;
right: -100px;
width: 200px;
min-height: 100px;
z-index: 999;
background: #F2E2BE;
padding: 10px;
}
.onCloseCss {
width: 50px;
height: 30px;
text-align: center;
line-height: 30px;
background: #108FFE;
margin: 10px auto;
z-index: 999;
}
::v-deep .is-edit {
background: palegoldenrod !important;
}
</style>
.json數(shù)據(jù)文章來源地址http://www.zghlxwxcb.cn/news/detail-651453.html
{
"orgAll":{
"id": 1,
"label": "xxx科技有限公司",
"disabled": true,
"children": [
{
"id": 2,
"pid": 1,
"label": "產(chǎn)品研發(fā)部",
"expand": false,
"children": [
{
"id": 6,
"pid": 2,
"label": "禁止編輯節(jié)點(diǎn)",
"disabled": true
},
{
"id": 8,
"pid": 2,
"label": "禁止拖拽節(jié)點(diǎn)",
"noDragging": true
},
{
"id": 7,
"pid": 2,
"label": "研發(fā)-后端",
"children": [
{
"id": 14,
"pid": 7,
"label": "后端1組"
},
{
"id": 15,
"pid": 7,
"label": "后端2組"
}
]
},
{
"id": 13,
"pid": 2,
"label": "研發(fā)-前端"
},
{
"id": 9,
"pid": 2,
"label": "產(chǎn)品經(jīng)理"
},
{
"id": 10,
"pid": 2,
"label": "測試"
}
]
},
{
"id": 3,
"pid": 1,
"label": "客服部",
"children": [
{
"id": 11,
"pid": 3,
"label": "客服一部"
},
{
"id": 12,
"pid": 3,
"label": "客服二部"
}
]
},
{
"id": 4,
"pid": 1,
"label": "業(yè)務(wù)部"
},
{
"id": 5,
"pid": 1,
"label": "人力資源中心"
}
]
}
}
到了這里,關(guān)于zm-org-tree可拖拽的組織樹,簡易好上手的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!