1.工作中遇到的问题

我们在使用react-native肯定遇到过各种奇葩的问题,比如引入Echarts时候莫名报错,但是Echarts官网明显告诉我们可以懒加载的,这是因为基本上js大部分原生的组件库都不支持React-Native,直接引用都会报"undefined is not an object (evaluating 'ua.match')" when importing an incompatible (browser) library.

2.经过调研得知react-native的WebView可以解决这个问题

有时候可以使用 WebView 弥补一些 ReactNative 内置的组件实现不了的东西,我们可以借助 HTML 来完成,毕竟 HTML 有丰富的工具可以用。例如要想在 ReactNative 里展示图表,原生自带的组件则没办法实现,其他的图表组件都是基于 react-native-svg 实现的,展示效果目前还不足人意,如果仅仅是展示,不在乎图表的各项数据和动态操作,这里也介绍几个小巧的图表插件,react-native-pathjs-charts,victory-native ( 展示效果丰富,极力推荐,名字有点随意,导致很多人不知道这个插件 )。但是如果需要echarts或者highChart这些丰富的功能,这个时候 HTML 则有一大堆图表工具可以使用。

那我们接下就教大家如何一步一步封装自己的echarts组件。

3.封装echarts

假设我有一个本地的react-native目录如下

Demo/
android/
ios/
App.js
index.js
packege.json src/
components/
chart/
view
...

我们在src/components/chart目录下新建两个文件,一个叫chart.html,一个叫chartComponent.js

编写chart.html如下:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>测试文件</h1>
</body>
</html>  

然后编写chartComponent.js

import React ,{Component} from 'react';
import {
View,
Text,
ScrollView ,
WebView,
Dimensions,
StyleSheet,
Platform
} from 'react-native'; export default class SelfEChart extends Component {
render() {
return (
<WebView
source={require('./chart.html')} //加载的html资源
/>
)
}
}

接下来引入你的SelfEchart组件展示到你的页面中,如果出现刚才的测试文件,那么你的webview就是起效果了。

我们开始改造我们的chart.html使它正式成为平时我们写echarts的样子

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style type="text/css">
html,body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#main {
height: 100%;
}
</style>
</head>
<body>
<div id="main"></div> <script>
/* echarts.min.js代码拷贝到这里 */
</script>
</body>
</html>

在使用html加载好我们的html文件以及文件内部的echarts.min.js后需要初始化echarts插件,这个时候需要用到webview的 injectedJavaScript 属性,但是该属性必须是一段js的字符串,我们先将需要执行的js字符串编写好如下:

/*在WebView加载外部html后执行的js,主要是初始化echart图表*/
function renderChart(props) {
const height = `${props.height || 400}px`;
const width = props.width ? `${props.width}px` : 'auto';
return `
document.getElementById('main').style.height = "${height}";
document.getElementById('main').style.width = "${width}";
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(${toString(props.option)});
       //这个自定义的message主要是监听webview组件传递来的数据变化的,假设图表数据变化,我们需要更新echart的option,使的
//图表的变化不间断,可以实现实时监控的效果,以至于不闪屏
window.document.addEventListener('message', function(e) {
var option = JSON.parse(e.data);
myChart.setOption(option);
});
`
}

我们注意到上述代码有个toString方法,主要是将option对象转成字符串,因为JSON.stringify()方法本身会忽略函数属性,所以toString队JSON.stringify做了判断,代码如下

function toString(obj) {
let result = JSON.stringify(obj, function(key, val) {
if (typeof val === 'function') {
return `~--demo--~${val}~--demo--~`;
}
return val;
});
do {
result = result.replace('\"~--demo--~', '').replace('~--demo--~\"', '').replace(/\\n/g, '').replace(/\\\"/g,"\"");
} while (result.indexOf('~--demo--~') >= 0);
return result;
}

所要的东西都准备好了,家下来开始在webview组件内引入在chart.html加载后需要执行的js代码了

export default class SelfEChart extends Component {
render() {
return (
<WebView
source={require('./chart.html')} //加载的html资源
injectedJavaScript = {renderChart(this.props)} //在html内执行js代码,必须是字符串
/>
);
}
}

option当然是父组件传递过来的,我们也可以指定该图标显示的高度和宽度,以及一些其他的属性,还有就是webview还有一些其他的辅助属性,可以帮组我们优化组件的功能,接下来我们看看完整的charComponent.js的代码

