1. uniapp EChars图表
(1)Apache ECharts 一个基于 JavaScript 的开源可视化图表库
https://echarts.apache.org/examples/zh/index.html
(1)官网图例
(2)个人实现图例
1.1. 下载echart
1.1.1. 下载
(1)方法一:从 npm 安装
使用 npm 安装 ECharts 到你的 uni-app 项目中。在项目根目录下打开终端,执行以下命令:
npm install echarts --save
(2)方法二:选择需要的模块,在线定制下载
下载 - Apache ECharts
即echarts.min.js 下载
1.1.2. 应用市场插件
在插件市场下载插件,使用hbuilderx导入即可。
https://ext.dcloud.net.cn/plugin?id=4899
1.1.3. 引用
// An highlighted block
import echarts from '@/components/echarts/echarts.vue';
下面的是 echarts.vue的代码 您可以在components 创建一个echarts的文件夹里面放echarts.vue
代码里script.src = ‘./static/echarts.min.js’ (更改路径不行的话,还是建议使用此路径
1.2. 示例代码
1.2.1. echars-helper.js
import echarsData from "../data/echarsData.json";
var ecahrsHelper = {
UNITS: {
'年': 31557600000,
'月': 2629800000,
'天': 86400000,
'小时': 3600000,
'分钟': 60000,
'秒': 1000
},
colorConstant: {
colorArr: [
'#FF3333', 'rgb(21,169,85)', '#0e9fff', '#FF8833',
'#11f6ad', '#9b7516', 'rgb(0,255,255)', '#FFD700',
'#d7b482', '#b01496', '#00ff00', '#A020F0',
'#fbcc00', 'rgb(103,161,181)', '#0acf59',
'#11f6ad', 'rgb(0,255,255)', '#0acf59']
},
getBarLine2Option: function (optionObj) {
var legendArr = []
optionObj.yObj.forEach((item, index) => {
legendArr.push(item.name)
})
var option = {
title: {
text: optionObj.title,
textStyle: {
fontSize: 12,
color: '#666666'
},
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {
// // itemHeight: 8,
// // itemWidth: 8,
// // type: 'scroll',
orient: 'horizontal', // vertical
x: 'right', //可设定图例在左、右、居中
// // y:'bottom', //可设定图例在上、下、居中
// // padding:[0,50,0,0], //可设定图例[距上方距离,距右方距离,距下方距离,距左方距离]
// // data: analyseArr,
// //circle:圆形 rect:矩形 roundRect:圆角矩形 triangle:角形
// // diamond:菱形 pin:水滴 arrow:箭头
// icon: 'roundRect',
},
grid: {
left: '2%',
right: '2%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: {
type: 'value',
boundaryGap: [0, 0.01],
// name:"123",//坐标轴名称。
nameLocation: 'end',//坐标轴名称显示位置。
axisLabel: {//坐标轴刻度标签的相关设置。
// interval:0,
// rotate:"45"
formatter: (value) => {//数字
if (value >= 10000) {
value = (value / 10000) + 'w';
}
if (value >= 1000) {
value = (value / 1000) + 'k';
}
return value;
}
}
},
series: optionObj.yObj
};
return option || '';
},
/**
* 初始化折线、饼状图配置
*/
getBarLineOption: function (optionObj) {
var legendArr = []
optionObj.yObj.forEach((item, index) => {
legendArr.push(item.name)
})
var option = {
title: {
text: optionObj.title,
textStyle: {
fontSize: 15,
color: '#000',
},
},
tooltip: {
trigger: 'axis',
shadowBlur: 0,
textStyle: {
textShadowBlur: 0
},
renderMode: 'richText',
axisPointer: {
type: 'shadow'
}
},
legend: {
data: legendArr,
// itemHeight: 8,
// itemWidth: 8,
// type: 'scroll',
orient: 'horizontal', // vertical
x: 'right',//可设定图例在左、右、居中
// y:'bottom',//可设定图例在上、下、居中
// padding:[0,50,0,0],//可设定图例[距上方距离,距右方距离,距下方距离,距左方距离]
// data: analyseArr,
//circle:圆形 rect:矩形 roundRect:圆角矩形 triangle:角形
// diamond:菱形 pin:水滴 arrow:箭头
// icon: 'roundRect',
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: true,
data: optionObj.xArr
},
yAxis: {
type: 'value',
boundaryGap: [0, 0.01],
name: "单位(件)",//坐标轴名称。
nameLocation: 'end',//坐标轴名称显示位置。
axisLabel: {//坐标轴刻度标签的相关设置。
interval: 0,
rotate: "0",//坐标轴刻度标签角度
formatter: (value) => {//数字
if (value >= 10000) {
value = (value / 10000) + 'w';
}
if (value >= 1000) {
value = (value / 1000) + 'k';
}
return value;
}
}
},
series: optionObj.yObj
}
return option || '';
},
getPieOption: function (optionObj) {
var totalNum = 0
optionObj.pieArr.forEach((item, index) => {
totalNum += Number(item.value);
})
var option = {
title: {标题
subtext: "",
text: optionObj.title + `\n` + '总数' + `\n` + totalNum + '人次',
top: 'center',
left: 'center',
textStyle: {
fontSize: 11,
}
},
legend: {
itemHeight: 8,
itemWidth: 8,
// type: 'scroll',
orient: 'horizontal', // vertical
x: 'center', //可设定图例在左、右、居中
y: 'bottom', //可设定图例在上、下、居中
// padding:[0,50,0,0],//可设定图例[距上方距离,距右方距离,距下方距离,距左方距离]
data: optionObj.pieArr,
//circle:圆形 rect:矩形 roundRect:圆角矩形 triangle:角形
// diamond:菱形 pin:水滴 arrow:箭头
icon: 'rect',
},
tooltip: {//弹出框
//trigger:触发类型,'item'数据项图形触发,主要在散点图,
// 饼图等无类目轴的图表中使用。'axis'坐标轴触发,主要在柱状图,
// 折线图等会使用类目轴的图表中使用。
trigger: 'item',
//triggerOn:提示框触发的条件,'mousemove'鼠标移动时触发。
// 'click'鼠标点击时触发。'mousemove|click'同时鼠标移动和点击时触发。
// 'none'不在 'mousemove' 或 'click' 时触发
//triggerOn:"mousemove",
//是否显示提示框浮层
//showContent:true,
//是否永远显示提示框内容
//alwaysShowContent:false,
//浮层显示的延迟,单位为 ms
//showDelay:0,
//浮层隐藏的延迟,单位为 ms
//hideDelay:100,
//鼠标是否可进入提示框浮层中
//enterable:false,
//是否将 tooltip 框限制在图表的区域内
confine: true,
//提示框浮层的移动动画过渡时间,单位是 s,设置为 0 的时候会紧跟着鼠标移动
//transitionDuration:0.4,
//提示框浮层的位置,默认不设置时位置会跟随鼠标的位置,[10, 10],回掉函数,
// inside鼠标所在图形的内部中心位置,top、left、bottom、right
// 鼠标所在图形上侧,左侧,下侧,右侧,
//position:['50%', '50%'],
//提示框浮层内容格式器,支持字符串模板和回调函数两种形式,
// 模板变量有 {a}, {b},{c},{d},{e},分别表示系列名,数据名,数据值等
//formatter:"{b0}: {c0}<br />{b1}: {c1}",
// formatter: '{a} <br/>{b}: {c} ({d}%)'
formatter: '{b} {c} 人({d}%)',
//标题背景色,
//backgroundColor:"white",
//边框颜色
//borderColor:"#ccc",
//边框线宽
//borderWidth:0,
//图例内边距,单位px 5 [5, 10] [5,10,5,10]
padding: 4,
//textStyle:文本样式
textStyle: {
fontSize: 10,
}
},
series: [
{
name: '统计分析',
type: 'pie',
clickable: true, //是否开启点击
minAngle: 2,//最小的扇区角度(0 ~ 360),用于防止某个值过小导致扇区太小影响交互
avoidLabelOverlap: true,//是否启用防止标签重叠策略
hoverAnimation: true,//是否开启 hover 在扇区上的放大动画效果。
silent: false,//图形是否不响应和触发鼠标事件
radius: ['30%', '50%'],
center: ['50%', '50%'],
labelLine: {
normal: {
length: 30, //第一条线
length2: 8, //第二条线
// lineStyle: {
// width: 1, // 线条的宽度
// color: "#000", //线的颜色设置, 如没有设置颜色则线条的颜色跟随饼状图的颜色
// }
}
},
label: {
// formatter: '{b|{b}}\n \n {per|{d}%} ',
//formatter: '{b|{b}}\n \n {per|{d}%} ',
formatter: '{b|{b}}',
borderWidth: 20,
borderRadius: 4,
padding: [20, 40],
normal: {
formatter(params) {
let text = params.name
if (text.length <= 6) {
return text = text + '\n' + params.percent + '%';
} else if (text.length > 6 && text.length <= 12) {
return text = `${text.slice(0, 6)}\n${text.slice(6)}`
+ params.percent + '%'
} else if (text.length > 12 && text.length <= 18) {
return text = `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12)}`
+ params.percent + '%'
} else if (text.length > 24 && text.length <= 30) {
return text = `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12, 18)}\n${text.slice(24)}`
+ params.percent + '%'
} else if (text.length > 30) {
return text = `${text.slice(0, 6)}\n${text.slice(6, 12)}\n${text.slice(12, 18)}\n${text.slice(24, 30)}\n${text.slice(30)}`
+ params.percent + '%'
}
},
textStyle: {
fontSize: 8
},
//柱状图颜色
// color: function (params) {
// // 颜色列表返回颜色
// return colorConstant.colorArr[(params.dataIndex
// % colorConstant.colorArr.length)];
// },
},
rich: {
a: {
color: '#6E7079',
lineHeight: 22,
align: 'center'
},
b: {
color: '#4C5058',
fontSize: 12,
fontWeight: 'bold',
lineHeight: 18,
align: "bottom",
font: "Xingkai SC",
},
c: {
fontSize: 12,
lineHeight: 30,
color: '#63BF6A',
align: "center"
},
d: {
fontSize: 10,
lineHeight: 12,
color: '#4C5058',
align: "top"
}
}
},
data: optionObj.pieArr,
itemStyle: {
normal: {
//柱状图颜色
color: function (params) {
// 颜色列表返回颜色
var colorArr = ecahrsHelper.colorConstant.colorArr
return colorArr[(params.dataIndex % colorArr.length)];
},
}
}
}
]
};
return option || '';
},
};
export {
ecahrsHelper
}
1.2.2. pageEchars.vue
<template>
<view class="base-echars-page">
<!--饼状图-->
<view class="base-echars-layout">
<view class="base-echars-title-layout">
<image class="base-echars-title-icon"
src="../../../static/icon/icon-loc.png"></image>
<view class="base-echars-title-title">饼状图</view>
</view>
<view class="base-echars-body">
<l-echart ref="pieChart" @finished="initPieEchars"></l-echart>
</view>
</view>
<!--柱状、柱状图-->
<view class="base-echars-layout">
<view class="base-echars-title-layout">
<image class="base-echars-title-icon"
src="../../../static/icon/icon-loc.png"></image>
<view class="base-echars-title-title">柱状、柱状图</view>
</view>
<view class="base-echars-body">
<l-echart ref="barLinechart" @finished="initBarLineEchars"></l-echart>
</view>
</view>
<!--双柱状、柱状图-->
<view class="base-echars-layout">
<view class="base-echars-title-layout">
<image class="base-echars-title-icon"
src="../../../static/icon/icon-loc.png"></image>
<view class="base-echars-title-title">双柱状、柱状图</view>
</view>
<view class="base-echars-body">
<l-echart ref="barLine2chart" @finished="initBarLine2Echars"></l-echart>
</view>
</view>
</view>
</template>
<script>
import pageUtil from '../../../utils/pageUtil.js';
import {ecahrsHelper} from '../../../helper/ecahrsHelper';
import echarsData from '../../../data/echarsData.json'
// #ifdef VUE3
// #ifdef MP
// 由于vue3 使用vite 不支持umd格式的包,小程序依然可以使用,但需要使用require
const echarts = require('../../../static/echarts.min');
// #endif
// #ifndef MP
// 由于 vue3 使用vite 不支持umd格式的包,故引入npm的包
import * as echarts from 'echarts/dist/echarts.esm';
// #endif
// #endif
export default {
data() {
return {
showTip: false,
}
},
onReady() {
pageUtil.setTitleBar('基础信息')
},
methods: {
/**
* 初始化饼状图
*/
initPieEchars() {
this.$refs.pieChart.init(echarts, chart => {
var optionObj = {}
optionObj.title = '数据统计'
optionObj.pieArr = echarsData.rows
var option = ecahrsHelper.getPieOption(optionObj)
chart.setOption(option);
// 监听tooltip显示事件
chart.on('showTip', (params) => {
this.showTip = true
console.log('showTip::')
});
// 监听tooltip隐藏事件
chart.on('hideTip', (params) => {
setTimeout(() => {
this.showTip = false
}, 300)
});
setTimeout(() => {
}, 1000)
});
},
/**
* 初始化柱状、折线图
*/
initBarLineEchars() {
this.$refs.barLinechart.init(echarts, chart => {
var optionObj = {}
optionObj.title = '数据统计表'
optionObj.xArr = []
var yArr = []
echarsData.rows.forEach((item, index) => {
optionObj.xArr.push(item.name)
yArr.push(item.value)
})
optionObj.yObj = [
{
name: '邮件营销',
type: 'line',//bar:柱状图 line:折线图
stack: '总量',
data: []
}
]
optionObj.yObj[0].data = yArr
var option = ecahrsHelper.getBarLineOption(optionObj)
chart.setOption(option);
// 监听tooltip显示事件
chart.on('showTip', (params) => {
this.showTip = true
console.log('showTip::')
});
// 监听tooltip隐藏事件
chart.on('hideTip', (params) => {
setTimeout(() => {
this.showTip = false
}, 300)
});
setTimeout(() => {
}, 1000)
});
},
/**
* 初始化双柱状、折线图
*/
initBarLine2Echars() {
this.$refs.barLine2chart.init(echarts, chart => {
var optionObj = {}
optionObj.title = '数据统计表'
optionObj.xArr = []
var yArr = []
var y2Arr = []
echarsData.rows.forEach((item, index) => {
optionObj.xArr.push(item.name)
yArr.push(item.value)
y2Arr.push(item.value2)
})
optionObj.yObj =
[
{
name: '邮件营销',
type: 'bar',//bar:柱状图 line:折线图
// stack: '总量',
data: [],
color: '#f00',
},
{
name: '邮件营销3',
type: 'bar',//bar:柱状图 line:折线图
// stack: '总量',
data: [],
color: '#0f0',
}
]
optionObj.yObj[0].data = yArr
optionObj.yObj[1].data = y2Arr
var option = ecahrsHelper.getBarLine2Option(optionObj)
chart.setOption(option);
// 监听tooltip显示事件
chart.on('showTip', (params) => {
this.showTip = true
console.log('showTip::')
});
// 监听tooltip隐藏事件
chart.on('hideTip', (params) => {
setTimeout(() => {
this.showTip = false
}, 300)
});
setTimeout(() => {
}, 1000)
});
},
}
}
</script>
<style>
</style>
2. uniapp EChars图表步骤
在 uni-app 中使用 ECharts 数据可视化库,通常需要完成以下步骤:
2.1. 安装 ECharts
使用 npm 安装 ECharts 到你的 uni-app 项目中。在项目根目录下打开终端,执行以下命令:
npm install echarts --save
2.2. 引入 ECharts
对于 Vue 单文件组件(.vue 文件)
在需要使用 ECharts 的 Vue 组件中,通过 import 语句引入 ECharts。同时,如果你需要使用地图功能,还需要额外引入相应的文件并注册。
<template>
<view>
<canvas ref="chartCanvas"></canvas>
</view>
</template>
<script>
import * as echarts from 'echarts';
import 'echarts/map/js/china.js'; // 引入中国地图(按需引入其他地图)
export default {
data() {
return {
chartInstance: null,
};
},
mounted() {
this.initChart();
},
methods: {
async initChart() {
// 等待 canvas 元素渲染完成(对于 H5 环境可能需要)
await this.$nextTick();
// 获取 canvas 元素
const chartDom = this.$refs.chartCanvas;
// 初始化 ECharts 实例
this.chartInstance = echarts.init(chartDom);
// 加载地图数据(如果需要)
echarts.registerMap('China', china); // 注册中国地图
// 设置图表配置项
const option = {
// ...具体的图表配置项
};
// 载入图表
this.chartInstance.setOption(option);
},
},
beforeDestroy() {
// 销毁图表实例以避免内存泄漏
if (this.chartInstance) {
this.chartInstance.dispose();
this.chartInstance = null;
}
},
};
</script>
对于使用 uni-app 插件市场的 ECharts 插件
如果你选择使用 uni-app 插件市场提供的 ECharts 插件(如 uni-ec-canvas),则需要按照插件文档的指引进行安装和使用。
通常情况下,你需要在 pages.json 中配置插件,然后在模板中使用特定的组件标签(如 ),并设置其属性来传递图表配置和数据。
2.3. 创建图表容器
在 Vue 组件的模板部分,创建一个 元素作为 ECharts 图表的容器,并为其指定一个 ref,以便在 JavaScript 中通过 this.$refs 访问。
<template>
<view>
<canvas ref="chartCanvas"></canvas>
</view>
</template>
2.4. 初始化图表
在 Vue 组件的 mounted 生命周期钩子中,初始化 ECharts 实例。
• 首先等待 DOM 更新完毕(使用 this.$nextTick())
• 然后获取 canvas 元素,使用 echarts.init() 方法初始化图表实例。
• 接着设置图表的配置项(option)
• 最后调用 setOption() 方法加载图表。
export default {
data() {
return {
chartInstance: null,
};
},
mounted() {
this.initChart();
},
methods: {
async initChart() {
await this.$nextTick();
const chartDom = this.$refs.chartCanvas;
this.chartInstance = echarts.init(chartDom);
const option = {
// ...具体的图表配置项
};
this.chartInstance.setOption(option);
},
},
// ...其他生命周期钩子,如销毁时清理图表资源
};
2.5. 配置图表
根据你的需求,编写 ECharts 的配置项(option)。
这通常包括:
• 图表类型、
• 数据源、
• 颜色、
• 图例、
• 坐标轴、
• 系列等设置。
ECharts 文档提供了详细的配置项说明和示例。
const option = {
title: {
text: '示例图表',
},
tooltip: {},
legend: {
data: ['数据系列'],
},
xAxis: {
data: ['类别A', '类别B', '类别C'],
},
yAxis: {},
series: [
{
name: '数据系列',
type: 'bar',
data: [100, 200, 300],
},
],
};
2.6. 更新图表数据
当需要动态更新图表数据时,可以直接修改 option 对象中的数据部分,然后调用 setOption() 方法重新加载图表。
为了优化性能,可以使用 setOption() 的第二个参数 notMerge 设置为 false,以合并新旧配置而不是完全替换。
// 更新数据
const newData = [400, 500, 600];
this.option.series[0].data = newData;
// 重新加载图表
this.chartInstance.setOption(this.option, { notMerge: true });
2.7. 注意事项
跨平台兼容性:确保你的 ECharts 版本与 uni-app 的版本兼容,并且了解不同平台(如 H5、小程序、App) 可能存在的差异和限制。某些功能可能需要特定版本的 ECharts 或 uni-app 支持。
• 地图数据:如果你使用地图图表,需要单独引入对应的地图数据文件,并使用 echarts.registerMap() 方法注册地图。地图数据可以从 ECharts 官方下载或在线定制。
• 性能优化:对于大数据量或复杂图表,注意优化数据处理和渲染性能,可以利用 ECharts 的数据分流、懒加载等功能。
遵循以上步骤,你应该能够在 uni-app 中成功集成并使用 ECharts 图表。
具体实现时,请参考 ECharts 官方文档以获取最新的配置选项和最佳实践。
3. uni-app 如何使用 renderjs 创建echart图表
在 uni-app 中使用 renderjs 模式创建 ECharts 图表,主要是利用 uni-app 提供的 RenderJS 能力,将 ECharts 渲染到指定的容器内。
RenderJS 是 uni-app 为解决跨端渲染复杂图形和自定义组件而引入的一种机制。
以下是一个基本步骤指南:
3.1. 安装 ECharts
确保已通过 npm 安装 ECharts:
npm install echarts --save
3.2. 创建 ECharts 配置文件
在项目中创建一个 .js 文件(如 chartConfig.js),编写所需的 ECharts 配置对象:
// chartConfig.js
export default {
title: {
text: '示例图表'
},
tooltip: {},
legend: {
data: ['数据系列']
},
xAxis: {
data: ['类别A', '类别B', '类别C']
},
yAxis: {},
series: [
{
name: '数据系列',
type: 'bar',
data: [100, 200, 300]
}
]
};
3.3. 创建 renderjs 页面
在 uni-app 项目中创建一个使用 RenderJS 的页面(如 chartPage.vue)。在 中添加一个 renderjs 标签作为 ECharts 的渲染容器:
<!-- chartPage.vue -->
<template>
<view>
<renderjs :canvas-id="'chartCanvas'"></renderjs>
</view>
</template>
3.4. 编写 renderjs 函数
在
<script>
import * as echarts from 'echarts';
import chartConfig from './chartConfig.js';
export default {
onReady() {
this.renderChart();
},
methods: {
async renderChart() {
const canvasId = 'chartCanvas';
const chartInstance = echarts.init({
canvas: this.$refs[canvasId].canvas,
renderer: 'canvas'
});
chartInstance.setOption(chartConfig);
// 如果需要监听窗口大小改变以自适应图表,可以添加以下代码
window.addEventListener('resize', () => {
chartInstance.resize();
});
}
}
};
</script>
3.5. (可选)注册自定义主题
如果需要使用自定义主题,可以按照 ECharts 官方文档的指引创建主题 JSON 文件,然后在 renderjs 函数中注册:
// 引入主题文件
import customTheme from './customTheme.json';
echarts.registerTheme('myCustomTheme', customTheme);
// 使用自定义主题初始化图表
const chartInstance = echarts.init({
canvas: this.$refs[canvasId].canvas,
renderer: 'canvas',
theme: 'myCustomTheme'
});
3.6. ((可选)更新图表数据
当需要动态更新图表数据时,可以修改配置对象中的数据部分,然后调用 setOption() 方法:
// 更新数据
chartConfig.series[0].data = [400, 500, 600];
// 重新加载图表
chartInstance.setOption(chartConfig, { notMerge: true });
3.7. 注意事项
跨平台兼容性:确保 ECharts 版本与 uni-app 的版本兼容,并了解不同平台(如 H5、小程序、App)可能存在的差异和限制。
• 性能优化:对于大数据量或复杂图表,注意优化数据处理和渲染性能,可以利用 ECharts 的数据分流、懒加载等功能。
<template>
<view class="content">
<!-- #ifdef APP-PLUS || H5 -->
<view @click="echarts.onClick" :prop="option" :change:prop="echarts.updateEcharts" id="echarts" class="echarts"></view>
<button @click="changeOption">更新数据</button>
<!-- #endif -->
<!-- #ifndef APP-PLUS || H5 -->
<view>非 APP、H5 环境不支持</view>
<!-- #endif -->
</view>
</template>
<script>
export default {
data() {
return {
option: {
title: {
text: 'ECharts 入门示例'
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ["衬衫", "羊毛衫", "雪纺衫", "裤子", "高跟鞋", "袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
}
}
},
onLoad() {
},
methods: {
changeOption() {
const data = this.option.series[0].data
// 随机更新示例数据
data.forEach((item, index) => {
data.splice(index, 1, Math.random() * 40)
})
},
onViewClick(options) {
console.log(options)
}
}
}
</script>
<script module="echarts" lang="renderjs">
let myChart
export default {
mounted() {
if (typeof window.echarts === 'function') {
this.initEcharts()
} else {
// 动态引入较大类库避免影响页面展示
const script = document.createElement('script')
// view 层的页面运行在 www 根目录,其相对路径相对于 www 计算
script.src = 'static/echarts.js'
script.onload = this.initEcharts.bind(this)
document.head.appendChild(script)
}
},
methods: {
initEcharts() {
myChart = echarts.init(document.getElementById('echarts'))
// 观测更新的数据在 view 层可以直接访问到
myChart.setOption(this.option)
},
updateEcharts(newValue, oldValue, ownerInstance, instance) {
// 监听 service 层数据变更
myChart.setOption(newValue)
},
onClick(event, ownerInstance) {
// 调用 service 层的方法
ownerInstance.callMethod('onViewClick', {
test: 'test'
})
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.echarts {
margin-top: 100px;
width: 100%;
height: 300px;
}
</style>
4. 什么是 RenderJS in uni-app?
RenderJS 是 uni-app 提供的一种技术手段,允许开发者在特定环境下(通常指 App 端的 Vue 页面)直接在视图层(而非逻辑层)执行 JavaScript 代码。
这样做的主要目的是 为了提升复杂视图渲染和交互的性能,尤其是在处理大量图形绘制、动画效果、地图渲染等场景时,通过减少逻辑层与视图层之间的通信损耗,提供更高效的视图更新和用户交互体验。
4.1. RenderJS 主要具有以下特点:
1. 运行环境:RenderJS 代码仅支持在 uni-app 的 App-Vue 环境 和 H5 环境 中运行。这意味着它不适用于小程序等其他平台,也不适用于原生的 iOS 或 Android 开发。
2. 性能优势:通过在视图层直接执行 JavaScript,RenderJS 可以避免频繁的数据绑定和视图更新,显著降低逻辑层与视图层之间的通讯损耗,特别适合处理需要密集计算或实时更新的视图内容,如地图渲染、图表绘制、游戏图形等。
3. 交互能力:RenderJS 提供了更强大的视图交互能力,可以直接响应触屏事件、手势识别等,实现流畅的用户交互体验。
4. 库支持:尽管 uni-app 提供了自身的地图、图表等组件,但有时开发者可能需要使用第三方库(如 Leaflet、ECharts、Three.js 等)以满足更复杂的需求。RenderJS 允许在视图层直接引入并使用这些库,从而实现更丰富的功能。
4.2. 使用 RenderJS 的基本步骤如下:
4.2.1. 准备页面结构
在 uni-app 的 Vue 页面中,需要创建一个用于承载 RenderJS 代码的容器。通常,这会是一个特殊的 标签,带有唯一的 canvas-id 属性,以便在 JavaScript 中引用:
### 4.2.2. 编写 RenderJS 代码 编写需要在视图层执行的 JavaScript 代码。这可以包括 DOM 操作、样式设置、事件监听、图形绘制等。代码通常保存在 Vue 组件的 methods 或 computed 中,然后在适当的生命周期钩子(如 mounted 或 onReady)中执行:// 页面脚本 (继续在 renderjsPage.vue)
4.2.3. 引入外部库
如果需要在 RenderJS 中使用第三方库,如 Leaflet、ECharts 等,需要确保库的源码可以在视图层访问,并在 RenderJS 代码中正确初始化:
• 安装库:使用 npm 安装所需的库。
• 引入库:将库的源码(通常是压缩后的 .js 文件)作为字符串嵌入到 renderJsCode 中。这可能需要使用 fs.readFileSync 或 Webpack 的 raw-loader 等工具。
• 初始化库:在 renderJsCode 中编写库的初始化代码,确保库在 RenderJS 环境中能够正常工作。
4.2.4. 数据通信
由于 RenderJS 运行在视图层,与 Vue 逻辑层之间需要进行数据交换:
• 逻辑层向 RenderJS 传递数据:将数据作为变量直接写入 renderJsCode 字符串中,或者通过 uni.postMessage 从逻辑层发送数据到视图层。
• RenderJS 向逻辑层发送数据:在 RenderJS 代码中使用 uni.postMessage 发送数据到逻辑层,逻辑层通过监听 uni.onMessage 事件接收数据。
注意事项
• 性能优化:合理组织 RenderJS 代码,避免频繁的数据交换,确保高效执行。
• 兼容性检查:确保所使用的库和 RenderJS 代码在目标平台上(App 端的 Vue 页面)能够正常工作。
• 异常处理:在 RenderJS 代码中适当使用 try…catch 语句捕获并处理可能发生的错误
在实际开发过程中,请参考 uni-app 的官方文档以获取最新的 API 说明和最佳实践。