跳转到内容

网易

刀刀

6/20/2025

0 字

0 分钟

一面

Q:uniapp 小程序里面怎么塞一个 h5

我的回答

我记得是要用 web-view 组件,传一个 url ,渲染这个 url 的页面

Q:那么需要注意什么呢?

我的回答

我记得 web-view 组件渲染页面是有一些坑点的,但是太久没用了我一时想不起来,好像是 url 不能跨域?

Deepseek 回答

一、核心注意事项

  1. 平台兼容性

    • iOS 限制:WKWebView 强制开启跨域限制,无法绕过
    • Android 差异:不同厂商 WebView 内核行为不同(系统 WebView/X5 内核)
    • 小程序端:需配置业务域名(仅支持 https)
  2. 通信机制

    • UniApp → H5:通过 URL 传参(src="url?param=value")
    • H5 → UniApp:使用 uni.postMessage() + @message 事件
    • 双向通信:依赖 uni-webview.js 库(需在 H5 中引入)
  3. 导航栏控制

    默认显示顶部导航栏,需在 pages.json 配置:

    json
    {
      "path": "pages/webview",
      "style": {
        "navigationBarTitleText": "H5页面",
        "app-plus": {
          "titleNView": false // 隐藏导航栏
        }
      }
    }
  4. 生命周期协调

    H5 页面无法直接感知 UniApp 的 onShow/onHide,需通过 visibilitychange 事件模拟:

    js
    document.addEventListener("visibilitychange", () => {
      if (document.hidden) {
        // 通知 UniApp 页面隐藏
        uni.postMessage({ type: "pageHide" });
      }
    });

二、高频坑点及解决方案

  1. 白屏问题

    场景:Android 低版本加载 HTTPS 资源失败

    解决方案:

    html
    <!-- H5 页面头部添加 -->
    <meta
      http-equiv="Content-Security-Policy"
      content="upgrade-insecure-requests"
    />
  2. 滚动穿透

    现象: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"));
  3. 键盘顶起布局

    问题:iOS 键盘弹出挤压 WebView 高度

    应对方案:

    js
    // UniApp 中监听键盘事件
    onPageScroll(e) {
      if (e.scrollTop > 0) {
        this.webviewStyle = { height: `calc(100vh - ${e.scrollTop}px)` };
      }
    }
  4. 通信延迟

    现象: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);
    };
  5. 缓存失控

    问题:iOS 强缓存导致 H5 更新不生效

    强制更新策略:

    javascript
    // UniApp 页面 onLoad
    onLoad() {
      const timestamp = new Date().getTime();
      this.url = `https://your-h5.com?t=${timestamp}`;
    }

Q:移动端怎么做适配布局?

我的回答

vwvhrem%flex 等布局

Q:怎么实现瑞幸咖啡小程序那种,咖啡做好了发一个消息给你的微信,你点击进去后跳转到对应的详情页?

我的回答

我没做过这种通知,没有思路

Deepseek 回答

流程图

  1. 配置微信订阅消息

    在微信公众平台配置消息模板:

    json
    // 示例模板
    模板ID:AT0001
    标题:您的订单已完成
    内容:
    {{thing1.DATA}} 已制作完成
    请到 {{thing2.DATA}} 取餐
    订单号:{{number3.DATA}}
  2. 前端请求订阅授权

    在支付成功页请求用户授权:

    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')
        }
      });
    }
  3. 后端状态监控与消息发送

    当订单状态变为"制作完成"时触发:

    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 },
        },
      });
    };
  4. 深度链接处理

    在 app.vue 中处理打开参数:

    javascript
    onLaunch(options) {
      // 从微信服务通知打开时
      if (options.referrerInfo?.extraData) {
        const { orderId } = options.referrerInfo.extraData;
        if (orderId) {
          uni.reLaunch({
            url: `/pages/order/detail?orderId=${orderId}`
          });
        }
      }
    }
  5. 订单详情页接收参数

    javascript
    // pages/order/detail.vue
    onLoad(query) {
      this.orderId = query.orderId;
      this.loadOrderData();
    }

Q:说一下哪些方法能实现数据本地持久化?

我的回答

localStoragesessionStoragecookie

Q:promise、async await、回调函数的区别?

我的回答

async awaitfunction *() {} 的语法糖,yield 后面的操作会等待执行完毕后再往下;promise 是同步任务,执行完后修改状态,状态修改完一次后就永远不会改变,对应的 then 或者 catch 方法再放到微任务队列中

Deepseek 回答

特性回调函数Promiseasync/await
本质基础函数传递异步操作容器对象语法糖(基于 Promise)
可读性嵌套回调时差(回调地狱)链式调用改善类似同步代码,最佳可读性
错误处理手动判断(error-first).catch() 统一处理try/catch 同步式处理
流程控制手动管理.then() 链式管理顺序编写,自动管理
返回值无直接返回值返回 Promise 对象返回 Promise 对象
组合能力困难Promise.all() 等组合方法与 Promise 方法结合
  1. 回调函数(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("操作完成!");
          });
      });
    });

    问题:

    1. 回调地狱:多层嵌套导致代码金字塔
    2. 错误处理碎片化:每个回调需单独判断错误
    3. 流程控制困难:并行/顺序执行需手动实现
  2. Promise

    javascript
    fs.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);
    });

    优势:

    1. 链式调用:解决回调嵌套问题
    2. 集中错误处理:.catch() 捕获链中任何错误
    3. 状态明确:pending/fulfilled/rejected

    组合方法:Promise.all/race/any 等

  3. async/await

    javascript
    async 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);
      }
    }

    优势:

    1. 同步化编码:用同步写法处理异步
    2. 错误处理简化:try/catch 同步语法
    3. 变量作用域自然:避免闭包陷阱

Q:我的项目试听功能怎么实现的?

我的回答

后端那边会有试听的音频链接。

二面

Q:算法题,实现一个函数,接收两个从小到大排列的数组,如 a = [1, 4, 6],b = [3, 9]。合并为新数组 c,并继续保持从小到大排列。

双指针法高效合并两个有序数组的 JavaScript 函数实现:

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]

递归法:

javascript
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))];
  }
}