最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 模拟实现 Vue Router

    正文概述 掘金(Yaping)   2020-12-25   437

    创建Vue项目

    • 首先我们通过vue create vueApp 来创建一个vue的项目,
    • 进入vueApp 后执行vue add router 载入vue-router
    • 执行npm run serve打开浏览器,发现我们的项目已经初始化完成了

    Vue Router 分析

    首先我们对Vue Router功能进行简单的分析:

    1. 他是前端路由,当路径切换的时候,在浏览器端判断路径,并加载当前路径对应的组件
    2. 他有两种模式,一种是hash,一种是history
      • hash模式是基于锚点,以及onhashchange事件
      • history模式是基于html5只不过的History API
        • history.pushState() IE10以后才支持
        • history.replaceState()
      • history简单的工作流程
        • 通过 history.pushState()方法改变地址栏
        • 监听 popstate 事件
        • 根据当前路由地址找到对应组件重新渲染
    3. 接下来我们去项目中看下vue-router 是如何使用的

    模拟实现 Vue Router

    1. 下面是VueRouter的一个类图,我们接下来根据这个类图来实现VueRouter

    模拟实现 Vue Router

    模拟实现Vue Router

    回到刚创建的vueApp项目中,在src下创建一个vuerouter文件夹,并添加index.js在这个文件夹,此文件夹存放我们自己写的vue-router模块,在index.js中进行开发

    install 方法

    install的分析

    1. Vue.use()调用VueRouter时会传递两个参数,一个是Vue的构造函数,第二个是可选的选项对象(本文中没用到这个参数)
    2. install是一个静态方法静态方法,接收VueRouter传递的两个参数
    3. 函数内部首先判断下这个插件是否被安装
    4. 在全局作用域储存Vue构造函数(后面还需要调用Vue构造函数)
    5. 把创建Vue实例时传入的router对象,注入到所有Vue实例上(this.$router就是在这个时候注册到Vue实例上的)

    代码实现

    let _Vue = null
    export default class VueRouter {
      static install(Vue){
        if(VueRouter.install.installed) {
          return
        }
        VueRouter.install.installed = true
        _Vue = Vue
        _Vue.mixin({
          beforeCreate(){
            if(this.$options.router){
              _Vue.prototype.$router = this.$options.router;
              this.$options.router.init() // 调用init()方法,此方法定义在下文中可以看到
            }
          }
        })
      }
    }
    
    

    构造函数

    构造函数分析

    1. 观察上文中的类图,发现构造函数接收一个参数options
    2. 在构造函数中初始化类图中的三个属性
      • options:存储传入的参数options
      • routeMap: 存储键值对,值可以从传入options中routes里面中拿到,键:path, 值:component
      • data 是一个响应式对象,里面current存放当前的路由地址

    代码实现

    constructor(options) {
      this.options = options
      this.routeMap = {} 
      this.data =  _Vue.ovservable({
        current: '/'
      })
    }
    

    createRouteMap

    函数分析

    1. 遍历所有的路由规则(options.route),把路由规则转换成上文说的键值对形式 存在routeMap对象中去

    代码实现

    createRouteMap(){
      this.options.routes.forEach(route => {
        this.routeMap[route.path] = route.component
      })
    }
    

    initComponents

    函数分析

    1. 这个方法接收一个Vue构造函数(也可以不去传这个参数,因为我们在全局已经存储到_Vue了,这样做的目的是为了减少此模块对其他模块的依赖)
    2. 这个方法是创建router-link组件
      • router-link在使用的时候,传入了to属性
      • router-link最终渲染的时候是一个a标签
      • router-link中间会有一些展示内容

    代码实现

    ? template参数方式创建会有些小坑,后面会说到

    initComponents(Vue){
      Vue.component('router-link',{
        props: {
          to: String,
        },
        template: '<a :herf="to"><slot></slot></a>' 
      })
    }
    

    init函数

    这个函数没什么特别的 就是帮助我们执行一些初始化的方法

    init(){
      this.createRouteMap()
      this.initComponents(_Vue)
    }
    // 在instll中调用,调用位置参看上面的install方法
    
    • 初始化完成后去修改router.js文件中导入VueRouter的模块,然后重新运行项目

    模拟实现 Vue Router

    • 运行后报错,You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build . 我们正在使用只包含运行版本的Vue,模板编译器不可用,这里就引出了关于Vue构建版本的问题

    Vue构建版本

    • 运行时版: 不支持template模板,需要打包的时候提前编译
    • 完整版:包含运行时编译器的完整版,体积比运行时版本大10K左右,程序运行的时候把模板转换成render函数

    解决方法

    ? 来解决上面说的template参数的坑啦,两种方式解决:1.使用Vue完整版 2.使用render函数

    • 使用Vue完整版

    思路就是将当前运行时版改成完整版,创建vue.config.js

    module.exports={
      runtimeCompiler: true // 启动包含运行时编译器的完整版
    }
    

    这个方法主要是开启完整版,对于配置的具体说明本文就不过多赘述,详情可以参考vue官方文档

    • 使用render函数
    initComponents(Vue){
      Vue.component('router-link',{
        props: {
          to: String,
        },
        render(h){
          return h('a', {
            attrs: {
              herf: this.to
            },
          },[this.$slots.default]);
        }
        // template: '<a :herf="to"><slot></slot></a>'
      })
    }
    

    router-view组件

    组件分析

    • 相当于一个占位符,在这个组件内部,根据当前的路由地址获取到对应的组件,并渲染到router-view的位置
    • 在initComponents 函数中继续创建router-view组件
    • 上面我们已经知道如何去创建一个组件,现在思考一下在创建组件的render函数中需要进行什么样的操作
      • 获取到当前的路由地址,根据路由地址在routeMap中找到对应的组件
      • 然后调用h函数帮我们把找到的组件转成虚拟dom返回
    initComponents(Vue){
      Vue.component('router-link',{
        props: {
          to: String,
        },
        render(h){
          return h('a', {
            attrs: {
              herf: this.to
            },
            on: {
              click: this.clickHandler
            }
          },[this.$slots.default]);
        },
        methods: {
          clickHandler(e){
            // 改变浏览器地址栏,但是不会向浏览器发请求
            history.pushState({}, '', this.to)
            // 把当前路径记录到current里面
            this.$router.data.current = this.to
            e.preventDefault();
          }
        }
        // template: '<a :herf="to"><slot></slot></a>'
      })
      const self = this
      Vue.component('router-view',{
        render(h){
          const component = self.routeMap[self.data.current]
          return h(component)
        }
      })
    
    }
    
    

    initEvent

    • 点击浏览器的前进和后退按钮,地址栏发生了改变,但是视图没有发生变化,下面我来解决这个问题
    • 这个方法的作用是用来注册popstate事件
    initEvent(){
      window.addEventListener('popstate',()=>{
        this.data.current = window.location.pathname
      })
    }
    // 然后在init方法中调用此方法
    

    起源地下载网 » 模拟实现 Vue Router

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元