磨刀不誤砍柴工,在開發之前做好準備工作可以大大提升開發效率、減少冗餘程式碼,這篇文章結合自己做過的幾個小程式的經驗做一個總結。
著手開發小程式前都有哪些工作要準備?
- 重寫小程式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
}
複製程式碼