IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> Vue-Router原理实现 -> 正文阅读

[JavaScript知识库]Vue-Router原理实现

Vue-Router原理实现

VueRouter使用步骤

  1. 首先,在router/index.js 中引入VueVueRouter,使用Vue.use(VueRouter)注册插件。use方法接收一个方法或对象。若传入的是方法,则会调用该方法;若传入的是对象,则会调用该对象的install方法。

  2. 定义路由规则routes,使用new VueRouter({routes})创建router对象

    // router/index.js
    
    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import Index from '../views/Index.vue'
    // 1. 注册路由插件
    Vue.use(VueRouter)
    
    // 路由规则
    const routes =[
      {
        path: '/',
        name: 'Index',
        component: Index
      },
    ]
    // 2. 创建 router 对象
    const router = new VueRouter({
      routes
    })
    
    export default router
    
  3. 在mian.js 中引入定义好的router,并在new Vue实例的时候进行注册

    // main.js
    
    import Vue from 'vue'
    import App from './App.vue'
    import router from './router'
    
    Vue.config.productionTip = false
    
    new Vue({
      // 3. 注册 router 对象
      router,
      render: h => h(App)
    }).$mount('#app')
    
    
  4. 在页面中使用<router-view/>创建路由占位符,通过<router-link to='pathName'>name</router-link>的方式创建路由链接。

    <div id="nav">
      <!-- 5. 创建链接 -->
      <router-link to="/">Index</router-link> |
      <router-link to="/blog">Blog</router-link> |
      <router-link to="/photo">Photo</router-link>
    </div>
    <!-- 4. 创建路由组建的占位 -->
    <router-view/>
    

路由模式

均为客户端路由,路径变化时不会向服务器发送请求

hash模式
https://music.163.com/#/playlist?id=123

原理:

Hash模式是基于锚点,以及onhashchange事件。通过锚点的值作为路由地址,当地址发生变化时,触发onhashchange事件,根据路径决定页面内容。可以使用location.href改变路由地址

history模式

History模式需要服务器支持(单页应用不存在.../playlist/123这样的地址,请求时会返回404),在服务端应该除了静态资源外都返回单页应用的index.html

https://music.163.com/playlist/123

原理:

History模式是基于HTML5中的History API,以及popstate事件。当地址发生变化时,会根据当前路由地址找到对应组件进行渲染。

// IE10以后才支持,不会向服务器发送请求,只会改变地址栏地址,并且将地址记录到历史记录中。
history.pushState()
// 改变地址栏地址,并替换当前历史记录
history.replaceState()
history.go()

// 注意:以上API不会触发popstate事件,只有点击浏览器前进后退按钮或调用history的back或forward方法时,才会触发popstate事件

开启history模式

const router = new VueRouter({
// mode: 'hash',
mode: 'history',
routes
})

模拟实现VueRouter

核心代码分析
  • VueRouter应为一个类或一个对象,应该包含一个install方法,用于注册插件
  • VueRouter的构造函数需要接收一个对象参数,对象参数中应传入路由规则(记录了路径和对应组件)
  • 在创建Vue实例的时候将VueRouter的实例对象传入
// router/index.js
// 注册组件
Vue.use(VueRouter) //内部调用传入对象的 install 方法
// 创建路由对象
const router = new VueRouter({
	routes:[
		{name: 'home', path: '/', component: homeComponent}
	]
})

// main.js
// 创建Vue实例,注册 router 对象
new Vue({
	router,
	render: h => h(App)
}).$mount('#app')
VueRouter属性方法分析
属性
  1. options

    记录VueRouter构造函数中传入的对象

  2. data

    一个响应式对象(路由地址发生变化后,对应组件需要更新),里面有一个current属性,存放了当前的路由地址

  3. routeMap

    一个对象,用来记录路由地址与组件的对应关系

方法
  1. Constructor(Options): VueRouter

    初始化属性,调用初始化方法

  2. static install(Vue): void

    用于插件注册

  3. init(): void

    封装下面三个方法

  4. initEvent(): void

    用来注册popstate事件,监听浏览器地址变换

  5. createRouteMap(): void

    初始化routeMap属性,将路由规则转换为键值对

  6. initComponents(Vue): void

    用于创建router-linkrouter-view组件

VueRouter实现
install

Vue.use(VueRouter)时,会调用install方法

