Vue2 基础五路由

代码下载

路由

路由是一个比较广义和抽象的概念,路由的本质就是一种对应关系。比如说在url地址中输入我们要访问的url地址之后,浏览器要去请求这个url地址对应的资源。
那么url地址和真实的资源之间就有一种对应的关系,就是路由。

路由分为前端路由和后端路由:

  • 后端路由根据不同的用户 URL 请求,返回不同的内容,本质是 URL 请求地址与服务器资源之间的对应关系
  • 前端路由根据不同的用户事件,显示不同的页面内容,本质是用户事件与事件处理函数之间的对应关系,是依靠hash值(锚链接)的变化进行实现

后端路由性能相对前端路由来说较低,所以,我们接下来主要学习的是前端路由
前端路由的基本概念:根据不同的事件来显示不同的页面内容,即事件与事件处理函数之间的对应关系
前端路由主要做的事情就是监听事件并分发执行事件处理函数

SPA(Single Page Application)

  • 后端渲染(存在性能问题)
  • Ajax前端渲染(前端渲染提高性能,但是不支持浏览器的前进后退操作)
  • SPA(Single Page Application)单页面应用程序:整个网站只有一个页面,内容的变化通过Ajax局部更新实现、同时支持浏览器地址栏的前进和后退操作
  • SPA实现原理之一:基于URL地址的hash(hash的变化会导致浏览器记录访问历史的变化、但是hash的变化不会触发新的URL请求)
  • 在实现SPA过程中,最核心的技术点就是前端路由

实现简易前端路由

  • 基于URL中的hash实现(点击菜单的时候改变 URL 的 hash,根据 hash 的变化控制组件的切换)
  • component 标签根据 is 属性指定的组件名称,把对应的组件渲染到 component 标签所在的位置,可以把 component 标签当做是【组件的占位符】
  • 监听 window 的 onhashchange 事件,根据获取到的最新的 hash 值(通过 location.hash 获取),切换要显示的组件的名称
<body>
    <div class="main" id="app">
        <h2>实现简易前端路由</h2>
        <a href="#/zhuye">主页</a>
        <a href="#/keji">科技</a>
        <a href="#/caijing">财经</a>
        <a href="#/yule">娱乐</a>
        <component :is="cname"></component>
    </div>

    <script src="../js/vue.js"></script>
    <script>
        let vm = new Vue({
            el: '#app',
            data: {
                cname: 'zhuye'
            },
            components: {
                'zhuye': {
                    template: '<h3>主页内容</h3>'
                }, 
                'keji': {
                    template: '<h3>科技内容</h3>'
                }, 
                'caijing': {
                    template: '<h3>财经内容</h3>'
                }, 
                'yule': {
                    template: '<h3>娱乐内容</h3>'
                }
            }
        });
        window.onhashchange = function() {
            console.log('hash: ', location.hash.slice(1));
            switch (location.hash.slice(1)) {
                case '/zhuye':
                    vm.cname = 'zhuye';
                    break;
                case '/keji':
                    vm.cname = 'keji';
                    break;
                case '/caijing':
                    vm.cname = 'caijing';
                    break;
                case '/yule':
                    vm.cname = 'yule';
                    break;
            }
        };
    </script>
</body>

Vue Router

Vue Router(官网)是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,可以非常方便的用于SPA应用程序的开发。Vue Router依赖于Vue,所以需要先引入Vue,再引入Vue Router。Vue Router的特性:

  • 支持H5历史模式或者hash模式
  • 支持嵌套路由
  • 支持路由参数
  • 支持编程式路由
  • 支持命名路由
  • 支持路由导航守卫
  • 支持路由过渡动画特效
  • 支持路由懒加载
  • 支持路由滚动行为
vue-router的基本使用

1、引入相关的库文件:

    <!-- 导入相关js库文件 -->
    <script src="../js/vue.js"></script>
    <script src="../js/vue-router_v3.6.5.js"></script>

2、添加路由链接,是路由中提供的标签,默认会被渲染为a标签,to属性默认被渲染为href属性,to属性的值会被渲染为#开头的hash地址:

        <router-link to="/user">User</router-link>
        <router-link to="/register">Register</router-link>

