[英]v-on click, add handler only if condition has been met
经过一番研究,发现了 Evan You 先生的以下建议:https ://github.com/vuejs/vue/issues/7349#issuecomment-354937350
于是我毫不犹豫地试了一下:
组件模板
<template>
<div v-on='{ click: dataType === `section` ? toggleSectionElements : null }'>
... magic
</div>
<template>
JS 逻辑
<script>
export default {
name: `product-section`,
props: [`section`, `sectionName`, `depth`],
methods: {
toggleSectionElements() {
... magic
}
},
computed: {
dataType() {
if (this.$props.section.sections || this.$props.depth === 0) {
return `section`
} else {
return `element`
}
}
}
}
</script>
但是对于所描述的情况,它会在渲染过程中导致错误:
[Vue warn]: Invalid handler for event "click": got null
有人可以建议做错了什么吗? :思维:
更新
Data Model
的样子:
DataModel: {
mainSectionA: {
sections: {
sectionA: {
sections: {
elementA: { values: { ... } },
elementB: { values: { ... } }
}
values: { ... }
}
sectionB: {
elementA: { values: { ... } },
elementB: { values: { ... } }
}
},
values: { ... }
},
mainSectionB: {
sections: {
elementA: { values: { ... } },
elementB: { values: { ... } },
elementC: { values: { ... } },
... elements
},
values: { ... }
}
}
只需将其更改为以下内容即可
v-on="condition ? { mouseover: handler } : {}"
或者,如果您的处理程序被称为 mouseover
v-on="condition ? { mouseover } : {}"
与其用三元逻辑污染模板,不如在点击处理程序中实际执行检查。 它不仅使您的模板更具可读性,而且使维护代码更容易,因为所有逻辑都已被抽象并委托给事件处理程序的回调。
因此,快速的解决方案是实际确保toggleSectionElements()
仅在存在正确的dataType
时才起作用。 这可以通过使用保护子句来实现:
toggleSectionElements() {
// Guard clause to prevent further code execution
if (this.dataType() !== 'section')
return;
// Magic here
}
更好的是,如果应该为每个dataType
分配单独的处理程序:然后您可以为此目的创建一个工厂函数:
methods: {
// This is just a factory function
toggleElements() {
switch (this.dataType()) {
case 'section':
return this.toggleSectionElements;
case 'element':
// Something else...
}
},
toggleSectionElements() {
// Magic for section element
}
}
由于将单击事件处理程序绑定到最终什么都不做的元素可能成本很高,因此您还可以将组件分解为更具原子性。 集合元素将负责接收“节”或“元素”的数组,每个“节”/“元素”都有自己的组件,如下所示:
<my-collection>
,它包含所有“部分”和“元素”组件<my-section>
组件<my-element>
组件这是 VueJS 变得真正强大的时候:您可以在<my-collection>
中使用动态组件来根据遇到的dataType
确定要使用哪个组件。
这是通过在集合中运行v-for
来完成的,然后使用v-bind:is="..."
来确定特定集合项应该使用“部分”还是“元素”。 我知道这可能会超出您原始问题的范围,但这是一个值得考虑的设计:
const collectionComponent = Vue.component('my-collection', { template: '#my-collection-component', data: function() { return { collection: [{ dataType: 'section', description: 'Hello I am section 1' }, { dataType: 'element', description: 'Hello I am element 1' }, { dataType: 'section', description: 'Hello I am section 2' }, { dataType: 'element', description: 'Hello I am element 2' }] } }, methods: { componentToUse(dataType) { return 'my-' + dataType; } } }); const sectionComponent = Vue.component('my-section', { template: '#my-section-component', props: ['itemData'], methods: { toggle() { console.log('Doing some magic.'); } } }); const elementComponent = Vue.component('my-element', { template: '#my-element-component', props: ['itemData'] }); new Vue({ el: '#app' });
.box { border: 1px solid #999; cursor: pointer; margin: 10px; padding: 10px; } .box:hover { background-color: #eee; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script> <div id="app"> <my-collection /> </div> <script type="text/x-template" id="my-collection-component"> <div> <component v-for="(item, i) in collection" v-bind:key="i" v-bind:is="componentToUse(item.dataType)" v-bind:itemData="item" /> </div> </script> <script type="text/x-template" id="my-section-component"> <div @click="toggle" class="box"> <h1>{{ itemData.dataType }}</h1> <p>{{ itemData.description }}</p> <p>Clicking on me will invoke a section-specific logic</p> </div> </script> <script type="text/x-template" id="my-element-component"> <div class="box"> <h1>{{ itemData.dataType }}</h1> <p>{{ itemData.description }}</p> <p>Clicking on me will do nothing</p> </div> </script>
这里:
click: dataType === `section` ? toggleSectionElements : null
在不相等的情况下,您传递 null,但单击时的值需要一个函数。 您可以尝试一个空函数:
click: dataType === `section` ? toggleSectionElements : ()=>{}
在 Vue 3 中,您可以将null
传递给侦听器。 将它与可选链接相结合,您可以这样做:
@click="handler?.() || null"
旧浏览器也一样:
@click="handler ? handler() : null"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.