摘要: 微信小程序開發技巧。

  • 作者:xiaoyueyue
  • 原文:2019,幫助你更好的開發小程序

Fundebug經授權轉載,版權歸原作者所有。

前言

原生開發小程序有了兩個項目,在原生開發小程序經驗技巧方面有一些自己的總結,此篇文章做原創分享!

本文適合老手查看,新手請參閱官方文檔,同步至github。

1. 發布訂閱處理複雜邏輯

支持先訂閱後發布,以及先發布後訂閱

  • 方法源碼

var Event = (function() {
var clientList = {},
pub,
sub,
remove;
?
var cached = {};
?
sub = function(key, fn) {
if (!clientList[key]) {
clientList[key] = [];
}
// 使用緩存執行的訂閱不用多次調用執行
cached[key + "time"] == undefined ? clientList[key].push(fn) : "";
if (cached[key] instanceof Array && cached[key].length > 0) {
//說明有緩存的 可以執行
fn.apply(null, cached[key]);
cached[key + "time"] = 1;
}
};
pub = function() {
var key = Array.prototype.shift.call(arguments),
fns = clientList[key];
if (!fns || fns.length === 0) {
//初始默認緩存
cached[key] = Array.prototype.slice.call(arguments, 0);
return false;
}
?
for (var i = 0, fn; (fn = fns[i++]); ) {
// 再次發布更新緩存中的 data 參數
cached[key + "time"] != undefined
? (cached[key] = Array.prototype.slice.call(arguments, 0))
: "";
fn.apply(this, arguments);
}
};
remove = function(key, fn) {
var fns = clientList[key];
// 緩存訂閱一併刪除
var cachedFn = cached[key];
if (!fns && !cachedFn) {
return false;
}
if (!fn) {
fns && (fns.length = 0);
cachedFn && (cachedFn.length = 0);
} else {
if (cachedFn) {
for (var m = cachedFn.length - 1; m >= 0; m--) {
var _fn_temp = cachedFn[m];
if (_fn_temp === fn) {
cachedFn.splice(m, 1);
}
}
}
for (var n = fns.length - 1; n >= 0; n--) {
var _fn = fns[n];
if (_fn === fn) {
fns.splice(n, 1);
}
}
}
};
return {
pub: pub,
sub: sub,
remove: remove
};
})();

  • 全局掛載使用

// app.js
App({
onLaunch: function(e) {
// 註冊 storage,這是第二條
wx.Storage = Storage;
// 註冊發布訂閱模式
wx.yue = Event;
}
});

  • 使用實例

// 添加收貨地址頁面訂閱
onLoad: function (options) {
wx.yue.sub("addAddress", function (data) {
y.setData({
addAddress: data
})
})
}
/**
* 生命週期函數--監聽頁面隱藏
*/
onHide: function () {
// 取消多餘的事件訂閱
wx.Storage.removeItem("addAddress");
},
onUnload: function () {
// 取消多餘的事件訂閱
wx.yue.remove("addAddress");
}
// 傳遞地址頁面獲取好數據傳遞
wx.yue.pub("addAddress", data.info);
// 補充跳轉返回

注意:使用完成數據後要注意卸載,在頁面被關閉時操作

2. Storage

storage 管理封裝,用法和上面的一致,掛載在全局對象上調用,使用介紹就不列了

const Storage = {
setItem: function(key, obj, callback) {
wx.setStorage({
key: key,
data: obj,
success: callback || function() {}
});
},
getItem: function(key) {
return wx.getStorageSync(key);
},
removeItem: function(key) {
wx.removeStorage({
key: key
});
}
};

3. filter 計算屬性

小程序也有計算屬性,你知道嗎?

// 文件名稱為 :filter.wxs
// 不支持es6,Date,Number
function filterOrderTitleName(status) {
switch (status) {
case "1":
return "待支付";
case "2":
return "待配送";
case "3":
return "配送中";
case "4":
return "已完成";
}
}
function filterPrice(str) {
// 四捨五入 格式化數字
// toFix(8440.55,1) => 8440.6
var times = Math.pow(10, 2);
var roundNum = Math.round(str * times) / times;
return roundNum.toFixed(2);
}
?
module.exports = {
filterOrderTitleName: filterOrderTitleName,
filterPrice: filterPrice
};

  • 使用實例,過濾處理打折後的金額小數位數

// 當前文件名:shoppingCart.wxml
// wxs 文件頂部導入
<wxs src="../../filter/filter.wxs" module="filter"></wxs>
<view class=offerPrice nowrap>¥{{filter.filterPrice(item.plus*100*item.price/1000)}}
<image class=youhuiBox src="../../assets/youhuiBox.png">
<view class=youhuiText>會員{{item.dazhe}}折</view>
</image>
</view>

4. flex Style

分享我常使用的自定義的一套 flex 樣式,快速實現佈局

