v模型和子组件?

pan*_*hro 36 vue.js vuejs2

我有一个表单并使用v-model绑定输入:

<input type="text" name="name" v-model="form.name">
Run Code Online (Sandbox Code Playgroud)

现在我想提取输入并使其成为自己的组件,然后如何将子组件的值绑定到parent对象form.name

tha*_*ksd 89

如文档中所述,

v-model 只是语法糖:

<input
  v-bind:value="something"
  v-on:input="something = $event.target.value">
Run Code Online (Sandbox Code Playgroud)

要实现v-model自定义组件的指令:

  • value为组件指定prop
  • 将data属性设置为方法中valueprop 的值data(因为您不应该从组件中修改prop的值).
  • input每当它发生更改时,都会使用data属性的值发出一个事件

这是一个简单的例子:

Vue.component('my-input', {
  template: `
    <div>
      My Input:
      <input v-model="inputVal">
    </div>
  `,
  props: ['value'],
  data() {
    return { inputVal: this.value }
  },
  watch: {
    inputVal(val) {
      this.$emit('input', val);
    }
  }
})

new Vue({
  el: '#app',
  data() {
    return { foo: 'a', bar: 'b' }
  }
})
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
  <!-- using v-model... -->
  <my-input v-model="foo"></my-input>
  
  <!-- is the same as this... -->  
  <my-input :value="bar" @input="bar = $event"></my-input>

  {{ foo }}<br>
  {{ bar }}
</div>
Run Code Online (Sandbox Code Playgroud)

  • `v-model` 会自动执行此操作,将变量设置为绑定到发出的值。您还可以通过子组件标签上的“@input”显式监听它。 (2认同)
  • @GaryO,不,这是因为您不应该修改道具的值。https://vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow (2认同)
  • @thanksd - 在您的示例中,如果您复制其中一个输入字段,然后编辑其中之一,为什么第二个字段的值不更新?如果它是原生元素而不是组件,那就会了。 (2认同)
  • @kthornbloom 哈哈,因为我的例子并不完全正确,你是第一个注意到的。该组件不会更新,因为它没有对“value”属性的更改做出反应。更新了我的示例,使其按预期工作。谢谢你的提问! (2认同)

fit*_*rec 17

sync在主实例,如果你使用VUE> 2.2您需要使用emit到的组件.

查看此文档: - https://alligator.io/vuejs/upgrading-vue-2.3/#propsync

一个简单的例子(使用vue 2.5):

Vue.component('my-input', {
	template: '<input v-on:keyup="onChange($event)" :value="field"></div>',
	props: ["field"],
	methods: {
		onChange: function (event) {
			this.$emit('update:field', event.target.value);
		}
	}
});

var vm = new Vue({
	el: '#app',
	data:{val: ''},
});
Run Code Online (Sandbox Code Playgroud)
h1 span { color: red }
Run Code Online (Sandbox Code Playgroud)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.js"></script>

<div id='app'>
 <h1>
   value
   <span>{{ val }}</span>
 </h1>
	<my-input :field.sync="val">
   </my-input>
 </div>
Run Code Online (Sandbox Code Playgroud)


Ben*_*hon 13

Vue 2 的解决方案

您可以将所有属性和侦听器(包括v-model)从父级转发到子级,如下所示:

<input v-bind="$attrs" v-on="$listeners" />
Run Code Online (Sandbox Code Playgroud)

这是$attrs文档

包含未被识别(和提取)为 props 的父范围属性绑定(除了classstyle)。当一个组件没有任何声明的 props 时,这基本上包含所有父范围的绑定(除了classstyle),并且可以通过v-bind=" $attrs"-在创建高阶组件时传递给内部组件

确保设置inheritAttrsfalse避免将属性应用于根元素(默认情况下,所有属性都应用于根元素)。

这是$listeners文档

包含父范围的 v-on 事件侦听器(无.native修饰符)。这可以传递给内部组件 via v-on="$listeners"-在创建透明包装组件时很有用

因为v-model只是v-bind+的简写v-on,它也被转发。

请注意,此技术自Vue 2.4.0(2017 年 7 月)起可用,其中此功能被描述为“更轻松地创建包装器组件”。

Vue 3 的解决方案

Vue 3删除了该$listeners对象,因为侦听器现在也在该$attrs对象中。所以你只需要这样做:

<input v-bind="$attrs" />
Run Code Online (Sandbox Code Playgroud)

这是文档$attrs

包含未识别(和提取)为组件道具或自定义事件的父级范围属性绑定和事件。当一个组件没有任何声明的 props 或自定义事件时,这基本上包含所有父级范围的绑定,并且可以通过v-bind="$attrs"- 在创建高阶组件时被传递到内部组件。

如果您的组件只有一个根元素(Vue 3 允许多个根元素),那么仍然需要设置inheritAttrsfalse以避免将属性应用于根元素。

这是文档inheritAttrs

默认情况下,未被识别为 props 的父范围属性绑定将“失败”。这意味着当我们有一个单根组件时,这些绑定将作为普通的 HTML 属性应用于子组件的根元素。在创作包装目标元素或其他组件的组件时,这可能并不总是所需的行为。通过设置 inheritAttrsfalse,可以禁用此默认行为。这些属性可通过$attrs实例属性获得,并且可以使用 显式绑定到非根元素v-bind

与 Vue 2 的另一个区别是$attrs对象现在包含classstyle

这是“禁用属性继承”的片段

通过将inheritAttrs选项设置为false,您可以控制应用到其他元素的属性以使用组件的$attrs属性,其中包括未包含在组件propsemits属性中的所有属性(例如,classstylev-on侦听器等)

  • 这是迄今为止最好的答案 - 使它变得非常简单 (3认同)

Cam*_*lby 5

您还可以在子组件上指定:value@input事件,并利用事件而不是创建监视。

MyInput.vue

<template>
  <input 
    :value="value" 
    @input="$emit('input', $event.target.value)" />
</template>

<script>
export default {
  props: ['value']
};
</script>
Run Code Online (Sandbox Code Playgroud)

屏幕画面

<template>
  <my-input v-model="name" />
</template>

<script>
import MyInput from './MyInput.vue';

export default {
  components: { MyInput },
  data() {
    return {
      name: ''
    }
  }
};
</script>
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案。这是最简单、最直接的版本。当您所需要做的只是通过 v-model 时,无需在子组件中监视或复制数据 (10认同)
  • 这就是答案。 (4认同)
  • 迄今为止最简单的答案 (3认同)
  • 这里的缺点是使用“v-modal”你不能为你的 prop 指定一个名称。所以我使用 ``.sync`` 将卡梅伦的答案与下一个答案结合起来:``&lt;input :value="myVal" @input="$emit('update:myVal', $event.target.value)"&gt;` ` 并在父组件中: ``&lt;my-input myVal.sync="name" /&gt;`` 。 (2认同)
  • 顺便说一句,如果你像我一样使用 Vuetify 的 ``&lt;v-text-field&gt;`` 而不是 ``&lt;input&gt;`` ,请将 ``$event.target.value`` 替换为 ``$event`` (2认同)
  • 改变 props eslint 规则失败。你如何解决这个问题? (2认同)