需求驱动开发。
因项目需求,需要在app中搞大量的表格。当然相如什么charts,pncharts等原生插件也可以用,之前也用过,但是因为他们可以说没有什么文档,当时踩过不少坑,纯靠猜属性是什么意思。所以,决定选择echarts来实现。
但是如何使用echarts才能让其达到跟原生一样的体验,不会出现白屏,不会加载缓慢?
so,继续往下看。
首先我们肯定知道,html css js什么的放到本地,加载的速度肯定比下载的快,毕竟一个echarts.conmmon.min.js文件都有0.5M大小。
还有webview的选型,选择的wkwebview,虽然wkwebview肯定是有不少坑,但是,毕竟快啊。
最后一点,对于数据的获取,如果是通用的图表,会让服务器来拼数据。如果不是通用的图表,我选择在本地model中拼option,直接拿来用。
置于传值什么的,直接走js 交互,还是很简单的。
第一步
首先自定义了一个BaseWKWebView
-(WKWebView *)webView{
if (!_webView) {
// self.userInteractionEnabled= NO;
self.userInteractionEnabled = true;
WKWebViewConfiguration * configuration = [[WKWebViewConfiguration alloc]init];
configuration.preferences.javaScriptEnabled = YES;//打开js交互
_webConfiguration = configuration;
// _jsHandler = [[XLJSHandler alloc]initWithViewController:self configuration:configuration];
_webView = [[WKWebView alloc]initWithFrame:self.bounds configuration:configuration];
[_webView setOpaque:NO];
_webView.scrollView.backgroundColor = [UIColor clearColor];
_webView.scrollView.scrollEnabled = false;
_webView.navigationDelegate = self;
_webView.backgroundColor = [UIColor clearColor];
// _webView.allowsBackForwardNavigationGestures =YES;//打开网页间的 滑动返回
_webView.scrollView.decelerationRate = UIScrollViewDecelerationRateNormal;
// //监控进度
// [_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
[self addSubview:_webView];
}
return _webView;
}
然后就开始遇到坑了,看下面这两个方法,就是坑所在的地方,刚开始一直用第一个方法,然后总是取不到css和js的路径,最后发现是没搞根目录,也就是第二个方法。
-(void)setLocalUrl:(NSString *)localUrl{
NSURL * url = [[NSBundle mainBundle] URLForResource:localUrl withExtension:@"html"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
-(void)setLocalUrl:(NSString *)localUrl subdirectory:(NSString *)subdirectory {
NSURL * url = [[NSBundle mainBundle] URLForResource:localUrl withExtension:@"html" subdirectory:subdirectory];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[self.webView loadRequest:request];
}
第二步
在这里先看下服务器返回的格式 数据格式
然后根据数据格式抽了一个model出来。
@property (nonatomic, retain) NSMutableArray * target_source; // 按钮数据源
@property (nonatomic, retain) NSMutableArray * timeAxis; // 横坐标
@property (nonatomic, retain) NSMutableArray * source; // 数据
在这里我们从baseWKwebView里抽个代理方法出来。然后在app中的wkwebview加载完毕的时候把数据通过js交互注入进去。
#pragma mark -- BaseWkWebViewDelegate
- (void)baseWkWebView:(BaseWKWebView *)baseWkWebView didFinishNavigation:(WKNavigation *)navigation {
[self loadBaseWKWebview:self.chartModel];
}
// 监测数据是否取到,未取到数据隔0.4秒获取一次
- (void)loadBaseWKWebview:(QuotesChartModel *)data {
if (!data) {
[self performSelector:@selector(loadBaseWKWebview:) withObject:self.chartModel afterDelay:0.4];
return;
}
NSString * jsonStr = [[data mj_keyValues] mj_JSONString];
[self.chartView jsFuncationName:@"setData" params:@[jsonStr]];
}
下面的是webview调用js的方法。
/**
* webview调用JS方法
*/
-(void)jsFuncationName:(NSString *)funcation params:(NSArray *)params {
NSString * params_str = [params componentsJoinedByString:@","];
NSString * js = [NSString stringWithFormat:@"%@(%@)",funcation,params_str];
[self.webView evaluateJavaScript:js completionHandler:nil];
}
第三步
该来看看放在本地的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">
<link type="text/css" rel="stylesheet" href="./CSS/common.css">//引入css
<title>Document</title>
</head>
<body>
<script type="text/javascript" src="./modules/echarts.common.min.js"></script>//引入js文件
<div id="sc_chart" style="width: 100%;height:100%"></div>
<script type="text/javascript">
var source = [];
var timeAxis = [];
// 指定图表的配置项和数据
var option = {
dataZoom:{
type:'inside'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'line',
label: {
backgroundColor: '#343A45'
}
}
},
grid:{
top:'0px',
bottom:'30px',
left:'0px',
right:'0px',
},
xAxis: {},
yAxis: [],
series: [],
animationThreshold:false
};
/**
* 设置图数据
* keys:[key1,key2,...] 下面这个是拼接数据格式option 具体格式可以去echars官网去看
*/
function setKeys(keys){
// 设置图数据
var yAxis = [];
var series = [];
keys.push({name:'默认',key:'default',color:'#FFFFFF'})
keys.forEach((d,index) => {
if (source.hasOwnProperty(d.key)) {
var obj = source[d.key];
var color = d.color ? d.color : '#fff'
var name = obj.data['yAxis']['name'];
var unit = obj.data['yAxis']['unit'];
var yAxis_obj = {
show:false,
}
var series_obj = obj.data['series']
series_obj['symbol'] = 'circle';
series_obj['lineStyle'] = {width:0.5};
series_obj['yAxisIndex'] = index;
series_obj["itemStyle"] = {
normal:{
color:d.color,
}
},
series.push(series_obj)
yAxis.push(yAxis_obj);
}
});
option.yAxis = yAxis;
option.xAxis = {
axisLabel: {color: "#fff"},
data:timeAxis,
fontSize:9,
}
option.series = series;
var echartsDom = document.getElementById('sc_chart');
echartsDom.removeAttribute("_echarts_instance_");
var myChart = echarts.init(echartsDom);
myChart.setOption(option);
window.addEventListener('resize', function () {
myChart.resize();
})
}
function setData(data){ //webview调用的js方法注入数据
// 组装数据
data.source.map(d=>{
source[d.key] = d;//把数据抽成一个数组里面是key value形式。
})
timeAxis = data.timeAxis;//直接给x轴
setKeys([]);//这个方法是默认选中
}
function setOption(opt){
option = opt;
var echartsDom = document.getElementById('sc_chart');
echartsDom.removeAttribute("_echarts_instance_");
var myChart = echarts.init(echartsDom);
myChart.setOption(option);
window.addEventListener('resize', function () {
myChart.resize();
})
}
</script>
</body>
</html>
下面是具体效果。
不管是从加载速度还是响应速度都跟原生相差无几。
当遇到需要定制化的图的时候,可以在本地拼接option,同样走交互传到html中
/**
* model转chartOption
*/
- (NSDictionary *)chartOptionByModel{
NSDictionary * option = [NSDictionary dictionary];
NSMutableArray * out_arr = [NSMutableArray array];
for (id value in self.outAxis) {
NSInteger v = 0 - [value doubleValue];
[out_arr addObject:[NSNumber numberWithInteger:v]];
};
option = @{
@"dataZoom":@{
@"type":@"inside"
},
@"tooltip":@{
@"trigger":@"axis",
@"axisPointer":@{
@"type":@"line",
}
},
@"grid":@[@{
@"left":@"0px",
@"right":@"0px",
@"bottom":@"30px",
@"top":@"0px",
}],
@"xAxis":@{@"axisLabel": @{@"color":@"#fff"},
@"data":self.timeAxis,
@"axisLine":@{@"show":[NSNumber numberWithBool:false]},
@"axisTick":@{@"show":[NSNumber numberWithBool:false]},
@"fontSize":@"9"},
@"yAxis":@[@{
@"show":[NSNumber numberWithBool:false],
@"inverse": @0,
},
@{
@"show":[NSNumber numberWithBool:false],
}],
@"series":@[@{
@"type":@"bar",
@"name": @"In",
@"stack": @"one",
@"barMaxWidth": @"60px",
@"data":self.inAxis,
@"itemStyle":@{
@"normal": @{
@"color": @"#FA5452"
},
}
},
@{
@"type":@"bar",
@"name": @"Out",
@"stack": @"one",
@"barMaxWidth": @"60px",
@"data":out_arr,
@"itemStyle":@{
@"normal": @{
@"color": @"#3CC28C"
},
}
}]
};
return option;
}
深坑更新中。。
为了实现这个效果
首先是push是把数组后面添加元素,unshift是往首位添加元素。
如果不用unshift的话就会面临,series_obj['yAxisIndex'] 对不上的情况。