3、添加路由填充位,(也叫做路由占位符)将来通过路由规则匹配到的组件,会被渲染到 router-view 所在的位置:

        <router-view></router-view>

4、定义路由组件:

        const user = {
            template: '<h3>User 组件</h3>'
        };
        const register = {
            template: '<h3>Register 组件</h3>'
        }

5、配置路由规则并创建路由实例:

        // 创建路由实例对象
        let router = new VueRouter({
            // routes 是路由规则数组
            routes: [
                // 每个路由规则都是一个配置对象,其中至少包含 path 和 component 两个属性:
                // path 表示当前路由规则匹配的 hash 地址
                // component 表示当前路由规则对应要展示的组件
                {path: '/user', component: user},
                {path: '/register', component: register}
            ]
        });

6、把路由挂载到 Vue 根实例中:

        let vm = new Vue({
            el: '#app',
            data: {},
            router
        });
vue-router路由重定向

路由重定向指的是用户在访问地址 A 的时候,强制用户跳转到地址 C ,从而展示特定的组件页面;通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向:

        let router = new VueRouter({
            routes: [
                {path: '/user', component: user},
                {path: '/register', component: register},
                // 其中,path 表示需要被重定向的原地址,redirect 表示将要被重定向到的新地址
                {path: '/', redirect: '/user'}
            ]
        });
vue-router嵌套路由

点击父级路由链接显示模板内容,模板内容中又有子级路由链接,点击子级路由链接显示子级模板内容,使用方法如下:

1、在父路由组件模板中添加子级路由链接和子级路由填充位:

        const register = { 
            template: `
                <div>
                    <h3>Register 组件</h3>

                    <!-- 子路由连接 -->
                    <router-link to='/register/tab1'>Tab1</router-link>
                    <router-link to='/register/tab2'>Tab2</router-link>
                    
                    <!-- 子路由的占位符 -->
                    <router-view></router-view>
                </div>
            ` 
        };

2、构建子路由组件:

        const tab1 = {
            template: `<h4>Tab1 子组件</h4>`
        }
        const tab2 = {
            template: `<h4>Tab2 子组件</h4>`
        }

3、嵌套路由配置,父级路由通过children属性配置子级路由:

        const router = new VueRouter({
            routes: [
                { path: '/user', component: user },
                { path: '/register', component: register, 
                    children: [
                        { path: '/register/tab1', component: tab1 },
                        { path: '/register/tab2', component: tab2 }
                    ]
                }
            ]
        });
vue-router动态路由

通过动态路由参数的模式进行路由匹配:

  • 动态路径参数以冒号开头
  • 路由组件中通过$route.params获取路由参数
        const user = {
            template: `
                <div>id: {{$route.params.id}}</div>
            `
        }
        const router = new VueRouter({
            routes: [
                { path: '/user/:id', component: user }
            ]
        });
vue-router路由组件传递参数

$route与对应路由形成高度耦合,不够灵活,所以可以使用props将组件和路由解耦。

1、props的值为布尔类型:props 被设置为 true,route.params 将会被设置为组件属性,使用 props 接收路由参数

        const user = {
            // 使用 props 接收路由参数
            props: ['id'],
            template: `<h3>User 组件内容 id: {{id}}</h3>`
        };
        const router = new VueRouter({
            routes: [
                // 如果 props 被设置为 true,route.params 将会被设置为组件属性
                { path: '/user/:id', component: user, props: true }
            ]
        });

2、props的值为对象类型:props 是一个对象,它会被按原样设置为组件属性

        const user = {
            // 使用 props 接收路由参数
            props: ['id', 'name', 'age'],
            template: `<h3>User 组件内容 id: {{id}}, name: {{name}}, age: {{age}}</h3>`
        };
        const router = new VueRouter({
            routes: [
                // 如果 props 是一个对象,它会被按原样设置为组件属性
                { path: '/user/:id', component: user, props: { id: 2, name: '张三', age: 18 } }
            ]
        });

3、props的值为函数类型:如果需要传递参数值则需将 props 设置为一个函数,这个函数接收 route 对象为自己的形参

        const user = {
            // 使用 props 接收路由参数
            props: ['id', 'name', 'age'],
            template: `<h3>User 组件内容 id: {{id}}, name: {{name}}, age: {{age}}</h3>`
        };
        const router = new VueRouter({
            routes: [
                // 如果 props 是一个函数,则这个函数接收 route 对象为自己的形参
                { path: '/user/:id', component: user, props: (route) => ({ id: route.params.id, name: '张三', age: 18 }) }
            ]
        });
vue-router命名路由

为了更加方便的表示路由的路径,可以给路由规则起一个别名,即为“命名路由”:

        const user = {
            props: ['id', 'name', 'age'],
            template: `<h3>User 组件内容 id: {{id}}, name: {{name}}, age: {{age}}</h3>`
        };
        const router = new VueRouter({
            // 命名路由
            routes: [ { name: 'User', path: '/user/:id', component: user, props: (route) => ({ id: route.params.id, name: route.params.name, age: route.params.age }) } ]
        });

使用命名路由:

        <router-link :to="{ name: 'User', params: { id: 4, name: '李四', age: 18 }}">User 4</router-link>

        <router-view></router-view>

或编程式导航:

        router.push({ name: 'User', params: { id: 4, name: '李四', age: 18}})
vue-router编程式导航

页面导航的两种方式:

  • 声明式导航:通过点击链接实现导航的方式,叫做声明式导航,例如:普通网页中的 链接 或 vue 中的
  • 编程式导航:通过调用JavaScript形式的API实现导航的方式,叫做编程式导航,例如:普通网页中的 location.href

常用的编程式导航 API 如下:

  • this.$router.push(‘hash地址或对象’)
  • this.$router.go(n),其中 n 为数字,正整数代表前进,负整数代表回退,参考history.go

router.push() 方法的参数规则:

  • 字符串(路径名称)——this.$router.push('/user/1');
  • 对象——this.$router.push({ path: '/user/2' });
  • 命名的路由(传递参数)——this.$router.push({ name: 'User', params: { id: 3, name: '李四', age: 19 }});
  • 带查询参数,变成 /user?id=4&name=lisi&age=20,在路由规则中可以通过 route.params 获取查询参数——this.$router.push({ path: '/user', query: { id: 4, name: 'lisi', age: 20 }});
<body>
    <div class="main" id="app">
        <h2>vue-router编程式导航</h2>

        <h3>声明式导航</h3>
        <router-link :to="{ name: 'User', params: { id: 1, name: '张三', age: 18 }}">User 1</router-link>

        <h3>编程式导航</h3>
        <button @click="strHandle">字符串</button>
        <button @click="objHandle">对象</button>
        <button @click="nameHandle">命名路由</button>
        <button @click="queryHandle">查询路由</button>

        <router-view></router-view>
    </div>

    <script src="../js/vue.js"></script>
    <script src="../js/vue-router_v3.6.5.js"></script>
    <script>
        let user = {
            props: [ 'id', 'name', 'age' ],
            template: `
            <div>
                <h3>User 组件内容 id: {{id}} name: {{name}} age: {{age}}</h3>
                <button @click='registerHandel'>去注册</button>
            </div>
            `,
            methods: {
                registerHandel: function() {
                    this.$router.push('/register')
                }
            }
        };
        let register = {
            template: `
            <div>
                <h3>Register 组件内容</h3>
                <button @click='backHandel'>返回</button>
            </div>
            `,
            methods: {
                backHandel: function() {
                    // 回退
                    this.$router.go('-1');
                }
            }
        }
        let router = new VueRouter({
            routes: [
                { path: '/', component: user, props: {id: 1, name: '张三', age: 18} },
                // 命名路由 带 params 参数
                { name: 'User', path: '/user/:id', component: user, props: (route) => ({ id: route.params.id, name: route.params.name, age: route.params.age }) },
                // 带 query 查询参数
                { path: '/user', component: user, props: (route) => ({ id: route.query.id, name: route.query.name, age: route.query.age }) },
                { path: '/register', component: register }
            ]
        });
        let vm = new Vue({
            el: '#app',
            data: {},
            router,
            methods: {
                strHandle: function() {
                    console.log('hash: ', location.hash);
                    if (location.hash !== '#/user/1') {
                        // 字符串(路径)
                        this.$router.push('/user/1');
                    }
                },
                objHandle: function() {
                    console.log('hash: ', location.hash);
                    if (location.hash !== '#/user/2') {
                        // 对象
                        this.$router.push({ path: '/user/2' });
                    }
                },
                nameHandle: function() {
                    console.log('hash: ', location.hash);
                    if (location.hash !== '#/user/3') {
                        // 命名的路由(传递参数)
                        this.$router.push({ name: 'User', params: { id: 3, name: '李四', age: 19 }});
                    }
                },
                queryHandle: function() {
                    console.log('hash: ', location.hash);
                    let name = '王五';
                    let ecName = encodeURI(name);
                    if (location.hash !== `#/user?id=4&name=${ecName}&age=19`) {
                        // // 带查询参数
                        this.$router.push({ path: '/user', query: { id: 4, name: name, age: 20 }});
                    }
                }
            }
        });
    </script>
