Vue2.x里watch导致filter不断调用的问题,vue1.x无此类问题

新手上路,请多包涵

问题如题,vue2.x里watch data里的属性导致其它data属性的filter不断调用的问题(下面的代码控制台会不断打出---filter),vue1.x无此类问题。
这是bug,还是有其它配置可以设置?

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app">
    {{str}} = {{str | myUppercase}}<br>
    {{index}} = {{myIndex}}
  </div>
  <script src="//cdn.bootcss.com/vue/2.0.3/vue.js"></script>
  <!--<script src="//cdn.bootcss.com/vue/1.0.28/vue.js"></script>-->
  <script>
    var vm=new Vue({
      el:"#app",
      data:{
        index:0,
        myIndex:0,
        str:'hello'
      },
      mounted:function(){
        var vm=this;
        setInterval(function(){
          vm.index++;
        },200);
      },
      /*created:function(){
        var vm=this;
        setInterval(function(){
          vm.index++;
        },200);
      },*/
      filters:{
        myUppercase:function(value){
          console.log('---filter');
          if(!value) return '';
          value=value.toString();
          return value.toUpperCase();
        }
      },
      watch:{
        index:function(newValue,oldValue){
          this.myIndex=newValue*2;
        }
      }
    })
  </script>
</body>
</html>
阅读 5.7k
2 个回答
新手上路,请多包涵

简单来说,是因为 Vue2 有了 Virtual DOM,index 的变化导致 render 函数被调用,继而导致 filter 函数被调用。
首先,你出现的问题跟你有没有 watch 其实没有关系,这点你可以把 watch 去掉试试。
其次, Vue1 因为没有 Virtual DOM,当观察到变化后去做 DOM 更新的时候是直接更新对应的节点,而 Vue2 则是先调用组件的 render 函数更新 Virtual DOM,再去做真实的 DOM 操作。而你的例子中,模板中有 index 和 str,所以组件的 render 函数依赖了 index 和 str,所以 index 变化的时候 render 函数被调用。
使用 Vue.compile 得到的 render 函数如下:

function anonymous() {
with(this){return _c('div',{attrs:{"id":"app"}},[_v(_s(str)+" = "+_s(_f("myUppercase")(str))),_c('br'),_v(_s(index)+" = "+_s(myIndex))])}
}

最后,filter 理应是一个纯函数,不应该产生副作用(比如上述的输出)。
参考:
https://segmentfault.com/a/11...
https://vuejs.org/v2/guide/re...
https://github.com/youngwind/...

如果在代码中加入 updatedbeforeUpdate 这两个生命周期钩子函数,可以看到在 myIndex 变化时,这两个钩子函数会被调用。原因是:当 data 被修改时会导致虚拟 DOM 重新渲染和打补丁,因此应用会更新。大多数情况下都是使用 计算属性 computed 来代替。
关于 updatedbeforeUpdate 的解释,可以参照下官方文档:https://cn.vuejs.org/v2/api/#...

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