【问题标题】:Undestanding Custom Component and V-Model in VueJS了解 VueJS 中的自定义组件和 V-Model
【发布时间】:2020-09-26 07:10:23
【问题描述】:

注意:我制作了这个问题的视频版本,您可以在此处查看: https://www.loom.com/share/6a23d0791c2444068e964b388ed5497e


VueJS 文档讨论了如何使用 v-modelcomponents: https://vuejs.org/v2/guide/components.html#Passing-Data-to-Child-Components-with-Props

如果我创建的组件完全符合文档中的规定,它就可以正常工作。代码如下:

Vue.component('custom-input', {
  props: ['value'],
  template: `
    <input
      v-bind:value="value"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})

但现在让我尝试更改该组件中道具的名称——例如,改为bar

Vue.component('custom-input', {
  props: ['bar'],
  template: `
    <input
      v-bind:value="bar"
      v-on:input="$emit('input', $event.target.value)"
    >
  `
})

现在它只工作了一半。也就是说,假设我将custom-input 绑定到一个名为message 的数据属性,如下所示:&lt;custom-input v-model="message"&gt;&lt;/custom-input&gt;。如果我动态更新message 的值,那么custom-input 的值将更新 -- 但只会更新一次。如果我再次更新该值,它将不会更新custom-input 的值。

但是,如果我将道具名称改回value(而不是bar),那么每次更新message 的值时,custom-input 的值都会更新。

[再次,这是我正在谈论的视频描述:https://www.loom.com/share/6a23d0791c2444068e964b388ed5497e]

这是为什么呢?为什么我给道具起什么名字很重要?是否必须将其命名为value,因为我绑定到value 属性?如果有,为什么?

简而言之,这里发生了什么?

谢谢。

【问题讨论】:

    标签: vue.js vuejs2 vue-component


    【解决方案1】:

    是的,属性必须命名为value,因为您使用v-model 进行绑定。 v-model是绑定属性value并监听事件input的缩写。这是一种以两种方式绑定值的特殊用例。

    所以,这完全一样:

    <custom-input v-model="user" />
    

    还有:

    <custom-input :value="user" @input="user = $event" />
    

    如果您更喜欢完整的属性表示法:

    <custom-input v-bind:value="user" v-on:input="user = $event" />
    

    使用变量$event,您可以直接在模板中访问发出的值。您还可以在模板中写入不带括号的函数名称,以将发出的值作为第一个参数传递(例如@input="setUser",然后声明一个方法setUser(user))。

    【讨论】:

    • 我知道attribute 必须命名为value。我不明白为什么prop 必须命名为value。为什么我不能将prop 命名为其他名称?换句话说,为什么这行得通::value="value",但这行不通:value="bar"
    • 如果您在子节点中将属性命名为bar,而在父节点中使用v-model,则实际上是将父节点的值绑定到属性value在孩子中定义而不是观看。您只有一种通过事件绑定到父级的方式。在这种情况下,您需要在父级中使用 v-bind:bar="..."v-on:input="..." 而不是 v-model 以使其再次工作。
    • 太棒了——我现在感觉自己已经完成了 75% 的工作。我明白你在说什么。但是我现在想知道,为什么当我将bar 设置为孩子的道具并在父母中使用v-model 时,custom-input 会更新一次?换句话说,它是双向绑定的——但仅用于一次更新。之后是单向绑定?为什么?
    • 您可能正在更改子组件中的bar 值,然后使用该值更新父组件(通过发出input 事件)。如果更改父项中的值,子项将不会更新(使用:barv-model 时)。使用 Chrome DevTools 的 Vue DevTools 查看当前哪个组件拥有哪个值。还要记住,不鼓励直接修改父级的值(除非它是原始值或字符串)。
    【解决方案2】:
    props is used to get data down from a parent component to a child component
    $emit is used to send back data from the child to the parent
    v-model is used for 2 way data binding
    always make the data reactive with a return data(){return{...}}
    props example:
    Vue.component('product',{
      template:`
          <div>
             <item :items="items"/>
          </div>
    `,
        data() {
          return{
            items:'hi'
          }
      }
    })
    
    Vue.component('item',{
      template:`
    <div>
        {{items}}
    </div>
    `,
      props:{
        items:{
          type:String,
          required:false
        }
      }
    })
    
    var app= new Vue({
      el:"#app"
    })
    
    //in html file
    <div id="app">
    <product/>
    </div> 
    

    【讨论】: