3👍
✅
v-model
is just syntax sugar for :value
and @input
. It works differently for native input elements than it does for components; it’s not as simple as just adding v-on="$listeners" v-bind="$props"
to your component’s template. It won’t work.
If you want v-model
to work, you’ll need to handle the input event within the component and emit the changed value:
<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),
});
},
},
});
The above is kind of a hack to make v-model
work correctly, otherwise you could just do this:
<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>
`,
});
Note that class
and style
cannot be proxied to the inner <select>
because they’re not props, they’re handled specially by Vue and will be applied to the root element of the component’s template.
EDIT: Actually you can proxy class
and style
but it requires writing the render function manually:
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)]);
},
});
Source:stackexchange.com