耿健的个人博客

一个即将放飞理想的咸鱼博主

0%

12.关于小程序开发的一些杂谈

书写背景

从接触到开发小程序,
也有一段时间了。
想新建一个帖子,
借此总结复盘一下自己踩过的坑,
和含泪背锅的经历。

背锅标签

  1. wx.previewImage 不能禁用用户保存图片
  2. ios 播放音频偶尔会出现错误
  3. UploadTask.onProgressUpdate 进度回调不准确
  4. “右滑手势返回”能力调整
  5. 微信 7.0.12 调用 wx.scanCode 后无 path 返回
  6. video 在 scrollView 中使用的俩个 bug
  7. video 退出全屏播放后,安卓会回到顶部?
  8. canvasContext.draw 回调 ios 第二次不执行

应用场景

  1. 每个页面尽量重新调用接口
    这样做的好处是降低耦合,
    页面与页面之间是一个非常脆弱的关联。
    因为谁也说不准未来的需求,
    会不会一时兴起要“空降”这个页面。
    那么如果这个页面依赖于之前的缓存或者其他处获取 Redux 等全局的数据,
    最后的结果肯定是惨痛的修修补补。

  2. onLoad/ onShow 生命周期
    onLoad 的声明周期只用来处理页面传参。
    onShow 的声明周期用来调用接口初始化数据。
    如果二者混用,那么绝逼会由于接口异步的调用,
    导致某些数据依赖数据没获取到就执行下一步,
    从而使程序出现一堆偶现且莫名其妙的错误。

  3. 自定义封装的顶部导航
    关于自定义的导航有两点想说一下:
    一是,fixed 样式兼容。
    当处于 fixed 样式的时候,
    最好能实现个空格高度来占位文档流。
    这样可以兼容用 fixed 的页面和不用 fixed 的页面。
    有了占位之后,可以保证 fixed 的页面不会被搞垮掉。
    另外也没必要让每个页面都要特意做个 padding-top。
    这个 padding-top 还需要根据机型来判断高度。
    所以最好还是都封装在顶部导航组件里来处理这个脏活是最好了。
    二是,返回按钮劫持事件。
    由于微信版本的更新,
    在真机使用小程序时候,
    可以通过右划左屏幕边缘,来完成快捷返回上一页的交互。
    这个交互且无法关闭。
    (可能为了照顾大屏手机 or 最小化小程序交互?)
    这样相当于跨过了点返回按钮才返回的交互。
    如果再点击返回按钮时候做了逻辑处理,
    那么就很容易给未来的自己挖坑。
    所以,最好还是通过 重定向 的跳转方式,
    稳定的来维护我们的路由堆栈。

  4. 关于接口参数的传递
    比如封装接口,需要传值的时候,
    需要多少参数,就给封装函数参数设置多少个变量。
    举个例子。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    const queryAppInfo = async (
    memberId?: string,
    appId?: string,
    timestamp?: string
    ) => {
    const params = {
    memberId,
    appId,
    timestamp,
    };
    const res = await CloudFetch.callFunction("fetchAppInfo", params);
    return res.data.data[0];
    };

    而有些参数是可选传参。比如我们不需要传递 appId 的时候,
    外部调用的时候就会很难看

    1
    queryAppInfo("007", , '123');

    那么,个人认为还是在调用接口的地方处理好参数对象,
    直接将参数对象传入封装的函数中,

    1
    2
    3
    4
    5
    const param = {
    memberId: "007",
    timestamp: "123",
    };
    queryAppInfo(param);

    这样看起来比较规范,数据也会比较安全。

  5. 弹出弹窗效果的实现
    无论是模态对话框,还是弹出提示性的对话框。
    虽然看起来只是弹出个对话框。
    不过最好底部加一层蒙板,

    1
    2
    3
    4
    5
    6
    7
    8
    .mask {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.2);
    }

    无论是透明或者有颜色。
    这样不仅可以在蒙板上完成,阻止事件冒泡。
    也可以在蒙板上完成,点击其他部分关闭提示对话框。

  6. 应用系的组件,要清晰回调函数
    比如:登录、授权组件,回传事件需要明确。

    1
    2
    3
    4
    5
    6
    success: (res) => {
    // TODO:...
    };
    fail: (err) => {
    // TODO:...
    };
  7. 保证性能,谨慎接口调用
    如果说前端都可以判断到,条件是不符合的,
    那么无需做无用功,去再调用接口。

  8. 公共组件内的数据建议还是通过组件传值来取
    如果过度依赖 Redux 中的数据,
    就会导致该模块只能适用当前模块。
    以至于后期其他模块无法复用。

  9. Html 模板内尽可能的使用自闭合标签
    在多方因素的作用下:
    面条型的代码量的增加,
    个别情况下的书写习惯,
    线上 bug 临时写一笔赶工,
    代码过长,缩进捋不清除。
    在这种情况下,是很容易将一些代码混进标签内,
    进而引发一些莫名其妙的错误,而且很难定位具体问题。
    所以尽量使用自闭合标签来避免这些问题。

  10. JSON.parse 的坑
    JSOM.stringify 和 JSON.parse 是对序列化很有效的方法。
    可供使用的场景也非常频繁。
    JSOM.stringify 还好说,转换为字符串问题都不是很大。
    JSON.parse 相对而言就要谨慎使用。
    将一个 JSON 字符串转换为对象,
    可是如果参数传入一个非 JSON 字符串的话,就会导致报错。
    所以在使用 JSON.parse 的时候,一定要有一层保护。
    即使传入的参数不是个正经值的时候,
    传入个’{}’默认字符串以保证程序不至于报错。

  11. wx.scanCode() 返回结果的坑。
    调用微信小程序官方 API
    wx.scanCode() 返回值的 path 字段,
    竟然有时候存在,有时候就没有。
    对照官方文档之后,看到官方给出的说法是

    1
    当所扫的码为当前小程序二维码时,会返回此字段,内容为二维码携带的 path

    不过有的时候也没有,只能通过 result 字段存储两份数据。
    在扫码成功后,能读取成功哪个字段就取哪个字段的数据。

  12. 微信小程序 scroll-view 组件实现横向滚动的坑
    经过测试,
    发现要想实现横向滚动,不仅在组件设置对应属性字段,
    还需要 CSS 中满足两个条件:

    1. 外部 scroll-view 容器设置
    1
    white-space: nowrap;
    1. 每个滚动子项需要设置
    1
    display: inline-block;
  13. 在 ScrollView 中使用 Canvas 组件
    会有很多异常的情况出现,比如真机情况下,渲染出来的图片需要屏幕左上角闪一次才会回到期望渲染位置。
    解决方案,尽量不要将 Canvas 放到 ScrollView 里。生成出来的图片,尽量通过 Canvas 转为 Base64,然后再通过 Base64 渲染到 Image 标签上。

  14. 模拟器 canvas 绘制海报的时候 canvasContext.draw 回调第二次不执行。
    如下代码所示,
    第一次执行的时候该段函数 1、2、3 都可以执行,
    不过第二次则只会执行 1、2,
    3 则不会再进入。

    真机暂未发现该问题。

    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
    console.log("updateCanvasShare1", srcQRCode, strShareContentUrlTmp);
    await drawCanvasShare(
    canvasShare,
    strShareContentUrlTmp,
    srcQRCode,
    strSharePosterText || sharePosterText,
    2
    );
    console.log("updateCanvasShare2", srcQRCode, strShareContentUrlTmp);
    canvasShare.draw(false, () => {
    console.log("updateCanvasShare3", srcQRCode, strShareContentUrlTmp);
    // Taro.hideToast();
    Taro.canvasToTempFilePath({
    x: 0,
    y: 0,
    width: PANEL_SHARE_WIDTH * 2,
    height: PANEL_SHARE_HEIGHT * 2,
    destWidth: PANEL_SHARE_WIDTH * 2,
    destHeight: PANEL_SHARE_HEIGHT * 2,
    fileType: "jpg",
    canvasId: "canvas-share",
    success: (resToCanvas) => {
    console.log("canvasToTempFilePath success.", resToCanvas);
    setSharePhotoUrl(resToCanvas.tempFilePath);
    },
    fail: (errToCanvas) => {
    console.log("canvasToTempFilePath fail.", errToCanvas);
    setShowBtnRefresh(true);
    Taro.showToast({ title: "生成海报失败", icon: "none" });
    },
    });
    });
  15. 小程序检测版本更新 wx.getUpdateManager 的一些坑。
    如下为官方的示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    const updateManager = wx.getUpdateManager();
    updateManager.onCheckForUpdate(function (res) {
    // 请求完新版本信息的回调
    console.log(res.hasUpdate);
    });

    updateManager.onUpdateReady(function () {
    wx.showModal({
    title: "更新提示",
    content: "新版本已经准备好,是否重启应用?",
    success: function (res) {
    if (res.confirm) {
    // 新的版本已经下载好,调用 applyUpdate 应用新版本并重启
    updateManager.applyUpdate();
    }
    },
    });
    });
    updateManager.onUpdateFailed(function () {
    // 新版本下载失败
    });

    如果在触发更新提示弹窗后,点击确认,
    此时,会弹出小程序需要重启以使用最新功能弹窗,点击知道了即可重启小程序。

    可如果不点确认,而业务逻辑异步出现跳转页面的逻辑,更新逻辑就会被冲掉。
    而第二次进入小程序的时候,在触发更新提示弹窗后,点击确认,也不会出现小程序需要重启以使用最新功能弹窗,
    只能默默等待小程序自动更新,或者手动杀掉小程序,清除缓存。

  16. 实机 css 动画超出圆角 overflow:hidden 范围
    真机的情况,css animation 动画,在圆角 overflow:hidden 标签内,显示的内容会超出范围。
    解决方法:
    调整父级元素的层级即可。
    实机 css 动画超出圆角 overflow:hidden 范围

  17. iOS 上 video 位于 scrollView 内部时,全屏后返回,scrollView 自动滚动到顶部
    微信小程序当前版本的表现即是如此,
    目前解决方式即是 video 的标签,不要放到 scrollView 内部。(scrollview 的坑太多)
    iOS 上 video 位于 scrollView 内部时,全屏后返回,scrollView 自动滚动到顶部

后记

如果后续有想到的会随时更新。