Vue——路由(面试、引入、router-view和router-link标签、动态路由&传参、路由嵌套--子路由跳转、路由模式--hash&history、VueRouter router ro)

目录

路由

1.相关认识

2.引入

 2.1 方法一:cdn查阅

 2.2 方法二:自己npm下载引入使用

2.3 方法三: cli安装  (常用)

3.router-view和router-link   标签

4.动态路由&传参

4.1 query传参:

4.2 动态路由传参

5.路由嵌套--子路由跳转

6.路由模式--hash&history(面试)

1)hash模式:

2)history模式:

3)抽象模式

4)面试题:history模式和hash模式的区别

7.VueRouter router route区别

8.路由守卫

8.1全局守卫

8.2路由独享的守卫

9、动态添加(注册)路由


路由

1、生态系统(就是全家桶),就是插件

2、singe  page app==>单页应用==>一个网站只有一个页面

3、前后端路由名一定不要同名

4、面试题——Vue的优缺点:

1.相关认识

 后端路由:对于前端的网络请求,不同的pathname,去执行后端的不同业务
 前端路由:不同的网址对应各自的页面
 vue的前端路由:SPA应用要做出路由效果,就得判断当前网址,然后切换组件
 vue-router就是专门做切换组件的功能,它是一个单独的技术,依赖vue
 就像jQuery和dom操作一样

2.引入

 2.1 方法一:cdn查阅

 2.2 方法二:自己npm下载引入使用

 安装到项目中:
 npm i vue-router --save-dev//注意:这种下载不好,因为打包之后容易出问题
 npm i vue-router --save或者 npm i vue-router --S

 //在main.js入口文件中引入
 import Vue from "vue"
 import VueRouter from "vue-router"//引入路由工具,一般让脚手架去下载,自己手动下载不知道下哪一个版本
 import App from "./App.vue"
 Vue.use(VueRouter)//注入路由,就是运行路由的相关函数和给vue绑定东西:比如$router。把router擦火箭的功能绑定到原型上
 
 //创建路由工具/路由对象
 const router=new VueRouter({
    mode:"history"  //模式,历史记录
	 //routes路由器 生成很多网址对应的切换组件。相当于注册网址
	 routes:[{path:"/home",component:()=>import("./home.vue")},
             {path:"/about",component:()=>import("./about.vue")}]
 })
 new Vue({
	 router,//把路由挂载到页面   :主要功能就是监听地址栏的改变,然后修改项目中的router-view组件应该加载的组件
	 render(h){return h(App)}
 }).$mount("#app")
 
//在App.vue中写 <router-view></router-view>

2.3 方法三: cli安装  (常用)

自定义就会把路由安装好

1、新建一个文件夹,cmd

2、vue create init

选择第三个:Manually select features

选择 :Babel、Router、CSS Pro-processors、Linter / Formatter

选择:2.

回车

Sass

回车

Lint on save 不勾选

然后全部回车

代码解释:

src里面的内容

 main.js

import Vue from 'vue'
import App from './App.vue'
//引入路由:主要功能就是配置路由的规则(路由模式 注册的路由地址-网址  组件原型链中绑定路由对象和路由信息)
import router from './router'
new Vue({
  //挂载路由到整个项目中:主要功能就是监听地址栏的改变 然后修改项目中的router-view组件应该加载的组件
  router,
  render: h => h(App)
}).$mount('#app')

router下面的index.js

//引入Vue webpack打包时如果已经打包过了 就不会打包了 
//所以这行代码时为了当前文件中不报错  但是实质打包时并不会打包,因为main.js中已经打包了
import Vue from 'vue'
//引入路由插件
import VueRouter from 'vue-router'
//引入首页组件:一开始就会打包,因为首页一般是用户直接访问的页面 
import Home from '../views/home/index.vue'
//给组件的原型链绑定功能: this.$router  this.$routes
Vue.use(VueRouter)
//注册路由
const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  },
  {
    path: '/login',
    name: 'login',
    component: () => import('../views/login/index.vue')
  }
]
//配置路由规则
const router = new VueRouter({
  mode: 'history',
  routes
})
export default router

App.vue

<template>
  <div id="app">  
    <!-- <h1>app组件</h1> -->
   <router-view></router-view>
  </div>
</template>
<style lang="scss">
</style>

views下面的home下面的index.vue

<template>
	<div>
		<div>home666</div>
		<Box1></Box1>
		<a href="/login">去login</a>
	</div>
</template>
<script>
	import Box1 from "./Box1.vue"
	export default {
		components: {
			Box1 //:()=>import("./Box1.vue")
		}
	}
</script>
<style>
</style>

3.router-view和router-link   标签

router-view: (会显示某一个组件)

相当于 路由网址匹配到的组件 会渲染到当前组件的这个标签上

当地址栏的网址改变时,如果新网址跟提前注册路由匹配,就会加载注册的组件

遇到这个 <router-view></router-view>标签,就会去匹配路由

router-link:相当于a标签,给我们提供跳转到某个路由的功能,如果没有匹配到路由就会跳转失败: 

<router-link to="/login"> xx<router-link >

<router-link to="{path:'/login'}"> xx<router-link >
编程式跳转(JS跳转-编程式导航):

this.$router.push("/login")

this.$router.push({path:"/login"}

this.$router绑定在组件原型链上的,路由对象,它有一些功能

a标签和router-link:的区别

1、a标签会请求服务器,然后刷新网页,因此用在链接外部网站

2、router-link:  它是渲染到页面也是a标签,但是只是改变了地址栏的网址并没有重新加载网页 ==>  路由的底层就是采用的history,去监听地址栏的变化,然后把当前APP组件中的router-view切换了,因此这种跳转用在网站内部的路由跳转

3、router-link: 可以传参,传对象,但是 a标签就不行

4.动态路由&传参

路由传参有2种方式

传递的参数都在路由信息对象中:  路由对应的组件中获取 this.$route

4.1 query传参:

4种传参:

query是一个对象,query传参是把参数放在querystring字段中

    <router-link to="/login?name=karen&pwd=123">go</router-link>
    <router-link :to="{ path: '/login', query: { a: 1, b: 2 } }">go</router-link>
    this.$router.push("/login?a=1&b=2")
    this.$router.push({path:"/login",query:{name:"karen",pwd:123}})

一种接收获取数据:

==> 在路由匹配的组件中获取数据:
目标页面:在create之后的所有地方
this.$route.query 接收获取数据,如果没有传参,这个值就没有
this.$route 绑定在组件原型链上,路由信息对象,它有一些信息
mounted(){let queryObj=this.$route.query}

4.2 动态路由传参

params传参

动态路由传参就是把参数放在pathname中

//注册 
{   path:"/news/:id",
	name:"news",
	component:()=>import("../views/news/index.vue")
  }
//设计:
const router=new VueRouter({
	 routes:[
		 {path:"/home/:id",component:()=>import("./home.vue")},
		 {path:"/about",component:()=>import("./about.vue")}]
 })
 
 //2种传参:
 <router-link to="/home/123">go</router-link>
 this.$router.push({path:"/home",params:{id:123}})
// 如果提供了 path,params 会被忽略,上述例子中的 query 并不属于这种情况。
//取而代之的是下面例子的做法,你需要提供路由的 name 或手写完整的带有参数的 path:
this.$router.push({name:"myhome",params:{id:arg}})   /name是独一无二的,和id一样,不可以重名

//得出四种跳转==>
<router-link to="/news/参数">news</router-link><br>
<router-link :to="{name:"news",params:{id:参数}}">news</router-link><br>
this.$router.push("/news/参数")
this.$router.push({name:"news",params:{id:参数}})  //必须用name跳路由
 
//在路由匹配的组件中获取数据:
mounted(){let paramsObj=this.$route.params}

//目标页面:在created之后的所有地方
this.$route.params   // 接受获取数据,如果没有传参 这个值就没有

5.路由嵌套--子路由跳转

 语法:一个路由对象的设计中中包含:

path(路由匹配的路径)

component(匹配路径时对应渲染的组件)  

redirect(匹配路径时重新匹配另外的路径)

 children(子路由们的数组)  

==>子路由中的匹配地址不要在前面加/  否则就会认为是根路由。如果非要写/,那就将父级的也加上。(eg:a的儿子是a1,那么a1的path可以写:a1或者/a/a1)

name(路由的名字,方便直接通过名字来匹配路由)
routes=[{path,component,redirect,children,name},{path,component,redirect,children,name}]

const routes = [{
	path: '/',
	component: () => import("../views/root.vue"),
    redirect:"/goods_rank",//重定向==> 访问/时默认重新访问/goods_rank
	children: [{
            name:"goods_rank",
			path: "goods_rank",  
			component: () => import("../views/root/goods_rank.vue"),
  //goods_rank组件加载的条件是路由匹配上了: localhost:8080/goods_rank
			children: [{
                    name:"goods_rank_all",
					path: "goods_rank_all",    
//这里path不加/  如果要加的话就应该写:/goods_rank/goods_rank_all
					component: () => import("../views/root/goods_rank/goods_rank_all.vue")
  //goods_rank_all组件加载的条件是路由匹配上了: localhost:8080/goods_rank/goods_rank_all
				},
				{
					path: "goods_rank_highpraise",
                    name:"goods_rank_highpraise",
					component: () => import("../views/root/goods_rank/goods_rank_highpraise.vue")
				},
				{
					path: "*",   //统配==>都没匹配上,就匹配这个,所以这个要放在最后
					component: () => import("../views/root/goods_rank/goods_rank_all.vue")
				}
			]

		},
		{
			path: "goods_inventory",
            name:"goods_inventory",
			component: () => import("../views/root/goods_inventory.vue")
		},
		{
			path: "goods_new",
            name:"goods_new",
			component: () => import("../views/root/goods_new.vue")
		},
		{
			path: "goods_set",
            name:"goods_set",
			component: () => import("../views/root/goods_set.vue")
		}
	]
}]

组件中跳转时:

//4种语法:
//1
<router-link to="/当前代码所在组件的路由地址/去哪一个子路由的地址">go</router-link>
this.$router.push({path:"/当前代码所在组件的路由地址/去哪一个子路由的地址"})
//2
<router-link to="去哪一个子路由的地址">go</router-link>
this.$router.push({path:"去哪一个子路由的地址"})
//注意:前面的/要写上,代表绝对路由,不写的话代表相对于当前路由,而不是当前父组件路由
//3
<router-link :to="{name:'注册的路由的name'}">go</router-link>
this.$router.push({name:'注册的路由的name'})

例:
<router-link to="/goods_rank/goods_rank_highpraise">go</router-link>
this.$router.push({path:"/goods_rank/goods_rank_highpraise"})

<router-link :to="{name:'goods_rank_highpraise'}">go</router-link>
this.$router.push({name:'goods_rank_highpraise'})


补充:
push用的更多
this.$router.push("/") //push就添加一条新的历史记录,点击返回,真的可以回到刚刚那个页面

//replace跟push很像,但不会向 history 添加新记录,而是替换当前的history记录
this.$router.replace({path:"/home"})

this.$router.go(1)// 在浏览器记录中前进一步,等同于 history.forward()
this.$router.go(-1)// 后退一步记录,等同于 history.back()
this.$router.go(3)// 前进 3 步记录
this.$router.go(-100)// 如果 history 记录不够用,那就失败

跳转总结:

注册路由时,路由路径不要在前面加 斜杠

跳转路由时

1.path里写的路径必须前面加斜杠 从根路由路径开始写

2.不用path 直接使用name

6.路由模式--hash&history(面试)

router下的index.js

//配置路由规则
const router = new VueRouter({
  mode: "hash",//'history',
  routes
})

1)hash模式:

