You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Vue 3渲染vis.js自定义item模板

Vue 3 实现vis.js自定义item及group模板方案

核心实现思路

vis.js的模板配置项支持返回原生DOM元素,因此我们可以利用Vue3的runtime渲染能力,将Vue组件编译为真实DOM后传入vis.js即可,无需适配vis官方的React示例逻辑。

前置依赖安装

npm install vis-timeline
# 如使用其他vis模块按需安装即可

步骤1:封装Vue组件转为DOM的通用工具函数

import { createVNode, render } from 'vue'

/**
 * 将Vue组件转为真实DOM节点,供vis.js模板使用
 * @param {Component} component Vue组件
 * @param {Object} props 传给组件的参数(item/group的原始数据等)
 * @returns {HTMLElement} 渲染完成的DOM节点
 */
export function renderVueComponentToDom(component, props) {
  // 创建虚拟节点
  const vnode = createVNode(component, props)
  // 创建挂载容器
  const container = document.createElement('div')
  // 渲染虚拟节点到容器
  render(vnode, container)
  // 返回渲染后的真实DOM
  return container.firstElementChild
}

步骤2:编写自定义模板组件

自定义项模板示例 CustomItem.vue

<template>
  <div class="custom-item">
    <p>*{{ item.content }}*</p>
    <span class="time">{{ item.start.toLocaleTimeString() }}</span>
  </div>
</template>

<script setup>
const props = defineProps({
  // 接收vis.js传入的item原始数据
  item: {
    type: Object,
    required: true
  },
  // 可自定义传其他参数,比如编辑回调等
  onEdit: {
    type: Function,
    default: () => {}
  }
})
</script>

自定义分组模板示例 CustomGroup.vue

<template>
  <div class="custom-group">
    <img :src="group.avatar" alt="头像" class="group-avatar" />
    <span>{{ group.content }}</span>
    <button @click="addItem(group.id)">新增项</button>
  </div>
</template>

<script setup>
const props = defineProps({
  group: {
    type: Object,
    required: true
  },
  addItem: {
    type: Function,
    required: true
  }
})
</script>

步骤3:初始化timeline时配置模板

<template>
  <div ref="timelineRef" class="timeline-container"></div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { Timeline } from 'vis-timeline'
import 'vis-timeline/styles/vis-timeline-graph2d.min.css'
import { renderVueComponentToDom } from './utils'
import CustomItem from './CustomItem.vue'
import CustomGroup from './CustomGroup.vue'

const timelineRef = ref(null)
let timelineInstance = null

// 模拟数据
const items = [
  { id: 1, content: '项1', start: new Date(), group: 1 },
  { id: 2, content: '项2', start: new Date(Date.now() + 3600000), group: 2 }
]
const groups = [
  { id: 1, content: '分组1', avatar: 'xxx.png' },
  { id: 2, content: '分组2', avatar: 'yyy.png' }
]

const addItem = (groupId) => {
  // 新增项逻辑
  console.log('给分组新增项', groupId)
}

onMounted(() => {
  const options = {
    // 其他配置按需加
    template: {
      // 自定义item模板
      item: (item) => {
        return renderVueComponentToDom(CustomItem, {
          item,
          onEdit: () => console.log('编辑项', item.id)
        })
      },
      // 自定义group模板,解决groupTemplate不生效问题
      group: (group) => {
        return renderVueComponentToDom(CustomGroup, {
          group,
          addItem
        })
      }
    }
  }
  // 初始化timeline,必须传入groups配置,group模板才会生效
  timelineInstance = new Timeline(timelineRef.value, items, groups, options)
})

// 销毁时卸载组件避免内存泄漏
onBeforeUnmount(() => {
  if (timelineInstance) {
    timelineInstance.destroy()
    timelineInstance = null
  }
})
</script>

groupTemplate不生效常见排查点

  • 必须在初始化Timeline时传入第三个参数groups,未传分组数据时group模板不会触发
  • 模板函数必须返回DOM节点,不能返回字符串/Vue虚拟节点
  • 如果自定义组件存在多个根节点,需要在外层套一个单独的div容器,避免渲染时取到undefined
  • 确保timeline挂载的容器已经渲染到DOM树中再初始化实例

内容的提问来源于stack exchange,提问作者Fanna1119

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 07:15:06