首页 > 其他分享 >第143篇:手写vue-router,实现router-view

第143篇:手写vue-router,实现router-view

时间:2024-03-12 18:44:20浏览次数:26  
标签:vue 143 route component current Vue router options

好家伙,

 

今天来手写我们的老伙计vue-router,

 

1.替换router

新开一个项目,并使用我们手写的router

 

2.大致结构

let Vue; // 保存vue的构造函数
class VueRouter {
    constructor(options) {
        
    }
}

VueRouter.install = (_Vue) => {
    Vue = _Vue; //备份Vue

    Vue.mixin({
        beforeCreate() {
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router;
            }
        }
    })
    Vue.component("router-link", {});

    //实现思路,找到对应的组件并将它渲染出来
    Vue.component("router-view", {});

}

export default VueRouter;

  2.1.这里使用Vue.mixin(),使任何组件都能调用到router

  2.2.Vue = _Vue,一会要用到Vue的方法,将某个变量变为响应式的

 

 

 

3.router-link实现

  3.1.组件的使用

 

  3.2.实现

Vue.component("router-link", {
        props: {
            to: {
                type: String,
                required: true,
            },
        },
        render(h) {
            return h("a", {
                attrs: {
                    href: `#${this.to}`
                }
            }, this.$slots.default);
        }
    });

  重点来了,为什么要用个#?

  在这段代码中,使用 # 的目的是为了在单页面应用(SPA)中实现基于 hash 的路由。在传统的单页面应用中,通过改变 URL 中的 hash   部分来切换页面内容,而不会导致整个页面重新加载。这种方式被称为 hash 模式路由。

  具体来说,当用户点击带有 # 的链接时,浏览器会更新 URL 中的 hash 部分,但不会触发整个页面的重新加载,而是根据新的 hash 值来  更新页面内容,从而实现页面的切换和路由导航。

  在 Vue 中,使用 # 可以帮助我们正确地处理 hash 模式路由。

 

4.实现router-view

Vue.component("router-view", {
        render(h) {
            let component = null;
            //获取当前路由所对应的组件并将它渲染出来
            const current = this.$router.current;
            const route = this.$router.$options.routes.find((route) => 
                route.path === current
            )
            // const route = this.$router.$options.routes.find((route) => 
            //     {route.path === current}
            // )
            //!!错误
            //若使用箭头函数块{},必须要有返回值
            
            console.log(route, current)
            if (route) {
                component = route.component
            }


            return h(component);
        }
    });

  总体上看,代码逻辑非常简单,在router中找到匹配的组件,然后返回相应的组件就好了,但问题来了,我怎么知道当前页面current是什么?

 

5.实现VueRouter

class VueRouter {
    constructor(options) {
        this.$options = options;

        this.current = "/";

        let initial = window.location.hash.slice(1) || "/"

        Vue.util.defineReactive(this, "current", initial)

        window.addEventListener("hashchange", () => {
            this.current = window.location.hash.slice(1) || "/"
            console.log(this.current)
        })
    }
}

     第一步:开始我们默认this.current = "/"; 即首页,

  第二步:将current变为响应式数据,

  第三步:让current动态获取当前路由的值

问:为什么要将current变为响应式数据?

答:render的更新依赖于响应式数据curren,若current不为响应式数据,current变化,render不会重新渲染

 

搞定

 

6.源码

let Vue; // 保存vue的构造函数
class VueRouter {
    constructor(options) {
        this.$options = options;

        this.current = "/";

        let initial = window.location.hash.slice(1) || "/"

        Vue.util.defineReactive(this, "current", initial)

        window.addEventListener("hashchange", () => {
            this.current = window.location.hash.slice(1) || "/"
            console.log(this.current)
        })
    }
}

VueRouter.install = (_Vue) => {
    Vue = _Vue; //备份Vue

    Vue.mixin({
        beforeCreate() {
            if (this.$options.router) {
                Vue.prototype.$router = this.$options.router;
            }
        }
    })
    Vue.component("router-link", {
        props: {
            to: {
                type: String,
                required: true,
            },
        },
        render(h) {
            return h("a", {
                attrs: {
                    href: `#${this.to}`
                }
            }, this.$slots.default);
        }
    });

    //实现思路,找到对应的组件并将它渲染出来
    Vue.component("router-view", {
        render(h) {
            let component = null;
            //获取当前路由所对应的组件并将它渲染出来
            const current = this.$router.current;
            // const route = this.$router.$options.routes.find((route) => 
            //     route.path === current
            // )
            const route = this.$router.$options.routes.find((route) => 
                {return route.path === current}
            )
            //!!错误
            //若使用箭头函数块{},必须要有返回值

            console.log(route, current)
            if (route) {
                component = route.component
            }


            return h(component);
        }
    });

}

export default VueRouter;

 

 

7.补充

一个小小bug

const route = this.$router.$options.routes.find((route) => 
                route.path === current
            )

