vue.js @click绑定到v-for循环中的每个项目,当单击时执行多次

hpxqektj  于 2023-05-18  发布在  Vue.js
关注(0)|答案(2)|浏览(405)

我有一个@click绑定到v-for循环中的单个项目。在生成的渲染中,每个项目都应该有一个@click,所以单击一个项目应该触发绑定到该项目的函数一次。
但它触发的次数和物品一样多。为什么?

<ul>
  <li :key="option.value" v-for="option in options">
    <QuizCheckbox
      @click.native="handleClick(option.value)"
    >
      {{ option.value }}
    </QuizCheckbox>
  </li>
</ul>

...

methods: {
  handleClick(val) {
    console.log(val);
  },

编辑:如果我换了…使用一个简单的元素,那么单击它不会触发问题。所以<QuizCheckbox>组件才是罪魁祸首。然而,其中似乎没有任何东西表明是什么导致了这个问题。下面是QuizCheckbox.vue的内容:

<template>
  <div :class="['quiz-checkbox', {'quiz-checkbox--checked': shouldBeChecked}]">
    <div :class="['form-checkbox']">
      <label class="form-checkbox__label">
        <slot/>
        <input
          :checked="shouldBeChecked"
          :value="value"
          @change="updateInput"
          class="form-checkbox__input"
          type="checkbox"
        />
        <span class="form-checkbox__checkmark"></span>
      </label>
    </div>
  </div>
</template>

<script>
export default {
  model: {
    prop: 'modelValue',
    event: 'change'
  },
  props: {
    value: {
      type: String,
    },
    modelValue: {
      type: [Boolean, Array],
      default: false
    }
  },
  computed: {
    shouldBeChecked() {
      if (this.modelValue instanceof Array) {
        return this.modelValue.includes(this.value);
      }
      return this.modelValue;
    }
  },
  created() {
    if (!this.$slots.default) {
      console.error('QuizCheckbox: requires label to be provided in the slot');
    }
  },
  methods: {
    updateInput(event) {
      const isChecked = event.target.checked;

      if (this.modelValue instanceof Array) {
        const newValue = [...this.modelValue];

        if (isChecked) {
          newValue.push(this.value);
        } else {
          newValue.splice(newValue.indexOf(this.value), 1);
        }

        this.$emit('change', newValue);
      } else {
        this.$emit('change', isChecked);
      }
    }
  }
};
</script>
dy2hfwbg

dy2hfwbg1#

你发布的代码看起来很好。虽然这里简化了你发布运行的代码:

new Vue({
  el: 'ul',
  data: {
    options: [
      {
        value: 'option1',
      },
      {
        value: 'option2',
      }
    ]
  },
  methods: {
    handleClick(val) {
      console.log(val);
    },
  }
 });
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<ul>
  <li :key="option.value" v-for="option in options">
    <div
      @click="handleClick(option.value)"
    >
      {{ option.value }}
    </div>
  </li>
</ul>

问题一定出在别处。

dgtucam1

dgtucam12#

触发的第二个点击事件的罪魁祸首是QuizCheckboxlabel元素及其与最外面的div的关系。
你实际上有两个点击监听器。你在最外面的div元素上赋值的一个,第二个是JS在input元素上赋值的。后者也可以通过点击label元素来触发。
您不能单独单击外部div(您期望发生的事情)和内部label(如果您精确单击它)。单击label会产生要冒泡的click事件(参见捕获和冒泡JS事件的phases)。
您可以通过在labelinput元素上使用v-on:click.stop来避免第二个触发。
或者,您可以在handleClick($event, option.value)处理程序中管理事件(请参阅作为第一个参数传递的$event),并根据例如:event.target:这可以是label或外部div元件。

相关问题