VueRoute 知识点
文章目录
1. 路由简介
前端路由
- 根据不同的用户事件渲染不同的页面
后端路由
- 根据不同的请求url分发不同的服务器资源
单页面spa
- 基于url的hash变化
2. VueRouter的基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div class="" id="app">
<router-link to="/user">
User页面
</router-link>
<router-link to="/home">Home</router-link>
<router-view>
</router-view>
</div>
<script src="./lib/vue-2.6.12.js"></script>
<script src="./lib/vue-router.min.js"></script>
<script>
const User = {
template: '<div>User页面</div>'
}
const Home = {
template: '<div>Home页面</div>'
}
const router = new VueRouter({
routes: [
{ path: '/user', component: User },
{ path: '/home', component: Home }
]
})
const vm = new Vue({
el: '#app',
data: {
},
router
})
</script>
</body>
</html>
路由重定向
const router = new VueRouter({
routes: [
{path:'/',redirect:'/home'}
{ path: '/user', component: User },
{ path: '/home', component: Home }
]
})
路由嵌套
const router = new VueRouter({
routes: [
{path:'/',redirect:'/home'}
{ path: '/user', component: User,
children:[
{path:'tab1',component:Tab1},
{path:'tab2',component:Tab2}
]
},
{ path: '/home', component: Home }
]
})
- User组件
const User={
template:'<div>
<router-link>tab1</router-link>
<router-link>tab2</router-link>
<router-view></router-view>
</div>'
}
动态路由
const router = new VueRouter({
routes: [
{path:'/',redirect:'/home'}
// 动态路由,允许传递参数
{ path: '/user/:id', component: User,props:true
children:[
{path:'tab1',component:Tab1},
{path:'tab2',component:Tab2}
]
},
{ path: '/home', component: Home }
]
})
- 获取路由参数
const User={
template: '<h1>User 组件 -- 用户id为: {{$route.params.id}}</h1>'
}
// 或者props
const User={
props:['id']
}
传递对象时路由参数
const router = new VueRouter({
routes: [
{path:'/',redirect:'/home'}
// 动态路由,允许传递参数
// 值为对象,结构赋值
{ path: '/user/:id', component: User,props: { uname: 'lisi', age: 12 }}
children:[
{path:'tab1',component:Tab1},
{path:'tab2',component:Tab2}
]
},
{ path: '/home', component: Home }
]
})
传递的值为函数的类型
const router = new VueRouter({
routes: [
// 如果 props 是一个函数,则这个函数接收 route 对象为自己的形参
//route就是参数对象。
{ path: '/user/:id',
component: User,
props: route => ({ uname: 'zs', age: 20, id: route.params.id })}
]
})
const User = {
props: ['uname', 'age', 'id'],
template: ‘<div>用户信息:{{ uname + '---' + age + '---' + id}}</div>'
}
命名路由
const router = new VueRouter({
routes: [
{ path: '/user/:id',
//路由命名
name:'user',
component: User,
props: route => ({ uname: 'zs', age: 20, id: route.params.id })}
]
})
- 模板使用
const user={
template:'<div>
<router-link :to="{name:'user',params:{}}"></router-link>
</div>'
}
编程式导航
// 字符串(路径名称)
router.push('/home')
// 对象
router.push({ path: '/home' })
// 命名的路由(传递参数)
router.push({ name: '/user', params: { userId: 123 }})
// 带查询参数,变成 /register?uname=lisi
router.push({ path: '/register', query: { uname: 'lisi' }})
路由守卫
- 全局路由守卫
const router = new VueRouter({
routes: [
{ path: '/user/:id',
//路由命名
name:'user',
// 添加元数据,表名改路由是需要权限的
meta:{
auth:true
}
component: User,
props: route => ({ uname: 'zs', age: 20, id: route.params.id })}
]
})
router.beforeEach((to,from,next)=>{
if(to.meta.auth){
// 有权限路由
if(localStorage.getItem('token')){
next()
}else{
// 重定向到登录页面
// 登录成功后回跳
next("/login?redirect="+to.fullPath)
}
}else{
next()
}
})
const login(){
methods:{
login(){
localstorage.setItem('token')
this.$router.push(this.$router.query.redirect)
}
}
}
- 路由独享守卫
const router = new VueRouter({
routes: [
{ path: '/user/:id',
//路由命名
name:'user',
// 添加元数据,表名改路由是需要权限的
meta:{
auth:true
},
// 守卫写在路由配置里
beforeEnter(to,from,next){
// 有权限路由
if(localStorage.getItem('token')){
next()
}else{
// 重定向到登录页面
// 登录成功后回跳
next("/login?redirect="+to.fullPath)
}
}
component: User,
props: route => ({ uname: 'zs', age: 20, id: route.params.id })}
]
})
- 配置项
beforeRouteEnter
beforeRouteUpdate
beforeRouteLeave
- 组件内路由守卫
const User={
beforeRouteEnter(to, from, next) {
if (window.isLogin) {
next();
} else {
next("/login?redirect=" + to.fullPath);
}
},
}
3. addRoutes 动态路由添加
- 静态路由配置式
- 动态路由在用户登录时按需添加,添加的都是当前用户可以访问的
const router=new VueRouter({
routes:[
// 只配置登录的静态路由
{path:'/logon',component:Login}
]
})
const Login={
methods:{
// login方法
login(){
localStorage.setItem("token",'xxx')
// 动态添加当前用户可以访问的路由
this.$router.addRoutes([
{path:'/',redirect:'/users'},
{path:'/user',component:User},
{path:'/home',component:Home},
])
// 登录成功后跳转到重定向的地方,或者直接跳转到/
if(this.$router.query.redirect){
this.$router.push(this.$router.query.redirect)
}else{
this.$router.push("/")
}
}
}
}
// 设置全局的路由守卫
router.beforeEach((to,from,next)=>{
// 判断用户是否登录
const token=localStorage.getItem("item")
if(token){
// 去登录页面
if(to.path==='/login'){
// 去登录页面
next("/")
}else{
next()
}
}else{
// 没有登录
if(to.if(to.path==='/login'){
// 去登录页面
next()
}else{
next("/login?redirect="+to.fullPath)
}path==='login'){
// 去登录页面
next()
}else{
next("/login?redirect="+to.fullPath)
}
}
})
4. 路由组件缓存
<keep-alive></keep-alive>
// 可添加的属性,include确定哪些组件需要缓存
// 属性值为组件的name属性
const Home={
name:'home',
...
}
<keep-alive include="home,user"></keep-alive>
// 可添加的属性,exclude除了这些组件其他组件需要缓存
<keep-alive include="login"></keep-alive>
- 钩子函数触发
- 页面属性,如果组件加了缓存:created—>mounted—>activited
13.2 History
模式的使用
History
模式需要服务器的支持,为什么呢?
因为在单页面的应用中,只有一个页面,也就是index.html
这个页面,服务端不存在http://www.test.com/login
这样的地址,也就说如果刷新浏览器,
请求服务器,是找不到/login
这个页面的,所以会出现404
的错误。(在传统的开发模式下,输入以上的地址,会返回login
这个页面,而在单页面应用中,只有一个页面为index.html
)
所以说,在服务端应该除了静态资源外都返回单页应用的index.html
下面我们开始history
模式来演示一下对应的问题。
首先添加一个针对404组件的处理
首先在菜单栏中添加一个链接:
<!-- 左侧菜单栏 -->
<div class="content left">
<ul>
<li><router-link to="/users"> 用户管理</router-link></li>
<li><router-link to="/rights"> 权限管理</router-link></li>
<li><router-link to="/goods"> 商品管理</router-link></li>
<li><router-link to="/orders"> 订单管理</router-link></li>
<li><router-link to="/settings"> 系统设置</router-link></li>
<li><router-link to="/about"> 关于</router-link></li>
</ul>
</div>
这里我们添加了一个“关于”的链接,但是我们没有为其定义相应的组件,所以这里需要处理404的情况。
const NotFound = {
template: `<div>
你访问的页面不存在!!
</div>`,
};
在程序中添加了一个针对404的组件。
const router = new VueRouter({
mode: "history",
const router = new VueRouter({
mode: "history",
routes: [
{ path: "/login", component: Login },
{ path: "*", component: NotFound },
{
path: "/",
component: App,
redirect: "/users",
children: [
{
path: "/users",
component: Users,
meta: {
auth: true,
},
// beforeEnter(to, from, next) {
// if (window.isLogin) {
// next();
// } else {
// next("/login?redirect=" + to.fullPath);
// }
// },
},
{ path: "/userinfo/:id", component: UserInfo, props: true },
{ path: "/rights", component: Rights },
{ path: "/goods", component: Goods },
{ path: "/orders", component: Orders },
{ path: "/settings", component: Settings },
],
},
],
});
在上面的代码中,指定了处理404的路由规则,同时将路由的模式修改成了history
模式。同时,启用这里启用了其它的组件的路由规则配置,也就是不在login
方法中使用addRoutes
方法来动态添加路由规则了。
login
方法修改成如下形式:
login() {
// window.isLogin = true;
window.sessionStorage.setItem("isLogin", true);
if (this.$route.query.redirect) {
// //动态添加路由:
// this.$router.addRoutes([
// {
// path: "/",
// component: App,
// redirect: "/users",
// children: [
// {
// path: "/users",
// component: Users,
// meta: {
// auth: true,
// },
// // beforeEnter(to, from, next) {
// // if (window.isLogin) {
// // next();
// // } else {
// // next("/login?redirect=" + to.fullPath);
// // }
// // },
// },
// { path: "/userinfo/:id", component: UserInfo, props: true },
// { path: "/rights", component: Rights },
// { path: "/goods", component: Goods },
// { path: "/orders", component: Orders },
// { path: "/settings", component: Settings },
// ],
// },
// ]);
this.$router.push(this.$route.query.redirect);
} else {
this.$router.push("/");
}
}
现在已经将前端vue
中的代码修改完毕了,下面我们要将页面的内容部署到node.js
服务器中。
而且上面的代码中,我们使用了sessionStorage
来保存登录用户的信息,不在使用window
下的isLogin
对应的data
内容下的代码也要修改:
const Login = {
data() {
return {
isLogin: window.sessionStorage.getItem("isLogin"),
};
},
路由守卫中的代码进行如下修改:
jsrouter.beforeEach((to, from, next) => {
//to:去哪个页面,from来自哪个页面,next继续执行.
if (window.sessionStorage.getItem("isLogin")) {
//用户已经登录
if (to.path === "/login") {
// 用户已经登录了,但是又访问登录页面,这里直接跳转到用户列表页面
next("/");
} else {
//用户已经登录,并且访问其它页面,则运行访问
next();
}
} else {
//用户没有登录,并且访问的就是登录页,则运行访问登录页
if (to.path === "/login") {
next();
} else {
//用户没有登录,访问其它页面,则跳转到登录页面。
next("/login?redirect=" + to.fullPath);
}
}
});
在上面的代码中,我们也是通过sessionStorage
来获取登录信息。
index.html
完整代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>基于vue-router的案例</title>
<script src="./lib/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
</head>
<body>
<div id="app"><router-view></router-view></div>
<script>
const App = {
template: `<div>
<!-- 头部区域 -->
<header class="header">传智后台管理系统</header>
<!-- 中间主体区域 -->
<div class="main">
<!-- 左侧菜单栏 -->
<div class="content left">
<ul>
<li><router-link to="/users"> 用户管理</router-link></li>
<li><router-link to="/rights"> 权限管理</router-link></li>
<li><router-link to="/goods"> 商品管理</router-link></li>
<li><router-link to="/orders"> 订单管理</router-link></li>
<li><router-link to="/settings"> 系统设置</router-link></li>
<li><router-link to="/about"> 关于</router-link></li>
</ul>
</div>
<!-- 右侧内容区域 -->
<div class="content right"><div class="main-content">
<keep-alive include='goods'>
<router-view />
</keep-alive>
</div></div>
</div>
<!-- 尾部区域 -->
<footer class="footer">版权信息</footer>
</div>`,
};
const Users = {
data() {
return {
userlist: [
{ id: 1, name: "张三", age: 10 },
{ id: 2, name: "李四", age: 20 },
{ id: 3, name: "王五", age: 30 },
{ id: 4, name: "赵六", age: 40 },
],
};
},
methods: {
goDetail(id) {
console.log(id);
this.$router.push("/userinfo/" + id);
},
},
template: `<div>
<h3>用户管理区域</h3>
<table>
<thead>
<tr><th>编号</th><th>姓名</th><th>年龄</th><th>操作</th></tr>
</thead>
<tbody>
<tr v-for="item in userlist" :key="item.id">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.age}}</td>
<td>
<a href="javascript:;" @click="goDetail(item.id)">详情</a>
</td>
</tr>
</tbody>
</table>
</div>`,
// beforeRouteEnter(to, from, next) {
// if (window.isLogin) {
// next();
// } else {
// next("/login?redirect=" + to.fullPath);
// }
// },
};
//用户详情组件
const UserInfo = {
props: ["id"],
template: `<div>
<h5>用户详情页 --- 用户Id为:{{id}}</h5>
<button @click="goback()">后退</button>
</div>`,
methods: {
goback() {
// 实现后退功能
this.$router.go(-1);
},
},
};
const Rights = {
template: `<div>
<h3>权限管理区域</h3>
</div>`,
};
const Goods = {
name: "goods",
template: `<div>
<h3>商品管理区域</h3>
</div>`,
created() {
console.log(new Date());
},
};
const Orders = {
template: `<div>
<h3>订单管理区域</h3>
</div>`,
};
const Settings = {
template: `<div>
<h3>系统设置区域</h3>
</div>`,
};
const NotFound = {
template: `<div>
你访问的页面不存在!!
</div>`,
};
const Login = {
data() {
return {
isLogin: window.sessionStorage.getItem("isLogin"),
};
},
template: `<div>
<button @click="login" v-if="!isLogin">登录</button>
<button @click="logout" v-else>注销</button>
</div>`,
methods: {
login() {
// window.isLogin = true;
window.sessionStorage.setItem("isLogin", true);
if (this.$route.query.redirect) {
// //动态添加路由:
// this.$router.addRoutes([
// {
// path: "/",
// component: App,
// redirect: "/users",
// children: [
// {
// path: "/users",
// component: Users,
// meta: {
// auth: true,
// },
// // beforeEnter(to, from, next) {
// // if (window.isLogin) {
// // next();
// // } else {
// // next("/login?redirect=" + to.fullPath);
// // }
// // },
// },
// { path: "/userinfo/:id", component: UserInfo, props: true },
// { path: "/rights", component: Rights },
// { path: "/goods", component: Goods },
// { path: "/orders", component: Orders },
// { path: "/settings", component: Settings },
// ],
// },
// ]);
this.$router.push(this.$route.query.redirect);
} else {
this.$router.push("/");
}
},
logout() {
this.isLogin = window.isLogin = false;
},
},
};
// 创建路由对象
const router = new VueRouter({
mode: "history",
routes: [
{ path: "/login", component: Login },
{ path: "*", component: NotFound },
{
path: "/",
component: App,
redirect: "/users",
children: [
{
path: "/users",
component: Users,
meta: {
auth: true,
},
// beforeEnter(to, from, next) {
// if (window.isLogin) {
// next();
// } else {
// next("/login?redirect=" + to.fullPath);
// }
// },
},
{ path: "/userinfo/:id", component: UserInfo, props: true },
{ path: "/rights", component: Rights },
{ path: "/goods", component: Goods },
{ path: "/orders", component: Orders },
{ path: "/settings", component: Settings },
],
},
],
});
//实现全局守卫
// router.beforeEach((to, from, next) => {
// //to:去哪个页面,from来自哪个页面,next继续执行.
// //判断哪个路由需要进行守卫,这里可以通过元数据方式
// if (to.meta.auth) {
// if (window.isLogin) {
// next();
// } else {
// next("/login?redirect=" + to.fullPath);
// }
// } else {
// next();
// }
// });
router.beforeEach((to, from, next) => {
//to:去哪个页面,from来自哪个页面,next继续执行.
if (window.sessionStorage.getItem("isLogin")) {
//用户已经登录
if (to.path === "/login") {
// 用户已经登录了,但是又访问登录页面,这里直接跳转到用户列表页面
next("/");
} else {
//用户已经登录,并且访问其它页面,则运行访问
next();
}
} else {
//用户没有登录,并且访问的就是登录页,则运行访问登录页
if (to.path === "/login") {
next();
} else {
//用户没有登录,访问其它页面,则跳转到登录页面。
next("/login?redirect=" + to.fullPath);
}
}
});
const vm = new Vue({
el: "#app",
router,
});
</script>
</body>
</html>
当然,项目的目录结构做了一定的调整,如下图所示:
在web
目录下面,存放的是index.html
,在webserver
目录下面存放的是node
代码。
下面看一下具体的node
代码的实现。
app.js文件中的代码如下:
const path = require("path");
//导入处理history模式的模块
const history = require("connect-history-api-fallback");
const express = require("express");
const app = express();
//注册处理history模式的中间件
// app.use(history())
//处理静态资源的中间件,处理web目录下的index.html
app.use(express.static(path.join(__dirname, "../web")));
app.listen(3000, () => {
console.log("服务器开启");
});
connect-history-api-fallback
模块的安装如下(注意在上面的代码中还没有使用该模块)
npm install --save connect-history-api-fallback
下面还需要安装express
npm install express
启动服务
node app.js
现在在地址栏中输入:http://localhost:3000
就可以访问网站了。
并且当我们去单击左侧的菜单的时候,可以实现页面的切换,同时单击“关于”的时候,会出现NotFound
组件中的内容。
经过测试发现好像没有什么问题,那这是什么原因呢?你想一下当我们单击左侧菜单的时候,路由是怎样工作的呢?
因为现在我们开启了路由的history
模式,而该模式是通过HTML5
中的history
中的api
来完成路由的操作的,也就是当我们单击菜单的时候,是通过history.pushState( )
方法来修改地址栏中的地址,实现组件的切换,而且还会把地址保存的历史记录中(也就是可以单击浏览器中后退按钮,实现后退等操作),但是它并不会向服务器发送请求。
所以说现在整个操作都是在客户端完成的。
但是,当我刷新了浏览器以后,会出现怎样的情况呢?
上图的含义就是,当单击浏览器中的刷新按钮的时候,会向服务器发送请求,要求node
服务器处理这个地址,但是服务器并没有处理该地址,所以服务器会返回404
以上就是如果vue-router
开启了history
模式后,出现的问题。
下面解决这个问题,在服务端启用connect-history-api-fallback
模块就可以了,如下代码所示:
const path = require("path");
//导入处理history模式的模块
const history = require("connect-history-api-fallback");
const express = require("express");
const app = express();
//注册处理history模式的中间件
app.use(history());
//处理静态资源的中间件
app.use(express.static(path.join(__dirname, "../web")));
app.listen(3000, () => {
console.log("服务器开启");
});
服务端的代码做了修改以后,一定要服务端重新启动node app.js
然后经过测试以后发现没有问题了。
那么现在你考虑一下,具体的工作方式是什么?
当我们在服务端开启对history
模式的支持以后,我们刷新浏览器,会想服务器发送请求,例如:http://localhost:3000/orders
服务器接收该请求,那么用于服务器开启了history
模式,然后服务器会检查,根据该请求所访问的页面是不存在的,所以会将单页面应用的index.html
返回给浏览器。浏览器接收index.html
页面后,会判断路由地址,发现地址为orders
,所以会加载该地址对应的组件内容。
5. hash模式和history模式
- hash模式:
- URL#后面的内容作为路径地址,地址发生变化不会发起请求,但会触发hashchange事件
- 监听hashchange事件,根据路由地址找到新组件重新渲染
- history模式
- history.pushState()改变地址栏,不会发送请求
- 监听popstate事件,监听浏览器历史操作变化,记录改变后的地址,单击前进或者是后退按钮的时候触发该事件
- 根据当前路由地址找到对应组件渲染
6.nginx配置history模式
location / {
root html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
- 路由查找规则
- 单页面应用,查找路由,比如查找/user,会尝试查找user.html,查找不到,就会找到html页面下的index.html,这样就实现了history模式
7. Vue运行时版和完整版
- Vue-Cli创建的默认是运行时版本,不支持template模板
- 不支持下述代码
Vue.component("router-link",{
template:"<a><slot></slot></a>"
})
- 完整版具有编译器,可以识别
- vue.config.js中配置位置版
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
// 修改为完整版vue
runtimeCompiler: true
})
使用render函数解决template不识别的问题
Vue.component('router-link', {
props: {
to: String
},
methods: {
clickHandle (e) {
// 阻止默认行为
e.preventDefault()
// 因为是history模式,调用history.pushState
history.pushState({}, '', this.$props.to)
// data属性同步更新
self.data.current = this.$props.to
}
},
// template: '<a :href="to"><slot></slot></a>'
render (h) {
// 直接渲染a标签会导致点击时发送页面刷新
// 我们给a添加click的事件处理函数
return h(
'a',
{
attrs: {
href: this.$props.to
},
on: {
click: this.clickHandle
}
},
[this.$slots.default]
)
}
})
8. vue-router 手写版本1
// 实现vue-router的插件
// 我们先看看vue-router的基本使用
// import Vue from 'vue'
// import VueRouter from 'vue-router'
// Vue.use(VueRouter)
// const router = new VueRouter({
// routes: [
// { path: '/user', component: User },
// { path: '/home', component: Home }
// ]
// })
// new Vue({
// router,
// render: h => h(App)
// }).$mount('#app')
/*
自己实现一个vue-router
*/
// 定义成插件模式,实现install方法 ,使用 VueRouter.install(Vue)
let _Vue = null
export default class VueRouter {
// 1.判断插件是否已经安装过
// new Vue({
// router,
// render: h => h(App)
// }).$mount('#app')
// 当我们在new Vue 时,把router对象挂载上去
static install (Vue) {
// console.log(Vue)
if (VueRouter.install.installed) {
return
}
VueRouter.install.installed = true
// 2.将Vue实例保存到_Vue全局变量中
_Vue = Vue
// 3.没有安装过,挂载router对象到Vue的原型上
// 直接挂载不行,this指向为VueRouter,我们如果用call,this是Vue实例还没有被创建出来(生命周期)
// _Vue.prototype.$router=this.$options.router
_Vue.mixin({
// 这个生命周期是,vue实例已经创建完成
// this.$options===>{
// router,
// render: h => h(App)
// }
beforeCreate () {
// console.log(this.$options, 'options')
if (this.$options.router) {
// 这个就是传递进去的router,组件创建时时没有router这个选项的
_Vue.prototype.$router = this.$options.router
// 挂载成功后,进行路由解析和router-link创建,注意这里的this为vue实例
this.$options.router.init()
}
}
})
}
// 解析routes对象
createRouteMap () {
this.options.routes.forEach((route) => {
this.routeMap[route.path] = route.component
})
}
// 创建router-link组件
initComponents (Vue) {
const self = this
Vue.component('router-link', {
props: {
to: String
},
methods: {
clickHandle (e) {
// 阻止默认行为
e.preventDefault()
// 因为是history模式,调用history.pushState
history.pushState({}, '', this.$props.to)
// data属性同步更新
self.data.current = this.$props.to
}
},
// template: '<a :href="to"><slot></slot></a>'
render (h) {
// 直接渲染a标签会导致点击时发送页面刷新
// 我们给a添加click的事件处理函数
return h(
'a',
{
attrs: {
href: this.$props.to
},
on: {
click: this.clickHandle
}
},
[this.$slots.default]
)
}
})
// 创建Router-view组件
Vue.component('router-view', {
// template: '<a :href="to"><slot></slot></a>'
render (h) {
// console.log('router-view render')
// 根据routeMap获取对应的组件
// console.log(self.data.current)
// console.log(self.routeMap)
console.log(self)
const component = self.routeMap[self.data.current]
return h(component)
}
})
}
// 处理前进和后退按钮,当我们点击浏览器的前进后退按钮时,popstate事件会被触发
// 我们的数据,也就是this.data.current也需要同步更新
initEvents () {
window.addEventListener('popstate', () => {
// 使用箭头函数后,this指向不在是window,而是VueRouter实例
// 获取一下当前的路由路径
this.data.current = window.location.pathname
})
}
// 我们需要在new Vue() 当vue实例被创建之后指向解析routes对象和创建router-link组件
init () {
this.createRouteMap()
this.initComponents(_Vue)
this.initEvents()
}
// 构造函数
// const router = new VueRouter({
// routes: [
// { path: '/user', component: User },
// { path: '/home', component: Home }
// ]
// })
constructor (options) {
// 根据传入的选项进行路由规则解析
this.options = options
// 我们设置一个map,存储路由地址到组件的映射
this.routeMap = {}
// 设置当前路由的路由地址,响应式
this.data = _Vue.observable({
current: '/'
})
}
}
9. vue-router 版本2
', {
// template: '<a :href="to"><slot></slot></a>'
render (h) {
// console.log('router-view render')
// 根据routeMap获取对应的组件
// console.log(self.data.current)
// console.log(self.routeMap)
console.log(self)
const component = self.routeMap[self.data.current]
return h(component)
}
})
}
// 处理前进和后退按钮,当我们点击浏览器的前进后退按钮时,popstate事件会被触发
// 我们的数据,也就是this.data.current也需要同步更新
initEvents () {
window.addEventListener(‘popstate’, () => {
// 使用箭头函数后,this指向不在是window,而是VueRouter实例
// 获取一下当前的路由路径
this.data.current = window.location.pathname
})
}
// 我们需要在new Vue() 当vue实例被创建之后指向解析routes对象和创建router-link组件
init () {
this.createRouteMap()
this.initComponents(_Vue)
this.initEvents()
}
// 构造函数
// const router = new VueRouter({
// routes: [
// { path: ‘/user’, component: User },
// { path: ‘/home’, component: Home }
// ]
// })
constructor (options) {
// 根据传入的选项进行路由规则解析
this.options = options
// 我们设置一个map,存储路由地址到组件的映射
this.routeMap = {}
// 设置当前路由的路由地址,响应式
this.data = _Vue.observable({
current: '/'
})
}
}
### 9. vue-router 版本2
- 看文件夹下codes