# SyncTree 异步树

版本:1.13.0

开发:徐子龙

# 异步树使用须知

  1. 异步树是为了解决大数据量下树节点展示和操作问题,它根据isc项目实际应用场景设计(交互设计文档)需要一定后台数据的支持。无法支持所有需求,异步树组件对此一般也不再会进行大幅度的调整和改动;
  2. 单选异步树和多选异步树可能存在不同的数据方式,在以往版本中,单选异步树我们要求后台分页返回数据,多选异步树要求后台一次返回所有数据;
  3. 与HUI的树不同,异步树联动勾选仅支持父联动子(子节点的勾选与去勾选不会影响父节点),且没有半选的概念;
  4. 异步树要实现分页效果,它的数据节点格式如下:
{
  "lastPage": false,
  "rows": [
    { "id": 1, "name": "节点1", "open": true },
    { "id": 2, "name": "节点2", "open": true },
    { "id": 3, "name": "节点3", "open": true }
  ]
}

其中lastPagefalse时,代表存在下一页数据,则节点末会出现......的符号可点击展开。open属性代表节点加载后是否自动展开。rows这个字段是写死的,其余字段均可在组件中配置。

  1. 异步树的性能不是无限的,在页面已加载和展示的数据太多时,还是会出现性能问题。
  2. 如果引用后出现不显示数据或是数据无限加载的问题,请检查传入的根节点数据是否有问题。

# 安装

$ npm i @hui-pro/sync-tree -D
# 或者
$ yarn add @hui-pro/sync-tree --dev

# 引入

import syncTree from '@hui-pro/sync-tree';
import '@hui-pro/sync-tree/theme/index.scss';
Vue.use(syncTree);

# 单选异步树

当前查看数据量较大,流畅度会有所下降,建议使用搜索。
搜索结果过多,仅展示前500条,建议缩小搜索范围。
暂无数据
单选异步树
<template>
  <div style="width: 320px;">
    <sync-tree
      :map="map"
      :pageSize="20"
      :node-limit="50"
      :set-tree-data="setTreeData"
      :set-search-data="setSearchData"
    ></sync-tree>
  </div>
</template>

<script>
  import api from '@/api/api'
  export default {
    data() {
      return {
        map: {
          children: 'children',
          label: 'name',
          isLeaf: 'leaf',
          icon: 'iconSkin'
        }
      }
    },
    methods: {
      setTreeData ({parentId, pageNo, pageSize, keyWord}) {
        return new Promise(async(resolve, reject) => {
          try {
            let {data} = await api.fetchUnitTree({pId: parentId, pageNo, pageSize})
            resolve(data)
          } catch (err) {
            console.error(err)
          }
        })
      },
      setSearchData (keyWord) {
        return new Promise(async(resolve, reject) => {
          try {
            let {data} = await api.fetchSearchTree({keyWord})
            resolve(data)
          } catch (err) {
            console.error(err)
          }
        })
      }
    }
  }
</script>

# 多选异步树

当前查看数据量较大,流畅度会有所下降,建议使用搜索。
搜索结果过多,仅展示前500条,建议缩小搜索范围。
暂无数据
多选异步树
<template>
  <div style="width: 320px;">
    <sync-tree
      :map="map"
      :highlight-current="false"
      type="sync"
      :pageSize="20"
      :node-limit="50"
      :set-tree-data="setTreeData"
      :set-search-data="setSearchData"
    ></sync-tree>
  </div>
</template>

<script>
  import api from '@/api/api'
  export default {
    data() {
      return {
        map: {
          children: 'children',
          label: 'name',
          isLeaf: 'leaf',
          icon: 'iconSkin'
        }
      }
    },
    methods: {
      setTreeData ({parentId, pageNo, pageSize, keyWord}) {
        return new Promise(async(resolve, reject) => {
          try {
            let {data} = await api.fetchRealTree()
            resolve(data)
          } catch (err) {
            console.error(err)
          }
        })
      },
      setSearchData (keyWord) {
        return new Promise(async(resolve, reject) => {
          try {
            let {data} = await api.fetchSearchTree({keyWord})
            resolve(data)
          } catch (err) {
            console.error(err)
          }
        })
      }
    }
  }
</script>

# API

# Attributes

