磨刀不误砍柴工,在开发之前做好准备工作可以大大提升开发效率、减少冗余代码,这篇文章结合自己做过的几个小程序的经验做一个总结【demo地址】。
着手开发小程序前都有哪些工作要准备?
- 重写小程序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
}
复制代码