vue中两种路由模式的实现详解

 更新时间:2023年08月13日 10:17:24   作者:闽南,  
这篇文章主要为大家详细介绍了vue中两种路由模式的实现,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下

平时我们编写路由时,通常直接下载插件使用,在main.js文件中引入直接通过引入vue-router中的Router通过Vue.use使用以后定义一个routeMap数组,里边是我们编写路由的地方,最后通过实例化一个 Router实例 将routes=我们定义的routeMao路由数组。

但是我们并不知道它是如何实现的,因此我们可以通过自己编写插件的形式,实现一个vue-router

常用路由步骤:

//router/index.js
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export const routeMap= [
     {
         path: '/home',
         component: () => import('../components/Home/Home.vue')
     },
     {
         path: '/list',
         component: () => import('../components/List/List.vue')
    },
]
const router = new Router({
    routes: constantRouterMap
})
export default router
//main.js
import router from './router'
new Vue({
  router,
  store,
  render: h => h(App),
}).$mount('#app')

我们来实现一下如何实现一个hash模式的路由

由于我们不适用插件形式实现,因此我们使用步骤与平常实现有一些差异。

router/index.js是我们的路由文件,里面放置我们的路由

plugin/router.js是我们的自定义插件文件,里面放置我们自定义插件内容

components是我们组件目录,放置我们的路由组件(通常使用view定义路由组件)

main.js是我们的入口文件,需要在该文件引入router并且实例化vue的时候需要将引入的router使用

1、首先我们在App.vue文件中,通过<router-view/>以及<router-link/>定义声明式导航和路由占位

<div>
    <router-link to="/home">首页</router-link>
    <router-link to="/list">列表</router-link>
    <hr>
    <router-view></router-view>
</div>

这里我们会发现使用以后会报错,因为我们没有下载插件,因此没有这两个组件。

我们需要配置plugin插件

由于没有这两个全局组件因此我们需要配置两个全局组件

install方法是为了将我们的路由挂载在我们的组件实例上,通过mixin全局混入,将我们的实例上挂载$router属性

然后定义两个全局组件,router-link由于它渲染出来相当于html中的a标签,使用render方法,参数为一个createElement方法接收三个参数(第一个参数创建的元素,第二个参数元素具有的属性, 第三个参数元素的内容)

router-view由于是一个路由占位符,因此返回的是个组件,渲染组件。

通过routesMap是我们存放的路由,current是我们的当前的path路由,因此可以通过查找路由中key值为我们当前path路径的,查找到我们的组件。通过return渲染我们的组件

VueRouter.install = function (_Vue) {
    //1、保存Vue
    Vue = _Vue
    //2、将以下代码延迟到vue实例初始化完毕执行
    Vue.mixin({
        beforeCreate() {
            //判断如果有router属性就执行下方代码
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router;
            }
        }
    })
    //创建全局组件router-link和router-view
    //创建router-link组件
    Vue.component('router-link', {
        props: {
            to: {
                type: String | Object,
                required: true
            }
        },
        render(h) {// h 有三个参数,第一个参数创建的元素,第二个参数元素具有的属性, 第三个参数元素的内容
            return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
        }
    })
    //创建router-view组件
    Vue.component('router-view', {
        // 组件要重新渲染,必须要让数据发生改变的时候,重新去执行render函数
        render(h) {
            const router = this.$router
            console.log(router.routesMap, 'routesMap');
            let component = router.routesMap[router.current];//组件
            //获取到外部传递的路由表
            return h(component)
        }
    })
}

2、我们定义一个路由类,该类会获取到我们的路由信息从而进行路由监听以及组件渲染。

(1)、该类中constructor是我们通过实例化vueRouter传入的数据,我们需要通过将数据保存在vueRouter实例上,获取到当前的url path路径。

(2)、通过监听方法hashchange监听我们hash值的变化,通过方法进行监听,但是一定要注意这里方法的this指向必须是vueRouter实例不可以是window,因此需要通过bind改变this指向

(3)、通过defineReactive来讲我们的path路径变为响应式,这样每次路径发生变化可以监测到变化。

(4)、定义routesMap为我们的路由对象,遍历我们传入的路由数组,将我们每个path路径对应组件,为一组一组的键值对。

这样可以实现一套hash路由模式的路由跳转。

全部代码如下:

