推荐几个微信小程序开发小技巧

马丁路德 等级 755 0 0

前段时间在下开发了个微信小程序,开发过程中总结了一些我觉得对我有用的小技巧,提炼出来,相当于一个总结复盘,也希望可以帮助到大家。如果对大家确实有帮助,别忘了点赞哦 🌟 ~

1. 开发中可能遇到的坑以及 Tips

本来想写个小技巧的,结果我总结了一堆坑,没上手之前完全想象不到微信小程序的开发体验是如此之差、如此之烂,从微信开发者工具到所谓的「全新语言」,都有一种浓浓的半成品的 five 即视感,实在让我 emmm.... 另外我发现网上的小程序文章大部分都是如何使用和如何避坑的实用文,而不是技巧文,这也从侧面反映了小程序的坑多。

在微信小程序原生开发过程中,我不断发出这样的疑问「为什么堂堂技术人才多如牛毛的腾讯,会推出如此 laji」,很多弱智反人类的地方,在两三年前社区就已经提出来,官方回复已经反馈正在修复中,但几年过去了,还是没有音信,官方回复仍然是一句冷冰冰的「已反馈」 😤

  1. 微信开发者工具经常热更新不起作用甚至白屏,重新编译也不行,只能强行退出后再次打开;
  2. 跟上一条类似,有时候一点样式出错,预览整个都白屏,调试器里也不说哪里的问题,直接就给你弃疗不显示,重新编译也无法解决问题,只能强行退出后再次打开;
  3. 跟上一条类似,调试器里报的错经常没什么用,驴头不对马嘴,让人很难定位问题;
  4. Android 端自定义 Tabbar 在下拉刷新的时候,也会跟着屏幕一起往下移,而且是无法绕过的 Bug,自定义 Tabbar 样式都写好了的我又改成自带的 Tabbar 了!
  5. import 的路径不支持绝对路径,比如你希望引用 utils/fetch.js,在不管多深的组件里面你都要慢慢 ../ 点到根目录,同样 .wxss 文件 @import 导入文件时也只能使用相对路径,所以就会出现 ../../../../../../utils/fetch.js 这种东西;
  6. 静态资源路径不能有汉字,有汉字就无法加载;
  7. .wxs 文件不支持 ES6,只能使用蹩脚的 ES5 写法;
  8. .wxml 中只能引入 .wxs 文件不能引入 .js 文件???
  9. 模板 {{}} 中连方法都不能执行,只能处理简单的运算如 + - * /,如果遇到数据需要 filter 的场景,需要在 .js 文件中预先格式化好再一个个 setData,比如经常写的 [2,3,4].includes(type),居然都跑不起来!
  10. .wxs 文件中无法使用 Date 对象,所以不能 new Date(),只能使用蹩脚的 getDate 方法,正则也是一样,生成正则对象需要使用 getRegExp 函数 getRegExp(pattern[, flags])
  11. .wxs 中可以调用其它 .wxs 文件,并且只能 require 调用 .wxs 文件,引入的文件必须使用相对路径;
  12. setData 连一个对象合并都懒得做,如果 data: {a: {b: 1, c: 1}},那么 setData({a: {b: 2}}) 就会丢失 a.c 的值,真是让人火冒三丈啊,还要 setData({['a.b': 2]}) 这样才行;
  13. IOS 上 Date 对象获取任意时间参数比如 getDaygetTime 都为 NaN,是因为 IOS 的 Date 构造函数不支持 2018-04-26 这种格式的日期,必须转换为 2018/04/26 这种格式才会显示正常;
  14. 开发版小程序有时候请求莫名其妙发不出去,右上角三个点 enable debug 打开「开发调试」之后就莫名其妙能发出去请求了,在多部手机上都是这样,不明真相。

2. 微信请求 Promise 化

2.1 使用现成的库

安装 Promise 库 wx-promise-pro,记得一定要带 -s--production,要不然无法构建成功。

npm i -S wx-promise-pro 

然后在 app.js 中:

import { promisifyAll } from 'wx-promise-pro'

promisifyAll()  // promisify all wx api

App({ ... }) 

之后就可以正常使用了:

wx.pro.showLoading({
    title: '加载中',
    mask: true
})
  .then(() => console.log('in promise ~')) 

2.2 自己实现

其实我们可以自己来实现一个这样的库,原理很简单,以原生 API 的 wx.request 为例:

// 原生 API 使用方式
wx.request({
    url: '',     // 请求的 url
    data: {},    // 参数
    method: '',  // post、get
    success: res => {
        // 请求成功回调函数,res为回调参数
    },
    fail: res => {
        // 请求失败回调函数,res为回调参数
    }
}) 

如果我们将其 Promise 化,应该的调用方式希望是:

// Promise 化后的期望使用方式
wx.pro.request({
    url: '',     // 请求的 url
    data: {},    // 参数
    method: ''   // post、get
})
  .then(res => {
      // 请求成功回调函数,res为回调参数
  })
  .catch(res => {
      // 请求失败回调函数,res为回调参数
  }) 

并且 then 函数返回的是一个 Promise 对象,让这个函数可以不断链式调用下去,所以首先需要 new 出来一个 Promise 对象:

function request(opt) {
    return new Promise((resolve, reject) => {
        wx.request({
            ...opt,
            success: res => { resolve(res)},
            fail: res => {reject(res)}
        })
    })
} 

这里代码我们可以进一步改进,由于 successfail 这里传入的参数只是由 resolvereject 方法执行了下,所以可以直接传入 resolvereject 方法即可。

另外,由于其他小程序原生 API 格式一致,所以我们可以使用柯里化方法,来将其他需要进行 Promise 化的 API 进行处理:

function promisify(api) {
    return (opt = {}) => {
        return new Promise((resolve, reject) => {
            api({
                ...opt,
                fail: reject,
                success: resolve
            })
        })
    }
} 

然后,将柯里化方法执行的结果作为新的 Promise 化的 API 挂载到 wx.pro 对象上:

// 将指定 API 进行 Promise 化
wx.pro.request = promisify(wx.request)

// 使用
wx.pro.request({...})
    .then(...) 

然后为了方便我们使用其他方法,可以循环将 wx 对象上可以被 Promise 化的方法比如 requestscanCodeshowToastgetUserInfo 等一一挂载到 wx.pro 对象上,使用时可以直接 wx.pro.xx,由于这个方法执行返回的是一个 Promise 对象,因此可以像其它 Promise 化的对象那样使用。

事实上,不知不觉,我们就自己实现了 wx-promise-pro 的源码,这个库的核心代码也就是上面那这几行 🥳

2.3 在项目中使用

有了上面的工具后,我们可以将其使用在项目中,为了不在项目中遍布 wx.requestwx.pro.request 这里可以简单进行封装,新建两个文件如下:

// utils/api/fetch.js 封装请求方法、请求拦截器

const app = getApp()

const BaseUrl = 'http://172.0.0.1:7300/mock'

const TokenWhiteList = [
    '/app/user/get-by-code'     // 不需要鉴权的api手动添加到这里
]

/**
 * 设置请求拦截器
 * @param params 请求参数
 */
const fetch = (params = {}) => {
    // 拦截器逻辑
    if (!TokenWhiteList.includes(params.url)) {
        params.header = {
            'content-type': 'application/json',             // 默认值
            'token': app.globalData.token || ''
        }
    }

    if (params.url.startsWith('/')) {    // 拼接完整URL
        params.url = BaseUrl + params.url
    }

    // 返回promise
    return wx.pro.request({ ...params })
      .then(({ data: { code, message, data } }) => {
          // ... 各种异常情况的逻辑处理
          // 与后端约定 code 20000 时正常返回
          if (code === 20000) return Promise.resolve(data)
          return Promise.reject(message)
      })
}

export { fetch } 

然后再将所有 API 封装到单独的文件中集中管理:

// utils/api/apis.js 封装所有请求 API

import { fetch } from './fetch'

/* 根据微信code获取用户信息 */
const appUserGetByCode = ({ code } = {}) => fetch({
    url: '/app/user/get-by-code',
    data: { code }
})

/* 扫码登录 */
const appUserQrLogin = ({ qrCode } = {}) => fetch({
    method: 'POST',
    url: '/app/user/qr-login',
    data: { qrCode }
})

/* 个人信息 */
const appUserInfo = () => fetch({
    url: '/app/user/info'
})

/* 系统参数获取,数据字典 */
const appSysParamListByParam = () => fetch({
    url: '/app/sys-param/list-by-param'
})

/* 数据字典所有 */
const appSysParamListAll = () => fetch({
    url: '/app/sys-param/list-all'
})

export {
    appSysParamListAll,   // 数据字典所有
    appSysParamListByParam,   // 系统参数获取,数据字典
    appUserGetByCode,   // 根据微信code获取用户信息
    appUserQrLogin,   // 扫码登录
    appUserInfo   // 个人信息
} 

在要使用 API 的地方就可以这样引入:

