190 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			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 };
 |