文章目录
1. 缓存路由组件
keepalive标签就可以实现组件的缓存。
- 组件缓存后,是被挂载起来,并不会被销毁的!
- 注意:include属性里面必须是组件的属性名!!!
<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>
<!--
keep-alive默认是里面所有的内容全部缓存。
include属性:定义哪个组件需要缓存!
如下面就是让组件名为News的组件进行缓存。
缓存后,这个News组件不会被销毁的。
-->
<!--对于单个组件缓存,直接写字符串就行。-->
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
<!--对于多个组件缓存,用数组形式。-->
<keep-alive :include="['News','Message']">
<router-view></router-view>
</keep-alive>
</div>
多个组件需要缓存,可以写成数组形式:
总结:
2. 路由组件对应的两个特别的 钩子函数
activated激活,deactivated失活。
使用场景,当我们缓存了一些组件,切换组件的时候该组件是被挂载并不会销毁,组件中的一些东西仍然是在进行的,例如:定时器;这个时候想要关闭定时器,就需要这个两个特别的钩子函数来操作了。
export default {
name:'News',
data(){
return {
opacity:1,
}
},
//激活
activated(){
console.log('News组件被激活了')
this.timer = setInterval(()=>{
console.log("定时器在工作。")
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
})
},
//失活
deactivated() {
console.log('News组件失活了')
clearInterval(this.timer)
}
}
this.nextTick(function(){})的nextTick也是个生命周期的钩子函数。
- 当dom元素加载完成后,再加载里面的function函数内容。
总结:
3. 路由守卫
3.1 全局前置路由守卫
路由守卫:负责管理路由的权限。
例如:用户在没有登录的情况下,能看到个人中心的组件么?显然是不可以的,这就由路由守卫来管理,判断有没有进入该路由组件的权限。
全局前置路由守卫(router.beforeEach()):
- 什么时候出发全局前置守卫?初始化的时候会调用。每次切换路由之前会被调用。
- beforeEach函数的三个参数:to参数:要去哪个路由的信息。from参数:来自哪个路由的信息。next参数:是一个函数它是放行的意思。
//该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
import About from '../pages/About.vue'
import Home from '../pages/Home.vue'
import News from '../pages/News.vue'
import Message from '../pages/Message.vue'
import Detail from '../pages/Detail.vue'
const router = new VueRouter({
routes:[
{
name:'guanyu',
path:'/about',
component:About
},
{
name:'zhuye',
path:'/home',
component:Home,
},
]
})
/*
全局前置路由守卫:
before在...之前,each每一次的意思。
从英文意思就是在每次切换路由之前,都会调用beforeEach里面的函数。
此外,初始化的时候也会调用它。
什么时候出发全局前置守卫?
初始化的时候会调用。
每次切换路由之前会被调用。
beforeEach函数的三个参数:
to参数:要去哪个路由的信息(路由规则)。
from参数:来自哪个路由的信息(路由规则)。
next参数:是一个函数它是放行的意思。
*/
router.beforeEach((to,from,next)=>{
console.log(to)
console.log(from)
//接下来就是判断什么时候放行,什么时候不放行!
//判断to里面path或者name去哪里。
if(to.path === '/home/news' || to.path === '/home/message'){
//模拟登录效果
if(sessionStorage.getItem('username') === 'itholmse'){
next()
}else{
alert('请先登录')
}
}else{
next()
}
})
//暴露router路由器
export default router
打印两个参数:
3.2 this.$route的meta
我们定义的这些都是配置对象!都是系统自己设计好的!因此,不能随便添加内容。vue为了能让我们存信息,专门设置了meta。
可以将判断的权限存到meta中,进而直接判断,避免一些繁琐的内容。
//该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
import About from '../pages/About.vue'
import Home from '../pages/Home.vue'
import News from '../pages/News.vue'
import Message from '../pages/Message.vue'
import Detail from '../pages/Detail.vue'
const router = new VueRouter({
routes:[
{
//定义的这些都是配置对象,都是系统自己设计好的!
name:'guanyu',
path:'/about',
component:About,
//使用meta中的isAuth来做权限校验,这样就不需要乱七八糟的校验了。
meta:{
isAuth:false
}
},
{
name:'zhuye',
path:'/home',
component:Home,
children:[
{
name:'xinwen',
path:'news',
component:News,
meta:{
isAuth:true
}
},
{
name:'xiaoxi',
path:'message',
component:Message,
meta:{
isAuth:true
},
children:[
{
name:'xiangqing',
path:'detail/:id/:title',
component:Detail,
props({query:{id,title}}){
//解构赋值
return {
id,
title
}
}
}
]
}
]
},
]
})
router.beforeEach((to,from,next)=>{
// 直接判断每个路由中,meta中的isAuth来判别是否需要权限验证。
if(to.meta.isAuth){
if(sessionStorage.getItem('username') === 'itholmse'){
next()
}else{
alert('请先登录')
}
}else{
next()
}
})
//暴露router路由器
export default router
3.3 全局后置路由守卫
全局后置路由守卫什么时候调用?
- 初始化的使用被调用。每次路由切换之后被调用。
全局后置路由守卫的to,from参数都和前置路由守卫也一样。并且没有next()方法(不需要)。
//该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
import About from '../pages/About.vue'
import Home from '../pages/Home.vue'
import News from '../pages/News.vue'
import Message from '../pages/Message.vue'
import Detail from '../pages/Detail.vue'
const router = new VueRouter({
routes:[
{
//我们定义的这些都是配置对象,都是系统自己设计好的!
name:'guanyu',
path:'/about',
component:About,
//使用meta中的isAuth来做权限校验,这样就不需要乱七八糟的校验了。
meta:{
isAuth:false,
title:'关于'
}
},
{
name:'zhuye',
path:'/home',
component:Home,
meta:{
isAuth:false,
title:'主页'
},
children:[
{
name:'xinwen',
path:'news',
component:News,
meta:{
isAuth:true,
}
},
{
name:'xiaoxi',
path:'message',
component:Message,
meta:{
isAuth:true
},
}
]
},
]
})
router.beforeEach((to,from,next)=>{
if(to.meta.isAuth){
if(sessionStorage.getItem('username') === 'itholmse'){
next()
}else{
alert('请先登录')
}
}else{
next()
}
})
/*
全局后置路由守卫什么时候调用?
初始化的使用被调用。
每次路由切换之后被调用。
to,from参数都和全局前置路由守卫也一样。并且没有next()方法(不需要)。
*/
router.afterEach((to,from)=>{
//当通过了全局前置路由守卫得到放行后,可以修改一些内容!
document.title = to.meta.title || 'itholmes' // 如果为空,就让他为itholmes。
console.log(to,from)
})
//暴露router路由器
export default router
4. 独享路由守卫
某一个路由所单独响应的路由守卫。
独享路由守卫:beforeEnter:(to,from,next)=>{} , 是在路由器配置项里面配置。
- 注意:独享路由守卫只有前置,没有后置。
- 如果需要在后置搞东西,直接用全局后置路由守卫也是一样的。
{
name:'xinwen',
path:'news',
component:News,
meta:{
isAuth:true,
},
//独享路由守卫
beforeEnter:(to,from,next)=>{
if(to.meta.isAuth){
if(sessionStorage.getItem('username') === 'itholmse'){
next()
}else{
alert('请先登录')
}
}else{
next()
}
}
},
5. 组件内路由守卫
beforeRouteEnter和beforeRouteLeave函数,是定义在组件内部的配置项中。
- beforeRouteEnter函数是通过路由规则,进入该组件时被调用。注意是路由规则,并不是组件。
- beforeRouteLeave函数是通过路由规则,离开该组件时被调用。同样注意是路由规则,并不是组件。
<template>
<h2>我是About内容</h2>
</template>
<script>
export default {
name:'About',
//通过路由规则,进入该组件时被调用
//注意:这里是通过路由规则,beforeRouteEnter才会被调用。并不是看组件!
beforeRouteEnter(to,from,next) {
console.log('Enter == >beforeRouteEnter')
//要放行才能进入
next()
// console.log(to)
// console.log(from)
},
//通过路由规则,离开该组件时被调用
// 注意:这里是通过路由规则,beforeRouteLeave才会被调用。并不是看组件!
beforeRouteLeave(to,from,next) {
console.log('Leave == >beforeRouteLeave')
//要放行才能离开
next()
}
}
</script>
<style>
</style>
6. hash模式和history模式
6.1 什么是hash?
这里平时看到的#号,叫做hash。
hash后面的内容是不会发给后台服务器的,不走http协议的。
hash后面的内容全部以hash值的形式存在的。
- 前端的js就可以操作这些hash值,来控制。前端服务器只是一个提供html,js等资源的。这些hash值并不会传给前端服务器的。
6.2 hash模式和history模式
在Vue-router中,有两种工作模式:hash模式和history模式。
设置history模式:
hash的兼容性要比history好一些。就是一些浏览器hash就能兼容。
部署前端项目后,history模式有一个严重的问题,就是当直接访问组件中的组件路径,它不识别!也就是history模式刷新404问题!
hash模式,因为不会收到服务器的限制,所以hash模式是可以避免history模式上面的问题的。
6.3 项目的安装,部署
项目打包:npm run build 将项目打包。
打包后会生成一个dist文件,会将当前项目的一些内容,转成css,js,html的文件。
npm init命令
npm i express命令
server.js文件内容:
const express = require('express')
const app = express()
//配置好进入的目录。
app.use(express.static(__dirname + '/static'))
app.get('/person',(req,resp)=>{
resp.send({
name:'tom',
age:18
})
})
app.listen(5005,(err)=>{
if(!err){
console.log("服务器启动成功")
}
})
6.4 如何解决history模式刷新404问题?
问题根源就是服务器端没有固定的路径来访问:
我们可以在服务器端一个个配置,这样太麻烦了,可以通过第三方库解决。
对于不同的服务器,有不同的库来解决history模式刷新404问题。
对于nodejs服务器而言,可以在npmjs官方上面找到connect-history-api-fallback
安装:
- npm install --save connect-history-api-fallback
server.js配置:
const express = require('express')
const app = express()
//解决history模式刷新404错误。
var history = require('connect-history-api-fallback');
app.use(history())
app.use(express.static(__dirname + '/static'))
app.get('/person',(req,resp)=>{
resp.send({
name:'tom',
age:18
})
})
app.listen(5005,(err)=>{
if(!err){
console.log("服务器启动成功")
}
})
6.5 总结
7. Vue UI组件库
UI组件库分两类:移动端组件库 和 PC端组件库。
京东也出了一个移动端的UI组件库。叫做NutUI组件库。
饿了么团队业开发了一个PC端的组件库,ElementUI组件。
elementui是vue中的插件库。
8. elementui组件库
8.1 elementUI安装和引入
elementUI组件不用记住,如何安装,如何引入,如何使用都可以直接去官方文档上面看。
安装elementUI组件:
- npm i element-ui
在main.js中引入elementUI组件库和elementUI所有样式。
import Vue from "vue"
import App from "./App.vue"
//引入vue的elementUI组件库
import ElementUI from 'element-ui';
//引入elementUI全部样式
import 'element-ui/lib/theme-chalk/index.css';
//应用elementUI插件。
Vue.use(ElementUI)
Vue.config.productionTip = false;
const vm = new Vue({
el:'#app',
render:h=>h(App),
})
8.2 elementUI操作
注意两种标签命名的写法规则:
<!--
标签的几种格式写法:
el-row 通过vue开发者工具查看其实也就是ElRow。
这两种写法是最常用的!
-->
<el-row>
<el-button>默认按钮</el-button>
<el-button type="primary">主要按钮</el-button>
</el-row>
对于elementUI组件,只要导入了elementUI组件库和样式并且应用了(use)。
组件就可以随便调用。
如果先要修改组件的一些信息,在每一个elementui组件上面都会有标识的!
像刚才的main.js中引入,有一个弊端!
- 因为我们引入了全部的elementUI样式库和组件库。这样相当于将全部的内容发给了前端,这样就会发送很多的内容!
- 因此,我们要按需引入才行!
8.3 elementUI的 按需引入
在官方也是有说到,如何进行按需引入。
安装 babel-plugin-component:
- npm install babel-plugin-component -D (-D是开发依赖,还有一个生产依赖)
一个注意点:官方要修改一个.babelrc,但是babel的最新版文件已经成为了js文件。
因为配置文件不同了,我们只需要按照对象形式引入就可以:(babel.config.js)
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset',
//官方的es2015会报错的,可能是版本更新导致。
//这里我们使用@babel/preset-env。
["@babel/preset-env", { "modules": false }]
],
plugins: [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
}
这样我们只需要一个个引入,并且全局注册组件就可以了。
总结如下:
- mian.js文件:
import Vue from "vue"
import App from "./App.vue"
/*
完整引入:
//引入vue的elementUI组件库
import ElementUI from 'element-ui';
//引入elementUI全部样式
import 'element-ui/lib/theme-chalk/index.css';
//应用elementUI插件。
Vue.use(ElementUI)
*/
/*
按需引入
这里的引入如果标签是el-button ,那么就是引入Button,将el去掉,首字母大写。
el-date-picker就是DatePicker,去掉el和- , 使用大驼峰写法。
*/
import {Button ,Row,DatePicker} from 'element-ui';
//这里的Button.name是就是组件名,也可以自己操作。
//内部默认就是el-button名。
Vue.component(Button.name, Button);
Vue.component('itholmes-row', Row);
Vue.config.productionTip = false;
const vm = new Vue({
el:'#app',
render:h=>h(App),
})
8.4 总结
不管哪个组件库,其实过程都是一样的对于vue而言。
都是导入组件库样式和引用,部分引用等等
直接看对应的官方,一步步来就可以了。