在做购物车的全选和反选功能的时候,因为要将选项框的状态发送请求提交到后台,所以将对应的功能写在了change事件绑定的函数里:
这里el-checkbox绑定的是 cartStore.allSelected,是一个计算属性,然后我发现我点击全选这个框的话,change事件是会触发的,请求也会正常发送,但是当我是通过js逻辑改变了它的值(比如我把购物车的每个商品的选框都选中,allSelected会变成true),这种情况下是不会触发change事件的,也就不会发送请求。
我的解决办法是自己封装一个自定义组件:
1. 我会给这个组件用v-model绑定allSelected,那allSelected就要可写
2. 在这个子组件我就要实现v-model的原理也就是 :modelValue 和 @update:modelValue,所以在这个子组件中,可以根据父组件传过来的值再搞一个计算属性value,这个计算属性的getter返回modelValue接收的值,setter进行emit传递update:modelValue和值。
3. 子组件里面的el-checkbox绑定数据value,如果value的值改变了,就会触发update:modelValue,到这里就是实现了el-checkbox改变了value的值也会间接改变父组件传过来的值。
就是value改变 -> emit('update:modelValue',val) -> 影响到v-model="cartStore.allSelected" -> allSelected的set()就会执行,然后又返回了get()
4. 最后在子组件中再对value进行监听,如果改变了,就会像父组件emit自定义的autoChange事件,接着在父组件中的my-checkbox绑定autoChange事件执行发送请求到后台的函数就行。
这一步就是 emit的多了一个'autoChange' -> 发送请求。
// cartStore.js
// 设置全选的计算属性,getter和setter
const allSelected = computed({
get() {
return cartData.value.every((item) => item.selected)
},
set(val) {
// 让全选计算属性可写
cartData.value.forEach((item) => (item.selected = val))
}
})
// 自定义组件 myCheckbox.vue
<script setup>
import { computed, watch } from 'vue'
const props = defineProps({
// 这里不改名 父组件直接使用v-model就会传过来
modelValue: Boolean
})
const emit = defineEmits(['update:modelValue', 'autoChange'])
const value = computed({
get() {
return props.modelValue
},
set(val) {
emit('update:modelValue', val)
}
})
// 监听value 如果改变了,就提交到父组件autoChange
watch(value, () => {
emit('autoChange')
})
</script>
<template>
// v-model不能直接绑定父组件传过来的modelValue,所以还得用一个计算属性来实现父组件v-model的功能
// 然后监听value进行绑定
<el-checkbox v-model="value"></el-checkbox>
</template>
<style lang="scss" scoped></style>
// 父组件
<script setup>
import { changeCart, changeSelect } from '@/api/cart'
import { useCartStore } from '@/stores'
import MyCheckbox from '@/components/MyCheckbox.vue'
const cartStore = useCartStore()
const onChange = async (item) => {
// 商品修改重新提交到后台(登录状态下)
if (cartStore.isLogin) {
await changeCart(item)
// 提交后更新购物车
cartStore.updateCart()
}
}
const onChangeAllSelect = async () => {
// 提交全选/取消全选状态到后台数据
if (cartStore.isLogin) {
await changeSelect({
selected: cartStore.allSelected,
ids: cartStore.cartData.map((item) => item.skuId)
})
// 提交后更新购物车
cartStore.updateCart()
}
}
</script>
<template>
....
<my-checkbox
v-model="cartStore.allSelected"
@autoChange="onChangeAllSelect"
></my-checkbox>
...
<my-checkbox v-model="i.selected" @autoChange="onChange(i)"></my-checkbox>
...
</template>