В связи с потребностями бизнеса компании необходимо разработать древовидный компонент, отображающий организационную структуру (проект компании основан на Vue). После долгих поисков на GitHub таких компонентов не так много, и нет компонентов, отвечающих потребностям бизнеса, поэтому я решил собрать свои собственные колеса!
анализировать
- Поскольку это дерево, каждый узел должен быть одним и тем же компонентом.
- Узел устанавливается ниже узла, поэтому компонент узла должен бытьРекуррентный компонент
Ну вот и проблема. Как писать рекурсивные компоненты?
рекурсивный компонент
Официальная документация VueВот что он говорит:
Компонент может рекурсивно вызывать себя в пределах своего шаблона. Однако это возможно только в том случае, если у него есть опция имени
Далее напишем рекурсивный компонент узла дерева:
<template>
<div class="org-tree-node">
<div class="org-tree-node-label">{{data.label}}</div>
<div class="org-tree-node-children" v-if="data.children">
<org-tree-node v-for="node in data.children" :data="node" :key="data.id"></org-tree-node>
</div>
</div>
</template>
<script>
export default {
name: 'OrgTreeNode',
props: {
data: Object
}
}
</script>
<style>
/* ... */
</style>
Затем визуализируйте этот компонент, эффект будет следующим
На данный момент простой компонент организационного дерева завершен.
Однако дела еще далеки от завершения. . .
Требования: Метка узла должна поддерживать настройку, а дерево должно поддерживать горизонтальное отображение!
Поэтому мы модифицируем рекурсивный компонент следующим образом:
<template>
<div class="org-tree-node">
<div class="org-tree-node-label">
<slot>{{data.label}}</slot>
</div>
<div class="org-tree-node-children" v-if="data.children">
<org-tree-node v-for="node in data.children" :data="node" :key="data.id"></org-tree-node>
</div>
</div>
</template>
<script>
export default {
name: 'OrgTreeNode',
props: {
data: Object
}
}
</script>
<style>
/* ... */
</style>
Мы используем слот-слоты для поддержки настраиваемости меток, но здесь возникает проблема: мы обнаружили, что только метки узлов на первом уровне могут быть настроены, а вложенные дочерние узлы не могут эффективно передавать слоты-слоты. Я долго проверял интернет, но все равно никаких результатов, поэтому посмотрел официальную документацию. найтифункциональные компоненты.由于之前使用过element-ui
изtree
компонент, вдохновленный идеей, что он может быть какelement-ui
изtree
Передайте компонент, напримерrenderContent
Функция, вызывающая сторона сама отображает метку узла, чтобы достичь цели настройки узла!
функциональные компоненты
Затем мы преобразуем компонент шаблона узла дерева в функциональный компонент. Напишите node.js:
-
Сначала мы реализуем функцию рендеринга
export const render = (h, context) => { const {props} = context return renderNode(h, props.data, context) }
-
Реализовать функцию renderNode
export const renderNode = (h, data, context) => { const {props} = context const childNodes = [] childNodes.push(renderLabel(h, data, context)) if (props.data.children && props.data.children.length) { childNodes.push(renderChildren(h, props.data.children, context)) } return h('div', { domProps: { className: 'org-tree-node' } }, childNodes) }
-
Реализуйте функцию renderLabel. Ключ к настройке метки узла находится здесь:
export const renderLabel = (h, data, context) => { const {props} = context const renderContent = props.renderContent const childNodes = [] // 节点label定制,由调用者传入的renderContent实现 if (typeof renderContent === 'function') { let vnode = renderContent(h, props.data) vnode && childNodes.push(vnode) } else { childNodes.push(props.data.label) } return h('div', { domProps: { className: 'org-tree-node-label' } }, childNodes) }
-
Реализуйте функцию renderChildren. Здесь рекурсивно вызывается renderNode, который реализует рекурсивный компонент
export const renderChildren = (h, list, context) => { if (Array.isArray(list) && list.length) { const children = list.map(item => { return renderNode(h, item, context) }) return h('div', { domProps: { className: 'org-tree-node-children' } }, children) } return '' }
На этом наша функция рендеринга завершена, а затем используйте функцию рендеринга для определения функциональных компонентов. В компоненте дерева объявите:
<template>
<!-- ... -->
</template>
<script>
import render from './node.js'
export default {
name: 'OrgTree',
components: {
OrgTreeNode: {
render,
// 定义函数式组件
functional: true
}
}
}
</script>
На этом преобразование нашего функционального компонента завершено, и горизонтальным отображением можно управлять с помощью стиля.
CSS-стиль
Стили предварительно компилируются с помощью less. Линии между узлами:before
,:after
псевдоэлементborder
рисовать
расширение функции
- Добавлен
labelClassName
Атрибут для поддержки настройки стиля меток узлов - Добавлен
labelWidth
Атрибут для ограничения ширины метки узла - Добавлен
props
атрибут, ссылкаelement-ui
изtree
Реквизиты компонентов для поддержки сложных структур данных - Добавлен
collapsable
Атрибуты для поддержки расширения и свертывания дочерних узлов (операции развертывания и свертывания должны быть реализованы вызывающей стороной)
только начал использовать
flex
Макет, но для совместимости с IE9, позже был изменен наdisplay: table
макет
окончательный эффект
-
default
-
horizontal
краткое изложение проблемы
- Хранилище дерева может быть определено для хранения состояния каждого узла, так что расширяемые и сворачиваемые состояния узлов дерева могут поддерживаться внутри.
Наконец, прикрепите исходный код портала:GitHub.com/Ху Кайбайху/… !