【问题标题】:@click on parent div not firing when pressing child button@click on parent div在按下子按钮时不会触发
【发布时间】:2019-11-29 18:33:18
【问题描述】:

我制作了一个自定义数字输入框组件,并希望它在点击时激活。该组件由 3 个元素、两个按钮(用于减少和增加数值)和一个输入组成,其中显示数字并可以手动更改。问题是父div (.numberField) 的@click 仅在单击输入框时触发,而不是在单击按钮时触发。

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

我检查了@click 的子元素(两个按钮和输入)何时触发,并确认它们都以相同的方式运行(它们不会在设置: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) 切换 activeItems[item.id] 的布尔值。 NumberField 在项目处于非活动状态时被禁用。

我的期望是单击.numberField 的任何子元素会触发.numberField@click,然后(仅当该项目处于非活动状态时)然后传播到@987654337 的@click @,但似乎只有在单击 input[type=number] 时才会出现这种情况。

我会很感激任何帮助,我完全迷路了!

【问题讨论】:

  • 为了实现你应该使用 $emit/$on 事件,vuejs.org/v2/guide/components-custom-events.html
  • 您在观察问题时能否确认disabled 设置为true
  • 父元素是什么意思?那个带有numberField 类的div?顺便说一句,您的fieldClicked 错过了event 参数。
  • @Thamerbelfkih 我不确定这会有什么帮助。我将无法发出事件,因为 \@click 对这些按钮不起作用,因为它们已被禁用
  • @skirtle 是的,我最初使用的 NumberField 实例已禁用:true。单击输入字段时,它会更改为 false,单击任何一个按钮时都不会。它更改为 false,因为 .numberField@click 被传播到 div(NumberField 实例的父级),它更改了作为 disabled 属性传递的值

标签: vue.js


【解决方案1】:

带有disabled 属性集的&lt;button&gt; 不会触发点击事件。如果事件没有在&lt;button&gt; 上触发,那么它也不会传播到&lt;div&gt;

在您的情况下,一个简单的解决方法是将pointer-events: none 放在您的按钮上,以便完全跳过该按钮。 &lt;div&gt; 将直接收到点击,就好像按钮根本不存在一样。

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>

【讨论】:

  • 非常感谢!现在我阅读了您的解释,这很有意义,我想我很困惑,因为输入 did 有效。无论如何,再次感谢。祝你有美好的一天!
猜你喜欢
  • 2014-11-25
  • 2012-10-10
  • 1970-01-01
  • 2018-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-06
相关资源
最近更新 更多