Fix Bug #500: 【门诊医生站】检查申请右侧"检查项目分类"切换时,界面出现明显抖动/闪烁
修复策略A(直接修复代码逻辑),采用4个手术式修改消除抖动根因: 1. 方法列表区域 v-if → v-show:避免异步加载后 DOM 突然插入导致高度跳变 2. CSS transition: all → height/max-height:明确过渡属性,防止子元素意外动画 3. .collapse-scroll 添加 min-height: 120px:固定最小高度,避免 flex 容器高度突变 4. handleCategoryExpand 添加 currentActiveCategory 守卫:快速切换分类时忽略过期请求响应,防止旧数据覆盖导致闪烁 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -376,8 +376,9 @@
|
|||||||
加载中...
|
加载中...
|
||||||
</div>
|
</div>
|
||||||
<!-- Bug #428修复: 渲染分类联动加载的检查方法列表 -->
|
<!-- Bug #428修复: 渲染分类联动加载的检查方法列表 -->
|
||||||
|
<!-- Bug #500修复: v-if 改为 v-show,避免方法列表加载时 DOM 突然插入导致高度跳变 -->
|
||||||
<div
|
<div
|
||||||
v-if="cat.methods && cat.methods.length > 0"
|
v-show="cat.methods && cat.methods.length > 0"
|
||||||
class="method-section"
|
class="method-section"
|
||||||
>
|
>
|
||||||
<div class="method-section-title">检查方法</div>
|
<div class="method-section-title">检查方法</div>
|
||||||
@@ -682,6 +683,7 @@ const categoryList = ref([]); // 原始分类+项目数据
|
|||||||
const dictSearchKey = ref('');
|
const dictSearchKey = ref('');
|
||||||
const activeNames = ref(''); // 当前展开的折叠项
|
const activeNames = ref(''); // 当前展开的折叠项
|
||||||
const categoryLoadingSet = ref(new Set()); // Bug #500: 正在加载方法的分类集合
|
const categoryLoadingSet = ref(new Set()); // Bug #500: 正在加载方法的分类集合
|
||||||
|
const currentActiveCategory = ref(null); // Bug #500: 记录当前激活的分类,忽略过期请求响应
|
||||||
const isAnimating = ref(false); // Bug #500: 防止快速切换时折叠动画重叠导致抖动
|
const isAnimating = ref(false); // Bug #500: 防止快速切换时折叠动画重叠导致抖动
|
||||||
|
|
||||||
const allMethods = ref([]);
|
const allMethods = ref([]);
|
||||||
@@ -799,15 +801,18 @@ const availableMethods = computed(() => {
|
|||||||
// 当可选方法列表改变时,如果当前选中的方法不在新列表中,则清空
|
// 当可选方法列表改变时,如果当前选中的方法不在新列表中,则清空
|
||||||
// #428: 分类展开时联动加载检查方法
|
// #428: 分类展开时联动加载检查方法
|
||||||
// Bug #500: 使用 categoryLoadingSet 替代 dictLoading,避免切换分类时整个区域闪烁
|
// Bug #500: 使用 categoryLoadingSet 替代 dictLoading,避免切换分类时整个区域闪烁
|
||||||
|
// Bug #500: 添加 currentActiveCategory 守卫,忽略过期请求响应,防止快速切换时数据闪烁
|
||||||
async function handleCategoryExpand(cat) {
|
async function handleCategoryExpand(cat) {
|
||||||
if (!cat || !cat.typeName) return;
|
if (!cat || !cat.typeName) return;
|
||||||
|
|
||||||
// 如果已加载过或正在加载中,跳过
|
|
||||||
if ((cat.methods && cat.methods.length > 0) || categoryLoadingSet.value.has(cat.typeId)) return;
|
if ((cat.methods && cat.methods.length > 0) || categoryLoadingSet.value.has(cat.typeId)) return;
|
||||||
|
|
||||||
categoryLoadingSet.value.add(cat.typeId);
|
categoryLoadingSet.value.add(cat.typeId);
|
||||||
|
currentActiveCategory.value = cat.typeId;
|
||||||
try {
|
try {
|
||||||
const res = await searchCheckMethod({ checkType: cat.typeName });
|
const res = await searchCheckMethod({ checkType: cat.typeName });
|
||||||
|
// 忽略过期请求:用户已切换到其他分类,丢弃当前响应
|
||||||
|
if (currentActiveCategory.value !== cat.typeId) return;
|
||||||
let data = res?.data?.data || res?.data || res?.rows || res;
|
let data = res?.data?.data || res?.data || res?.rows || res;
|
||||||
if (!Array.isArray(data) && res?.data && Array.isArray(res.data.data)) {
|
if (!Array.isArray(data) && res?.data && Array.isArray(res.data.data)) {
|
||||||
data = res.data.data;
|
data = res.data.data;
|
||||||
@@ -826,18 +831,22 @@ async function handleCategoryExpand(cat) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (currentActiveCategory.value !== cat.typeId) return;
|
||||||
console.error('加载分类检查方法失败', err);
|
console.error('加载分类检查方法失败', err);
|
||||||
} finally {
|
} finally {
|
||||||
categoryLoadingSet.value.delete(cat.typeId);
|
categoryLoadingSet.value.delete(cat.typeId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Bug #500: 添加防抖逻辑,快速切换时跳过中间状态的动画,避免高度跳变和白屏闪烁
|
// Bug #500修复: 添加防抖逻辑,快速切换时跳过中间状态的动画,避免高度跳变和白屏闪烁
|
||||||
function handleCollapseChange(activeName) {
|
function handleCollapseChange(activeName) {
|
||||||
if (isAnimating.value) return; // 动画进行中,忽略后续点击
|
if (isAnimating.value) return; // 动画进行中,忽略后续点击
|
||||||
|
|
||||||
isAnimating.value = true;
|
isAnimating.value = true;
|
||||||
setTimeout(() => { isAnimating.value = false; }, 300); // 与 CSS 过渡时长一致
|
setTimeout(() => { isAnimating.value = false; }, 300); // 与 CSS 过渡时长一致
|
||||||
|
|
||||||
|
// Bug #500修复: 记录当前激活的分类,用于 handleCategoryExpand 中忽略过期请求
|
||||||
|
currentActiveCategory.value = activeName || null;
|
||||||
|
|
||||||
if (activeName) {
|
if (activeName) {
|
||||||
// Bug #428修复: 直接从 categoryList(原始响应式数组)查找分类,
|
// Bug #428修复: 直接从 categoryList(原始响应式数组)查找分类,
|
||||||
// 确保后续 handleCategoryExpand 对 cat.methods 的赋值能正确触发 Vue 响应式更新
|
// 确保后续 handleCategoryExpand 对 cat.methods 的赋值能正确触发 Vue 响应式更新
|
||||||
@@ -1642,6 +1651,7 @@ defineExpose({ getList });
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden; /* Bug #500: 防止切换时水平方向溢出导致抖动 */
|
overflow-x: hidden; /* Bug #500: 防止切换时水平方向溢出导致抖动 */
|
||||||
|
min-height: 120px; /* Bug #500: 固定最小高度,避免分类切换时 flex 容器高度突变 */
|
||||||
}
|
}
|
||||||
.empty-hint {
|
.empty-hint {
|
||||||
color: #909399;
|
color: #909399;
|
||||||
@@ -1914,10 +1924,10 @@ defineExpose({ getList });
|
|||||||
height: auto;
|
height: auto;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
}
|
}
|
||||||
/* Bug #500: 折叠内容添加平滑过渡动画,避免切换时高度跳变 */
|
/* Bug #500修复: 折叠内容使用明确属性过渡,避免 transition: all 导致子元素意外动画 */
|
||||||
:deep(.el-collapse-item__content) {
|
:deep(.el-collapse-item__content) {
|
||||||
padding-bottom: 4px;
|
padding-bottom: 4px;
|
||||||
transition: all 0.3s ease;
|
transition: height 0.3s ease, max-height 0.3s ease;
|
||||||
}
|
}
|
||||||
/* Bug #500: 折叠面板动画容器,添加 overflow:hidden 防止展开时内容溢出导致闪烁 */
|
/* Bug #500: 折叠面板动画容器,添加 overflow:hidden 防止展开时内容溢出导致闪烁 */
|
||||||
:deep(.el-collapse-item__wrap) {
|
:deep(.el-collapse-item__wrap) {
|
||||||
|
|||||||
Reference in New Issue
Block a user