前言
原生
开发小程序有了两个项目,在原生开发小程序经验技巧方面有一些自己的总结,此篇文章做原创分享!
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) { if (!Array.isArray(arr)) { throw new Error("第一个参数必须为数组类型") } let 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
后续分享...
作者: xiaoyueyue