🥬 🐶的uniapp学习之🦌 【计时器】

1,247 阅读5分钟

「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战

【前言】 我们这篇文章打算先画出页面的大概样式,具体录音功能下篇文章实现。

uView

这个并不是官方开发的第三方UI,是一个大佬开发的。现在使用的很广泛。 官网 💻

安装

我这里使用的是npm安装。如果是纯的uniapp项目,是没有包管理器package.json的,更没有node_modules的。

初始化

 npm init -y

初始化之后就会有package.json文件了

开始安装

新打开一个终端,执行命令

npm install uview-ui

📢

目前(2020-05-06)不支持通过cnpm安装uView

并且由于uView使用easycom模式,让您无需引入组件即可直接使用,但是此功能需要Hbuilder X 2.5.5及以上版本才支持。(类似于)

配置一下

像Vue项目引用第三方组件库一样,在main.js中引入 然后 Vue.use 使用

import uView from "uview-ui"; 
Vue.use(uView);

然后再去uni.scss中 在全局的CSS中加入

@import 'uview-ui/theme.scss';

最后在page.json配置文件中添加easycom

"easycom": {
            "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
	},
"pages": [

      ]

然后测试一下,最方便的就是加入按钮

<u-button shape="square" type="success">乌啼</u-button>

如下:引入成功

实现录音器效果

步入正题,我想实现一个录音器。如下图:

需求

  1. 最上部,在计时的时候是一个动画效果,涟漪波纹效果。在停止计时的时候是话筒。
  2. 中间是 计时器 分:秒:毫秒
  3. 底部是三个按钮:第一个是重置按钮、第二个是开始和结束按钮(初始按钮是开始按钮中间是圆形,开始之后按钮是停止按钮中间是正方形)。第三个按钮是暂停和继续按钮,初始是播放按钮 ▶️,当开始录制后变为暂停⏸按钮。

顶部

主要是一个涟漪效果和话筒图标的切换

html部分

 <u-row gutter="16"> 
   <u-col span="12"> 
    <view v-if="pendingBtn==false" class="waves"> 
    </view> 
    <view v-if="pendingBtn==true" class="waves_stop"> 
     <u-icon name="mic" size="100"></u-icon> 
    </view> 
   </u-col> 
  </u-row>
  • <u-row>是UView栅格化布局的行。gutter:栅格间隔,左右各为此值的一半,单位rpx。
  • <u-col>是列,栅格占据的列数,总12等分。
  • 使用了一个变量 pendingBtn 来判断是哪种状态
  • 然后根据不同的类名来展示不同的效果

定义数据

export default {
     data() {
            return {
                pendingBtn: true,
                }
            }
      }    

样式

这个地方把后面能用到的样式也都放在这了。

涟漪主要是添加了animation动画效果

<style>
	.wrap {
		background-color: #193443;
		height: 100%
	}

	body {
		width: 100%;
		height: 100%;
		background: #142c3a;
		margin: 0px;
		overflow: hidden;
	}

	.waves {
		position: relative;
		top: 50%;
		left: 44%;
		width: 250rpx;
		height: 250rpx;
		margin-left: 0px;
		margin-top: 200rpx;
		border-radius: 50%;
		/* padding-top:100rpx; */
		-webkit-backface-visibility: hidden;
	}

	.wave,
	.waves:before,
	.waves:after {
		position: absolute;
		background: white;
		margin-left: 0px;
		margin-top: 0px;
		width: 50px;
		height: 50px;
		content: "";
		display: block;
		border-radius: 50%;
		-webkit-backface-visibility: hidden;
	}

	.waves:before {
		animation: wave-animate 3s infinite ease-out;
	}

	.waves:after {
		opacity: 0;
		animation: wave-animate 3s 1.5s infinite ease-out;
	}

	.waves_stop {
		display: flex;
		background-color: #e0f2ea;
		width: 250rpx;
		height: 250rpx;
		margin-left: 33%;
		margin-top: 200rpx;
		border-radius: 50%;
		padding: 80rpx;
	}
        @keyframes wave-animate {
		0% {
			transform: scale(0);
			opacity: 1;
			transform-origin: center;
		}

		100% {
			transform: scale(3);
			opacity: 0;
			transform-origin: center;
		}
	}

	.timeStep {
		height: 100rpx
	}

	.startBtn {
		border-radius: 50%;
		width: 90rpx;
		height: 90rpx;
		border: 8rpx solid #ffffff;
		background-color: #f4f1f1;
		justify-content: center; //子元素水平居中
		align-items: center; //子元素垂直居中
		display: flex;

	}

	.circl {
		width: 50rpx;
		height: 50rpx;
		border-radius: 50%;
		background-color: red;
	}

	.square {
		width: 45rpx;
		height: 45rpx;
		background-color: red;
	}
        </style>

中间计时器

html

image.png 因为时间的这种格式,所以我进行了几个判断 对于分,当小于10的时候补个0占位。 对于秒,同样是补个0占位 对于毫秒,当时0的时候补两个0

	<!-- 第二行 计时器 -->
  <u-row gutter="16">
    <u-col span="12" class="timeStep" style="color: white;font-size:30px;text-align: center;height:400rpx;padding-top:40rpx">
		<span v-if="minute<10">0{{minute}}:</span>
		<span v-else>{{minute}}:</span>
		<span v-if="mill<10">0{{mill}}</span>
		<span v-else>{{mill}}</span> 
		<span v-if="millisecond==0">:00{{millisecond}}</span>
		<span v-else>:{{millisecond}}</span>		
	</u-col>
 </u-row>

setInterval()

计时需要使用setInterval()方法,setInterval()有两个参数,

  • 第一个参数是要执行的函数
  • 第二个参数是多久执行一次,单位是毫秒。[1m=1000ms]
    this.init = setInterval(this.timer, 100)

把函数赋值给一个变量,相当于给这个计时器绑定了唯一id,当我们要停止这个计时的时候通过这个id来停止。

clearInterval()

停止计时器需要clearInterval()方法,将我们定义的setInterval()函数对应变量传给它,来停止计时。

开始暂停继续结束 计时器

  • 定义好三个变量 分:minute 秒:mill 毫秒:millisecond
  • 开始时 执行setInterval(),并赋值给init变量。
  • 暂停时 执行clearInterval(),将刚才的init对应的计时器清除掉。但是对应的分 秒 毫秒 值还在。
  • 继续时 执行setInterval(),还要给它赋值给init。
  • 结束时 执行clearInterval(),销毁init 三个变量都清零。 然后具体代码实现我们在下面结合按钮一起讲。

最后底部按钮

html部分

<!-- 第三行 按钮 -->
        <!-- 重置按钮 -->
		<u-row gutter="16">
			<u-col span="3" offset="2">
				<u-icon name="reload" size="53rpx" color="white" @click="touchReset"></u-icon>
			</u-col>
			<u-col span="2" style="padding-left:13rpx;">
				<!-- 开始结束按钮 -->
				<view class="startBtn" @click="status==0?touchStart():touchStop()">
					<!-- 按钮状态为0是圆形-->
					<view v-if="status===0" class="circl">
					</view>
					<!-- 按钮状态 除了0 是正方形-->
					<view v-if="status!=0" class="square">
					</view>
				</view>
			</u-col>
			<!-- 暂停 继续 -->
			<u-col span="3" offset="2">
				<u-icon v-if="pendingBtn==false"  name="pause" size="50rpx" color="white" @click="touchpending() ">
				</u-icon>
				<u-icon v-if="pendingBtn==true" :style="{'pointer-events':status==0?'none':''}" name="play-right" size="50rpx" color="white" @click="status==0?a():touchpending()">
				</u-icon>
			</u-col>
		</u-row>
  • 重置按钮 <u-icon>是UView的图标,name对应不同的图标,size是图标大小,color是图标颜色。点击重置执行函数touchReset() 清零了时分秒,并且销毁了init
// 点击重置按钮
touchReset:function(){
	// 将时分秒清零
	this.minute = 0
	this.mill = 0
	this.millisecond = 0
	clearInterval(this.init)			
}
  • 开始结束按钮 使用了一个阴影效果样式请看.startBtn

内部的 ○ 和 □ 的切换, ○ 和 □ 的切换根据变量status[0:未开始 1:开始 2:暂停 3:继续 4:结束 ]。 当未开始时时○,其他状态都是□

当status是0时点击按钮执行touchStart()

// 点击开始按钮
touchStart: function() {
        // 开始后 把status变为1:开始 
	this.status = 1
        // 执行计时
	this.init = setInterval(this.timer, 100)
	// 这个变量用于:在未开始前暂停继续按钮禁止点击 true是禁止
        this.pendingBtn = false
	},

当status不是0️⃣ 的时候,点击此按钮,执行touchStop()

// 点击结束按钮
touchStop: function() {		
	this.pendingBtn = true
	clearInterval(this.init)
},
  • 暂停继续按钮 在页面初始加载的时候是继续播放按钮(pendingBtn是true)并且status是0也就是未开始时时不可点击的,但图标没有disabled属性,所以使用了pointer-events:none 属性来实现不可点击效果。但是点击它,它依旧执行了,所以我在点击的时候又加了个判断:当status是0时执行一个空函数,当不是0时执行touchpending()

当点击开始按钮后变为暂停按钮(pendingBtn是false),执行touchpending()。

// 点击暂停按钮
touchpending: function() {
        // 切换状态
	this.pendingBtn = !this.pendingBtn
	// 清除掉计时器
	clearInterval(this.init)
        // 继续时创建新的计时器
	this.pendingBtn == false ?
	this.init = setInterval(this.timer, 100) : ''
	},

完整代码

<template>
	<view class="wrap">
		<!-- 第一行 波纹 -->
		<u-row gutter="16">
			<u-col span="12">
				<!--  -->
				<view v-if="pendingBtn==false" class="waves">
				</view>
				<view v-if="pendingBtn==true" class="waves_stop">
					<u-icon name="mic" size="100"></u-icon>
				</view>
			</u-col>
		</u-row>
		<!-- 第二行 计时器 -->
		<u-row gutter="16">
			<u-col span="12" class="timeStep"
				style="color: white;font-size:30px;text-align: center;height:400rpx;padding-top:40rpx">
				<span v-if="minute<10">0{{minute}}:</span>
				<span v-else>{{minute}}:</span>
				<span v-if="mill<10">0{{mill}}</span>
				<span v-else>{{mill}}</span>
				<span v-if="millisecond==0">:00{{millisecond}}</span>
				<span v-else>:{{millisecond}}</span>

			</u-col>
		</u-row>
		<!-- 第三行 按钮 -->
		<u-row gutter="16">
			<u-col span="3" offset="2">
				<u-icon name="reload" size="53rpx" color="white" @click="touchReset"></u-icon>
			</u-col>
			<u-col span="2" style="padding-left:13rpx;">
				<!-- 开始结束按钮 -->
				<view class="startBtn" @click="status==0?touchStart():touchStop()">
					<!-- 按钮状态为0是圆形-->
					<view v-if="status===0" class="circl">
					</view>
					<!-- 按钮状态 除了0 是正方形-->
					<view v-if="status!=0" class="square">
					</view>
				</view>
			</u-col>
			<!-- 暂停 继续 -->
			<u-col span="3" offset="2">
				<u-icon v-if="pendingBtn==false" name="pause" size="50rpx" color="white" @click="touchpending() ">
				</u-icon>
				<u-icon v-if="pendingBtn==true" :style="{'pointer-events':status==0?'none':''}" name="play-right"
					size="50rpx" color="white" @click="status==0?a():touchpending()">
				</u-icon>
			</u-col>
		</u-row>
	</view>
</template>

<script>

	export default {
		data() {
			return {
				// 0:未开始 1:开始 2:暂停 3:继续 4:结束 
				status: 0,
				playStatus: 0,
				pendingBtn: true,
				init: '',
				millisecond: 0,
				mill: 0,
				minute: 0

			}
		},
		onLoad() {

		},
		methods: {
			// 点击开始按钮
			touchStart: function() {
				// 开始后 把status变为1:开始 
				this.status = 1
				this.init = setInterval(this.timer, 100)
				// 这个变量用于:在未开始前暂停继续按钮禁止点击 true是禁止
				this.pendingBtn = false
			},
			// 点击暂停按钮
			touchpending: function() {
				this.pendingBtn = !this.pendingBtn
				// 清除掉计时器
				clearInterval(this.init)
				 // 继续时创建新的计时器
				this.pendingBtn == false ?
					this.init = setInterval(this.timer, 100) : ''
			},
			// 点击结束按钮
			touchStop: function() {
				this.pendingBtn = true
				clearInterval(this.init)

			},
			// 点击重置按钮
			touchReset: function() {
				// 将时分秒清零
				this.minute = 0
				this.mill = 0
				this.millisecond = 0
				clearInterval(this.init)

			},
			changeRecordStart: function() {
				this.start = !this.start
				this.recordStart()
			},
			changeFinish: function() {
				this.finish += 1
				this.changeRecordStart()
				if (this.finish == 3) {
					console.log("录音结束了")
				}
			},

			// 计时器
			timer: function() {
				this.millisecond += 100
				if (this.millisecond >= 1000) {
					this.millisecond = 0;
					this.mill = this.mill + 1;
				}
				if (this.mill >= 60) {
					this.mill = 0;
					this.minute = this.minute + 1;
				}

			}
			

		}


	}
</script>

<style>
	.wrap {
		background-color: #193443;
		height: 100%
	}

	body {
		width: 100%;
		height: 100%;
	}

	body {
		background: #142c3a;
		margin: 0px;
		overflow: hidden;
	}

	.waves {
		position: relative;
		/* background-image: url(../../static/MV.png); */
		top: 50%;
		left: 44%;
		width: 250rpx;
		height: 250rpx;
		margin-left: 0px;
		margin-top: 200rpx;
		border-radius: 50%;
		/* padding-top:100rpx; */
		-webkit-backface-visibility: hidden;
	}

	.wave,
	.waves:before,
	.waves:after {
		position: absolute;
		background: white;
		margin-left: 0px;
		margin-top: 0px;
		width: 50px;
		height: 50px;
		content: "";
		display: block;
		border-radius: 50%;
		-webkit-backface-visibility: hidden;
	}

	.waves:before {
		animation: wave-animate 3s infinite ease-out;
	}

	.waves:after {
		opacity: 0;
		animation: wave-animate 3s 1.5s infinite ease-out;
	}

	.waves_stop {
		display: flex;
		background-color: #e0f2ea;
		width: 250rpx;
		height: 250rpx;
		margin-left: 33%;
		margin-top: 200rpx;
		border-radius: 50%;
		padding: 80rpx;
	}

	@keyframes wave-animate {
		0% {
			transform: scale(0);
			opacity: 1;
			transform-origin: center;
		}

		100% {
			transform: scale(3);
			opacity: 0;
			transform-origin: center;
		}
	}

	.timeStep {
		height: 100rpx
	}

	.startBtn {
		border-radius: 50%;
		width: 90rpx;
		height: 90rpx;
		border: 8rpx solid #ffffff;
		background-color: #f4f1f1;
		justify-content: center; //子元素水平居中
		align-items: center; //子元素垂直居中
		display: flex;

	}

	.circl {
		width: 50rpx;
		height: 50rpx;
		border-radius: 50%;
		background-color: red;
	}

	.square {
		width: 45rpx;
		height: 45rpx;
		background-color: red;
	}
</style>