解决watch循环
This commit is contained in:
@@ -81,7 +81,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, watch, reactive } from 'vue';
|
||||
import { computed, watch, reactive, ref } from 'vue';
|
||||
|
||||
interface ParamOption {
|
||||
label: string;
|
||||
@@ -117,6 +117,9 @@ const emit = defineEmits<{
|
||||
// 内部值使用 reactive,保证双向绑定
|
||||
const innerValue = reactive<Record<string, any>>({});
|
||||
|
||||
// 同步标志位,防止死循环
|
||||
const isSyncing = ref(false);
|
||||
|
||||
// 为了兼容不同类型控件,做一些视图层的映射
|
||||
const innerNumberMap = computed({
|
||||
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(
|
||||
() => props.modelValue,
|
||||
(val) => {
|
||||
// 如果正在同步或者值没有变化,跳过
|
||||
if (isSyncing.value || isEqual(val || {}, innerValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
isSyncing.value = true;
|
||||
Object.keys(innerValue).forEach((k) => delete innerValue[k]);
|
||||
if (val) {
|
||||
Object.assign(innerValue, val);
|
||||
}
|
||||
isSyncing.value = false;
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
@@ -152,7 +183,15 @@ watch(
|
||||
watch(
|
||||
innerValue,
|
||||
(val) => {
|
||||
emit('update:modelValue', { ...val });
|
||||
// 如果正在同步,跳过
|
||||
if (isSyncing.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 只有当值真的改变时才 emit
|
||||
if (!isEqual(val, props.modelValue || {})) {
|
||||
emit('update:modelValue', { ...val });
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user