本文详细解析了在 React Native 中基于 WebView 封装响应式 Echarts 组件的实现方案。通过对比第三方库的局限性,提出自定义 WebChart 组件的设计思路,涵盖响应式数据刷新、事件通信机制及性能优化策略,并总结了 iOS 透明渲染、Android 资源加载等常见坑点及解决方案。
引言
前言
这是一种在 React Native 环境中封装的响应式 Echarts 组件,具体的使用方法和示例代码可以查看 react-native-echarts-demo 项目。
背景与现状
近年来,移动端对数据可视化的需求日益增长,传统的图表库如 MPAndroidChart 已难以满足产品经理不断变化的复杂需求。相比之下,前端领域的数据可视化生态更为成熟,利用 WebView 在移动端集成功能强大的前端图表库 Echarts,成为解决这一问题的有效途径。
在 React Native 开发中,由于底层使用 JavaScript 语言,与 Echarts 的集成相对顺畅。然而,为了提升开发效率,仍有必要对常用组件进行适当的封装。
现有方案局限性
Echarts 官方曾推荐过一个第三方封装库 react-native-echarts(对应的 npm 包名为 native-echarts),该库目前拥有 400 多个 Star 和每周 100 多次下载,显示出一定的用户基础。但经过深入调研,我们发现该库存在以下不足之处:
- 该库已超过半年未进行更新,且内置的 Echarts 版本仍停留在 3.0 版本。此外,Android 端打包时需要手动添加 assets 资源的问题也长期未得到解决。
- 该库的接口灵活性较低,例如仅支持通过 width 和 height 属性设置图表大小;不支持使用 Echarts 的扩展包;也无法实现事件注册和 WebView 之间的通信等功能。
由于使用 WebView 封装 Echarts 涉及本地 HTML 文件,这超出了纯 JavaScript 的功能范畴,且缺乏原生代码支持,因此将其打包为 npm package 并非最佳选择。将其作为项目内部组件自行配置,反而更加便捷和灵活。
WebChart 组件设计
基于上述原因,我们决定不使用第三方 Echarts 封装库,而是自行开发一个通用组件 WebChart。为了提高开发便利性,该组件具备以下特点:
- 组件采用响应式设计,只需在 option 中配置好数据源,当数据发生变化时,图表会自动刷新,这更符合 React 的开发风格。
- 我们的实现方案是在组件每次更新时,判断传入的 option 参数是否发生变化。如果检测到变化,则通过 webView.postMessage 以 JSON 格式传入新的 option,通知 Echarts 重新调用 setOption。
- 虽然 Echarts 内部会对 option 进行对比,但提前判断可以减少因组件更新导致的与 WebView 的频繁通信,这在父组件包含大量异步请求的场景下效果尤为明显。在 WebView 内部,更新操作直接采用 Echarts 自身的 setOption 方法,无需重新加载整个 WebView。
- 利用 WebView 的 postMessage 和 onMessage 接口,可以实现图表与其他 React Native 组件之间的事件通信。
- 通过组件的 exScript 参数,可以为 WebView 添加任意脚本,使用方式更加灵活。
- 由于是自行开发的组件,Echarts 的版本、扩展包、SVG/Canvas 渲染模式以及数据增量加载等配置均可由开发者自行设定。
集成与配置
Demo 与使用方法
具体使用与示例请参考 react-native-echarts-demo。如需直接集成,可按照以下步骤进行移植:
首先,将根目录下的 WebChart 组件文件夹复制到项目中的合适位置。其次,将 /android/app/src/main/assets/web 文件夹复制到项目的相同位置,如果项目中没有 assets 文件夹,需要手动创建。完成以上两步后,即可在项目中使用 WebChart 组件。
若需进一步定制,Echarts 代码位于上述两个文件夹中的 index.html 文件的 <script /> 标签内。目前使用的是 4.0 完整版,未包含扩展包,开发者可前往官网下载所需版本和扩展包进行替换。此外,SVG/Canvas 渲染模式及数据增量加载等配置可在 WebChart/index.js 中直接修改。在移动端,出于性能考虑,通常推荐使用 SVG 渲染模式。
WebChart 的具体使用可参考 App.js 文件。样式的设置与普通 React Native 组件相同,既可以使用 flex 布局,也可以设置为固定值。此外,还有三个额外参数需要注意:
- option(object):这是传递给 setOption 的参数对象。当该对象发生变化时,WebChart 内部会自动调用 setOption,实现响应式刷新。需特别注意,JSON 解析过程未处理函数,因此应避免使用函数式的 formatter 和类形式的 LinearGradient,建议像 demo 中那样使用模板字符串和普通对象。
- exScript(string):这是在 WebView 加载时执行的任意代码,通常用于事件注册,推荐使用模板字面量格式。
- onMessage(function):这是 WebView 内部触发 postMessage 后的回调函数。需在 exScript 中预先设置 postMessage,用于实现图表与其他 React Native 组件之间的通信。
当然,这些参数是根据我们的业务需求设计的,开发者完全可以自由重新设定。
通信机制实现
Echarts 与 React Native 组件的通信
在 React Native 的 WebView 组件中,提供了 onMessage 和 postMessage 接口来实现 HTML 与组件之间的双向通信,具体使用方法可参考相关文档。
利用 webView.postMessage,WebChart 实现了通知 Echarts 执行 setOption 的功能;而在 exScript 中,可以通过 window.postMessage 实现 Echarts 事件向 React Native 组件的通信。
通常我们会约定通信数据的格式为一个对象,例如:
{
type: 'someType',
payload: {
value: 111,
},
}
由于 onMessage 和 postMessage 仅支持字符串传递,在 exScript 中需要进行 JSON 序列化,类似如下代码:
exScript={`
chart.on('click', (params) => {
if(params.componentType === 'series') {
window.postMessage(JSON.stringify({
type: 'select',
payload: {
index: params.dataIndex,
},
}));
}
});
`}
以上介绍了我们封装的响应式 WebChart 组件及其使用方法,完整代码请参见 react-native-echarts-demo。
常见问题与规避
在使用过程中,还有以下几个问题尚未完全解决,目前只能采取规避措施,欢迎了解情况的开发者指正:
- 在 iOS 系统中,Echarts 似乎无法渲染透明效果,使用 rgba 设置的颜色无法正常显示。
- React Native 的 WebView 组件中,style.height 属性似乎无效,因此不得不在外层包裹一个 View 来解决高度问题。
- 按照当前的资源加载方式,index.html 在 Android 平台上会有两份副本。因为平台判断是在运行时进行的,即使分别设置 index.android.js 和 index.ios.js,打包时两者都会被包含进去。而 Android 中又必须手动添加 assets 资源。
- index.html 中必须内联引入 Echarts 的代码,外部引用单独的 js 文件似乎无效。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。