/* -------------------------------------------------------------flex------------------------------------------------------- */
?
.center {
display: flex;
align-items: center;
justify-content: center;
}
?
/* 單行水平垂直 */
?
.oneLineCenter {
display: flex;
display: -webkit-flex;
justify-content: center;
align-items: center;
}
?
/* 單行垂直居中,水平向左 */
?
.oneLineStart {
display: flex;
display: -webkit-flex;
justify-content: flex-start;
align-items: center;
}
?
/* 單行垂直居中,水平向右 */
?
.oneLineEnd {
display: flex;
display: -webkit-flex;
justify-content: flex-end;
align-items: center;
}
?
/* 單行垂直居中,水平保持間距 */
?
.oneLineAround {
display: flex;
display: -webkit-flex;
justify-content: space-around;
align-items: center;
}
?
/* 單行垂直居中,兩端對齊 */
?
.oneLineBetween {
display: flex;
display: -webkit-flex;
justify-content: space-between;
align-items: center;
}
?
/* 超過單行設置的最大寬度,允許換行顯示 */
?
.f-wrap {
flex-wrap: wrap;
}
?
/* 多軸線方向,一般配合 wrap 使用 */
?
/* 寬度不足換行後,垂直方向靠上排列 */
?
.mulitLineStart {
display: flex;
display: -webkit-flex;
flex-wrap: wrap;
align-content: flex-start;
}
?
/* 寬度不足換行後,垂直方向居中排列 */
?
.mulitLineCenter {
display: flex;
display: -webkit-flex;
flex-wrap: wrap;
align-content: center;
}
?
/* 寬度不足換行後,垂直方向靠下排列 */
?
.mulitLineEnd {
display: flex;
display: -webkit-flex;
flex-wrap: wrap;
align-content: flex-end;
}
?
/* 寬度不足換行後,垂直方向上保持間隔排列 */
?
.mulitLineAround {
display: flex;
display: -webkit-flex;
flex-wrap: wrap;
align-content: space-around;
}
?
/* 寬度不足換行後,垂直方向上靠兩側最頂開始間隔排列 */
?
.mulitLineBetween {
display: flex;
display: -webkit-flex;
flex-wrap: wrap;
align-content: space-between;
}
?
/* 縱軸變主軸,垂直靠上,水平居中 */
?
.columnStart {
display: flex;
display: -webkit-flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
}
?
/* 縱軸變主軸,垂直靠下,水平居中 */
?
.columnEnd {
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: center;
}
?
/* 縱軸變主軸,垂直居中,水平居中 */
?
.columnCenter {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
?
/* 縱軸變主軸,垂直間隔排列,水平居中 */
?
.columnAround {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
?
/* 縱軸變主軸,垂直上下兩側按間隔排列,水平居中 */
?
.columnBetween {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
}
/* 縱軸變主軸,垂直上下兩側按間隔排列,水平靠左 */
?
.columnBetweenStart {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-start;
}
/* 縱軸變主軸,垂直上下兩側按間隔排列,水平靠右 */
?
.columnBetweenEnd {
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: flex-end;
}

5. async await

使用runtime.js,使小程序支持 async await,拷貝文件至項目目錄下。

  • 實例用法

const regeneratorRuntime = require("../../utils/runtime.js");
Page({
shopCartInit() {
var y = this;
// 拿到商鋪位置信息再去渲染購物計算當前的address符合不符合規定
var showCartList = function() {
// 顯示全局的地址信息
var globalAddress = wx.Storage.getItem("globalAddress");
if (globalAddress) {
y.setData({
globalAddress: globalAddress,
addr_id: globalAddress.id
});
y.calculateDistance(
qqmapsdk,
globalAddress.latitude,
globalAddress.longitude
);
} else {
y.setData({
globalAddress: {}
});
}
};
// await 等待獲取商鋪位置信息
async function getShopPosTionMsg() {
await util.promiseRequest(api.merchant_addr, {}).then(res => {
var data = res.data.response_data.lists[0];
y.setData({
shop_lat: data.latitude, // 商鋪緯度
shop_lng: data.longitude, // 商鋪經度
peiSongFanWei: data.scope // 配送範圍
});
});
}
?
async function initData() {
await getShopPosTionMsg();
await showCartList();
util.closeLoading();
y.setData({
loading: false
});
}
// 開始執行
initData();
}
});

6. addKey Api

使用自定義屬性的方法輔助完成業務邏輯

/**
* 為數組添加新的自定義鍵值以及過濾每個子項的方法
*
* @param {*} arr
* @param {*} obj { isShow:false,isStar:false}
* @param {*} filterFn
* @returns
*/
function addKey(arr, obj, filterFn) {
var temp = arr.forEach((v, index, arr) => {
typeof filterFn === "function" ? filterFn(v, index) : "";
for (var key in obj) {
v[key] = obj[key];
}
});
return temp;
}

  • 使用實例

util.addKey(data, { y_isCheck: false }, function(v) {
v.dazhe = Number(v.plus);
});
this.setData({
cartList: data
});

7. 自定義 headerBar

後續分享...

參考

  • 小程序使用 async await

生態圈

  • ColorUI 鮮亮的高飽和色彩,專註視覺的小程序組件庫
  • taro 多端統一開發框架, React 語法

關於Fundebug

Fundebug專註於JavaScript、微信小程序、微信小遊戲、支付寶小程序、React Native、Node.js和Java線上應用實時BUG監控。 自從2016年雙十一正式上線,Fundebug累計處理了10億+錯誤事件,付費客戶有Google、360、金山軟體、百姓網等眾多品牌企業。歡迎大家免費試用!

推薦閱讀:

相關文章