也许这是一个简单的问题,但我找不到创建基本包装器组件的正确方法。例如,我有一个像这样的选择:
<select v-model="foo" name="bar" v-validate="'required'" v-bind:class="{ invalid: errors.has('bar') }">
<option value="">Default</option>
<option value="1">Value 1</option>
<option value="2">Value 2</option>
</select>
我需要添加一些糖,一个div
加上类custom-select
。所以我创建了一个custom-select
组件来包装原生选择:
Vue.component('custom-select', {
template: `
<div class="custom-select">
<select v-on="$listeners" v-bind="$props">
<slot></slot>
</select>
</div>
`,
});
我的问题是我的组件没有继承像v-model
和class
这样的道具。我想知道是否有全局方式,不必重写组件中的所有道具并让他继承一切?
答案 0 :(得分:2)
v-model
只是:value
和@input
的语法糖。它对本机输入元素的工作方式与对组件的工作方式不同;它并不像将v-on="$listeners" v-bind="$props"
添加到您的组件模板那么简单。它不会工作。
如果您希望v-model
正常工作,您需要处理组件中的输入事件并发出更改后的值:
<custom-select v-model="selected">
Vue.component('custom-select', {
template: `
<div class="custom-select">
<select v-bind="$attrs" v-on="computedListeners">
<slot></slot>
</select>
</div>
`,
computed: {
computedListeners() {
return Object.assign({}, this.$listeners, {
input: e => this.$emit('input', e.target.value),
});
},
},
});
以上是让v-model
正常工作的黑客攻击,否则你可以这样做:
<custom-select :value="selected" @input="selected = $event.target.value">
Vue.component('custom-select', {
template: `
<div class="custom-select">
<select v-bind="$attrs" v-on="$listeners">
<slot></slot>
</select>
</div>
`,
});
请注意,class
和style
无法代理内部<select>
,因为它们不是道具,它们由Vue专门处理并将应用于组件模板的根元素。
编辑:实际上你可以代理class
和style
,但它需要手动编写渲染功能:
Vue.component('custom-select', {
functional: true,
render(h, ctx) {
const on = Object.assign({}, ctx.listeners);
if (ctx.listeners.input) {
// Required for v-model to work
on.input = e => ctx.listeners.input(e.target.value);
}
const data = Object.assign({}, ctx.data, { on });
return h('div', { class: 'custom-select' }, [h('select', data, ctx.children)]);
},
});