Vue - vue 前端开发技术指南
以 vite + vue3 + ElementPlus + pinia 开发技术栈所遇到的技术难题及解决方案汇总
如何在 vite+vue3 项目中支持 jsx 技术
- 安装插件
pnpm add -D @vitejs/plugin-vue-jsx
- 配置 vite.config.js
import vueJsx from '@vitejs/plugin-vue-jsx';
export default defineConfig({
plugins: [
vueJsx(), // 在vue() 之前
vue(),
]
})
- 在使用 jsx 语法的组件中设置 lang
<script lang='jsx' setup>
function formatPlateNumber(row) {
const colorStyle = PLATE_COLOR[row.plateColor];
return (
<div style={colorStyle}>{row.plateNumber}</div>
);
}
</script>
如何在 vue3 项目中支持 echarts
- 安装 echarts
pnpm add echarts
- 在项目中使用 echarts
// 设置图形挂载点ref
<template>
<div class="board-item-body" ref="chartRef" v-loading="isLoading" element-loading-background="rgba(0,0,0,0)">
</div>
</template>
// 导入echarts
import * as echarts from 'echarts';
const isLoading = ref(false); // 设置图像加载过程指示
const statsData = ref(null); // 统计数据
// 初始化ref
const chartRef = ref();
// 设置图像实例
let chart = null;
// 绘制图表
function renderChart() {
// 构建图表数据
const legendData = map(statsData.value, 'overRangeName');
const seriesData = map(statsData.value, (item) => ({ name: item.overRangeName, value: item.rangeRatio }));
// 图表参数配置
const option = {
legend: {
orient: 'vertical',
x: '15%',
y: 'center',
textStyle: {
color: '#E5EFFF',
},
data: legendData,
},
tooltip: {
trigger: 'item',
formatter: (item) => `${item.marker}${item.name} <span style="font-weight: bold;">${item.value}%</span>`,
},
series: [
{
type: 'pie',
avoidLabelOverlap: true,
label: { show: false },
data: seriesData,
radius: ['30%', '70%'],
center: ['70%', '50%'],
}]
};
// 图表容器是否已加载完毕
if (chartRef) {
// 首次绘制图表需要进行初始化
if (!chart) chart = echarts.init(chartRef.value);
// 设置图表参数更新图表
chart.setOption(option);
}
}
// 获取统计数据
function getData(callback) {
isLoading.value = true;
overRangeStats({}).then((res) => {
statsData.value = res.data;
callback && callback();
}).finally(() => {
isLoading.value = false;
});
}
// 设置图表在页面调整大小时也能够适配调整大小
window.addEventListener('resize', function () {
chart.resize();
});
// 页面加载后获取图表数据后绘制图表
onMounted(() => {
getData(renderChart);
});
// 页面卸载后销毁图形实例
onUnmounted(() => {
chart.dispose();
});
vue3 中引入 dayjs 处理日期时间
- 安装 dayjs
pnpm add dayjs
- 使用 dayjs
import dayjs from 'dayjs';
// 引入duration 插件
import duration from 'dayjs/plugin/duration'
dayjs.extend(duration);
dayjs.duration(duration, 'seconds').format('HH:mm:ss');
dayjs(time).format('YYYY-MM-DD HH:mm');
vue3 项目中引入 lodash-es 进行数据处理
- 安装 lodash-es
pnpm add lodash-es
- 使用 lodash-es
import {map, isEmpty, reduce} from 'lodash-es';
vue3 页面中监听键盘事件的方法
- @keydown.enter 进行事件绑定到回车键
<el-form-item prop="username">
<el-input v-model="form.username" :placeholder="t('form.username')" prefix-icon="user" @keydown.enter="doLogin"></el-input>
</el-form-item>
在vue3中如何引入样式
- 在组件的style区域引入
<style>
@import "./styles/index.less"
</style>
- 在main.js 中引入
import "@/styles/index.less";
在vue3 style中如何引入js变量
- 使用v-bind(variable) 的形式
<script setup>
const paddingStyle = props.isFront ? '0!important' : '15px 20px';
const marginStyle = props.isFront ? '0!important' : '20px';
</script>
<style scoped lang="scss">
:deep(.cm-table_top__toolbar){
padding: v-bind(paddingStyle);
margin-top: v-bind(marginStyle);
}
</style>
vue3 中 v-loading, 遮罩层变透明的方法加 (element-loading-background="rgba(0,0,0,0)")属性即可。
<template>
<div class="board-item-body" v-loading="isLoading" element-loading-background="rgba(0,0,0,0)"> </div>
</template>
<script>
const isLoading = ref(false);
</script>
vue3 中引入element-Plus 图标集
- 将图标注册为全局组件Icon,并通过属性icon进行区分, 其优势是可以做到动态图标,通过传入不同的icon属性值可以渲染不同的图标
- 在main.js 中注册为全局组件, 通过createVNode, h 函数创建vue的虚拟节点
// 导入 element-plus 的图标集
import * as ElIcons from '@element-plus/icons-vue';
// 注册Icon组件
const Icon = (props) => {
const { icon } = props;
return createVNode(ElIcons[icon]);
}
app.component('Icon', Icon);
- 在vue组件中使用
<el-icon :size="25">
<Icon :icon="weatherName"/>
</el-icon>
- 将图标直接注册为全局组件, 其优势是简单明了,但无法在动态场景下使用。
- 在main.js 进行全局注册
import * as ElIcons from '@element-plus/icons-vue';
// 注册ElIcons为app的子组件
for (const name in ElIcons){
app.component(name, ElIcons[name]);
}
- 在vue组件中使用
<el-icon :size="25">
<WeatherName />
</el-icon>
vue3 + Element-plus 项目中 el-select 数据无法正常回显,设定了value值,但不能正常回显label问题
问题原因: 在于设定的value值类型与options选项value值类型不匹配造成的。
解决方案:可以转换options里的value值类型或者设定的value值类型,值类型两者匹配后即可正常回显。
<template>
<el-form-item prop="status" label="状态">
<el-select clearable v-model="filters.status" placeholder="全部" style="width: 180px">
<el-option v-for="item in statusOptions" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</template>
<script setup>
import { SWITCH_STATUS } from '@/const';
const statusOptions = computed(() =>
// 将options 中的value值转为数字型
map(SWITCH_STATUS, (value, key) => ({ label: value, value: Number(key) }))
);
</script>
vue-router, 通过路由传送参数,以及接收参数
- 通过query
// 传送参数
const router = useRouter();
router.push({path: '', query: {key: value}});
// 接收参数
const route = useRoute();
const value = route.query?.key;
vue 页面中的图片或图标在本地正常显示,部署上线后无法正常显示
原因分析: 对于js代码中的路径,vite无法进行提前分析和编译,所以导致打包后找不到相关图片,对于style中的背景图片静态路径则没有影响。
解决方案:
- 将无法正常显示的图标移到项目更目录的public 目录下。
- 在图片路径引用的地方,将路径全部改为'/' 根目录下的图片即可。
js 代码中图片引用
<script setup>
// 处理icon图标
function formatIcon(row) {
return <img src={`/img/z${row.vehicleType}.png`} />;
}
</script>
图片实际所在位置: /public/img/z1.png
css 中的图片引用
<style lang="scss">
.board-item-header {
background: url('@/assets/panel-title-bg.png') center top no-repeat;
display: flex;
justify-content: space-between;
}
</style>
图片实际所在位置: /src/assets/panel-title-bg.png
html 中的图片引用
<template>
<img src="@/assets/login-bg.png" </div>
</template>
图片实际所在位置: /src/assets/login-bg.png
vite build 执行后sass报警告: Sass‘s behavior for declarations that appear after nested rules will be changing
问题原因: sass 为了迎合css最新的行为,将之前嵌套定义的规则会统一定义在开始,现在则保持原来的位置
.el-icon.el-dialog__close:hover {
svg {
color: #fff;
}
background: #2a77b7; // 报错位置
}
解决方案一: 手动将原有的嵌套规则,放在开始位置
.el-icon.el-dialog__close:hover {
background: #2a77b7; // 放到开头
svg {
color: #fff;
}
}
解决方案二: 使用 & {} 将已有的规则包含起来
.el-icon.el-dialog__close:hover {
svg {
color: #fff;
}
& { // 使用 & {}
background: #2a77b7;
}
}
vue组件样式重置 :deep (child) {}
<style scoped lang="scss">
.charts-body-data {
width: 100%;
:deep(.el-progress) {
padding-top: 5px;
}
}
</style>
vue 前端路由模式为history模式,部署到线上刷新页面404问题
问题分析:出现此问题的原因是刷新页面后,向后端发送url请求,nginx无法找到路由对应的资源所以返回了404,
因此需要对后端nginx服务器进行适当的配置, 使其始终返回网站首页,这样网站首页加载后会根据前端的路由加载对应的页面。
#index index.html index.htm;
try_files $uri $uri/ /index.html;
[element-plus] el-dialog 组件以及由它封装的组件必须放置在template 的最顶层,否则可能出现异常情况,包括打不开,关闭不了的情况。
[element-plus] el-select 作为行内组件使用时,必须设置style="width:200px" 属性,否则会有样式问题。
[element-plus] el-form 组件必须设置ref , 所有el-form-item 必须设置prop 属性, resetFields 方法才会生效。
[element-plus] el-progress无法正常显示的问题
- 将组件放到别的地方看能否正常显示,如果能够在别的地方正常显示,则说明放置的位置上层的样式对当前的组件产生了影响。
- 去掉父级组件的样式,重新为el-progress 添加新的父级样式。
eharts 中设置柱状图的图例,无法显示处理方法
- 在series中设置name属性
series: [
{
type: 'bar',
name: '检测量',
data: [240, 180, 140, 180, 80],
itemStyle: {
color: '#3EAAFF',
}
},
{
type: 'bar',
name: '超限',
data: [95, 70, 80, 60, 23, 20],
itemStyle: {
color: '#FFBA37',
}
}
]
- lengend 属性中data数据项与name保持一致
legend: {
orient: 'horizontal',
x: 'center',
y: 'bottom',
data: ['检测量', '超限'],
},
调整echarts 圆环图的位置
series: [{
center: ['60%', '50%'],
}]
在使用async,await发送多个网络请求时,如果请求之间没有依赖关系,则要注意使其并行发送。
async function getData1() {
const res = await getRemoteData();
return res;
}
async function getData2() {
const res = await getRemoteData();
return res;
}
// 将多个请求进行各自的封装然后进行调用,实现并行发送
onMounted(() => {
getData1();
getData2();
});
后端返回的数据id作为整数传送到前端,导致数据精度丢失,从而导致获取接口调用失败
原因分析: 由于前端的数字类型实际存储时都是8为double类型存储的,因此最大能表示的数字范围有限,导致从后端返回的大整数在前端无法正常处理,进行json解析后 导致了数据失去精度, 从而进一步影响到后续的接口调用。
解决方案:
- 后端解决方案: 在服务端将整型改为字符串类型(最佳方案)
- 前端解决方案:
- 将返回的数据在未进行解析前,通过正则表达式将要转换的数据从数字类型改为字符串类型。
- 引入json-bigint包,并替换axios等相关请求解析库的JSON.parse 方法, 在使用时通过大数整型的.tostring 转为字符串。