Vue——路由(面试、引入、router-view和router-link标签、动态路由&传参、路由嵌套--子路由跳转、路由模式--hash&history、VueRouter router ro)
注册路由时,路由路径不要在前面加 斜杠跳转路由时 1.path里写的路径必须前面加斜杠 从根路由路径开始写 2.不用path 直接使用name。
目录
路由
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>标签,就会去匹配路由
1、
router-link:相当于a标签,给我们提供跳转到某个路由的功能,如果没有匹配到路由就会跳转失败:
<router-link to="/login"> xx<router-link >
<router-link to="{path:'/login'}"> xx<router-link >
2、
编程式跳转(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 // 接受获取数据,如果没有传参 这个值就没有
4.3vue3.0中跳转传参: state
和React中的state参数类似
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.路由守卫guard/导航钩子
vue操作的是app那个div,并没有操作body标签
8.1全局守卫
router下的index.js里面的全局里==>和const router =new VueRouter({})同级
全局前置钩子router.beforeEach( fn (to,from,next) ),导航被触发----一般登录验证
无论进入哪一个路由(只要每匹配一次路由),都要先调用这个函数
to、from 路由信息对象,next()去匹配路由,然后加载组件
next() 去渲染组件,一定要以next() 结尾,否则会造成死循环
全局解析钩子router.beforeResolve(fn),组件初始化,路由匹配成功
全局后置钩子router.afterEach(fn),没有next,导航被确认,它可以解决很多问题:
比如:一般路由跳转以后用window.scroollTo把窗口调上去
当在A组件中划到了一定长度,然后跳转到B组件的页面,这个时候,B组件的滚动条也在A页面的位置,就可以使用它来写(window.scroollTo(0,0))让B组件回到顶部
//全局前置守卫
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路由独享的守卫
写在router下的index.js里面的path,name、component的后面
路由独享的守卫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()
}
}
}]
8.3 组件内部生命周期守卫
写在组件里,比如login/index.vue里与methods同级
beforeRouteLeave 从该组件离开,可以进行缓存用户的选择,视频的暂停等
beforeRouteEnter(to,from,next),组件被激活,路由已经跳过去了,使用不了this,故构造指定该next 可以接收一个回调函数接收当前vm 实例----路由传参获取参数,得到初始化数据
beforeRouteUpdate(to,from,next),组件重用时被调用----路由传参获取参数,避免增添watch 开销
导航守卫执行顺序:
beforeRouteLeave < beforeEach < beforeRouteUpdate < beforeEnter < beforeRouteEnter < beforeResolve < afterEach
出发路由,预备从当前组件离开,判断路由变化,判断组件是否重用,判断新路由初始化,判断组件初始化,路由与组件初始化完毕,路由组件重定向完毕
路由守卫和vue的8个钩子函数的执行顺序:
1、缓冲页面(keep-alive:true)
初次进入页面
beforeRouteEnter(next()外) → beforeCreate → created → beforeMount → beforeRouteEnter( next()内 ) → mounted → activated → (离开页面时): beforeRouteLeave → deactivated
再次进入页面
beforeRouteEnter( next()外 ) → beforeRouteEnter( next()内 ) → activated
2、未缓存页面beforeRouteEnter(next()外) → beforeCreate → created → beforeMount → beforeRouteEnter( next()内 ) → mounted → beforeRouteLeave → (离开页面时): beforeRouteLeave → beforeDestroy → destroyed
//引入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、动态添加(注册)路由
一般是架构师在设计使用
以前是 addRoutes,现在变为了addRoute,没有了s
添加一条新的路由记录作为现有路由的子路由。
如果路由有一个name,并且已经有一个与之名字相同的路由,它会先删之前的路由。
addRoute(parentName:string|symbol,route:RouteRecordRaw):()=>void (案例未写)
addRoute(route:RouteRecordRaw):()=>void
一般用于数据处理后进行动态的添加/注册路由
比如:当输入账号的密码之后,进行判断,去动态的添加路由,是用户界面还是管理页面,这样这个账号才可以跳转相应的页面
// addRoute(route:RouteRecordRaw):()=>void 的 两种方式:
//1、在router下的index.js中
router.addRoute({ //动态注册(添加)路由:
path: '/car2',
name: 'car2',
component: () => import("../views/car/index.vue")
})
//2、在mehtods中
methods: {
addro() {
console.log(123445)
//
this.$router.addRoute({
path: "/car",
component: () => import("../car/index.vue")
})
}
}
案例:
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>
//要上面的添加路由的函数addro 执行了,这里才能跳转到/home/car,不然就会到err页面
<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>
更多推荐
所有评论(0)