</body>

案例

请添加图片描述

点击左侧的"用户管理",“权限管理”,“商品管理”,“订单管理”,"系统设置"都会出现对应的组件并展示内容;其中"用户管理"组件展示的效果如上图所示,在用户管理区域中的详情链接也是可以点击的,点击之后将会显示用户详情信息,并在详情页实现后退功能。

1、基于组件构建基本结构,右侧的主体内容使用路由填充位,根据路由导航渲染具体组件

        let header = {
            props: ['title'],
            template: `<h2 class="header" v-text="title"></h2>`
        };
        let leftContent = {
            template: `<div class="left content">
                <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>
                </ul>
            </div>`
        };
        let rightContent = {
            template: `<div class="right content">
                <router-view></router-view>
            </div>`
        };
        let footer = {
            props: ['info'],
            template: `<h4 class="footer" v-text="info"></h4>`
        };
        let app = {
            props: ['title', 'crInfo'],
            template: `
                <div class="main">
                    <header-com :title="title"></header-com>
                    <left-com></left-com>
                    <right-com></right-com>
                    <footer-com :info="crInfo"></footer-com>
                </div>
            `,
            components: {
                'header-com': header,
                'left-com': leftContent,
                'right-com': rightContent,
                'footer-com': footer
            }
        };

2、定义右侧主体内容的各个路由组件

        let users = {
            data: function() {
                return {
                    userList: [
                        { id: 1, name: '张三', age: 18},
                        { id: 2, name: '李四', age: 19},
                        { id: 3, name: '王五', age: 20},
                        { id: 4, name: '赵六', age: 21}
                    ]
                }
            },
            template: `
                <div class="users">
                    <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 v-text="item.id"></td>
                                <td v-text="item.name"></td>
                                <td v-text="item.age"></td>
                                <td><a href="javascript:;" @click="goDetail(item.id)">详情</a></td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            `,
            methods: {
                goDetail: function(id) {
                    console.log('-----', id, '-----');
                    this.$router.push('/userInfo/' + id);
                }
            }
        }
        let rights = {
            template: `
                <div>
                    <h3>权限管理</h3>
                </div>
            `
        }
        let goods = {
            template: `
                <div>
                    <h3>商品管理</h3>
                </div>
            `
        }
        let orders = {
            template: `
                <div>
                    <h3>订单管理</h3>
                </div>
            `
        }
        let settings = {
            template: `
                <div>
                    <h3>系统设置</h3>
                </div>
            `
        }
        let userInfo = {
            props: ['id'],
            template: `
                <div class="detail">
                    <h3>用户详情-----{{id}}</h3>
                    <button @click="goBack">返回</button>
                </div>
            `,
            methods: {
                goBack: function() {
                    this.$router.go(-1);
                }
            }
        }

3、配置路由并挂载到 Vue 根实例中,由一个根路由显示主体结构,子路由显示右侧具体内容

        let router = new VueRouter({
            routes: [
                { 
                    path: '/', 
                    component: app, 
                    redirect: '/users',
                    children: [
                        { path: '/users', component: users },
                        { path: '/userInfo/:id', component: userInfo, props: true },
                        { path: '/rights', component: rights },
                        { path: '/goods', component: goods },
                        { path: '/orders', component: orders },
                        { path: '/settings', component: settings }
                    ],
                    props: { title: '后台管理案例', crInfo: '版权信息' }
                }
            ]
        });
        let vm = new Vue({
            el: '#app',
            router
        });

4、添加路由填充位,渲染根组件

    <div id="app">
        <router-view></router-view>
    </div>
  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值