在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取;

特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。

hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。

hash底层切换组件的方式是使用的老技术的Hash值,当地址栏的hash变化的时,切换了router-view渲染的组件,来”欺骗”用户,到达切换新网页的效果,hash值是不会发送给后端的,所以不需要后端配合

2)history模式:

history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。

history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“这种模式,需要后台配置支持……

所以,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。

window.history==>H5之后出来的,打印出来的话,里面有length、state等等

history底层切换组件的方式是使用的H5的window.history的技术,当地址栏的history状态发生变化时,切换了router-view渲染的组件,来”欺骗“用户,到达切换新网页的效果

需要后端工程师配合  (写一个后端路由,并且与前端不一样)

打包:那npm run biuld

const router=new VueRouter({
     mode:"hash",//"history"
	 routes:[{path:"/home",component:()=>import("./home.vue")},
	         {path:"/about",component:()=>import("./about.vue")}]
 })

3)抽象模式

自行查阅学习

常用的是hash模式和history模式

4)面试题:history模式和hash模式的区别

将上面的内容说出即可

7.VueRouter router route区别

VueRouter是一个nodejs识别的模块包
route是路由匹配时,携带了一些信息的对象,包括path,params,hash,query等等信息
router是路由实例对象,包含了路由的跳转方法,钩子函数等等

