VueRouter和Vue生命周期(钩子函数)
一、vue-router路由
1、介绍
vue-router是Vue的路由系统,用于定位资源的,在页面不刷新的情况下切换页面内容。
类似于a标签,实际上在页面上展示出来的也是a标签,是锚点。
router需要相应的js文件,可到官网下载或者使用CDN: https://unpkg.com/vue-router/dist/vue-router.js
使用Vue需要引入相应的JS文件,可到官网下载或者直接使用CDN:https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js
2、路由注册
1. 定义一个路由匹配规则和路由对应组件的对象
let url = [
{
path: "/", // 路由
component: { // 组件:component单数时,代表这个组件就是这个url的唯一组件,因此不需要写组件名
}
}
]
2. 实例化VueRouter对象 并把匹配规则注册进去
let my_router = new VueRouter({
routes: url,
// 路由去掉#
mode: 'history'
})
3. 把VueRouter实例化对象注册Vue的根实例
const app = new Vue({
el: "#app",
router: my_router
})
4. router-link
把匹配规则转成a标签
5. router-view
路由的组件显示的区域
6. demo

<body> <div id="app"> <router-link to="/">首页</router-link> <router-link to="/class">班级</router-link> <router-view></router-view> </div> <script> // 定义路由匹配规则和路由对应的组件对象 let url = [ { path: "/", component: {// component单数时,代表这个组件就是这个url的唯一组件,因此不需要写组件名,直接写配置信息即可 template: `<div><h1>你好!这是首页</h1></div>` } }, { path: "/class", component: { template: `<div><h1>这是班级信息</h1></div>` } } ]; // 实例化VueRouter对象,并把url注册进去 let my_router = new VueRouter({ routes: url, // 路由去掉# mode: 'history' }); // 把VueRouter实例对象注册到Vue的根实例里 const app = new Vue({ el: "#app", router: my_router }) </script> </body>
3、命名路由及参数
1. 注意:要使用命名路由,那么命名路由的router-link里to一定要v-bind,可以简写 :to
2. Vue的路由中,路由命名相当于python的路由别名,用name命名
3. 如果路由中需要在路由中加参数,则使用params
4. 如果在路由后面添加?搜索参数,则使用query
5. 要使用这些参数,则用this.$route,route是路由的所有信息
6. $route的参数
fullPath: "/student/ming?age=38" # 包含?参数的路径
hash: ""
matched: [{…}] # 路由匹配的正则
meta: {} # 元信息
name: "student" # 路由别名
params: {sname: "ming"} # 路由参数
path: "/student/ming" # 不含?参数的路径
query: {age: 38} # ?参数
__proto__: Object
7. demo

