来个 vue 大牛解释下这个神奇的 bug?

  • 完整代码
    bug 出现在 watch 中,已写注释
<!--
 * @Version: 2.0
 * @Date: 2021-12-20 09:30:41
 * @LastEditTime: 2022-01-13 11:15:54
-->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <div id="app">
      <component-a></component-a>
      <component-b></component-b>
    </div>
  </body>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.js"></script>
  <script src="https://unpkg.com/vuex@3.6.2/dist/vuex.js"></script>
  <script>
    const store = new Vuex.Store({
      state: {
        localData: { name: '' },
      },
      getters: {
        localData: (state) => state.localData,
      },
      mutations: {
        changeLocalData(state, data) {
          state.localData = data;
        },
      },
    });
    const mapGetters = Vuex.mapGetters;

    var myMixin = {
      data() {
        return {
          msg: 'mixin',
        };
      },
      computed: {
        ...mapGetters(['localData']),
      },
      watch: {
        // 此处有个bug 我点击 `a` 组件的时候 为什么打印的是 b 的值? 期望的是 a
        localData: {
          handler: _.debounce(function() {
            console.log('this.msg', this.msg);
          }, 500),
          deep: true,
        },
      },
    };
    var a = {
      mixins: [myMixin],
      template: '<div @click="_changeMsg()">a</div>',
      mounted() {
        this.msg = 'aaa';
      },
      methods: {
        _changeMsg() {
          this.$store.commit('changeLocalData', { name: 'a' });
        },
      },
    };
    var b = {
      mixins: [myMixin],
      template: '<div @click="_changeMsg()">b</div>',
      mounted() {
        this.msg = 'bbb';
      },
      methods: {
        _changeMsg() {
          this.$store.commit('changeLocalData', { name: 'b' });
        },
      },
    };
    new Vue({
      el: '#app',
      data() {
        return {
          flag: false,
        };
      },
      store,
      components: {
        'component-a': a,
        'component-b': b,
      },
    });
  </script>
</html>

项目中 用到了 vuex mixins debounce

如果让我打印 this, 已经知道两个 this 都是 b 组件了...

  • 改造一下

删除 myMixinwatch 添加到 a b中,就符合我的期望了,每个 watch 都打印出来了 a,b

var myMixin = {
  data() {
    return {
      msg: 'mixin',
    };
  },
  /* ------删除部分------- */
  // watch: {
  //   localData: {
  //     handler: _.debounce(function() {
  //       console.log('this.msg', this.msg);
  //     }, 500),
  //     deep: true,
  //   },
  // },
  computed: {
    ...mapGetters(['localData']),
  },
};
var a = {
  mixins: [myMixin],
  template: '<div @click="_changeMsg()">a</div>',
  mounted() {
    this.msg = 'aaa';
  },
  /* ------新增 start------- */
  watch: {
    localData: {
      handler: _.debounce(function() {
        console.log('this.msg', this.msg);
      }, 500),
      deep: true,
    },
  },
  /* ------新增 end------- */
  methods: {
    _changeMsg() {
      this.$store.commit('changeLocalData', { name: 'a' });
    },
  },
};
var b = {
  mixins: [myMixin],
  template: '<div @click="_changeMsg()">b</div>',
  mounted() {
    this.msg = 'bbb';
  },
  /* ------新增 start------- */
  watch: {
    localData: {
      handler: _.debounce(function() {
        console.log('this.msg', this.msg);
      }, 500),
      deep: true,
    },
  },
  /* ------新增 end------- */
  methods: {
    _changeMsg() {
      this.$store.commit('changeLocalData', { name: 'b' });
    },
  },
};

就是为了想知道原理,请大佬丝滑的解释一波✨(可能是我理解的 mixin 用法有问题?)

阅读 2k
2 个回答

引用一下 @李十三 的回复

那你应该吧mixin封装成一个函数返回,就跟vue的data必须是函数一样mixin: [myMixin()],为了避免公用对象同一个引用地址

再次感谢大佬的细心解答!

来, 把去抖动函数去掉,这段改成这

 handler() {
          console.log('this.msg', this.msg);
        // this.msg aaa
        // this.msg bbb
        },

其实两个都打印了,只是防抖动函数起作用了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题