Skip to content

如何自定义部分节点内容

除了完全自定义整个节点内容外还支持自定义部分节点内容。

添加附加的节点前置和后置内容

前置内容指和文本同一行的区域中的前置内容,不包括节点图片部分。如果存在编号、任务勾选框内容,这里添加的前置内容会在这两者之后。

后置内容指和文本同一行的区域中的后置内容,不包括节点图片部分。

添加这两个内容主要是使用createNodePrefixContentcreateNodePostfixContent实例化选项:

js
new MindMap({
  createNodePrefixContent: node => {
    const el = document.createElement('div')
    el.style.width = '50px'
    el.style.height = '50px'
    el.style.background = 'red'
    return {
      el, // 要添加的内容,DOM节点
      width: 50, // 内容的宽高
      height: 50
    }
  },
  createNodePostfixContent: node => {
    const domparser = new DOMParser()
    const doc = domparser.parseFromString(
      '<b style="background-color: rgb(214, 239, 214);">白日依山尽</b>',
      'text/html'
    )
    const el = doc.querySelector('b')
    return {
      el,
      width: 50,
      height: 50
    }
  }
})

添加额外的内容

v0.13.1+版本新增了一个addCustomContentToNode实例化选项,进一步增强了添加自定义内容的能力,通过这个选项创建的自定义内容需要自己来定位在节点内的位置,如下示例用于给节点添加一个角标,显示子节点的数量:

js
new MindMap({
  addCustomContentToNode: {
    // 返回要添加的DOM元素信息
    // 接收的node参数为节点实例
    create: node => {
      const childrenLength = node.nodeData.children.length
      if (childrenLength <= 0) return null
      const el = document.createElement('div')
      el.style.cssText = `
        width: 20px;
        height: 20px;
        background: red;
        border-radius: 50%;
        color: #fff;
        text-align: center;
        line-height: 20px;
      `
      el.innerText = childrenLength
      return {
        el, // DOM节点
        width: 20, // 宽高
        height: 20
      }
    },
    // 处理生成的@svgdotjs/svg.js库的ForeignObject节点实例,可以设置其在节点内的位置,定位的方法需要自行查看@svgdotjs/svg.js库的文档
    // content:create函数返回的数据
    // element:ForeignObject节点实例
    // node:当前所属节点实例
    handle: ({ content, element, node }) => {
      element.x(node.width - content.width / 2).y(-content.height / 2)
    }
  }
})

上面这个示例初始渲染你发现很正常,正确的渲染出了当前节点子节点的数量,但是当你给节点动态再添加一个子节点后发现自定义内容中的数量没有更新,理想情况下应该是希望子节点数量改变了,自定义内容中的数量也跟着更新了,那么这时为什么呢。

原因很简单,simple-mind-map是数据驱动的,对于某个节点,它只关心它自身的数据,也就是数据中的data,虽然它的子节点改变了,但只影响的是数据中的children数据,data并没有发生改变,所以库内部判断该节点数据没有发生改变便不会重新渲染它的内容,所以你的自定义内容也就不会重新渲染。

所以解决的关键的是想办法触发自身数据的改变:

js
mindMap.on('data_change_detail', list => {
  list.forEach(item => {
    if (item.action === 'update') {
      if (item.oldData.children.length !== item.data.children.length) {
        mindMap.renderer
          .findNodeByUid(item.data.data.uid)
          .setData({ _count: item.data.children.length })
      }
    }
  })
})

在前面的基础上我们监听一下data_change_detail事件,可以获取到数据更新明细,我们找出其中的update更新类型,然后就可以根据变更数据的切换判断出某个节点的子节点数量是否改变了,是的话我们就获取到该节点实例,然后给其添加一个自定义数据,这样库内部就会发现它的数据改变了,就会触发其重新渲染,这样自定义的内容也就会随之更新了。

当然这只是一个示例,具体情况可能还需要具体的做法,但核心就是需要想办法触发数据改变,以触发节点重新渲染。

MIT License.