小程序开发前的准备工作
磨刀不误砍柴工,在开发之前做好准备工作可以大大提升开发效率、减少冗余代码,这篇文章结合自己做过的几个小程序的经验做一个总结。
着手开发小程序前都有哪些工作要准备?
重写小程序Page、Component函数
Request方法封装
Router路由封装
Less的使用
Util的封装
为什么要重写Page、Component函数?
准备开发页面之前你是否经历过这样...
import store from "../utils/store"; import util from "../utils/util"; import fetch from "../utils/fetch"; import config from "../utils/config"; Page ({ // ... })
以下办法可能会解决这些问题 并且相当舒适
创建Init.js 并引入到app.js里, 像这样:
require('./utils/Init.js'); App({ onLaunch: function () {} })
重写Page、Component函数
函数重写思考:小程序属于单页面应用,全局的页面组件注册全依靠Page、Component函数,实际上就是调用了一个函数 传入了一个对象,那我们能不能在函数调用前,对参数做一些小动作呢?
先来试验一下
编辑Init.js
// 函数劫持 重写注册函数 let originPage = Page; Page = (opt) => { // 在传入Page函数的参数中 添加一个util对象 opt.util = { test () { return 1; } } return originPage(opt); }
在页面onLoad方法中测试一下
Page({ data: { }, onLoad: function () { console.log(this.util.test()) } })
结果输出如下
运行成功!接下来你应该懂我的意思 塞他!
编辑Init.js
import _store from "./store"; import _util from "./util"; import _fetch from "./fetch"; let originPage = Page; Page = (opt) => { // 把创建好的工具类引入opt参数内 opt = { ...opt, _store, _util, _fetch } return originPage(opt); }
然后在页面中输出一下this关键字
注意!Component函数中如果也这么写 组件实例中并不会出现添加的对象 像这样
// Init.js import _store from "./store"; import _util from "./util"; import _fetch from "./fetch"; let originComponent = Component; Component = (opt) => { opt.util = { test() { return 1 } } return originComponent(opt); } ------------ // components/img/index.js Component({ attached () { this.test(); }, methods: { test() { console.log(this.util) } } })
但这就不代表我没有办法 
编辑init.js 重写component部分
Component = (opt) => { // Component函数的options无法直接插入参数 只能在某个生命周期函数被调用时动态赋值 let originAttached = opt.attached || function () {}; opt.attached = function(e) { this.util = { a() { return 1; } }; return originAttached.apply(this); } return originComponent(opt) }
最终把下面的各种工具类添加上之后 简单写个请求、跳转 大概就是这个样子
Page({ data: { }, onLoad: function ({ goodId }) { this._fetch({ url: "getGoods", data: { goodId } }).then(res => { if (res.length) { this._router.go("detail", { firstGoodsId: res[0].id }) } }) } })

以下是工作中各种用到的封装
Request方法封装
wx.request方法封装点:请求状态、错误统一处理,以当前上下文可控制页面所有需要请求状态的组件
Fetch.js
const host = { Dev: "http://test.com" } const api = { getUserInfo: "...", getGoods: "..." } export default function ({ url, data, showLoading = false }) { let self = this; changeFetchState(self, true); showLoading && wx.showLoading({ title: showLoading }) return new Promise((resolve, reject) => { const options = { url: host.Dev + api[url], method: "POST", header: { "content-type": "application/json" }, data, success: ({ data }) => { resolve(data.data, data); }, fail: err => { reject(err); }, complete() { changeFetchState(self, false); showLoading && wx.hideLoading(); } }; wx.request(options); }) } // 以当前作用域调用,可控制页面需要请求状态的组件 function changeFetchState (self, state) { self && self.setData({ _fetchState: state }); }
Router路由封装
规范路由管理、传参,以{key:value}形式定义路由,重新封装路由跳转方法,方便调用。
Router.js
// 路由定义 const routePath = { "index": "/pages/index/index", "detail": "/pages/detail/index", "service": "/pages/service/index" }; // tabbar名单 特殊处理 const tabbar = ['index', 'service'] const Router = { // 参数转换 parse: function (data) { if (!data) return ''; let tempArr = []; for (let key in data) { tempArr.push(`${key}=${encodeURIComponent(data[key])`); } return '?' + tempArr.join('&'); }, go: function (path = 'index', params = null, duration = 0) { setTimeout(() => { const isTabbar = tabbar.indexOf(path) == -1; // 如果是tabbar用switchTab方法切换 wx[isTabbar ? 'navigateTo' : 'switchTab']({ url: routePath[path] + this.parse(params), }) }, duration * 1000); }, goBack: function (delta = 1, duration) { setTimeout(() => { wx.navigateBack({ delta }) }, duration * 1000) } } export default Router;
Less的使用
首先全局安装less插件 npm install less -g
Util通用类封装
自己常用的工具大概有这几种:Storage存储、页面地址取参、获取当前上下文等等,通常Util一下也想不全都是在开发中边用边写,以下几个为例子。
Util.js
// Storage相关 function getStore (name1, name2) { if (!name1) return false; let baseStore = wx.getStorageSync(name1); if (!baseStore) return false; return name2 ? (baseStore[name2] || '') : baseStore; } function setStore (name, value) { if (!name) return false; return wx.setStorageSync(name, value); } function setStoreChild (name1, name2, value) { if (!name1 || !name2) return false; let baseStore = getStore(name1) || {}; baseStore[name2] = value; return setStore(name1, baseStore); } /** * 获取数据类型 * @param value * @returns {*} */ function getValueType(value) { if (typeof value === 'number') return Number; if (typeof value === 'string') return String; if (typeof value === 'boolean') return Boolean; if (value instanceof Object && !value instanceof Array) return Object; if (value instanceof Array) return Array; return null; } /** * 获取当前页面上下文 * @returns {*} */ function getPageContext() { var pages = getCurrentPages(); return pages[pages.length - 1]; } /** * 获取元素 * @param classItem */ function $select(className, cb) { const query = wx.createSelectorQuery().in(this) query.select(className).boundingClientRect() query.selectViewport().scrollOffset() query.exec(function (res) { cb(className.substr('0') === '#' ? res[0] : res); }) } module.exports = { getStore, setStore, setStoreChild, getValueType, getPageContext, $select }
作者: