vue学习笔记(四)之路由

简介

路由
1、vue-router 的理解

vue 的一个插件库,专门用来实现 SPA 应用

2、对 SPA 应用的理解

  1. 单页 Web 应用(single page web application,SPA)。
  2. 整个应用只有一个完整的页面。
  3. 点击页面中的导航链接不会刷新页面,只会做页面的局部更新。
  4. 数据需要通过 ajax 请求获取
    在这里插入图片描述
    在这里插入图片描述

3、路由的理解

(1)什么是路由?

1. 一个路由就是一组映射关系(key - value) 
2.  key 为路径, value 可能是 function 或 component

(2)路由分类

  1. 后端路由:
    1) 理解:value 是 function, 用于处理客户端提交的请求。
    2) 工作过程:服务器接收到一个请求时, 根据请求路径找到匹配的函数 来处理请求, 返回响应数据。
  2. 前端路由:
    1) 理解:value 是 component,用于展示页面内容。
    2) 工作过程:当浏览器的路径改变时, 对应的组件就会显示。

(3)总结

1)一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。
2)前端路由:key是路径,value是组件。

基本使用

1、安装vue-router,命令:npm i vue-router
注意:
vue-router 4 只能在 vue3 中使用;vue-router 3 才能在 vue2中使用
因此,如果在vue2中安装,需要这样写:npm i vue-router@3

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
		        }
		    ]
		})

4、在main.js 中引入

		// 引入vue
		import Vue from 'vue'
		// 引入App
		import App from './App.vue'
		// 引入VueRouter
		import VueRouter from 'vue-router'
		// 引入路由器
		import router from './router'
		
		// 关闭生产提示
		Vue.config.productionTip = false		
		// 使用插件
		Vue.use(VueRouter)
		// 创建vm
		new Vue({
		    el:'#app',
		    render: h => h(App),
		    router:router
		})

配置好路由器之后,地址栏会显示#
在这里插入图片描述
5、实现切换(active-class可配置选中时的高亮样式)

	<router-link active-class="active" to="/about">About</router-link>

6、指定展示位置

	<router-view></router-view>

案例的几个注意点

在这里插入图片描述
(1)
靠路由器规则,由路由器渲染出来的组件称为 路由组件。这里的Home.vue,About.vue。
通过<Banner/>来使用的组件,称为 一般组件
为了区分它们:

  • src/pages 一般用来放 路由组件 (别忘了修改 src/router/index.js中的路径)
  • src/components 一般用来放 一般组件

(2)当 从 Home 切换到 About, Home组件去哪里了?
Home组件会被销毁
(3)在Home组件中输出this,发现Home的vc身上多了两个属性
在这里插入图片描述
总结:

  • 路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。
  • 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
  • 每个组件都有自己的$route属性,里面存储着自己的路由信息。
  • 整个应用只有一个router(路由器),可以通过组件的$router属性获取到。(每个组件上的$router属性是完全相同的)

嵌套(多级)路由

在这里插入图片描述
1、配置路由规则,使用children配置项:

		routes:[
		    {
		        path:'/about',
		        component:About,
		    },
		    {
		        path:'/home',   //这里的home 相当于一级路由
		        component:Home,
		        children:[ //通过children配置子级路由
		            {
		                path:'news', //此处一定不要写:/news
		                component:News
		            },
		            {
		                path:'message',//此处一定不要写:/message
		                component:Message
		            }
		        ]
		    }
		]

注意!!
配置children的 path时,,一定不要加 斜杠 /
不要忘记在 上面 引入 相关的组件
2、跳转(要写完整路径):

	<router-link to="/home/news">News</router-link>

路由的query参数

在这里插入图片描述
1、传递参数
(推荐使用对象写法)

	<!-- 跳转并携带query参数,to的字符串写法 -->
	<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">跳转</router-link>
	
	<!-- 跳转并携带query参数,to的对象写法 -->
	<router-link 
	    :to="{
	        path:'/home/message/detail',
	        query:{
	           id:m.id,
	           title:m.title
	        }
	    }"
	>跳转</router-link>

