Vue.js - 监听对象的特定属性并在更改时加载数据。

10

我有一个Vue组件,其中有一个名为product的prop,它是一个带有许多属性的对象,并且经常发生更改。

export default {
    props: {
        product: {
            type: Object,
            default: () => {},
        },
    },
    watch: {
        'product.p1'() {
            this.loadData()
        },
        'product.p2'() {
            this.loadData()
        },
    },
    methods: {
        loadData() {
            doApiRequest(this.product.p1, this.product.p2)
        }
    },
}

当且仅当product的属性p1p2发生变化时,该组件应加载新数据。

其中一种方法是监视整个product并在其发生更改时加载数据。但这会产生不必要的请求,因为p1p2可能没有更改。

另一个想法是监视product.p1product.p2,并在每个监视器中调用相同的函数来加载数据。 但是,如果在产品的新版本中同时更改了p1p2,它将触发两个调用。

使用防抖函数加载数据是否是一个好的解决方案?

还是使用单个监视器监视整个product,并将新的p1p2字符串化后与它们的旧版本进行比较以确定是否应触发数据加载?


1
嗨,一个小的代码块可以让他人了解你尝试做什么。 我认为你需要将产品作为计算属性。 https://vuejs.org/v2/guide/computed.html#Computed-vs-Watched-Property - Abregre
我认为在整个产品中使用防抖与观察器(watch)是一个好的解决方案。防抖对性能有好处。在整个产品中只有一个观察器可以让你将所有数据加载条件放在一个地方,这使得代码更易于阅读和编辑。 - Nikolai Borisik
2
或者您可以创建一个计算属性,返回p1和p2的字符串表示形式,并监视该计算属性。 - Terry
要不考虑采用第二种方法,但是保存上次调用的时间戳到本地变量中,如果时间戳小于一定值,则不再重新加载数据,如果时间戳超过一定值,则在重新加载数据之前更新时间戳。 - Jimmar
3个回答

2

当您在使用Vue.js与HTML内联时,希望为您提供关于如何处理不触摸事件的帮助。如果您有一个对象模型,其中包含其他变量,并且您需要验证任何变量,则需要将它们放入观察程序中并使用引号('')告诉Vue.js这是来自模型.email的内容。

希望这对您有所帮助。

数据(){
返回 {

        model: {},
        error_message: [],
    }
},
watch: {
    'model.EmailAddress'(value) {
        // binding this to the data value in the email input
        this.model.EmailAddress = value;
        this.validateEmail(value);
    },
},
methods: {
    validateEmail(value) {
        if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(value)) {
            this.error_message['EmailAddress'] = '';
        } else {
            this.error_message['EmailAddress'] = 'Invalid Email Address';
        }
    }
   


},

感谢您的贡献,但是如果您仅仅把代码丢在那里而不解释,那么解释一下会更有帮助。 - Mitya

2
有几种方法可以实现这个,每种方法都有其优缺点。
我通常采用的一种简单方法是使用一个监视函数来访问您想要监视的每个属性,然后返回一个新的空对象。Vue 知道在监视函数中访问了 product.p1product.p2 属性,因此会在这些属性任何一个发生变化时重新执行它。然后,通过从监视函数返回一个新的空对象实例,Vue 将触发监视处理程序,因为监视函数返回了一个新值(因此被监视的内容“发生了变化”)。
created() {
  this.$watch(() => {
    // Touch the properties we want to watch
    this.product.p1;
    this.product.p2;

    // Return a new value so Vue calls the handler when
    // this function is re-executed
    return {};
  }, () => {
    // p1 or p2 changed
  })
}

优点:

  • 您不需要将任何内容转换为字符串。
  • 您不必防抖观察处理程序函数。

缺点:

  • 您无法跟踪 p1p2 的先前值。
  • 请注意,this.product 可能为 null/undefined。
  • 它将始终在更改 p1p2 时触发;即使在下一个微任务(即 $nextTick())之前将 p1p2 设置回其先前的值;但在大多数情况下,这不太可能成为问题。
  • 您需要使用 this.$watch()。如果要改用 watch 选项,则需要观察计算属性。

这些缺点适用于其他方法。

更紧凑的版本如下:

this.$watch(
  () => (this.product.p1, this.product.p2, {}),
  () => {
    // changed
  }
})

这会导致监视器在产品发生任何更改时运行,而不仅仅是p1和p2属性的更改,因为您每次返回一个新对象。 - KienHT
@KienHT 只有在更改了 this.product 属性时,才会触发,而不是其他任何 this.product 属性被更改。 - Decade Moon

1

就像其他开发者所说,您可以使用计算属性来监控product.p1product.p2的变化,或者两者都监控,并且在每种情况下仅调用一次loadData()方法。这里是一个假想的product.vue组件的代码:

<template>
    <div>
        this is product compo
    </div>
</template>

<script>
export default {
    name: "product",
    watch: {
        p1p2: function(newVal, oldVal) {
            this.loadData();
        }
    },
    props: {
        productProp: {
            type: Object,
            default: () => {},
        },
    },

    computed: {
        p1p2: function() {
            return this.productProp.p1 + this.productProp.p2;
        }
    },
    methods: {
        loadData() {
            console.log("load data method");
        }
    },
}
</script>

我将它接收到的属性重命名为productProp,并在其中查找名为p1p2的计算属性。我假设数据的值是以字符串格式存储的(但如果不是,您可以进行转换)。实际上,p1p2productProp.p1productProp.p2的拼接。因此,更改其中一个或两个都可能触发loadData()方法。以下是传递数据给product.vue的父组件代码:

<template>
<section>
   
  <product :productProp = "dataObj"></product>
  <div class="d-flex justify-space-between mt-4">
    <v-btn @click="changeP1()">change p1</v-btn>
    <v-btn @click="changeP2()">change p2</v-btn>
    <v-btn @click="changeBoth()">change both</v-btn>
    <v-btn @click="changeOthers()">change others</v-btn>
  </div>
  
</section>
</template>

<script>
import product from "../components/product";

export default {
    name: 'parentCompo',

    data () {
      return {
        dataObj: {
          p1: "name1",
          p2: "name2",
          p3: "name3",
          p4: "name4"
        }
      }
    },
    components: {
      product
    },

    methods: {
      changeP1: function() {
        if (this.dataObj.p1 == "name1") {
          this.dataObj.p1 = "product1"
        } else {
          this.dataObj.p1 = "name1"
        }
      },

      changeP2: function() {
        if (this.dataObj.p2 == "name2") {
          this.dataObj.p2 = "product2"
        } else {
          this.dataObj.p2 = "name2"
        }
      },

      changeBoth: function() {
        if (this.dataObj.p2 == "name2") {
          this.dataObj.p2 = "product2"
        } else {
          this.dataObj.p2 = "name2"
        }

        if (this.dataObj.p1 == "name1") {
          this.dataObj.p1 = "product1"
        } else {
          this.dataObj.p1 = "name1"
        }
      },

      changeOthers: function() {
        if (this.dataObj.p3 == "name3") {
          this.dataObj.p3 = "product3"
        } else {
          this.dataObj.p3 = "name3"
        }
      }
    },
   
}
</script>

您可以测试更改按钮,通过更改dataObj.p1dataObj.p2或两者都更改,loadData()方法仅被调用一次,而更改其他内容则不会调用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接