vue2 如何剔除监听对象的某个值?

比如我有个 obj

const obj = {
    name:'mike'
    age:12,
    height:178,
    money:200
}

监听指定值

watch:{
    'obj.name':...
}

但是 我现在有个需求 就是不想监听 money

请问如何实现?

阅读 2.5k
6 个回答

如果你这个money一定要放在obj里的话,那可以这么做——再定义一个money的字段,然后深度监听obj,当obj.money != money时代表更改的是money的值

{
  data: {
      obj: {
        name:'mike',
        age:12,
        height:178,
        money:200
      },
      money: 200,
  },
  watch: {
    obj: {
      handler(value) {
        if(value.money != this.money) return this.money = value.money;
        console.log('do somthing')
      },
      deep: true,
    }
  }
}

DEMO

我的考虑是 先用computed 获取去除money这个值的对象

然后再去监听这个对象

  computed: {
      newObj() {
        let temp
        for(let key in this.obj) {
          if (key !== 'money') {
            temp[key] = this.obj[key]
          }
        }
      }
    
    },
    watch: {
      newObj() {
        // ......
      }
    },
const obj = {
  name:'mike'
  age:12,
  height:178,
}
let money = 200

moneyobj 当中拿出来。

能写成这种方式吗

    const unwatch = this.$watch('data.name', () => {
      ...
    })
    unwatch()

或者可以监听整个obj,然后拿newVal和oldVal对比,如果发现其他的都相等,但是money不相等,那就说明只有money变动了,这样就跳过处理了,性能会很差就是了

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"
    />
    <title>Document</title>
    <link
      href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.1/theme-chalk/index.css"
      rel="stylesheet"
    />
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/vant@2.10/lib/index.css"
    />
    <style>
      * {
        padding: 0;
        margin: 0;
        box-sizing: border-box;
      }
    </style>
  </head>

  <body>
    <div id="app">
      <input type="text" v-model="obj.name" />
      <input type="text" v-model="obj.age" />
      <input type="text" v-model="obj.height" />
      <input type="text" v-model="obj.money" />
    </div>
  </body>
  <script src="https://cdn.bootcdn.net/ajax/libs/axios/0.19.2/axios.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.5.16/vue.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.0/jquery.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.13.1/index.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/vant@2.10/lib/vant.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/vConsole/3.3.4/vconsole.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.min.js"></script>
  <script>
    let obj = {
      name: 'mike',
      age: 12,
      height: 178,
      money: 200
    }
    let dev_oldVal = JSON.parse(JSON.stringify(obj))

    new Vue({
      el: '#app',
      data() {
        return {
          obj
        }
      },
      watch: {
        obj: {
          handler: function (newVal) {
            let str0 = ``
            let moneyStr0 = ``
            for (const key in newVal) {
              const element = newVal[key]
              if (key === 'money') {
                moneyStr0 = `${element}${key}`
              } else {
                str0 = str0 + `${element}${key}`
              }
            }

            let str1 = ``
            let moneyStr1 = ``
            for (const key in dev_oldVal) {
              const element = dev_oldVal[key]
              if (key === 'money') {
                moneyStr1 = `${element}${key}`
              } else {
                str1 = str1 + `${element}${key}`
              }
            }

            if (str0 === str1 && moneyStr0 !== moneyStr1) {
              console.log('money字段改变了')
            }

            if (str0 !== str1 && moneyStr0 !== moneyStr1) {
              console.log('money字段和其他字段都改变了')
            }

            if (str0 !== str1 && moneyStr0 === moneyStr1) {
              console.log('其他字段改变了')
            }

            dev_oldVal = JSON.parse(JSON.stringify(newVal))
          },
          deep: true
        }
      },
      mounted() {
        // 测试多字段改变
        // setTimeout(() => {
        //   this.obj = {
        //     name: 'mike',
        //     age: 321,
        //     height: 312,
        //     money: 312
        //   }
        // }, 3000)
      }
    })
  </script>
</html>

代码没有优化过的,这个只是一个思路,你可以用其他的工具减少代码,例如lodash

借助 computed,就是你这种情况稍微有点麻烦,下面是伪代码,经供参考:

const obj = {
    name:'mike'
    age:12,
    height:178,
    money:200
}

{
  computed: {
    name() {
      return obj.name;
    },
    age() {
      return obj.age;
    },
    height() {
      return obj.height;
    },
    watchObj() {
      return {
         name,
        age,
        height
      }
    }
  },
  watch: {
    watchObj() {
      // ...
    }
  }
}

很明显会比较麻烦,所以还是建议给 money 从 obj 中拿出来

推荐问题
宣传栏