vue,发射与传递函数作为道具

Posted

技术标签:

【中文标题】vue,发射与传递函数作为道具【英文标题】:vue, emitting vs passing function as props 【发布时间】:2018-11-05 00:48:54 【问题描述】:

假设我有一个在其他几个组件中导入的按钮组件。我希望子组件不与单击按钮时发生的任何一种逻辑耦合。所以我想在利用这个按钮组件的各种组件中保留这个逻辑。

我认为至少有两种方法可以解决这个问题。

    让孩子向父母发出事件,然后让父母定义处理程序。

    在 parent 中定义处理程序并将其作为 props 传递给按钮组件。

我习惯于在 React 中做后者。 vue 中是否有针对这种情况的最佳实践?

【问题讨论】:

【参考方案1】:

Vue.js 事件 是回调,它们不是 DOM 事件。您可以验证这一点,因为您将自定义名称添加到事件侦听器而不是 DOM 事件名称(clickfocus...),并且没有 event 对象传递给函数,除非您指定$emit 调用中的 $event 参数。

活动

优点

对于库:使其更轻,客户端在方法使用方面具有更大的灵活性 有用的 Vue devtools 事件日志记录 允许全局监听器 (this.$root.on),尽管这可以通过 Vuex.js 得到更好的增强。 区分语法:: 用于道具,@ 用于事件/方法

缺点

不那么明确,更难调试(如果没有侦听器或事件名称拼写错误,则静默失败)

道具

优点

更明确,是声明性的,可以是默认的、必需的、验证的,是什么让它们更容易调试(TypeScript 中的运行时错误或编译错误)

缺点

必须包含 props 验证,这样您就不必在调用之前检查 function() prop 是否存在(但无论如何使用 props 验证都是一个好习惯...)

结论

看起来这些方法比其他任何方法都更符合惯例和个人偏好,尽管我认为如果不是 Vue.js 文档优先考虑 events 方法,每个人都会很高兴仅使用 props在我看来更好(更清晰)

Props 可以做所有 events 做的事情,除了少数情况(比如 $root 事件监听模式 - 注意 Vuex.js 替换了这个特性并且是可伸缩性的首选),其优点是它们更明确、可调试且易于检查。

总结自:https://forum.vuejs.org/t/events-vs-callback-props/11451

【讨论】:

【参考方案2】:

作为从 React 迁移而来的新手视角,我不知道为什么 @event 甚至存在(或者像上面的答案 - 作为标准)。我无法声明哪个events 组件将$emit?,但我可以很容易地看到哪个props 被传递下来。并且通过一个好的命名,我将能够知道哪个实际上是回调事件。

【讨论】:

为了澄清事实,您绝对可以使用 Vue 的 Custom Events (vm.$emit()) 机制准确声明组件可以发出哪些事件以及它们何时发出。这使得组件可以完全控制它们的事件发射,并保持它们的功能比使用函数 props 更容易封装。【参考方案3】:

您正在寻找“透明包装”

Vue 的自定义事件与原生 DOM 事件的工作方式不同。所以你需要将 .native 属性附加到事件中

但是,如果您希望事件发生在孩子身上,那么您定义一个将返回的计算属性和一个侦听器对象。现在你不会了

默认情况下,未定义为 props 的属性将被添加到视图的根元素中

所以你可以设置inheritAttrs: false,然后将$attrs绑定到孩子,然后它就成为那些属性的目标

现在您不必考虑根组件是什么。

Chris Fritz 在他的 7 个秘密模式谈话中很好地解释了它们是如何工作的。 21:44 左右开始https://youtu.be/7lpemgMhi0k?t=21m44s

【讨论】:

【参考方案4】:

最佳实践

最佳做法是选项 1。您可以在官方文档中看到这种做法:https://vuejs.org/v2/guide/components.html#Sending-Messages-to-Parents-with-Events

性能

只要您在使用事件总线或作为道具传递时传递对要执行的函数的引用,您应该几乎看不到性能差异。

使用选项编号 1 的示例

您可以使用this.$emit('eventName', dataToSend, ...) 将数据发送到父组件,然后父组件将像<my-component @eventName="yourHandler" /> 一样监听组件。然后您就可以为每个按钮使用不同的逻辑。

我为实现此功能的多选组件创建了一个小提琴:https://jsfiddle.net/wkdL0xbc/

// HTML
<div id="app">
  <multi-choice :items="myItems" @selected="alert($event)"></multi-choice>
  <multi-choice :items="myItems" @selected="sayIsCool"></multi-choice>
</div>

// javascript
const multiChoice = 
    template: '<div class="multi-choice"><span v-for="item in items" @click="select(item)"> item </span></div>',
  props: ['items'],
  methods: 
    select(item) 
        this.$emit('selected', item);
    
  
;

new Vue(
  el: "#app",
  data() 
    return 
        myItems: [
        'Homer',
        'Marge',
        'Bart'
      ],
    
  ,
  components: 
    multiChoice: multiChoice
  ,
  methods: 
    sayIsCool(item) 
        alert(item + ' is cool!')
    
  
)

【讨论】:

我不是在寻找实施,我在寻找最佳实践 将函数作为道具向下传递也可以实现您的回答状态。我的问题是有任何性能差异或 vue 最佳实践 好的。那么最佳实践是选项 1。您可以在官方文档中看到这种做法:vuejs.org/v2/guide/…。我在您的原始问题中看不到任何有关性能的问题,但如果您只传递对要执行的函数的引用,它很可能是相同的。【参考方案5】:

Vue 的理念是道具向下,事件向上。第一个选项紧随其后,因为事件本身被发射(向上)到父级然后处理。

此外,在 Vue SFC 中,您还可以在绑定属性前加上 v-on(或 @)前缀,将其意图描述为向上传播的事件,而不是 v-bind(或 :),这意味着它是一个道具,即使它确实是对事件的回调。

【讨论】:

以上是关于vue,发射与传递函数作为道具的主要内容,如果未能解决你的问题,请参考以下文章

Vue 3 发射道具

Laravel 控制器将值作为 Vue 道具传递

作为道具传递的函数不是函数

使用 createElement 和 render 函数从 .blade.php 文件将道具传递给 vue 实例

测试 React 组件方法正在调用函数传递作为道具

将回调函数作为道具传递给孩子