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

适用场景 ​

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

核心要点 ​

  • 正文已经按 「JSbridge.VebView.Native.js」、「使用方法」 等小节组织,阅读时可以先定位到当前问题对应的小节。
  • 保留了 1 段可直接参考的代码或命令,主要涉及 javascript,复制前需要按当前项目路径、版本和变量名做调整。
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
## JSbridge.VebView.Native.js
const guid = () =>
'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
const r = (Math.random() * 16) | 0
const v = c === 'x' ? r : (r & 0x3) | 0x8
return v.toString(16)
})
const callbackMaps = {};
const ua = window.navigator.userAgent;
const isAndroid = ua.indexOf('Android') > -1 || ua.indexOf('Adr') > -1;
const isiOS = !!ua.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);

/**
* 供native调用,传递执行结果
* @param {*} messageJson native返回的结果
* messageJson 的格式为
* {
* error: '', // 错误描述
* data: {}, // 响应数据
* callbackId: '', 对应回调函数id
* }
*/
function dispatchMessageFromNative(messageJson) {
let message = {}
try {
message = JSON.parse(messageJson);
const messageCallbackId = message.callbackId;
if (messageCallbackId) {
const responseCallback = callbackMaps[messageCallbackId];
if (responseCallback) {
responseCallback(message.error, message.data);
delete callbackMaps[messageCallbackId];
} else {
console.log(`%c [ E0004:responseCallback回调方法不存在${messageCallbackId} ]-68`, 'font-size:14px; background:#cf222e; color:#fff;', )
}
} else {
console.log(`%c [ callbackId不存在${messageCallbackId} ]-71`, 'font-size:14px; background:#cf222e; color:#fff;', )
}
} catch (e) {
console.log('%c [ E0004:native返回结果是json字符串 ]-57', 'font-size:14px; background:#cf222e; color:#fff;', )
}
}

/**
* 供JavaScript调用,执行指定native方法 xxxxxxxxxxxxxxxxxxxxxxxxxxx 需要自定义
* @param {*} handlerName native方法名
* @param {*} data native方法需要的参数
* @param {*} callback 匿名回调函数
*/
function dispatchMessageToNative(handlerName, data = {}, callback) {
if (!callback && typeof data !== 'function') {
callback = data;
data = null;
console.log('%c [ E0001:callback是函数类型 ]-93', 'font-size:14px; background:#cf222e; color:#fff;', )
}

if (callback && typeof callback !== 'function') {
console.log('%c [ E0001:callback是函数类型 ]-100', 'font-size:14px; background:#cf222e; color:#fff;', )
}

if (
!(
typeof data === 'object' &&
Object.prototype.toString.call(data) === '[object Object]'
)
) {

console.log('%c [ E0001:data是对象类型 ]-112', 'font-size:14px; background:#cf222e; color:#fff;', )
}

if (typeof handlerName !== 'string') {
console.log('%c [ E0001:handlerName是字符串类型 ]-120', 'font-size:14px; background:#cf222e; color:#fff;', )
}

const message = {
data: '',
callbackId: ''
};
if (data) {
message.data = data;
}
if (callback) {
const callbackId = `cb_${guid()}_${new Date().getTime()}`;
callbackMaps[callbackId] = callback;
message.callbackId = callbackId;
}

const messageStr = JSON.stringify(message);
try {
if (isAndroid) {
window.xxxxxxxxxxxxxxxxxxxxxxxxxxx[handlerName](messageStr);
} else if (isiOS) {
window.webkit.messageHandlers[handlerName].postMessage(messageStr);
} else {
console.log('%c [ E0002:当前操作系统不被支持 ]-140', 'font-size:14px; background:#cf222e; color:#fff;', )
}
} catch (e) {
console.log('%c [ E0003:`native方法${handlerName}不存在` ]-144', 'font-size:14px; background:#cf222e; color:#fff;')
}
}

window.webViewJavascriptBridge = { dispatchMessageFromNative }

export default (name, param) =>
new Promise(resolve => {
try {
dispatchMessageToNative(
name,
param,
(err, data) => {
if (err) {
resolve({ err })
console.error(
`dispatchMessageToNative 返回结果错误, name: ${name},err: ${err}`
)
} else {
resolve(data)
}
}
)
} catch (error) {
resolve({})
}
})


#### 使用方法

import webViewJSBridge from '@/utils/JSbridge.VebView.Native';

const data = await webViewJSBridge('事件名', '传递参数') # 参数为对象

实践检查清单 ​

  • 把示例函数放进业务前,先补齐空值、异常输入、异步失败和浏览器兼容性测试。
  • 通用工具函数应尽量收敛到项目公共模块,避免多个页面复制出不同版本。
  • 涉及 UI 或浏览器行为时,至少在桌面端和移动端各验证一次关键路径。

复盘小结 ​

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