跨框架的表格组件: 一套代码多框架运行

本文介绍了如何开发一个原生JS表格组件,使其能够跨框架(Angular、Vue、React、jQuery)运行。作者面临的主要挑战是框架模板无法解析,选择在原生组件上进行改造,通过为每个框架提供壳项目来实现模板解析。文章详细描述了针对不同框架的包装组件和模板解析的实现过程,最后总结了开发经验并提供了相关链接。
摘要由CSDN通过智能技术生成

这几年来,一直在思考怎么做出一款功能强大且配置简易的原生JS表格组件。
为此做了很多功能,也对这些功能做过多轮的优化以达到配置简易的愿景。

而在开发过程中,总有个绕不过去的坎: 框架模板无法解析。

这是一个什么概念呢?

当在框架环境中渲染表格组件,这个表格内的模板只能使用原生JS,无法使用任何框架特性。
这也就意味着,当在表格模板内使用框架组件时将无法渲染。

如下所示,通过模板配置一个Vue的Button组件是无法渲染的。

columnData: [
	{
   
		key: '操作',
		template: <el-button @click="delRelation(row)">删除</el-button>
	}
]

在框架满天飞的现在,这是无法忍受的。

选择方案

当时,看着满屏的代码,发呆了许久。

期间一直在思考使用哪种方案来面向框架:

  • 原生版本停止开发,重新开发多套基于框架的表格组件。
  • 在现有组件上进行改造,支持框架特性。

重新开发基于框架的表格组件,需要同时维护多套代码。
而在原生组件上进行改造,可以实现一套代码多框架运行。

毕竟无论哪种框架,都是源于JS。

设计思路

一旦选择,那么就坚持下去吧。虽然,谁都会知道中间的路很坎坷。

思路讲起来很简单,只是做出来需要很多调研工作,需要对各个框架有一定的熟识度,甚至在找不到解决方案时需要去阅读框架源码。

构思了一段时间后,一套只有两个步骤的实践方案就这么设定了:

  • 为每个框架提供壳项目,在壳项目中实现框架解析模板的勾子。
  • 原生组件负责在渲染过程中对各类模板进行整合,并在特定的时机发送至壳项目中进行解析。

思路确定之后,就该动手开工了。

实施

三个框架虽有不同,但都提供了解析原生DOM或动态创建框架对像的方法:

  • Angular: $compile()
  • Vue: new Vue()
  • React: render()

在对框架进行支撑前,首先要对原生组件进行一些改造。

改造原生组件

声明一个容器,用于存储待解析的模板。

// 存储容器,基本格式: {'table-key': []}
const compileMap = {
   };

// 获取指定表格的存储容器
const getCompileList = gridManagerName => {
   
    if (!compileMap[gridManagerName]) {
   
        compileMap[gridManagerName] = [];
    }
    return compileMap[gridManagerName];
};

收集原生表格中使用到的模板:

  • td模板
  • th模板
  • 为空模板
  • 通栏模板

为这些模板提供解析函数, 通过该函数生成不同框架的待解析模板,并存入compileMap等待解析。

// td模板解析函数
const compileTd = (settings, el, template, row, index, key) => {
   
    const {
    gridManagerName, compileAngularjs, compileVue, compileReact } = settings;
    const compileList = getCompileList(gridManagerName);
    // React and not template
    if (!template) {
   
        return row[key];
    }

    // React element or React function
    // react 返回空字符串,将单元格内容交由react控制
    if (compileReact) {
   
        compileList.push({
   el, template, row, index, key, type: 'template', fnArg: [row[key], row, index, key]});
        return '';
    }

    // 解析框架: Angular 1.x || Vue
    if (compileVue || compileAngularjs) {
   
        compileList.push({
   el, row, index, key});
    }

    // not React
    // 非react时,返回函数执行结果
    if (!compileReact) {
   
        return template(row[key], row, index, key);
    }
};

// ... 其它模板的解析函数,大致上与td类似

在原生组件拥有模板解析函数后,还需要为原生组件提供与各框架版本的通迅函数。

// 通迅函数: 与各框架模板解析勾子进行通迅,在特定时间调用
function sendCompile(settings, isRunElement) {
   
    const {
    gridManagerName, compileAngularjs, compileVue, compileReact } = settings;
    const compileList = getCompileList(gridManagerName);
    if (compileList.length === 0) {
   
        return;
    }
    if (isRunElement) {
   
        compileList.forEach((item, index) => {
   
            item.el = document.querySelector(`[${
     getKey(gridManagerName)}="${
     index}"]`);
        });
    }
    // 解析框架: Vue
    if (compileVue) {
   
        await compileVue(compileList);
    }

    // 解析框架: Angular 1.x
    if (compileAngularjs) {
   
        await compileAngularjs(compileList);
    }

    // 解析框架: React
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值