8.路由守卫

8.1全局守卫

全局前置钩子router.beforeEach( fn (to,from,next) ),导航被触发----一般登录验证

无论进入哪一个路由(只要每匹配一次路由),都要先调用这个函数

to、from 路由信息对象,next()去匹配路由,然后加载组件

next()  去渲染组件


全局解析钩子router.beforeResolve(fn),组件初始化
全局后置钩子router.afterEach(fn),没有next,导航被确认,一般路由跳转以后用window把窗口调上去

//全局前置守卫
router.beforeEach((to, from, next) => {
	//用户未登录只能访问首页、登录注册页面
	if (to.path == "/" || to.path == "/login" || to.path == "/register") {
		next();
	} else {
		//去其他页面判断是否登录
		let flag = window.localStorage.getItem("email");
		//登录过直接放行
		if (flag) {
			next()
		} else {
			//未登录则跳转到首页
			Message({
				message: '您尚未登录哦,请先登录!',
				type: 'warning',
				duration: 1500
			});
			next("/");
		}
	}
})

//全局后置守卫
router.afterEach((to, from) => {
  window.scrollTo(0,0)
})

8.2路由独享的守卫

路由独享的守卫beforeEnter(to,from,next),路由初始化(组件未初始化)----

a,路由鉴权-----用户体验:界面,功能,bug,效率,权限

b,组件异步加载情景中(插件配置:syntax-dynamic-import)

routes:[{
    path:"/test",
    component:()=>import("../components/Test.vue"),
    beforeEnter(to,from,next){
        if(to.path==="/test"){
          alert("请登录");
          next(false); // 禁止跳转
        }else{
          next()
        }
 	}
}]

3)组件内部生命周期守卫

beforeRouteLeave 从该组件离开

beforeRouteEnter(to,from,next),组件被激活,使用不了this,故构造指定该next 可以接收一个回调函数接收当前vm 实例----路由传参获取参数,得到初始化数据

beforeRouteUpdate(to,from,next),组件重用时被调用----路由传参获取参数,避免增添watch 开销

导航守卫执行顺序:beforeRouteLeave < beforeEach < beforeRouteUpdate < beforeEnter < beforeRouteEnter < beforeResolve < afterEach

出发路由,预备从当前组件离开,判断路由变化,判断组件是否重用,判断新路由初始化,判断组件初始化,路由与组件初始化完毕,路由组件重定向完毕

//引入Vue webpack打包时如果已经打包过了 就不会打包了 
//所以这行代码时为了当前文件中不报错  但是实质打包时并不会打包,因为main.js中已经打包了
import Vue from 'vue'
//引入路由插件
import VueRouter from 'vue-router'
//引入首页组件:一开始就会打包,因为首页一般是用户直接访问的页面 
// import Home from '../views/home/index.vue'
//给组件的原型链绑定功能: this.$router  this.$routes
Vue.use(VueRouter)
//注册路由
const routes = [{
		path: '/',
		name: 'home',
		component: () => import("../views/home/index.vue")
	},
	{
		path: '/home',
		name: 'home2',
		component: () => import("../views/home/index.vue")
	},
	{
		path: '/login',
		name: 'login',
		component: () => import("../views/login/index.vue")
	},
	{
		path: '/car',
		name: 'car',
		component: () => import("../views/car/index.vue")
	},
	{
		path: '/news',
		name: 'news',
		component: () => import("../views/news/index.vue"),
		beforeEnter(to,from,next){
			console.log("beforeEnter",1111)
			next()
		}
	},
	{
		path: '/*',
		name: 'err',
		component: () => import("../views/err/index.vue")
	}
]
const router = new VueRouter({
	mode: "history",
	routes
})
//收尾一定是next(),不然就死循环了
router.beforeEach(function(to, from, next) {
	//to,from路由信息对象  
	// console.log("无论进入哪个路由(只要每匹配一次路由)  都要先调用这个函数", 11111111111)
	// console.log(to, from)
	if (to.path == "/car"||to.path=="/info") {
	    var islogin=window.localStorage.getItem("islogin")
		if(islogin=="ok"){
			next()
		}else{
			 next("/login")
		}      
	} else {
		next() //去匹配路由然后加载组件
	}
	// next("/car")
})
//这个守卫 知道它什么时候触发  我没用过
router.beforeResolve(function(to,from,next){
	console.log("路由匹配完毕",to,from)
	next()//渲染组件
})
//操作window
router.afterEach(function(to,from){
	console.log("组件渲染了")
	window.scrollTo(0,0)
})
//路由全局守卫: 所有路由匹配都会经过这三个钩子:beforeEach  beforeResolve  afterEach
//guard
export default router; 