参数 说明 类型 可选值 默认值
map 映射关系(和HUI-tree上的props属性相同) Object - {children: "children", label: "name", isLeaf: "leaf", icon: "iconSkin", disabled: "chkDisabled", selectable: "selectable"}
type 1.3.3+ 类型 String async:异步(后台分页);sync:同步(前端分页);mixed:混合;hierarchical:分层(父子后台分页,同级前端分页) async
page-size 每页数据量 Number - 100
node-key tree上的node-key String - id
parent-key tree上的parent-key String - pId
search-text 搜索框的文字,可加.sync修饰符 String - -
node-type-values 1.3.3+ 节点nodeType对应的值 Object - { singleNode: 'singleNode', subTree: 'subTree' }
root-parent-key 1.3.3+ 根节点父节点对应的值(默认父节点Id为null,'0','-1'算根节点) String/Number - null
loading 是否处于加载状态 Boolean - false
set-tree-data 设置树节点数据(return一个promise对象),必填 Function - 见demo
set-search-data 设置搜索时树节点数据(return一个promise对象),必填 Function - 见demo
current-node-key 默认选中的节点的key String - -
node-limit 展示节点的数量限制 Number - 1000
node-limit-alert 展示节点数量限制上限的提示 String - 当前查看数据量较大,流畅度会有所下降,建议使用搜索。
search-limit 搜索节点的数量限制 Number - 500
search-limit-alert 搜索节点数量限制上限的提示 String - 搜索结果过多,仅展示前500条,建议缩小搜索范围。
search-input-text 搜索框中placeholder的提示 String - 搜索
search-maxlength 搜索框中输入长度限制 Number - -
v-node-key 1.3.3+ 虚拟节点的标识 String - $loadmore
v-node-title 虚拟节点的title文字 String - 更多
key-highlight 是否开启搜索关键字高亮 Boolean - true
show-checkbox 是否显示勾选框 Boolean - false
check-strictly 是否父子不联动 Boolean - false
hide-node-title 不显示节点上的title Boolean - false
auto-load 是否初始化的时候自动加载树 Boolean - true
expand-on-click-node 是否在点击节点的时候展开或者收缩节点, 默认值为 false,只有点箭头图标的时候才会展开或者收缩节点。 Boolean - false
expand-on-dbclick-node 是否在双击节点的时候展开或者收缩节点, 默认值为 true。 Boolean - true
default-select-current 是否默认选中节点(不传current-node-key将默认选中根节点) Boolean - true
highlight-current 是否高亮当前选中节点 Boolean - true
linked-expand-key 联动展开的节点(会在树初始化的时候,自动展开该节点所在的所有父级节点,需要父级节点已经传给前端(混合类型或同步类型)才能生效) String - -
accordion 1.3.3+ 是否开启手风琴 Boolean - false
disabledInherit 1.3.3+ 是否继承禁用状态(继承禁用即为:父节点未加载子节点,操作父节点勾选并pullNodes后,展开加载子节点,此时子节点默认会继承父节点的禁用状态) Boolean - true
move 移动节点 Boolean - false
move-area 节点可拖拽的区域,outter 表示节点只有拖拽到树区域以外才会响应 string all/outter outter
before-drag 移动前回调(和HUI相同) Function - null
before-drop 移动释放前回调(和HUI相同) Function - null
has-original-checked 是否含有初始化勾选的节点(data中有数据的checked为true)(为了优化性能) Boolean - true
before-click 点击前的回调 Function - null
before-search 点击搜索之前回调(return false就不再执行搜索) Function - null
after-search 点击搜索之后回调 Function - null
after-loadmore 完成加载更多之后的回调 Function - null
after-load 每次加载完数据之后的回调(包括展开和点击加载更多) Function - null

# 方法

方法 说明 参数
refresh 重新渲染异步树组件 callback:渲染完第一层节点后的回调函数
setSelected 设置某个节点的选中状态 (key/data, selected, deep) 接收三个参数,1. 选中节点的 key 或者 data 2. boolean 类型,节点是否选中
getCheckedNode 获取勾选的节点(仅为已经渲染的节点) -
getAllChecked 获取勾选的所有节点(包括没有渲染的节点) -
pullNodes 抽取节点。return一个被抽取的nodes集合 (keys)接收一个参数,keys代表节点key的数组集合,如果keys传的话,代表手动抽取传入的节点。
pullAllLoadedNodes 1.3.3+ 抽取所有加载过的节点(仅分层模式下) 返回一个被抽取节点的集合
pushNodes 还原被抽取的节点 (keys)接收一个参数,keys代表节点key的数组集合
getHandleChecked 1.3.3+ 获取操作过的节点(仅分层模式下) 返回一个对象,包含新勾选节点和去勾选节点的两个数组
getAllRenderNodes 1.3.3+ 获取所有渲染过的节点 返回一个节点的list数组
getAllLoadedDataWithHierar 1.3.3+ 获取已经加载过的节点(仅分层模式下) 返回一个节点的list数组

