目录
一、路由 vue-router
(一)路由与路由器
路由器能让多台设备同时上网 每个网线插口都能对应一个设备
路由器 的英文名是 router
路由器上的插口就相当于 key 我们的每个设备相当于 value 一共四个接口
那路由就是 route
key1 + value1 => 路由 route
key2 + value2 => 路由
key3 + value3 => 路由
key4 + value4 => 路由
路由就是一组 key-value 的对应关系
多个路由需要经过路由器管理
我们编程中的路由和生活中的不一样 我们编程中的路由是为了 实现 SPA 应用(单页面应用)
之前的应用是 我们写很多网页然后得来回跳转 这就是多页面应用 不太好来回跳很烦
单页面就一个页面比较好 然后里面有导航区 和展示区 点击导航区的导航然后实现显示区的内容发生变化,但是页面没跳转,左上角没转圈,路径也能跟着变化
怎么实现的页面变化然后路径也发生变化的呢
点击导航区中的班级管理 然后我们路径中多了 /class
原来是 我们的vue 中 router 能监测到 我们路径中 /class 这样的路由
路由规则是 router /class => 班级组件 如果监测到 /class 就展示 班级组件
/class 就相当于是key 班级组件相当于 value
(二)vue-router 理解
vue 的一个插件库 专门实现 SPA 应用 npm i vue-router
Vue.use()使用
(三)SPA 理解
单页面 Web 应用,整个应用只有一个完整的页面 index.html
点击页面中的导航链接不会刷新页面 只会做页面的局部更新
数据要通过 ajax 请求获取
(四)路由 理解
一个路由就是一组映射关系
key 是路径 value 是function 或 component
路由分类 :
1.后端路由:
理解;value 是 funciton 用于处理客户端提交的请求
工作过程:服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据。
2.前端路由
理解:value 是 component用于显示页面内容
工作过程:当浏览器路径改变时,对应的组件就会显示
(五)小案例
1.About.vue
<template>
<h2>我是About的内容</h2>
</template>
<script>
export default {
name: "About",
};
</script>
<style>
</style>
2.Home.vue
<template>
<h2>我是Home的内容</h2>
</template>
<script>
export default {
name: "Home",
};
</script>
<style>
</style>
3.index.js
import VueRouter from 'vue-router'
import About from '../components/About'
import Home from '../components/Home'
export default new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home
},
]
})
4.App.vue
<template>
<div>
<div class="row">
<div class="col-xs-offset-2 col-xs-8">
<div class="page-header"><h2>Vue Router Demo</h2></div>
</div>
</div>
<div class="row">
<div class="col-xs-2 col-xs-offset-2">
<div class="list-group">
<!-- <a class="list-group-item" href="./about.html">About</a>
<a class="list-group-item active" href="./home.html">Home</a> -->
<router-link class="list-group-item" active-class="active" to="/about">About</router-link>
<router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
</div>
</div>
<div class="col-xs-6">
<div class="panel">
<div class="panel-body">
<router-view></router-view>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "app",
};
</script>
5.main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import router from './router/index'
Vue.use(VueRouter)
Vue.config.productionTip = false
new Vue({
el: '#app',
render: h => h(App),
router: router
})
(六)使用步骤
1.安装 vue-router 命令 npm i vue-router
2.使用插件 Vue.use(VueRouter)
3.编写 router 配置项
就是在 src 文件夹中创建一个 router 文件夹 然后里面创建一个 index.js 文件里面配置路由
import VueRouter from 'vue-router'
import About from '../components/About'
import Home from '../components/Home'
export default new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home
},
]
})
main.js 中引入 router 然后内部 写上 router:router
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import router from './router/index'
Vue.use(VueRouter)
Vue.config.productionTip = false
new Vue({
el: '#app',
render: h => h(App),
router: router
})
4.实现切换
然后我们写切换组件的内容我们来到 app 组件中 得用一个特殊的标签 就是 router-link 里面再用一个 to 来表示 切换到的标签
router-link 里面能自动转换成 a 标签 所以我们得用人家的router-link 标签
<router-link class="list-group-item" to="/about">About</router-link>
<router-link class="list-group-item active" to="/home">Home</router-link>
5.指定显示内容
最后指定显示的内容到页面上该标签的位置
<router-view></router-view>
(七)注意点
路由组件 不用我们自己写 <zujian/> 而是靠路由规则而显示的标签叫做路由组件
这些路由组件 单独放一个文件夹中 不放 conponents 中 放在 pages 中
切换显示的组件的时候 不显示的组件是被销毁了
路由组件上 有两个属性 一个是 $route 是路由属性是我们配置的每个组件都不一样
另一个是 $router 是路由器 每个网页只能由一个路由器 是所有组件共有的
二、嵌套路由/多级路由
点击导航栏 然后显示的页面中又显示 一个导航栏 再点击 路径中出现 /school/student 的类似情况就是多级路由
在路由中再配置其它的路由就是多级路由
如下是一级路由
export default new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home
},
]
})
多级路由就是在我们已经配置的路由里面再配置子路由,因为可能不止一个子路由 就用数组对象的形式,注意里面的 path 不用加斜杠 因为网页在寻找的时候已经自动帮我们配置了斜杆
export default new VueRouter({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
children:[
{
path:'news',
component: News,
},
{
path: 'message',
component: Message,
}
]
},
]
})
在写按钮时 跳转时 路径名得补全 /home/news
<template>
<div>
<h2>Home组件内容</h2>
<div>
<ul class="nav nav-tabs">
<li>
<router-link class="list-group-item" active-class="active" to="/home/news">News</router-link>
</li>
<li>
<router-link class="list-group-item" active-class="active" to="/home/message">Message</router-link>
</li>
</ul>
<router-view></router-view>
</div>
</div>
</template>
三、路由传参
(一)query 参数
跳转路由并携带 query 参数,有两种写法
跳转的时候带着参数 我们用 ajax 请求 携带query 参数实现路由传参 不一直用多级路由来写,要不然组件太多
1.to 的字符串写法
里面是字符串 然后里面套一个 模板字符串 然后 用${ } 传入数据 :是使用 js 语法来解析
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<router-link :to="`/home/message/detail?id=${m.id}$title=${m.title}`">{{m.title}}</router-link>
</li>
</ul>
<hr>
<router-view></router-view>
</div>
</template>
我们在子路由中通过 $route.query.id $route.query.title 就能读取我们传入 detail 的数据
2.to 的对象写法
把 to 里面的东西写成对象的写法 有两个参数 第一个是我们要跳转的目标,第二个是我们要传入的参数,里面配置参数即可
<router-link
:to="{
path: '/home/message/detail',
query: {
id: m.id,
title: m.title,
},
}">
{{ m.title }}
</router-link>
我们在子路由中通过 $route.query.id $route.query.title 就能读取我们传入 detail 的数据
用这两句 接收一下就行
(二)params 参数
也是 ajax 请求中的,我们在 路由配置时 用两个占位符占两个 params 传入参数变量
路由中声明接收 params 参数
children:[
{
name:'xiangqing',
path: 'detail/:id/:title',
component: Detail,
}
]
1.to 的字符串写法
直接拼进去
配置选择路由路径的时候 直接 在 detail 后面写上 /加变量的形式 就能传入数据了
<router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{m.title}}</router-link>
我们在子路由中通过 $route.params.id $route.params.title 就能读取我们传入 detail 的数据
2.to 的对象写法
和 query 参数的对象写法中类似,对象里面的第二个配置项变成了 params 而且 第一个属性不能用 path 必须用 name !!!
<router-link
:to="{
name: 'xiangqing',
params: {
id: m.id,
title: m.title,
},
}">
{{ m.title }}
</router-link>
我们在子路由中通过 $route.params.id $route.params.title 就能读取我们传入 detail 的数据
(三)detail 读取路由中参数
我们在子路由中通过 $route.params.id $route.params.title 读取我们传入 detail 的数据
我们在子路由中通过 $route.query.id $route.query.title 读取我们传入 detail 的数据
但是这样很麻烦 如果要传入很多 我们得一个个写一遍 我们也能 通过计算属性简化写法,但是每个参数我们都得写一遍 也挺麻烦 所以我们需要路由中的一个全新的配置项 props
1.值为对象(用的非常少)
该对象中的所有 key-value 都会以props 的形式传给 Detail 组件
path: 'message',
component: Message,
children:[
{
name:'xiangqing',
path: 'detail/:id/:title',
component: Detail,
props:{a:1,b:'hello'}
}
]
组件中也得用 props 接收然后就能用这个a b 两个属性了
props: ["a", "b"],
2.值为布尔值
如果 值为 true 就会把路由中 组件收到的所有 params 参数 以props 的 形式传给 Detail 组件
不会理会 query 参数
path: 'message',
component: Message,
children:[
{
name:'xiangqing',
path: 'detail/:id/:title',
component: Detail,
// props:{a:1,b:'hello'}
props:true
}
]
接收一下
props: ["id", "title"],
3.值为函数
有一个回调函数 里面会返回给我们 $route 我们把 query 类型数据返回 实现简写
path: 'message',
component: Message,
children: [
{
name: 'xiangqing',
path: 'detail',
component: Detail,
// props:{a:1,b:'hello'}
// props:true
props($route) {
return {
id:$route.query.id,
title:$route.query.title
}
}
}
]
改成 query 方式发送
<router-link
:to="{
name: 'xiangqing',
query: {
id: m.id,
title: m.title,
},
}">
{{ m.title }}
</router-link>
四、命名路由
就是给路由起名字 给谁起名字 就在哪个路由上 加一个名字属性
可以在跳转的时候简化代码
给路由起名字 就是加一个配置属性 name
export default new VueRouter({
routes: [
{
name:'guanyu',
path: '/about',
component: About
},
{
path: '/home',
component: Home,
children:[
{
path:'news',
component: News,
},
{
path: 'message',
component: Message,
children:[
{
name:'xiangqing',
path: 'detail',
component: Detail,
}
]
}
]
},
]
})
然后给我们跳转传参的时候 可以把 path 配置项 改成 name 配置项 然后里面写上我们要传入的路由名,就能实现 简化路由的路径写法
<router-link
:to="{
name: 'xiangqing',
query: {
id: m.id,
title: m.title,
},
}">
{{ m.title }}
</router-link>
五、<router-link> 的 replace 属性
路由对浏览器中浏览记录的影响
浏览器中的前进后退按钮 是根据浏览器记录 进行使用的
使用 router-link 标签设计的 按钮 点击都会留下记录
有两种模式
(一)push 模式
保存浏览器记录 是栈的形式 点击按钮会依次将记录留在栈中 是 push 模式(默认模式)
指针指向浏览器最后的记录
点击回退 指针依次向下指
(二)replace 模式
替换当前的记录
另一种模式 replace 模式 点击新的链接 然后上一条的存在栈中的 浏览记录被删除
在 代码中 router-link 标签 中加入 一个 replace 属性就能开启 replace 模式
<router-link replace class="list-group-item" active-class="active" to="/home/news">News</router-link>
最后会回到 没被删除的记录
六、编程式路由导航
不借助 router-link 实现路由跳转 让路由跳转更灵活
不用 router-link 标签 实现路由选择 因为 router-link 最后只能转换成 a 标签,别的就不行了,比如按钮
我们就用一个新的方法来实现
如果是按钮我们先绑定一个点击事件 pushShow(m) 我们在方法中写一个函数 也叫 pushShow(m)
oush 方式跳转
pushShow(m) {
this.$router.push({
name: "xiangqing",
query: {
id: m.id,
title: m.title,
}
});
},
replace 方式跳转
replaceShow(m) {
this.$router.replace({
name: "xiangqing",
query: {
id: m.id,
title: m.title,
}
});
},
this.$router.go(数字) 里面是正数 跳转往前跳转
如果是负数就往后跳转
七、缓存路由组件
让不展示的路由组件保持挂载,不被销毁
如果写在 keep-alive 里面的组件都将被缓存 如果标签里面写了 inlcude=“News” 就指明了缓存的对象不是所有都缓存,只缓存里面的 News 缓存的名字是组件名 就是我们组件中写的第一个属性 name
<keep-alive incluede="News">
<router-view></router-view>
</keep-alive>
如果要缓存多个组件 那就写成数组的形式 先规定里面使用 js 中的规则 加一个冒号 即可
<keep-alive :incluede=["News","message"]>
<router-view></router-view>
</keep-alive>
八、新的声明周期钩子
路由组件独有的声明周期钩子
一个是激活的 另一个是失活的 两个钩子 当组件展示到我们眼前时就调用激活的函数
当组件被切走的时候 失活的周期就调用了
activated(){
},
deactivated(){
}
正常我们想写一个 文字循环减少透明度的格式,我们在 mounted 和 beforeDestoryed 两个声明周期写 但是我们我们前面实现对这个组件实现了缓存 会导致计时器关闭不了的情况
beforeDestroy() {
clearInterval(this);
},
mounted() {
this.timer = setInterval(() => {
this.opacity -= 0.01;
if (this.opacity <= 0) this.opacity = 1;
}, 16);
},
所以我们得用这两个声明周期钩子 就能成功解决了 显示的时候就显示 不显示的时候就关闭
activated() {
console.log('显示')
this.timer = setInterval(() => {
this.opacity -= 0.01;
if (this.opacity <= 0) this.opacity = 1;
}, 16);
},
deactivated() {
clearInterval(this.timer);
},
九、路由守卫
保护路由的安全就是给访问者设置权限
(一)全局路由守卫
1.前置路由守卫
全局前置路由守卫
在初始化和切换路由之前进行调用下面的函数
能把所有的东西都给拦住
函数内部有三个参数 to from next 一个是出发的路由 一个是目的路由 next 是放行的意思
然后在里面加上跳转权限就行
router.beforeEach((to, from, next) => {
console.log(to, from)
if (to.path === '/home/news' || to.path === '/home/message') {
if (localStorage.getItem('school') === 'xuexiao') {
next()
}
}else{
next()
}
})
export default router
但是第一个判断 条件太长 我们能在路由中加一个属性,我们加一个布尔属性就行 判断路由是否用判断路由是否需要 判断权限
我们得添加在 meta 中的属性中 比如叫 isAuth 是否授权
哪个路由需要判断权限 就给哪个路由加这个属性
{
name: 'guanyu',
path: '/about',
component: About,
meta: {
isAuth: true
}
},
然后代码就能简化一下
router.beforeEach((to, from, next) => {
console.log(to, from)
if (to.meta.isAuth) {
if (localStorage.getItem('school') === 'xuexiao') {
next()
}
} else {
next()
}
})
export default router
2.后置路由守卫
在初始化和切换路由之后进行调用下面的函数
后置路由守卫 函数中没有 next 参数,因为已经切换成功了 不需要再判断是否切换了
router.afterEach()
router.afterEach((to, from) => {
document.title = to.meta.title || '硅谷系统'
})
(二)独享路由守卫
在路由里面单独配置守卫函数名为 beforeEnter 只有前置没有后置路由守卫
但是可以和全局路由守卫中的后置路由守卫相配合
里面的参数和全局路由守卫 一样 用法也一样
beforeEnter: (to, from, next) => {
if (to.meta.isAuth) {
if (localStorage.getItem('school') === 'xuexiao') {
next()
}
} else {
next()
}
}
(三)组件内部路由守卫
通过路由规则进入该组件时被调用
to 就是该组件 from 是来的地方
beforeRouteEnter(to, from, next) {
if (to.meta.isAuth) {
if (localStorage.getItem("school") === "xuexiao") {
next();
}
} else {
next();
}
},
通过路由规则离开该组件时被调用
to 是离开该组件前往的地方 from 是该组件
beforeRouteLeave(to, from, next) {
next();
},
十、history 模式和 hash 模式
我们浏览器中 网页路径 # 和后面的东西都算作哈希值
hash 模式它不会随着 http 协议发给服务器
路由器默认进行 hash 工作模式
hash 模式
兼容性略好 转发网页路径容易非法
history 模式
没有 # 号 路径没有 hash 值
兼容性略差
需要后端人员解决 404 的问题
打包 就是把 我们写的vue 文件转会 html css js 文件
我们用 build 文件生成 dist 文件夹 里面就有这些文件
生成的 文件不能直接打开 还得放在服务器上部署 才行
十一、Vue UI 组件库
常用于 不是定制化网页的开发 因为定制化的组件比较有辨识度 容易被认为抄袭
移动端常用的 UI 组件库 Vant 、Cube UI 、Mint UI
PC 端常用的 UI 组件库 Element UI、IView UI
问题 : 组件库基于 Vue 还是 React
是 pc 端 还是移动端
建议使用 部分引入 减少文件大小