# Tree 树形控件

用清晰的层级结构展示信息,可展开或折叠。

# 基础用法

基础的树形结构展示。

一级 1
一级 2
一级 3
<j-tree :list="data" :props="defaultProps" @click="handleNodeClick"></j-tree>

<script>
  export default {
    data() {
      return {
        data: [{
          label: '一级 1',
          children: [{
            label: '二级 1-1',
            children: [{
              label: '三级 1-1-1'
            }]
          }]
        }, {
          label: '一级 2',
          children: [{
            label: '二级 2-1',
            children: [{
              label: '三级 2-1-1'
            }]
          }, {
            label: '二级 2-2',
            children: [{
              label: '三级 2-2-1'
            }]
          }]
        }, {
          label: '一级 3',
          children: [{
            label: '二级 3-1',
            children: [{
              label: '三级 3-1-1'
            }]
          }, {
            label: '二级 3-2',
            children: [{
              label: '三级 3-2-1'
            }]
          }]
        }],
        defaultProps: {
          children: 'children',
          label: 'label'
        }
      };
    },
    methods: {
      handleNodeClick(data) {
        console.log(data);
      }
    }
  };
</script>
显示代码 复制代码

# 可选择

适用于需要选择层级时使用。

a
b
<j-tree
   tKey="sku"
  :list="data"
  :props="props"
  checkbox
  @check="handleCheckChange">
</j-tree>

<script>
  export default {
    data() {
      return {
        data: [
        { size: 'a', sku: '1',
          childList: [{ size: 'a1', sku: '1-1',
            childList: [{ size: 'a11', sku: '1-1-1',
              childList: [{ size: 'a111', sku: '1-1-1-1' }, { size: 'a112', sku: '1-1-1-2' }]
            }, { size: 'a12', sku: '1-1-2' }] }]
        },
        { size: 'b', sku: '2',
          childList: [{ size: 'b1', sku: '2-1',
            childList: [{ size: 'b11', sku: '2-1-1' }] }]
        }
      ],
        props: {
          label: 'size',
          children: 'childList'
        },
        count: 1
      };
    },
    methods: {
      handleCheckChange( checked, data,nodeData) {
        console.log( checked, data,nodeData);
      }
    }
  };
</script>
显示代码 复制代码

# 默认展开和默认选中

可将 Tree 的某些节点设置为默认展开或默认选中

一级 1
一级 2
二级 2-1
二级 2-2
一级 3

1.分别通过default-openeddefault-checked设置默认展开和默认选中的节点。需要注意的是,此时必须设置t-key,其值为节点数据中的一个字段名,该字段在整棵树中是唯一的;2.也可设置数据中对应的$checked$opened来达到默认选中,默认展开的效果;

<j-tree
  :list="data"
  checkbox
  t-key="id"
  :default-opened="[3]"
  :default-checked="[5]"
  :props="defaultProps">
</j-tree>

<script>
  export default {
    data() {
      return {
        data: [{
          id: 1,
          label: '一级 1',
          $checked:true,
          children: [{
            id: 4,
            label: '二级 1-1',
            children: [{
              id: 9,
              label: '三级 1-1-1'
            }, {
              id: 10,
              label: '三级 1-1-2'
            }]
          }]
        }, {
          id: 2,
          label: '一级 2',
          $opened:true,
          children: [{
            id: 5,
            label: '二级 2-1'
          }, {
            id: 6,
            label: '二级 2-2'
          }]
        }, {
          id: 3,
          label: '一级 3',
          children: [{
            id: 7,
            label: '二级 3-1'
          }, {
            id: 8,
            label: '二级 3-2'
          }]
        }],
        defaultProps: {
          children: 'children',
          label: 'label'
        }
      };
    }
  };
</script>
显示代码 复制代码

# 展开/关闭所有选中节点和展开/关闭所有节点

可通过 tree 的指定方法达成所需效果

一级 1
一级 2
一级 3
<j-tree
  :list="data"
  ref="tree1"
  checkbox
  t-key="id"
  :props="defaultProps">
</j-tree>

<j-button class="small" @click="$refs.tree1.openChecked()">展开选中节点</j-button>
<j-button class="small" @click="$refs.tree1.closeUnchecked()">折叠未选中添加节点</j-button>
<j-button class="small" @click="$refs.tree1.openAll()">展开所有节点</j-button>
<j-button class="small" @click="$refs.tree1.closeAll()">折叠所有节点</j-button>
<script>
  export default {
    data() {
      return {
        data: [{
          id: 1,
          label: '一级 1',
          children: [{
            id: 4,
            label: '二级 1-1',
            children: [{
              id: 9,
              label: '三级 1-1-1'
            }, {
              id: 10,
              label: '三级 1-1-2',
              children: [{
                $checked:true,
                id: 11,
                label: '三级 1-1-1'
              }, {
                id: 12,
                label: '三级 1-1-2'
              }]
            }]
          }]
        }, {
          id: 2,
          label: '一级 2',
          children: [{
            id: 5,
            label: '二级 2-1'
          }, {
            id: 6,
            label: '二级 2-2'
          }]
        }, {
          id: 3,
          label: '一级 3',
          children: [{
            id: 7,
            label: '二级 3-1'
          }, {
            id: 8,
            label: '二级 3-2'
          }]
        }],
        defaultProps: {
          children: 'children',
          label: 'label'
        }
      };
    }
  };