static install(Vue) {
    // 1、判断当前插件是否已经被安装
    if (VueRouter.install.installed) {
        return
    }
    VueRouter.install.installed = true
    // 2、把Vue构造函数记录到全局变量
    _Vue = Vue
    // 3、把创建Vue实例时候传入的router对象注入到Vue实例上
    // _Vue.prototype.$router = this.$options.router
    // 混入
    _Vue.mixin({
        beforeCreate() {
            // 避免组件重复注入router,仅new Vue创建的实例注入
            if (this.$options.router) {
                _Vue.prototype.$router = this.$options.router
                // 初始化路由规则、创建组件、监听popstate事件
                this.$options.router.init()
            }
        },
    })
}
constructor
// 构造函数
constructor(options) {
    this.options = options
    this.routeMap = {}
    // 响应式data
    this.data = _Vue.observable({
        // 当前路由
        current: window.location.pathname
    })
}
createRouteMap
createRouteMap() {
    // 遍历所有的路由规则,把路由规则解析成键值对的形式,存储到routeMap中
    this.options.routes.forEach(route => {
        this.routeMap[route.path] = route.component
    })
}
initComponents
initComponents(Vue) {
    // router-link
    Vue.component('router-link', {
        props: {
            to: String
        },
        // template: '<a :href="to"><slot></slot></a>'
        render(h) {
            return h('a', {
                attrs: {
                    href: this.to,
                },
                on: {
                    click: this.handleClick
                }
            }, [this.$slots.default])
        },
        methods: {
            handleClick(e) {
                // 改变浏览器地址栏
                history.pushState({}, '', this.to)
                // 访问Vue原型对象上保存的router,将当前路由地址保存到router.data.current上,此时data变化,将会重新渲染页面更新组件
                this.$router.data.current = this.to
                e.preventDefault();
            }
        },
    })
    const self = this
    // router-view
    Vue.component('router-view', {
        render(h) {
            const component = self.routeMap[self.data.current]
            return h(component)
        }
    })
}
initEvent
initEvent(){
    window.addEventListener('popstate',()=>{
        this.data.current=window.location.pathname
    })
}
init
init() {
    this.createRouteMap()
    this.initComponents(_Vue)
    this.initEvent()
}
完整代码
let _Vue = null

export default class VueRouter {
    static install(Vue) {
        // 1、判断当前插件是否已经被安装
        if (VueRouter.install.installed) {
            return
        }
        VueRouter.install.installed = true
        // 2、把Vue构造函数记录到全局变量
        _Vue = Vue
        // 3、把创建Vue实例时候传入的router对象注入到Vue实例上
        // _Vue.prototype.$router = this.$options.router
        // 混入
        _Vue.mixin({
            beforeCreate() {
                // 避免组件重复注入router,仅new Vue创建的实例注入
                if (this.$options.router) {
                    _Vue.prototype.$router = this.$options.router
                    // 初始化路由规则、创建组件、监听popstate事件
                    this.$options.router.init()
                }
            },
        })
    }

    // 构造函数
    constructor(options) {
        this.options = options
        this.routeMap = {}
        // 响应式data
        this.data = _Vue.observable({
            // 当前路由
            current: window.location.pathname
        })
    }

    init() {
        this.createRouteMap()
        this.initComponents(_Vue)
        this.initEvent()
    }

    createRouteMap() {
        // 遍历所有的路由规则,把路由规则解析成键值对的形式,存储到routeMap中
        this.options.routes.forEach(route => {
            this.routeMap[route.path] = route.component
        })
    }

    initComponents(Vue) {
        // router-link
        Vue.component('router-link', {
            props: {
                to: String
            },
            // template: '<a :href="to"><slot></slot></a>'
            render(h) {
                return h('a', {
                    attrs: {
                        href: this.to,
                    },
                    on: {
                        click: this.handleClick
                    }
                }, [this.$slots.default])
            },
            methods: {
                handleClick(e) {
                    // 改变浏览器地址栏
                    history.pushState({}, '', this.to)
                    // 访问Vue原型对象上保存的router,将当前路由地址保存到router.data.current上,此时data变化,将会重新渲染页面更新组件
                    this.$router.data.current = this.to
                    e.preventDefault();
                }
            },
        })
        const self = this
        // router-view
        Vue.component('router-view', {
            render(h) {
                const component = self.routeMap[self.data.current]
                return h(component)
            }
        })
    }

    initEvent(){
        window.addEventListener('popstate',()=>{
            this.data.current=window.location.pathname
        })
    }
}
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-07-20 18:43:07  更:2022-07-20 18:44:29 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 13:12:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码