按下子按钮时,@ click在父div上未触发

时间:2019-07-21 16:13:24

标签: vue.js

我已经制作了一个自定义数字输入框组件,并希望其在单击时激活。该组件包括3个元素,两个按钮(用于减小和增大数字值)和一个输入,其中显示数字并可以手动更改。问题在于,父div(@click)的.numberField仅在单击输入框时才会触发,而在单击按钮时则不会触发。

因为输入框似乎正常工作,所以我尝试将按钮元素更改为input[type=button]元素,但这失败了。

我检查了@click个子元素(两个按钮和输入)何时触发,并确认它们的行为均相同(它们不会在设置{ {1}})

如果重要的话,我的:disabled="false"版本是Vue

3.7.0

这是我如何使用此组件的摘要:

<template>
  <div class="numberField" @click="fieldClicked">
    <button @click="stepDown()" :disabled="disabled" class="left">
      &minus;
    </button>
    <input
      v-model="value"
      type="number"
      :max="max"
      :min="min"
      :step="step"
      :disabled="disabled">
    <button @click="stepUp()" :disabled="disabled" class="right">
      &plus;
    </button>
  </div>
</template>

<script>
export default {
  name: 'NumberField',
  props: {
    defaultValue: Number,
    max: Number,
    min: Number,
    step: Number,
    disabled: Boolean,
  },
  data() {
    return {
      value: this.defaultValue,
    };
  },
  watch: {
    value() {
      this.value = Math.min(this.max, Math.max(this.min, this.value));
    },
  },
  methods: {
    stepDown() {
      this.value -= this.step;
    },
    stepUp() {
      this.value += this.step;
    },
    fieldClicked(event) {
      // @click.stop will stop all clicks from propagating; we will only stop clicks when the field is active
      if (!this.disabled) event.stopPropagation()
    },
  },
};
</script>

<style scoped>
.numberField {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  height: 3em;
  width: 8em;
}

.left {
  border-top-left-radius: 0.2em;
  border-bottom-left-radius: 0.2em;
}

.right {
  border-top-right-radius: 0.2em;
  border-bottom-right-radius: 0.2em;
}

input, button {
  padding: 0;
  border-radius: 0;
  min-width: 0;
  height: 100%;
  width: 33%;
  min-height: 0;
  font-size: 1rem;
  text-align: center;
}
</style>

<div class="item" v-for="item in items" :key="item.id" @click="toggleItem(item.id)" :class="{ active: activeItems[item.id] }"> <h1>{{ item.name }}, some other elements irrelevant are here too</h1> <NumberField :defaultValue="item.amount" :max="item.amount" :min="1" :step="1" :disabled="!activeItems[item.id]"></NumberField> </div> 切换toggleItem(id)的布尔值。该项目处于非活动状态时,将禁用NumberField。

我的期望是,单击activeItems[item.id]的任何子元素将触发.numberField的{​​{1}},(仅当该项目处于非活动状态时)该传播到@click中的.numberField,但是仅在单击@click时才是这种情况。

我将不胜感激,我绝对迷路了!

1 个答案:

答案 0 :(得分:2)

设置了<button>属性的disabled不会触发点击事件。如果事件未在<button>上触发,那么它也不会传播到<div>

在您的情况下,一种简单的解决方法是将pointer-events: none放在按钮上,以便完全跳过该按钮。 <div>会直接收到点击,就好像按钮甚至不在那里一样。

const NumberField = {
  name: 'NumberField',
  template: `
    <div class="numberField" @click="fieldClicked">
      <button @click="stepDown()" :disabled="disabled" class="left">
        &minus;
      </button>
      <input
        v-model="value"
        type="number"
        :max="max"
        :min="min"
        :step="step"
        :disabled="disabled">
      <button @click="stepUp()" :disabled="disabled" class="right">
        &plus;
      </button>
    </div>
  `,
  props: {
    defaultValue: Number,
    max: Number,
    min: Number,
    step: Number,
    disabled: Boolean,
  },
  data() {
    return {
      value: this.defaultValue,
    };
  },
  watch: {
    value() {
      this.value = Math.min(this.max, Math.max(this.min, this.value));
    },
  },
  methods: {
    stepDown() {
      this.value -= this.step;
    },
    stepUp() {
      this.value += this.step;
    },
    fieldClicked(event) {
      console.log('here')
      // @click.stop will stop all clicks from propagating; we will only stop clicks when the field is active
      if (!this.disabled) event.stopPropagation()
    },
  },
};

new Vue({
  el: '#app',
  components: {
    NumberField
  }
})
.numberField {
  display: flex;
  flex-direction: row;
  justify-content: center;
  align-items: center;
  height: 3em;
  width: 8em;
}

.left {
  border-top-left-radius: 0.2em;
  border-bottom-left-radius: 0.2em;
}

.right {
  border-top-right-radius: 0.2em;
  border-bottom-right-radius: 0.2em;
}

input, button {
  padding: 0;
  border-radius: 0;
  min-width: 0;
  height: 100%;
  width: 33%;
  min-height: 0;
  font-size: 1rem;
  text-align: center;
}

button[disabled] {
  pointer-events: none;
}
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
<div id="app">
  <number-field :defaultValue="7" :step="1" :min="0" :max="10" disabled></number-field>
</div>