vue源码分析之删除监听列表

<!DOCTYPE html>
<html>
    
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <title>BRACKETS 入门</title>
        <meta name="description" content="Brackets 互动式入门指引。">
        <link rel="stylesheet" href="main.css">
        <script src="./vue.js"></script>
        <script src="./text.js"></script>
        <style>
            .class1{
                width: 100px;
                height: 50px;
                background-color: red;
            }
        </style>
    </head>
    <body>
        <div id="app">
<!--            <div v-html='name' :class='{class1:result}'></div>
            <div v-if="result">
               {{name | myFilter('你好啊')}}
            </div>
           <input type="checkbox" v-model='result' @click="show">
            <template v-if='result'>
                <div>{{updateDate}}</div>
            </template>
            <div v-show='result'>v-show</div>-->
            <div>{{age2}}</div>
        </div>
        <script>
        var data={name:'123',result:false,value:'2020',age:'18'}     
        var v=new Vue({
          el: '#app',
          data: data,
            methods:{
                show:function(){
                    //alert('ddd'+this.value)
                    var that=this;
                    setInterval(function(){
                        that.name=that.name+1;
                    },500)
                }
            },
            computed:{
                updateDate:function(){
                    
                },
                age2:{
                    set:function(value){
                        this.age=value;
                    },
                    get:function(){
                        return this.age+'当今';
                    }
                }
            },
            filters:{
                myFilter:function(str,str2){
                    return str.split('').reverse().join(',')+this.data.value
                }
            }
        })
        var s=v.$watch('name',function(){
            console.log('我在变化')
        })
        </script>
    </body>
</html>

看源码$watch:

 Vue.prototype.$watch = function (
      expOrFn,
      cb,
      options
    ) {
      var vm = this;
      if (isPlainObject(cb)) {
        return createWatcher(vm, expOrFn, cb, options)
      }
      options = options || {};
      options.user = true;
      var watcher = new Watcher(vm, expOrFn, cb, options);
      if (options.immediate) {
        try {
          cb.call(vm, watcher.value);
        } catch (error) {
          handleError(error, vm, ("callback for immediate watcher \"" + (watcher.expression) + "\""));
        }
      }
      return function unwatchFn () {
        watcher.teardown();
      }
    };

方法一:

 var watcher = new Watcher(vm, expOrFn, cb, options);

Watcher源码:

  var Watcher = function Watcher (
    vm,
    expOrFn,
    cb,
    options,
    isRenderWatcher
  ) {
    this.vm = vm;
    if (isRenderWatcher) {
      vm._watcher = this;
    }
    vm._watchers.push(this);
    // options
    if (options) {
      this.deep = !!options.deep;
      this.user = !!options.user;
      this.lazy = !!options.lazy;
      this.sync = !!options.sync;
      this.before = options.before;
    } else {
      this.deep = this.user = this.lazy = this.sync = false;
    }
    this.cb = cb;
    this.id = ++uid$2; // uid for batching
    this.active = true;
    this.dirty = this.lazy; // for lazy watchers
    this.deps = [];
    this.newDeps = [];
    this.depIds = new _Set();
    this.newDepIds = new _Set();
    this.expression = expOrFn.toString();
    // parse expression for getter
    if (typeof expOrFn === 'function') {
      this.getter = expOrFn;
    } else {
      this.getter = parsePath(expOrFn);
      if (!this.getter) {
        this.getter = noop;
        warn(
          "Failed watching path: \"" + expOrFn + "\" " +
          'Watcher only accepts simple dot-delimited paths. ' +
          'For full control, use a function instead.',
          vm
        );
      }
    }
    this.value = this.lazy
      ? undefined
      : this.get();
  };

重点在: this.vm = vm;
    if (isRenderWatcher) {
      vm._watcher = this;
    }

vm是Vue的继承实例

vm._watcher=this,当前的this是Watcher实例;也就是后边返回的watcher对象

因此vue实例也能访问_watcher进而调用Watcher实例的teardown函数,这里不建议这样调用因为根据变量命名来看是不建议外部调用的。

v._watcher.teardown();

方法二:

return function unwatchFn () {
        watcher.teardown();
      }

返回的是一个函数,函数体 watcher.teardown();是什么?继续看源码

 */
  Watcher.prototype.teardown = function teardown () {
    if (this.active) {
      // remove self from vm's watcher list
      // this is a somewhat expensive operation so we skip it
      // if the vm is being destroyed.
      if (!this.vm._isBeingDestroyed) {
        remove(this.vm._watchers, this);
      }
      var i = this.deps.length;
      while (i--) {
        this.deps[i].removeSub(this);
      }
      this.active = false;
    }
  };

看注释// remove self from vm's watcher list  移除自身的来自vm的所有监听器  vm是谁? vm是Vue的的父类实例 即Vue.prototype

因此我们只需执行$watch()返回的函数即可,s();

发布了28 篇原创文章 · 获赞 16 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/sunboylife/article/details/103989413