import * as Api from '../../utils/api/apis.js'   // 相对路径

// 使用方式
Api.appSysParamListAll()
  .then(({ dataList }) => this.upData({ sysParamList: dataList }))
  .then(() => {
      const keyList = this.data.sysParamList.map(T => T.key)
      this.upData({
          keyList,
          formData: { keys: keyList }
      })
  }) 

使用方式就很舒服,这里使用到了 upData,就是下面我要介绍的内容,是在下非常推介的小程序工具~ 🥳

3. setState 修改 data 中想修改对象的属性

在小程序中,data 是不能直接操作的,需要使用 setData 函数。鉴于微信小程序开发时 setData 的使用体验十分蹩脚,我使用了个库函数 wx-updata,这个库函数在开发的时候对我很有帮助,这里特意推介给大家。

3.1 为什么要使用 wx-updata

你在使用 setData 的时候,是不是有时候觉得很难受,举个简单的例子:

// 你的 data
data: {
    name: '蜡笔小新',
    info: { height: 140, color: '黄色' }
} 

如果要修改 info.height 为 155,使用 setData 要怎么做呢:

// 这样会把 info 里其他属性整不见了
this.setData({ info: { height: 155 } })

// 你需要取出 info 对象,修改后整个 setData
const { info } = this.data
info.height = 155
this.setData({ info }) 

似乎并不太复杂,但如果 data 是个很大的对象,要把比较深且不同的对象、数组项挨个改变:

data: {
    name: '蜡笔小新',
    info: {
        height: 140, color: '黄色',
        desc: [{ age: 8 }, '最喜欢大象之歌', '靓仔', { dog: '小白', color: '白色' }]
    }
} 

比如某个需求,需要把 info.height 改为 155,同时改变 info.desc 数组的第 0 项的 age 为 12,第 3 项的 color 为灰色呢?

// 先取出要改变的对象,改变数字后 setData 回去
const { info } = this.data
info.height = 155
info.desc[0].age = 12
info.desc[3].color = '灰色'
this.setData({ info })

// 或者像某些文章里介绍的,这样可读性差,也不太实用
this.setData({
    'info.height': 155,
    'info.desc[0].age': 12,
    'info.desc[3].color': '灰色'
}) 

上面这两种方法,是我们平常小程序里经常用的,和其他 Web 端的框架相比,就很蹩脚,一种浓浓的半成品感扑面而来,有没有这样一个方法:

this.upData({
    info: {
        height: 155,
        desc: [{ age: 12 }, , , { color: '灰色' }]
    }
}) 

这个方法会帮我们深度改变嵌套对象里对应的属性值,跳过数组项里不想改变的,只设置我们提供了的属性值、数组项,岂不是省略了一大堆蹩脚的代码,而且可读性也极佳呢。

这就是为什么我在上线的项目中使用 wx-updata,而不是 setData

wx-updata 的原理其实很简单,举个例子:

this.upData({
    info: {
        height: 155,
        desc: [{ age: 12 }]
    }
})

// 会被自动转化为下面这种格式,
// this.setData({
//    'info.height': 155,
//    'info.desc[0].age': 12,
// }) 

原来这个转化工作是要我们自己手动来做,现在 wx-updata 帮我们做了,岂不美哉!

3.2 wx-updata 使用方式

在一般情况下,我们可以将方法直接挂载到 Page 构造函数上,这样就可以在 Page 实例中像使用 setData 一样使用 upData 了:

// app.js 中挂载
import { updataInit } from './miniprogram_npm/wx-updata/index'  // 你的库文件路径

App({
    onLaunch() {
        Page = updataInit(Page, { debug: true })
    }
})

// 页面代码中使用方式
this.upData({
    info: { height: 155 },
    desc: [{ age: 13 }, '帅哥'],
    family: [, , [, , , { color: '灰色' }]]
}) 

有的框架可能在 Page 对象上进行了进一步修改,直接替换 Page 的方式可能就不太好了,wx-updata 同样暴露了工具方法,用户可以在页面代码中直接使用工具方法进行处理:

// 页面代码中
import { objToPath } from './miniprogram_npm/wx-updata/index'  // 你的库文件路径

Page({
    data: { a: { b: 2}, c: [3,4,5]},

    // 自己封装一下
    upData(data) {
        return this.setData(objToPath(data))
    },

    // 你的方法中或生命周期函数
    yourMethod() {
        this.upData({ a: { b: 7}, c: [8,,9]})
    }
}) 

