美文网首页Vue技术探究Vue.js专区
Vue源码分析(10)--实例分析computed和watch

Vue源码分析(10)--实例分析computed和watch

作者: 风之化身呀 | 来源:发表于2017-07-08 16:46 被阅读86次

前言

本文是vue2.x源码分析的第十篇,主要看computed和watch的处理过程!

实例代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Vue</title>
  <script src="./vue10.js" type="text/javascript" charset="utf-8" ></script>
</head>
<body>
  <div id="app">
    {{messages}}
  </div>
  <script>
    var vm=new Vue({
      el:'#app',
      name:'app',
      data:{
        message:'message'
      },
      computed:{
        messages(){
            return this.message+'s'
        }
      },
      watch:{
        message(){
            alert('message changed!')
        }
      }
    });
    debugger;
    setTimeout(
        ()=>{
            vm.message='messages'
        }
    ,0)
  </script>
</body>
</html>

1 computed

关键断点
initState(vm);
if (opts.computed) { initComputed(vm, opts.computed); }
watchers[key] = new Watcher(vm, getter, noop,
computedWatcherOptions);//option中lazy:true导致watcher.get不执行,从而该watcher不收集dep,dep也不订阅该watcher
defineComputed(vm, key, userDef);
看下defineComputed

    function defineComputed (target, key, userDef) {
      if (typeof userDef === 'function') {
        sharedPropertyDefinition.get = createComputedGetter(key);
        sharedPropertyDefinition.set = noop;
      } else {
        sharedPropertyDefinition.get = userDef.get
          ? userDef.cache !== false
            ? createComputedGetter(key)
            : userDef.get
          : noop;
        sharedPropertyDefinition.set = userDef.set
          ? userDef.set
          : noop;
      }
      Object.defineProperty(target, key, sharedPropertyDefinition);
}

一句话总结computed原理:通过Object.defineProperty将计算属性的key(即messages)定义为vm的存取器属性,该key的get函数即是计算属性的value(即messages对应的函数),key的更新随着它所依赖的data中的某个属性一同更新

2 watch

关键断点
initState(vm);
if (opts.watch) { initWatch(vm, opts.watch); }
createWatcher(vm, key, handler);
vm.$watch(key, handler, options);
看下该函数:

    Vue.prototype.$watch = function (expOrFn,cb, options) {
        var vm = this;
        options = options || {};
        options.user = true;  //user watcher
        var watcher = new Watcher(vm, expOrFn, cb, options);
        if (options.immediate) {
          cb.call(vm, watcher.value);
        }
        return function unwatchFn () {
          watcher.teardown();
        }
    };
    var Watcher = function Watcher (vm,expOrFn,cb,options) {
      ...
      this.user=true;
      this.cb = cb;
      ...
      // parse expression for getter
      if (typeof expOrFn === 'function') { render watcher从这儿进
        this.getter = expOrFn;
      } else {
        this.getter = parsePath(expOrFn);  user watcher从这儿进
      }
      this.value = this.lazy
        ? undefined
        : this.get();
    };

接下来和render watcher一样执行get函数,然后message的dep订阅该user watcher,随后message的dep又订阅render watcher,也就是说message的dep.sub数组中有两个watcher,分别是user watcher和render watcher,页面初次渲染时user watcher不起什么作用,当message值改变导致页面更新时,先执行user watcher,这会执行该watcher.cb函数也即定义watch时的message的回调函数,从而实现了watch监控message变化的功能,然后执行render watcher实现页面更新。

相关文章

网友评论

    本文标题:Vue源码分析(10)--实例分析computed和watch

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