我已经制作了一个自定义数字输入框组件,并希望其在单击时激活。该组件包括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">
−
</button>
<input
v-model="value"
type="number"
:max="max"
:min="min"
:step="step"
:disabled="disabled">
<button @click="stepUp()" :disabled="disabled" class="right">
+
</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
时才是这种情况。
我将不胜感激,我绝对迷路了!
答案 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">
−
</button>
<input
v-model="value"
type="number"
:max="max"
:min="min"
:step="step"
:disabled="disabled">
<button @click="stepUp()" :disabled="disabled" class="right">
+
</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>