• 前端路由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调用事件方法

    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' }})
    

      注意:如果提供了 pathparams 会被忽略,上述例子中的 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,从首页切换到沸点,仍保持为红色。

  • 相关阅读:
    常见SQL语句
    测试用例的设计
    移动端测试注意事项
    markdown编辑模式基本使用
    常用修改请求或返回方法
    前端性能测试工具Lighthouse
    presto环境部署
    pyenv管理python版本
    python2.6.6升级python2.7.14
    InfluxDB权限认证机制
  • 原文地址:https://www.cnblogs.com/xiugeng/p/9779208.html
Copyright © 2020-2023  润新知