这篇内容是在有道云旧笔记基础上重新整理的 JavaScript 与前端开发 笔记。原始记录偏碎片化,这里补充了使用场景、阅读顺序和落地时需要注意的边界,方便以后在项目里快速复用。

适用场景 ​

  • 前端业务中需要快速处理数据、DOM、浏览器能力或通用工具函数时参考。
  • 把散落在项目里的小技巧抽成可复用代码片段,减少重复实现。
  • 排查兼容性和边界输入问题前,先用本文示例确认核心思路。

核心要点 ​

  • 正文已经按 「在微信H5中打开小程序/APP」 等小节组织,阅读时可以先定位到当前问题对应的小节。
  • 保留了 1 段可直接参考的代码或命令,主要涉及 javascript,复制前需要按当前项目路径、版本和变量名做调整。
  • 涉及环境变量的示例只保留命名和加载方式,真实密钥、token 和本地配置应放在未提交的本地文件或 CI 密钥变量中。

在微信H5中打开小程序/APP ​

这里要注意用户可能会设置微信中的字体大小,故导致按钮文字被缩放,或者想自定义按钮文字,就得定位在微信标签按钮的底层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
<template>
<div :class="['open-app', customClass]">
<template v-if="browser === 'weixin'">
<!-- @click="openAppByWeiXin" -->
<div class="open-content wx-open-content">
<div :class="`open-btn wx-open-btn wx-weapp-btn wx-weapp-btn--0${i}`" v-for="(p, i) of path" :key="`we-${i}`">
<wx-open-launch-weapp
class="launch-btn"
username="gh_95ecbbd143f0"
:path="p"
:env_version="release"
@ready="handleReadyToDo('weapp', i)"
@launch="handleLaunchToDo('weapp', i)"
@error="handleErrorToDo('weapp', i)"
>
<script type="text/wxtag-template">
<div style="width:100%;height:100%;opacity:0;position:absolute;top:0;bottom:0;right:0">打开微信小程序</div>
</script>
</wx-open-launch-weapp>
<slot :name="`weapp_${i + 1}`">
<div class="btn">打开小程序{{ i }}</div>
</slot>
</div>

<div :class="`open-btn wx-open-btn wx-app-btn ${!isIos ? 'and' : 'ios'}-app-btn wx-app-btn--0${k}`" v-for="(e, k) of extinfo" @click="openAppByNative(k)">
<template v-if="!isIos">
<wx-open-launch-app
class="launch-btn"
appid="wx50578d97168b0f31"
:extinfo="e"
@ready="handleReadyToDo('app', k)"
@launch="handleLaunchToDo('app', k)"
@error="handleErrorToDo('app', k)"
>
<script type="text/wxtag-template">
<div style="width:100%;height:100%;opacity:0;position:absolute;top:0;bottom:0;right:0">打开 安卓 APP</div>
</script>
</wx-open-launch-app>
<slot :name="`waapp_${ k+1 }`">
<div class="btn">打开 安卓 APP {{ k+1 }}</div>
</slot>
</template>
<template v-else>
<slot :name="`wiapp_${ k+1 }`">
<div class="btn">打开 IOS APP {{ k+1 }}</div>
</slot>
</template>
</div>
</div>
</template>
<template v-else>
<div class="open-content na-open-content">
<div :class="`open-btn wx-open-btn wx-app-btn and-app-btn wx-app-btn--0${g}`" v-for="(e, g) of extinfo" :key="g" @click="openAppByNative(g)">
<slot :name="`ntapp_${ g + 1 }`">
<div class="btn">打开 Native APP {{ g + 1 }}</div>
</slot>
</div>
</div>
</template>
</div>
</template>
<script>
export default {
name: "open-app",
props: {
path: {
type: Array,
default: () => []
},
extinfo: {
type: Array,
default: () => []
},
customClass: {
type: String,
default: ''
}
},
data() {
return {
release: "release", // 正式版release、开发版develop、体验版trial
url: '',
browser: '',
timer: null
}
},
mounted() {
if (process.env.NODE_ENV !== "pro") this.release = 'trial'
!isIos && this.timerWatchdogInterval()
},
created() {
this.initPageData()
},
methods: {
initPageData() {
this.url = location.href.split("#")[0]
try {
const ua = navigator.userAgent.toLowerCase()

if (typeof WeixinJSBridge === 'object' && typeof WeixinJSBridge.invoke === 'function' || ua.indexOf('micromessenger') !== -1) {
//在微信中打开
this.browser = 'weixin'
console.log('%c [ 微信浏览器 ]-42', 'font-size:14px; background:#cf222e; color:#fff;', this.browser)
const oScript = document.createElement("script")
oScript.type = "text/javascript"
oScript.src = "https://res2.wx.qq.com/open/js/jweixin-1.6.0.js"
// oScript.onload = this.wxmini
document.body.appendChild(oScript)

this.WeiXinInitData()

}

// 安卓的这里会不让所有的字体放大
// (function () {
// if (typeof WeixinJSBridge == 'object' && typeof window.WeixinJSBridge.invoke == 'function') {
// handleFontSize();
// } else {
// if (document.addEventListener) {
// document.addEventListener('WeixinJSBridgeReady', handleFontSize, false);
// } else if (document.attachEvent) {
// document.attachEvent('WeixinJSBridgeReady', handleFontSize);
// document.attachEvent('onWeixinJSBridgeReady', handleFontSize);
// }
// }

// function handleFontSize() {
// // 设置网页字体为默认大小
// window.WeixinJSBridge.invoke('setFontSizeCallback', {'fontSize': 0});
// // 重写设置网页字体大小的事件
// window.WeixinJSBridge.on('menu:setfont', function () {
// window.WeixinJSBridge.invoke('setFontSizeCallback', {'fontSize': 0});
// });
// }
// })();

} catch (error) { }
},
async WeiXinInitData() {
const { data } = await this.$http({
url: `https://api.xxxxxxxx/signature?url=${this.url}`,
method: "GET",
})
if (data?.data?.appId) {
const { appId, timestamp, nonceStr, signature } = data.data
wx.config({
appId,
timestamp,
nonceStr,
signature,
jsApiList: [
"onMenuShareTimeline", // 分享给好友
"onMenuShareAppMessage", // 分享到朋友圈
],
openTagList: ["wx-open-launch-app", "wx-open-launch-weapp"], // 获取开放标签权限
})
}
console.log('%c [ signature data ]-63', 'font-size:14px; background:#515151; color:#fff;', data)
},
handleLaunchToDo(native, index) {
console.log(`%c [ handleLaunchToDo ${this.browser} ${native} ]-102`, 'font-size:14px; background:#cca255; color:#fff;', )
},
handleReadyToDo(native, index) {

console.log(`%c [ handleReadyToDo ${this.browser} ${native} ]-105`, 'font-size:14px; background:#cf222e; color:#fff;', )
},
handleErrorToDo(native, index) {
console.log(`%c [ handleErrorToDo ${this.browser} ${native} ]-109`, 'font-size:14px; background:#18723a; color:#fff;', )
if (this.isIos) {
this.browser = ''
setTimeout(() => this.openAppByNative(index), 500);
}
this.global.downloadApp()
},
openAppByNative(index) {
const { extinfo, global, $route } = this

console.log('%c [ openAppByNative ]-168', 'font-size:14px; background:#cf222e; color:#fff;', index)

try {
//如果是ios,则替换成universallink
location.href = `${isIos ? 'https://app.xxxxx.mobi/scvw/?' : ''}${extinfo[index]}`
} catch (e) {}
finally {
setTimeout(downloadApp(), 1000)
}
},
timerWatchdogInterval() {
this.timer = setInterval(() => {
const ele = document.querySelectorAll('.open-btn .btn')
// 判断ele是否已经渲染加载完成
if (ele && Object.keys(ele).length) {
//执行方法
this.resetAndroidFontSize()
clearInterval(this.timer)
}
}, 50)
setTimeout(() => {
if (this.timer) clearInterval(this.timer)
}, 10000);
},
resetAndroidFontSize() {
const ele = document.querySelectorAll('.open-btn .btn')
//! 计算出放大后的字体
const scaledFontSize = parseInt(getComputedStyle(ele[0], null)['font-size'])
// 计算原字体和放大后字体的比例
const scaleFactor = 14 / scaledFontSize;
if (scaledFontSize !== 14) {
for (const e of ele) {
e.style.fontSize = `${scaledFontSize * scaleFactor * scaleFactor}px`
}
}
},
openAppByWeiXin() {},
},
beforeDestroy() {
if (this.timer) clearInterval(this.timer)
}
}
</script>
<style lang="scss">
// IOS 这里设置不继承缩放
body {
.open-app {
-webkit-text-size-adjust: 100% !important;
text-size-adjust: 100% !important
}
}
</style>
<style lang="scss" scoped>

.open-app {
position: fixed;
bottom: 0;
font-size: 16px;
// height: 60px;
width: 100vw;
box-sizing: border-box;
padding: 11px 16px 36px;
background-color: #fff;
.open-btn {
position: relative;
z-index: 0;
width: 100%;
height: 100%;
font-size: 1.5rem;
.launch-btn {
width: 100%;
height: 100%;
display: block;
}
.btn {
left: 0;
top: 0;
width: 100%;
height: 100%;
font-size: 1rem;
position: absolute;
z-index: -1;
}
}
}
</style>

实践检查清单 &#8203;

  • 把示例函数放进业务前,先补齐空值、异常输入、异步失败和浏览器兼容性测试。
  • 通用工具函数应尽量收敛到项目公共模块,避免多个页面复制出不同版本。
  • 不要把真实 token、密码、私钥或本地 .env.local 提交到仓库。
  • 涉及 UI 或浏览器行为时,至少在桌面端和移动端各验证一次关键路径。
  • 涉及接口、服务端或权限逻辑时,补充失败分支和权限边界测试。

复盘小结 &#8203;

这篇笔记更适合作为问题排查或方案落地前的速查材料。后续如果在真实项目中再次遇到同类问题,可以继续把具体版本、报错信息、最终取舍和验证结果补到对应小节里,让它从代码片段逐步沉淀成完整方案。