import React ,{Component} from 'react';
import {
View,
Text,
ScrollView ,
WebView,
Dimensions,
StyleSheet,
Platform
} from 'react-native'; /*获取设备的屏幕宽度和高度*/
const {width, height} = Dimensions.get('window'); function toString(obj) {
let result = JSON.stringify(obj, function(key, val) {
if (typeof val === 'function') {
return `~--demo--~${val}~--demo--~`;
}
return val;
});
do {
result = result.replace('\"~--demo--~', '').replace('~--demo--~\"', '').replace(/\\n/g, '').replace(/\\\"/g,"\"");
} while (result.indexOf('~--demo--~') >= 0);
return result;
} /*在WebView加载外部html后执行的js,主要是初始化echart图表*/
function renderChart(props) {
const height = `${props.height || 400}px`;
const width = props.width ? `${props.width}px` : 'auto';
return `
document.getElementById('main').style.height = "${height}";
document.getElementById('main').style.width = "${width}";
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption(${toString(props.option)});
window.document.addEventListener('message', function(e) {
var option = JSON.parse(e.data);
myChart.setOption(option);
});
`
} /**
* 通过WebView封装react-native不支持的插件,本次封装echarts
*
* 该组件需要的props
* option 必填,为ECharts配置属性option,详细配置参考官网EChartshttp://echarts.baidu.com/option.html#title
* width 不必填,为图表的宽度
* height 不必填,为图表的高度
*
*
*/
export default class SelfEChart extends Component {
constructor(props) {
super(props);
this.setNewOption = this.setNewOption.bind(this);
}
componentWillReceiveProps(nextProps) {
if(nextProps.option !== this.props.option) {
this.refs.chart.reload();
}
}
setNewOption(option) {
          //postMessage会触发刚才js中的message监听方法,使得图表刷新option配置
this.refs.chart.postMessage(JSON.stringify(option));
}
render() {
/**在安卓下加载的资源跟ios不同,需要做兼容处理,
* 就是将当下的chart.html拷贝到android/app/src/main/assets
*/
const source = (Platform.OS == 'ios') ? require('./chart.html') : { uri: 'file:///android_asset/chart.html' }
return (
<View style={{width:this.props.width || width,flex: 1, height: this.props.height || 400,}}>
<WebView
ref="chart"
scrollEnabled = {false}
style={{
height: this.props.height || 400,
backgroundColor: this.props.backgroundColor || 'transparent'
}}
source={source} //加载的html资源
scalesPageToFit={Platform.OS !== 'ios'}
injectedJavaScript = {renderChart(this.props)} //在html内执行js代码,必须是字符串
/>
</View>
);
}
}

  到此为止,我们的echar组件已经封装好了,接下来我们看看怎么使用

import React ,{Component} from 'react';
import { View, Text,ScrollView } from 'react-native';
import SelfEChart from '../../components/chart/chart' export default class ListScreen extends React.Component {
componentDidMount(){
/**
* 连续不间断刷新图标demo
*/
setInterval(()=>{
let data = [5, 20, 36, 10, 10, 20].map((v)=>{
return Math.random()*v
})
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data:['销量']
},
xAxis: {
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: data
}]
};
/**普通图表刷新通过改变state内部的option实现,缺点就是组件不断更新,导致图表组件重头开始渲染,没有连贯效果
* 在chartComponent里面封装的setNewOption方法,
* 目的是为了调用myChart.setOption(option)
* 达到不抖屏不更新state刷新图表
* */
this.refs.charts.setNewOption(option)
},2000)
}
render() {
var option = {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data:['销量']
},
xAxis: {
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
}; return (
<ScrollView>
<View style={ { flex: 1, justifyContent: 'center', alignItems: 'center'} }>
<Text>ListScreen!</Text>
<SelfEChart
ref="charts"
option={option}
/>
</View>
</ScrollView>
);
}
}

  最好附上已经全部搭建好的react-native框架地址:https://github.com/jiangzhenfei/react-native-demo

