ziwei3749 / blog

已停止更新..转移至 https://segmentfault.com/u/ziwei3749
9 stars 1 forks source link

几天vue-route的学习成果 #13

Open ziwei3749 opened 6 years ago

ziwei3749 commented 6 years ago

vue-router学习成果

经过几天的研究,对以下问题做了一些探究:

1.前端路由是什么?

本质上前端路由: 前端监听和解析url的变化,并匹配url对应的页面

2.思考实现一个前端路由需要具备哪些功能

我觉得最起码需要有2个功能

打开动作

如果是模拟的话,div的显示隐藏就可以了。

实际上vue-router用起来,有router-view组件,这里渲染的内容,可以通过routes配置

routes是一个数组,里面写着path和components的映射关系

历史记录操作单

那hash变化自动就会有一个历史记录
html5新增加的history.pushState也增加历史记录。

所以这2个api都具备实现前端路由的能力

3.前端路由2种实现方式的区别和注意事项

hash 和 history的区别

history模式的话需要后端做一个配置,如果这个url匹配到任何路由,那不要返回404,而是返回Index.html

但是这样,你如果url不匹配,也永远没有404了,vue为例子的话,routes里需要配置path:* 对应一个404页面

4.【代码实现】基础路由实现代码,以hash

html

<ul>
    <a href="#/"></a>
    <a href="#/about"></a>
    <a href="#/topics"></a>
</ul>

<div id="router-view"></div>

调用方式

var router = new Router()
var routerView = document.querySelector('#router-view')
router.init()

 // 这里是注册路由,指定url对应做什么事情。有点routes里指定path和component的对应关系
router.route('/',() => {           
    routerView.innerHTML = 'home'
})
router.route('/about',() => {
    routerView.innerHTML = 'about'
})
router.route('/topics',() => {
    routerView.innerHTML = 'topics'
})

实现hash路由

class Router{
    construtor() {
        this.routes = {}     // 存放path和 fn的映射关系
    }

    route(path,fn){
        this.routes[path] = fn
    }

    updateView(){
        // 获取hash就知道执行哪个fn,显示哪个页面了
        var url = window.location.hash.substr(1)
        this.routes[url]()
    }

    init(){
        window.addEventListenr('hashchange',() => {
            this.updateView()
        })
        window.addEventListenr('load',() => {
            this.updateView()
        })
    }

}

梳理一下过程


那为什么不用history实现呢,因为History要多考虑一些地方,pushState并不能触发popstate的变化

既然通过popstate监听不太靠谱,那如何拦截各种情况下路由的变化的

其实路由的变化,就3个情况

在点击a标签或者pushState时去updateView一下,在源码中其实有一个render,需要用这个方法去更新页面

基本就是这一个思路,(注意history跳转时跨域问题)

5.【vue-router源码学习】vue-router源码中学习到的技巧

我是看的v2.03版本,后来有看了一眼vue-router@3.01的版本,目录结构和写法也不一样

目录结构

技巧1.mian.js入口文件,我们一般引入vue-router后,需要Vue.use(VueRouter)

这个是Vue提供的插件机制,这个机制就是Vue会调用插件的install方法(如果没有的话就把插件自身作为函数调用)

技巧2.插件打包时肯定不希望把整个Vue打包进去,但是又希望使用Vue对象的方法,所以就可以在install时赋值

去看index.js的话,vue-rotuer这个插件是有install方法,单独写install.js文件里

_Vue = Vue

技巧3: Object.defineProperty给Vue.prototype添加$router和$route,这样可以让所有Vue都有这2个属性

技巧4: 有一些嘈杂哦判断你的 mode和fallback

this.fallback = mode === 'history' && !supportsHistory if (this.fallback) { mode = 'hash' }

switch (mode) { case 'history': this.history = new HTML5History(this, options.base) break case 'hash': this.history = new HashHistory(this, options.base, this.fallback) break case 'abstract': this.history = new AbstractHistory(this) break default: assert(false, invalid mode: ${mode}) }

yancongwen commented 5 years ago

写的不错,学习一下