9、动态添加(注册)路由

一般是架构师在设计使用

main.js

import Vue from 'vue'
import App from './App.vue'
//引入路由:主要功能就是配置路由的规则(路由模式 注册的路由地址-网址  组件原型链中绑定路由对象和路由信息)
import router from './router'
new Vue({
  //挂载路由到整个项目中:主要功能就是监听地址栏的改变 然后修改项目中的router-view组件应该加载的组件
  router,
  render: h => h(App)
}).$mount('#app')
 

router下的index.js

//引入Vue webpack打包时如果已经打包过了 就不会打包了 
//所以这行代码时为了当前文件中不报错  但是实质打包时并不会打包,因为main.js中已经打包了
import Vue from 'vue'
//引入路由插件
import VueRouter from 'vue-router'

//引入首页组件:一开始就会打包,因为首页一般是用户直接访问的页面 
// import Home from '../views/home/index.vue'

//给组件的原型链绑定功能: this.$router  this.$routes
Vue.use(VueRouter)


//注册路由
const routes = [{
		path: '/',
		name: 'home',
		component: () => import("../views/home/index.vue")
	},
	{
		path: '/home',
		name: 'home2',
		component: () => import("../views/home/index.vue")
	},
	{
		path: '/login',
		name: 'login',
		component: () => import("../views/login/index.vue")
	},
	// {
	// 	path: '/*',
	// 	name: 'err',
	// 	component: () => import("../views/err/index.vue")
	// }
]

//配置路由规则
const router = new VueRouter({
	// history 底层切换组件的方式是使用的H5的window.history的技术,当地址栏的history状态发生变化时 切换了router-view渲染的组件 来"欺骗"用户 到达切换新网页的效果
	//hash底层切换组件的方式是使用的是老技术Hash值,当地址栏的hash变化时 切换了router-view渲染的组件 来"欺骗"用户 到达切换新网页的效果,hash值是不会发送给后端的
	mode: "hash", //'history',
	routes
})
// console.log(router)
//addRoutes已经废弃了
// router.addRoutes([{
// 	path: '/car',
// 	name: 'car',
// 	component: () => import("../views/car/index.vue")
// }])
//动态注册(添加)路由:
router.addRoute({
	path: '/car2',
	name: 'car2',
	component: () => import("../views/car/index.vue")
})
router.addRoute({
	path: '/car3',
	name: 'car3',
	component: () => import("../views/car/index.vue")
})
export default router

home下的index.vue

<template>
	<div>
		<h1>home页面</h1>
		<button @click="addro">添加新路由</button>  <br>
		<router-link to="/car">car</router-link><br>
		<router-link to="/home/car">/home/car</router-link><br>
		<router-view></router-view><br>
	</div>
</template>
<script>
	export default {
		methods: {
			addro() {
				console.log(123445)
				//
				this.$router.addRoute({
					path: "/car",
					component: () => import("../car/index.vue")
				})
			}
		}
	}
</script>
<style>
</style>

猜你喜欢

转载自blog.csdn.net/qq_52301431/article/details/126772899