补充:在字符串写法中

	:to="`/home/message/detail?id=${m.id}&title=${m.title}`"
  • to 前面加 冒号: 表示要把后面当成 js表达式 解析
  • 而使用模板字符串之后 ``,表明是 字符串
  • 在模板字符串中,可以使用 ${xxx}的 形式引用变量

2、接收参数:

	$route.query.id
	$route.query.title

命名路由

1、作用:可以简化路由的跳转。

2、使用方式:

(1)给路由命名:

{
    path:'/demo',
    component:Demo,
    children:[
        {
            path:'test',
            component:Test,
            children:[
                {
                    name:'hello' //给路由命名
                    path:'welcome',
                    component:Hello,
                }
            ]
        }
    ]
}

(2)简化跳转:

	<!--简化前,需要写完整的路径 -->
	<router-link to="/demo/test/welcome">跳转</router-link>
	
	<!--简化后,直接通过名字跳转 -->
	<router-link :to="{name:'hello'}">跳转</router-link>
	
	<!--简化写法配合传递参数 -->
	<router-link 
	    :to="{
	        name:'hello',
	        //简化前 path:'/demo/test/welcome',
	        query:{
	           id:666,
	           title:'你好'
	        }
	    }"
	>跳转</router-link>

路由中的params参数

在这里插入图片描述
1、配置路由,声明接收params参数

{
    path:'/home',
    component:Home,
    children:[
        {
            path:'news',
            component:News
        },
        {
            component:Message,
            children:[
                {
                    name:'xiangqing',
                    path:'detail/:id/:title', //使用占位符声明接收params参数
                    component:Detail
                }
            ]
        }
    ]
}

2、传递参数

	<!-- 跳转并携带params参数,to的字符串写法 -->
	<router-link :to="/home/message/detail/666/你好">跳转</router-link>
	
	<!-- 跳转并携带params参数,to的对象写法 -->
	<router-link 
	    :to="{
	        name:'xiangqing',   //必须用name
	        params:{
	           id:666,
	            title:'你好'
	        }
	    }"
	>跳转</router-link>

特别注意:
路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!
3、接收参数:

	$route.params.id
	$route.params.title

路由的props配置

​1、作用:让路由组件更方便的收到参数
2、使用方式
在index.js 中配置props

{
    name:'xiangqing',
    path:'detail',
    component:Detail,

    //第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
    // props:{a:900}

    //第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件(只适用于 params)
    // props:true

    //第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
    props($route){
        return {
            id:$route.query.id,
            title:route.query.title
        }
    }
    //解构赋值的方式
    // props({query}){
    //     return {id:query.id,title:query.title}
    // }
    //连续解构赋值的方式
    // props({query:{id,title}}){
    //     return {id,title}
    // }
}

在组件中接收:

	props:['id','title']

路由对历史记录的影响

1、默认 是 push的模式
在这里插入图片描述
浏览器以压栈的形式,逐条的存放历史数据。可以前进也可以后退
2、可以更改成 replace 模式,新的替代旧的
在这里插入图片描述
可以为路由开启 replace模式,在<router-link>标签中

<router-link :repalce="true" class="list-group-item" active-class="active" to="/home">Home</router-link>
//简写
<router-link repalce class="list-group-item" active-class="active" to="/home">Home</router-link>

3、总结
<router-link>的replace属性
(1)作用:控制路由跳转时操作浏览器历史记录的模式
(2)浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push
(3)如何开启replace模式:<router-link replace .......>News</router-link>
(4)案例中,当为News和Messages开启了replace,并且按照 About-Home-News-Messages的次序点击时:历史记录的情况如图所示
在这里插入图片描述
所以,当在message这个页面后退时,会退回到about那个页面

编程式路由导航

1、作用:不借助<router-link> 实现路由跳转,让路由跳转更加灵活

2、具体编码:
里面的内容和 <router-link> 的对象写法中的内容一致

		//$router的两个API,使用push查看
		this.$router.push({
		    name:'xiangqing',
		        params:{
		            id:xxx,
		            title:xxx
		        }
		})	
		//使用replace 查看
		this.$router.replace({
		    name:'xiangqing',
		        params:{
		            id:xxx,
		            title:xxx
		        }
		})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进(正数)也可后退(负数)。
this.$router.go(2)//前进两步

3、应用举例

<button @click="pushShow(message)">push查看</button>
<button @click="replaceShow(message)">replace查看</button>
<button @click="back">后退</button>
<button @click="forward">前进</button>

methods: {
            pushShow(m){
                this.$router.push({
                    name:'xiangqing',
                    query:{
                        id:m.id,
                        title:m.title
                    }
                })
            },
            replaceShow(m){
                this.$router.replace({
                    name:'xiangqing',
                    query:{
                        id:m.id,
                        title:m.title
                    }
                })
            },
            back(){
                this.$router.back()
            },
            forward(){
                this.$router.forward()
            }
        },

缓存路由组件

在这里插入图片描述
当在输入框输入东西后,切到message,再点回news,发现文本框中的内容没有了
因为 组件再被切换掉的时候,路由会被销毁
如何保存呢?

1、作用:让不展示的路由组件保持挂载,不被销毁。

2、具体编码:
include里面写 要缓存的组件名,如果不写默认全部的组件都要缓存

	<keep-alive include="News"> 
	    <router-view></router-view>
	</keep-alive>
	//缓存多个组件
	<keep-alive :include="['News','Message']"> 
	    <router-view></router-view>
	</keep-alive>

注意:这里要判断 要缓存的那个组件在哪展示,在它展示地方的外面包上<keep-alive></keep-alive>

两个新的生命周期钩子

1、作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
2、具体名字:

  • activated路由组件被激活时触发。
  • deactivated路由组件失活时触发。

3、使用场景:
在这里插入图片描述
当使用如下代码实现 渐变效果时

<li :style="{opacity}">欢迎学习Vue</li>

 data() {
            return {
                opacity:1
            }
        },
        mounted(){
            this.timer = setInterval(() => {
                this.opacity -= 0.01
                if(this.opacity <= 0) this.opacity = 1
            },16)
        },
        beforeDestroy(){
            clearInterval(this.timer)
        },

从 News 切换到 Message ,定时器还会一直执行。
所以用这两个钩子就能很好地解决问题:

		data() {
		      return {
		           opacity:1
		      }
		},
        
        activated() {
            this.timer = setInterval(() => {
                this.opacity -= 0.01
                if(this.opacity <= 0) this.opacity = 1
            },16)
        },
        deactivated(){
            clearInterval(this.timer)
        }
    }

这样从News切换到其他组件时,定时器就会关闭。

4、补充:
在之前生命周期的学习中,除了图中的8个生命周期钩子。还有额外的3个钩子。
分别是 之前学到的 $nextTick ,和这里的 activated、deactivated

路由守卫

  1. 作用:对路由进行权限控制

  2. 分类:全局守卫、独享守卫、组件内守卫

1.、全局守卫

// 创建并暴露一个路由器
const router = new VueRouter({
    routes:[
        {
            name:'guanyu',
            path:'/about',
            component:About,
            meta:{title:'关于'}

        },
        {
            name:'zhuye',
            path:'/home',
            component:Home,
            meta:{title:'主页'},
            children:[
                {
                    name:'xinwen',
                    path:'news',
                    component:News,
                    meta:{isAuth:true,title:'新闻'}
                },
                {
                    name:'xiaoxi',
                    path:'message',
                    component:Message,
                    meta:{isAuth:true,title:'消息'},
                    children:[
                        {
                            name:'xiangqing',
                            path:'detail',
                            component:Detail,
                            meta:{title:'详情'},
                            props($route){
                                return {id:$route.query.id,title:$route.query.title}
                            }
                        }
                    ]
                },
            ]
        }
    ]
})
	//全局前置守卫:初始化时执行、每次路由切换前执行
	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

注意:
(1)使用全局守卫就不能使用默认暴露了
(2)routes里面的每个对象 都有一个 meta 属性,可以用来自定义一些属性
(3)在修改网页标题是,使用后置守卫

2、独享守卫

