Vue 组件化开发笔记
环境安装
1、全局安装webpack
npm install webpack -g
2、全局安装vue脚手架
npm i -g @vue/cli-init
3、关于vue-cli2.x和vue-cli3.x创建项目的区别:
(1)vue-cli2.x创建项目:
vue init webpack 项目名称
(2)vue-cli3.x创建项目:
vue create 项目名称
4、启动项目
npm run dev
生命周期

Vue2笔记
CSS局部生效
scoped关键字
<style scoped>
</style>
组件自定义事件
绑定事件监听
<Header @addTodo="addTodo"/>
或者
<Header ref="header"/>
this.$refs.header.$on('addTodo', this.addTodo)
触发事件
this.$emit('addTodo', todo)
全局事件总线
1. Vue 原型对象上包含事件处理的方法
1) $on(eventName, listener): 绑定自定义事件监听
2) $emit(eventName, data): 分发自定义事件
3) $off(eventName): 解绑自定义事件监听
4) $once(eventName, listener): 绑定事件监听, 但只能处理一次
2. 所有组件实例对象的原型对象的原型对象就是 Vue 的原型对象
1) 所有组件对象都能看到 Vue 原型对象上的属性和方法
2) Vue.prototype.$bus = new Vue(), 所有的组件对象都能看到$bus 这个属性
对象
3. 全局事件总线
1) 包含事件处理相关方法的对象(只有一个)
2) 所有的组件都可以得到
4. 全局事件总线操作
1 指定事件总线对象
new Vue({
beforeCreate () { // 尽量早的执行挂载全局事件总线对象的操作
Vue.prototype.$globalEventBus = this //globalEventBus为自定义名称
},
}).$mount('##root')
2 绑定事件
this.$globalEventBus.$on('deleteTodo', this.deleteTodo)
3 分发事件
this.$globalEventBus.$emit('deleteTodo', this.index)
4 解绑事件
this.$globalEventBus.$off('deleteTodo')
在main.js中设置全局时间总线
new Vue({
el: '##app',
router,
components: { App },
//在模板解析前创建
beforeCreate() {
//vm及所有的vc都能看到
Vue.prototype.$bus = this
},
template: '<App/>'
})
5. 消息订阅与发布
- 这种方式的思想与全局事件总线很相似
- 它包含以下操作:
(1) 订阅消息 --对应绑定事件监听
(2) 发布消息 --分发事件
(3) 取消消息订阅 --解绑事件监听 - 需要引入一个消息订阅与发布的第三方实现库: PubSubJS:
1. 在线文档: https://github.com/mroderick/PubSubJS
2. 下载: npm install -S pubsub-js
3. 相关语法
(1) import PubSub from 'pubsub-js' // 引入
(2) PubSub.subscribe(‘msgName’, functon(msgName, data){ })
(3) PubSub.publish(‘msgName’, data): 发布消息, 触发订阅的回调函数调用
(4) PubSub.unsubscribe(token): 取消消息的订阅
$nextTick
- 语法:this.$nextTick(回调函数)
- 作用:在下一次DOM更新结束后执行其指定的回调
- 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
过渡动画
1. 用transition包裹需要动画的元素
<transition name="hello" appear>
<h1>hello</h1>
</transition>
2. 当多个元素时需要使用transition-group
引入第三方动画库
npm install animate.css
导入
import 'animate.css';
<transition-group
name="animate__animated animate__bounce"
appear
enter-active-class="animate__headShake"
leave-active-class="animate__backOutRight"
>
<MyItem v-for="todoObj in todos" :key="todoObj.id" :todo="todoObj" />
</transition-group>
axios
1. 安装
npm install axios
2. 导入
import axios from "axios";
2.1 在main.js中引入axios并全局配置
//--------------------------axios------------------------------------
//在main.js中引入axios并全局配置
import axios from 'axios'
Vue.prototype.$axios = axios
3. GET请求
// 向给定ID的用户发起请求
axios.get('/user?ID=12345')
.then((response) => {
// 处理成功情况
console.log(response);
})
.catch((error) => {
// 处理错误情况
console.log(error);
})
.then(function () {
// 总是会执行
});
// 上述请求也可以按以下方式完成(可选)
axios.get('/user', {
params: {
ID: 12345
}
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
})
.then(function () {
// 总是会执行
});
// 支持async/await用法
async function getUser() {
try {
const response = await axios.get('/user?ID=12345');
console.log(response);
} catch (error) {
console.error(error);
}
}
4. POST请求
发起一个POST请求
axios.post('/user', {
firstName: 'Fred',
lastName: 'Flintstone'
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
发起多个并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
Promise.all([getUserAccount(), getUserPermissions()])
.then(function (results) {
const acct = results[0];
const perm = results[1];
});
vue-resource插件
1. 安装
npm i vue-resource
2. 引入并使用插件
//引入
import vueResource from 'vue-resource'
//使用插件
Vue.use(vueResource)
3. 发送请求
this.$http.get() //post等请求方法与axios一致
引入ElementUI
1 安装
npm i element-ui -S
2 main.js中引入
//---------引入Element-UI---------
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
Vue.use(ElementUI);
//--------------------------------
代理(可用于前端解决跨域)
1. vue.config.js 配置
devServer.proxy 可以是一个指向开发环境 API 服务器的字符串:
module.exports = {
devServer: {
proxy: 'http://localhost:4000'
}
}
这会告诉开发服务器将任何未知请求 (没有匹配到静态文件的请求) 代理到http://localhost:4000。
如果你想要更多的代理控制行为,也可以使用一个 path: options 成对的对象。
完整的选项可以查阅 http-proxy-middleware。
module.exports = {
devServer: {
proxy: {
'/api': {
target: '<url>', //后端地址
ws: true, //用于websocket
changeOrigin: true //是否跨域(端口欺骗)
},
'/foo': {
target: '<other_url>'
}
}
}
}
2. config文件夹下的index.js文件找到dev里面的proxyTable{}
proxyTable: {
"/api": {
target: "<url>", //ip地址后端给的不变
changeOrigin: true, //是否跨域
pathRewrite: {
"^/api": "" //重写为空,这个时候api就相当于上面target接口基准地址
},
}
}
插槽
1.默认插槽
1.Student组件中声明插槽
<slot>这是一个插槽,等着被填充内容</slot>
2.App使用组件并填充内容
<Student>
<!-- 此时img标签将会放入Student组件slot中 -->
<img src="abc.png" alt="">
</Student>
2.具名插槽
1.Student组件中声明插槽并追加name
<slot name="top">这是一个插槽,等着被填充内容</slot>
2.App使用组件并填充内容
<Student>
<!-- 此时img标签将会放入Student组件名为top的slot中 -->
<img slot="top" src="abc.png" alt="">
<!-- 当有多个标签时推荐使用template包裹,有两种写法,v-slot只能搭配template使用 -->
<template v-slot:top>
<template slot="top">
<img src="abc.png" alt="">
<a href="http://www.abc.com">abc.com</a>
</template>
</Student>
3.作用域插槽
1.Student组件中声明插槽并传递data数据
<slot name="top" :message="message">这是一个插槽,等着被填充内容</slot>
2.App使用组件并填充内容
scope接收一个或多组数据并封装
<Student slot="top" title="学生信息">
<template scope="scopeData">
<ul>
<li v-for="(m,index) in scopeData.message" :key="index">{{m}}</li>
</ul>
</template>
</Student>
如果只接收具体数据,可解构
<Student slot="top" title="学生信息">
<template scope="{message}">
<ul>
<li v-for="(m,index) in message" :key="index">{{m}}</li>
</ul>
</template>
</Student>
vuex
1. 工作原理

2.使用Vuex
1. 安装Vuex
最新版本只能在vue3中使用,vue2中只能使用vuex的3版本
npm i vuex@3
2. 环境搭建
- 创建文件:
src/store/index.js
//该文件用于创建Vuex的store
//引入Vue
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//使用Vuex插件
Vue.use(Vuex)
//准备actions用于响应组件动作
const actions = {}
//准备mutations用于操作数据(state)
const mutations = {}
//准备state用于存储数据
const state = {}
//创建并暴露store
export default new Vuex.Store({
actions,
mutations,
state,
})
- 在
main.js中创建vm时传入store配置项
//引入store
import store from './store/index'
new Vue({
el: '#app',
router,
store, //vm配置store
components: { App },
beforeCreate() {
Vue.prototype.$bus = this
},
template: '<App/>'
})
3. 基本使用
-
初始化数据、配置
actions、配置mutations,操作文件store.js//引入Vue核心库 import Vue from 'vue' //引入Vuex import Vuex from 'vuex' //引用Vuex Vue.use(Vuex) const actions = { //响应组件中加的动作 jia(context,value){ // console.log('actions中的jia被调用了',miniStore,value) context.commit('JIA',value) }, } const mutations = { //执行加 JIA(state,value){ // console.log('mutations中的JIA被调用了',state,value) state.sum += value } } //初始化数据 const state = { sum:0 } //创建并暴露store export default new Vuex.Store({ actions, mutations, state, }) -
组件中读取vuex中的数据:
$store.state.sum -
组件中修改vuex中的数据:
$store.dispatch('action中的方法名',数据)或$store.commit('mutations中的方法名',数据)备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写
dispatch,直接编写commit
4. getters的使用
-
概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。
-
在
store.js中追加getters配置...... const getters = { bigSum(state){ return state.sum * 10 } } //创建并暴露store export default new Vuex.Store({ ...... getters }) -
组件中读取数据:
$store.getters.bigSum
5. 四个map方法的使用
-
组件中引入相关map方法
//组件中引入mapState,mapGetters,mapActions,mapMutations import {mapState,mapGetters,mapActions,mapMutations} from 'vuex' -
mapState方法:用于帮助我们映射
state中的数据为计算属性computed: { //...是ES6写法,展开对象放入computed //借助mapState生成计算属性:sum、school、subject(对象写法) ...mapState({sum:'sum',school:'school',subject:'subject'}), //借助mapState生成计算属性:sum、school、subject(数组写法) ...mapState(['sum','school','subject']), }, -
mapGetters方法:用于帮助我们映射
getters中的数据为计算属性computed: { //借助mapGetters生成计算属性:bigSum(对象写法) ...mapGetters({bigSum:'bigSum'}), //借助mapGetters生成计算属性:bigSum(数组写法) ...mapGetters(['bigSum']) }, -
mapActions方法:用于帮助我们生成与
actions对话的方法,即:包含$store.dispatch(xxx)的函数methods:{ //靠mapActions生成:incrementOdd、incrementWait(对象形式) ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'}) //靠mapActions生成:incrementOdd、incrementWait(数组形式) ...mapActions(['jiaOdd','jiaWait']) }- mapMutations方法:用于帮助我们生成与
mutations对话的方法,即:包含$store.commit(xxx)的函数
methods:{ //靠mapActions生成:increment、decrement(对象形式) ...mapMutations({increment:'JIA',decrement:'JIAN'}), //靠mapMutations生成:JIA、JIAN(对象形式) ...mapMutations(['JIA','JIAN']), } - mapMutations方法:用于帮助我们生成与
备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。
6. 模块化+命名空间
-
目的:让代码更好维护,让多种数据分类更加明确。
-
修改
store.jsconst countAbout = { namespaced:true,//开启命名空间 state:{x:1}, actions: { ... }, mutations: { ... }, getters: { bigSum(state){ return state.sum * 10 } } } const personAbout = { namespaced:true,//开启命名空间 state:{ ... }, actions: { ... }, mutations: { ... }, } const store = new Vuex.Store({ modules: { countAbout, personAbout } }) -
开启命名空间后,组件中读取state数据:
//方式一:自己直接读取 this.$store.state.personAbout.list //方式二:借助mapState读取: ...mapState('countAbout',['sum','school','subject']), -
开启命名空间后,组件中读取getters数据:
//方式一:自己直接读取 this.$store.getters['personAbout/firstPersonName'] //方式二:借助mapGetters读取: ...mapGetters('countAbout',['bigSum']) -
开启命名空间后,组件中调用dispatch
//方式一:自己直接dispatch this.$store.dispatch('personAbout/addPersonWang',person) //方式二:借助mapActions: ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'}) -
开启命名空间后,组件中调用commit
//方式一:自己直接commit this.$store.commit('personAbout/ADD_PERSON',person) //方式二:借助mapMutations: ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
vue-router
- 路由组件通常存放在
pages文件夹,一般组件通常存放在components文件夹。- 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
- 每个组件都有自己的
$route属性,里面存储着自己的路由信息。- 整个应用只有一个router,可以通过组件的
$router属性获取到。
1.安装
最新版本vue-router需要Vue3才能使用,vue2安装3版本
vue2:
npm i vue-router@3
2.编写router配置项:
//引入VueRouter
import VueRouter from 'vue-router'
//引入Luyou 组件
import About from '../components/About'
import Home from '../components/Home'
//创建并暴露router实例对象,去管理一组一组的路由规则
export default new VueRouter({
routes:[
{
path:'/about',
component:About
},
{
path:'/home',
component:Home
}
]
})
3.实现切换(active-class可配置高亮样式)
<router-link active-class="active" to="/about">About</router-link>
4.指定展示位置
<router-view></router-view>
5.多级路由(嵌套路由)
-
配置路由规则,使用children配置项:
routes:[ { path:'/about', component:About, }, { path:'/home', component:Home, children:[ //通过children配置子级路由 { path:'news', //此处一定不要写:/news component:News }, { path:'message',//此处一定不要写:/message component:Message } ] } ] -
跳转(要写完整路径):
<router-link to="/home/news">News</router-link>
6.命名路由(简化跳转)
-
作用:可以简化路由的跳转。
-
如何使用
- 给路由命名:
{ path:'/demo', component:Demo, children:[ { path:'test', component:Test, children:[ { name:'hello' //给路由命名 path:'welcome', component:Hello, } ] } ] }- 简化跳转:
<!--简化前,需要写完整的路径 --> <router-link to="/demo/test/welcome">跳转</router-link> <!--简化后,直接通过名字跳转 --> <router-link :to="{name:'hello'}">跳转</router-link> <!--简化写法配合传递参数 --> <router-link :to="{ name:'hello', query:{ id:666, title:'你好' } }" >跳转</router-link>
7.路由传参
1.路由的query参数
-
传递参数
<!-- 跳转并携带query参数,to的字符串写法 --> <router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link> <!-- 跳转并携带query参数,to的对象写法 --> <router-link :to="{ path:'/home/message/detail', query:{ id:666, title:'你好' } }" >跳转</router-link> -
接收参数:
$route.query.id $route.query.title
2.路由的params参数(path)
-
配置路由,声明接收params参数
{ path:'/home', component:Home, children:[ { path:'news', component:News }, { component:Message, children:[ { name:'xiangqing', path:'detail/:id/:title', //使用占位符声明接收params参数 component:Detail } ] } ] } -
传递参数
<!-- 跳转并携带params参数,to的字符串写法 --> <router-link :to="/home/message/detail/666/你好">跳转</router-link> <!-- 跳转并携带params参数,to的对象写法 --> <router-link :to="{ name:'xiangqing', params:{ id:666, title:'你好' } }" >跳转</router-link>特别注意:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
-
接收参数:
$route.params.id $route.params.title
8.路由的props配置
作用:让路由组件更方便的收到参数
{
name:'xiangqing',
path:'detail/:id',
component:Detail,
//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
// props:{a:900}
//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
// props:true
//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
props(route){
return {
id:route.query.id,
title:route.query.title
}
}
}
9.<router-link>的replace属性
- 作用:控制路由跳转时操作浏览器历史记录的模式
- 浏览器的历史记录有两种写入方式:分别为
push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push - 如何开启
replace模式:<router-link replace .......>News</router-link>
10.编程式路由导航
-
作用:不借助
<router-link>实现路由跳转,让路由跳转更加灵活 -
具体编码:
//$router的两个API this.$router.push({ name:'xiangqing', params:{ id:xxx, title:xxx } }) this.$router.replace({ name:'xiangqing', params:{ id:xxx, title:xxx } }) this.$router.forward() //前进 this.$router.back() //后退 this.$router.go() //可前进也可后退
11.缓存路由组件
-
作用:让不展示的路由组件保持挂载,不被销毁。
-
具体编码:
<keep-alive include="News"> 指定缓存News组件 <router-view></router-view> </keep-alive>
12.两个新的生命周期钩子
- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
- 具体名字:
activated路由组件被激活时触发。deactivated路由组件失活时触发。
13.路由守卫
-
作用:对路由进行权限控制
-
分类:全局守卫、独享守卫、组件内守卫
-
全局守卫:
//src/router/index.js const router = new VueRouter({ routes:[ { name:'guanyu', path:'/about', component:About, meta:{isAuth:true} }, { name:'zhuye', path:'/home', component:Home, meta:{isAuth:true} } ] }) //全局前置守卫:初始化时执行、每次路由切换前执行 router.beforeEach((to,from,next)=>{ console.log('beforeEach',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则 next() //放行 }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() //放行 } }) //全局后置守卫:初始化时执行、每次路由切换后执行 router.afterEach((to,from)=>{ console.log('afterEach',to,from) if(to.meta.title){ document.title = to.meta.title //修改网页的title }else{ document.title = 'vue_test' } }) //暴露 export default router -
独享守卫:
//src/router/index.js //独享守卫 //beforeEnter(to,from,next){} const router = new VueRouter({ routes:[ { name:'guanyu', path:'/about', component:About, meta:{isAuth:true} }, { name:'zhuye', path:'/home', component:Home, meta:{isAuth:true} beforeEnter(to,from,next){ console.log('beforeEnter',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制(路由配置项中自定义的数据可放入meta对象中) if(localStorage.getItem('school') === 'atguigu'){ next() }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() } } } ] }) -
组件内守卫:
//xxx.vue //进入守卫:通过路由规则,进入该组件时被调用 beforeRouteEnter (to, from, next) { }, //离开守卫:通过路由规则,离开该组件时被调用 beforeRouteLeave (to, from, next) { }
14.路由器的两种工作模式
-
对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
-
hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
-
hash模式:
- 地址中永远带着#号,不美观 。
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
- 兼容性较好。
-
history模式:
- 地址干净,美观 。
- 兼容性和hash模式相比略差。
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。
-
修改工作模式
//router中配置mode属性 mode:'hash' //hash、history
15.命名视图(router-view)
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar(侧导航) 和 main(主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view没有设置名字,那么默认为 default。
<router-view class="view left-sidebar" name="LeftSidebar"></router-view>
<router-view class="view main-content"></router-view>
<router-view class="view right-sidebar" name="RightSidebar"></router-view>
一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s):
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/',
components: {
default: Home,
// LeftSidebar: LeftSidebar 的缩写
LeftSidebar,
// 它们与 `<router-view>` 上的 `name` 属性匹配
RightSidebar,
},
},
],
})
嵌套命名视图
我们也有可能使用命名视图创建嵌套视图的复杂布局。这时你也需要命名用到的嵌套 router-view 组件。我们以一个设置面板为例:
/settings/emails /settings/profile
+-----------------------------------+ +------------------------------+
| UserSettings | | UserSettings |
| +-----+-------------------------+ | | +-----+--------------------+ |
| | Nav | UserEmailsSubscriptions | | +------------> | | Nav | UserProfile | |
| | +-------------------------+ | | | +--------------------+ |
| | | | | | | | UserProfilePreview | |
| +-----+-------------------------+ | | +-----+--------------------+ |
+-----------------------------------+ +------------------------------+
Nav只是一个常规组件。UserSettings是一个视图组件。UserEmailsSubscriptions、UserProfile、UserProfilePreview是嵌套的视图组件。
注意:我们先忘记 HTML/CSS 具体的布局的样子,只专注在用到的组件上。
UserSettings 组件的 <template> 部分应该是类似下面的这段代码:
<!-- UserSettings.vue -->
<div>
<h1>User Settings</h1>
<NavBar />
<router-view />
<router-view name="helper" />
</div>
那么你就可以通过这个路由配置来实现上面的布局:
{
path: '/settings',
// 你也可以在顶级路由就配置命名视图
component: UserSettings,
children: [{
path: 'emails',
component: UserEmailsSubscriptions
}, {
path: 'profile',
components: {
default: UserProfile,
helper: UserProfilePreview
}
}]
}
16.重定向和别名
-
重定向
重定向也是通过routes配置来完成,下面例子是从/home重定向到/:const routes = [{ path: '/home', redirect: '/' }]重定向的目标也可以是一个命名的路由:
const routes = [{ path: '/home', redirect: { name: 'homepage' } }]甚至是一个方法,动态返回重定向目标:
const routes = [ { // /search/screens -> /search?q=screens path: '/search/:searchText', redirect: to => { // 方法接收目标路由作为参数 // return 重定向的字符串路径/路径对象 return { path: '/search', query: { q: to.params.searchText } } }, }, { path: '/search', // ... }, ]请注意,导航守卫并没有应用在跳转路由上,而仅仅应用在其目标上。在上面的例子中,在
/home路由中添加beforeEnter守卫不会有任何效果。在写
redirect的时候,可以省略component配置,因为它从来没有被直接访问过,所以没有组件要渲染。唯一的例外是嵌套路由:如果一个路由记录有children和redirect属性,它也应该有component属性。 -
相对重定向
也可以重定向到相对位置:const routes = [ { // 将总是把/users/123/posts重定向到/users/123/profile。 path: '/users/:id/posts', redirect: to => { // 该函数接收目标路由作为参数 // 相对位置不以`/`开头 // 或 { path: 'profile'} return 'profile' }, }, ] -
别名
重定向是指当用户访问/home时,URL 会被/替换,然后匹配成/。那么什么是别名呢?将
/别名为/home,意味着当用户访问/home时,URL 仍然是/home,但会被匹配为用户正在访问/。上面对应的路由配置为:
const routes = [{ path: '/', component: Homepage, alias: '/home' }]通过别名,你可以自由地将 UI 结构映射到一个任意的 URL,而不受配置的嵌套结构的限制。使别名以
/开头,以使嵌套路径中的路径成为绝对路径。你甚至可以将两者结合起来,用一个数组提供多个别名:const routes = [ { path: '/users', component: UsersLayout, children: [ // 为这 3 个 URL 呈现 UserList // - /users // - /users/list // - /people { path: '', component: UserList, alias: ['/people', 'list'] }, ], }, ]如果你的路由有参数,请确保在任何绝对别名中包含它们:
const routes = [ { path: '/users/:id', component: UsersByIdLayout, children: [ // 为这 3 个 URL 呈现 UserDetails // - /users/24 // - /users/24/profile // - /24 { path: 'profile', component: UserDetails, alias: ['/:id', ''] }, ], }, ]关于 SEO 的注意事项: 使用别名时,一定要定义规范链接.
Vue UI 组件库
1.移动端
- Vant https://youzan.github.io/vant
- Cube UI https://didi.github.io/cube-ui
- Mint UI http://mint-ui.github.io
2.PC端
- Element UI https://element.eleme.cn
- IView UI https://www.iviewui.com