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