1. 前言
在進行小程式開發過程中,涉及一個業務需求:新人領券。
業務需求具體:
- 在首頁中添加有3種不同的彈窗: 立即領取A, 現有優惠券清單B,登陸/注冊C ,和提示領券的浮窗A
- 為了不影響使用者體驗,彈窗A/C都要求一周内最多隻能彈出3次,且相鄰兩次彈窗的時間間隔必須超過3小時,彈窗B要求一周内最多隻能彈出1次
- 在使用者未登入/未領取到目标優惠券之前,将一直顯示浮窗
- 此次領取失敗時(等到要關閉遮蓋層時進行判斷是否此次領取成功)要通知首頁,進行自動添加小程式收藏提示add-tip,并于5s後自動消失
- 當使用者從我的頁面登入後再進來首頁時,需重新執行一遍領券邏輯。判斷是否彈出
2. 實作思路
- 步驟1:初始化頁面中各彈窗以及浮窗的顯示,(目标:為了不讓上一次調用時顯示的布局影響到這一次的顯示)
- 步驟2:檢查是否登陸(已登陸 -> 步驟3, 未登入 -> 步驟4)
- 步驟3:檢查該使用者是否有領過新人券
- 步驟4:是否彈窗
- 判斷彈出什麼類型的彈窗(根據步驟1得到的是否登入以及步驟3得到的使用者是否領過新人券決定),
- 是否彈出彈窗(根據現在距離上一次彈窗時間以及總彈窗次數判斷),
- 彈窗失敗回調:顯示浮窗(根據是否領過目标優惠券判斷)
- 步驟5:檢查是否領取成功,通知首頁自動添加小程式收藏提示進行顯示
3. 頁面布局
view.wrapper >
<view class="counpon_fornew_panel" catchtap="emptyFn">
<view class="showPopA" wx:if="{{showPopA}}">
<view class="showPopA" wx:if="{{!showSuccessPopA}}">
彈窗A:已領取
優惠券已放入我的優惠券清單
</view>
<view class="showSuccessPopA" wx:else>
<button bindtap="collectCoupon">點選領取(進行綁定券操作)</button>
</view>
</view>
<view class="showPopB" wx:if="{{showPopB}}">
彈窗B:展示券清單前3張和券總數
<button bindtap="navigateFn" data-action="/pages/web/web?key=coupon">點選檢視更多(跳轉到官網優惠券清單)</button>
</view>
<view class="showPopC" wx:if="{{showPopC}}">
<button open-type="getUserInfo" class='login_btn' bindgetuserinfo='userlogin'>
彈窗C:點選登入/注冊
</button>
</view>
</view>
<view class="showFloatWindowA" wx:if="{{showFloatWindowA}}">
<button bindtap="collectCoupon">浮窗A:點選領取(進行綁定券操作)</button>
</view>
4. 部分代碼
4.1 整體邏輯
// 初始化新人領券
initCouponForNewUser: function() {
// 初始化頁面中各彈窗以及浮窗的顯示
this.initCouponWrapper();
// 檢查是否登入
app.globalData.userInfoPromise.then(() => {
console.log('登入成功....');
this.setData({
isLogin: true
});
// 判斷是否有領過新人券,如領過,加載使用者有效優惠券清單,如未領過,加載新人券具體詳情
this.loadCouponUserAvailAble().then(()=>{
// 判斷是否彈出新人領券彈窗
this.loadCouponForNewUser();
})
},(err) => {
console.log('登入失敗....');
this.setData({
isLogin:false
});
// 擷取新人券資訊
this.getTargetCouponPromise().then(()=>{
// 判斷是否彈出新人領券彈窗
this.loadCouponForNewUser();
})
});
},
// 初始化頁面中各彈窗以及浮窗的顯示
initCouponWrapper(){
this.setData({
isShowGetCouponWrapper: false,
showPopA: false,
showPopB: false,
showPopC: false,
showFloatWindowA: false,
isShowAddTipWrapper: false
});
},
4.2 判斷彈出什麼類型的彈窗
由于未登入,未領取,已領取三種狀态下展示的彈窗不同,我們這裡根據條件作出判斷:
- 當有登入且有領過新人券:彈出使用者優惠券清單彈窗
- 當有登入但無領過新人券:彈出領新人券彈窗
- 當無登入:彈出登入/注冊彈窗
// 是否顯示新人領券
loadCouponForNewUser: function(){
this.couponpopA = wx.getStorageSync('M60_COUPONPOP_A');
this.couponpopB = wx.getStorageSync('M60_COUPONPOP_B');
this.couponpopC = wx.getStorageSync('M60_COUPONPOP_C');
this.now = Date.now();
// 有登陸并且領取過
if (this.data.isLogin && this.data.hasCouponForNew) {
this.showCouponPop(this.couponpopB, "B", 1);
return;
}
// 有登陸沒有領取過
if (this.data.isLogin && !this.data.hasCouponForNew) {
this.showCouponPop(this.couponpopA, "A", 3);
return;
}
this.showCouponPop(this.couponpopC, "C", 3);
},
4.3 判斷是否彈出彈窗
由于需根據上一次彈窗的時間,以及最近一周彈窗的次數,來判斷是否彈窗,是以我們每一次彈窗時,就把彈窗時間記錄在storage中,以數組的形式儲存(友善記錄多個資料),彈窗緩存長度不會超過(即<=)時間段内最大彈出次數:
當該彈窗沒彈出過:即彈窗緩存長度為0(空字元串長度也為0),設定緩存記錄為空數組 -> 彈出,并記錄下目前彈出時間
當該彈窗已彈出過:取記錄中第一次彈窗時間與目前時間作比較,如若 目前時間- 第一次彈窗時間 > 7 天,就清除緩存記錄,設為空數組 -> 彈出, 并記錄下目前彈出時間,否則:
當彈窗緩存長度 == 時間段内最大彈出次數:執行彈出失敗回調:顯示浮窗
當彈窗緩存長度 < 時間段内最大彈出次數:取記錄中最後一次彈窗時間與目前時間作比較,如若 目前時間- 最後一次彈窗時間 > 3 小時 -> 彈出, 并記錄下目前彈出時間,否則執行彈出失敗回調:顯示浮窗
showCouponPop: function(couponpopType, strType, maxPopTime) {
let now = this.now;
// 第一次彈窗
if (couponpopType.length == 0) {
couponpopType = [];
this.showCouponPopFn(couponpopType, strType);
return;
}
if (couponpopType.length > maxPopTime) {
return;
}
let firstPop = couponpopType[0];
// 超過7天清除彈窗記錄
if (now - firstPop >= 1000 * 60 * 60 * 24 * 7) {
couponpopType = [];
this.showCouponPopFn(couponpopType, strType);
return;
}
// 已經彈出最大允許次數并且沒有超過7天
if (couponpopType.length == maxPopTime) {
this.couponPopFail(strType);
return;
}
let lastPop = couponpopType[couponpopType.length - 1];
// 距離最近一次彈窗時間> 3小時
if (now - lastPop >= 1000 * 60 * 60 * 3) {
this.showCouponPopFn(couponpopType, strType);
return;
}
this.couponPopFail(strType);
},
4.4 執行彈出彈窗
顯示遮蓋層,顯示相應的彈窗類型,記錄下目前彈窗時間(由于在判斷是否彈窗的push到數組中)
/**
*
* @param {Array} couponpopType
* @param {String} strType
*/
showCouponPopFn: function(couponpopType, strType){
let storagePop; // 彈窗對應本地storage_key
let now = this.now; // 目前時間
switch(strType){
case 'A': {
// 先去擷取新人券的資訊,再顯示彈窗
this.setData({
showPopA: true,
showPopC: false
})
storagePop = 'M60_COUPONPOP_A';
break;
}
case 'B': {
// 先去擷取有效優惠券清單和總券數,再顯示彈窗
if(this.data.couponUserAvailAbleSize > 0){
this.setData({
showPopB: true,
showPopC: false
})
storagePop = 'M60_COUPONPOP_B';
}else{
this.initCouponWrapper();
return;
}
break;
}
case 'C': {
this.setData({
showPopC: true
})
storagePop = 'M60_COUPONPOP_C';
break;
}
}
this.showGetCouponWrapper();
// 記錄目前彈窗時間
couponpopType.push(now);
console.log("更改後的彈窗記錄時間", couponpopType)
wx.setStorageSync(storagePop, couponpopType);
console.log("更改後的記憶體",wx.getStorageSync(storagePop))
},
4.5 通知首頁顯示收藏提示
在領取優惠券方法中添加一個字段:collectSuccess,Boolean類型,判斷是否領取成功
當關閉遮蓋層時,根據是否領券成功向首頁傳遞不同資訊:
預設展示首頁的add-tip,當此次領取成功後,不展示首頁的add-tip,而是展示遮蓋層式的收藏提示:
- 首先根據 collectSuccess 字段判斷是否領券成功
- 如若領券成功,再根據目前是否展示優惠券清單判斷是此次領券成功還是上次領券成功,(因為當領券成功後在退出小程式前collectSuccess字段一直為true, 此時需判斷是此次領券成功還是上次領券成功,如果是上次領券成功 = 即this.data.showPopB 顯示優惠券清單為true,否則則為此次領取成功),
- 如若為此次領取成功,顯示遮蓋層式的收藏提示,不關閉遮蓋層(因為從頁面結構中可以看到遮蓋層式的收藏提示包含在遮蓋層中)
- 若為上次領取成功,關閉遮蓋層,不顯示收藏提示
- 如若領券未成功,關閉遮蓋層
- 如若領券成功,再根據目前是否展示優惠券清單判斷是此次領券成功還是上次領券成功,(因為當領券成功後在退出小程式前collectSuccess字段一直為true, 此時需判斷是此次領券成功還是上次領券成功,如果是上次領券成功 = 即this.data.showPopB 顯示優惠券清單為true,否則則為此次領取成功),
- 當不是此次領券成功時,才通知首頁開始進行為時5s的自動添加收藏提示的顯示
// 關閉遮蓋層時,根據是否領券成功向首頁傳遞不同資訊
closedGetCouponWrapper() {
if(this.data.collectSuccess){ // 當領券成功後,不展示首頁的add-tip,而是展示遮蓋層式的收藏提示
// 當遮蓋層式的收藏提示沒有顯示并且不是展示優惠券清單時,顯示收藏提示,不關閉彈出層
if(!this.data.isShowAddTipWrapper && !this.data.showPopB){
this.setData({
isShowAddTipWrapper: true,
showPopA: false
})
}else{
// 關閉收藏提示,關閉彈出層
this.setData({
isShowAddTipWrapper: false,
isShowGetCouponWrapper: false
})
wx.showTabBar({});
}
}
// 有領過券了,就不顯示浮窗了
else{
this.setData({
isShowGetCouponWrapper: false
})
wx.showTabBar({})
if(!this.data.hasCouponForNew){
this.setData({
showFloatWindowA: true
})
}
this.triggerEvent('showIndexAddTip', true);
}
},
4.6 當使用者登入狀态改變時,需重新執行一遍是否彈窗邏輯
當使用者從我的頁面登入後再進來首頁時,這裡從首頁傳一個properties:isLogin 字段來判斷是否登入,當為登入時,即重新執行一遍業務邏輯,判斷是否彈出
properties: {
isLogin:{
type: Boolean,
value: false,
observer(newVal, oldVal){
if(newVal){
this.initCouponForNewUser();
}
}
}
},
5. 總結
- 在決定是否展示彈窗時,記得先清除先前的展示記錄
- 可根據具體場景添加編譯模式,能更快速定位到錯誤
如果文章對你有幫助,麻煩點贊哦,一起走花路吧~
