021 vue路由vue-router
[A] 认识路由
路由是网络工程中的一个专业术语
(维基百科)路由就是通过互联的网络把信息从源地址传输到目的地址的活动
1. 路由提供两种机制:路由和转送
路由是决定数据包从来源到目的地的路径
转送将输入端的数据转送到合适的输出端
2. 路由中有一个重要的概念:路由表
路由表实质上是一个映射表,决定了数据包的指向
3. 前端路由和后端路由
首先解释前端渲染和后端渲染
在最初的网页开发中,前后端是不分离的,网页的展示都是在后端,也就是服务器端
后端渲染:服务器根据用户的请求,控制器会将对应数据处理,并渲染生成相应的页面,
然后将生成的页面直接发送给前端,展示给用户。
前端渲染:随着ajax的出现,网页开发实行前后端分离的开发模式,后端只负责数据处理,
将用户所需的数据发送给前端,前端将拿到的数据进行处理,最后渲染到页面上展示给用户。
前端路由和后端路由:
前端路由:在 Web 前端单页应用 SPA(Single Page Application)中,
路由描述的是 URL 与 UI 之间的映射关系,这种映射是单向的,
即 URL 变化引起 UI 更新(无需刷新页面)。
后端路由:前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做,
每跳转到不同的URL都是使用前端的锚点路由. 随着(SPA)单页应用的不断普及,
前后端开发分离,目前项目基本都使用前端路由,在项目使用期间页面不会重新加载。
4. 目前前端流行的三大框架都有自己的路由实现
Angular的ngRouter
React的ReactRouter
Vue的vue-Router
vue-Router
1. vue-Router是Vue.js官方的路由插件(通过npm下载),它与vue.js高度集成,适合用于的单页面应用
2. vue-Router路由学习网站:https://router.vue.js.org.zh/
3. vue-Router是基于路由和组件的
路由用于设定访问路径,将路径和组件映射起来
在vue-Router的单页面应用中,页面的路径的改变就是组件的切换
[B] vue-router的基本使用
1. 安装路由
npm install vue-router --save
2. 在工程模块中使用(因为这是一个插件,所有可以通过Vue.use()来安装路由功能)
1. 创建路由
第一步:导入路由对象,并且调用Vue.use(router)
第二步:创建路由实例,并且给传入路由映射配置
第三步:导出路由
示例代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// router/index.js // 1. 导入vue组件和vue-router组件 import Vue from 'vue' import VueRouter from 'vue-router' const home = () => import('@/views/home/home') // 调用路由组建 Vue.use(VueRouter); const routes = [ { path: '/', redirect: '/home' }, { path: '/home', component: home, meta:{ title: '首页' } }, ]; // 2. 创建路由实例 const router = new VueRouter({ routes, mode: 'history', }) // 3. 导出路由实例 export default router
2. 挂载路由
第一步:导入路由
第二步:将创建的路由实例挂载到Vue实例中去
示例代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
// main.js文件 // 1. 导入路由组件 import Vue from 'vue' import App from './App.vue' import router from './router' Vue.config.productionTip = false // vue实例化 new Vue({ // 将路由对象挂载到vue实例中 router, render: h => h(App), }).$mount('#app')
3. 使用步骤
第一步:创建路由组件(/component)
第二步:配置路由映射:组件和路径的映射关系(/router/index.js)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
const routes = [ { // 2. 重定向配置,页面创建后就直接显示这个被重定向的页面 path: '/', redirect: '/home' }, { // 1. 基本配置,将组件个和路径匹配起来 path: '/home', component: home, meta:{ title: '首页' } }, ]
第三步:使用路由(App.vue)
<router-link>: 用于跳转到指定页面的连接
1. router-link标签用于最终会渲染成a标签,即超链接,这是一个全局组件,可以在任何位置使用
2. router-link标签的to属性用于指定跳转的路径,该路径在路由组件中指定的那个组件就是跳转到的页面。
<router-link to="/home">首页</router-link>
<router-view>:用于指定渲染页面的显示位置
1. 该组件是配合router-link组件使用的
2. router-link组件用于指定跳转到哪个组件去,而router-view组件指定跳转的那个页面显示在哪个位置。
示例代码:
最终会渲染出 首页 和 关于 两个a标签
点击这两个a标签,会跳转到对应的页面去,而页面就显示在这两个a标签下面(router-view所在的这个位置)
<router-link to="/home">首页</router-link> <router-link to="/about">关于</router-link> <router-view/>
4. 路由的默认配置
默认情况下,首次渲染出来的页面会显示App.vue中的内容,即页面为空的,当点击连接时才会显示页面
此时,我们想要页面渲染出来的时候就直接显示指定的一个页面
在router/index.js中的路由映射中新增一个对象
{
path:'/'
// 这里也可以为path: ''
redirect: '/home'
// 这里是将路径重定向到/home路径下,即默认页面显示的内容为home页面
}
【注】这里的路径path可以随便写,只要和App.vue中的要引用的路径一致就行了
5. 改成history模式
改变路径的方式有两种:
URL的hash
HTML5的history
在上述中,通过单页面富应用的模式,会实现从主页面到子页面的跳转,到那时路径中包含有#
如:http://localhost:8080/#/home等等
即默认为hash模式,通过锚点来改变页面内容
hash模式改成history模式:
在配置路由映射表(router/index.js)中的路由实例中新增一个对象:
mode: 'history'
6. router-link的其他属性
router-link标签写在App.vue中,最终会被渲染成a标签
1. to属性,用于指定跳转的路径
2. tag属性,用于指定将该标签渲染成什么组件,默认是a标签
取值:
button:按钮
li:列表
等等
3. replace
默认采用history的pushState方式跳转页面的,这样就使得可以使用默认的返回箭头回到之前的页面
添加replace属性后,则采用replaceState方式跳转页面,也就灭了历史记录,只能通过html元素跳转页面
4. router-link-exact-active 和 router-link-active
App.vue中的router-link链接被单击之后,会跳转到相应的页面,与此同时,被单击的那个router-link标签
会被增加上两个class:router-link-exact-active 和 router-link-active
1. 这里只讲router-link-active,这个类是被激活的标签的默认添加的类名,
因此可以App.vue类添加样式,使得该页面对应的链接在激活时显示样式
2. 也可以修改这个激活添加的类名,在路由中添加新的对象
linkActiveClass: "active",
7. 通过代码实现页面跳转
在上面router-link标签可以实现点击后页面跳转
给普通标签(如div,button等)添加点击事件,也可以通过调用函数的方法实现页面的跳转
1. 给标签添加点击事件,并绑定发一个方法(App.vue中)
2. 在方法中指定跳转的页面(App.vue中)
this.$router.push("/home"); // 这个跳转后历史记录
或者:
this.$router.replace("/home"); // 这个跳转后没有历史记录
【注】这里的$router实际上就是在router/index.js中,我们创建的那个router
【注】$route指的是当前处于活跃状态的那个组件,即在App.vue中通过<router-view/>被渲染出的那个组件
8. 动态路由的使用
在某些情况下,一个页面的path路径可能是不确定的,除了前面的user,我们还希望加上用户的名字
比如:
/user/zhangsan
/user/lisi
1. 在路由映射中,将路径path修改为/user/zhangsan的模式
2. 在App.vue中调用页面时,填写上一步中相同的路径即可实现
而上述两步中是静态的,若要实现动态路由,需改进前两步骤:
1. 在路由映射中,将路径path修改为动态绑定模式:/user/:name
2. 在App.vue中调用页面时,页面路径改为::to = /user/+NAME, 这里的NAME为App组件中保存的数据
3. 此外,若想在相应的页面中获取第2步中传入的NAME值,可以在相应页面中调用$route独享获取
this.$route.params.name, 这里的name必须与第1步中的name同名
【注】这里的$route对象指的是当前处于活跃状态的路由
而之前在路由映射中超出对象中的routes指的是所有的路由
9. vue-router打包文件解析
项目开发结束之后,我们会使用在控制台使用:npm run build将开发代码进行打包
打包完成之后们会在当前路径下生成一个dist文件夹,里卖弄包含内容“
【注】 -xxx表示文件夹, --xxx表示文件
-dist
-static
-css
--app.(hash).css // css相关文件,即样式内容
--app.(hash).map.css
-js
--app.(hash).js // 业务代码,即开发者手动书写的代码
--app.(hash).js.map
--manifest.(hash).js // 为我们打包的代码做底层支撑的,如使得CommonJS,ES6语法都可使用等等内容
--manifest.(hash).js.map
--vendor.(hash).js // 提供商,即第三方提供的内容,vue,vue-router,axios(网络请求)等等
--vendor.(hash).js.map
--index.html
[C] vue-router的懒加载
在开发中,如果代码过多,那么一次性请求这些代码数据,需要时间加载, 这就会导致用户界面在加载的时候处于短暂的空白,
这样使得用户体验不好,因此我们希望把不同的路由对应的组件分割成不同的代码块,然后当路由别访问时才加载相应的组件
1. 官方解释
1. 路由中筒仓会定义很多不同的页面
2. 这些不同的页面通常会被打包到一个.js文件中
3. 到那时所有页面都打包到一个.js中,会造成这个js文件非常大
4. 如果我们一次性从服务器请求下来这个页面,会耗费一定的时间等待,而在这个等待的时间里,用户界面会出现短暂的空白
5. 为避免这种短暂空白的现象,我们使用懒加载
2. 懒加载做了什么
1. 路由的懒加载主要作用是将路由对应的组件打包成一个个的js代码块
2. 只有在这个路由被访问的时候才加载相应的组件
3. 路由懒加载生成的文件
--vendor.(hash).js
--manifest.(hash).js
--app.(hash).js
--页面1.js
--页面2.js
......
4. 懒加载的实现
一共三种方式:
1. vue异步组件和webpack的代码实现
const home = resolve => {require.ensure(['../component/home.vue'],
() => resolve(require('../component/home.vue')))};
2. AMD写法
const home = resolve => require(['../component/home.vue'], resolve);
3. ES6语法
const home = () => import('../component/home.vue')
[D] vue-router嵌套路由
路由嵌套是一个常见的功能,比如再home页面中,我们希望通过/home/news和/home/messages访问一些内容
1. 一个路径映射一个组件,访问这两个路径也会分别渲染两个组件
2. 路径与组件的关系:
/home----------------------->Home
/home/news-------------->News
/home/message----------->Message
/about---------------------->About
3. 实现嵌套的步骤
1. 创建对应的子组件
2. 并且在路由映射中配置相应的子路由,在相应父组件映射中新增children数组来保存子组件的路由映射
{
path: '/home',
component: home,
children:[
{
path: 'news', // 这里你的路径前不加/
component: news
},
{
path: 'message', // 这里你的路径前不加/
component: message
},
]
},
2. 在f父组件(home组件)内部使用<router-view>标签
<router-link to = "/home/news">新闻</router-link>
<router-link to = "/home/message">消息</router-link>
<router-view/>
【注】这里的to的路径要写全
[E] vue-router参数传递
参数传递有两种方式:params和query
params类型
1. 配置路由格式:/user/:id
2. 传递方式:在path后面跟上对应的值
3. 传递后形成的路径:/user/abs, /user/123等
query类型
1. 配置路由格式:/user (即普通格式)
2. 传递方式: 对象中使用query的key作为传递方式
3. 传递后形成的路径:/user?id=123, /user?id=abs
实现过程:
1. 创建相应组件
2. 在App.vue中引用这个组件,在to属性中添加需要传递的参数
<router-link :to = "{path: '/profile', query:{name: 'jack', age:18}}">我的</router-link>
【注】这里to中绑定的数据也可存储在组件的数据中,然后在再引用
3. 在原组件profile中获取参数,通过$route.query获取
data(){
return {
name: this.$route.query.name,
age: this.$route.query.age
}
}
当<router-link>别替换成button时如何传递数据
添加点击事件,在事件内部push相关路径和所要传输的数据
params类型:
this.$router.push("/student/" + this.name);
query类型
this.$router.push({
path: '/profile',
query:{
name: 'jack',
age: 18
}
})
【注】所有的组件都继承自vue类的原型,如果在main.js中给vue实例新增一个原型对象,则在所有组件中都会增加这个对象
[F] vue-router导航守卫
1. 我们在主页中通过点击按钮实现页面的跳转,又是我们需要记录页面跳转的记录和过程,在跳转的时候实现一下功能,比如页面标题的修改等
************************************************************************************************
知识点补充:生命周期
*************************************************************************************************
2. 在组件的生命周期中,利用hook函数可以实现组件创建后完成相应自定义命令的功能
因此,在每个组件创建时,在created函数中添加相应指令即可
如:
// 在每个组件中新增created函数
created(){
document.title = '主页';
},
// 即可实现,给每个页面添加页面标题
3. 然而上述的实现方法中,需要给每个页面都新增created方法,过程过于冗杂,因此我们使用全局守卫的方法动态添加标题
1. 在路由映射中给每个映射的页面添加需要保存的数据,如title
{
path: '/profile',
component: profile,
meta:{
title: '我的'
}
}
2. 在路由映射中调用当前实例化路由的beforeEach函数
router.beforeEach(function(to, from, next){
// 从from页面跳转到to页面
document.title = to.meta.title;
next()
})
4. 相关补充
1. mata:元数据,为描述数据的数据
2. router.beforeEach: 为前置钩子,即页面跳转之前完成的操作
此外,还有后置钩子router.afterEach,在后置钩子中,不需要调用next()函数
3. 除了全局守卫还有:
路由独享的守卫
组件内的守卫
学习网址:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
我们通过按钮可以实现页面跳转,在一个页面中国我们可能进行一些操作之后在跳转到别的页面,
当再次跳转到该页面时,页面已经刷新了,之前的操作全没了,
这是因为当跳转到别的页面,之前的页面就被销毁掉了,当再次跳转到之前的页面,页面会被重新建立和渲染
若想保留之前页面的操作,需要使用keep-alive
keep-alive是Vue内置的一个组件,可以是被包含的组件保留状态,或避免重新渲染
router-view也是一个组件,如果直接被包在keep-alive里面,所有路径匹配到的视图组件都会被缓存
实现步骤:
1. 在App.vue组件中用keep-alive组件将router-view包裹
即:
<keep-alive>
<router-view/>
</keep-alive>
2. 在需要保存状态的那个组件中(如home),新增组件内的守卫函数:beforeRouteLeave
beforeRouteLeave(to, from, next){
this.currentPath = this.$route.path
console.log(this.currentPath);
next();
}
// 这一步可以用来保存离开当前页面时,当前页面的路径
3. 在需要保存状态的那个组件中(如home),新增一个回调函数:activated
activated(){
this.$router.push(this.currentPath)
},
// 这一步,是将该页面再次被激活时,将上次保存的路径重新赋值
知识点补充:
对于每一个组件,都有activated和deactivated两个回调函数,用来识别该组件时处在激活状态还是未激活状态
activated(){
// 当组件别激活时调用该回调函数
}
deactivated(){
// 当组件未被激活时调用该回调函数
}
keep-alive补充属性:
1. 在App.vue中使用了keep-alive组件之后,所有被渲染的单页面都会保存其原来的状态,
但是有时候,有的页面我们不想保存原有状态,比如学生页面
解决: keep-alive组件有两个属性:include和exclude,取值为字符串或正则表达式
// 这里的user为组件名(即name)
// 若有多个组件名,应为exclude = "user,student",这里,之后不能加" "(空格)
<keep-alive exclude = "user">
<router-view/>
</keep-alive>
// 同理,include表示为只有包含的组件才会被缓存
[H] vue-router相关配置设置
使得打包的文件不进行压缩(丑化),便于阅读
build/webpack.prod.config.js文件中
注释掉UglifyJsPlugin的相关代码
[ I ] 案例实践:TabBar的实现
样式:
-----------页面内容----------
首页----分类----购物车----我的
TabBar实现思路:
1. 在下方有一个单独的组件
--自定义TabBar组件,在App中使用
--让TabBar置于底部,并设置相关的样式
2. TabBar中显示的内容由外界决定
--定义插槽
--flex布局平分TabBar
3. 自定义TabBarItem,可以传入图片和文字
--定义TabBarItem,并且定义两个插槽:图片和文字
--给两个插槽外层包装div,用于设置样式
--填充插槽,实现底部TabBar的效果
4. 传入高亮图片
--定义另一个插槽,后插入active-icon的数据
--定义一个变量isActive,通过v-show来决定是否显示对应的icon
5. TabBarItem绑定路由数据
--安装路由:npm install vue-router --save
--完成router/index.js中的内容,以及创建对应的组件
--main.js中注册router
--APP中加入<router-view>组件
6. 点击item跳转到对应路由,并且动态的决定isActive
--监听item的点击,通过this.$router.replace()替换路由路径
--通过this.$router。path.indexOf(this.link) !== -1来判断是否是active
7. 动态计算active眼视光hi
--封装新的计算属性; this.isActive ? {'color':'red'};{}
知识点补充:
1. 给文件路径起别名
我们若被引用的文件层级较多,那么我们引用文件缩写的路径就很长很繁琐。此外,我呢见中的路径复制到别的文件中,路径就会出错,这样很不方便
【解决办法】:
给特定的文件夹起个别名,就可以直接使用别名
【操作步骤】:
1. 在配置文件(webpack.base.conf.js)中给路径起别名
修改resolve对象中的alias对象
resolve: {
// 这里表示拓展名为'.js', '.vue', '.json'的文件在引用时,可以不写后缀名
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
// 以下为自定义别名
'@assets': resolve('@assets'),
'@components': resolve('@components'),
'@pages': resolve('@pages'),
}
},
2. 在路径中使用路径的别名
如:
<img slot="item-icon" src="~@assets/img/tabBar/home.svg" alt="首页">
【注】
1. 这里的别名@assets前必须加~
2. 由于修改了配置文件,因此该项目必须重新使用npm run start运行,否则配置文件不起作用