我有一个表单并使用v-model绑定输入:
<input type="text" name="name" v-model="form.name">
现在我想提取输入并将其作为自己的组件,然后如何将子组件的值绑定到父对象form.name
?
答案 0 :(得分:63)
As stated in the documentation,
v-model
只是语法糖:<input v-bind:value="something" v-on:input="something = $event.target.value">
为自定义组件实现v-model
指令:
value
道具value
方法中将数据属性设置为data
道具的值(因为您不应该从组件中修改道具的值)。input
事件,只要数据属性发生更改,就会发出这是一个简单的例子:
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' }
}
})
<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>
答案 1 :(得分:13)
在您的主要实例中使用sync
,如果您使用的是vue&gt; 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: ''},
});
h1 span { color: red }
<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>
答案 2 :(得分:5)
您可以像这样将所有属性和侦听器(包括v-model
)从父级转发到子级:
<input v-bind="$attrs" v-on="$listeners" />
包含无法识别为道具的父范围属性绑定(
class
和style
除外)。当组件没有任何声明的道具时,它实质上包含所有父作用域绑定(class
和style
除外),并且可以通过v-bind=" $attrs"
向下传递给内部组件-在创建高阶组件时很有用。
请确保将inheritAttrs
设置为false
,以避免将属性应用于根元素(默认情况下,所有属性都应用于根)。
这是documentation for $listeners:
包含父作用域v-on事件侦听器(不带
.native
修饰符)。可以通过v-on="$listeners"
将此信息传递到内部组件-在创建透明包装器组件时很有用。
由于v-model
只是v-bind
+ v-on
的简写,因此也会转发。
请注意,此技术自Vue 2.4.0(2017年7月)开始可用,该功能被描述为“更容易创建包装器组件”。
Vue 3 删除了$listeners
对象,因为侦听器现在也位于$attrs
对象中。因此,您只需要这样做:
<input v-bind="$attrs" />
包含父范围的属性绑定和事件,这些绑定和事件未被识别(提取)为组件道具或自定义事件。当组件没有任何声明的prop或自定义事件时,它实质上包含所有父作用域绑定,并且可以通过
v-bind="$attrs"
向下传递到内部组件-在创建高阶组件时很有用。
如果您的组件只有一个根元素(Vue 3允许多个根元素),那么仍然需要将inheritAttrs
设置为false
,以避免将属性应用于根元素。
这里是documentation for inheritAttrs
默认情况下,未被识别为道具的父范围属性绑定将“掉线”。这意味着当我们有一个单根组件时,这些绑定将作为常规HTML属性应用于子组件的根元素。在创作包装目标元素的组件或另一个组件时,这可能并非总是期望的行为。通过设置
inheritAttrs
至false
,可以禁用此默认行为。这些属性可通过$attrs
实例属性使用,并且可以使用v-bind
明确绑定到非根元素。
与Vue 2的另一个区别是$attrs
对象现在包括class
和style
。
这里是a snippet from "Disabling Attribute Inheritance":
通过将
inheritAttrs
选项设置为false
,您可以控制将属性应用于其他元素以使用组件的$attrs
属性,该属性包括组件{{1 }}和props
属性(例如emits
,class
,style
侦听器等)。
答案 3 :(得分:1)
您还可以在子组件上指定:value
和@input
事件,并利用事件而不是创建监视。
MyInput.vue
<template>
<input
:value="value"
@input="$emit('input', $event.target.value)" />
</template>
<script>
export default {
props: ['value']
};
</script>
Screen.vue
<template>
<my-input v-model="name" />
</template>
<script>
import MyInput from './MyInput.vue';
export default {
components: { MyInput },
data() {
return {
name: ''
}
}
};
</script>
答案 4 :(得分:1)
下面的示例向您展示如何从父组件到子组件设置模型以及如何在它们之间同步数据。当您将应用程序表单拆分为不同的组件并在不同的上下文中使用它们时,这非常有用。这样,您可以在不同位置使用表单片段(组件),而无需重复自己的操作。
父组件
<template lang="pug">
.parent
Child(:model="model")
br
label(for="c") Set "c" from parent
input(id="c", v-model="model.c")
.result.
<br>
<span> View from parent :</span>
<br>
a = {{ model.a }}
<br>
b = {{ model.b }}
<br>
c = {{ model.c }}
</template>
<script>
import Child from './components/child.vue'
export default {
name: "App",
components: {
Child
},
data() {
return {
// This model is set as a property for the child
model: {
a: 0,
b: 0,
c: 0
}
}
},
};
</script>
儿童组件
<template lang="pug">
.child
label(for="a") Set "a" from child
input(id="a", v-model="internalModel.a", @input="emitModel")
br
br
label(for="b") Set "b" from child
input(id="b", v-model="internalModel.b", @input="emitModel")
.result
br
span View from child
br
| a = {{ internalModel.a }}
br
| b = {{ internalModel.b }}
br
| c = {{ internalModel.c }}
</template>
<script>
export default {
name: 'Child',
props: {
model: {
type: Object
}
},
data() {
return {
internalModel: {
a:0,
b:0,
c:0
}
}
},
methods: {
emitModel() {
this.$emit('input', this.internalModel)
}
},
mounted() {
this.internalModel = this.model;
}
}
</script>
答案 5 :(得分:1)
将数据绑定到自定义复选框或复选框集与将其绑定到文本输入完全不同:
https://www.smashingmagazine.com/2017/08/creating-custom-inputs-vue-js/
<template>
<label>
<input type="checkbox" :checked="shouldBeChecked" :value="value" @change="updateInput">
{{ label }}
</label>
</template>
<script>
export default {
model: {
prop: 'modelValue',
event: 'change',
},
props: {
value: {
type: String,
},
modelValue: {
default: false,
},
label: {
type: String,
required: true,
},
// We set `true-value` and `false-value` to the default true and false so
// we can always use them instead of checking whether or not they are set.
// Also can use camelCase here, but hyphen-separating the attribute name
// when using the component will still work
trueValue: {
default: true,
},
falseValue: {
default: false,
}
},
computed: {
shouldBeChecked() {
if (this.modelValue instanceof <span class="hljs-built_in">Array) {
return this.modelValue.includes(this.value);
}
// Note that `true-value` and `false-value` are camelCase in the JS
return this.modelValue === this.trueValue;
}
},
methods: {
updateInput(event) {
let isChecked = event.target.checked;
if (this.modelValue instanceof Array) {
let newValue = [...this.modelValue];
if (isChecked) {
newValue.push(this.value);
} else {
newValue.splice(newValue.indexOf(this.value), 1);
}
this.$emit('change', newValue);
} else {
this.$emit('change', isChecked ? this.trueValue : this.falseValue);
}
}
}
}
</script>
答案 6 :(得分:1)
使用以下内容,您可以传递所有输入属性,例如占位符:
Vue.component('my-input', {
template: `<div>
<input v-bind="$attrs" :value="value" @input="$emit('input', $event.target.value)">
</div>`,
inheritAttrs: false,
props: ["value"],
})
new Vue({
el: '#app',
data: () => ({
name: "",
}),
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.3/vue.min.js"></script>
<div id="app">
<div>Name: {{name}}</div>
<input placeholder="Standard Input" v-model="name">
<my-input placeholder="My Input" v-model="name"></my-input>
</div>
答案 7 :(得分:0)
对于Vue 3
已接受的答案中提到的value
道具已变为modelValue
,并且emit事件也进行了相应的修改:
https://v3.vuejs.org/guide/migration/v-model.html#migration-strategy
^通过实施已接受的答案并进行了迁移策略中建议的一些更改,使其正常工作。
答案 8 :(得分:0)
除了上面的方法,还有一个更简单的实现
父组件
const value = ref('');
// provide value
provive('value', value);
子组件
// inject value
const value = inject('value');
<input v-modelValue="value" />