react-native中使用Echarts,自己使用WebView封装Echarts经验的更多相关文章

  1. react native中的聊天气泡以及timer封装成的发送验证码倒计时

    今天看来情书写的文章,研究了一下大佬写的文章,自己做一点总结. 其实,今天我想把我近期遇到的坑都总结一下:1.goBack的跨页面跳转,又两种方法,一可以像兔哥那样修改navigation源码,二可以 ...

  2. react native中使用echarts

    开发平台:mac pro node版本:v8.11.2 npm版本:6.4.1 react-native版本:0.57.8 native-echarts版本:^0.5.0 目标平台:android端收 ...

  3. [转] 「指尖上的魔法」 - 谈谈 React Native 中的手势

    http://gold.xitu.io/entry/55fa202960b28497519db23f React-Native是一款由Facebook开发并开源的框架,主要卖点是使用JavaScrip ...

  4. React Native 中 CSS 的使用

    首先声明,此文原作者为黎 跃春 React Native中CSS 内联样式 对象样式 使用Stylesheet.Create 样式拼接 导出样式对象 下面的代码是index.ios.js中的代码: / ...

  5. react native中的欢迎页(解决首加载白屏)

    参照网页: http://blog.csdn.net/fengyuzhengfan/article/details/52712829 首先是在原生中写一些方法,然后通过react native中js去 ...

  6. React Native中的网络请求fetch和简单封装

    React Native中的网络请求fetch使用方法最为简单,但却可以实现大多数的网络请求,需要了解更多的可以访问: https://segmentfault.com/a/1190000003810 ...

  7. [转] 在React Native中使用ART

    http://bbs.reactnative.cn/topic/306/%E5%9C%A8react-native%E4%B8%AD%E4%BD%BF%E7%94%A8art 前半个月捣腾了一下Rea ...

  8. react native中一次错误排查 Error:Error: Duplicate resources

    最近一直在使用react native中,遇到了很多的坑,同时也学习到了一些移动端的开发经验. 今天在做一个打包的测试时,遇到了一个问题,打包过程中报错“Error:Error: Duplicate ...

  9. 在React Native中,使用fetch网络请求 实现get 和 post

    //在React Native中,使用fetch实现网络请求 /* fetch 是一个封装程度更高的网络API, 使用了Promise * Promise 是异步编程的一种解决方案 * Promise ...

随机推荐

  1. 大型网站架构演化(六)——使用反向代理和CDN加速网站响应

    随着网站业务不断发展,用户规模越来越大,由于中国复杂的网络环境,不同地区的用户访问网站时,速度差别也极大.有研究表明,网站访问延迟和用户流失率正相关,网站访问越慢,用户越容易失去耐心而离开.为了提供更 ...

  2. 用svmpredict输出的结果为空

    源程序:

  3. 网卡多ip 再看arp; arp队列也会缓存skb

    [结论] 当协议失效的时候,skb会挂载arp的neigt的一个链表上,然后直接返回了,相当于数据包发下了,当arp收到数据包去修复neigh的目的地址的时候,会把之前所有的neihe中等待的skb全 ...

  4. Spring Boot中使用@Transactional注解配置事务管理

    事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功能支持.Spring 事务管理分为编程式和声明式的两种方式.编程式事务指的是通过编码方式实现事务:声明式事务基于 AOP ...

  5. 使用for循环遍历数组元素

    循环可以将代码块执行指定的次数.如果您希望一遍又一遍地运行相同的代码,并且每次的值都不同,那么使用循环是很方便的.迭代语句又叫循环语句. JavaScript 支持不同类型的循环: for - 循环代 ...

  6. Python面向对象—类的继承

    一个子类可以继承父类的所有属性,不管是父类的数据属性还是方法. class Father(object): num = 0 def __init__(self): print "I'm Pa ...

  7. CF939E:Maximize! ——题解

    http://codeforces.com/problemset/problem/939/E https://vjudge.net/problem/CodeForces-939E 给一个集合,每次两个 ...

  8. 洛谷 P1653 猴子 解题报告

    P1653 猴子 题目描述 有N只猴子,第一只尾巴挂在树上,剩下的N-1只,要么被其他的猴子抓住,要么抓住了其他的猴子,要么两者均有.当然一只猴子最多抓两只另外的猴子.现在给出这N只猴子抓与被抓的信息 ...

  9. 51nod 1196 字符串的数量(DP+数论?)

    这题好像是神题...V1 V2 V3分别涵盖了51nod 5级算法题 6级算法题 难题 讨论区的曹鹏神牛好强啊...一种做法切了V1 V2 V3,而且做法是一步一步优化的 还没去看优化的部分,未优化已 ...

  10. [PKUWC2018]随机算法

    题意:https://loj.ac/problem/2540 给定一个图(n<=20),定义一个求最大独立集的随机化算法 产生一个排列,依次加入,能加入就加入 求得到最大独立集的概率 loj25 ...