【问题标题】:Prop inheritance from component从组件继承道具
【发布时间】:2020-03-04 06:11:20
【问题描述】:

不太确定我是否理解手册(或 vue.js)中的“非道具属性”:https://vuejs.org/v2/guide/components-props.html

假设我有 ChildComponent.vue 文件:

<template>
  <input type="text" class="input" :value="childValue" v-on="listeners">
</template>

<script>
  export default {
    props: {
      childValue: {
        type: String,
        default: 'blah',
      }
    },
    computed: {
      listeners() {
        return {
          // Pass all component listeners directly to input
          ...this.$listeners,
          // Override input listener to work with v-model
          input: event => this.$emit('input', event.target.value)
        }
      }
    }
  }
</script>

然后我像这样将它添加到 ParentComponent:

<template>
  <ChildComponent v-model="parentValue" placeholder="default" @keydown.enter="parentMethod"/>
</template>

<script>
  export default {
    data () {
      return {
        parentValue: "",
      };
    },
    methods: {
      parentMethod () {
        ...
      }
    },
  }
</script>

流程应该是(并且像这样工作) - 在按下 Enter 后写入 ChildComponent 中的文本字段的任何内容都应该一直发送到 ParentComponent,因为应该调用 parentValueparentMethod()

    1234563 1234563 p>
  1. 另一个问题 - v-on="listeners" 是如何在不指定事件的情况下工作的,这是否意味着我正在收听每个事件? 在父组件中有一个简写 @keydown.enter 这意味着它正在侦听 keydown.enter 事件,但在 listeners() 方法中我发出了一个 input 事件...

  2. 我也很难理解 listeners() 方法中发生的事情,因此任何有助于破译这一点的帮助将不胜感激。 :D

提前感谢您的帮助。

干杯

【问题讨论】:

    标签: vue.js


    【解决方案1】:

    让我们一次做一个主题...

    道具和非道具属性的区别:

    Props 是您在 props 对象中定义的参数。通过 props,您可以告诉用户他们应该为给定的 prop 使用什么类型、是否需要、默认值、分配验证函数等。

    此外,道具是反应式的,因此如果您的模板依赖于道具并且道具更新,那么您的模板也会更新。

    您分配给组件但不对应于任何道具的属性将传递给$attrs 变量。您可以使用它来访问这些值,例如 $attrs.id 获取 id,或 $attrs.name 获取名称,等等。

    您案例中的事件流程:

    是的,您在ChildComponent 上键入的内容传递给ParentComponent。它们通过您的v-model@keydown.enter="parentMethod" 传递。

    您可能知道事件是如何工作的,但如果您不知道,这里的要点是:当您需要将数据从子组件传递到父组件时,您会在您的子组件中发出一个事件并在其中监听它你的父母。

    例如,如果您想发出一个名为 foo 的事件,您可以使用 $emit('foo') 在您孩子的某处调用 $emit。然后,您可以通过将@foo="yourHandler" 添加到子级来在父级中收听它,其中yourHandler 是为处理事件而编写的函数。这就是你对@keydown.enter="parentMethod" 所做的。

    &lt;input&gt; 不仅会设置 props 类型和类,还会设置占位符(具有“默认”值)?

    回答:视情况而定。模板中的 &lt;input&gt; 标记将接收什么取决于您的根元素 (&lt;input&gt;) 是否继承组件属性。该行为由组件的 inheritsAttrs 属性定义,默认为 true。

    这意味着,在您的情况下,由于您没有指定 inheritsAttrs,它将默认为 true,并且 ,您传递给 &lt;ChildComponent&gt; 的每个属性都将传递给您的&lt;input&gt; 标签,你手动定义的东西除外。

    既然你这样声明你的&lt;input&gt;标签:

    <input type="text" class="input" :value="childValue" v-on="listeners">
    

    您的&lt;input&gt; 标签将继承&lt;ChildComponent&gt; 的所有属性除了 typevalue 和您的听众(稍后会详细介绍)。该规则的例外是 classstyle,它们总是被继承。

    PS:请注意,typeclassplaceholder 是属性,而不是道具。

    这是否意味着分配给 parentValue 数据的 v-model prop 也将传播到元素,从而使我的 :value 和 v-on 绑定冗余?

    回答:不,但它也行不通。原因如下:

    当你使用这段代码声明你的监听器时:

    listeners() {
        return {
            // Pass all component listeners directly to input
            ...this.$listeners,
            // Override input listener to work with v-model
            input: event => this.$emit('input', event.target.value)
        }
    }
    

    您正在为您的 listeners 计算属性分配放置在您的 ChildComponent 标记上的每个事件侦听器,包括您的 keydown 事件,这就是它起作用的原因。

    赋值是在这一行完成的:

    ...this.$listeners,
    

    它使用扩展运算符将$listeners 变量(包含所有组件事件)中的所有元素添加到您要返回的对象中。

    您没有继承的唯一事件是input,如下行中所定义:

    input: event => this.$emit('input', event.target.value)
    

    通过该行,您告诉您的代码input 事件的行为将是您定义的行为,而不是继承的行为。

    然后,当您将 v-on="listeners" 分配给您的输入时,您是在告诉它监听您的 listeners 变量中列出的每个事件。也就是说:您将所有继承的事件和您的自定义 input 事件附加到您的输入事件。

    最后,要解释为什么它不是多余的,但为什么它不起作用,你必须了解v-model 是如何工作的。它(通常)通过侦听组件的input 事件并使用它来更新同一组件的value 属性来工作。所以在这一行:

    <ChildComponent v-model="parentValue" placeholder="default" @keydown.enter="parentMethod"/>
    

    你在做两件事:

    • 您将parentValue 的值分配给ChildComponentvalue 属性
    • 您是在告诉您的组件在调用 input 事件时更新 parentValue

    这意味着为您的input 标签分配一个值和侦听器并不是多余的,因为您需要它才能使v-model 正常工作,但它最终不会工作,因为您的组件没有value 道具。它有一个 childValue 属性。

    要修复它,您有两种选择:

    • childValue 重命名为value
    • 或者告诉你的组件使用childValue作为模型

    要执行第二种方法,只需将这段代码附加到您的ChildComponent

    model: {
        prop: 'childValue',
        event: 'input'
    }
    

    这将告诉您的组件使用该道具和该事件来使v-model 工作。

    结束

    最后一点:以后,请尝试将您的问题缩小到一个主题。这将更容易回答,并将帮助以后搜索这些主题的人。

    【讨论】:

    • 非常感谢。再澄清一点,我读过:“v-model 在内部使用不同的属性并为不同的输入元素发出不同的事件”。所以对于 textarea 元素,prop 将是“value”,但是对于像复选框这样的东西,这将是“checked”属性。我测试了您的两个解决方案并且它们确实有效,但是在第一种方法中,它如何知道“价值”应该是在 v-model 中使用的道具?
    • BasicComponent 是否以某种方式从它的 根组件继承类型,或者'value' prop 是默认的,并且复选框之类的东西使用模型覆盖它:{} 方法你在第二种方法中向我展示了?或者也许还有其他我不知道的魔法。
    • value 是任何 custom 组件(即用户编写的组件)的默认值。不同的输入字段有自己的默认值,例如 checked 用于复选框。
    猜你喜欢
    • 2019-05-22
    • 1970-01-01
    • 2021-03-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-07
    相关资源
    最近更新 更多