</script>
显示代码 复制代码

# 禁用状态

可将 Tree 的某些节点设置为禁用状态

一级 2

通过$disabled设置禁用状态。

<j-tree
  :list="data"
  checkbox
  t-key="id"
  :default-opened="[2, 3]"
  :default-checked="[5]">
</j-tree>

<script>
  export default {
    data() {
      return {
        data: [{
          id: 1,
          label: '一级 2',
          children: [{
            id: 3,
            label: '二级 2-1',
            children: [{
              id: 4,
              label: '三级 3-1-1'
            }, {
              id: 5,
              label: '三级 3-1-2',
              $disabled: true
            }]
          }, {
            id: 2,
            label: '二级 2-2',
            $disabled: true,
            children: [{
              id: 6,
              label: '三级 3-2-1'
            }, {
              id: 7,
              label: '三级 3-2-2',
              $disabled: true
            }]
          }]
        }],
        defaultProps: {
          children: 'children',
          label: 'label'
        }
      };
    }
  };
</script>
显示代码 复制代码

# 树节点的选择

本例展示如何获取和设置选中节点。获取和设置各有两种方式:通过 key。如果需要通过 key 来获取或设置,则必须设置t-key

如果需要默认选中样式,可以使用setCurrentKey,前提是必须设置highlight-current属性

<j-tree
  :list="data"
  checkbox
  opened-all
  t-key="id"
  ref="tree"
  highlight-current
  :props="defaultProps">
</j-tree>

<div class="buttons">
  <j-button @click="getChecked">获取选中数据</j-button>
  <j-button @click="setChecked">通过 key 设置</j-button>
  <j-button @click="resetChecked">清空</j-button>
</div>

<script>
  export default {
    mounted(){
      this.$refs.tree.setCurrentKey(1);
    },
    methods: {
      getChecked() {
        console.log(this.$refs.tree.getChecked());
      },
      setChecked() {
        this.$refs.tree.setChecked([3]);
      },
      resetChecked() {
        this.$refs.tree.setChecked([]);
      }
    },

    data() {
      return {
        data: [{
          id: 1,
          label: '一级 1',
          children: [{
            id: 4,
            label: '二级 1-1',
            children: [{
              id: 9,
              label: '三级 1-1-1'
            }, {
              id: 10,
              label: '三级 1-1-2'
            }]
          }]
        }, {
          id: 2,
          label: '一级 2',
          children: [{
            id: 5,
            label: '二级 2-1'
          }, {
            id: 6,
            label: '二级 2-2'
          }]
        }, {
          id: 3,
          label: '一级 3',
          children: [{
            id: 7,
            label: '二级 3-1'
          }, {
            id: 8,
            label: '二级 3-2'
          }]
        }],
        defaultProps: {
          children: 'children',
          label: 'label'
        }
      };
    }
  };
</script>
显示代码 复制代码

# 自定义节点内容

节点的内容支持自定义,可以在节点区添加按钮或图标等内容

一级 1
二级 1-1
三级 1-1-1
三级 1-1-2
一级 2
二级 2-1
二级 2-2
一级 3
二级 3-1
二级 3-2

可以通过两种方法进行树节点内容的自定义:render-content和 scoped slot。使用render-content指定渲染函数,该函数返回需要的节点区内容即可。渲染函数的用法请参考 Vue 文档。使用 scoped slot 会传入两个参数nodedata,分别表示当前节点的 Node 对象和当前节点的数据。注意:由于 jsfiddle 不支持 JSX 语法,所以render-content示例在 jsfiddle 中无法运行。但是在实际的项目中,只要正确地配置了相关依赖,就可以正常运行。

<j-tree
  ref="treeZdy"
  :list="data"
  t-key="id"
  opened-all
  @click="handleNodeClick">
  <span class="custom-tree-node" slot-scope="{ vnode, data }">
    <span>{{data.label}}</span>
    <span style="margin-left:20px;">
        <i class="j-icon icon-add-select" @click.stop="addChild(data)"></i>
        <i class="j-icon icon-sami-select" @click.stop="deleteChild(data,vnode)"></i>
    </span>
  </span>
</j-tree>
<j-button @click="addActiveChild">添加子节点</j-button>
<script>
  var id=1000;

  export default {
    data() {
      const data = [{
        id: 1,
        label: '一级 1',
        children: [{
          id: 4,
          label: '二级 1-1',
          children: [{
            id: 9,
            label: '三级 1-1-1',
            children:[]
          }, {
            id: 10,
            label: '三级 1-1-2',
            children:[]
          }]
        }]
      }, {
        id: 2,
        label: '一级 2',
        children: [{
          id: 5,
          label: '二级 2-1',
          children:[]
        }, {
          id: 6,
          label: '二级 2-2',
          children:[]
        }]
      }, {
        id: 3,
        label: '一级 3',
        children: [{
          id: 7,
          label: '二级 3-1',
          children:[]
        }, {
          id: 8,
          label: '二级 3-2',
          children:[]
        }]
      }];
      return {
        data: JSON.parse(JSON.stringify(data)),
      }
    },

    methods: {
      handleNodeClick(data,vnode){
        console.log(data,vnode);
      },
      addChild(data){
        const newChild = {id:id++,label: 'testtest'+id, children: [] };
         if (!data.children) {
          this.$set(data, 'children', []);
        }
        data.children.push(newChild);
      },
      deleteChild(data,vnode){
        const parent = vnode.componentInstance.parent;
        if(parent){
          const index = parent.children.findIndex(d => d.id === data.id);
          parent.children.splice(index, 1);
        }else{
          const index = this.data.findIndex(d => d.id === data.id);
          this.data.splice(index, 1);
        }
      },
      addActiveChild(){
        // 当前子节点添加,若无选中节点则添加到根节点
        this.$refs.treeZdy.appendActivedTree([{id:id++,label: 'testtest'+id, children: [] }])
        // 当前子节点指定位置添加
        //this.$refs.treeZdy.appendActivedTree([{id:id++,label: 'testtest'+id, children: [] }],1)
        // 根节点添加
        // this.$refs.treeZdy.appendActivedTree([{id:id++,label: 'testtest'+id, children: [] }],1,true)
      }
    }
  };
</script>
<style>
  .custom-tree-node{
    width:50%;
    display:flex;
  }
  .icon-add-select{
    color:#257fea;
  }
  .icon-sami-select{
    color:red;
  }
</style>
显示代码 复制代码

# 手风琴模式

对于同一级的节点,每次只能展开一个

一级 1
一级 2
一级 3
<j-tree
  :list="data"
  :props="defaultProps"
  accordion
  @click="handleNodeClick">
</j-tree>

<script>
  export default {
    data() {
      return {
        data: [{
          label: '一级 1',
          children: [{
            label: '二级 1-1',
            children: [{
              label: '三级 1-1-1'
            }]
          }]
        }, {
          label: '一级 2',
          children: [{
            label: '二级 2-1',
            children: [{
              label: '三级 2-1-1'
            }]
          }, {
            label: '二级 2-2',
            children: [{
              label: '三级 2-2-1'
            }]
          }]
        }, {
          label: '一级 3',
          children: [{
            label: '二级 3-1',
            children: [{
              label: '三级 3-1-1'
            }]
          }, {
            label: '二级 3-2',
            children: [{
              label: '三级 3-2-1'
            }]
          }]
        }],
        defaultProps: {
          children: 'children',
          label: 'label'
        }
      };
    },
    methods: {
      handleNodeClick(data) {
        console.log(data);
      }
    }
  };
</script>
显示代码 复制代码

# Attributes

参数 说明 类型 可选值 默认值
data 展示数据 array
empty-text 内容为空的时候展示的文本 String
t-key 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的 String
props 配置选项,具体看下表 object
render-after-opened 是否在第一次展开某个树节点后才渲染其子节点 boolean true
opened-all 是否默认展开所有节点 boolean false
default-opened 默认展开的节点的 key 的数组 array
checkbox 节点是否可被选择 boolean false
default-checked 默认勾选的节点的 key 的数组 array
accordion 是否每次只打开一个同级树节点展开 boolean false
check-level 选择层级联动 boolean false

# props

参数 说明 类型 可选值 默认值
label 指定节点标签为节点对象的某个属性值 string, function(data, node)
children 指定子树为节点对象的某个属性值 string
disabled 指定节点选择框是否禁用为节点对象的某个属性值 boolean, function(data, node)

# 方法

Tree 内部使用了 Node 类型的对象来包装用户传入的数据,用来保存目前节点的状态。 Tree 拥有如下方法:

方法名 说明 参数
getChecked 若节点可被选择(即 checkboxtrue),则返回目前被选中的节点所组成的数组,使用此方法必须设置 t-key 属性
setChecked 设置勾选的节点, 使用此方法必须设置 t-key 属性 勾选节点的 key 的数组
openChecked 展开所有复选框选中的节点
closeUnchecked 折叠所有复选框未选中的节点
openAll 展开所有节点
closeAll 折叠所有节点
setCurrentKey 默认选中节点样式

# Events

事件名称 说明 回调参数
click 节点被点击时的回调 共两个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node。
check 当复选框被点击的时候触发 共三个参数,依次为:树目前的选中状态对象、传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node
item-dblclick 没有子集的节点被双击时的回调 共两个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node。

# Scoped Slot

name 说明
自定义树节点的内容,参数为 { vnode, data }