尝试创建通用输入组件
我正在开发一个 Web 应用程序,其中有很多表单需要创建,为此我使用了 Vue,因此我一直在尝试创建一个可以一直使用的通用输入组件。我使用的是 Bootstrap 网格,因此我的想法是,我应该能够向组件传递要占用的列数、标签、名称和用作 v-model 的属性。我想我已经差不多做到了,但我遇到了 props 变异的问题 - [Vue 警告]:避免直接变异 prop,因为每当父组件重新呈现时,该值都会被覆盖。相反,使用基于 prop 值的数据或计算属性。变异的 prop:“model” (在组件中找到)。 这是模板(简化形式):
<template id="field">
<div v-bind:class="colsClass">
<div class='form-group form-group-sm'>
<label v-bind:for="name">{{labelText}}</label>
<input v-bind:id='name' ref="input" class='form-control' v-bind:name='name' v-model='model'/>
</div>
</div>
这是(再次简化的)JS:
Vue.component('field', {
template: '#field',
props: ['cols','label','group','name','model'],
computed:{
colsClass:function(){
return "col-xs-"+this.cols
}
,
labelText:function(){
if(this.label) {
return this.label
} else {
return _.startCase(this.name);
}
}
}
});
这在另一个“edit-product”组件中使用,如下所示:
<field :cols="8" name="name" :model="product.name"></field>
这显示 OK,但当我编辑字段的值时会抛出错误(或更准确地说是警告)。那么我做错了什么?
实际上,我选择的解决方案比上面建议的更简单,实际上非常简单,取自 https://forum-archive.vuejs.org/topic/4468/trying-to-understand-v-model-on-custom-components/9 。
我不需要 'model' prop,我有一个 'value' prop,因此 JS 更改为此:
Vue.component('field', {
template: '#field',
props: ['cols','label','group','name','value'],
computed:{
colsClass:function(){
return "col-xs-"+this.cols
}
,
labelText:function(){
if(this.label) {
return this.label
} else {
return _.startCase(this.name);
}
}
}
});
模板变为:
<div class='form-group form-group-sm'>
<label :for="name">{{labelText}}</label>
<input :id='name' :name='name' class='form-control' :value="value" @input="$emit('input', $event.target.value)"/>
</div>
</div>
我像这样使用它这个:
<field :cols="8" name="name" v-model="product.name"></field>
不同之处在于我实际上并没有尝试传递模型 prop,我只是传递一个值,并监听该值的变化。它似乎运行良好,并且足够干净和简单。我的下一个挑战是将一组任意属性传递给输入,但这是另一个问题的主题。
正如警告所建议的那样,您不应直接编辑要传递的值的 prop。
而是将其用作原始值,并在输入上设置一个单独的值 - 您可以将其传递给 v-model。如果您需要父级具有当前值,则还应传递一个 prop,以便您更新父级的参数,即
输入组件
# script
props: [
'origValue',
'valueChange',
],
data: {
inputValue: '',
...
},
mounted () {
this.inputValue = this.origValue
},
watch: {
inputValue () {
this.valueChange(this.inputValue)
},
...
},
...
# template
<input type="text" v-model="inputValue">
父级
# script
data () {
return {
fieldValue: 'foo',
...
},
},
methods: {
updateField (value) {
this.fieldValue = value
},
...
},
...
# template
<field :value-change="updateField" :orig-value="fieldValue"></field>