解决watch循环

This commit is contained in:
2025-11-27 12:02:07 +08:00
parent 99eb18c4bd
commit 2b236c543d

View File

@@ -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 }
); );