「这是我参与11月更文挑战的第11天,活动详情查看:2021最后一次更文挑战」
【前言】 我们这篇文章打算先画出页面的大概样式,具体录音功能下篇文章实现。
这个并不是官方开发的第三方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>
如下:引入成功
步入正题,我想实现一个录音器。如下图:
主要是一个涟漪效果和话筒图标的切换
<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>
因为时间的这种格式,所以我进行了几个判断 对于分,当小于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()有两个参数,
this.init = setInterval(this.timer, 100)
把函数赋值给一个变量,相当于给这个计时器绑定了唯一id,当我们要停止这个计时的时候通过这个id来停止。
停止计时器需要clearInterval()方法,将我们定义的setInterval()函数对应变量传给它,来停止计时。
<!-- 第三行 按钮 -->
<!-- 重置按钮 -->
<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)
},
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>