某一个路由所独享的守卫。注意这里没有 after,只有before。可以和全局后置守卫搭配使用

	{
          name:'xinwen',
          path:'news',
          component:News,
          meta:{isAuth:true,title:'新闻'},
          beforeEnter: (to, from, next) => {
                if(to.meta.isAuth){    //判断是否需要鉴权
                    if (localStorage.getItem('school') === 'atguigu') {
                            next()
                	}else{
                            alert('无权限查看')
                           }
                 }else{
                     next()
                 }
          }
  },

3、组件内守卫

在某个组件内写的,为某个组件配置的

	//进入守卫:通过路由规则,进入该组件时被调用
	beforeRouteEnter (to, from, next) {
	},
	//离开守卫:通过路由规则,离开该组件时被调用
	beforeRouteLeave (to, from, next) {
	}

注意:离开守卫与上面的全局后置守卫不同! 全局后置守卫 进入组件之后 会立即被调用
但这里的离开守卫,是在离开组件的时候才被调用

路由器的两种工作模式

1、对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
2、hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
3、hash模式:

  • 地址中永远带着#号,不美观。
  • 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
  • 兼容性较好。

4、history模式:

  • 地址干净,美观 。
  • 兼容性和hash模式相比略差。
  • 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。

在这里插入图片描述
这里的 # 称为 hash(哈希),#/home/message 称为哈希值,它不会随着http请求发给服务器
比如说,在地址栏加入哈希值之后:
在这里插入图片描述
访问到的还是 http://localhost:5000/students 这个页面,也就是说哈希值不会作为路径的一部分发给服务器

构建一个小型的服务器

1、关于打包

  • 写好的项目需要进行打包,才能放到服务器上
  • npm run build
  • 打包完成后会生成dist文件夹

2、打包后要将其部署到服务器上才能访问
可以使用 node express 搭建一个服务器
(1)创建一个文件夹 demo,并用 vscode打开
(2)npm init – 输入名称
(3)安装express :npm i express
(4)在demo下新建一个服务器文件:server.js

	// 引入express
	const { response } = require('express')
	const express = require('express')
	
	const app =express()
	
	app.get('/person',(req,res) => {
	    res.send({
	        name:'tom',
	        age:18
	    })
	})
	
	app.listen(5005,(err) => {
	    if(!err) console.log('服务器启动成功了')
	})

(5)启动服务器: node server
在这里插入图片描述
(6)在demo下新建static文件夹,它一本用来存放 css,js和html文件。所以这里将 生成的dist文件下的内容 放到 static文件夹下

在server.js 中添加如下配置:

	// 引入express
	const { response } = require('express')
	const express = require('express')
	
	const app =express()
	app.use(express.static(__dirname+'/static'))    //这里!!!!
	
	app.get('/person',(req,res) => {
	    res.send({
	        name:'tom',
	        age:18
	    })
	})
	
	app.listen(5005,(err) => {
	    if(!err) console.log('服务器启动成功了')
	})

(7)server.js更改后需要重启服务器,关闭(Ctrl+c), 开启 node server
如果static下有 index.html,输入 http://localhost:5005/ 即可访问
在这里插入图片描述
访问static下的其他文件,可以使用http://localhost:5005/xxx.html
注意:

  1. 在 history 模式下,当刷新页面时,就会发送网络请求,而服务器中并没有这个路径就会报错
    在这里插入图片描述
  2. 而在 哈希模式下 不会出现这个问题,刷新也没事
  3. 但是在 实际工作中,还是常用 history 模式,因为路径比较美观。如何解决history的这一问题?
    找后端工程师:
    https://www.npmjs.com/package/connect-history-api-fallback
    在server.js中:
    安装:npm i connect-history-api-fallback
    引入:const history = require(‘connect-history-api-fallback’);
    使用:app.use(history()) //必须在引入静态资源前使用
	// 引入express
	const { response } = require('express')
	var history = require('connect-history-api-fallback');
	const express = require('express')
	
	const app =express()
	app.use(history())
	app.use(express.static(__dirname+'/static'))

	app.get('/person',(req,res) => {
	    res.send({
	        name:'tom',
	        age:18
	    })
	})
	
	app.listen(5005,(err) => {
	    if(!err) console.log('服务器启动成功了')
	})

这样就可以解决404 的问题了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值