# Events

事件 说明 回调参数
init-select 节点初始化选择事件 共两个参数,依次为:当前节点的数据,当前节点的 Node 对象。
node-click 节点点击事件 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。
current-change 当前选中节点变化时触发的事件 共两个参数,依次为:当前节点的数据,当前节点的 Node 对象
check-change 节点选中状态发生变化时的回调 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点本身是否被选中、节点的子树中是否有被选中的节点
node-expand 节点展开事件 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。
node-collapse 节点关闭事件 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。
node-drag 节点移动前事件 共四个参数,依次为:事件event对象,传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。
node-drop 节点移动释放事件 共六个参数,依次为:事件event对象,传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、目标节点targetNode、位置position、节点组件本身。
node-drag-move 节点移动中事件 共四个参数,依次为:事件event对象,传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、节点组件本身。
node-mouseenter 鼠标移入节点事件 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、mouseenter 事件对象。
node-mouseleave 鼠标移出节点事件 共三个参数,依次为:传递给 data 属性的数组中该节点所对应的对象、节点对应的 Node、mouseleave 事件对象。

# 1.3.3修改内容说明

# 主要内容

  1. 是否勾选与加载模式解耦。showCheckbox设置节点是否存在勾选;type设置加载模式。现在的加载模式有async异步、sync同步、mixed混合、hierarchical分层4种。
  2. 支持自定义根节点的父节点。之前是null'0''-1'3种值,现在支持可使用rootParentKey属性设置任意值。
  3. 支持自定义虚拟节点的标识。虚拟节点······以前标识是$loadmore,现在可使用vNodeKey属性自定义。
  4. 更好的支持树props映射关系的自定义。以前chkDisabled等字段是代码里写死的,现在可以用map属性自定义。
  5. 抛出新的方法:getAllRenderNodes获取所有渲染过的节点,getAllLoadedDataWithHierar分层模式下获取所有加载过的节点

# 迁移文档

# 说明

重构后的异步树兼容之前的所有属性、方法和事件,如果你的项目中不想采用新的分层方案,只需要设置type属性即可(单选的值为async,多选的值为sync)。
2.0中哪怕什么都不改,性能也能提升一倍左右。

<!-- 老方案 -->
<sync-tree
  show-checkbox
  :map="map"
  :set-tree-data="setHeirarTreeData"
  :set-search-data="setSearchData"
></sync-tree>

<!-- 新方案 -->
<sync-tree
  show-checkbox
  :map="map"
  type="sync"
  :set-tree-data="setHeirarTreeData"
  :set-search-data="setSearchData"
></sync-tree>

# 以下步骤针对的是采用分层模式的设计方案

# 前端部分
  1. 安装最新异步树控件
$ npm i @hui-pro/sync-tree@latest
  1. 设置属性type="hierarchical"accordion=true
<sync-tree
  ref="syncTree"
  show-checkbox
  :map="map"
  type="hierarchical"
  accordion
  :set-tree-data="setHeirarTreeData"
  :set-search-data="setSearchData"
></sync-tree>
  1. 点击保存时,调用getHandleChecked获取数据。
    注意,这是一个json对象,其中包括adddel两个值,分别代表本次操作勾选的节点和去勾选的节点。请根据业务需要自行处理。

  2. 处理保存的数据。 现在传给后台的不再是一个逗号,分隔的字符串,而是一个list数组,你需要通过data.map()方法将数据提取出来,示例代码如下。

const data = this.$refs.syncTree.getHandleChecked();
const { add, del } = data;

const addData = add.map(item => ({
  id: item.id,
  nodeType: item.nodeType
}));
console.log(addData);
// [
//   { id: '1', nodeType: 'singleNode' },
//   { id: '2', nodeType: 'subTree' }
// ]

this.save(addData);
# 后台对接

后台存储的数据不再是全量的勾选数据,而是一个增量勾选的数据集合,数据中不包括没有从后台加载出的节点,后续需要自己计算。