网易
刀刀
6/20/2025
0 字
0 分钟
一面
Q:uniapp 小程序里面怎么塞一个 h5
我的回答
我记得是要用
web-view
组件,传一个url
,渲染这个url
的页面
Q:那么需要注意什么呢?
我的回答
我记得
web-view
组件渲染页面是有一些坑点的,但是太久没用了我一时想不起来,好像是url
不能跨域?
Deepseek 回答
一、核心注意事项
平台兼容性
- iOS 限制:WKWebView 强制开启跨域限制,无法绕过
- Android 差异:不同厂商 WebView 内核行为不同(系统 WebView/X5 内核)
- 小程序端:需配置业务域名(仅支持 https)
通信机制
- UniApp → H5:通过 URL 传参(src="url?param=value")
- H5 → UniApp:使用 uni.postMessage() + @message 事件
- 双向通信:依赖 uni-webview.js 库(需在 H5 中引入)
导航栏控制
默认显示顶部导航栏,需在 pages.json 配置:
json{ "path": "pages/webview", "style": { "navigationBarTitleText": "H5页面", "app-plus": { "titleNView": false // 隐藏导航栏 } } }
生命周期协调
H5 页面无法直接感知 UniApp 的 onShow/onHide,需通过 visibilitychange 事件模拟:
jsdocument.addEventListener("visibilitychange", () => { if (document.hidden) { // 通知 UniApp 页面隐藏 uni.postMessage({ type: "pageHide" }); } });
二、高频坑点及解决方案
白屏问题
场景:Android 低版本加载 HTTPS 资源失败
解决方案:
html<!-- H5 页面头部添加 --> <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
滚动穿透
现象:H5 内容滚动时连带父页面滚动
修复方案:
js// 在 H5 页面中 let overscroll = (el) => { el.addEventListener("touchstart", () => { let top = el.scrollTop; if (top <= 0) el.scrollTop = 1; if (top + el.offsetHeight >= el.scrollHeight) el.scrollTop = el.scrollHeight - el.offsetHeight - 1; }); }; overscroll(document.querySelector(".scroll-container"));
键盘顶起布局
问题:iOS 键盘弹出挤压 WebView 高度
应对方案:
js// UniApp 中监听键盘事件 onPageScroll(e) { if (e.scrollTop > 0) { this.webviewStyle = { height: `calc(100vh - ${e.scrollTop}px)` }; } }
通信延迟
现象:postMessage 在 Android 偶发丢失
健壮性方案:
javascript// UniApp 端 let retryCount = 0; const sendToH5 = (data) => { this.$refs.webview.evalJs(`receiveData(${JSON.stringify(data)})`); setTimeout(() => { if (!ackReceived) retryCount++ < 3 && sendToH5(data); }, 300); };
缓存失控
问题:iOS 强缓存导致 H5 更新不生效
强制更新策略:
javascript// UniApp 页面 onLoad onLoad() { const timestamp = new Date().getTime(); this.url = `https://your-h5.com?t=${timestamp}`; }
Q:移动端怎么做适配布局?
我的回答
vw
、vh
、rem
、%
、flex
等布局
Q:怎么实现瑞幸咖啡小程序那种,咖啡做好了发一个消息给你的微信,你点击进去后跳转到对应的详情页?
我的回答
我没做过这种通知,没有思路
Deepseek 回答
配置微信订阅消息
在微信公众平台配置消息模板:
json// 示例模板 模板ID:AT0001 标题:您的订单已完成 内容: {{thing1.DATA}} 已制作完成 请到 {{thing2.DATA}} 取餐 订单号:{{number3.DATA}}
前端请求订阅授权
在支付成功页请求用户授权:
javascript// pages/order/paySuccess.vue requestSubscribe() { const tmplIds = ['AT0001']; // 订阅的模板ID uni.requestSubscribeMessage({ tmplIds: tmplIds, success: (res) => { if (res[tmplIds[0]] === 'accept') { this.bindOrderNotice(); // 绑定订单通知 } } }); } // 向后端发送订阅绑定 bindOrderNotice() { uni.request({ url: '/api/bindNotice', method: 'POST', data: { orderId: this.orderId, openid: uni.getStorageSync('openid') } }); }
后端状态监控与消息发送
当订单状态变为"制作完成"时触发:
javascript// 伪代码示例 const sendWechatNotice = (order) => { const accessToken = getWechatAccessToken(); const apiUrl = `https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=${accessToken}`; axios.post(apiUrl, { touser: order.userOpenid, template_id: "AT0001", page: `pages/order/detail?orderId=${order.id}`, // 关键:跳转路径 data: { thing1: { value: order.productName }, thing2: { value: order.storeName }, number3: { value: order.orderNumber }, }, }); };
深度链接处理
在 app.vue 中处理打开参数:
javascriptonLaunch(options) { // 从微信服务通知打开时 if (options.referrerInfo?.extraData) { const { orderId } = options.referrerInfo.extraData; if (orderId) { uni.reLaunch({ url: `/pages/order/detail?orderId=${orderId}` }); } } }
订单详情页接收参数
javascript// pages/order/detail.vue onLoad(query) { this.orderId = query.orderId; this.loadOrderData(); }
Q:说一下哪些方法能实现数据本地持久化?
我的回答
localStorage
、sessionStorage
、cookie
Q:promise、async await、回调函数的区别?
我的回答
async await
是function *() {}
的语法糖,yield
后面的操作会等待执行完毕后再往下;promise
是同步任务,执行完后修改状态,状态修改完一次后就永远不会改变,对应的then
或者catch
方法再放到微任务队列中
Deepseek 回答
特性 | 回调函数 | Promise | async/await |
---|---|---|---|
本质 | 基础函数传递 | 异步操作容器对象 | 语法糖(基于 Promise) |
可读性 | 嵌套回调时差(回调地狱) | 链式调用改善 | 类似同步代码,最佳可读性 |
错误处理 | 手动判断(error-first) | .catch() 统一处理 | try/catch 同步式处理 |
流程控制 | 手动管理 | .then() 链式管理 | 顺序编写,自动管理 |
返回值 | 无直接返回值 | 返回 Promise 对象 | 返回 Promise 对象 |
组合能力 | 困难 | Promise.all() 等组合方法 | 与 Promise 方法结合 |
回调函数(Callbacks)
javascript// 典型 "error-first" 回调风格 fs.readFile("file.txt", "utf8", (err, data) => { if (err) { console.error("读取失败:", err); return; } // 嵌套第二个异步操作 processData(data, (err, result) => { if (err) console.error("处理失败:", err); else saveResult(result, (err) => { if (err) console.error("保存失败:", err); else console.log("操作完成!"); }); }); });
问题:
- 回调地狱:多层嵌套导致代码金字塔
- 错误处理碎片化:每个回调需单独判断错误
- 流程控制困难:并行/顺序执行需手动实现
Promise
javascriptfs.promises .readFile("file.txt", "utf8") .then((data) => processData(data)) // 返回新 Promise .then((result) => saveResult(result)) .then(() => console.log("操作完成!")) .catch((err) => { // 统一错误处理 console.error("失败:", err); }); // 并行处理多个异步 Promise.all([fetchUser(), fetchOrders()]).then(([user, orders]) => { console.log(user, orders); });
优势:
- 链式调用:解决回调嵌套问题
- 集中错误处理:.catch() 捕获链中任何错误
- 状态明确:pending/fulfilled/rejected
组合方法:Promise.all/race/any 等
async/await
javascriptasync function handleFile() { try { const data = await fs.promises.readFile("file.txt", "utf8"); const result = await processData(data); await saveResult(result); console.log("操作完成!"); // 并行示例 const [user, orders] = await Promise.all([fetchUser(), fetchOrders()]); } catch (err) { // 统一捕获所有错误 console.error("失败:", err); } }
优势:
- 同步化编码:用同步写法处理异步
- 错误处理简化:try/catch 同步语法
- 变量作用域自然:避免闭包陷阱
Q:我的项目试听功能怎么实现的?
我的回答
后端那边会有试听的音频链接。
二面
Q:算法题,实现一个函数,接收两个从小到大排列的数组,如 a = [1, 4, 6],b = [3, 9]。合并为新数组 c,并继续保持从小到大排列。
双指针法高效合并两个有序数组的 JavaScript 函数实现:
function mergeSortedArrays(a, b) {
const merged = [];
let i = 0; // 数组 a 的指针
let j = 0; // 数组 b 的指针
// 遍历两个数组,比较元素大小
while (i < a.length && j < b.length) {
if (a[i] <= b[j]) {
merged.push(a[i]);
i++;
} else {
merged.push(b[j]);
j++;
}
}
// 将剩余元素添加到结果数组
while (i < a.length) {
merged.push(a[i]);
i++;
}
while (j < b.length) {
merged.push(b[j]);
j++;
}
return merged;
}
// 测试示例
console.log(mergeSortedArrays([1, 4, 6], [3, 9])); // 输出: [1, 3, 4, 6, 9]
console.log(mergeSortedArrays([], [1, 2, 3])); // 输出: [1, 2, 3]
console.log(mergeSortedArrays([5, 7, 9], [2, 6])); // 输出: [2, 5, 6, 7, 9]
console.log(mergeSortedArrays([1, 2, 3], [4, 5, 6])); // 输出: [1, 2, 3, 4, 5, 6]
递归法:
function mergeSortedArraysRecursive(a, b) {
if (a.length === 0) return b;
if (b.length === 0) return a;
if (a[0] <= b[0]) {
return [a[0], ...mergeSortedArraysRecursive(a.slice(1), b)];
} else {
return [b[0], ...mergeSortedArraysRecursive(a, b.slice(1))];
}
}