[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fteam-documents\u002F15":3,"knowledge-related-\u002Fknowledge\u002Fteam-documents\u002F15":775,"knowledge-series-\u002Fknowledge\u002Fteam-documents\u002F15":802},{"source":4,"connector":5,"page":6},"sqlite","better-sqlite3",{"path":7,"title":8,"description":9,"category":10,"tags":11,"date":15,"pinned":16,"draft":16,"body":17,"seo":771,"stem":772,"id":773,"extension":774},"\u002Fknowledge\u002Fteam-documents\u002F15","移动端返回事件触发两次问题复盘","App + H5 混合开发中，点击返回后直接跳出 H5 页面回到原生首页。复盘现象、复现路径、双触发的根因、两种修复方案及取舍建议，并给出回归检查清单。","团队文档",[12,13,14],"team","vue","mobile","2021-03-09",false,{"type":18,"value":19,"toc":760},"minimark",[20,23,36,40,53,56,59,73,76,91,99,102,114,129,132,139,157,160,167,170,221,231,234,241,415,514,624,627,687,690,693,739,742,756],[21,22,8],"h1",{"id":8},[24,25,26,27,31,32,35],"p",{},"在一次 App + H5 混合开发项目中，出现了「点击返回后直接跳出 H5 页面」的异常。\nH5 端技术栈为 ",[28,29,30],"code",{},"Vue 3 + Vant 3","，顶部 ",[28,33,34],{},"tabBar"," 为二次封装组件。",[37,38,39],"h2",{"id":39},"问题现象",[41,42,43,47,50],"ul",{},[44,45,46],"li",{},"页面层级：一级 H5 页面 -> 二级 H5 页面；",[44,48,49],{},"预期行为：二级页面点击返回，应停留在 H5 内并回到一级页面；",[44,51,52],{},"实际行为：二级页面返回时直接退出整个 H5 容器，回到 App 原生首页，H5 内的页面栈被“跳过”。",[24,54,55],{},"从用户视角看，这是一次典型的「返回过深」问题：本应回退一层，实际回退了两层甚至更多。",[37,57,58],{"id":58},"影响范围",[41,60,61,67,70],{},[44,62,63,64,66],{},"所有经过二次封装 ",[28,65,34],{}," 组件、且同时监听了返回事件的二级及以上层级页面；",[44,68,69],{},"App 内嵌 WebView 场景下复现明显，普通浏览器直接访问 H5 时基本不复现（这是定位问题方向的重要线索）；",[44,71,72],{},"影响用户对页面层级的信任感，容易造成「误以为已退出功能」的困惑，甚至需要重新进入功能入口。",[37,74,75],{"id":75},"复现与排查",[24,77,78,79,82,83,86,87,90],{},"在浏览器中直接访问，",[28,80,81],{},"vue-router"," 的 ",[28,84,85],{},"router.back()","、",[28,88,89],{},"router.go(-1)"," 行为正常，页面层级回退符合预期。",[24,92,93,94,98],{},"但在 App WebView 容器中，返回逻辑被触发了",[95,96,97],"strong",{},"两次","，导致页面层级连续回退：本应回退一层，实际回退了两层，因此表现为“直接跳出 H5”。",[24,100,101],{},"复现步骤：",[103,104,105,108,111],"ol",{},[44,106,107],{},"在 App 内打开 H5 一级页面，再跳转到二级页面；",[44,109,110],{},"点击二级页面的返回按钮（或 App 原生返回键，二者链路一致）；",[44,112,113],{},"观察实际落地页面：预期停在一级页面，实际直接回到 App 原生首页。",[24,115,116,117,120,121,124,125,128],{},"通过 ",[28,118,119],{},"console"," 与 ",[28,122,123],{},"debugger"," 在返回事件触发处打点排查确认：",[95,126,127],{},"同一个用户返回动作，触发了两次“返回”的执行逻辑","。",[37,130,131],{"id":131},"根因分析",[24,133,134,135,138],{},"返回事件在组件内部存在",[95,136,137],{},"两条调用链","，二者叠加导致重复执行：",[103,140,141,150],{},[44,142,143,144,146,147,149],{},"子组件（二次封装的 ",[28,145,34],{},"）内部已经调用了返回 API（例如内部直接调用了 ",[28,148,85],{}," 或 App 提供的原生返回桥接方法）；",[44,151,152,153,156],{},"同时，子组件又通过 ",[28,154,155],{},"emit"," 抛出一个「返回」事件，父组件监听到该事件后，再次触发一次返回逻辑。",[24,158,159],{},"两条链路在普通浏览器环境下叠加执行，浏览器历史栈足够宽容，多退一层通常还在 H5 路由栈内，因此现象不明显；但在 App WebView 场景中，返回动作会同时影响「H5 内部路由栈」与「WebView 容器本身的返回栈」，两次触发叠加后表现为「直接跳出 H5，回到原生首页」。",[24,161,162],{},[163,164],"img",{"alt":165,"src":166},"效果图","https:\u002F\u002Fcdn.wangxiaoze.cn\u002Fstatic\u002Fimages\u002F05a9ab7c-4cba-4876-b9b0-68596d65a8e4.svg",[37,168,169],{"id":169},"修复方案",[171,172,173,189],"table",{},[174,175,176],"thead",{},[177,178,179,183,186],"tr",{},[180,181,182],"th",{},"方案",[180,184,185],{},"做法",[180,187,188],{},"适用场景",[190,191,192,207],"tbody",{},[177,193,194,198,204],{},[195,196,197],"td",{},"方案一（推荐）",[195,199,200,201,203],{},"移除子组件内置的返回 API 调用，仅保留 ",[28,202,155],{},"，统一由父组件处理返回逻辑",[195,205,206],{},"子组件与父组件职责边界清晰，返回逻辑应集中管理时优先选择",[177,208,209,212,218],{},[195,210,211],{},"方案二",[195,213,214,215,217],{},"保留双层结构，但修改 ",[28,216,155],{}," 事件名，避免与子组件内部事件同名冲突",[195,219,220],{},"子组件内置返回逻辑无法轻易移除（如涉及其他历史依赖）时的折中方案",[24,222,223,224,230],{},"实现原则：",[95,225,226,227,229],{},"父组件监听的事件名必须与子组件 ",[28,228,155],{}," 定义一致，且同一返回动作只能保留一条执行链路","。无论采用哪种方案，核心目标都是确保“一次用户操作只触发一次返回逻辑”。",[37,232,233],{"id":233},"修复代码示意",[24,235,236,237,240],{},"以方案一为例，核心改动是",[95,238,239],{},"移除子组件内部的返回调用，只保留事件抛出","：",[242,243,247],"pre",{"className":244,"code":245,"language":13,"meta":246,"style":246},"language-vue shiki shiki-themes material-theme-lighter github-light github-dark","\u003C!-- 修复前：子组件内部既调用返回，又抛出事件 -->\n\u003Cscript setup lang=\"ts\">\nconst emit = defineEmits\u003C{ back: [] }>();\n\nfunction handleBack() {\n  router.back(); \u002F\u002F 问题点：子组件内部已经执行了一次返回\n  emit(\"back\"); \u002F\u002F 又抛出事件，父组件监听后会再执行一次\n}\n\u003C\u002Fscript>\n","",[28,248,249,258,292,334,341,355,376,399,405],{"__ignoreMap":246},[250,251,254],"span",{"class":252,"line":253},"line",1,[250,255,257],{"class":256},"sutJx","\u003C!-- 修复前：子组件内部既调用返回，又抛出事件 -->\n",[250,259,261,265,269,273,276,279,283,287,289],{"class":252,"line":260},2,[250,262,264],{"class":263},"sP7_E","\u003C",[250,266,268],{"class":267},"sQzsp","script",[250,270,272],{"class":271},"s9AJx"," setup",[250,274,275],{"class":271}," lang",[250,277,278],{"class":263},"=",[250,280,282],{"class":281},"sjJ54","\"",[250,284,286],{"class":285},"s_sjI","ts",[250,288,282],{"class":281},[250,290,291],{"class":263},">\n",[250,293,295,299,303,307,311,314,318,321,325,328,331],{"class":252,"line":294},3,[250,296,298],{"class":297},"sbsja","const",[250,300,302],{"class":301},"s_hVV"," emit",[250,304,306],{"class":305},"smGrS"," =",[250,308,310],{"class":309},"sGLFI"," defineEmits",[250,312,313],{"class":263},"\u003C{",[250,315,317],{"class":316},"sucvu"," back",[250,319,320],{"class":305},":",[250,322,324],{"class":323},"su5hD"," [] ",[250,326,327],{"class":263},"}>",[250,329,330],{"class":323},"()",[250,332,333],{"class":263},";\n",[250,335,337],{"class":252,"line":336},4,[250,338,340],{"emptyLinePlaceholder":339},true,"\n",[250,342,344,347,350,352],{"class":252,"line":343},5,[250,345,346],{"class":297},"function",[250,348,349],{"class":309}," handleBack",[250,351,330],{"class":263},[250,353,354],{"class":263}," {\n",[250,356,358,361,364,367,370,373],{"class":252,"line":357},6,[250,359,360],{"class":323},"  router",[250,362,363],{"class":263},".",[250,365,366],{"class":309},"back",[250,368,330],{"class":369},"skxfh",[250,371,372],{"class":263},";",[250,374,375],{"class":256}," \u002F\u002F 问题点：子组件内部已经执行了一次返回\n",[250,377,379,382,385,387,389,391,394,396],{"class":252,"line":378},7,[250,380,381],{"class":309},"  emit",[250,383,384],{"class":369},"(",[250,386,282],{"class":281},[250,388,366],{"class":285},[250,390,282],{"class":281},[250,392,393],{"class":369},")",[250,395,372],{"class":263},[250,397,398],{"class":256}," \u002F\u002F 又抛出事件，父组件监听后会再执行一次\n",[250,400,402],{"class":252,"line":401},8,[250,403,404],{"class":263},"}\n",[250,406,408,411,413],{"class":252,"line":407},9,[250,409,410],{"class":263},"\u003C\u002F",[250,412,268],{"class":267},[250,414,291],{"class":263},[242,416,418],{"className":244,"code":417,"language":13,"meta":246,"style":246},"\u003C!-- 修复后：子组件只负责抛出事件，不直接处理返回逻辑 -->\n\u003Cscript setup lang=\"ts\">\nconst emit = defineEmits\u003C{ back: [] }>();\n\nfunction handleBack() {\n  emit(\"back\"); \u002F\u002F 只通知父组件，具体如何返回由父组件统一决定\n}\n\u003C\u002Fscript>\n",[28,419,420,425,445,469,473,483,502,506],{"__ignoreMap":246},[250,421,422],{"class":252,"line":253},[250,423,424],{"class":256},"\u003C!-- 修复后：子组件只负责抛出事件，不直接处理返回逻辑 -->\n",[250,426,427,429,431,433,435,437,439,441,443],{"class":252,"line":260},[250,428,264],{"class":263},[250,430,268],{"class":267},[250,432,272],{"class":271},[250,434,275],{"class":271},[250,436,278],{"class":263},[250,438,282],{"class":281},[250,440,286],{"class":285},[250,442,282],{"class":281},[250,444,291],{"class":263},[250,446,447,449,451,453,455,457,459,461,463,465,467],{"class":252,"line":294},[250,448,298],{"class":297},[250,450,302],{"class":301},[250,452,306],{"class":305},[250,454,310],{"class":309},[250,456,313],{"class":263},[250,458,317],{"class":316},[250,460,320],{"class":305},[250,462,324],{"class":323},[250,464,327],{"class":263},[250,466,330],{"class":323},[250,468,333],{"class":263},[250,470,471],{"class":252,"line":336},[250,472,340],{"emptyLinePlaceholder":339},[250,474,475,477,479,481],{"class":252,"line":343},[250,476,346],{"class":297},[250,478,349],{"class":309},[250,480,330],{"class":263},[250,482,354],{"class":263},[250,484,485,487,489,491,493,495,497,499],{"class":252,"line":357},[250,486,381],{"class":309},[250,488,384],{"class":369},[250,490,282],{"class":281},[250,492,366],{"class":285},[250,494,282],{"class":281},[250,496,393],{"class":369},[250,498,372],{"class":263},[250,500,501],{"class":256}," \u002F\u002F 只通知父组件，具体如何返回由父组件统一决定\n",[250,503,504],{"class":252,"line":378},[250,505,404],{"class":263},[250,507,508,510,512],{"class":252,"line":401},[250,509,410],{"class":263},[250,511,268],{"class":267},[250,513,291],{"class":263},[242,515,517],{"className":244,"code":516,"language":13,"meta":246,"style":246},"\u003C!-- 父组件：统一处理返回逻辑 -->\n\u003Ctemplate>\n  \u003CCustomTabBar @back=\"onBack\" \u002F>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup lang=\"ts\">\nfunction onBack() {\n  router.back();\n}\n\u003C\u002Fscript>\n",[28,518,519,524,533,556,564,568,588,599,611,615],{"__ignoreMap":246},[250,520,521],{"class":252,"line":253},[250,522,523],{"class":256},"\u003C!-- 父组件：统一处理返回逻辑 -->\n",[250,525,526,528,531],{"class":252,"line":260},[250,527,264],{"class":263},[250,529,530],{"class":267},"template",[250,532,291],{"class":263},[250,534,535,538,541,544,546,548,551,553],{"class":252,"line":294},[250,536,537],{"class":263},"  \u003C",[250,539,540],{"class":267},"CustomTabBar",[250,542,543],{"class":271}," @back",[250,545,278],{"class":263},[250,547,282],{"class":281},[250,549,550],{"class":285},"onBack",[250,552,282],{"class":281},[250,554,555],{"class":263}," \u002F>\n",[250,557,558,560,562],{"class":252,"line":336},[250,559,410],{"class":263},[250,561,530],{"class":267},[250,563,291],{"class":263},[250,565,566],{"class":252,"line":343},[250,567,340],{"emptyLinePlaceholder":339},[250,569,570,572,574,576,578,580,582,584,586],{"class":252,"line":357},[250,571,264],{"class":263},[250,573,268],{"class":267},[250,575,272],{"class":271},[250,577,275],{"class":271},[250,579,278],{"class":263},[250,581,282],{"class":281},[250,583,286],{"class":285},[250,585,282],{"class":281},[250,587,291],{"class":263},[250,589,590,592,595,597],{"class":252,"line":378},[250,591,346],{"class":297},[250,593,594],{"class":309}," onBack",[250,596,330],{"class":263},[250,598,354],{"class":263},[250,600,601,603,605,607,609],{"class":252,"line":401},[250,602,360],{"class":323},[250,604,363],{"class":263},[250,606,366],{"class":309},[250,608,330],{"class":369},[250,610,333],{"class":263},[250,612,613],{"class":252,"line":407},[250,614,404],{"class":263},[250,616,618,620,622],{"class":252,"line":617},10,[250,619,410],{"class":263},[250,621,268],{"class":267},[250,623,291],{"class":263},[37,625,626],{"id":626},"两种方案的取舍对比",[171,628,629,642],{},[174,630,631],{},[177,632,633,636,639],{},[180,634,635],{},"维度",[180,637,638],{},"方案一（移除子组件内置返回）",[180,640,641],{},"方案二（修改事件名避免冲突）",[190,643,644,655,666,676],{},[177,645,646,649,652],{},[195,647,648],{},"改动范围",[195,650,651],{},"需要梳理并移除子组件内部的返回调用",[195,653,654],{},"仅需调整事件命名，改动更小",[177,656,657,660,663],{},[195,658,659],{},"长期可维护性",[195,661,662],{},"更好，返回逻辑集中在父组件，职责清晰",[195,664,665],{},"一般，仍存在「子组件内部处理返回」的隐患，未来可能再引入类似问题",[177,667,668,670,673],{},[195,669,188],{},[195,671,672],{},"子组件返回逻辑可以放心移除时优先选择",[195,674,675],{},"子组件返回逻辑涉及其他历史依赖、短期无法安全移除时的过渡方案",[177,677,678,681,684],{},[195,679,680],{},"风险",[195,682,683],{},"需要覆盖测试所有引用该子组件的页面",[195,685,686],{},"后续新增事件监听时仍需警惕命名冲突",[24,688,689],{},"团队最终采用方案一，因为「返回逻辑由谁处理」的职责边界问题如果不彻底解决，类似的双触发风险会在其他组件中重复出现。",[37,691,692],{"id":692},"回归检查清单",[41,694,697,706,712,718,727,733],{"className":695},[696],"contains-task-list",[44,698,701,705],{"className":699},[700],"task-list-item",[702,703],"input",{"disabled":339,"type":704},"checkbox"," 浏览器直接访问 H5：多级页面返回行为符合预期（逐层回退，不跳级）；",[44,707,709,711],{"className":708},[700],[702,710],{"disabled":339,"type":704}," App WebView 内访问：点击页面内返回按钮，行为与浏览器一致；",[44,713,715,717],{"className":714},[700],[702,716],{"disabled":339,"type":704}," App WebView 内访问：使用 App 原生返回键（非页面内按钮），行为同样符合预期；",[44,719,721,723,724,726],{"className":720},[700],[702,722],{"disabled":339,"type":704}," 覆盖所有使用了二次封装 ",[28,725,34],{}," 组件的页面，逐一验证无「多退一层」现象；",[44,728,730,732],{"className":729},[700],[702,731],{"disabled":339,"type":704}," 快速连续点击返回按钮（模拟用户手抖多点），确认不会因事件重复绑定导致多次触发；",[44,734,736,738],{"className":735},[700],[702,737],{"disabled":339,"type":704}," 检查是否存在其他组件采用了类似「内部调用 + emit 双通道」的返回实现模式，一并排查修复。",[37,740,741],{"id":741},"经验总结",[41,743,744,750,753],{},[44,745,746,747,749],{},"混合开发场景中，H5 内部路由栈与容器（WebView\u002FApp）返回栈是两套独立机制，任何“既在组件内部处理返回、又向外 ",[28,748,155],{}," 事件”的实现，都有双触发风险；",[44,751,752],{},"排查此类问题时，优先确认是否在多个环境（浏览器 vs WebView）下表现不一致，环境差异往往能快速缩小根因范围；",[44,754,755],{},"组件封装应明确「返回逻辑由谁处理」的单一职责，避免子组件既处理又转发。",[757,758,759],"style",{},"html pre.shiki code .sutJx, html code.shiki .sutJx{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#6A737D;--shiki-dark-font-style:inherit}html pre.shiki code .sP7_E, html code.shiki .sP7_E{--shiki-light:#39ADB5;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sQzsp, html code.shiki .sQzsp{--shiki-light:#E53935;--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .s9AJx, html code.shiki .s9AJx{--shiki-light:#9C3EDA;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sjJ54, html code.shiki .sjJ54{--shiki-light:#39ADB5;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .s_sjI, html code.shiki .s_sjI{--shiki-light:#91B859;--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sbsja, html code.shiki .sbsja{--shiki-light:#9C3EDA;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .s_hVV, html code.shiki .s_hVV{--shiki-light:#90A4AE;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .smGrS, html code.shiki .smGrS{--shiki-light:#39ADB5;--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sGLFI, html code.shiki .sGLFI{--shiki-light:#6182B8;--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sucvu, html code.shiki .sucvu{--shiki-light:#E53935;--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .skxfh, html code.shiki .skxfh{--shiki-light:#E53935;--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":246,"searchDepth":260,"depth":260,"links":761},[762,763,764,765,766,767,768,769,770],{"id":39,"depth":260,"text":39},{"id":58,"depth":260,"text":58},{"id":75,"depth":260,"text":75},{"id":131,"depth":260,"text":131},{"id":169,"depth":260,"text":169},{"id":233,"depth":260,"text":233},{"id":626,"depth":260,"text":626},{"id":692,"depth":260,"text":692},{"id":741,"depth":260,"text":741},{"title":8,"description":9},"knowledge\u002Fteam-documents\u002F15","knowledge\u002Fknowledge\u002Fteam-documents\u002F15.md","md",{"items":776},[777,782,786,790,794,798],{"path":778,"title":779,"description":780,"category":10,"score":781},"\u002Fknowledge\u002Fteam-documents\u002F03","键盘弹起导致底部被顶起问题（H5 适配）","在移动端 H5 页面中，当用户聚焦 input、textarea 等可编辑元素、软键盘弹出时，常见表现包括：",12,{"path":783,"title":784,"description":785,"category":10,"score":781},"\u002Fknowledge\u002Fteam-documents\u002F22","企业微信 uni-app H5：OAuth 回退白屏与列表缓存","第三方 BI 报表项目，企业微信内嵌 H5，uni-app 编译，history 模式。主页面 BiLink 同时承担静默授权和列表展示，上线后碰到两个问题：授权完清掉 URL 参数，iOS 侧滑返回还是白屏；列表加了缓存以后，刷新行…",{"path":787,"title":788,"description":789,"category":10,"score":781},"\u002Fknowledge\u002Fteam-documents\u002F17","支付中转页面升级实践","本次需求是支付链路升级：在兼容原有支付能力的基础上，新增不同版本的支付方案（如原生微信支付、小程序拉起支付）。",{"path":791,"title":792,"description":793,"category":10,"score":407},"\u002Fknowledge\u002Fteam-documents\u002F19","GridView 宫格加载渲染优化","系统首页 GridView 宫格模块接口耗时不高，但首次进入总耗时接近 22s。复盘耗时分层定位过程、代码层面的瓶颈（约 2000 行、100 个 tab 重复节点）、优化手段与最终指标对比。",{"path":795,"title":796,"description":797,"category":10,"score":407},"\u002Fknowledge\u002Fteam-documents\u002F06","企业微信与小程序工单问题","企微师傅端与商家小程序端长期共用一套代码，页面与组件嵌套边界不清晰、引入规范缺失、公共代码与端侧代码耦合度高，导致维护成本持续上升。本文给出拆分为两套独立项目的架构建议，并说明边界划分、迁移注意事项与性能优化方向。",{"path":799,"title":800,"description":801,"category":10,"score":407},"\u002Fknowledge\u002Fteam-documents\u002F13","新商家系统性能优化实践","商家系统新版本上线后，团队持续针对构建效率与用户体验做了一轮系统性优化。本文记录核心方案与落地结果，供后续版本复用。",{"series":803,"title":804,"items":805,"index":879,"prev":880,"next":881},"team-documents","team documents",[806,810,814,816,820,824,826,830,834,838,842,846,850,852,856,857,861,863,867,869,873,877],{"path":807,"title":808,"date":809,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F01","执行价格弹窗：表头 \u002F 表体合并与可配置表格","2024-07-27",{"path":811,"title":812,"date":813,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F02","防篡改水印","2024-01-09",{"path":778,"title":779,"date":815,"pinned":16},"2024-09-17",{"path":817,"title":818,"date":819,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F04","老系统升级与兼容改造实践","2024-12-12",{"path":821,"title":822,"date":823,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F05","内部插件 \u002F 工具库开发实践","2021-08-19",{"path":795,"title":796,"date":825,"pinned":16},"2025-10-01",{"path":827,"title":828,"date":829,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F07","企业微信群工具打开缓慢原因分析","2020-04-12",{"path":831,"title":832,"date":833,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F08","属性排序需求","2024-06-16",{"path":835,"title":836,"date":837,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F09","同业主重复单提醒规则","2020-06-07",{"path":839,"title":840,"date":841,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F10","图片上传前的自定义水印实践","2021-06-10",{"path":843,"title":844,"date":845,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F11","系统下单（重复单提示框）异常复盘","2023-11-21",{"path":847,"title":848,"date":849,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F12","系统自动更新说明","2025-05-26",{"path":799,"title":800,"date":851,"pinned":16},"2025-04-08",{"path":853,"title":854,"date":855,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F14","选项卡切换与 Loading 状态封装","2019-11-03",{"path":7,"title":8,"date":15,"pinned":16},{"path":858,"title":859,"date":860,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F16","在线协作表格接入实践","2023-10-27",{"path":787,"title":788,"date":862,"pinned":16},"2022-10-15",{"path":864,"title":865,"date":866,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F18","中英文输入法下搜索触发冲突复盘","2024-09-01",{"path":791,"title":792,"date":868,"pinned":16},"2026-03-17",{"path":870,"title":871,"date":872,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F20","H5 GPS 定位问题说明","2023-08-31",{"path":874,"title":875,"date":876,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F21","vxe-table 行 Hover 联动高亮","2024-08-31",{"path":783,"title":784,"date":878,"pinned":16},"2023-08-17",14,{"path":853,"title":854,"date":855,"pinned":16},{"path":858,"title":859,"date":860,"pinned":16}]