element-tree-line
Version:
给element-ui和element-plus的el-tree组件添加结构线的子组件
190 lines (187 loc) • 7.32 kB
JavaScript
function getComConfig(h) {
return {
name: 'element-tree-line',
props: {
node: {
type: Object,
required: true,
},
data: {
type: Object,
},
treeData: {
type: Array,
},
indent: {
type: Number,
default() {
return 16;
},
},
showLabelLine: {
type: Boolean,
default: true,
},
},
render(createElement) {
const $createElement = h || createElement;
// 自定义整行节点label区域
const scopeSlotDefault = this.getScopedSlot('default');
// 显示横线时自定义节点label区域
const labelSlot = this.getScopedSlot('node-label');
// 显示横线时追加在横线右边的内容
const afterLabelSlot = this.getScopedSlot('after-node-label');
const labelNodes = scopeSlotDefault
? this.getScopedSlotValue(scopeSlotDefault, {
node: this.node,
data: this.data,
})
: [
labelSlot
? this.getScopedSlotValue(labelSlot, {
node: this.node,
data: this.data,
})
: $createElement(
'span',
{ class: 'element-tree-node-label' },
this.node.label
),
this.showLabelLine
? $createElement('span', {
class: 'element-tree-node-label-line',
})
: null,
this.getScopedSlotValue(afterLabelSlot, {
node: this.node,
data: this.data,
}),
];
// 取得每一层的当前节点是不是在当前层级列表的最后一个
const lastnodeArr = [];
let currentNode = this.node;
while (currentNode) {
let parentNode = currentNode.parent;
// 兼容element-plus的 el-tree-v2 (Virtualized Tree 虚拟树)
if (currentNode.level === 1 && !currentNode.parent) {
// el-tree-v2的第一层node是没有parent的,必需 treeData 创建一个parent
if (!this.treeData || !Array.isArray(this.treeData)) {
throw Error(
'if you using el-tree-v2 (Virtualized Tree) of element-plus,element-tree-line required data.'
);
}
parentNode = {
children: Array.isArray(this.treeData)
? this.treeData.map((item) => {
return { ...item, key: item.id };
})
: [],
level: 0,
key: 'node-0',
parent: null,
};
}
if (parentNode) {
// element-plus的 el-tree-v2 使用的是children和key, 其他使用的是 childNodes和id
const index = (
parentNode.children || parentNode.childNodes
).findIndex(
(item) =>
(item.key || item.id) ===
(currentNode.key || currentNode.id)
);
lastnodeArr.unshift(
index ===
(parentNode.children || parentNode.childNodes)
.length -
1
);
}
currentNode = parentNode;
}
const lineNodes = [];
for (let i = 0; i < this.node.level; i++) {
if (lastnodeArr[i] && this.node.level - 1 !== i) {
continue;
}
lineNodes.push(
$createElement('span', {
class: {
'element-tree-node-line-ver': true,
'last-node-isLeaf-line':
lastnodeArr[i] && this.node.level - 1 === i,
},
style: { left: this.indent * i + 'px' },
})
);
}
return $createElement(
'span',
{
class: 'element-tree-node-label-wrapper',
},
[labelNodes].concat(lineNodes).concat([
$createElement('span', {
class: 'element-tree-node-line-hor',
style: {
width: (this.node.isLeaf ? 24 : 8) + 'px',
left: (this.node.level - 1) * this.indent + 'px',
},
}),
])
);
},
methods: {
getScopedSlot(slotName) {
if (!slotName) {
return null;
}
const slotNameSplits = slotName.split('||');
let scopeSlot = null;
for (let index = 0; index < slotNameSplits.length; index++) {
const name = slotNameSplits[index];
const slot = (this.$slots || {})[name];
if (slot) {
scopeSlot = slot;
break;
}
scopeSlot = (this.$scopedSlots || {})[name];
if (scopeSlot) {
break;
}
}
return scopeSlot;
},
getScopedSlotValue(scopeSlot, scopedData, defaultNode = null) {
if (typeof scopeSlot === 'function') {
return scopeSlot(scopedData) || defaultNode;
}
return scopeSlot || defaultNode;
},
},
};
}
function getElementLabelLine(h) {
const conf = getComConfig(h);
if (h) {
conf.methods.getScopedSlot = function getScopedSlot(slotName) {
if (!slotName) {
return null;
}
const slotNameSplits = slotName.split('||');
let scopeSlot = null;
for (let index = 0; index < slotNameSplits.length; index++) {
const name = slotNameSplits[index];
const slot = (this.$slots || {})[name];
if (slot) {
scopeSlot = slot;
break;
}
}
return scopeSlot;
};
}
return conf;
}
const ElementLabelLine = getElementLabelLine();
export { ElementLabelLine as default, getElementLabelLine };