磨刀不误砍柴工,在开发之前做好准备工作可以大大提升开发效率、减少冗余代码,这篇文章结合自己做过的几个小程序的经验做一个总结【demo地址】。
相关参考 vant-weapp、武装你的小程序——开发流程指南
着手开发小程序前都有哪些工作要准备?
重写小程序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" },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) {
set Timeout(() => {
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) {
set Timeout(() => {
wx.navigateBack({ delta })
},duration * 1000)
}
}
export default Router;
复制代码
Less的使用
首先全局安装less插件 npm install less -g
WebStorm -> Preferences
Tools -> File Watchers -> 新建监听文件选择Less -> 【重点】设置Output文件格式为wxss
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 set Store (name,value) {
if (!name) return false ;
return wx.setStorageSync(name,value);
}
function set StoreChild (name1,name2,value) {
if (!name1 || !name2) return false ;
let baseStore = getStore(name1) || {};
baseStore[name2] = value;
return set Store(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,set Store,set StoreChild,getValueType,getPageContext,$select
}
复制代码