vue插件

作者: 百里哈哈 | 来源:发表于2019-02-13 11:02 被阅读0次

    vuex

    函数过程
    new Store() -> (resetStoreVM)installModule -> (getNamespace, registerMutation, registerAction, registerGetter) makeLocalContext ->(dispatch、commit、getters、state)

    resetStoreVM -> (wrappedGetters, new Vue(…))


    vue-router

    导航守卫中为什么需要手动触发next
    其主要代码如下

    function runQueue (queue, fn, cb) {
      var step = function (index) {
        if (index >= queue.length) {
          cb();
        } else {
          if (queue[index]) {
            fn(queue[index], function () {
              step(index + 1);
            });
          } else {
            step(index + 1);
          }
        }
      };
      step(0);
    }
    

    通过runQueue触发守卫队列函数

    var iterator = function (hook, next) {
        if (this$1.pending !== route) {
          return abort()
        }
        try {
          hook(route, current, function (to) {
            if (to === false || isError(to)) {
              // next(false) -> abort navigation, ensure current URL
              this$1.ensureURL(true);
              abort(to);
            } else if (
              typeof to === 'string' ||
              (typeof to === 'object' && (
                typeof to.path === 'string' ||
                typeof to.name === 'string'
              ))
            ) {
              // next('/') or next({ path: '/' }) -> redirect
              abort();
              if (typeof to === 'object' && to.replace) {
                this$1.replace(to);
              } else {
                this$1.push(to);
              }
            } else {
              // confirm transition and pass on the value
              next(to);
            }
          });
        } catch (e) {
          abort(e);
        }
      };
    

    通过iterator实现一个迭代器
    runQueue方法调用

    runQueue(queue, iterator, function () {
        var postEnterCbs = [];
        var isValid = function () { return this$1.current === route; };
        // wait until async components are resolved before
        // extracting in-component enter guards
        var enterGuards = extractEnterGuards(activated, postEnterCbs, isValid);
        var queue = enterGuards.concat(this$1.router.resolveHooks);
        runQueue(queue, iterator, function () {
          if (this$1.pending !== route) {
            return abort()
          }
          this$1.pending = null;
          onComplete(route);
          if (this$1.router.app) {
            this$1.router.app.$nextTick(function () {
              postEnterCbs.forEach(function (cb) { cb(); });
            });
          }
        });
      });
    

    有runQueue方法可知, iterator即为指向runQueue中的fn参数
    iterator方法中的hook(route, current, function (to) {…})即为触发的钩子函数
    所以当触发钩子函数而不执行function (to){}这个方法时,也就没有触发iterator中的next方法。此时导航守卫钩子函数队列的执行被终止。

    vue-router有哪几种导航钩子

    在回答这个问题之前我先多说几句做个铺垫
    先说钩子函数吧,钩子函数在前端是个神奇的存在,在框架模型的生命周期中的不同有时候你想做一些不可描述的事情,怎么办那就注册回调呗。而钩子函数用来挂载这些回调的。

    再说生命周期吧,个人意见呀,前端开发多涉及到视图变换,而视图变换的过程可以将其理解为一个生命周期

    接下来说说路由这件事情。 举个栗子,假设存在 a, b两个路径 有a切换到B这是一个过程在, 在这个过程中涉及到A的离开 B的进入,A离开前、离开后、B进入前进入后,我们希望在这些节点可以做一些事情,这时就要考虑设计自身的钩子函数; 我们有时候也会希望 在进入A的过程中、进入B的过程中都调用同样的方法,那么全局钩子就应运而生了。

    在窥探源码可知,实现导航队列时,会将这些钩子函数进行封装,然后放入queue这个变量中。
    queue的主要代码如下所示

    var queue = [].concat(
        // in-component leave guards
        extractLeaveGuards(deactivated),
        // global before hooks
        this.router.beforeHooks,
        // in-component update hooks
        extractUpdateHooks(updated),
        // in-config enter guards
        activated.map(function (m) { return m.beforeEnter; }),
        // async components
        resolveAsyncComponents(activated)
      );
    
    var queue = enterGuards.concat(this$1.router.resolveHooks);
    

    vue-router的导航守卫 包括全局守卫 beforeenter, beforeresolved, afterEnter 独立路由守卫 beforeenter ; 还有就是组件级的包括 beforerouterenter 、 beforerouterupdated、 beforerouterleaved ; 从思路上来说大概就这些。

    然后接下来在举过例子阐述这些钩子发生的过程

    还用AB这两个导航来说吧 。 第一种情况 我们首次进入A 发生的过程是 beforeenter- beforeenter-beforerouterenter-beforesolved-模板更新-afterenter ;

    第二中情况有A切换进入B 多了一个A离开时的回调

    第三种情况是由B的参数改变而产生的一系列的变化 beforeenter—beforerouterupdated-beforesolved-模板更新-afterenter ;

    路径切换流程
    init -> transitionTo -> confirmTransition -> updateRoute -> afterHooks
    push -> transitionTo ->pushHash -> pushState、getUrl -> saveScrollPosition

    监听浏览器路径切换
    setupListeners -> window.addEventListener(supportsPushState ? ‘popstate’ :’hash change’

    ** popstate事件**
    当活动历史记录条目更改时,将触发popstate事件。
    需要注意的是调用history.pushState()或history.replaceState()不会触发popstate事件。只有在做出浏览器动作时,才会触发该事件,如用户点击浏览器的回退按钮(或者在Javascript代码中调用history.back())

    window.addEventListener('popstate', function (e) {
          var current = this$1.current;
    
          // Avoiding first `popstate` event dispatched in some browsers but first
          // history route not updated since async guard at the same time.
          var location = getLocation(this$1.base);
          if (this$1.current === START && location === initLocation) {
            return
          }
    
          this$1.transitionTo(location, function (route) {
            if (expectScroll) {
              handleScroll(router, route, current, true);
            }
          });
        });
    

    ensureURL函数
    当前路径不等于getHash时所进行的路径操作

    HashHistory.prototype.ensureURL = function ensureURL (push) {
        var current = this.current.fullPath;
        if (getHash() !== current) {
          push ? pushHash(current) : replaceHash(current);
        }
      };
    

    replaceHash->replaceState、 getUrl -> pushState -> saveScrollPosition(history.pushState)-> getStateKey ->

    路由切换视图变更

    在路由view组件渲染时会获取其父元素上挂载的$router对象,在初始化阶段对该对象进行自动监听的绑定。
    当改值发生变化时会引起其父组件的重新渲染
    主要代码如下

    Vue.mixin({
        beforeCreate: function beforeCreate () {
          if (isDef(this.$options.router)) {
            this._routerRoot = this;
            this._router = this.$options.router;
            this._router.init(this);
            Vue.util.defineReactive(this, '_route', this._router.history.current);
          } else {
            this._routerRoot = (this.$parent && this.$parent._routerRoot) || this;
          }
          registerInstance(this, this);
        },
        destroyed: function destroyed () {
          registerInstance(this);
        }
      });
    
    Object.defineProperty(Vue.prototype, '$route', {
        get: function get () { return this._routerRoot._route }
      });
    
    this$1.updateRoute(route);
    
    var handler = function (e) {
          if (guardEvent(e)) {
            if (this$1.replace) {
              router.replace(location);
            } else {
              router.push(location);
            }
          }
        };
    

    location指向当前link对应的路由对象
    window.history 与 hash模式

    1.hash ---- 利用URL中的hash(“#”)
    2.利用History interface在 HTML5中新增的方法

    window.history是用来保存用户在一个会话期间的网站访问记录,并提供相应的方法进行追溯。其对应的成员如下:
    方法:back()、forward()、go(num)、pushState(stateData, title, url)、replaceState(stateData, title, url)
    属性:length、state
    事件:window.onpopstate
    back():回退到上一个访问记录;
    forward():前进到下一个访问记录;
    go(num):跳转到相应的访问记录;其中num大于0,则前进;小于0,则后退;
    pushState(stateData, title, url):在history中创建一个新的访问记录,不能跨域,且不造成页面刷新;
    replaceState(stateData, title, url):修改当前的访问记录,不能跨域,且不造成页面刷新;

    值得注意的是,通过pushState新增或者修改的history记录,被访问时,当前页面不刷新。而locaiton.href生成的记录被访问时,页面将进行刷新。
    浏览器history变化图示

    history

    相关文章

      网友评论

          本文标题:vue插件

          本文链接:https://www.haomeiwen.com/subject/nqmreqtx.html