node 12.16.1 vue/cli 4.5.13 vite 2.4.4 vue 3.1.5 element-plus 1.0.2-beta.70 ...
1. 安装
Vue/cli 4.5版本以上作为 @vue/cli ,否则需要全局重新安装最新版本。
npm install -g @vue/cli
基于 vite2 创建 Vue3 项目
npm init vite-app 项目名称
Monster:Project chiang$ npm init vite-app abc
npx: 7 安装成功,用时 5.835 秒
Scaffolding project in /Users/chiang/Person/Project/abc...
Done. Now run:
cd abc
npm install (or `yarn`)
npm run dev (or `yarn dev`)
进入项目目录执行npm install 及 npm run dev 完成项目初始化启动。
目录结构
.
├── index.html
├── node_modules
├── package-lock.json
├── package.json
├── public
└── src
├── App.vue
├── assets
├── components
└── main.js
- index.html:主页。
- node_modules:项目依赖的包均在该文件夹下。
- package-lock.json:锁定安装时的包的版本号,保证所有项目成员依赖相同。
- package.json:项目名称、版本、作者、github地址、 当前项目依赖了哪些第三方模块等。
- public:放置公共资源,例如图片、全局CSS等。
- src:项目根路径,所有功能基于该文件下开展。
src概述
- App.vue:根组件。
- main.js:入口文件。
- asserts:静态资源文件夹,常放置图片、JSON文件等等静态资源。
- components:组件文件夹,vue的特点之一就是组件化,业务逻辑组件放置该文件夹下。
1.1. 注意事项
vue 和 @vue/compiler-sfc 版本需一致,若版本较低使用下方指令。
npm install vue@3.1.5 --S
npm install @vue/compiler-sfc@3.1.5 --S
2. vite
2.1. vs webpack
vite 基于 ECMAScript 标准原生模块系统 (ES Modules) 实现,最突出的优点 快 (启动快,更新快...),依赖少,但只支持 vue3.0以上的版本,生态较差。 webpack 虽然各种优点不及 vite ,但周边生态好,简单说经过多年的积累,用户群体庞大。总之不同应用场景选择不同技术,扬长避短。
2.2. 启动参数
"scripts": {
"dev": "cross-env vite --mode dev",
"prod": "cross-env vite --mode prod",
"build": "vite build",
"preview": "vite preview"
},
根据项目的运行环境使用 vite cross-env 设置不同的启动参数。
cross-env安装
npm install cross-env --S
环境变量
以 .env. 开头自定义环境名称结尾。例 .env.dev
NODE_ENV=dev
VITE_BUILD_ENV=dev
VITE_APP_URL=http://127.0.0.1:8080
vite.config.js
项目根路径下创建 vite.config.js 文件,用于配置服务端口、跨域、代理、路径、插件等...
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';
export default defineConfig({
server: {
port: '8000',
open: true,
cors: true,
// 代理规则
proxy: {
'/api': {
target: 'http://127.0.0.1:8080',
changeOrigin: true,
secure: false,
},
},
},
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'~@': path.resolve(__dirname, 'src/configurations'),
},
},
plugins: [vue()],
});
3. vuex
安装
npm install vuex --S
目录结构
src
├── assets
├── components
│ └── modules
├── configurations
│ └── store
│ └── index.js
├── App.vue
└── main.js
index.js
import Vuex from 'vuex';
/**
* Web Storage
*/
export default new Vuex.Store({
state: {
token: sessionStorage.getItem('token'),
},
mutations: {
/**
* 改变token
* @param {*} state 存储信息
* @param {*} token 登录口令
*/
change(state, token) {
state.token = token;
sessionStorage.setItem('token', token);
},
/**
* 删除token
* @param {*} state 存储信息
*/
remove(state) {
state.token = null;
sessionStorage.removeItem('token');
},
},
});
4. vue-router
安装
npm install vue-router --S
目录结构
src
├── assets
├── components
│ └── modules
├── configurations
│ ├── store
│ └── router
│ └── index.js
├── App.vue
└── main.js
index.js
import { createRouter, createWebHistory } from 'vue-router';
import store from '~@/store';
/**
* 路由文件加载
*/
const files = import.meta.globEager('/src/components/modules/**/*.router.js');
/**
* 路由配置
*/
const routes = Object.keys(files).map((item) => files[item].default);
/**
* 路由配置
* history: 1.createWebHistory(), 2.createWebHashHistory()
* routes: 路由跳转配置
*/
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: () => import('@/components/layout/container.vue'),
children: routes,
},
],
});
/**
* 路由前置守卫
*/
router.beforeEach((to, from, next) => {
let token = store.state.token;
if (token === null || token === '') {
// 当路由跳转不满足定义的条件时,实现某个操作
} else {
next();
}
});
export default router;
5. axios
安装
npm install axios --S
目录结构
src
├── assets
├── components
│ └── modules
├── configurations
│ ├── store
│ ├── router
│ └── http
│ └── index.js
├── App.vue
└── main.js
index.js
import axios from 'axios';
import store from '~@/store';
/**
* axios配置
*/
const instance = axios.create({
// 接口域名
baseURL: import.meta.env.VITE_APP_URL,
// 超时时限
timeout: 6000,
// 请求头
headers: {
'Content-Type': 'application/json;charset=UTF-8;',
},
});
/**
* 请求拦截器
*/
instance.interceptors.request.use(
(config) => {
const token = store.state.token;
token && (config.headers.token = token);
if (config.method === 'POST') {
config.data = JSON.stringify(config.data);
}
return config;
},
(error) => Promise.reject(error)
);
/**
* 响应拦截器
*/
instance.interceptors.response.use(
(response) => {
if (response.status != 200 && valid(response.data)) {
throw new Error(response);
}
return handle(response.data);
},
(error) => Promise.reject(error)
);
/**
* 响应参数格式检验
* @param {*} object response.data
* @returns true: 满足, false: 不满足
*/
const valid = (object) => {
if (!object.code || !object.message || !object.data) {
console.error('data struct is not match');
return false;
}
return true;
};
/**
* 出参业务判定处理
* @param {*} object response.data
* @returns
* 200: object.data
* 401: 移除登录信息
*/
const handle = (object) => {
if (object.code === '200') {
return object.data;
} else if (object.code === '401') {
store.commit('remove');
console.warn('token invalid');
} else {
// todo
}
};
export default instance;
6. element-plus
6.1. 安装
element-plus
npm install element-plus --save
@vitejs/plugin-vue
npm install @vitejs/plugin-vue
6.2. 配置
官方提示:强烈建议直接引入全部的样式文件。
main.js
import { createApp } from 'vue';
import ElementPlus from 'element-plus';
import App from '@/App.vue';
import 'element-plus/lib/theme-chalk/index.css';
createApp(App).use(ElementPlus).mount('#app');
6.3. 布局
目录结构
.
└── layout
├── affix.vue
├── aside.vue
├── container.vue
├── header.vue
└── menu.vue
- affix:图钉,用于控制“抽屉”展示与收起。
- aside:左侧菜单栏整体布局。
- menu:动态数据生成菜单的基础组件,可理解
aside内容之一。 - header:页头。
- container:布局整体容器。
7. echarts
安装
npm install echarts --S
#用于声明元素唯一ID
npm install vue-uuid --S
目录结构
src
├── assets
│ ├── components
│ │ ├── data
│ │ ├── layout
│ │ ├── login.vue
│ │ ├── modules
│ │ ├── plugins
│ │ │ └── echarts
│ │ │ └── echarts.vue
│ │ └── login.vue
│ └── configurations
│ ├── http
│ ├── router
│ └── store
├── App.vue
└── main.js
echarts.vue
<template>
<div :style="{height: height}" :id="id"></div>
</template>
<script>
import { defineComponent, onMounted, watch } from "vue";
import * as echarts from "echarts";
import { uuid } from "vue-uuid";
import store from "~@/store";
export default defineComponent({
props: {
height: {
type: String,
},
option: {
type: Object,
},
},
setup(context) {
// 图表div唯一标志
const id = uuid.v4();
onMounted(() => {
let dom = document.getElementById(id);
let chart = echarts.init(dom);
chart.setOption(context.option);
// 监听导航折叠状态
watch(
() => store.state.collapse,
() => {
setTimeout(() => chart.resize(), 400);
}
);
// 监听浏览器窗口变化
window.onresize = () => {
chart.resize();
};
});
return {
id,
};
},
});
</script>
<style scoped></style>
Gitee:gitee.com/tinychiang/…
Github:github.com/tinychiang/…