解决watch循环
This commit is contained in:
@@ -81,7 +81,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, watch, reactive } from 'vue';
|
import { computed, watch, reactive, ref } from 'vue';
|
||||||
|
|
||||||
interface ParamOption {
|
interface ParamOption {
|
||||||
label: string;
|
label: string;
|
||||||
@@ -117,6 +117,9 @@ const emit = defineEmits<{
|
|||||||
// 内部值使用 reactive,保证双向绑定
|
// 内部值使用 reactive,保证双向绑定
|
||||||
const innerValue = reactive<Record<string, any>>({});
|
const innerValue = reactive<Record<string, any>>({});
|
||||||
|
|
||||||
|
// 同步标志位,防止死循环
|
||||||
|
const isSyncing = ref(false);
|
||||||
|
|
||||||
// 为了兼容不同类型控件,做一些视图层的映射
|
// 为了兼容不同类型控件,做一些视图层的映射
|
||||||
const innerNumberMap = computed({
|
const innerNumberMap = computed({
|
||||||
get() {
|
get() {
|
||||||
@@ -136,14 +139,42 @@ const innerBoolMap = computed({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 比较两个对象是否相等(浅比较)
|
||||||
|
function isEqual(obj1: Record<string, any>, obj2: Record<string, any>): boolean {
|
||||||
|
const keys1 = Object.keys(obj1);
|
||||||
|
const keys2 = Object.keys(obj2);
|
||||||
|
|
||||||
|
if (keys1.length !== keys2.length) return false;
|
||||||
|
|
||||||
|
return keys1.every(key => {
|
||||||
|
const val1 = obj1[key];
|
||||||
|
const val2 = obj2[key];
|
||||||
|
|
||||||
|
// 处理数组的比较(如日期范围)
|
||||||
|
if (Array.isArray(val1) && Array.isArray(val2)) {
|
||||||
|
if (val1.length !== val2.length) return false;
|
||||||
|
return val1.every((item, index) => item === val2[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return val1 === val2;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 初始化 / 外部变更时同步
|
// 初始化 / 外部变更时同步
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
(val) => {
|
(val) => {
|
||||||
|
// 如果正在同步或者值没有变化,跳过
|
||||||
|
if (isSyncing.value || isEqual(val || {}, innerValue)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSyncing.value = true;
|
||||||
Object.keys(innerValue).forEach((k) => delete innerValue[k]);
|
Object.keys(innerValue).forEach((k) => delete innerValue[k]);
|
||||||
if (val) {
|
if (val) {
|
||||||
Object.assign(innerValue, val);
|
Object.assign(innerValue, val);
|
||||||
}
|
}
|
||||||
|
isSyncing.value = false;
|
||||||
},
|
},
|
||||||
{ immediate: true, deep: true }
|
{ immediate: true, deep: true }
|
||||||
);
|
);
|
||||||
@@ -152,7 +183,15 @@ watch(
|
|||||||
watch(
|
watch(
|
||||||
innerValue,
|
innerValue,
|
||||||
(val) => {
|
(val) => {
|
||||||
emit('update:modelValue', { ...val });
|
// 如果正在同步,跳过
|
||||||
|
if (isSyncing.value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只有当值真的改变时才 emit
|
||||||
|
if (!isEqual(val, props.modelValue || {})) {
|
||||||
|
emit('update:modelValue', { ...val });
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{ deep: true }
|
{ deep: true }
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user