携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情
背景
在ztree不满足现有的业务背景下,得知有虚拟节点概念,且主流elementPlus、ant等均封装了虚拟树、虚拟列表、虚拟表格等,并做相关的调研,虚拟树可以解决目前使用中的节点性能问题,但是目前还存在一些问题,要等一段时间在进行推广
问题
项目使用的技术栈vue2+elementUI
,想使用elementPlus的虚拟树组件
思路
-
参考elementPlus tree-V2的源码使用vue2进行改写实现
不太会vue3、typescript 时间成本比较大
-
是否可以elementUI、elementPlus共存在同一项目使用
经过尝试该方式不行
-
直接使用vue3+vite+elementPlus(tree-V2)封装成组件包,在vue2中安装使用
试验后可走通
🤦♀️ 个人能力、时间有限,没考虑过从0-1
实现
把vue3+elementPlus(tree-V2)组件一起打包,通过创建挂载实例的方式,把vue3组件挂载在vue2项目的dom节点上。从而实现在vue2中使用vue3的组件
- 新建vue3+vite+elementPlus项目,通过把vue3+elementPlus(el-tree-v2)一起打包成压缩文件VirtualTree.umd.js,对外抛出一个函数,接收2个参数el、prop,返回值是组件树应用实例。el:挂载的dom节点,prop:根组件的 attributes属性 和事件监听器。
// packages/index.js 核心文件
import 'element-plus/theme-chalk/el-tree.css';
import { ElTreeV2 } from "element-plus";
import { createApp} from "vue";
export default function(el, props) {
// 参数说明 插入节点的el、props(所有的配置项、属性等,)、方法、事件
return createApp(ElTreeV2,props).mount(el)
}
// vite.config.ts 打包配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
vue: 'vue/dist/vue.esm-bundler.js',
"@": path.resolve(__dirname, "src")
},
},
css: {
preprocessorOptions: {
scss: {
additionalData: '@import "./src/assets/style/index.scss";'
}
}
},
build: {
lib: {
entry: path.resolve(__dirname, 'packages/index.js'),
name: 'CetVirtualTree',
fileName: (format) => `CetVirtualTree.${format}.js`
},
}
})
- 在vue2项目中,引入VirtualTree.umd.js,创建dom节点,调用createTreeV2并传入el、prop参数。使用变量保存返回实例,且会触发onCreate事件,外部可获取组件树实例。 elementPlus组件事件通过事件转发($emit)方式实现,方法通过实例去调用。并使用 npm包的方式去封装发布@virtualtree
<template>
<div class="virtual-tree"></div>
</template>
<script>
// vue3+elementPlus+vite 打包生成物
import createTreeV2 from "./lib/VirtualTree.umd.js";
const treeInstance = Symbol('virtualTree');
const EVENTS = [
"onNodeClick",
"onNodeContextmenu",
"onCheckChange",
"onCheck",
"onCurrentChange",
"onNodeExpand",
"onNodeCollapse"
];
export default {
name: "VirtualTree",
props: {
attribute: {
type: Object,
default() {
return {};
}
}
},
data() {
return {};
},
watch: {},
mounted() {
this.init();
},
methods: {
init() {
//使用$emit实现事件转发
let event = this.forwardingEvents();
let props = Object.assign(this.attribute, event);
// 创建并挂载,返回实例
this[treeInstance] = createTreeV2(this.$el, props);
// 外部通过事件获取实例调用方法等
this.$emit("onCreate", this[treeInstance]);
},
// elementplus事件转发,方法直接通过 this[CetTreeV2]获取
forwardingEvents() {
const vm = this;
let obj = {
// onCheck:this.onCheck
};
EVENTS.forEach(eventName => {
vm[eventName] = (...args) => {
vm.$emit(eventName, ...args);
};
obj[eventName] = vm[eventName];
});
return obj;
}
}
};
</script>
3.打包发布
- 全局安装引用@virtualtree 包,通过VirtualTree 名称来使用。(图三)
//main.js
import VirtualTree from "@virtualtree";
Vue.use(VirtualTree);
<template>
<div>
<el-input v-model="filterText" placeholder="Filter keyword" />
<VirtualTree
v-bind="VirtualTree_obj"
v-on="VirtualTree_obj.event"
></VirtualTree>
</div>
</template>
export default{
data() {
VirtualTree_obj: {
attribute: {
data: [],
props: {
value: "id",
label: "name",
children: "children"
},
},
event: {
onCreate: this.onCreate,
onCheck: this.onCheck,
}
}
}