目录
简介
vue3:双向绑定改为ES6的Proxy;新的API风格,代码逻辑性更强、更易维护;性能提升,渲染更快、内存更少。
vite:新型前端构建工具,基于原生ES模块,极速启动、快速热更新,更优的开发体验。
以npm install和build过程为例, 之前vue2+webpack的项目在devops的编译环节非常耗时,在2-15min之间均有,vue3+vite的项目基本在1min以内。
脚手架
事先准备
nodejs需要大于16.0版本。
建议先卸载旧有nodejs,再安装nvm,通过nvm安装分别用于vue3项目和vue2项目的nodejs高低版本。
- 创建指令:
npm create vue@latest
- 选项:TypeScript、Vue Router、ESLint 、Prettier (按需即可)
- 运行指令:
npm install npm run dev
引入axios
npm install axios --save
- 配置文件axios-config.js,统一封装请求
/request/axios-config.jsimport axios from "axios"; import router from "@/router"; import qs from "qs"; /* http request **请求拦截器 **在发送请求之前进行的一系列处理,根据项目要求自行配置 **例如:loading */ axios.interceptors.request.use( (config) => { // 请求响应时间 config.timeout = 60 * 60 * 1000; config.headers = { token: sessionStorage.getItem("accessToken"), // "Content-Type": "application/json" "Content-Type": "application/x-www-form-urlencoded", }; return config; }, (error) => { // 对请求错误做处理 console.log(error); // for debug return Promise.reject(error); } ); /* response **响应拦截器 **允许在数据返回客户端前,修改响应的数据 **返回体中数据:response.data,如果需要全部,则 return response 即可 */ axios.interceptors.response.use( (response) => response, (error) => { let message = ""; // 处理响应错误 if (error && error.response) { const errorResponse = error.response.data; if (errorResponse.msg || errorResponse.message) { message = errorResponse.msg || errorResponse.message; if (message.indexOf("无效token") > -1) { sessionStorage.removeItem("accessToken"); sessionStorage.removeItem("userinfo"); router.push({ path: "/login" }); } } } return Promise.reject(error); } ); const fetchPost = (url, params) => { return new Promise((resolve, reject) => { axios .post(url, qs.stringify(params)) .then( (res) => { resolve(res.data.data); }, (err) => { reject(err.data); } ) .catch((err) => { reject(err.data); }); }); }; const fetchPut = (url, params) => { return new Promise((resolve, reject) => { axios .put(url, qs.stringify(params)) .then((res) => { resolve(res.data.data); }) .catch((err) => { reject(err.data); }); }); }; const fetchDel = (url, params) => { return new Promise((resolve, reject) => { axios .delete(url, { params: qs.stringify(params), }) .then((res) => { resolve(res.data.data); }) .catch((err) => { reject(err.data); }); }); }; const fetchGet = (url, params) => { return new Promise((resolve, reject) => { axios .get(url, { params: qs.stringify(params), }) .then((res) => { resolve(res.data.data); }) .catch((err) => { reject(err.data); }); }); }; /** * 不带参数的get请求 * @param {*} url */ const fetchGetNoParam = (url) => { return new Promise((resolve, reject) => { axios .get(url) .then((res) => { resolve(res.data.data); }) .catch((err) => { reject(err.data); }); }); }; export default { install: (app) => { app.config.globalProperties["$get"] = fetchGet; app.config.globalProperties["$post"] = fetchPost; app.config.globalProperties["$put"] = fetchPut; app.config.globalProperties["$del"] = fetchDel; app.config.globalProperties["$axios"] = axios; }, };
- main.js引入
import Axios from "@/request/axios-config.js"; const app = createApp(App) .use(Axios);
- .vue使用
import { getCurrentInstance } from "vue"; const { proxy } = getCurrentInstance(); let data=await proxy.$post("url",{});
引入sass
npm install sass --save -dev
npm install sass-loader --save -dev
- .vue使用:
<style scoped lang="scss"></style>
引入element-plus
npm install element-plus --save
- main.js引入
import "element-plus/dist/index.css"; import ElementPlus from "element-plus"; import zhCn from "element-plus/dist/locale/zh-cn.mjs"; const app = createApp(App) .use(ElementPlus, { locale: zhCn, });
- 使用见官网
vite.config.js
"@"路径配置及代理配置
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
server: {
port: 8081,
https: false,
proxy: {
"/check": {
// 后台地址
target: "http://127.0.0.1:18892",
changeOrigin: true,
// pathRewrite: {
// "^/check": "",
// },
},
},
},
});
引入echarts5
npm install echarts --save
- .vue使用
import * as echarts from "echarts"; let myChart = null; //用const和ref()会导致tooltip提示不显示 myChart = echarts.init(document.getElementById(id)); let option = {}; myChart.setOption(option); window.addEventListener("resize", () => { myChart.resize(); });
路由配置
/router/index.js
import { createRouter, createWebHistory } from "vue-router";
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: "/login",
name: "login",
component: () => import("../views/LoginView.vue"),
},
{
path: "/",
name: "home",
component: () => import("../views/HomeView.vue"),
children: [
{
path: "/index",
name: "index",
component: () => import("../views/Index.vue"),
},
],
},
],
});
router.beforeEach((to, from) => {
if (!sessionStorage.getItem("accessToken") && to.name !== "login") {
return { path: "/login" };
}
return true;
});
export default router;
main.js引入
import router from "./router";
const app = createApp(App)
.use(router);
全局状态管理
/store/store.js
import { reactive } from "vue";
export const store = reactive({
count: 0,
func: () => {
...
},
});
.vue使用
<template> {{ store.count }}</template>
<script setup>
import { store } from './store.js'
store.func();
</script>
完整main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
import "./assets/main.css";
import "element-plus/dist/index.css";
import ElementPlus from "element-plus";
import zhCn from "element-plus/dist/locale/zh-cn.mjs";
import Axios from "@/request/axios-config.js";
const app = createApp(App)
.use(router)
.use(ElementPlus, {
locale: zhCn,
})
.use(Axios);
app.mount("#app");
组合式API之Setup
常用功能
<script lang="ts" setup>
import { reactive, ref, getCurrentInstance, computed, onMounted } from "vue";
import { useRouter, useRoute, RouterView } from "vue-router";
const router = useRouter();
const route = useRoute();
const { proxy } = getCurrentInstance();
import { store } from "@/store/store.js";
// 计算属性,获取当前路由名称
const current= computed(() => {
return route.name;
});
// 钩子函数
// 在组件完成初始渲染并创建 DOM 节点后运行
onMounted(() => {
init();
});
// 响应式变量声明
const showTable = ref(false);
let tableData = reactive([]);
// axios请求及store状态管理
const init= () => {
tableData = await proxy.$post("/getResultList", {
quarter: store.getQuarter(),
year: store.getYear(),
});
showTable.value = true
};
// 路由跳转
const goLogin= () => {
router.push({ path: "/login" });
};
- ref:可以是 string、number 或 boolean 这样的原始类型,也可以是对象类型;在js中需要通过
.value
,在template不需要;适合于原始类型和浅层级的对象。 - reactive:只能用于对象类型;不需要
.value
;适合于层级比较深的可变复杂对象。
父子组件传值
父组件
<Chart
v-if="chartShow['v4']"
id="v4"
:tip="tip['v4']"
:title="titles['v4']"
:legend="legend['v4']"
:chartData="chartData['v4']"
:isPercent="isPercent['v4']"
></Chart>
import Chart from "../components/Chart.vue";
子组件
<template>
<div class="box">
<div v-if="title" class="box_top">
<div class="title">{{ title }}</div>
</div>
<div class="box_chart" ref="chart" :id="id"></div>
</div>
</template>
<script lang="ts" setup>
import { defineProps, onMounted, watch } from "vue";
//父传子
const props = defineProps({
id: {
type: String,
required: true,
},
isPercent: {
type: Boolean,
default: () => true,
},
title: {
type: String,
required: false,
},
chartData: {
type: Array,
default: () => [],
},
});
const emits = defineEmits(["updateData", "updateThreshold"]);
//监听数组变化
watch(
() => props.chartData,
() => {
init();
}
);
onMounted(() => {
init();
});
let myChart = null;
const init = () => {
//获取传值
console.log((props.id);
};
const handelChange= () => {
//子传父
emits("updateData", [props.id,val1,val2,...]);
};