针对修改数组指定项的时候,可能存在的跳过数组空位的情况,wx-updata 提供了 Empty 的 Symbol 类型替位符,还有数组的对象路径方式,感兴趣可以看看 wx-updata 的文档,也可以参考 <开发微信小程序,我为什么放弃 setData,使用 upData> 这篇介绍文章。

另外,使用了 wx-updata 也还可以使用原来的 setData,特别是有时候要清空数组时,灵活使用,可以获得更好的小程序开发体验,祝大家小程序开发愉快 🤣

4. 使用 scss 写样式

4.1 Webstorm 配置方法

关于蹩脚的 .wxss 样式,我使用 webstorm 的 file watcher 工具把 scss 文件监听改动并实时编译成 .wxss 文件,感觉比较好用,这里给大家分享一下我的配置:

推荐几个微信小程序开发小技巧

然后记得在 .gitignore 文件中加入要忽略的样式:

*.scss
*.wxss.map 

这样在上传到 git 的时候,就不会上传 scss 文件了~ 当然如果你的团队成员需要 scss 的话,还是建议 git 上传的时候也加上 scss 文件。

这样设置之后,一个组件在本地的会是下面这样

推荐几个微信小程序开发小技巧

其中我们需要关注的就是 .js.json.scss.wxml 文件,另外的文件 .wxss 会在你改动 .scss 文件之后自动生成并更新,而 .wxss.map 是插件自动生成的映射关系,不用管。

如果不是使用 webstorm,可以直接执行命令 sass --watch index.scss:index.wxss -s expanded,命令行如果关闭,sass 命令就不会监听文件的变动然后编译,所以最好用编辑器的插件。

同理,也可以使用 less、stylus 等预编译语言。

4.2 Visual Studio Code 配置方法

万能的 VSC 当然也可以做到这个功能,搜索并下载插件 easy sass,然后在 setting.json 中修改/增加配置:

"easysass.formats": [
  {
    "format": "expanded",
    "extension": ".wxss"
  },
  {
    "format": "compressed",
    "extension": ".min.wxss"
  }
] 

上面 expanded 是编译生成的 .wxss 文件,下面 compressed 是压缩之后的 .wxss 样式文件,下面这个用不到可以把下面这个配置去掉,然后在 .gitignore 文件中加入要忽略的中间样式:

*.scss 

当然也可以不添加,如果你的同事也是实用 scss 来开发小程序的话,其他跟上面一样,至此你就可以在小程序开发中快乐使用 scss 了~

5. 使用 iconfont 图标字体

在 Web 开发中 iconfont 可谓是最常用的灵活图标字体工具了,这里介绍一下如何在微信小程序中引入 iconfont 图标。

首先找到你想使用的图标们,点击购物车之后下载到本地。

推荐几个微信小程序开发小技巧

下载到本地是一个压缩包,解压缩之后将 iconfont.css 文件复制到微信小程序的 styles 文件夹中 (在下的习惯,也可以放到你想放的地方比如 fonts),将后缀改为 .wxss

推荐几个微信小程序开发小技巧

app.wxss 中引入样式:

@import "styles/iconfont.wxss"; 

然后在 .wxml 中就可以使用刚刚你添加的图标了,Web 使用 i 标签,小程序中使用 text 标签:

<text class="iconfont icon-my-edit" style="color: blue"></text> 

如果后面要加新的图标,要下载新的 iconfont.css 的文件到本地重命名并覆盖,重新走一遍这个流程。

当然,如果你使用的样式库提供的一些 icon 能满足你的要求,那更好,就不用引入外部图标字体文件了,不过大部分情况下是不满足的 🤣


网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出,如果本文帮助到了你,别忘了点赞支持一下哦(收藏不点赞,都是耍流氓 🤣)~

收藏
评论区

相关推荐

喜大普奔,微信终于支持外网打开小程序啦!
前言 千呼万唤始出来,微信小程序终于支持以URL Scheme的形式从外部唤起了。 long long ago 我们只能在微信内的网页中使用微信开发标签小程序跳转按钮
微信小程序modal
首先创建一个组件component,组件命名可以为modal modal.wxml的内容为 <view class'modalmask' wx:if'{{show}}' bindtap'clickMask' <view class'modalcontent' <scrollview scrolly class'mainc
微信小程序wxml使用substring
首先创建subutils.wxs文件 var sub function (val, start0, end17) { if (val.length 0 || val undefined) { return } if (val.length end) { return val.substring(start
微信小程序轮播图
实现效果 wxml代码 <view style"height:20rpx;"</view <view class"swiper"
微信小程序苹果机wx.showModal()
最近做项目中,发现使用wx.showModal()苹果机出现取消文字不显示问题,纠正后显示正确 wx.showModal({ title: '提示', content:'登录后体验更多功能' }) wx.showModal({ cancelText: '取消', confi
微信小程序 - 路由实践
欢迎来到我博客阅读:1\. 前言在微信小程序由一个 App()实例,和众多Page()组成。而在小程序中所有页面的路由全部由框架进行管理,框架以栈的形式维护了所有页面,然后提供了以下 API 来进行路由之间的跳转:1. wx.navigateTo2. wx.redirectTo3. wx.navigateBack4.
微信小程序 - 引入字体图标
网站图标要想做到清晰无锯齿,使用普通图片或者雪碧图都很难达到这个目的,一般我们都会引入字体图标(svg转font,使用图标像使用字体一样,详见《web页面使用字体图标》,那么如何在微信小程序中使用自定义图标呢?请看详细步骤:1、从上选择喜欢的图标加入购物车,在购物车弹窗中点击“下载代码”后,解压阿里图库 加入购物车购物车 下载代码图标文件内容2.、进入导入第
微信小程序 - 页面间传值
小程序页面间传值大家晚上好,说晚上好是因为是在晚上写的,说这句话是因为这句话开篇不那么突然。那么小程序的页面间传值,在我使用这段时间里,我就非常的主观的把它们分为wx.navigateTo和非wx.navigateTo的,因为wx.navigateTo有一个事件参数event,我从当前页跳转到下一页,如果需要能返回,我都用的wx.naviga
Vue和微信小程序的区别
_写了vue项目和小程序,发现二者有许多相同之处,在此想总结一下二者的共同点和区别。_一、生命周期先贴两张图: vue生命周期 小程序生命周期相比之下,小程序的钩子函数要简单得多。vue的钩子函数在跳转新页面时,钩子函数都会触发,但是小程序的钩子函数,页面不同的跳转方式,触发的钩子并不一样。 onLoad
推荐几个微信小程序开发小技巧
前段时间在下开发了个微信小程序,开发过程中总结了一些我觉得对我有用的小技巧,提炼出来,相当于一个总结复盘,也希望可以帮助到大家。如果对大家确实有帮助,别忘了点赞哦 🌟 ~1\. 开发中可能遇到的坑以及 Tips本来想写个小技巧的,结果我总结了一堆坑,没上手之前完全想象不到微信小程序的开发体验是如此之差、如此之烂,从微信
微信小程序体验composition-api(类似vue3)
微信小程序compositionapi用该是什么样子? 使用使用起来应该像是这个样子wxue(options) setup配置应该是包含一个setup选项是一个函数,返回的函数可以this.xxx调用,返回的数据可以this.data.xxx用到,如下import wxue, reactive from 'wxue'wxue( setup(option
PHP微信小程序支付——签名错误
![](https://static.oschina.net/uploads/space/2018/0509/141657_Tqix_3477605.png) 先分清几个概念:微信公众平台、微信开放平台、微信商户平台 1.微信公众平台、微信开放平台、微信商户平台是三个不同的平台 2.微信公众平台:用于公众号、小程序等等的设置平台,包括APPID、APP
5G消息与微信小程序互联互通?北京国都互联这么做……
最近微信小程序上线了一个超级流量的新入口 URL Scheme,据微信官网介绍,scheme码适用于短信、邮件、外部网页等拉起小程序的业务场景。通过小程序页面的URL Scheme,可以在短信、邮件或微信外部的网页中打开微信小程序。意义在于将微信流量生态延伸到微信以外渠道,进一步完善了小程序和外部渠道互通的营销场景。 **北京国都互联**第一时
1小时搭建微信小程序后端
CoNami小程序Demo端到端开发指南 ==================== 1\. 注册登录微信公众平台 -------------- 登录[https://mp.weixin.qq.com,里面有详细的指引,这里就不赘述了。这里注册最后得到的比较重要的东西包括两个](https://www.oschina.net/action/GoToLink
three.js
第1章 课程介绍 介绍了微信小游戏的概念以及相关的由来,从宏观上对于微信小游戏的定位和价值有一个明确的认识 第2章 微信小游戏平台与特性 讲了微信小游戏平台的相关特性,包括微信小游戏工程的建立,微信小游戏开发工具的详细使用,以及微信小游戏相关API的实战等 第3章 THREEJS与WebGL核心概念 通过理论和实战,讲解了什么是webgl、什