在 Vue 3 中,如何使自定义组件与复选框组的 v-model 一起工作?
In Vue3, how to make Custom Component work with v-model for group of checkboxs?
下面给出的代码您可以看到 v-model
的魔力,在选中/取消选中复选框后,数组 checkedNames
将自动 add/remove 命名。我们不必向数组中的 push/slice/filter 名称写入任何内容,对吗?
const { ref } = Vue;
const App = {
setup () {
const checkedNames = ref([])
return { checkedNames }
}
}
Vue.createApp(App).mount("#app");
<script src="https://unpkg.com/vue@3.0.11/dist/vue.global.js"></script>
<div id="app">
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>
我的问题是:如何使用自定义组件实现相同的功能?
你可以看到,在下面给出的代码片段中,我尝试了但我不喜欢它,因为我们缺少 v-model
的魔力,相反我在我的函数 addOrRemoveItem()
[=27 中处理它=]
heads-up: It may seem to you that I am over explaining :) sorry for that.
我关注了this tutorial for some idea but was not much helpful, then referred vue official doc here。下面是功能代码,但有点矫枉过正。
const { ref, createApp } = Vue;
const app = createApp({
setup() {
const itemsSelected = ref([]);
const items = ref([
{ id: '1', name: 'Jack' },
{ id: '2', name: 'John' },
{ id: '3', name: 'Mike' },
]);
const addOrRemoveItem = (itemId) => {
const exists = itemsSelected.value.includes(itemId);
if (exists) {
itemsSelected.value = itemsSelected.value.filter((id) => id !== itemId);
} else {
itemsSelected.value.push(itemId);
}
};
return {
items,
itemsSelected,
addOrRemoveItem,
};
},
});
app.component('custom-checkbox', {
props: {
item: { type: Object, default: () => ({}) },
modelValue: { type: Array, default: () => [] },
},
template: `
<div>
<input
type="checkbox" :value="item.id"
@change="$emit('update:model-value', $event.target.checked)"
> {{ item.name }}
</div>
`
})
app.mount("#app");
<script src="https://unpkg.com/vue@3.0.11/dist/vue.global.js"></script>
<div id="app">
<div><code>itemsSelected: {{ itemsSelected }}</code></div>
<hr />
<custom-checkbox
v-for="item in items"
:key="item.id"
:item="item"
:model-value="itemsSelected"
@update:model-value="addOrRemoveItem(item.id)"
></custom-checkbox>
</div>
如上所述,当我按照 doc $emit('update:model-value', ...)
中提到的代码时,代码有点矫枉过正,它可以是任何东西,例如:$emit('val-updated')
,这是之后的简化版本删除不需要的 prop
并减少 $emit
.
的长度
const { ref, createApp } = Vue;
const app = createApp({
setup() {
const itemsSelected = ref([]);
const items = ref([
{ id: '1', name: 'Jack' },
{ id: '2', name: 'John' },
{ id: '3', name: 'Mike' },
]);
const addOrRemoveItem = (itemId) => {
const exists = itemsSelected.value.includes(itemId);
if (exists) {
itemsSelected.value = itemsSelected.value.filter((id) => id !== itemId);
} else {
itemsSelected.value.push(itemId);
}
};
return {
items,
itemsSelected,
addOrRemoveItem,
};
},
});
app.component('custom-checkbox', {
props: {
item: { type: Object, default: () => ({}) },
},
template: `
<div>
<input
type="checkbox" :value="item.id"
@change="$emit('val-updated')"
> {{ item.name }}
</div>
`
})
app.mount("#app");
<script src="https://unpkg.com/vue@3.0.11/dist/vue.global.js"></script>
<div id="app">
<div><code>itemsSelected: {{ itemsSelected }}</code></div>
<hr />
<custom-checkbox
v-for="item in items"
:key="item.id"
:item="item"
@val-updated="addOrRemoveItem(item.id)"
></custom-checkbox>
</div>
根本不需要addOrRemoveItem()
方法。只需让 checkbox
的默认 Vue v-model
逻辑来完成繁重的工作。您唯一需要做的就是为 v-model
使用 computed
道具(因为无法直接使用道具,因为不能从子组件中更改道具)
const {
ref,
createApp
} = Vue;
const app = createApp({
setup() {
const itemsSelected = ref([]);
const items = ref([{
id: '1',
name: 'Jack'
},
{
id: '2',
name: 'John'
},
{
id: '3',
name: 'Mike'
},
]);
return {
items,
itemsSelected,
};
},
});
app.component('custom-checkbox', {
props: {
item: {
type: Object,
default: () => ({})
},
modelValue: {
type: Array,
required: true
}
},
emits: ['update:modelValue'],
computed: {
model: {
get() {
return this.modelValue
},
set(value) {
this.$emit('update:modelValue', value)
}
}
},
template: `
<div>
<input
type="checkbox" :value="item.id" v-model="model"
> {{ item.name }}
</div>
`
})
app.mount("#app");
<script src="https://unpkg.com/vue@3.0.11/dist/vue.global.js"></script>
<div id="app">
<div><code>itemsSelected: {{ itemsSelected }}</code></div>
<hr />
<custom-checkbox v-for="item in items" :key="item.id" :item="item" v-model="itemsSelected"></custom-checkbox>
</div>
下面给出的代码您可以看到 v-model
的魔力,在选中/取消选中复选框后,数组 checkedNames
将自动 add/remove 命名。我们不必向数组中的 push/slice/filter 名称写入任何内容,对吗?
const { ref } = Vue;
const App = {
setup () {
const checkedNames = ref([])
return { checkedNames }
}
}
Vue.createApp(App).mount("#app");
<script src="https://unpkg.com/vue@3.0.11/dist/vue.global.js"></script>
<div id="app">
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
</div>
我的问题是:如何使用自定义组件实现相同的功能?
你可以看到,在下面给出的代码片段中,我尝试了但我不喜欢它,因为我们缺少 v-model
的魔力,相反我在我的函数 addOrRemoveItem()
[=27 中处理它=]
heads-up: It may seem to you that I am over explaining :) sorry for that.
我关注了this tutorial for some idea but was not much helpful, then referred vue official doc here。下面是功能代码,但有点矫枉过正。
const { ref, createApp } = Vue;
const app = createApp({
setup() {
const itemsSelected = ref([]);
const items = ref([
{ id: '1', name: 'Jack' },
{ id: '2', name: 'John' },
{ id: '3', name: 'Mike' },
]);
const addOrRemoveItem = (itemId) => {
const exists = itemsSelected.value.includes(itemId);
if (exists) {
itemsSelected.value = itemsSelected.value.filter((id) => id !== itemId);
} else {
itemsSelected.value.push(itemId);
}
};
return {
items,
itemsSelected,
addOrRemoveItem,
};
},
});
app.component('custom-checkbox', {
props: {
item: { type: Object, default: () => ({}) },
modelValue: { type: Array, default: () => [] },
},
template: `
<div>
<input
type="checkbox" :value="item.id"
@change="$emit('update:model-value', $event.target.checked)"
> {{ item.name }}
</div>
`
})
app.mount("#app");
<script src="https://unpkg.com/vue@3.0.11/dist/vue.global.js"></script>
<div id="app">
<div><code>itemsSelected: {{ itemsSelected }}</code></div>
<hr />
<custom-checkbox
v-for="item in items"
:key="item.id"
:item="item"
:model-value="itemsSelected"
@update:model-value="addOrRemoveItem(item.id)"
></custom-checkbox>
</div>
如上所述,当我按照 doc $emit('update:model-value', ...)
中提到的代码时,代码有点矫枉过正,它可以是任何东西,例如:$emit('val-updated')
,这是之后的简化版本删除不需要的 prop
并减少 $emit
.
const { ref, createApp } = Vue;
const app = createApp({
setup() {
const itemsSelected = ref([]);
const items = ref([
{ id: '1', name: 'Jack' },
{ id: '2', name: 'John' },
{ id: '3', name: 'Mike' },
]);
const addOrRemoveItem = (itemId) => {
const exists = itemsSelected.value.includes(itemId);
if (exists) {
itemsSelected.value = itemsSelected.value.filter((id) => id !== itemId);
} else {
itemsSelected.value.push(itemId);
}
};
return {
items,
itemsSelected,
addOrRemoveItem,
};
},
});
app.component('custom-checkbox', {
props: {
item: { type: Object, default: () => ({}) },
},
template: `
<div>
<input
type="checkbox" :value="item.id"
@change="$emit('val-updated')"
> {{ item.name }}
</div>
`
})
app.mount("#app");
<script src="https://unpkg.com/vue@3.0.11/dist/vue.global.js"></script>
<div id="app">
<div><code>itemsSelected: {{ itemsSelected }}</code></div>
<hr />
<custom-checkbox
v-for="item in items"
:key="item.id"
:item="item"
@val-updated="addOrRemoveItem(item.id)"
></custom-checkbox>
</div>
根本不需要addOrRemoveItem()
方法。只需让 checkbox
的默认 Vue v-model
逻辑来完成繁重的工作。您唯一需要做的就是为 v-model
使用 computed
道具(因为无法直接使用道具,因为不能从子组件中更改道具)
const {
ref,
createApp
} = Vue;
const app = createApp({
setup() {
const itemsSelected = ref([]);
const items = ref([{
id: '1',
name: 'Jack'
},
{
id: '2',
name: 'John'
},
{
id: '3',
name: 'Mike'
},
]);
return {
items,
itemsSelected,
};
},
});
app.component('custom-checkbox', {
props: {
item: {
type: Object,
default: () => ({})
},
modelValue: {
type: Array,
required: true
}
},
emits: ['update:modelValue'],
computed: {
model: {
get() {
return this.modelValue
},
set(value) {
this.$emit('update:modelValue', value)
}
}
},
template: `
<div>
<input
type="checkbox" :value="item.id" v-model="model"
> {{ item.name }}
</div>
`
})
app.mount("#app");
<script src="https://unpkg.com/vue@3.0.11/dist/vue.global.js"></script>
<div id="app">
<div><code>itemsSelected: {{ itemsSelected }}</code></div>
<hr />
<custom-checkbox v-for="item in items" :key="item.id" :item="item" v-model="itemsSelected"></custom-checkbox>
</div>