開(kāi)頭
- 最近寫(xiě)小程序?qū)懮习a了,業(yè)務(wù)上需要實(shí)現(xiàn)一個(gè)倒計(jì)時(shí)的功能,考慮到可拓展以及使用方便,便將其封裝成組件(寫(xiě)習(xí)慣了JSX不得不吐槽小程序自定義組件的繁瑣)
需求
- 可配置倒計(jì)時(shí)的時(shí)間
- 倒計(jì)時(shí)結(jié)束后執(zhí)行事件
- 可配置倒計(jì)時(shí)時(shí)間的格式
步驟
- 先定義自定義組件的
properties
,這里有兩個(gè)父組件傳給該倒計(jì)時(shí)組件的參數(shù)target
倒計(jì)時(shí)的時(shí)間,format
倒計(jì)時(shí)時(shí)間的格式
properties: {
target: {
type: String,
},
format: {
type: Function,
default: null
}
},
- 定義組件生命周期函數(shù)
lifetimes: {
attached() {
//組件創(chuàng)建時(shí)
this.setData({
lastTime: this.initTime(this.properties).lastTime, //根據(jù) target 初始化組件的lastTime屬性
}, () => {
//開(kāi)啟定時(shí)器
this.tick();
//判斷是否有format屬性 如果設(shè)置按照自定義format處理頁(yè)面上顯示的時(shí)間 沒(méi)有設(shè)置按照默認(rèn)的格式處理
if (typeof this.properties.format === 'object') {
this.defaultFormat(this.data.lastTime)
}
})
},
detached() {
//組件銷(xiāo)毀時(shí)清除定時(shí)器 防止爆棧
clearTimeout(timer);
},
},
微信小程序自定義組件的生命周期指的是指的是組件自身的一些函數(shù)兵多,這些函數(shù)在特殊的時(shí)間點(diǎn)或遇到一些特殊的框架事件時(shí)被自動(dòng)觸發(fā)旦万。其中田晚,最重要的生命周期是
created
attached
detached
稀余,包含一個(gè)組件實(shí)例生命流程的最主要時(shí)間點(diǎn)邦邦。具體微信自定義組件學(xué)習(xí)參考官方文檔
- 定義組件自身的狀態(tài)
/**
* 組件的初始數(shù)據(jù)
*/
data: {
d: 0, //天
h: 0, //時(shí)
m: 0, //分
s: 0, //秒
result: '', //自定義格式返回頁(yè)面顯示結(jié)果
lastTime:'' //倒計(jì)時(shí)的時(shí)間錯(cuò)
},
- 組件自身的方法
methods: {
//默認(rèn)處理時(shí)間格式
defaultFormat: function(time) {
const day = 24 * 60 * 60 * 1000
const hours = 60 * 60 * 1000;
const minutes = 60 * 1000;
const d = Math.floor(time / day);
const h = Math.floor((time - d * day) / hours);
const m = Math.floor((time - d * day - h * hours) / minutes);
const s = Math.floor((time - d * day - h * hours - m * minutes) / 1000);
this.setData({
d,
h,
m,
s
})
},
//定時(shí)事件
tick: function() {
let {
lastTime
} = this.data;
timer = setTimeout(() => {
if (lastTime < interval) {
clearTimeout(timer);
this.setData({
lastTime: 0,
result: ''
},
() => {
this.defaultFormat(lastTime)
if (this.onEnd) {
this.onEnd();
}
}
);
} else {
lastTime -= interval;
this.setData({
lastTime,
result: this.properties.format ? this.properties.format(lastTime) : ''
},
() => {
this.defaultFormat(lastTime)
this.tick();
}
);
}
}, interval);
},
//初始化時(shí)間
initTime: function(properties) {
let lastTime = 0;
let targetTime = 0;
try {
if (Object.prototype.toString.call(properties.target) === '[object Date]') {
targetTime = Number(properties.target).getTime();
} else {
targetTime = new Date(Number(properties.target)).getTime();
}
} catch (e) {
throw new Error('invalid target properties', e);
}
lastTime = targetTime - new Date().getTime();
return {
lastTime: lastTime < 0 ? 0 : lastTime,
};
},
//時(shí)間結(jié)束回調(diào)事件
onEnd: function() {
this.triggerEvent('onEnd');
}
}
defaultFormat
:默認(rèn)時(shí)間處理函數(shù)tick
:定時(shí)事件initTime
初始化時(shí)間
onEnd
:時(shí)間結(jié)束的回調(diào)
- 倒計(jì)時(shí)組件
countDown.js
完整代碼
var timer = 0;
var interval = 1000;
Component({
/**
* 組件的屬性列表
*/
properties: {
target: {
type: String,
},
format: {
type: Function,
default: null
}
},
lifetimes: {
attached() {
//組件創(chuàng)建時(shí)
this.setData({
lastTime: this.initTime(this.properties).lastTime, //根據(jù) target 初始化組件的lastTime屬性
}, () => {
//開(kāi)啟定時(shí)器
this.tick();
//判斷是否有format屬性 如果設(shè)置按照自定義format處理頁(yè)面上顯示的時(shí)間 沒(méi)有設(shè)置按照默認(rèn)的格式處理
if (typeof this.properties.format === 'object') {
this.defaultFormat(this.data.lastTime)
}
})
},
detached() {
//組件銷(xiāo)毀時(shí)清除定時(shí)器 防止爆棧
clearTimeout(timer);
},
},
/**
* 組件的初始數(shù)據(jù)
*/
data: {
d: 0, //天
h: 0, //時(shí)
m: 0, //分
s: 0, //秒
result: '', //自定義格式返回頁(yè)面顯示結(jié)果
lastTime:'' //倒計(jì)時(shí)的時(shí)間錯(cuò)
},
/**
* 組件的方法列表
*/
methods: {
//默認(rèn)處理時(shí)間格式
defaultFormat: function(time) {
const day = 24 * 60 * 60 * 1000
const hours = 60 * 60 * 1000;
const minutes = 60 * 1000;
const d = Math.floor(time / day);
const h = Math.floor((time - d * day) / hours);
const m = Math.floor((time - d * day - h * hours) / minutes);
const s = Math.floor((time - d * day - h * hours - m * minutes) / 1000);
this.setData({
d,
h,
m,
s
})
},
//定時(shí)事件
tick: function() {
let {
lastTime
} = this.data;
timer = setTimeout(() => {
if (lastTime < interval) {
clearTimeout(timer);
this.setData({
lastTime: 0,
result: ''
},
() => {
this.defaultFormat(lastTime)
if (this.onEnd) {
this.onEnd();
}
}
);
} else {
lastTime -= interval;
this.setData({
lastTime,
result: this.properties.format ? this.properties.format(lastTime) : ''
},
() => {
this.defaultFormat(lastTime)
this.tick();
}
);
}
}, interval);
},
//初始化時(shí)間
initTime: function(properties) {
let lastTime = 0;
let targetTime = 0;
try {
if (Object.prototype.toString.call(properties.target) === '[object Date]') {
targetTime = Number(properties.target).getTime();
} else {
targetTime = new Date(Number(properties.target)).getTime();
}
} catch (e) {
throw new Error('invalid target properties', e);
}
lastTime = targetTime - new Date().getTime();
return {
lastTime: lastTime < 0 ? 0 : lastTime,
};
},
//時(shí)間結(jié)束回調(diào)事件
onEnd: function() {
this.triggerEvent('onEnd');
}
}
})
- 倒計(jì)時(shí)組件
countDown.wxml
完整代碼
<wxs src="../wxs/utils.wxs" module="utils" />
<wxs src="../../comm.wxs" module="comm" />
<view class="count-down">
<text wx:if="{{result!==''}}">{{result}}</text>
<block wx:else>
<text wx:if="{{comm.numberToFixed(d)>0}}">{fjur7fs}天</text>
<text>{{utils.fixedZero(h)}}</text>
<text style="font-weight: 500">:</text>
<text>{{utils.fixedZero(m)}}</text>
<text style="font-weight: 500">:</text>
<text>{{utils.fixedZero(s)}}</text>
</block>
</view>
其中引入了兩個(gè)wxs文件中的函數(shù)
WXS(WeiXin Script)是小程序的一套腳本語(yǔ)言,結(jié)合 WXML醉蚁,可以構(gòu)建出頁(yè)面的結(jié)構(gòu)燃辖。官方文檔
function fixedZero(val) {
return val * 1 < 10 ? '0' + val : val;
}
//保留 pos位小數(shù)
function numberToFixed(number, pos) {
if (number === null || number === '' || number < 0) return ''
return parseFloat(number).toFixed(pos)
}
組件使用
- 引入方式
"usingComponents": {
"countDown": "../../../components/countDown/countDown"
},
- 代碼演示
<countDown bind:onEnd="getPageList" format="{{formatTime}}" target="{{creatTargetTime}}" />
const formatChinaDate = mss => {
let days = parseInt(mss / (1000 * 60 * 60 * 24));
let hours = parseInt((mss % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
let minutes = parseInt((mss % (1000 * 60 * 60)) / (1000 * 60));
let seconds = parseInt((mss % (1000 * 60)) / 1000);
return days + ' 天 ' + hours + ' 小時(shí) ' + minutes + ' 分鐘 ' + seconds + ' 秒 ';
};
data:{
formatTime:formatChinaDate,
creatTargetTime:1556428889000, //時(shí)間戳
}
getPageList:function(){
//倒計(jì)時(shí)結(jié)束啦
console.log('倒計(jì)時(shí)結(jié)束啦')
}
API
參數(shù) | 說(shuō)明 | 類(lèi)別 | 默認(rèn)值 |
---|---|---|---|
format | 時(shí)間格式化顯示 | Function(time) | x天00:00:00 |
target | 目標(biāo)時(shí)間 | Date | |
onEnd | 倒計(jì)時(shí)結(jié)束回調(diào) | funtion |
補(bǔ)充
- 文章首發(fā)于:微信小程序之自定義倒計(jì)時(shí)組件