<body> <div id="app"> <router-link v-bind:to="{name: 'home'}">首页</router-link> <router-link to="/class?class_id=1">班级</router-link> <!--<router-link :to="{name: 'class', query: {class_id: 1}}">班级</router-link>--> <!--<router-link to="/student/ming?age=38">用户</router-link>--> <router-link :to="{name: 'student', params: {sname: 'ming'}, query: {age: 38}}">学生</router-link> <router-view></router-view> </div> <script> let url = [ { path: '/', name: 'home', component: { template: `<div><h1>你好!这是首页</h1></div>` } }, { path: '/class', name: 'class', component: { template: `<div><h1>这是{{this.$route.query.class_id}}班</h1></div>` } }, { // 在路由中添加参数使用 :name path: '/student/:sname', name: 'student', component: { template: `<div> <h1>这是{{this.$route.params.sname}}年龄是{{this.$route.query.age}}</h1> </div>`, mounted(){ console.log(this.$route) } } } ]; // 实例化VueRouter对象 let my_router = new VueRouter({ routes: url, mode: 'history' }); // 把VueRouter实例注册到Vue根实例 const app = new Vue({ el: "#app", router: my_router, }) </script> </body>
4、手动路由
1. 注意:$route是路由的所有信息,而$router是VueRouter实例化对象
2. $router.push 把这个router对象跳转到哪里
3. 手动路由的两种写法
this.$router.push("/login")
this.$router.push({name:'login', params:{},query: {}})
4. demo

<body> <div id="app"> <router-link to="/">首页</router-link> <router-link to="/class">班级</router-link> <router-link :to="{name:'login'}">登录</router-link> <router-view></router-view> </div> <script> // 定义路由匹配规则和路由对应的组件对象 let url = [ { path: "/", component: { template: `<div> <h1>你好!这是首页</h1> <button v-on:click="my_click">点击跳转到登录页面</button> </div>`, methods: { my_click: function () { // $route 路由的所有信息 // $router VueRouter实例化对象 console.log(this.$route); console.log(this.$router); // push跳转到登录页面 // this.$router.push("/login") this.$router.push({name: "login"}) } } } }, { path: "/class", component: { template: `<div><h1>这是班级信息</h1></div>` } }, { path: "/login", name: "login", component: { template: `<div><h1>这是登录页面</h1></div>` } } ]; // 实例化VueRouter对象,并把url注册进去 let my_router = new VueRouter({ routes: url, // 路由去掉# mode: 'history' }); // 把VueRouter实例对象注册到Vue的根实例里 const app = new Vue({ el: "#app", router: my_router }) </script> </body>
5、路由的钩子函数
1. 路由钩子函数:一个路由跳转到另一个路由(还没到)的过程中触发 beforeEach(function (to, from, next) {})
2. 路由钩子函数:一个路由已经跳转到了另一个路由后触发 afterEach(function (to, from) {})
3. 参数:
to 你要去哪里
from 你从哪里来
next 你接下来要做什么
4. next的参数详解
next(function) 一定要调用这个方法来resolve这个钩子函数。执行效果依赖next方法的调用参数
next() 什么都不做继续执行到调转的路由
next(false) 中断当前导航 没有跳转 也没有反应
next("/") 参数是路径 调转到该路径
next(error) 如果next参数是一个Error实例 导航终止该错误,会传递给router.onError()注册过的回调中
5. demo

<body> <div id="app"> <router-link to="/">首页</router-link> <router-link :to="{name: 'class', query: {class_id: 1}}">班级</router-link> <router-link :to="{name: 'user'}">用户</router-link> <router-link to="/login">登录</router-link> <router-view></router-view> </div> <script> let url = [ { path: '/', component: { template: `<div> <h1>你好!这是首页</h1> <button @click="my_click">点击跳转到登录页面</button> </div>`, methods: { my_click: function () { this.$router.push("/login") } } } }, { path: '/class', name: 'class', component: { template: `<div><h1>这是{{this.$route.query.class_id}}班的信息</h1></div>` } }, { path: '/login', name: 'login', component: { template: `<div> <h1>这是登录页面</h1> </div>` } }, { path: '/user', name: 'user', meta: { // 设置元信息 required_login: true }, component: { template: `<div><h1>这是用户组件</h1></div>` } } ]; // 实例化VueRouter对象 let my_router = new VueRouter({ routes: url, mode: 'history' }); // 路由my_router的钩子函数:一个路由跳转到另一个路由(还没到)的过程中触发 my_router.beforeEach(function (to, from, next) { console.log(to); // 你要去哪里 console.log(from); // 你从哪里来 console.log(next); // 你接下来要做什么 if(to.meta.required_login){ next('/login') }else{ next(); } }); // 路由my_router的钩子函数:一个路由已经跳转到了另一个路由后触发 my_router.afterEach(function (to, from) { // 一般只用于获取你从哪里来的路由信息 console.log(to); // 你要去哪里 console.log(from); // 你从哪里来 }); // 把VueRouter实例注册到Vue根实例 const app = new Vue({ el: "#app", router: my_router, }) </script> </body>
6、子路由的注册
1. 在父路由里注册children: [{},{}]
2. 在父路由对应的组件里的template里写router-link router-view
3. redirect:重定向到某个页面
4. 子路由的path不写"/"前缀,则会自动跟父级路由拼接
5. 如果写了"/"前缀,那么path就是你写的路径
6. 点击子路由连接,会触发其父路由,子路由的template只会显示在父路由的template里面
7. 子路由可以直接在Vue作用域使用,但还是会触发它的父路由的template
8. demo

<body> <div id="app"> <router-link to="/">首页</router-link> <router-link to="/class">班级</router-link> <router-link to="/class/info">班级信息</router-link> <router-link :to="{name: 'grade'}">年级</router-link> <router-view></router-view> </div> <script> let url = [ { path: '/', component: { template: `<div><h1>你好!这是首页</h1></div>` } }, { path: '/class', component: { template: `<div><h1>这是班级</h1></div>` } }, { path: '/class/info', // 路由重定向redirect,进入/class/info,就会重定向到/class/info/grade // redirect: {name: 'grade'}, component: { template: `<div> <h1>这是班级详细信息</h1> <hr> <router-link :to="{name: 'grade'}">所在年级</router-link> <router-link to="/class/class_id">所在班级</router-link> <router-view></router-view> </div>`, }, children: [ { // 没写前缀会直接拼接在父级路由后 path: /class/info/grade path: "grade", // 路由别名 name: 'grade', component: { template: `<div><h2>一年级</h2></div>` } }, { // 自己直接写路由,不会拼接在父级路由后 path: "/class/class_id", component: { template: `<div><h2>3班</h2></div>` } } ], }, ]; // 实例化VueRouter对象 let my_router = new VueRouter({ routes: url, mode: 'history' }); // 把VueRouter实例注册到Vue根实例 const app = new Vue({ el: "#app", router: my_router, }) </script> </body>
7、命名路由视图
1. 当我们只有一个<router-view></router-view>的时候,所有内容都展示在这一个面板里面。
如果是content和footer需要同时显示在不同区域,这就需要对视图进行命名。
2. 路由中使用components(是复数),{组件名1: 配置信息1, 组件名2: 配置信息2}
3. 在HTML视图中使用<router-view name="header"></router-view>区分不同的组件
4.也就是说路由的组件:
component(单数)用<router-view></router-view>标签
components(复数)用<router-view name="组件名"></router-view>标签
5. demo

<body> <div id="app"> <router-link to="/">首页</router-link> <router-link to="/class">班级</router-link> <router-link to="/class/info">班级信息</router-link> <router-view name="header"></router-view> <router-view name="footer" style="position: fixed;bottom: 0"></router-view> <router-view></router-view> </div> <script> let url = [ { path: '/', component: { template: `<div><h1>你好!这是首页</h1></div>` } }, { path: '/class', component: { template: `<div><h1>这是班级</h1></div>` } }, { path: '/class/info', // components 复数 有多个组件,要写组件名 components: { header: { template: `<div><h1>这是班级头</h1></div>` }, footer: { template: `<div><h1>这是班级尾</h1></div>` } }, }, ]; // 实例化VueRouter对象 let my_router = new VueRouter({ routes: url, mode: 'history' }); // 把VueRouter实例注册到Vue根实例 const app = new Vue({ el: "#app", router: my_router, }) </script> </body>
8、路由mode模式
vue-router 默认 hash 模式,还有一种是history模式。 hash: 1.url地址中带有# 2.不能随意的修改path地址 hash模式的工作原理是hashchange事件,可以在window监听hash的变化。我们在url后面随便添加一个#xx会触发这个事件。 比如请求:www.abcde.com/VueHistory/index.html# 我们修改为:www.abcde.com/VueHistory/index.html#red 或者:www.abcde.com/VueHistory/index.html#green 那么会触发: window.onhashchange = function(event) { let hashVal = window.location.hash.slice(1); // z这里可以根据这个hash值,即#后面的值进行一些操作,比如切换某个元素的颜色 $("#test").css("background-colro", hashVal); } 尽管浏览器没有请求服务器,但是页面状态和url已经关联起来了,这就是所谓的前端路由,单页应用的标配 3.在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。 history: 1.提供了切换历史状态的方法 // 原页面表单中的内容会丢失 history.go(-1);// 后退 + 刷新 history.go(0):刷新 history.go(2);// 前进两次 // 原页面表单中的内容会保留 history.back(); // 后退 history.back(0):刷新 history.back(1):前进 hsitory.forward(); // 前进 2.可以随意修改path地址 例如把: http://hello.com/zzz/id 修改为: http://xxxhello.com/zzz/id 3.页面刷新则需要重新请求接口 需要后台配置支持 如果后台没有正确的配置,有可能进入404 4.使用方法 template的html代码中: <a @click="$router.back()">返回上一页</a> vue实例方法中使用:reset() { this.$router.go(0);// 刷新页面 } 总结: 在hash模式下,前端路由修改的是#中的信息,而浏览器请求时是不携带它的,所以没有问题。 但是在history下,你可以自由的修改path,当刷新时,如果服务器中没有相应的响应或者资源,可能出现404。
二、Vue的生命周期及其钩子函数
1、图示
对比
2、demo
beforeCreate 啥也没有
created 有数据和事件(方法)、无el
beforeMount 形成虚拟Dom,有el、数据和事件(方法)
mounted 渲染页面了,有el、数据和事件(方法)
beforeUpdate 数据改变前触发
updated 数据改变后触发
beforeDestroy vue实例销毁前触发
destroyed vue实例销毁时触发

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script> </head> <body> <div id="app"> {{name}} <button @click="my_update">点击触发update</button> <button @click="my_destroy">点击触发destroy</button> </div> <script> const app = new Vue({ el: "#app", data: { name: "明哥" }, methods: { init: function () { console.log(123) }, my_update: function () { this.name = "狗子" }, my_destroy: function () { app.$destroy() } }, beforeCreate(){ console.group("BeforeCreate"); console.log(this.$el); console.log(this.name); console.log(this.init); }, created(){ console.group("Create"); console.log(this.$el); console.log(this.name); console.log(this.init); }, beforeMount(){ console.group("BeforeMount"); console.log(this.$el); console.log(this.name); console.log(this.init); }, mounted(){ console.group("mounted"); console.log(this.$el); console.log(this.name); console.log(this.init); }, beforeUpdate(){ console.group("BeforeUpdate"); console.log(this.$el); console.log(this.name); console.log(this.init); }, updated(){ console.group("updated"); console.log(this.$el); console.log(this.name); console.log(this.init); }, beforeDestroy(){ console.group("BeforeDestroy"); console.log(this.$el); console.log(this.name); console.log(this.init); }, destroyed(){ console.group("Destroy"); console.log(this.$el); console.log(this.name); console.log(this.init); } }) </script> </body> </html>
3、create 和 mounted 相关
执行上面代码,可以看到:
beforecreated :el 和 data 并未初始化
created:完成了data数据的初始化 el 没有
beforeMount:完成了el 和 data的初始化
mounted:完成了挂载
也就是说,挂载前的状态是虚拟DOM技术,先把坑站住了,挂载之后才真正的把值渲染进去
4、update 相关
我们修改了app的data的某个值时,
我们就触发了update相关的钩子函数,也就是说data里的值被修改会触发update的操作
5、destroy 相关
我们在浏览器console里执行命令:
app.$destroy();
触发了destroy相关的钩子函数,也就是说组件被销毁
更改message的值,DOM中的值不变,也就是说DOM元素依然存在只是不受vue控制了
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix