We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
原生开发小程序有了两个项目,在原生开发小程序经验技巧方面有一些自己的总结,此篇文章做原创分享!
原生
本文适合老手查看,新手请参阅官方文档,同步至github。
支持先订阅后发布,以及先发布后订阅
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); // 补充跳转返回
注意:使用完成数据后要注意卸载,在页面被关闭时操作
storage 管理封装,用法和上面的一致,挂载在全局对象上调用,使用介绍就不列了
const Storage = { // 第一个 key 参数可以省略,直接传递 obj 对象,支持 callback setItem: function(key, obj, callback) { const getType = function(a) { var typeArray = Object.prototype.toString.call(a).split(" "); return typeArray[1].slice(0, -1); }; var firstParamType = getType(arguments[0]); if (firstParamType === "Object") { var keyArrayLength = Object.keys(arguments[0]).length; var index = 0; for (var keyName in arguments[0]) { index++; wx.setStorage({ key: keyName, data: arguments[0][keyName], success: index == keyArrayLength ? arguments[1] : function() {} }); } } if (firstParamType === "String") { wx.setStorage({ key: key, data: obj, success: callback || function() {} }); } }, getItem: function(key) { return wx.getStorageSync(key); }, removeItem: function(key) { wx.removeStorage({ key: key }); } };
wx.Storage.setItem( { class_pid: that.data.class_pid, class_id: that.data.class_id, is_import: that.data.is_import, shop_type: 1 }, function() { console.log("Storage 已设置完毕!"); } );
小程序也有计算属性,你知道吗?
// 文件名称为 :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>
分享我常使用的自定义的一套 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; }
使用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(); } });
使用自定义属性的方法辅助完成业务逻辑,已发布至 addKey
/** * 为数组添加新的自定义键值以及过滤每个子项的方法 * * @param {*} arr * @param {*} obj { isShow:false,isStar:false} * @param {*} filterFn * @returns */ function addKey(sourceArray, extendObj, filterFn) { var getType = function(a) { var typeArray = Object.prototype.toString.call(a).split(" "); return typeArray[1].slice(0, -1); }; var secondParamType = getType(arguments[1]); if (!getType(sourceArray) == "Array") { throw new Error("The first argument must be an array type"); } if (secondParamType === "Object") { return sourceArray.forEach((v, index, sourceArray) => { for (var key in extendObj) { v[key] = extendObj[key]; } typeof filterFn === "function" ? filterFn(v, index, sourceArray) : ""; }); } else if (secondParamType === "Function") { return sourceArray.forEach((v, index, sourceArray) => { arguments[1](v, index, sourceArray); }); } else { return sourceArray; } }
util.addKey(data, { y_isCheck: false }, function(v) { v.dazhe = Number(v.plus); }); this.setData({ cartList: data });
组件化解构项目元件,提高开发效率,可参照官方介绍起步 !
这里介绍一个自定义的跑马灯的轮播图组件实例
Carousel
index
│ ├───component │ └───Carousel │ Carousel.js │ Carousel.json │ Carousel.wxml │ Carousel.wxss │ ├───filter │ filter.wxs │ ├───pages │ └───index │ index.js │ index.json │ index.wxml │ index.wxss │ └───utils api.js runtime.js util.js
props
bannerList
swiperHeight
dotWidthAndHeight
dotTop
** 最终在 index.wxml 的实际使用**
<view class="Carousel"> <Carousel swiperHeight="260rpx" bannerList="{{bannerList}}" dotWidthAndHeight="12rpx" dotTop="-20rpx" ></Carousel> </view>
{ "component": true }
<view class="Carousel_wrap"> <!-- 图片区 --> <swiper current="{{swiperCurrentIndex}}" circular="true" bindchange="swiperChange" indicator-dots="{{indicatorDots}}" autoplay="true" interval="5000" duration="1000" style="height:{{swiperHeight}}" > <swiper-item wx:for="{{bannerList}}" bindtap="toHref" wx:key="{{index}}" bindtap="toHref" data-type="{{item.type}}" data-id="{{item.goods_id}}" data-content="{{item.content}}" data-link="{{item.link}}" > <image src="{{item.img_url}}" class="slide-image" /> </swiper-item> </swiper> <!-- 关联按钮 --> <view class="boxCell" style="top:{{dotTop}}"> <block wx:for="{{bannerList.length > 1 ? bannerList:[]}}" wx:for-index="index" wx:key="{{item.banner}}" > <view id="{{index}}" class="dot {{index === swiperCurrentIndex ? 'dot_active':''}}" style="width:{{dotWidthAndHeight}},height:{{dotWidthAndHeight}}" bindtap="selectCarouselByIndex" /> </block> </view> </view>
Component({ /** * 组件的属性列表 必须 */ properties: { bannerList: { // 属性名 type: Array, // 类型(必填),目前接受的类型包括:String, Number, Boolean, Object, Array, null(表示任意类型) value: [], // 属性初始值(可选),如果未指定则会根据类型选择一个 observer: function(newVal, oldVal) {} // 属性被改变时执行的函数(可选),也可以写成在methods段中定义的方法名字符串, 如:'_propertyChange' }, dotWidthAndHeight: String, swiperHeight: String, // swiper 高度 dotTop: String // 小点距离顶部高度 }, /** * 组件的初始数据 */ data: { swiperCurrentIndex: 0, indicatorDots: false // 自定义轮播按钮 }, /** * 组件的方法列表 */ methods: { swiperChange: function(e) { var source = e.detail.source; if (source === "autoplay" || source === "touch") { this.setData({ swiperCurrentIndex: e.detail.current }); } }, selectCarouselByIndex: function(e) { this.setData({ swiperCurrentIndex: Number(e.currentTarget.id) }); }, // 轮播图跳转至内部页面 toHref(e) { const data = e.currentTarget.dataset; // type = 2,根据 goods_id 展示商品详情 // type = 3, 展示富文本的活动详情页面 if (data.type === "2") { wx.navigateTo({ url: `../sort_detail/sort_detail?id=${data.id}` }); } else if (data.type === "3") { wx.yue.pub("renderData", data.content); wx.navigateTo({ url: `../activity_detail/activity_detail` }); } } } });
后续分享...
The text was updated successfully, but these errors were encountered:
No branches or pull requests
前言
原生
开发小程序有了两个项目,在原生开发小程序经验技巧方面有一些自己的总结,此篇文章做原创分享!本文适合老手查看,新手请参阅官方文档,同步至github。
1.发布订阅处理复杂逻辑
2.Storage
例子
3.filter 计算属性
4.flex Style
5.async await
使用runtime.js,使小程序支持 async await,拷贝文件至项目目录下。
6.addKey Api
7. 组件化复用开发实践
这里介绍一个自定义的跑马灯的轮播图组件实例
(1) 第一步,查看目录结构划分,主要为
Carousel
组件 在index
页面的使用(2) 第二步我们分析看如何使用,设计 组件需要的
props
bannerList
swiperHeight
dotWidthAndHeight
dotTop
** 最终在 index.wxml 的实际使用**
(3).业务代码编写
开启自定义组件模式
更多
8. 自定义 headerBar
参考
生态圈
The text was updated successfully, but these errors were encountered: