(给前端大全加星标,提升前端技能)
安装 Promise 库 wx-promise-pro,记得一定要带-s或–production,要不然无法构建成功。
npm i -S wx-promise-pro
然后在app.js中:
import { promisifyAll } from’wx-promise-pro’promisifyAll() // promisify all wx apiApp({ … })
之后就可以正常使用了:
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) { returnnewPromise((resolve, reject) => { wx.request({ …opt, success: res => { resolve(res)}, fail: res => {reject(res)} }) })}
这里代码我们可以进一步改进,由于success、fail这里传入的参数只是由resolve、reject方法执行了下,所以可以直接传入resolve、reject方法即可。
function promisify(api) { return(opt = {}) => { returnnewPromise((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 化的方法比如request、scanCode、showToast、getUserInfo等一一挂载到wx.pro对象上,使用时可以直接wx.pro.xx,由于这个方法执行返回的是一个 Promise 对象,因此可以像其它 Promise 化的对象那样使用。
事实上,不知不觉,我们就自己实现了wx-promise-pro的源码,这个库的核心代码也就是上面那这几行 ??
2.3 在项目中使用
有了上面的工具后,我们可以将其使用在项目中,为了不在项目中遍布wx.request或wx.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) returnPromise.resolve(data) returnPromise.reject(message) })}export { fetch }
然后再将所有 API 封装到单独的文件中集中管理:
在要使用 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 } }) })
3. setState 修改 data 中想修改对象的属性
3.1 为什么要使用 wx-updata
你在使用setData的时候,是不是有时候觉得很难受,举个简单的例子:
// 你的 datadata: { name: ‘蜡笔小新’, info: { height: 140, color: ‘黄色’ }}
如果要修改info.height为 155,使用setData要怎么做呢:
// 这样会把 info 里其他属性整不见了this.setData({ info: { height: 155 } })// 你需要取出 info 对象,修改后整个 setDataconst { info } = this.datainfo.height = 155this.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.datainfo.height = 155info.desc[0].age = 12info.desc[3].color = ‘灰色’this.setData({ info })// 或者像某些文章里介绍的,这样可读性差,也不太实用this.setData({ ‘info.height’: 155, ‘info.desc[0].age’: 12, ‘info.desc[3].color’: ‘灰色’})
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) { returnthis.setData(objToPath(data)) }, // 你的方法中或生命周期函数 yourMethod() { this.upData({ a: { b: 7}, c: [8,,9]}) }})
4. 使用 scss 写样式4.1 Webstorm 配置方法
关于蹩脚的.wxss样式,我使用 webstorm 的 file watcher 工具把 scss 文件监听改动并实时编译成.wxss文件,感觉比较好用,这里给大家分享一下我的配置:
然后记得在.gitignore文件中加入要忽略的样式:
*.scss*.wxss.map
这样在上传到 git 的时候,就不会上传 scss 文件了~ 当然如果你的团队成员需要 scss 的话,还是建议 git 上传的时候也加上 scss 文件。
这样设置之后,一个组件在本地的会是下面这样
本地文件
同理,也可以使用 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
5. 使用 iconfont 图标字体
在下下载icon
放到本地
在app.wxss中引入样式:
@import”styles/iconfont.wxss”;
<text class=”iconfont icon-my-edit” style=”color: blue”></text>
如果后面要加新的图标,要下载新的iconfont.css的文件到本地重命名并覆盖,重新走一遍这个流程。
当然,如果你使用的样式库提供的一些 icon 能满足你的要求,那更好,就不用引入外部图标字体文件了,不过大部分情况下是不满足的 ??
参考文档:
– EOF –