這是我參與更文挑戰的第4天,活動詳情查看: 更文挑戰javascript
這是使用UNIAPP
Uview
開發出來的可得計時小程序,是一款簡約、方便的倒計時器微信小程序,您能夠設置在上面設定將來的什麼時候何分何秒後通知你。css
咱們先看看咱們的成品效果圖,是否是以爲很nice!html
在uniapp
中建立一個新的uniapp
項目,這裏我就命名爲codeTime了vue
咱們須要用到的uView
裏邊的CountDown
組件,因此咱們須要先安裝uView
,在項目所在位置打開終端,執行 (由於咱們的項目是經過hbx建立的,沒有package.json
文件)java
npm init -y
複製代碼
npm install uview-ui
複製代碼
安裝以後,須要在項目中配置下(引入uView
框架)git
// main.js
import uView from "uview-ui";
Vue.use(uView);
複製代碼
# uni.scss
@import 'uview-ui/theme.scss';
# app.vue
<style lang="scss">
@import "uview-ui/index.scss";
/*每一個頁面公共css */
</style>
複製代碼
// pages.json
"easycom": {
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
},
複製代碼
配置完後,咱們能夠使用console.log(this.$u.config.v);
,查看版本,檢測是否安裝及配置成功github
onShow: function() {
console.log(this.$u.config.v);
},
複製代碼
咱們還須要改下uView
框架中的CountDown
組件文件,由於須要咱們這個項目須要用到暫停倒計時,可是該組件沒有提供改方法web
在CountDown
組件中的props
對象中加入屬性npm
pause: {
type: Boolean,
default: false
}
複製代碼
修改CountDown
組件中的start
方法,利用父組件傳入的pause
屬性,來判斷是否執行seconds --
,也就便是否進行減秒操做json
// 倒計時
start() {
// 避免可能出現的倒計時重疊狀況
this.clearTimer();
if (this.timestamp <= 0) return;
this.seconds = Number(this.timestamp);
this.formatTime(this.seconds);
this.timer = setInterval(() => {
if (!this.pause) {
this.seconds--;
// 發出change事件
this.$emit('change', this.seconds);
if (this.seconds < 0) {
return this.end();
}
this.formatTime(this.seconds);
} }, 1000);
},
複製代碼
咱們把pages
文件夾下面的index.vue
文件整理下
<template>
</template>
<script>
export default {
data() {
return {
}
},
onLoad() {
},
methods: {
}
}
</script>
<style lang="scss">
</style>
複製代碼
咱們項目組件主體分爲三大部分
如今咱們就按這個順序來書寫咱們各部分的組件,到後面咱們將這些組件插入到index.vue中
note.vue
,其實它只是一個簡單的input組件,沒有任何邏輯處理的組件,也是這個項目中最簡單的一個組件,沒有之一哈哈
<template>
<view class="c-title">
<input class="c-input" type="text" :value="note" placeholder="#添加計時內容" placeholder-class="c-input-pla" />
</view>
</template>
複製代碼
<script>
export default {
name:"note",
}
</script>
複製代碼
<style lang="scss">
.c-title {
padding: 50rpx 20rpx 20rpx 20rpx;
margin: 20rpx;
color: #007aff;
width: 90%;
height: 60rpx;
.c-input {
text-align: center;
font-size: 45rpx;
line-height: 45rpx;
height: 60rpx;
}
.c-input-pla {
color: #e7e7e7;
}
}
</style>
複製代碼
在index.vue
中引入它看看效果如何
<template>
<view class="c-container">
<note></note>
</view>
</template>
複製代碼
<style lang="scss" scoped>
.c-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>
複製代碼
這是一個時間選擇器組件,也就是咱們用戶選擇時間用到的組件,這裏用到的是uniapp
自帶的組件,叫作picker-view
嵌入頁面的滾動選擇器,該組件文檔地址 uniapp.dcloud.io/component/p…
<template>
<view class="u-picker-body">
<picker-view :value="valueArr" @change="change" class="u-picker-view" @pickstart="pickstart" @pickend="pickend">
<picker-view-column>
<view class="u-column-item" v-for="(item, index) in hours" :key="index">
{{ formatNumber(item) }}
<text class="c-text" v-if="showTimeTag">時</text>
</view>
</picker-view-column>
<picker-view-column>
<view class="u-column-item" v-for="(item, index) in minutes" :key="index">
{{ formatNumber(item) }}
<text class="c-text" v-if="showTimeTag">分</text>
</view>
</picker-view-column>
<picker-view-column>
<view class="u-column-item" v-for="(item, index) in seconds" :key="index">
{{ formatNumber(item) }}
<text class="c-text" v-if="showTimeTag">秒</text>
</view>
</picker-view-column>
</picker-view>
</view>
</template>
複製代碼
<script>
export default {
name:"date-selector",
created(){
this.initTimeList()
},
data() {
return {
moving: false, // 列是否還在滑動中,微信小程序若是在滑動中就點肯定,結果可能不許確
hours: [],
minutes: [],
seconds: [],
hour: 0,
minute: 0,
second: 0,
valueArr: [],
timestamp:300
};
},
props:{
showTimeTag:{
type:Boolean,
default:false
}
},
methods:{
// 初始化
initTimeList(){
// 生成 時,分,秒
this.valueArr.push(0);
this.setHours();
this.valueArr.push(0);
this.setMinutes();
this.valueArr.push(0);
this.setSeconds();
},
getIndex(arr, val) {
let index = arr.indexOf(val);
// 若是index爲-1(即找不到index值),~(-1)=-(-1)-1=0,致使條件不成立
return ~index ? index : 0;
},
// 小於10前面補0,用於月份,日期,時分秒等
formatNumber(num) {
return +num < 10 ? '0' + num : String(num);
},
// 標識滑動開始,只有微信小程序纔有這樣的事件
pickstart() {
// #ifdef MP-WEIXIN
this.moving = true;
// #endif
},
// 標識滑動結束
pickend() {
// #ifdef MP-WEIXIN
this.moving = false;
this.$emit('pickend',this.timestamp)
// #endif
},
setHours() {
this.hours = this.generateArray(0, 23);
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.hours, this.hour));
},
setMinutes() {
this.minutes = this.generateArray(0, 59);
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.minutes, this.minute));
},
setSeconds() {
this.seconds = this.generateArray(0, 59);
this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.seconds, this.second));
},
// 生成遞進的數組
generateArray(start, end) {
// 轉爲數值格式,不然用戶給end-year等傳遞字符串值時,下面的end+1會致使字符串拼接,而不是相加
start = Number(start);
end = Number(end);
end = end > start ? end : start;
// 生成數組,獲取其中的索引,並剪出來
return [...Array(end + 1).keys()].slice(start);
},
// 用戶更改picker的列選項
change(e) {
this.valueArr = e.detail.value;
let i = 0;
this.hour = this.hours[this.valueArr[i++]];
this.minute = this.minutes[this.valueArr[i++]];
this.second = this.seconds[this.valueArr[i++]];
this.getTimeToSecond(this.hour, this.minute, this.second);
},
// 將picker的時間專成秒數
getTimeToSecond(hour, minute, second) {
let time = 0;
if (hour) {
time += hour * 60 * 60;
}
if (minute) {
time += minute * 60;
}
if (second) {
time += second;
}
this.timestamp = time;
},
quickSetMinutes(minutes){
this.valueArr[0] = 0;
this.valueArr[1] = minutes;
this.valueArr[2] = 0;
this.setHours()
this.setMinutes()
this.setSeconds()
}
}
}
</script>
複製代碼
<style lang="scss">
.u-picker-body {
margin: 0;
width: 100%;
height: 500rpx;
overflow: hidden;
background-color: #ffffff;
.u-picker-view {
height: 100%;
width: 700rpx;
box-sizing: border-box;
margin: 0 auto;
.u-column-item {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
font-size: 50rpx;
color: #000000;
padding: 0 8rpx;
.c-text {
font-size: 24rpx;
padding-left: 8rpx;
}
}
}
}
</style>
複製代碼
一樣,咱們在index.vue
中引入它,在此以前,咱們還要引入咱們魔改後的CountDown
組件並傳入須要的一些參數(timestamp
autoplay
...
),以後再引用咱們寫好的dateSelector
組件,記得加上v-if
,當start
爲true
時,說明當前正在倒計時,咱們須要把時間選擇器隱藏起來。(其實這裏使用v-show
更好,可是uniapp
自己不支持v-show
,由於v-if
會把元素從新渲染,這個以後再用style
的display
來控制吧,目前先這樣子吧)
<template>
<view class="c-container">
<note></note>
<view class="c-countdown" v-if="start">
<u-count-down ref="uCountDown" :timestamp="timestamp" :autoplay="autoplay" :show-days="false" :font-size="100" :separatorSize="65" :pause="pause"></u-count-down>
</view>
<date-selector v-else ref="dateSelectorRef" showTimeTag @pickend="pickend"></date-selector>
</view>
</template>
複製代碼
<script>
export default {
data() {
return {
start: false, // 是否開始倒計時
pause: false, // 是否處於暫停狀態
autoplay: false,
timestamp: 300, // 默認五分鐘
};
},
methods: {
pickend(timestamp) {
this.timestamp = timestamp
},
}
};
</script>
複製代碼
整個項目的按鈕組件都在這裏邊,它的按鈕功能主要是控制倒計時器 CountDown
的的進行和暫停以及重置功能
<template>
<view class="c-controller">
<!-- 快捷設置按鈕 -->
<view :animation="animationQuickChooseTime" class="c-default-list">
<view v-for="(time,index) in defaultTimeList" v-if="defaultTimeList.length!==0" @tap="selectDefaultTime(time,index)" :key="time">
<view :class="[index == selectIndex&&time*60==timestamp?'c-time-item-sel':'c-time-item']">
<view class="c-time-num">
{{time}}
</view>
<view :class="[index == selectIndex&&time*60==timestamp?'c-time-text-sel':'c-time-text']">
分鐘
</view>
</view>
</view>
</view>
<!-- 控制按鈕 -->
<view class="c-controller-area">
<view :animation="animationToLeftData" class="c-button" style="z-index: 1;" @tap="startCountTime()">
<image v-if="start" class="c-icon" src="../../static/restart.png"></image>
<image v-else class="c-icon" src="../../static/start.png"></image>
</view>
<view :animation="animationToRightData" class="c-button" @tap="stopCountTime()">
<image v-if="!pause" class="c-icon" src="../../static/stop.png"></image>
<image v-else class="c-icon" src="../../static/start.png"></image>
</view>
</view>
</view>
</template>
複製代碼
<script>
export default {
name: "controller-area",
data() {
return {
// 動畫
animationToLeftData: {},
animationToRightData: {},
animationQuickChooseTime: {},
selectIndex: null
};
},
methods: {
startCountTime() {
if (this.start) {
// 正在計時,中止它
this.$emit('startCountTime', this.start)
// 執行動畫
let leftButton = uni.createAnimation({
transformOrigin: "50% 50%",
duration: 500,
timingFunction: "ease",
delay: 0
})
// 執行動畫
let rightButton = uni.createAnimation({
transformOrigin: "50% 50%",
duration: 500,
timingFunction: "ease",
delay: 0
})
// 執行動畫
let quickChooseTimeButton = uni.createAnimation({
transformOrigin: "50% 50%",
duration: 300,
timingFunction: "ease",
delay: 0
})
leftButton.translateX(0).step()
this.animationToLeftData = leftButton.export()
rightButton.translateX(0).opacity(0).step()
this.animationToRightData = rightButton.export()
quickChooseTimeButton.scale(1.1).step()
quickChooseTimeButton.scale(1).step()
this.animationQuickChooseTime = quickChooseTimeButton.export()
} else {
// 沒有計時,開始計時
this.$emit('startCountTime', this.start)
// 執行動畫
let leftButton = uni.createAnimation({
transformOrigin: "50% 50%",
duration: 500,
timingFunction: "ease",
delay: 0
})
// 執行動畫
let rightButton = uni.createAnimation({
transformOrigin: "50% 50%",
duration: 500,
timingFunction: "ease",
delay: 0
})
// 執行動畫
let quickChooseTimeButton = uni.createAnimation({
transformOrigin: "50% 50%",
duration: 500,
timingFunction: "ease",
delay: 0
})
leftButton.translateX(-60).step()
this.animationToLeftData = leftButton.export()
rightButton.opacity(1).translateX(60).step()
this.animationToRightData = rightButton.export()
quickChooseTimeButton.scale(0).step()
this.animationQuickChooseTime = quickChooseTimeButton.export()
}
},
stopCountTime() {
this.$emit('stopCountTime')
},
selectDefaultTime(time, index) {
this.$emit('clickSetTime', time)
this.selectIndex = index;
},
},
props: {
timestamp: {
type: Number,
default: 0
},
defaultTimeList: {
type: Array,
default: []
},
pause: {
type: Boolean,
default: false
},
start: {
type: Boolean,
default: false
}
}
}
</script>
複製代碼
<style lang="scss">
.c-controller {
position: absolute;
top: 750rpx;
left: 0;
height: 400rpx;
width: 100%;
.c-default-list {
display: flex;
justify-content: center;
position: absolute;
top:0;
left: 0;
right: 0;
bottom: 0;
margin:auto;
.c-time-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 125rpx;
height: 125rpx;
border-radius: 50%;
padding: 20rpx;
margin: 20rpx;
background-color: #eeeeee;
}
.c-time-item-sel {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 125rpx;
height: 125rpx;
border-radius: 50%;
padding: 20rpx;
margin: 20rpx;
color: #FFFFFF;
background-color: #007aff;
}
.c-time-item,
.c-time-item-sel {
.c-time-num {
font-size: 45rpx;
}
.c-time-text {
font-size: 20rpx;
color: #808080;
}
.c-time-text-sel {
font-size: 20rpx;
color: #d0f0f7;
}
}
}
.c-controller-area {
height: 200rpx;
width: 100%;
position: absolute;
top: 200rpx;
left: 0;
margin: 0;
.c-button {
position: absolute;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 125rpx;
height: 125rpx;
border-radius: 50%;
background-color: #ffffff;
box-shadow: 0 4px 10px 0 rgba(0, 0, 0, 0.1), 0 3px 10px 0 rgba(0, 0, 0, 0.15);
top:0;
left: 0;
right: 0;
bottom: 0;
margin:auto;
/* 寬度的一半 */
.c-icon {
width: 50rpx;
height: 50rpx;
}
}
}
}
</style>
複製代碼
繼續在index.vue
中引入,在script
標籤中,繼續加入一些須要的屬性和方法
<template>
<view class="c-container">
<note></note>
<view class="c-countdown" v-if="start">
<u-count-down ref="uCountDown" :timestamp="timestamp" :autoplay="autoplay" :show-days="false" :font-size="100" :separatorSize="65" :pause="pause"></u-count-down>
</view>
<date-selector v-else ref="dateSelectorRef" showTimeTag @pickend="pickend"></date-selector>
<controller-area @startCountTime="startCountTime" @stopCountTime="stopCountTime" @clickSetTime="clickSetTime" :defaultTimeList="defaultTime" :timestamp="timestamp" :pause="pause" :start="start" class="">
</controller-area>
</view>
</template>
複製代碼
// 在index.vue中對應位置進行代碼補充
data() {
return {
defaultTime: [5, 10, 15],
};
},
methods: {
// 開始倒計時
startCountTime() {
if (this.start) {
// 正在計時,中止它
console.log('restart');
this.start = false;
this.pause = false;
} else {
// 沒有計時,開始計時
console.log('start');
this.start = true;
this.autoplay = true;
this.pause = false;
}
},
stopCountTime() {
this.pause = !this.pause;
},
clickSetTime(minutes) {
this.timestamp = minutes * 60;
this.$refs.dateSelectorRef.quickSetMinutes(minutes)
},
}
複製代碼
到了這裏咱們的三大組件已經書寫好啦,接下來咱們就要在index.vue
文件中進行一個引用,和一些邏輯方法的書寫
附上最終index.vue
的代碼
<template>
<view class="c-container">
<note></note>
<view class="c-countdown" v-if="start">
<u-count-down ref="uCountDown" :timestamp="timestamp" :autoplay="autoplay" :show-days="false" :font-size="100" :separatorSize="65" :pause="pause"></u-count-down>
</view>
<date-selector v-else ref="dateSelectorRef" showTimeTag @pickend="pickend"></date-selector>
<controller-area @startCountTime="startCountTime" @stopCountTime="stopCountTime" @clickSetTime="clickSetTime" :defaultTimeList="defaultTime" :timestamp="timestamp" :pause="pause" :start="start" class="">
</controller-area>
</view>
</template>
複製代碼
<script>
export default {
data() {
return {
start: false, // 是否開始倒計時
pause: false, // 是否處於暫停狀態
autoplay: false,
timestamp: 300, // 默認五分鐘
defaultTime: [5, 10, 15],
};
},
methods: {
// 開始倒計時
startCountTime() {
if (this.start) {
// 正在計時,中止它
console.log('restart');
this.start = false;
this.pause = false;
} else {
// 沒有計時,開始計時
console.log('start');
this.start = true;
this.autoplay = true;
this.pause = false;
}
},
pickend(timestamp) {
this.timestamp = timestamp
},
stopCountTime() {
this.pause = !this.pause;
},
clickSetTime(minutes) {
this.timestamp = minutes * 60;
this.$refs.dateSelectorRef.quickSetMinutes(minutes)
},
}
};
</script>
複製代碼
<style lang="scss" scoped>
.c-container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.c-countdown {
margin-top: 50rpx;
}
</style>
複製代碼
該小程序項目完整的GIT倉庫地址:github.com/eatmans/cod…
別忘了 ⭐️⭐️⭐️
最後再貼個小程序碼
感謝你們的閱讀,但願看完你們能有所收穫! 若有不足之處,請多多指教!