环境准备
- install node, reference: nodejs.org;
若下载的是 zip,还需设置环境变量,即将 node 根目录(node.exe 和 npm 命令所在处)添加到 path
node -v; npm -v;
- 可选:全局安装npm替代品,yarn,pnpm;会安装到npm命令所在目录
# 全局安装 pnpm
npm install -g pnpm
pnpm -v
# 全局安装 yarn
npm i -g yarn
yarn -v
使用vue-cli工具(基于webpack构建工具)创建vue基础范例+webpack基础配置项目,
- global install vue cli:
- npm i -g @vue/cli 或 yarn global add @vue/cli
- vue --version
- vue create vue3proj(项目名不能包含中文,和大写)
- npm run serve 或 yarn serve
使用create-vue工具(基于vite构建工具,新一代构建工具)创建vue基础范例+vite基础配置项目,
# 查看版本
node -v (must>=16)
npm -v
# create a new vue app:
npm init vue@latest # will install and execute create-vue
# Project Setup
yarn install | npm install
# Compile and Hot-Reload for Development
yarn dev | npm run dev
# Compile and Minify for Production
npm run build
npm run preview
plugins
- vs语法高亮插件vetur(vue2),volar(vue3)
- eslint>规范代码
- 常用代码规范:JavaScript Standard Style: standardjs.com/rules-zhcn.…
- eslint启用代码规范后,若代码不符合规范,eslint会报错
- 手动修改(不认识的规则查规则表)zh-hans.eslint.org/docs/latest…
- 自动修改
- vscode插件ESLint 教程的3m30s,090-ESLint自动修正代码规范错误
- Lints and fixes files ESLint
- npm run lint
vue-router
创建路由
/*
* 注意
* name重复的路由只会注册靠后的
* path重复的路由,都会注册,但是匹配靠前的
* */
import HomeView from "@/a-main-app/home/HomeView.vue";
const routes = {
// to属性与path匹配的RouterLink会加上类:router-link-active router-link-exact-active
// 而且此时to属性与其父级路由path匹配的RouterLink会加上类router-link-active
path: '/home',
// route level code-splitting
// this generates a separate chunk (About.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import('@/a-layout/homeLayout/HomeLayout.vue'),
redirect: '/',
//如果父级路由设置component,访问子路由会先在app.vue的RouterView(路由出口)中显示该组件,然后再在该组件的RouterView显示子组件,若该组件没有RouterView,子组件应该显示的位置会空白
//若未设置component,访问子路由就直接在app.vue的RouterView中显示子组件
// component: () => import('@/components/views/DemoView.vue'),
meta: {
title: 'Q享-齐分享,同乐趣,共进步!', // 设置该路由在侧边栏和面包屑中展示的名字
// icon: 'el-icon-s-help' // 设置该路由的图标,对应路径src/assets/icons/svg
// hidden: true, // 如果设置为true,则不会在侧边栏出现
// noCache: true // 如果设置为true,则不会被 <keep-alive> 缓存(默认 false)
// breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示
// affix: true // 如果设置为true,则标签将永远显示在左侧
// activeMenu: '/demo/note' // 如果设置路径,侧边栏将突出显示您设置的路径
// roles: ['admin','editor'] // 设置该路由进入的权限,支持多个权限叠加
},
children: [
{
path: '/',
name: 'home',
component: HomeView,
meta: {
title: 'Q享-菜单',
transition: 'fade',
anchorTopOffset: 200
},
},
{
path: '/demo',
name: 'demo',
children: [
// 动态路由传参,?为参数可选符,不加的话表示必须传参,否则匹配不到组件,如/demo/note,/demo/note/显示空白
{
path: '/note/:words?', name: 'note',
component: () => import('@/a-main-app/home/note/NoteCompositionApiSimple.vue')
},
]
},
]
}
路由模式
histroy模式
url scheme: [//[user[:password]@]host[:port]][/path][?query][#fragment]
url=http://localhost:9000/demo/?q=3#contact?a=1
location={
hash: "#contact?a=1"
host: "localhost:9000"
hostname: "localhost"
href: "http://localhost:9000/demo/?q=3#contact?a=1"
origin: "http://localhost:9000"
pathname: "/demo/"
port: "9000"
protocol: "http:"
search: "?q=3"
}
// 依赖 HTML5 History API 和服务器配置。
route={
fullPath: "/demo/?q=3#contact?a=1"
hash: "#contact?a=1"
matched: Array(2)
meta: Object
name: "demo"
params: Object
path: "/demo/"
query: {
q: "3"
}
}
hash模式
url=http://localhost:9000/demo/?a=1#/demoZj/?b=2#contact?c=3
location={
hash: "#/demoZj/?b=2#contact?c=3"
host: "localhost:9000"
hostname: "localhost"
href: "http://localhost:9000/demo/?a=1#/demoZj/?b=2#contact?c=3"
origin: "http://localhost:9000"
pathname: "/demo/"
port: "9000"
protocol: "http:"
search: "?a=1"
}
// 会根据location.hash进行路由
// 支持所有浏览器,包括不支持 HTML5 History Api 的浏览器。
route={
fullPath: "/demoZj/?b=2#contact?c=3"
hash: "#contact?c=3"
matched: Array(3)
meta: Object
name: "/demoZJ"
params: Object
path: "/demoZj/"
query: {
b: "2"
}
}
配置
// 参考https://v3.router.vuejs.org/zh/api/#routes
const router = createRouter({
// 路由模式简洁配置方法
// history路由,地址栏不带#号;hash路由,地址栏带#号,默认值
// mode: 'history',
// 配置地址栏基路径,会覆盖vite.config.js中base
// history: createWebHistory(import.meta.env.BASE_URL),// 为vite.config.js中base
// history: createWebHistory('/'),
// history: createWebHistory('/base'),
history: createWebHashHistory(),
linkActiveClass: 'linkActiveClass',
linkExactActiveClass: 'linkExactActiveClass',
callBack:'null',
// 当路由跳转后滚动条所在的位置,默认为上一路由所在位置
// 只是hash值变也会回调, url全完相同也会回调
scrollBehavior(to, from, savedPosition) {
if (from.path === to.path) {
//滚动条不动
return
} else {
return {left: 0, top: 0}
}
},
routes:constantRoutes,
})
区别和注意点
- history(推荐使用,更加兼容原生)
- 上线后,会按服务器实际配置的location(nginx)处理请求,所以需要配置后端,否则出现各种问题:如即点击RouterLink跳转正常,再次刷新或直接访问会404
- 不会对访问的url做任何变动
- hash
- 上线后,也是先根据后端location获取到html,在根据hash进行路由导航
- 会对访问的url智能加上#/,但路由导航取决于最终location.hash值
- 注意
- hash模式下,/#hash定位需要使用RouterLink,a标签不行,history模式都可以
- 使用a标签会刷新页面,会导致所有显示组件重新渲染,重走生命周期,所以非外链都应该用RouterLink来动态加载路由组件。如果只改变hash值使用a不会刷新页面,但任然建议使用RouterLink
other
- 搭配
- vue2 VueRouter3 Vuex3
- vue3 VueRouter4 Vuex4
- Recommended IDE Setup
VSCode + Volar (and disable Vetur) + TypeScript Vue Plugin (Volar).
Vite配置
vite环境变量
console.log("环境变量", import.meta.env)
/**
* BASE_URL: "/"
* DEV: true 是否处于开发环境
* MODE: "development"
* PROD: false
* */
- vite自定义环境变量
在以下文件中配置的变量
.env.development
.env.production
.env.staging
配置前缀envPrefix(官方文档), 然后上述文件中,以envPrefix
开头的环境变量会通过 import.meta.env 暴露在你的客户端源码中。
vite项目process.env.时process为undefined,webpack 才用 process.env.
自动导入配置
- 按需引入, 自动导入配置
// vite.config.ts
import {ConfigEnv, defineConfig, UserConfig} from 'vite'
import {VantResolver} from "@vant/auto-import-resolver";
import Components from 'unplugin-vue-components/vite';
import {ElementPlusResolver, LayuiVueResolver} from "unplugin-vue-components/resolvers";
import AutoImport from 'unplugin-auto-import/vite'
import IconsResolver from "unplugin-icons/resolver";
export default defineConfig((configEnv: ConfigEnv): UserConfig => {
// ...其他逻辑
return {
// ...其他配置
plugins: [
/**
* Vant, ElementPlus, Layui等库的按需引入, 自动导入
* ElementPlus参考:https://github.com/sxzz/element-plus-best-practices/blob/main/vite.config.ts
* 整体配置,原理参考:https://zhuanlan.zhihu.com/p/612397686
*/
AutoImport({
// 自动导入对应库中相关函数,但还是建议使用直接引入
// vue: ref, reactive, toRef...
// vue-router: useRoute, useRouter...
imports: [
"vue",
"vue-router",
"pinia",
],
resolvers: [
// 自动导入 Element Plus 相关函数,如:ElMessage, ElMessageBox... (带样式)
ElementPlusResolver(),
// 自动导入 Layui 相关函数,
LayuiVueResolver(),
// 自动导入图标组件
IconsResolver({
// prefix: 'Icon',
}),
],
eslintrc: {
// 如果使用了eslint,需要设置 eslintrc 字段
// 是否自动生成 eslint 规则至 filepath 指定文件,建议生成之后设置 false
enabled: false,
// 确保该文件在 eslint 配置文件 .eslintrc.js 或 .eslintrc.cjs 中被 extends
// 这样 ESlint 就不会报变量没有定义的错误了
filepath: "src/typings/.generated-auto-import-eslintrc.json",
globalsPropValue: true,
},
// 是否在 vue 模板中自动导入
vueTemplate: true,
// 自动生成函数类型声明类型至指定文件
// dts: false, //关闭自动生成
dts: "src/typings/generated-auto-import.d.ts",
}),
// ???开启后 RouterLink,RouterView 没有显性配置也会自动导入
Components({
resolvers: [
// 自动导入 Vant 组件
VantResolver(),
// 自动导入 Element Plus 组件
ElementPlusResolver(),
// 自动导入 LayuiVue 组件
LayuiVueResolver(),
// 自动注册图标组件
IconsResolver({
enabledCollections: [
// element-plus图标库,
"ep",
// 其他图标库 https://icon-sets.iconify.design/
],
}),
],
// 自动导入指定目录下的.vue组件 (默认为"src/components" ""等价于"src/*")
dirs: ["src/!**!/auto-import"],
// dirs: ["src/nocomponents"],
// dirs: ["src/components", "src/!**/components"],
/**
* 自动生成组件类型声明至指定文件,
* 声明只用于能在.vue中找到组件声明,解决TS类型丢失导致编译报错
* 真正的自动导入取决于resolvers,dirs配置
* 1.对于本地组件(dirs):就算没被引用也会生成生成声明
* 2.对于组件库(resolvers):
* 被引用的组件在dev,并且在浏览器访问后生成声明
* 若不希望生成该声明,则需要先注释reolvers生成本地组件声明,然后关闭自动生成,再解注释resolvers
* 或者在没在浏览器打开前关闭自动生成
* 4.声明只会增加,覆盖,不会删除(1.手动删除属性 2.删除声明文件再重新生成)
* 5.声明属性名称: 若为index.*则为目录名,否则为文件名,且会转为大坨峰
*/
dts: false, // 关闭自动生成
// dts: "src/typings/generated-components.d.ts",
}),
],
}
})