uni-app小程序分包中使用 Echarts, 并在分包里加载依赖
这篇笔记主要记录uni-app小程序, 在分包中使用Echarts,并在分包里加载Echarts依赖,减少主包的大小,提升小程序的加载速度.
- 在分包中使用Echarts
- 在分包里加载Echarts依赖
先看下效果,图表正常渲染,主包大小小于1.5M,主包存在仅被其他分包依赖的JS文件也通过✅
在分包中使用Echarts
我们要用的Echarts插件是lime-chart, 我们看下文档, 插件下载页面下面的描述
我们是Vue3小程序,先下载插件,下载好插件后,插件会安装在项目根目录下的uni_modules文件夹,下载插件截图
根据文档,我们require相对引入echarts.min文件,我们要渲染的图表数据来自接口
- 在onMounted里请求接口数据
- 接口数据返回后调用渲染图表的方法
- 渲染图表要用setTimeout,确保渲染图表时,组件的节点已经被渲染到页面上
<script setup>
import { onMounted } from 'vue'
// 根据项目目录相对引入
const echarts = require("../../uni_modules/lime-echart/static/echarts.min.js");
const getData = async () => {
const chartData = await getChartData() // 获取图表数据
setTimeout(() => {
renderChart() // 数据返回后渲染图表
}, 500)
}
onMounted(() => {
getData()
})
</script>
这样就能渲染了
刚开始我没渲染出来,对比文档,发现我没用setTimeout,用了之后就渲染出来了,看起来一切正常,但是,我们发布的时候,提示
主包超过1.5M, 主包有只被其他子包依赖的JS文件,都没通过,并且还告诉我们是uni_modules/lime-chart/static/echarts.min.js
这个文件
虽然我们是在分包里渲染Echarts,但是插件默认下载到主包的uni_modules,我们需要把Echarts依赖引入到分包里
在分包里加载Echarts依赖
我们把主包里的Echarts文件整个移入到分包里pages-me-dashboard
, 我在分包里建了一个文件夹uni_modules, 告诉自己这是一个插件,
可是却发现Echarts渲染不出来了,调试后发现chart组件不渲染了
<l-echart ref="pieChartRef"></l-echart>
于是就又手动引入lEchart组件,Echart在主包的时候,没引入lEchart组件就渲染了,发现可以正常渲染
import lEchart from "../uni_modules/lime-echart/components/l-echart/l-echart.vue";
再次发布下,主包大小通过,主包存在仅被其他分包依赖的JS文件也通过✅
完整代码
<template>
<view class="container">
<view class="stats-card">
<view class="header">
<view class="date-select">
<picker
mode="selector"
:value="selectedYearIndex"
:range="yearOptions"
@change="onYearChange">
<view class="picker">{{ yearOptions[selectedYearIndex] }} 年</view>
</picker>
<picker
mode="selector"
:value="selectedMonthIndex"
:range="monthOptions"
@change="onMonthChange">
<view class="picker">{{ monthOptions[selectedMonthIndex] }}</view>
</picker>
</view>
</view>
<view v-if="loading" class="loading">
<uni-load-more status="loading"></uni-load-more>
</view>
<view v-else class="stats-content">
<view class="stat-item">
<text class="label">总课程节数</text>
<text class="value">
{{ statistics.totalCourses }}
<text class="label">节</text>
</text>
</view>
<view class="stat-item mb-20">
<text class="label">出勤统计</text>
<text class="value">
{{ statistics.trainingDays }}
<text class="label">天</text>
</text>
</view>
<!-- Line Chart -->
<view style="width: 90vw; height: 750rpx">
<l-echart ref="lineChartRef"></l-echart>
</view>
<!-- Pie Chart -->
<view
style="
width: 85vw;
height: 550rpx;
margin-top: 20px;
overflow: hidden;
">
<l-echart ref="pieChartRef"></l-echart>
</view>
</view>
</view>
</view>
</template>
<script lang="ts" setup>
import { ref, onMounted, nextTick } from "vue";
// Import echarts
import lEchart from "../uni_modules/lime-echart/components/l-echart/l-echart.vue";
const echarts = require("../uni_modules/lime-echart/static/echarts.min");
interface Statistics {
totalCourses: number;
trainingDays: number;
courseDistribution: { name: string; value: number }[];
dailyCourses: { date: string; count: number }[];
}
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const currentMonth = currentDate.getMonth();
const yearOptions = Array.from({ length: 5 }, (_, i) => `${currentYear - i}`);
const monthOptions = Array.from({ length: 12 }, (_, i) => `${i + 1} 月`);
const selectedYearIndex = ref(0);
const selectedMonthIndex = ref(currentMonth);
const statistics = ref<Statistics>({
totalCourses: 0,
trainingDays: 0,
courseDistribution: [],
dailyCourses: [],
});
const loading = ref(false);
const onYearChange = (e: any) => {
selectedYearIndex.value = e.detail.value;
fetchStatistics();
};
const onMonthChange = (e: any) => {
selectedMonthIndex.value = e.detail.value;
fetchStatistics();
};
const fetchStatistics = async () => {
loading.value = true;
try {
console.log(
"year-month",
yearOptions[selectedYearIndex.value],
Number(selectedMonthIndex.value) + 1
);
const res = await uniCloud.callFunction({
name: "getMonthlyStatistics",
data: {
userId: uni.getStorageSync("userInfo").userId,
year: yearOptions[selectedYearIndex.value],
month: Number(selectedMonthIndex.value) + 1,
},
});
if (res.result.code === 0) {
statistics.value = res.result.data;
console.log("charts-----", res.result.data);
renderCharts();
}
} catch (error) {
console.error("获取统计数据失败", error);
} finally {
loading.value = false;
}
};
const lineChartRef = ref(null);
const pieChartRef = ref(null);
const renderCharts = async () => {
// Line Chart
setTimeout(async () => {
console.log("charts111-----", echarts, lineChartRef.value);
if (!lineChartRef.value) return;
const dailyCourses = statistics.value.dailyCourses;
const dates = dailyCourses.map((item) => item.date);
const counts = dailyCourses.map((item) => item.count);
const lineChartOption = {
title: {
text: "每日上课统计",
left: "left",
top: 10,
textStyle: {
fontSize: 18,
fontWeight: "bold",
color: "#333",
},
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "line",
},
},
xAxis: {
type: "category",
data: dates,
axisLine: {
lineStyle: {
color: "#999999",
},
},
axisLabel: {
color: "#666666",
},
axisTick: {
show: false,
},
},
yAxis: {
type: "value",
axisLine: {
lineStyle: {
color: "#999999",
},
},
axisLabel: {
color: "#666666",
},
axisTick: {
show: false,
},
},
series: [
{
name: "课程节数",
type: "line",
data: counts,
smooth: true,
},
],
};
console.log("echarts", echarts);
const lineChart = await lineChartRef.value.init(echarts);
lineChart.setOption(lineChartOption);
}, 500);
// Pie Chart
setTimeout(async () => {
if (!pieChartRef.value) return;
const courseDistribution = statistics.value.courseDistribution;
const pieChartOption = {
title: {
text: "课程分布",
left: "left",
top: 10,
textStyle: {
fontSize: 18,
fontWeight: "bold",
color: "#333",
},
},
tooltip: {
trigger: "item",
formatter: "{b}: {c} ({d}%)",
},
series: [
{
name: "课程分布",
type: "pie",
radius: ["30%", "50%"],
label: {
show: true,
position: "outside",
formatter: "{b}: {c} ({d}%)",
},
data: courseDistribution.map((item) => ({
name: item.name,
value: item.value,
})),
},
],
};
const pieChart = await pieChartRef.value.init(echarts);
pieChart.setOption(pieChartOption);
}, 600);
};
onMounted(() => {
fetchStatistics();
});
</script>
<style lang="scss" scoped>
.container {
display: flex;
justify-content: center;
align-items: flex-start;
// height: 100vh;
background-color: #f5f5f5;
padding: 20px;
box-sizing: border-box;
}
.stats-card {
width: 100%;
max-width: 650px;
background-color: #fff;
border-radius: 10px;
padding: 20px;
box-sizing: border-box;
}
.header {
display: flex;
justify-content: flex-start;
margin-bottom: 20px;
}
.date-select {
display: flex;
gap: 15px;
}
.picker {
padding: 8px 20px;
background-color: #f0f0f0;
border-radius: 8px;
font-size: 16px;
text-align: center;
}
.stats-content {
display: flex;
flex-direction: column;
// gap: 20px;
}
.stat-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 6px 0; // 减小 padding 让行距更紧凑
border-bottom: 1px solid #eee;
.label {
font-size: 14px; // 标签字体调小
color: #666;
}
.value {
font-size: 22px; // 数值字体加大
font-weight: bold; // 加粗数值
color: #333;
}
}
.chart {
height: 300px;
margin-top: 20px;
}
</style>
效果图页面渲染的数据
{
"totalCourses": 5,
"trainingDays": 3,
"dailyCourses": [
{
"date": "2025-01-01",
"count": 2
},
{
"date": "2025-01-02",
"count": 2
},
{
"date": "2025-01-03",
"count": 1
}
],
"courseDistribution": [
{
"name": "编舞基础",
"value": 2
},
{
"name": "Kpop基础",
"value": 1
},
{
"name": "Hiphop基础",
"value": 1
},
{
"name": "Jazz进阶",
"value": 1
}
]
}
作者:gongzemin
来源:juejin.cn/post/7455491124564885523
来源:juejin.cn/post/7455491124564885523