相关文章推荐

3.vue-org-tree 地址: https://github.com/hukaibaihu/vue-org-tree

这是一个纯vue版本,我喜欢它的缩进方式和样式,同时它也是github上星星最多的。

经过对比,我选择了vue-org-tree,但它只是相当于提供了模板,要实现自己的功能需要对插件进行改造。

vue-org-tree安装和使用:

# use npm
npm i vue2-org-tree --save
# use yarn
yarn add vue2-org-tree

main.js

import Vue from 'vue'
import Vue2OrgTree from 'vue2-org-tree'
Vue.use(Vue2OrgTree)

组件应用案例看这个: https://github.com/hukaibaihu/vue-org-tree/blob/gh-pages/index.html

可以直接复制运行。api也直接看github官网

可以看出来此组件官方只给了展示数据功能,增删改功能并没有明确给出,这就需要我们自己对组件进行改造。

因为是vue,所以对节点的增删改离不开对数据的增删改,侧重点是对于数据的处理才对。

vue-org-tree源码分析

我这里简单分析一下源码和改造

安装好vue-org-tree后,找到node_modules->vue2-org-tree文件夹

其中org-tree.vue为组件入口,node.js使用 渲染函数 动态渲染节点组件

关于渲染函数,看这个: https://cn.vuejs.org/v2/guide/render-function.html

org-tree.vue:

<template>
  <div class="org-tree-container">
    <div class="org-tree" :class="{horizontal, collapsable}">
      <org-tree-node
        :data="data"
        :props="props"
        :horizontal="horizontal"
        :label-width="labelWidth"
        :collapsable="collapsable"
        :render-content="renderContent"
        :label-class-name="labelClassName"
		:selectedKey="selectedKey"
		:selectedClassName="selectedClassName"
        @on-expand="(e, data) => {$emit('on-expand', e, data)}"
        @on-node-click="(e, data) => {$emit('on-node-click', e, data)}"
