我有一个Vue组件,它使用多个子组件.在这些子组件上,我有一个观察数据变化并处理这些变化的观察者.我想为此实施去抖动.
- watch: {
- data: {
- handler: function () {
- this.processData()
- },deep: true
- }
- },methods: {
- processData: debounce(function () {
- console.log(this.id)
- },250),
问题是debounce有效,所以它只在最后一个子组件上执行.
我找到了一个debounce功能的解决方案,可以接受额外的id debounceWithId
但问题是,如果我指定此函数如下:
- methods: {
- processData: debounceWithId(function () {
- console.log(this.id)
- },250,this.id),
最后一个this.id未定义.
解决方法
首先让我添加一个复制您正在描述的问题的示例.
- console.clear()
- function debounce(func,wait,immediate) {
- var timeout;
- return function() {
- console.log("Called from component ",this._uid)
- var context = this,args = arguments;
- var later = function() {
- timeout = null;
- if (!immediate) func.apply(context,args);
- };
- var callNow = immediate && !timeout;
- clearTimeout(timeout);
- timeout = setTimeout(later,wait);
- if (callNow) func.apply(context,args);
- };
- };
- Vue.component("doesntwork",{
- props:["value"],template:`<div>Component #{{_uid}} Value: {{innerValue}}</div>`,data(){
- return {
- innerValue: this.value
- }
- },watch:{
- value(newVal){
- this.processData(newVal)
- }
- },methods:{
- processData: debounce(function(newVal){
- this.innerValue = newVal
- },1000)
- },})
- new Vue({
- el: "#app",data:{
- parentValue: null,}
- })
- <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
- <script src="https://unpkg.com/vue@2.4.2"></script>
- <div id="app">
- Type some text. Wait one second. Only the *last* component is updated.<br>
- <input type="text" v-model="parentValue">
- <doesntwork :value="parentValue"></doesntwork>
- <doesntwork :value="parentValue"></doesntwork>
- <doesntwork :value="parentValue"></doesntwork>
- </div>
基本上这里发生的是debounced函数是在编译组件时创建的,并且组件的每个实例共享相同的去抖动函数.每种情况的背景都不同,但功能相同.我在生成的debounced函数中添加了一个console.log,以便您可以看到所有三个组件共享相同的功能.在这种情况下,该功能正在做它的设计目的;它会在经过一段时间后执行一次,这就是为什么只更新最后一个组件的原因.
要绕过这种行为,您需要为每个组件提供独特的去抖功能.这有两种方法可以做到这一点.
方法一
- methods: {
- processData(){}
- }
然后,在创建的生命周期事件中,将processData方法更改为debounced方法.
- created(){
- this.processData = debounce(function(){
- console.log(this.id)
- },250)
- }
这将为每个组件提供独特的去抖功能,并且应该处理只有最后一个组件正常工作的问题.
以下是从上面的示例修改的示例.
- console.clear()
- Vue.component("works",data(){
- return {
- innerValue: this.value,}
- },methods:{
- processData() {}
- },created(){
- this.processData = _.debounce(function(newVal){
- this.innerValue = newVal
- },1000)
- }
- })
- new Vue({
- el: "#app",}
- })
- <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
- <script src="https://unpkg.com/vue@2.4.2"></script>
- <div id="app">
- Type some text. Wait one second. <em>All</em> components are updated.<br>
- <input type="text" v-model="parentValue">
- <works :value="parentValue"></works>
- <works :value="parentValue"></works>
- <works :value="parentValue"></works>
- </div>
方法二
感谢@RoyJ的建议.您可以在数据中定义processData方法.通常你不这样做是因为你不经常需要函数的多个副本,这就是组件定义的方法部分存在的原因,但是在这种情况下,你需要为每个组件提供一个独特的函数,你可以在数据函数中定义方法,因为为组件的每个实例调用了数据函数.
- data(){
- return {
- innerValue: this.value,processData: _.debounce(function(newVal){
- this.innerValue = newVal
- },1000)
- }
- },
以下是使用该方法的示例.
- console.clear()
- Vue.component("works",processData: _.debounce(function(newVal){
- this.innerValue = newVal
- },1000)
- }
- },})
- new Vue({
- el: "#app",}
- })
- <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
- <script src="https://unpkg.com/vue@2.4.2"></script>
- <div id="app">
- Type some text. Wait one second. <em>All</em> components are updated.<br>
- <input type="text" v-model="parentValue">
- <works :value="parentValue"></works>
- <works :value="parentValue"></works>
- <works :value="parentValue"></works>
- </div>