不能写成

const route = this.$router.$options.routes.find((route) => 
       {route.path === current}
)

第一段代码使用了简洁的箭头函数写法,直接返回了 route.path === current 的结果。这种写法适用于只有一行代码的情况,箭头函数会自动将这一行代码的结果作为返回值。因此,第一段代码会返回第一个满足条件 route.path === current 的 route 对象。

第二段代码使用了代码块 {} 包裹起来,但在代码块中没有显式返回值。这种情况下,箭头函数不会自动返回代码块中的结果,需要手动添加 return 关键字来返回值。因此,第二段代码中的箭头函数没有正确返回值,会导致代码出错。

所以,若要使用代码块 {}

const route = this.$router.$options.routes.find((route) => 
                {return route.path === current}
            )

 

标签:vue,143,route,component,current,Vue,router,options
From: https://www.cnblogs.com/FatTiger4399/p/18068833

相关文章

  • Vue:表单修饰符(.lazy/.number/.trim)
    一、v-model.lazy默认情况下,v-model 会在每次 input 事件后更新数据。也就是说在每次输入时都会改变绑定的值。例如,在下面的代码中,每次在输入框中输入时,number都会立即改变{{number}}<inputtype="text"v-model="number"/>有时候我们希望在一次输入结束后再......
  • 【Springboot】--如何将springboot+vue项目部署到云服务器?
    目录一、准备工作1、购买云服务器2、获取面板地址二、jdk和数据库1、安装环境 2、配置jdk环境变量3、java版本的问题4、添加数据库三、前端部署 1、vue2、创建站点​编辑四、后端部署1、application.yml2、idea打包3、运行jar包4、开放端口五、可能遇到的......
  • 搭建Vue项目报yarn错误
    搭建Vue项目时(3/2)都会报一个Error:commandfailed:yarn的错误不废话直接上解决办法主要是这里出了问题,yarn不兼容当前模块,你只需要执行一句yarnconfigsetignore-enginestrue就完美解决了......
  • Vue2.x笔记:组件通信
    一、插槽slot插槽(slot)是一种Vue中组件通信的方式,主要用于父组件向子组件传递自定义内容。有三种插槽:默认插槽:最基本的插槽,没有任何标识,每个子组件只能定义一个具名插槽:具有name属性的默认插槽,每个子组件可以定义多个作用域插槽:子组件提供数据,由父组件决定其渲染方式1.默......
  • 创建Vue3项目,更多参考vue官网
     一、环境:1、Node版本(node-v命令查询,参考则是需要18.0及以上)C:\Users\86176>node-vv16.14.0后续又重新下载nvm进行新的版本安装,这里后面安装的19.0的也有错误,安装18.19.12、vue-cil版本(vue-V命令可查询电脑版本,参需3.0以上)C:\Users\86176>vue-V@vue/cli5.0.83、其他......
  • vue里面修改title样式
    今天遇到一个需求:鼠标滑过一个模块,提示框会随着鼠标移动而移动标签的title属性具有这个效果,但是标签title的默认样式太丑<template> <divclass=".item-title"title="点击查看详情"></div></template>前提:安装jquery然后再导入import$fromjquerymounted(){$(function()......
  • Vue 3 组件通信与 ViewDesign 最佳实践
    Vue3组件通信与ViewDesign最佳实践随着Vue3的发布,组件通信成为了前端开发中一个值得关注的话题。通过有效的组件通信方式,可以大幅提高代码的可维护性和可重用性。本文将探讨Vue3中组件通信的几种方式,并使用ViewDesign组件库中的实例加以说明。ViewDesign是一款......
  • vue3+elementplus(ElementUI)入门案例
    1、配置脚手架,已配置则无需再配npminstall-gvue-cli2、创建空文件夹,用vscode打开,并在vscode终端执行如下命令vuecreateXXXcdXXX3、安装elementplus插件,注意:vue3需要搭配elementplus使用,elementplus是elementui的升级版,需搭配vue3使用(初学者建议直接学vue3+elemen......
  • 基于Vue(提供Vue2/Vue3版本)和.Net Core前后端分离、跨平台的快速开发框架
    前言今天大姚给大家推荐一款基于Vue(提供Vue2/Vue3版本)和.NetCore前后端分离、开源免费(MITLicense)、强大、跨平台的快速开发框架,并且框架内置代码生成器(解决重复性工作,提高开发效率),支持移动端(iOS/Android/H5/微信小程序):Vue.NetCore。提高开发生产效率、避免996可以考虑试试这......
  • vue自定义指令
    这里记录下,自定义指令相关思路,用到vue3+elementplus:说明一下使用场景:创建自定义指令v-hasPermi,用来判断按钮权限的(新增/编辑/删除/查看等)。1.页面使用(全局使用,无需引入):<el-buttontype="primary"icon="Plus"plainv-hasPermi="['bid:bidding:save']">添加</el-butt......