</template>
<script>
import render from './node'
export default {
  name: 'Vue2OrgTree',
  components: {
    OrgTreeNode: {
      render,
      functional: true
  props: {
    data: {
      type: Object,
      required: true
    props: {
      type: Object,
      default: () => ({
        label: 'nodeName',
        expand: 'expand',
        children: 'children',
		dataCnt:'dataCnt',
		labelType:'nodeType',
		selectedKey:'nodeId'
    horizontal: Boolean,
    selectedKey: [String,Number],
    collapsable: Boolean,
    renderContent: Function,
    labelWidth: [String, Number],
    labelClassName: [Function, String],
    selectedClassName: [Function, String]
</script>
<style lang="less">
@import '../../styles/org-tree';
</style>

此vue的功能主要是接收数据和参数用的,org-tree-node是用来生成结构图节点的。重点在于这里:

一般来说组件都会引入一个vue

这里直接引入了一个render,一看就是个函数式渲染,一般的渲染函数为:

render: function (createElement) {
  return createElement('h1', "这是生成的内容")

createElement为vue中的生成dom的方法,在vue中一般用”h”代替。

如有时初始化vue时这么写:

new Vue({
  render: h => h(App),
}).$mount('#app')
render:function(createElement){
    return createElment(App)

直接生成组件元素,省去了设置components

类似于js原生中的createElement方法,不过原生中传的参数为节点名,如:

var btn=document.createElement("BUTTON");

而vue中的createElement中的参数 先看教程:

https://cn.vuejs.org/v2/guide/render-function.html#createElement-%E5%8F%82%E6%95%B0

第一个参数一般为html标签名或者组件(如上面例子直接传一个组件都能渲染出来),第二个为配置元素属性,第三个为配置子元素(可传字符串或者vnode数组)

vnode就是通过createElement创建出来的虚拟节点。

(太绕了,一定要好好看文档掌握基础知识)

但这种渲染函数没有状态管理和事件监听,所以vue还可以在render下面加一个functional:true,把它变成“函数式组件”

教程:https://cn.vuejs.org/v2/guide/render-function.html#%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BB%84%E4%BB%B6

render: function (createElement, context) {
    // ...
functional:ture

那么回到org-tree.vue中,node.js中返回的一定是类似 function(h,context){}的函数。

node.js:

// 判断是否叶子节点
const isLeaf = (data, prop) => {
  return !(Array.isArray(data[prop]) && data[prop].length > 0)
// 创建 node 节点
export const renderNode = (h, data, context) => {
  const { props } = context
  const cls = ['org-tree-node']
  const childNodes = []
  const children = data[props.props.children]
  if (isLeaf(data, props.props.children)) {
    cls.push('is-leaf')
  } else if (props.collapsable && !data[props.props.expand]) {
    cls.push('collapsed')
  childNodes.push(renderLabel(h, data, context))
  if (!props.collapsable || data[props.props.expand]) {
    childNodes.push(renderChildren(h, children, context))
  return h('div', {
    domProps: {
      className: cls.join(' ')
  }, childNodes)
// 创建展开折叠按钮
export const renderBtn = (h, data, { props, listeners }) => {
  const expandHandler = listeners['on-expand']
  let cls = ['org-tree-node-btn']
  if (data[props.props.expand]) {
    cls.push('expanded')
  return h('span', {
    domProps: {
      className: cls.join(' ')
    on: {
      click: e => expandHandler && expandHandler(e,data)
// 创建 label 节点
export const renderLabel = (h, data, context) => {
  const { props, listeners } = context
  const label = data[props.props.label]
	const labelType=data[props.props.labelType]
	const dataCnt=data[props.props.dataCnt]
	//console.log(label)
  const renderContent = props.renderContent
  const clickHandler = listeners['on-node-click']
  const childNodes = []
	if(labelType=="tag" || labelType=="root"){
		if (typeof renderContent === 'function') {
		  let vnode = renderContent(h, data)
		  vnode && childNodes.push(vnode)
		} else {
		  childNodes.push(label)
	}else if(labelType=="domain"){
		childNodes.push(label)
		childNodes.push(h('br', {
		childNodes.push(dataCnt)
  if (props.collapsable && !isLeaf(data, props.props.children)) {
    childNodes.push(renderBtn(h, data, context))
  const cls = ['org-tree-node-label-inner']
  let { labelWidth, labelClassName, selectedClassName, selectedKey } = props
	if(labelType == "root"){
		cls.push("bg-blue")
	}else if(labelType == "tag"){
		cls.push("bg-orange")
	}else if(labelType == "domain"){
		cls.push("bg-gray")
  if (typeof labelWidth === 'number') {
    labelWidth += 'px'
  if (typeof labelClassName === 'function') {
    labelClassName = labelClassName(data)
  labelClassName && cls.push(labelClassName)
  // add selected class and key from props
  if (typeof selectedClassName === 'function') {
    selectedClassName = selectedClassName(data)
  //给选中节点加class
  if(selectedKey == data[props.props.selectedKey]){
	  cls.push(selectedClassName)
 /* console.log(selectedKey)
  console.log(selectedClassName)
  selectedClassName && selectedKey && data[selectedKey] && cls.push(selectedClassName) */
  return h('div', {
    domProps: {
      className: 'org-tree-node-label'
  }, [h('div', {
    domProps: {
      className: cls.join(' ')
    style: { width: labelWidth },
    on: {
      click: e => clickHandler && clickHandler(e, data)
  }, childNodes)])
// 创建 node 子节点
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 ''
export const render = (h, context) => {
  const {props} = context
  return renderNode(h, props.data, context)
export default render

可见,确实返回的是render函数。

接下来的步骤就是renderNode-》renderLabel-》renderChildren-》renderBtn

理解了createElement方法,这些步骤都很好看懂。在里面改自己的业务需求就行。

需要注意的是在renderLabel中节点和展开按钮为同一个label,一般点击节点时肯定不想让点击按钮也触发,则这么处理:

onNodeClick: function(e, data) {
		//看是节点还是按钮
		var target=e.target;
		var classList=[...e.target.classList];
		var label=classList.find(item=> item=="org-tree-node-label-inner")
		if(label){
			this.$store.commit("setCurrentNode",data)
		}else{
			//alert(111)
                    需求:最近业务需要做类似思维导图的组织结构树功能,需要能动态增删改节点,且每层的节点样式并不相同可用插件:网上能找到的组织结构图插件有:1.orgchart.js 地址:https://github.com/dabeng/OrgChart.js这个缩进方式太另类了,个人不喜欢;2.vue-orgchart 地址:https://github.com/spiritre...
import Vue from 'vue'
import Vue2OrgTree from 'vue2-org-tree'
Vue . use ( Vue2OrgTree )
// ...
# css
< link href =" https://unpkg.com/vue2-org-tree/dist/style.css " >
< script src ="
<link href="https://unpkg.com/vue2-org-tree/dist/style.css" rel="stylesheet">
<template>
    <el-card :style="{height: scrollHeight}" style="ove
d3-org-tree是使用d3.js v5构建的高度可定制的树,可以在现代浏览器(例如Chrome , Edge , Firefox和Safari 。 除d3.js外,它没有任何第三方依赖性。
 某些d3-org-tree功能:
 自定义节点样式,包括svg和通过template纯HTML dom
 自定义节点行为,包括expand子节点, add子节点并delete它
自定义当前节点的highlight样式,并可以手动更改当前节点
预设或动态更改布局orientation ,链接样式以及是否display arrows
 预设svg容器的width/height和内容的边距偏移
预设变换动画的duration
 在节点click上自定义回调函数, add和remove事件
npm i d3-org-tree
import OrgTree from "d3-
				
如何使用vue2-org-tree来展示出架构关系,首先在vue-cli项目中npm i vue2-org-tree 插件 在main.js中引用 import Vue2OrgTree from ‘’ vue2-org-tree’’; Vue.use( Vue2OrgTree ) * 必须下载 npm i --save -D less less-loader , 不下载less就会报错,因为vue-org-tree内部就是lang= ‘’less’’ 规则(less-loader版本不能太高,不兼容..
如果你在 Vue 中使用 vue-org-tree 时遇到了问题,可以尝试以下几个步骤: 1. 确认你已经正确引入了 vue-org-tree 组件,可以在你的 Vue 组件中检查是否已经引入。例如: import VueOrgTree from 'vue-org-tree' export default { components: { VueOrgTree 2. 确认你已经正确使用了 vue-org-tree 组件,可以在你的 Vue 组件模板中检查是否已经使用。例如: <template> <vue-org-tree :data="treeData"></vue-org-tree> </template> 3. 确认你的数据格式是否正确,vue-org-tree 要求传入的数据格式是一个具有层级关系的树形结构,例如: label: 'Node 1', children: [ label: 'Node 1.1', children: [] label: 'Node 1.2', children: [ label: 'Node 1.2.1', children: [] 4. 确认你已经正确引入了 vue-org-tree 的 CSS 文件,可以在你的 HTML 文件中检查是否已经引入。例如: <link rel="stylesheet" href="path/to/vue-org-tree.css"> 如果以上步骤都没有解决问题,可以提供更多的信息,例如你的代码和具体的错误信息,方便更好地帮助你解决问题。
 
推荐文章