[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"knowledge-\u002Fapi\u002Fknowledge\u002Fteam-documents\u002F14":3,"knowledge-related-\u002Fknowledge\u002Fteam-documents\u002F14":1171,"knowledge-series-\u002Fknowledge\u002Fteam-documents\u002F14":1197},{"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":1167,"stem":1168,"id":1169,"extension":1170},"\u002Fknowledge\u002Fteam-documents\u002F14","选项卡切换与 Loading 状态封装","在业务页面中，选项卡切换是高频交互场景。例如切换商品分类时，通常需要携带对应 id 重新请求数据。","团队文档",[12,13,14],"team","vue","performance","2019-11-03",false,{"type":18,"value":19,"toc":1155},"minimark",[20,24,33,36,52,59,63,66,86,94,97,101,111,136,140,371,374,404,406,412,866,868,871,874,965,968,971,1053,1056,1111,1114,1151],[21,22,8],"h1",{"id":23},"选项卡切换与-loading-状态封装",[25,26,27,28,32],"p",{},"在业务页面中，选项卡切换是高频交互场景。例如切换商品分类时，通常需要携带对应 ",[29,30,31],"code",{},"id"," 重新请求数据。",[25,34,35],{},"如果不做统一封装，常见问题包括：",[37,38,39,43,49],"ul",{},[40,41,42],"li",{},"每个页面重复编写请求逻辑；",[40,44,45,48],{},[29,46,47],{},"loading\u002Fsuccess\u002Ferror"," 三态实现不一致；",[40,50,51],{},"重试逻辑分散，维护成本高。",[25,53,54,55,58],{},"因此，更推荐将该能力抽象为统一的 ",[29,56,57],{},"useFetch"," 方案。",[60,61,62],"h2",{"id":62},"方案目标",[25,64,65],{},"统一处理以下状态：",[37,67,68,74,80],{},[40,69,70,73],{},[29,71,72],{},"loading","：请求进行中；",[40,75,76,79],{},[29,77,78],{},"success","：请求成功并渲染结果；",[40,81,82,85],{},[29,83,84],{},"error","：请求失败并支持手动重试。",[25,87,88,89],{},"解析示意图：\n",[90,91],"img",{"alt":92,"src":93},"解析图","https:\u002F\u002Fcdn.wangxiaoze.cn\u002Fstatic\u002Fimages\u002F615ad39f-813c-40e0-8ebb-eba00ce8c292.png",[95,96],"hr",{},[60,98,100],{"id":99},"实现思路vue","实现思路（Vue）",[25,102,103,104,106,107,110],{},"核心点是监听“请求依赖”的变化（如 ",[29,105,31],{}," 或 ",[29,108,109],{},"url","），并自动触发请求：",[37,112,113,120,126],{},[40,114,115,116,119],{},"用 ",[29,117,118],{},"computed"," 维护派生请求地址；",[40,121,115,122,125],{},[29,123,124],{},"watchEffect"," 自动追踪依赖并执行请求；",[40,127,115,128,131,132,135],{},[29,129,130],{},"unref"," 兼容 ",[29,133,134],{},"ref"," 与普通值参数。",[137,138,139],"h3",{"id":139},"依赖监听示例",[141,142,147],"pre",{"className":143,"code":144,"language":145,"meta":146,"style":146},"language-javascript shiki shiki-themes material-theme-lighter github-light github-dark","import { computed, ref, watchEffect } from \"vue\";\n\nconst id = ref(1);\nconst changeId = () => id.value++;\n\nconst url = computed(() => `https:\u002F\u002Fapi-xxxxx.com?id=${id.value}`);\n\nwatchEffect(() => {\n  console.log(\"watchEffect url:\", url.value);\n});\n","javascript","",[29,148,149,196,203,233,263,268,309,314,328,361],{"__ignoreMap":146},[150,151,154,158,162,166,169,172,174,177,180,183,187,190,193],"span",{"class":152,"line":153},"line",1,[150,155,157],{"class":156},"sVHd0","import",[150,159,161],{"class":160},"sP7_E"," {",[150,163,165],{"class":164},"su5hD"," computed",[150,167,168],{"class":160},",",[150,170,171],{"class":164}," ref",[150,173,168],{"class":160},[150,175,176],{"class":164}," watchEffect",[150,178,179],{"class":160}," }",[150,181,182],{"class":156}," from",[150,184,186],{"class":185},"sjJ54"," \"",[150,188,13],{"class":189},"s_sjI",[150,191,192],{"class":185},"\"",[150,194,195],{"class":160},";\n",[150,197,199],{"class":152,"line":198},2,[150,200,202],{"emptyLinePlaceholder":201},true,"\n",[150,204,206,210,214,218,221,224,228,231],{"class":152,"line":205},3,[150,207,209],{"class":208},"sbsja","const",[150,211,213],{"class":212},"s_hVV"," id",[150,215,217],{"class":216},"smGrS"," =",[150,219,171],{"class":220},"sGLFI",[150,222,223],{"class":164},"(",[150,225,227],{"class":226},"srdBf","1",[150,229,230],{"class":164},")",[150,232,195],{"class":160},[150,234,236,238,242,244,247,250,252,255,258,261],{"class":152,"line":235},4,[150,237,209],{"class":208},[150,239,241],{"class":240},"sfCm-"," changeId",[150,243,217],{"class":216},[150,245,246],{"class":160}," ()",[150,248,249],{"class":208}," =>",[150,251,213],{"class":164},[150,253,254],{"class":160},".",[150,256,257],{"class":164},"value",[150,259,260],{"class":216},"++",[150,262,195],{"class":160},[150,264,266],{"class":152,"line":265},5,[150,267,202],{"emptyLinePlaceholder":201},[150,269,271,273,276,278,280,282,285,287,290,293,296,298,300,302,305,307],{"class":152,"line":270},6,[150,272,209],{"class":208},[150,274,275],{"class":212}," url",[150,277,217],{"class":216},[150,279,165],{"class":220},[150,281,223],{"class":164},[150,283,284],{"class":160},"()",[150,286,249],{"class":208},[150,288,289],{"class":185}," `",[150,291,292],{"class":189},"https:\u002F\u002Fapi-xxxxx.com?id=",[150,294,295],{"class":185},"${",[150,297,31],{"class":164},[150,299,254],{"class":185},[150,301,257],{"class":164},[150,303,304],{"class":185},"}`",[150,306,230],{"class":164},[150,308,195],{"class":160},[150,310,312],{"class":152,"line":311},7,[150,313,202],{"emptyLinePlaceholder":201},[150,315,317,319,321,323,325],{"class":152,"line":316},8,[150,318,124],{"class":220},[150,320,223],{"class":164},[150,322,284],{"class":160},[150,324,249],{"class":208},[150,326,327],{"class":160}," {\n",[150,329,331,334,336,339,342,344,347,349,351,353,355,357,359],{"class":152,"line":330},9,[150,332,333],{"class":164},"  console",[150,335,254],{"class":160},[150,337,338],{"class":220},"log",[150,340,223],{"class":341},"skxfh",[150,343,192],{"class":185},[150,345,346],{"class":189},"watchEffect url:",[150,348,192],{"class":185},[150,350,168],{"class":160},[150,352,275],{"class":164},[150,354,254],{"class":160},[150,356,257],{"class":164},[150,358,230],{"class":341},[150,360,195],{"class":160},[150,362,364,367,369],{"class":152,"line":363},10,[150,365,366],{"class":160},"}",[150,368,230],{"class":164},[150,370,195],{"class":160},[25,372,373],{},"说明：",[37,375,376,389,394],{},[40,377,378,379,382,383,385,386,388],{},"每次执行 ",[29,380,381],{},"changeId","，",[29,384,31],{}," 更新后 ",[29,387,109],{}," 会重新计算；",[40,390,391,393],{},[29,392,124],{}," 会自动监听依赖并立即执行；",[40,395,396,397,400,401,403],{},"若需要拿到“新旧值”，应使用 ",[29,398,399],{},"watch"," 而不是 ",[29,402,124],{},"。",[95,405],{},[60,407,409,411],{"id":408},"usefetch-封装示例",[29,410,57],{}," 封装示例",[141,413,415],{"className":143,"code":414,"language":145,"meta":146,"style":146},"import { isRef, ref, unref, watchEffect } from \"vue\";\n\nexport function useFetch(url) {\n  const data = ref(null);\n  const error = ref(null);\n  const loading = ref(false);\n\n  async function doFetch() {\n    data.value = null;\n    error.value = null;\n    loading.value = true;\n\n    try {\n      const urlVal = unref(url);\n      const res = await fetch(urlVal);\n      data.value = await res.json();\n    } catch (err) {\n      error.value = err;\n    } finally {\n      loading.value = false;\n    }\n  }\n\n  if (isRef(url)) {\n    watchEffect(doFetch);\n  } else {\n    doFetch();\n  }\n\n  return { data, error, loading, doFetch };\n}\n",[29,416,417,451,455,475,497,516,537,541,555,571,586,603,608,616,637,662,687,708,725,735,752,758,764,769,789,804,815,825,830,835,860],{"__ignoreMap":146},[150,418,419,421,423,426,428,430,432,435,437,439,441,443,445,447,449],{"class":152,"line":153},[150,420,157],{"class":156},[150,422,161],{"class":160},[150,424,425],{"class":164}," isRef",[150,427,168],{"class":160},[150,429,171],{"class":164},[150,431,168],{"class":160},[150,433,434],{"class":164}," unref",[150,436,168],{"class":160},[150,438,176],{"class":164},[150,440,179],{"class":160},[150,442,182],{"class":156},[150,444,186],{"class":185},[150,446,13],{"class":189},[150,448,192],{"class":185},[150,450,195],{"class":160},[150,452,453],{"class":152,"line":198},[150,454,202],{"emptyLinePlaceholder":201},[150,456,457,460,463,466,468,471,473],{"class":152,"line":205},[150,458,459],{"class":156},"export",[150,461,462],{"class":208}," function",[150,464,465],{"class":220}," useFetch",[150,467,223],{"class":160},[150,469,109],{"class":470},"s99_P",[150,472,230],{"class":160},[150,474,327],{"class":160},[150,476,477,480,483,485,487,489,493,495],{"class":152,"line":235},[150,478,479],{"class":208},"  const",[150,481,482],{"class":212}," data",[150,484,217],{"class":216},[150,486,171],{"class":220},[150,488,223],{"class":341},[150,490,492],{"class":491},"s39Yj","null",[150,494,230],{"class":341},[150,496,195],{"class":160},[150,498,499,501,504,506,508,510,512,514],{"class":152,"line":265},[150,500,479],{"class":208},[150,502,503],{"class":212}," error",[150,505,217],{"class":216},[150,507,171],{"class":220},[150,509,223],{"class":341},[150,511,492],{"class":491},[150,513,230],{"class":341},[150,515,195],{"class":160},[150,517,518,520,523,525,527,529,533,535],{"class":152,"line":270},[150,519,479],{"class":208},[150,521,522],{"class":212}," loading",[150,524,217],{"class":216},[150,526,171],{"class":220},[150,528,223],{"class":341},[150,530,532],{"class":531},"syTEX","false",[150,534,230],{"class":341},[150,536,195],{"class":160},[150,538,539],{"class":152,"line":311},[150,540,202],{"emptyLinePlaceholder":201},[150,542,543,546,548,551,553],{"class":152,"line":316},[150,544,545],{"class":208},"  async",[150,547,462],{"class":208},[150,549,550],{"class":220}," doFetch",[150,552,284],{"class":160},[150,554,327],{"class":160},[150,556,557,560,562,564,566,569],{"class":152,"line":330},[150,558,559],{"class":164},"    data",[150,561,254],{"class":160},[150,563,257],{"class":164},[150,565,217],{"class":216},[150,567,568],{"class":491}," null",[150,570,195],{"class":160},[150,572,573,576,578,580,582,584],{"class":152,"line":363},[150,574,575],{"class":164},"    error",[150,577,254],{"class":160},[150,579,257],{"class":164},[150,581,217],{"class":216},[150,583,568],{"class":491},[150,585,195],{"class":160},[150,587,589,592,594,596,598,601],{"class":152,"line":588},11,[150,590,591],{"class":164},"    loading",[150,593,254],{"class":160},[150,595,257],{"class":164},[150,597,217],{"class":216},[150,599,600],{"class":531}," true",[150,602,195],{"class":160},[150,604,606],{"class":152,"line":605},12,[150,607,202],{"emptyLinePlaceholder":201},[150,609,611,614],{"class":152,"line":610},13,[150,612,613],{"class":156},"    try",[150,615,327],{"class":160},[150,617,619,622,625,627,629,631,633,635],{"class":152,"line":618},14,[150,620,621],{"class":208},"      const",[150,623,624],{"class":212}," urlVal",[150,626,217],{"class":216},[150,628,434],{"class":220},[150,630,223],{"class":341},[150,632,109],{"class":164},[150,634,230],{"class":341},[150,636,195],{"class":160},[150,638,640,642,645,647,650,653,655,658,660],{"class":152,"line":639},15,[150,641,621],{"class":208},[150,643,644],{"class":212}," res",[150,646,217],{"class":216},[150,648,649],{"class":156}," await",[150,651,652],{"class":220}," fetch",[150,654,223],{"class":341},[150,656,657],{"class":164},"urlVal",[150,659,230],{"class":341},[150,661,195],{"class":160},[150,663,665,668,670,672,674,676,678,680,683,685],{"class":152,"line":664},16,[150,666,667],{"class":164},"      data",[150,669,254],{"class":160},[150,671,257],{"class":164},[150,673,217],{"class":216},[150,675,649],{"class":156},[150,677,644],{"class":164},[150,679,254],{"class":160},[150,681,682],{"class":220},"json",[150,684,284],{"class":341},[150,686,195],{"class":160},[150,688,690,693,696,699,702,705],{"class":152,"line":689},17,[150,691,692],{"class":160},"    }",[150,694,695],{"class":156}," catch",[150,697,698],{"class":341}," (",[150,700,701],{"class":164},"err",[150,703,704],{"class":341},") ",[150,706,707],{"class":160},"{\n",[150,709,711,714,716,718,720,723],{"class":152,"line":710},18,[150,712,713],{"class":164},"      error",[150,715,254],{"class":160},[150,717,257],{"class":164},[150,719,217],{"class":216},[150,721,722],{"class":164}," err",[150,724,195],{"class":160},[150,726,728,730,733],{"class":152,"line":727},19,[150,729,692],{"class":160},[150,731,732],{"class":156}," finally",[150,734,327],{"class":160},[150,736,738,741,743,745,747,750],{"class":152,"line":737},20,[150,739,740],{"class":164},"      loading",[150,742,254],{"class":160},[150,744,257],{"class":164},[150,746,217],{"class":216},[150,748,749],{"class":531}," false",[150,751,195],{"class":160},[150,753,755],{"class":152,"line":754},21,[150,756,757],{"class":160},"    }\n",[150,759,761],{"class":152,"line":760},22,[150,762,763],{"class":160},"  }\n",[150,765,767],{"class":152,"line":766},23,[150,768,202],{"emptyLinePlaceholder":201},[150,770,772,775,777,780,782,784,787],{"class":152,"line":771},24,[150,773,774],{"class":156},"  if",[150,776,698],{"class":341},[150,778,779],{"class":220},"isRef",[150,781,223],{"class":341},[150,783,109],{"class":164},[150,785,786],{"class":341},")) ",[150,788,707],{"class":160},[150,790,792,795,797,800,802],{"class":152,"line":791},25,[150,793,794],{"class":220},"    watchEffect",[150,796,223],{"class":341},[150,798,799],{"class":164},"doFetch",[150,801,230],{"class":341},[150,803,195],{"class":160},[150,805,807,810,813],{"class":152,"line":806},26,[150,808,809],{"class":160},"  }",[150,811,812],{"class":156}," else",[150,814,327],{"class":160},[150,816,818,821,823],{"class":152,"line":817},27,[150,819,820],{"class":220},"    doFetch",[150,822,284],{"class":341},[150,824,195],{"class":160},[150,826,828],{"class":152,"line":827},28,[150,829,763],{"class":160},[150,831,833],{"class":152,"line":832},29,[150,834,202],{"emptyLinePlaceholder":201},[150,836,838,841,843,845,847,849,851,853,855,857],{"class":152,"line":837},30,[150,839,840],{"class":156},"  return",[150,842,161],{"class":160},[150,844,482],{"class":164},[150,846,168],{"class":160},[150,848,503],{"class":164},[150,850,168],{"class":160},[150,852,522],{"class":164},[150,854,168],{"class":160},[150,856,550],{"class":164},[150,858,859],{"class":160}," };\n",[150,861,863],{"class":152,"line":862},31,[150,864,865],{"class":160},"}\n",[95,867],{},[60,869,870],{"id":870},"页面渲染建议",[25,872,873],{},"建议将状态渲染统一为公共组件，避免页面重复判断逻辑：",[141,875,879],{"className":876,"code":877,"language":878,"meta":146,"style":146},"language-html shiki shiki-themes material-theme-lighter github-light github-dark","\u003Cdiv v-if=\"loading\">loading...\u003C\u002Fdiv>\n\u003Cdiv v-else-if=\"error\">错误：xxxx（可重试）\u003C\u002Fdiv>\n\u003Cdiv v-else>数据：xxxx\u003C\u002Fdiv>\n","html",[29,880,881,917,945],{"__ignoreMap":146},[150,882,883,886,890,894,897,899,901,903,906,909,912,914],{"class":152,"line":153},[150,884,885],{"class":160},"\u003C",[150,887,889],{"class":888},"sQzsp","div",[150,891,893],{"class":892},"s9AJx"," v-if",[150,895,896],{"class":160},"=",[150,898,192],{"class":185},[150,900,72],{"class":189},[150,902,192],{"class":185},[150,904,905],{"class":160},">",[150,907,908],{"class":164},"loading...",[150,910,911],{"class":160},"\u003C\u002F",[150,913,889],{"class":888},[150,915,916],{"class":160},">\n",[150,918,919,921,923,926,928,930,932,934,936,939,941,943],{"class":152,"line":198},[150,920,885],{"class":160},[150,922,889],{"class":888},[150,924,925],{"class":892}," v-else-if",[150,927,896],{"class":160},[150,929,192],{"class":185},[150,931,84],{"class":189},[150,933,192],{"class":185},[150,935,905],{"class":160},[150,937,938],{"class":164},"错误：xxxx（可重试）",[150,940,911],{"class":160},[150,942,889],{"class":888},[150,944,916],{"class":160},[150,946,947,949,951,954,956,959,961,963],{"class":152,"line":205},[150,948,885],{"class":160},[150,950,889],{"class":888},[150,952,953],{"class":892}," v-else",[150,955,905],{"class":160},[150,957,958],{"class":164},"数据：xxxx",[150,960,911],{"class":160},[150,962,889],{"class":888},[150,964,916],{"class":160},[25,966,967],{},"在企业项目中，这类基础能力统一后，能够显著降低重复代码并提升交互一致性。",[60,969,970],{"id":970},"与手动实现的对比",[972,973,974,993],"table",{},[975,976,977],"thead",{},[978,979,980,984,987],"tr",{},[981,982,983],"th",{},"维度",[981,985,986],{},"页面内手写请求逻辑",[981,988,989,990,992],{},"统一 ",[29,991,57],{}," 封装",[994,995,996,1012,1025,1039],"tbody",{},[978,997,998,1002,1009],{},[999,1000,1001],"td",{},"状态管理",[999,1003,1004,1005,1008],{},"每个页面各自定义 ",[29,1006,1007],{},"loading\u002Ferror"," 变量",[999,1010,1011],{},"由封装统一返回，命名一致",[978,1013,1014,1017,1020],{},[999,1015,1016],{},"依赖切换",[999,1018,1019],{},"需要手动在切换回调里重新发请求",[999,1021,1022,1024],{},[29,1023,124],{}," 自动感知依赖变化",[978,1026,1027,1030,1033],{},[999,1028,1029],{},"重试逻辑",[999,1031,1032],{},"容易遗漏或各页面实现不一致",[999,1034,1035,1036,1038],{},"复用同一套 ",[29,1037,799],{},"，重试即重新调用",[978,1040,1041,1044,1047],{},[999,1042,1043],{},"可测试性",[999,1045,1046],{},"逻辑分散，难以单独测试",[999,1048,1049,1050,1052],{},"可对 ",[29,1051,57],{}," 单独编写单元测试",[60,1054,1055],{"id":1055},"回归检查清单",[37,1057,1060,1072,1084,1090,1105],{"className":1058},[1059],"contains-task-list",[40,1061,1064,1068,1069,1071],{"className":1062},[1063],"task-list-item",[1065,1066],"input",{"disabled":201,"type":1067},"checkbox"," 切换选项卡（更新依赖 ",[29,1070,31],{},"）后能正确重新发起请求，且旧请求结果不会覆盖新请求结果；",[40,1073,1075,1077,1078,1080,1081,1083],{"className":1074},[1063],[1065,1076],{"disabled":201,"type":1067}," 请求失败时 ",[29,1079,84],{}," 状态正确展示，重试按钮可正常触发 ",[29,1082,799],{}," 重新请求；",[40,1085,1087,1089],{"className":1086},[1063],[1065,1088],{"disabled":201,"type":1067}," 快速连续切换选项卡时不出现请求堆积或界面闪烁「loading -> 数据 -> loading」的异常跳变；",[40,1091,1093,1095,1096,1098,1099,1101,1102,1104],{"className":1092},[1063],[1065,1094],{"disabled":201,"type":1067}," ",[29,1097,109],{}," 传入非 ",[29,1100,134],{}," 的普通值时（一次性请求场景），逻辑仍能正确执行且不会误触发 ",[29,1103,124],{},"；",[40,1106,1108,1110],{"className":1107},[1063],[1065,1109],{"disabled":201,"type":1067}," 组件销毁时无残留的未处理 Promise 导致的报错或内存泄漏提示。",[60,1112,1113],{"id":1113},"常见疑问",[1115,1116,1117,1138],"ol",{},[40,1118,1119,1129,1132,1134,1135,1137],{},[1120,1121,1122,1123,1125,1126,1128],"strong",{},"为什么不直接用 ",[29,1124,399],{}," 而用 ",[29,1127,124],{},"？",[1130,1131],"br",{},[29,1133,124],{}," 会自动收集依赖，不需要手动列出监听的字段，对于「依赖变化即整体重新请求」的场景更简洁；如果后续需要对比新旧值做差异化处理，再改为 ",[29,1136,399],{}," 也不冲突。",[40,1139,1140,1145,1147,1148,1150],{},[1120,1141,1142,1144],{},[29,1143,57],{}," 是否可以扩展支持缓存？",[1130,1146],{},"\n可以，常见做法是按 ",[29,1149,109],{}," 作为 key 缓存最近一次结果，命中缓存时先展示旧数据再静默更新，避免每次切换都出现短暂空白，具体策略需结合业务对「数据实时性」的要求取舍。",[1152,1153,1154],"style",{},"html pre.shiki code .sVHd0, html code.shiki .sVHd0{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#D73A49;--shiki-default-font-style:inherit;--shiki-dark:#F97583;--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 .su5hD, html code.shiki .su5hD{--shiki-light:#90A4AE;--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .srdBf, html code.shiki .srdBf{--shiki-light:#F76D47;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sfCm-, html code.shiki .sfCm-{--shiki-light:#90A4AE;--shiki-default:#6F42C1;--shiki-dark:#B392F0}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);}html pre.shiki code .s99_P, html code.shiki .s99_P{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#E36209;--shiki-default-font-style:inherit;--shiki-dark:#FFAB70;--shiki-dark-font-style:inherit}html pre.shiki code .s39Yj, html code.shiki .s39Yj{--shiki-light:#39ADB5;--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .syTEX, html code.shiki .syTEX{--shiki-light:#FF5370;--shiki-default:#005CC5;--shiki-dark:#79B8FF}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}",{"title":146,"searchDepth":198,"depth":198,"links":1156},[1157,1158,1161,1163,1164,1165,1166],{"id":62,"depth":198,"text":62},{"id":99,"depth":198,"text":100,"children":1159},[1160],{"id":139,"depth":205,"text":139},{"id":408,"depth":198,"text":1162},"useFetch 封装示例",{"id":870,"depth":198,"text":870},{"id":970,"depth":198,"text":970},{"id":1055,"depth":198,"text":1055},{"id":1113,"depth":198,"text":1113},{"title":8,"description":9},"knowledge\u002Fteam-documents\u002F14","knowledge\u002Fknowledge\u002Fteam-documents\u002F14.md","md",{"items":1172},[1173,1177,1181,1185,1189,1193],{"path":1174,"title":1175,"description":1176,"category":10,"score":605},"\u002Fknowledge\u002Fteam-documents\u002F19","GridView 宫格加载渲染优化","系统首页 GridView 宫格模块接口耗时不高，但首次进入总耗时接近 22s。复盘耗时分层定位过程、代码层面的瓶颈（约 2000 行、100 个 tab 重复节点）、优化手段与最终指标对比。",{"path":1178,"title":1179,"description":1180,"category":10,"score":605},"\u002Fknowledge\u002Fteam-documents\u002F13","新商家系统性能优化实践","商家系统新版本上线后，团队持续针对构建效率与用户体验做了一轮系统性优化。本文记录核心方案与落地结果，供后续版本复用。",{"path":1182,"title":1183,"description":1184,"category":10,"score":605},"\u002Fknowledge\u002Fteam-documents\u002F04","老系统升级与兼容改造实践","公司原有业务系统采用 Node + jQuery 架构，长期运行后暴露出典型遗留系统问题：",{"path":1186,"title":1187,"description":1188,"category":10,"score":605},"\u002Fknowledge\u002Fteam-documents\u002F02","防篡改水印","在各类管理后台、SaaS 平台或内部系统中，页面水印已经是非常常见的能力：一方面在截图时携带账号、姓名、时间等信息，降低截图外传的风险；另一方面在上传图片或文档预览时，通过水印标记上传者与时间，满足审计和合规需求。",{"path":1190,"title":1191,"description":1192,"category":10,"score":605},"\u002Fknowledge\u002Fteam-documents\u002F22","企业微信 uni-app H5：OAuth 回退白屏与列表缓存","第三方 BI 报表项目，企业微信内嵌 H5，uni-app 编译，history 模式。主页面 BiLink 同时承担静默授权和列表展示，上线后碰到两个问题：授权完清掉 URL 参数，iOS 侧滑返回还是白屏；列表加了缓存以后，刷新行…",{"path":1194,"title":1195,"description":1196,"category":10,"score":605},"\u002Fknowledge\u002Fteam-documents\u002F05","内部插件 \u002F 工具库开发实践","在企业前端项目中，utils、hooks、libs 这类通用能力通常分散在多个仓库，常见问题包括：",{"series":1198,"title":1199,"items":1200,"index":610,"prev":1274,"next":1275},"team-documents","team documents",[1201,1205,1207,1211,1213,1215,1219,1223,1227,1231,1235,1239,1243,1245,1246,1250,1254,1258,1262,1264,1268,1272],{"path":1202,"title":1203,"date":1204,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F01","执行价格弹窗：表头 \u002F 表体合并与可配置表格","2024-07-27",{"path":1186,"title":1187,"date":1206,"pinned":16},"2024-01-09",{"path":1208,"title":1209,"date":1210,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F03","键盘弹起导致底部被顶起问题（H5 适配）","2024-09-17",{"path":1182,"title":1183,"date":1212,"pinned":16},"2024-12-12",{"path":1194,"title":1195,"date":1214,"pinned":16},"2021-08-19",{"path":1216,"title":1217,"date":1218,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F06","企业微信与小程序工单问题","2025-10-01",{"path":1220,"title":1221,"date":1222,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F07","企业微信群工具打开缓慢原因分析","2020-04-12",{"path":1224,"title":1225,"date":1226,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F08","属性排序需求","2024-06-16",{"path":1228,"title":1229,"date":1230,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F09","同业主重复单提醒规则","2020-06-07",{"path":1232,"title":1233,"date":1234,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F10","图片上传前的自定义水印实践","2021-06-10",{"path":1236,"title":1237,"date":1238,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F11","系统下单（重复单提示框）异常复盘","2023-11-21",{"path":1240,"title":1241,"date":1242,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F12","系统自动更新说明","2025-05-26",{"path":1178,"title":1179,"date":1244,"pinned":16},"2025-04-08",{"path":7,"title":8,"date":15,"pinned":16},{"path":1247,"title":1248,"date":1249,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F15","移动端返回事件触发两次问题复盘","2021-03-09",{"path":1251,"title":1252,"date":1253,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F16","在线协作表格接入实践","2023-10-27",{"path":1255,"title":1256,"date":1257,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F17","支付中转页面升级实践","2022-10-15",{"path":1259,"title":1260,"date":1261,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F18","中英文输入法下搜索触发冲突复盘","2024-09-01",{"path":1174,"title":1175,"date":1263,"pinned":16},"2026-03-17",{"path":1265,"title":1266,"date":1267,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F20","H5 GPS 定位问题说明","2023-08-31",{"path":1269,"title":1270,"date":1271,"pinned":16},"\u002Fknowledge\u002Fteam-documents\u002F21","vxe-table 行 Hover 联动高亮","2024-08-31",{"path":1190,"title":1191,"date":1273,"pinned":16},"2023-08-17",{"path":1178,"title":1179,"date":1244,"pinned":16},{"path":1247,"title":1248,"date":1249,"pinned":16}]