前端路由vue-router介绍
一、前端路由vue-router介绍
Vue-Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于 Vue.js 过渡系统的视图过渡效果
- 细粒度的导航控制
- 带有自动激活的 CSS class 的链接
- HTML5 历史模式或 hash 模式,在 IE9 中自动降级
- 自定义的滚动条行为
vue + vue-router 主要是用来做 单页面应用(Single Page Application)。
1、为什么要做单页面应用?
(1)传统的开发方式
url改变后,立马发送请求,响应整个页面,有可能资源过多,传统的开发会让前端的页面出现“白屏”。
用户体验不好。
(2)SPA单页面应用
SPA:Single Page Application
锚点值改变后,不会立刻发送请求,而是在某个合适的时机,发送ajax请求,局部改变页面中的数据。
页面不立刻跳转,用户体验好。
2、前端路由的实现原理
前端路由:
1.锚点值监视; 2.ajax获取动态的数据; 3.核心点是锚点值的改变;
前端中的 vue/react/angular 都很适合做单页面应用。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <a href="#/login">登录页面</a> <a href="#/register">注册页面</a> <div id="app"> </div> <script type="text/javascript"> // 获取div var oDiv = document.getElementById('app'); window.onhashchange = function () { console.log(location.hash); // 根据不同的锚点值,对页面不同的切换 switch (location.hash) { case '#/login': oDiv.innerHTML = '<h2>登录页面</h2>'; break; case '#/register': oDiv.innerHTML = '<h2>注册页面</h2>'; break; default: // statements_def break; } } </script> </body> </html>
(1)window.onhashchange介绍
当一个窗口的 hash (URL中'#'后面的部分)改变时就会触发 onhashchange 事件。
onhashchange 事件在当前url的锚点部分(以'#'号为开始)发生改变时触发。
锚部分的实例:指定当前URL为http://www.example.com/test.htm#part2 - 这个 URL 中的锚部分为 #part2。
(2)onhashchange调用事件方法
- 通过设置Location 对象 的 location.hash 或 location.href 属性修改锚部分。
- 使用不同书签导航到当前页面(使用"后退" 或"前进"按钮)
- 点击链接跳转到书签锚
3、根据不同锚点切换页面效果
(1)初始页面显示如下:
(2)点击登录页面
(3)点击注册页面
二、vue-router使用
1、用NPM下载安装vue-router
(venv) MacBook-Pro:vue_study hqs$ cd 03-vue-router/ (venv) MacBook-Pro:03-vue-router hqs$ ls 01-前端路由实现原理.html vue.js (venv) MacBook-Pro:03-vue-router hqs$ npm init --yes Wrote to /Users/hqs/PycharmProjects/vue_study/03-vue-router/package.json: { "name": "03-vue-router", "version": "1.0.0", "description": "", "main": "vue.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" } (venv) MacBook-Pro:03-vue-router hqs$ npm install vue-router -S 03-vue-router@1.0.0 /Users/hqs/PycharmProjects/vue_study/03-vue-router └── vue-router@3.0.1 npm WARN 03-vue-router@1.0.0 No description npm WARN 03-vue-router@1.0.0 No repository field.
查看项目文件目录:
2、vue-router应用实例
<body> <div id="app"></div> <script type="text/javascript" src="vue.js"></script> <!--1.引入vue-router的对象--> <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script> <!--全局的VueRouter对象 vue-router还提供了两个全局的组件router-link / router-view--> <script type="text/javascript"> // 2.让Vue使用该VueRouter创建 Vue.use(VueRouter); var Login = { // 组件创建 template:` <div>登录页面</div> ` }; var Register = { // 组件创建 template:` <div>注册页面</div> ` }; // 3.创建一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/login', // login路由 component:Login }, { path:'/register', component:Register } ] }); var App = { // App:入口组件 // router-link默认会被渲染为a标签,to属性默认会被渲染为href属性 // router-view是路由组件的出口 template:` <div> <router-link to="/login">登录页面</router-link> <router-link to="/register">注册页面</router-link> <router-view></router-view> </div> ` }; new Vue({ // Vue实例化对象 el:'#app', components:{ App }, router, // router:router, 在key和value相同时可以只写一个 template:`<App/>` // 入口组件 }); </script> </body>
注意要点:
(1)<router-link>组件和<router-view>组件
全局的VueRouter对象 vue-router 还提供了两个全局的组件router-link / router-view。
<router-link>
组件支持用户在具有路由功能的应用中 (点击) 导航。 通过 to
属性指定目标地址,默认渲染成带有正确链接的 <a>
标签,可以通过配置 tag
属性生成别的标签.。另外,当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名。
<router-view>
组件是一个 functional 组件,渲染路径匹配到的视图组件,是所有路由组件的出口。<router-view>
渲染的组件还可以内嵌自己的 <router-view>
,根据嵌套路径,渲染嵌套组件。
var App = { // router-link默认会被渲染为a标签 to属性默认会被渲染为href属性 // router-view是路由组件的出口 template:` <div> <router-link to="/login">登录页面</router-link> <router-link to="/register">注册页面</router-link> <router-view></router-view> </div> ` };
(2)报错Cannot read property 'matched' of undefined
这种问题就是因为自己创建的router对象没有被Vue实例化对象所使用:
new Vue({ // Vue实例化对象 el:'#app', components:{ App }, router, // router:router, 在key和value相同时可以只写一个 template:`<App/>` // 入口组件 });
(3)页面通过router-view渲染
1)点击前效果:
可以看到router-link默认会被渲染为a标签,to属性默认会被渲染为href属性。
2)点击后效果:
(4)小结
当你在页面访问login时,router-link对应着的路径是'/login',加载对应的component组件:Login,component组件找一个出口渲染出来:router-view。
3、命名路由
有时候,通过一个名称来标识一个路由显得更方便一些,特别是在链接一个路由,或者是执行一些跳转的时候。你可以在创建 Router 实例的时候,在 routes
配置中给某个路由设置名称。
给当前的配置路由信息对象设置name属性。
对上面代码做如下修改:
var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/login', name:'login', // 设置路由名称 component:Login }, { path:'/register', name:'register', // 设置路由名称 component:Register } ] }); var App = { // 不使用to属性访问路由,改用动态命名路由绑定 // 要链接到一个命名路由,可以给 router-link 的 to 属性传一个对象: template:` <div> <router-link :to="{name:'login'}">登录页面</router-link> <router-link :to="{name:'register'}">注册页面</router-link> <router-view></router-view> </div> ` };
4、总结Vue Router流程
(1)引入vue-router对象模块
<script type="text/javascript" src="vue.js"></script> <!--引入vue-router的对象--> <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
该模块默认会抛出一个VueRouter对象,另外还有两个全局的组件router-link和router-view。
(2)让Vue使用该VueRouter创建
// 如果使用模块化机制编程,导入Vue和VueRouter,要调用Vue.use(VueRouter) <script type="text/javascript"> // 让Vue使用该VueRouter创建 Vue.use(VueRouter); // 代码省略 </script>
(3)创建路由对象
// 3.创建一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/login', name:'login', // 设置路由名称 component:Login }, { path:'/register', name:'register', // 设置路由名称 component:Register } ] });
(4)路由对象挂载到vue实例化对象中
var App = { // 不使用to属性访问路由,改用动态命名路由绑定 // 要链接到一个命名路由,可以给 router-link 的 to 属性传一个对象: template:` <div> <router-link :to="{name:'login'}">登录页面</router-link> <router-link :to="{name:'register'}">注册页面</router-link> <router-view></router-view> </div> ` }; new Vue({ el:'#app', components:{ App }, router, // router:router, 在key和value相同时可以只写一个 template:`<App/>` });
三、路由参数(范式)
在vue-router路由中,传参方式一般分两种。如下所示:
(1)xxx.html#/user/1 params 动态路由参数 (2)xxx.html#/user?userId=2 query 查询
示例代码如下所示:
<body> <div id="app"></div> <script type="text/javascript" src="vue.js"></script> <!--1.引入vue-router的对象--> <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script> <!--全局的VueRouter对象 vue-router还提供了两个全局的组件router-link / router-view--> <script type="text/javascript"> // 路由范式 //(1)xxx.html#/user/1 params 动态路由参数 //(2)xxx.html#/user?userId=2 query 查询 // 2.让Vue使用该VueRouter创建 Vue.use(VueRouter); var UserParams = { template:` <div>我是用户1</div> `, created(){ // 接收参数 console.log(this.$route); // 其中包含params属性 console.log(this.$route.params.userId); // 输出:1 // 传参,发送ajax请求 console.log(this.$router); // VueRouter对象 } }; var UserQuery = { template:` <div>我是用户2</div> `, created(){ // 接收参数 console.log(this.$route); // 包含query属性,query: {userId: "2"} console.log(this.$route.query.userId); // 输出:2 // 传参,发送ajax请求 console.log(this.$router); // VueRouter对象 } }; // 3.创建一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/user/:userId', // params形式,动态路由参数,以冒号开头 name:'userp', // 设置路由名称 component:UserParams }, { path:'/user', name:'userq', // 设置路由名称 component:UserQuery } ] }); var App = { // 不使用to属性访问路由,改用动态命名路由绑定.要链接到一个命名路由,可以给 router-link 的 to 属性传一个对象 // 路由匹配,query是查询操作 template: ` <div> <router-link :to="{name:'userp', params:{userId:1}}">用户1</router-link> <router-link :to="{name:'userq', query:{userId:2}}">用户2</router-link> <router-view></router-view> </div> ` }; new Vue({ el:'#app', components:{ App }, router, // router:router, 在key和value相同时可以只写一个 template:`<App/>` }); </script> </body>
1、query方式传参和接收参数
利用$route.query对象的Get方式传参,与http的get方式一样,会将参数暴露到地址栏。
var UserQuery = { template:` <div>我是用户2</div> `, created(){ // 接收参数 console.log(this.$route); // 包含query属性,query: {userId: "2"} console.log(this.$route.query.userId); // 输出:2 // 传参,发送ajax请求 console.log(this.$router); // VueRouter对象 } };
显示效果如下:
2、params方式传参和接收参数
利用$route.params对象的Post方式传参,该方式具有一定限制,必须通过路径传参方式。
var UserParams = { template:` <div>我是用户1</div> `, created(){ // 接收参数 console.log(this.$route); // 其中包含params属性 console.log(this.$route.params.userId); // 输出:1 // 传参,发送ajax请求 console.log(this.$router); // VueRouter对象 } };
显示效果如下所示:
3、源码分析
// vue-router.js文件558行到564行 Object.defineProperty(Vue.prototype, '$router', { get: function get () { return this._routerRoot._router } }); Object.defineProperty(Vue.prototype, '$route', { get: function get () { return this._routerRoot._route } });
相当于给vue实例化对象添加了两个属性$router(VueRouter)和$route(路由配置信息)。
4、配置路由对象方式
// 3.创建一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/user/:userId', // params形式,动态路由参数,以冒号开头 name:'userp', // 设置路由名称 component:UserParams }, { path:'/user', name:'userq', // 设置路由名称 component:UserQuery } ] });
注意params形式,是配置动态路由参数,要以冒号开头。
5、匹配路由
var App = { // 不使用to属性访问路由,改用动态命名路由绑定.要链接到一个命名路由,可以给 router-link 的 to 属性传一个对象 template:` <div> <router-link :to="{name:'userp', params:{userId:1}}">用户1</router-link> <router-link :to="{name:'userq', query:{userId:2}}">用户2</router-link> <router-view></router-view> </div> ` };
访问效果如下所示:
四、编程式导航
除了使用 <router-link>
创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
1、编程式导航示例
对上例做如下修改,不再使用声明式的<router-link :to='...'>,改为使用编程式:router.push(...)
var App = { // 不使用to属性访问路由,改用动态命名路由绑定.要链接到一个命名路由,可以给 router-link 的 to 属性传一个对象 template:` <div> <button @click="paramsHandler">用户1</button> <button @click="queryHandler">用户2</button> <router-view></router-view> </div> `, methods:{ paramsHandler(){ // 编程式导航 this.$router.push({ name: 'userp', params: { userId: 123 }}) }, queryHandler(){ this.$router.push({ name: 'userq', query: {userId: 3221} }) } } };
params访问显示效果:
query访问显示效果:
2、router.push(location, onComplete?, onAbort?
)
注意:在 Vue 实例内部,你可以通过 $router
访问路由实例。因此你可以调用 this.$router.push
。
想要导航到不同的 URL,则使用 router.push
方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。
当你点击 <router-link>
时,这个方法会在内部调用,所以说,点击 <router-link :to="...">
等同于调用 router.push(...)
。
该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:
// 字符串 router.push('home') // 对象 router.push({ path: 'home' }) // 命名的路由 router.push({ name: 'user', params: { userId: 123 }}) // 带查询参数,变成 /register?plan=private router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path
,params
会被忽略,上述例子中的 query
并不属于这种情况。取而代之的是下面例子的做法,你需要提供路由的 name
或手写完整的带有参数的 path
:
const userId = 123 router.push({ name: 'user', params: { userId }}) // -> /user/123 router.push({ path: `/user/${userId}` }) // -> /user/123 // 这里的 params 不生效 router.push({ path: '/user', params: { userId }}) // -> /user
同样的规则也适用于 router-link
组件的 to
属性。
在 2.2.0+,可选的在 router.push
或 router.replace
中提供 onComplete
和 onAbort
回调作为第二个和第三个参数。这些回调将会在导航成功完成 (在所有的异步钩子被解析之后) 或终止 (导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由) 的时候进行相应的调用。
注意:如果目的地和当前路由相同,只有参数发生了改变 (比如从一个用户资料到另一个 /users/1
-> /users/2
),你需要使用 beforeRouteUpdate
来响应这个变化 (比如抓取用户信息)
五、嵌套路由
实际生活中的应用界面,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件,例如:
/user/foo/profile /user/foo/posts
+------------------+ +-----------------+
| User | | User |
| +--------------+ | | +-------------+ |
| | Profile | | +------------> | | Posts | |
| | | | | | | |
| +--------------+ | | +-------------+ |
+------------------+ +-----------------+
借助 vue-router
,使用嵌套路由配置,就可以很简单地表达这种关系。
1、嵌套路由示例
<body> <div id="app"></div> <script type="text/javascript" src="vue.js"></script> <!--1.引入vue-router的对象--> <script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script> <!--全局的VueRouter对象 vue-router还提供了两个全局的组件router-link / router-view--> <script type="text/javascript"> // 嵌套路由: // 需求:进入首页后,点击音乐(/home/music) 电影(/home/movie) // 2.让Vue使用该VueRouter创建 Vue.use(VueRouter); var Home = { // 子路由出口 template:` <div> <br/> <router-link to="/home/music">音乐</router-link> <router-link to="/home/movie">电影</router-link> <router-view></router-view> </div> ` }; var Music = { template:` <div>我是音乐</div> ` }; var Movie = { template:` <div>我是电影</div> ` }; // 3.创建一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/', redirect:'home' // redirect:{name:'home'} // 命令路由的方式 }, { path:'/home', // params形式,动态路由参数,以冒号开头 name:'home', // 设置路由名称 component:Home, children:[ // 动态路由匹配表示你的子组件中的结构是不同的 // 当访问/home组件时,Home组件的出口是不会渲染任何内容的, // 这是因为没有匹配到合适的子路由 { path:'', // 访问空字符串就表示访问/home了 component:Music // 默认加载孩子组件Music }, { path:'music', // 自己会默认去拼接斜杠 component:Music // 对应加载的组件 // children: // 可以继续配置三层路由 }, { path:'movie', // 自己会默认去拼接斜杠 component:Movie // 对应加载的组件 } ] }, ] }); var App = { // 路由出口 template:` <div> <router-link :to="{name:'home'}">首页</router-link> <router-view></router-view> </div> `, }; new Vue({ el:'#app', components:{ App }, router, // router:router, 在key和value相同时可以只写一个 template:`<App/>` }); </script> </body>
2、注意要点
(1)以 /
开头的嵌套路径会被当作根路径。 这让你充分的使用嵌套组件而无须设置嵌套的路径。
(2)children
配置就是像 routes
配置一样的路由配置数组,所以呢,你可以嵌套多层路由。
3、显示效果
(1)页面首页默认显示音乐
(2)点击切换到电影页面
4、嵌套路由警告处理
这个警告的意思是:当父路由有子路由时,不允许子路由中有命名路由。因此对代码做如下调整
var router = new VueRouter({ // 配置路由对象 routes:[ { path:'/', redirect:'home' // redirect:{name:'home'} // 命令路由的方式 }, { path:'/home', // params形式,动态路由参数,以冒号开头 // name:'home', // 设置路由名称 component:Home, children:[ // 动态路由匹配表示你的子组件中的结构是不同的 // 当访问/home组件时,Home组件的出口是不会渲染任何内容的, // 这是因为没有匹配到合适的子路由 { path:'', // 访问空字符串就表示访问/home了 component:Music // 默认加载孩子组件Music }, { path:'music', // 自己会默认去拼接斜杠 component:Music // 对应加载的组件 // children: // 可以继续配置三层路由 }, { path:'movie', // 自己会默认去拼接斜杠 component:Movie // 对应加载的组件 } ] }, ] }); var App = { // 路由出口 template:` <div> <!--<router-link :to="{name:'home'}">首页</router-link>--> <router-link to="/home">首页</router-link> <router-view></router-view> </div> `, };
再次查看控制台,警报解除:
六、动态路由匹配
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User
组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router
的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果。
const User = { template: '<div>User</div>' } const router = new VueRouter({ routes: [ // 动态路径参数 以冒号开头 { path: '/user/:id', component: User } ] })
1、动态路由匹配示例
<body>
<div id="app"></div>
<script type="text/javascript" src="vue.js"></script>
<!--1.引入vue-router的对象-->
<script type="text/javascript" src="./node_modules/vue-router/dist/vue-router.js"></script>
<!--全局的VueRouter对象 vue-router还提供了两个全局的组件router-link / router-view-->
<script type="text/javascript">
// 2.让Vue使用该VueRouter创建
Vue.use(VueRouter);
var Timeline = {
template:`
<div>
<router-link :to="{name:'comDesc', params:{id:'android'}}">Android</router-link>
<router-link :to="{name:'comDesc', params:{id:'frontend'}}">前端</router-link>
<router-view></router-view>
</div>
`
};
var Pins = {
template:`
<div>
我是沸点
</div>
`
};
// 共同的子组件
var ComDesc = {
data(){
return{
msg:''
}
},
template:`
<div>
我是{{msg}}
</div>
`,
created(){ // 生命周期方法
alert(1);
this.msg = '安卓';
}
};
// 3.创建一个路由对象
var router = new VueRouter({
// 配置路由对象
routes:[
// 动态路由参数以冒号开头
{
path:'/timeline',
component:Timeline,
children:[
{
path:"",
component:ComDesc // 访问Timeline时访问共同组件ComDesc
},
{
path:'/timeline/:id',
name:'comDesc',
component:ComDesc // 访问子动态路由时,也加载共同组件ComDesc
}
]
},
{
path:'/pins',
component:Pins
}
]
});
var App = {
// 路由出口
template:`
<div>
<router-link to="/timeline">首页</router-link>
<router-link to="/pins">沸点</router-link>
<router-view></router-view>
</div>
`,
};
new Vue({
el:'#app',
components:{
App
},
router, // router:router, 在key和value相同时可以只写一个
template:`<App/>`
});
</script>
</body>
(1)路由映射到公共路由
var router = new VueRouter({ // 配置路由对象 routes:[ // 动态路由参数以冒号开头 { path:'/timeline', component:Timeline, children:[ { path:"", component:ComDesc // 访问Timeline时访问共同组件ComDesc }, { path:'/timeline/:id', name:'comDesc', component:ComDesc // 访问子动态路由时,也加载共同组件ComDesc } ] }, { path:'/pins', component:Pins } ] });
/timeline/android和/timeline/frontend都将映射相同的路由。
一个“路径参数”使用冒号 :
标记。当匹配到一个路由时,参数值会被设置到 this.$route.params
,可以在每个组件内使用。
(2)组件实例复用
当使用路由参数时,例如从 /user/foo
导航到 /user/bar
,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
// 共同的子组件 var ComDesc = { data(){ return{ msg:'' } }, template:` <div> 我是{{msg}} </div> `, created(){ // 生命周期方法 alert(1); this.msg = '安卓'; } };
(3)显示效果及生命周期钩子不重复调用
初始状态:
点击首页,显示alert:
点击确认后显示:
点击前端:
再点回安卓或首页,页面显示会调整,但都不再显示alert。说明生命周期钩子不再运行。
2、响应路由参数的变化
前面已经说到当使用路由参数时,例如从 /user/foo
导航到 /user/bar
,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。
复用组件时,想对路由参数的变化作出响应的话,你可以简单地 watch (监测变化) $route
对象:
// 共同子组件 var ComDesc = { data(){ return{ msg:'' } }, template:` <div> 我是{{msg}} </div> `, created(){ // 生命周期方法 // alert(1); // this.msg = '安卓'; }, watch:{ '$route' (to, from) { // 对路由变化作出响应... console.log(to); console.log(from); } } };
(1)点击安卓页面,打印出的to和from信息
(2)然后再点击前端页面,打印的to和from信息
(3)直接渲染
var ComDesc = { data(){ return{ msg:'' } }, template:` <div> 我是{{msg}} </div> `, created(){ // 生命周期方法 // alert(1); // this.msg = 'android'; }, watch:{ '$route' (to, from) { // 对路由变化作出响应... console.log(to); console.log(from); // 直接渲染 this.msg = to.params.id; } } };
点击显示效果如下所示:
也可以看到组件没有再次被销毁或创建。
七、keep-alive在路由中的使用
<keep-alive>
是Vue的内置组件,能在组件切换过程中将状态保留在内存中(缓存),防止重复渲染DOM。
(1)Props:
- include:字符串或正则表达式。只有名称匹配的组件会被缓存。
- exclude:字符串或正则表达式。任何名称匹配的组件都不会被缓存。
- max:数字。最多可以缓存多少组件实例。
(2)用法:
<keep-alive>
包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。和 <transition>
相似,<keep-alive>
是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。
当组件在 <keep-alive>
内被切换,它的 activated
和 deactivated
这两个生命周期钩子函数将会被对应执行。
主要用于保留组件状态或皮面重新渲染。
1、不使用keep-alive切换页面
<script type="text/javascript"> // 2.让Vue使用该VueRouter创建 Vue.use(VueRouter); var Timeline = { template:` <div> 我是首页 </div> `, created(){ console.log('首页组件创建了'); }, mounted(){ console.log('首页组件DOM加载了'); }, destroyed(){ console.log('首页销毁了'); } }; var Pins = { template:` <div> <h3 @click="clickHandler">我是沸点</h3> </div> `, methods:{ clickHandler(e){ e.target.style.color = 'red'; } }, created(){ console.log('沸点组件创建了'); }, mounted(){ console.log('沸点组件DOM加载了'); }, destroyed(){ console.log('沸点销毁了'); }; // 3.创建一个路由对象 var router = new VueRouter({ // 配置路由对象 routes:[ // 动态路由参数以冒号开头 { path:'/timeline', component:Timeline, }, { path:'/pins', name:'pins', component:Pins } ] }); var App = { // keep-alive组件保持缓存,把router-view渲染的出口缓存起来 template:` <div> <router-link to="/timeline">首页</router-link> <router-link to="/pins">沸点</router-link> <router-view></router-view> </div> `, }; new Vue({ el:'#app', components:{ App }, router, // router:router, 在key和value相同时可以只写一个 template:`<App/>` }); </script>
此时还没有使用keep-alive,切换页面时都会执行生命周期操作:
而且切换到沸点页面,点击“我是沸点”,可以将字体变红,但是切换到首页再切换沸点时,又变黑色了。也说明了重新进行了创建销毁。
2、用keep-alive组件把router-view渲染的出口缓存起来
注意:<keep-alive>
是用在其一个直属的子组件被开关的情形。如果你在其中有 v-for
则不会工作。如果有上述的多个条件性的子元素,<keep-alive>
要求同时只有一个子元素被渲染。
var App = { // keep-alive组件保持缓存,把router-view渲染的出口缓存起来 template:` <div> <router-link to="/timeline">首页</router-link> <router-link to="/pins">沸点</router-link> <keep-alive> <router-view></router-view> </keep-alive> </div> `, };
显示效果如下:
可以看到第一次点击会创建和加载,但并没有销毁DOM,从首页切换到沸点,仍保持为红色。