前言

最近在开发小程序项目,将项目中遇到的问题和要点记录下来,方便以后查阅。

字体

全局字体

项目中使用了 vant-weapp,有赞开源的小程序组件库。

为保证在不同设备上提供最佳的视觉体验,且与组件库风格统一,可在 app.wxss 中设置以下全局字体。

page {
  font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica,
    Segoe UI, Arial, Roboto, 'PingFang SC', 'Hiragino Sans GB', 'Microsoft Yahei',
    sans-serif;
}

字号单位

字号单位用 px,不同分辨率设备上字体大小保持一致,取值尽量是偶数。

可以将常用的字号写成 css 变量,方便使用。

page {
    --font-size-xs: 10px;
    --font-size-sm: 12px;
    --font-size-md: 14px;
    --font-size-lg: 16px;
    --font-size-xl: 18px;
    --font-size-xxl: 24px;
}

view {
    font-size: var(--font-size-md);
}

图片资源

项目中经常会使用图片、SVG 等文件,而这些文件占据项目体积很大的比重。因小程序包体积限制,需要对图片文件进行压缩处理。

WXS 工具方法

WXS 是小程序的一套脚本语言。语法跟 JavaScript 类似,但其中有一些坑。比如不能遍历对象。没有 Object 对象,不能使用 for ... in ...。小程序社区里也有关于这个的吐槽

只能通过正则的方式来实现对象的遍历方法:

// object.wxs
var REGEXP = getRegExp('{|}|"', 'g');

function keys (obj) {
  return JSON.stringify(obj)
    .replace(REGEXP, '')
    .split(',')
    .map(function(item) {
      return item.split(':')[0]
    })
}

function values (obj) {
  return JSON.stringify(obj)
    .replace(REGEXP, '')
    .split(',')
    .map(function(item) {
      return item.split(':')[1]
    })
}

module.exports = {
  keys: keys,
  values: values,
}

iPhoneX 适配

屏幕上边框,右边框,下边框,左边框安全距离:

safe-area-inset-top
safe-area-inset-right
safe-area-inset-bottom
safe-area-inset-left

使用:

iOS 11

padding-top: constant(safe-area-inset-top);
padding-right: constant(safe-area-inset-right);
padding-bottom: constant(safe-area-inset-bottom);
padding-left: constant(safe-area-inset-left);

iOS 11.2 beta 及其后

padding-top: env(safe-area-inset-top);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);

兼容性写法:

padding-top: constant(safe-area-inset-top);
padding-top: env(safe-area-inset-top);

参考文档:苹果官方文档

iOS 中 Promise 对象不存在 finally 方法

在开发者工具中没有这个问题,只在 iOS 真机中存在。不知小程序官方是否修复了此 bug。

在 app.js 中添加如下代码:

if (!Promise.prototype.finally) {
  Promise.prototype.finally = function (callback) {
    this.then(res => {
      callback && callback(res)
    }, error => {
      callback && callback(error)
    })
  }
}

引入路径

在小程序中 import ... from ...require 不支持绝对路径。只能使用相对路径引入,如果目录过深就会写成 ../../../../util.js,不够直观优雅。

可以通过以下方式优化引入:

// app.js 中
App({
    require (path) {
        return require(`${path}`)
    }
})

在其他 page 和组件中,就可以统一相对于根路径引入。

const app = getApp()
const { formatTime } = app.require('/utils/util')

SKU 商品规格

SKU 是指物理上不可分割的最小存货单元

开发的是电商类型项目,SKU 商品规格选择功能是必不可少的,也是项目中比较复杂的功能。将功能封装为组件,具体的代码查看该地址

笛卡尔积应用

SKU 商品规格选择是 C 端的功能,其中还涉及到如何生成商品 SKU 数据。也就是笛卡尔积的应用。

如上图所示,通过“颜色”和“尺寸”2个销售属性来生成商品的 SKU,就需要对属性的值做笛卡尔积,其中核心代码如下:

/**
 * @desc 多数组求笛卡尔积
 * @param { Array } array [['粉色', '黄色', '蓝色'], ['大', '小']]
 * @return { Array } ['粉色', '大'], ['粉色', '小'], ['黄色', '大'], ['黄色', '小'], ['蓝色', '大'], ['蓝色', '小']
 */
function cartesianProduct (array) {
  return array.reduce(function (a, b) {
    return a.map(function (x) {
      return b.map(function (y) {
        return x.concat(y)
      })
    }).reduce(function (a, b) { return a.concat(b) }, [])
  }, [[]])
}

总结

这些都是最近项目中记录下来的,欢迎大家交流,以后开发中碰到了其他问题也会持续更新的。