繁体   English   中英

v-on 单击,仅在满足条件时添加处理程序

[英]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> ,它包含所有“部分”和“元素”组件
  • "section" 组件将使用<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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM