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

vol*_*lna 5 javascript vue.js vuejs2

经过一番研究,找到了尤文先生的以下建议:https : //github.com/vuejs/vue/issues/7349#issuecomment-354937350

所以我毫不犹豫地试了一下:

组件模板

<template>
  <div v-on='{ click: dataType === `section` ? toggleSectionElements : null }'>
    ... magic 
  </div>
<template>
Run Code Online (Sandbox Code Playgroud)

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>
Run Code Online (Sandbox Code Playgroud)

但是对于描述的情况,它会在渲染过程中导致错误:

[Vue warn]: Invalid handler for event "click": got null
Run Code Online (Sandbox Code Playgroud)

有人可以建议做错了什么吗?:思维:

更新
方式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: { ... }
  }
}
Run Code Online (Sandbox Code Playgroud)

Ter*_*rry 3

您实际上应该在点击处理程序内执行检查,而不是用三元逻辑污染您的模板。它不仅使您的模板更具可读性,而且还使代码的维护变得更加容易,因为所有逻辑都已被抽象并委托给事件处理程序的回调。

快速解决方案

因此,快速的解决方案是确保只有在存在toggleSectionElements()正确的情况下才有效。dataType这可以通过使用保护子句来实现:

toggleSectionElements() {
  // Guard clause to prevent further code execution
  if (this.dataType() !== 'section')
    return;

  // Magic here
}
Run Code Online (Sandbox Code Playgroud)

更好的是,如果应该为每个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
  }
}
Run Code Online (Sandbox Code Playgroud)

建议:使用原子组件

由于将单击事件处理程序绑定到最终不执行任何操作的元素可能成本高昂,因此您还可以将组件分解为更加原子化。集合元素将负责接收“节”或“元素”的数组,每个“节”/“元素”将有自己的组件,如下所示:

  • 例如,您有一个集合组件,<my-collection>它包含所有“部分”和“元素”组件
  • “section”组件将使用该<my-section>组件
  • “element”组件将使用该<my-element>组件

这就是VueJS真正强大的时候:你可以在里面使用动态组件<my-collection>来根据遇到的情况来决定使用哪个组件dataType

这是通过运行v-for集合来完成的,然后使用v-bind:is="..."来确定特定集合项是否应该使用“部分”或“元素”。我知道这可能超出了您最初问题的范围,但这是一个值得考虑的设计:

toggleSectionElements() {
  // Guard clause to prevent further code execution
  if (this.dataType() !== 'section')
    return;

  // Magic here
}
Run Code Online (Sandbox Code Playgroud)
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
  }
}
Run Code Online (Sandbox Code Playgroud)
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'
});
Run Code Online (Sandbox Code Playgroud)