//plugin/router.js
let Vue;
class VueRouter {
    constructor(options) {
        //保存选项
        this.options = options;
        // console.log(options, '路由数据');
        // 定义一个响应式的变量current,保存当前的hash值
        let url = location.hash.slice(1,) || '/';
        // defineReactive定义响应式的对象
        Vue.util.defineReactive(this, 'current', url)
        // hashchange事件来监听hash值的变化, 注意this指向问题
        addEventListener('hashchange', this.changeHash.bind(this))
        this.routesMap = {};
        //对routes中的对象做一个映射:routesMap = {'/home':component,'/list': component}
        this.options.routes.forEach(route => {
            this.routesMap[route.path] = route.component
        })
    }
    //监听hash值变化的函数
    changeHash() {
        //通过location.hash来获取到hash值
        this.current = location.hash.slice(1,)
        console.log(this.routesMap, '555');
        // console.log(this.current);//当前path路径
    }
}
VueRouter.install = function (_Vue) {
    //1、保存Vue
    Vue = _Vue
    //2、将以下代码延迟到vue实例初始化完毕执行
    Vue.mixin({
        beforeCreate() {
            //判断如果有router属性就执行下方代码
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router;
            }
        }
    })
    //创建全局组件router-link和router-view
    //创建router-link组件
    Vue.component('router-link', {
        props: {
            to: {
                type: String | Object,
                required: true
            }
        },
        render(h) {// h 有三个参数,第一个参数创建的元素,第二个参数元素具有的属性, 第三个参数元素的内容
            return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
        }
    })
    //创建router-view组件
    Vue.component('router-view', {
        // 组件要重新渲染,必须要让数据发生改变的时候,重新去执行render函数
        render(h) {
            const router = this.$router
            console.log(router.routesMap, 'routesMap');
            let component = router.routesMap[router.current];//组件
            console.log(component, 'component');
            //获取到外部传递的路由表
            return h(component)
        }
    })
}
export default VueRouter;

接下来实现历史路由模式

我们知道历史路由模式和hash路由模式区别是域名是否存在#因此我们可以通过在路由文件中定义mode属性判断是历史路由模式还是hash路由模式。

先大白话来说一下大概的实现思路(hash和history实现区别):

1、我们通过我们定义的mode判断是hash路由模式还是history路由模式,router-link点击跳转的时候如果是hash路由模式,我们通过render方法返回我们渲染到浏览器域名的数据,hash模式是带#的,因此我们定义href属性需要+#,但是history模式是不带#的,因此我们不需要加#。其次,因为hash模式自动检测我们的域名,因此我们实现历史模式需要手动加一个点击事件,并且需要阻止a链接默认跳转的行为(preventDefault取消默认行为),并且通过pushState方法,实现跳转,这是历史路由模式的方法pushState(obj,title,url),最后设置我们的路由当前path路径为我们跳转的路径。

2、当我们定义好它的router-link全局组件以后,这时我们hash路由模式和history路由模式已经可以基本实现,hash模式带#,history路由模式不带#。但是我们仍要定义一个监听历史路由模式变化的监听事件。这里我们通过mode判断是什么模式从而监听不同的事件,历史路由模式监听需要通过监听popState方法,来判断是否发生变化,它坚挺的是我们浏览器的前进后退的变化。

历史路由模式监听事件为hashchange方法,这个事件是用来监听我们hash值的变化,通过设置两个方法从而设置我们当前路径为对应的path路径。hash模式会通过slice剪切到#,历史路由模式则通过location.pathname获取到当前path路径。

实现如下:

let Vue;
class VueRouter {
    constructor(options) {
        //保存选项
        this.options = options;
        // console.log(options, '路由数据');
        // 定义一个响应式的变量current,保存当前的hash值
        let url = location.hash.slice(1,) || '/';
        // defineReactive定义响应式的对象
        Vue.util.defineReactive(this, 'current', url)
        //判断当前的路由模式
        if (this.options.mode === 'hash') {
            // hashchange事件来监听hash值的变化, 注意this指向问题
            addEventListener('hashchange', this.changeHash.bind(this))
        } else if (this.options.mode === 'history') {
            // history模式监听的事件叫做:popstate, 监听的是浏览器左上角的两个小箭头的变化
            addEventListener('popstate', this.changeHistory.bind(this))
        }
        this.routesMap = {};
        //对routes中的对象做一个映射:routesMap = {'/home':component,'/list': component}
        this.options.routes.forEach(route => {
            this.routesMap[route.path] = route.component
        })
    }
    //监听hash值变化的函数
    changeHash() {
        //通过location.hash来获取到hash值
        this.current = location.hash.slice(1,)
        console.log(this.routesMap, '555');
        // console.log(this.current);//当前path路径
    }
    // history
    changeHistory() {
        // console.log(location.pathname)
        this.current = location.pathname;
    }
}
 VueRouter.install = function (_Vue) {
    //1、保存Vue
    Vue = _Vue
    //2、将以下代码延迟到vue实例初始化完毕执行
    Vue.mixin({
        beforeCreate() {
            //判断如果有router属性就执行下方代码
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router;
            }
        }
    })
    //创建全局组件router-link和router-view
    //创建router-link组件
    Vue.component('router-link', {
        props: {
            to: {
                type: String | Object,
                required: true
            }
        },
        render(h) {// h 有三个参数,第一个参数创建的元素,第二个参数元素具有的属性, 第三个参数元素的内容
            const router = this.$router;
            if (router.options.mode === 'hash') {
                return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
            } else if (router.options.mode === 'history') {
                return h('a', {
                    attrs: { href: this.to },
                    on: {
                        'click': ev => {
                            // 1. 阻止a链接的默认跳转行为
                            ev.preventDefault()
                            // 2. 调用pushState方法来实现跳转: pushState(obj, title, url)
                            history.pushState({}, '', this.to)
                            // 3. 设置current的值
                            router.current = this.to;
                        }
                    }
                }, this.$slots.default)
            }
        }
    })
    //创建router-view组件
    Vue.component('router-view', {
        // 组件要重新渲染,必须要让数据发生改变的时候,重新去执行render函数
        render(h) {
            const router = this.$router
            console.log(router.routesMap, 'routesMap');
            let component = router.routesMap[router.current];//组件
            console.log(component, 'component');
            //获取到外部传递的路由表
            return h(component)
        }
    })
}

这一期我们讲解了,如何实现一个基本的hash路由模式以及history路由模式,但是我们通常使用情况下路由嵌套通过一级路由下定义children属性来定义二级路由,这并没有实现,下一期来实现路由嵌套。

到此这篇关于vue中两种路由模式的实现详解的文章就介绍到这了,更多相关vue路由模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • vue登录以及权限验证相关的实现

    vue登录以及权限验证相关的实现

    这篇文章主要介绍了vue登录以及权限验证相关的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-10-10
  • vue组件定义,全局、局部组件,配合模板及动态组件功能示例

    vue组件定义,全局、局部组件,配合模板及动态组件功能示例

    这篇文章主要介绍了vue组件定义,全局、局部组件,配合模板及动态组件功能,结合实例形式分析了vue.js中组件的定义、全局组件、局部组件、配合模板组件及动态组件的相关使用方法与操作注意事项,需要的朋友可以参考下
    2019-03-03
  • vue3的动态组件是如何工作的

    vue3的动态组件是如何工作的

    这篇文章主要介绍了vue3的动态组件是如何工作的,帮助大家更好的理解和学习使用vue框架,感兴趣的朋友可以了解下
    2021-03-03
  • VNode虚拟节点实例简析

    VNode虚拟节点实例简析

    这篇文章主要介绍了VNode虚拟节点,结合实例形式分析了VNode虚拟节点的基本功能、原理与实现方法,需要的朋友可以参考下
    2023-06-06
  • Vue 3.0 v-for中的Ref数组用法小结

    Vue 3.0 v-for中的Ref数组用法小结

    在 Vue 2 中,在 v-for 里使用的 ref attribute会用ref 数组填充相应的 $refs property,本文给大家介绍Vue 3.0 v-for中的Ref数组的相关知识,感兴趣的朋友一起看看吧
    2023-12-12
  • vue的指令和插值问题汇总

    vue的指令和插值问题汇总

    Vue 是一套用于构建用户界面的渐进式框架,Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合,这篇文章主要介绍了vue的指令和插值总结,需要的朋友可以参考下
    2022-10-10
  • Vue取消Axios发出的请求

    Vue取消Axios发出的请求

    axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。首先需要知道:axios不是一种新的技术。axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范
    2022-09-09
  • vue+echarts5实现中国地图的示例代码

    vue+echarts5实现中国地图的示例代码

    本文主要介绍了vue+echarts5实现中国地图的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • 基于vue.js组件实现分页效果

    基于vue.js组件实现分页效果

    这篇文章主要为大家详细介绍了基于vue.js组件实现分页效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-12-12
  • 如何使用Vue3实现文章内容中多个"关键词"标记高亮显示

    如何使用Vue3实现文章内容中多个"关键词"标记高亮显示

    高亮显示是我们日常开发中经常会遇到的需求,下面这篇文章主要给大家介绍了关于如何使用Vue3实现文章内容中多个"关键词"标记高亮显示的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-11-11

最新评论