第二章 "我要点爆"微信小程序点爆页面的实现与云函数和云存储的应用
点爆页面的实现与云函数和云存储的应用以及录音功能讲解
点爆页面制作
点爆页面主要提供文字记录和语音记录两种爆文记录方式,在本页面内输入文字或录入语音后选择心情点击点爆按钮,跳转到点爆方式选择界面。
首先,我们来实现页面布局,将文字记录和语音记录使用导航切换的方式放在一个页面内。
导航中在js中设置一个currentTab变量通过数据绑定判断显示文字记录和语音记录的切换,{{item}},使用列表渲染wx:for创建导航,同时通过data-index将当前项的的下标index记录,用于在js中控制currentTab的值,并为导航每个组件添加一个点击事件。分别为文字记录和语音记录设置两个form,通过导航切换时currentTab的值和show与hide样式来判断是否显示。
detonation.wxml
<view class="the_header">
<text>点爆-抑制不住的心情</text>
<image src="/images/fencun.png"></image>
</view>
<view class="the_nav">
<text class="item {{currentTab==index ? 'active' : ''}}" wx:for="{{navber}}"
data-index="{{index}}" wx:key="unique" bindtap="navbarTap">{{item}}</text>
</view>
<form class="{{currentTab==0 ? 'show' : 'hide'}}">
<view class="the_main">
<text space="ensp"> 我们在路上,点爆,让时间忘不掉你的脚步!</text>
<!-- 当点击输入时触发bindinput -->
<textarea bindinput="textInput" value="{{baotext.wtext}}" maxlength="-1"></textarea>
</view>
<view class="the_check">
<!-- 当点击值时触发bindchange -->
<radio-group bindchange="changeMood">
<radio checked="checked" value="红色">红色心情</radio>
<radio value="黑色">黑色心情</radio>
</radio-group>
</view>
<view class="the_button">
<button bindtap="detonation">点爆</button>
</view>
</form>
<form class="{{currentTab==1 ? 'show' : 'hide'}}">
<view class="the_main">
<text space="ensp"> 我们在路上,点爆,让时间忘不掉你的脚步!</text>
<view class="yuyin">
<button bindtouchstart="touchdown" bindtouchend="touchup"><image src="/images/yuyin2.png" bindtap="ystart"></image></button>
</view>
</view>
<view class="the_check">
<radio-group bindchange="changeMoody">
<radio checked="checked">红色心情</radio>
<radio>黑色心情</radio>
</radio-group>
</view>
<view class="the_button">
<button bindtap="ydetonation">点爆</button>
</view>
</form>
在js页面中将实现登录判断、导航切换、录音功能、文字记录等功能。
在onShow中对用户是否为登录状态进行判断,如果未登录则跳转到user页面。
navbarTap为导航点击切换事件,当文本记录与语音记录导航被点击时触发,将当前点击组件的下标index赋值给控制变量currentTab,通过数据绑定改变导航和页面显示。
textInput为textarea组件中bindinput属性的方法,用于实时记录组件中输入的文本值。

changeMood情绪单选按钮组当选中情绪项发生改变时触发,记录用户选择的情绪颜色。

detonation文字记录点爆按钮点击事件方法,当完成文字记录后,点击点爆按钮即可跳转到爆炸方式选择界面,此时我们把当前页面所有的数据信息暂时保存在本地,方便在最后爆文发布页面提交保存到数据库中。
录音功能:通过button按钮进行录音,当按下按钮时录音开始,当松开按钮时录音结束跳转到录音试听页面,分别使用button组件的bindtouchstart属性和bindtouchend属性。
这里使用RecorderManager来实现录音操作,在顶部实例化一个唯一的RecorderManager录音管理器,配置录音参数options然后调用start开始录音API开始录音,松开按钮录音结束后调用stop录音结束API,同时调用录音结束的回调函数onStop,将音频文件保存在本地。
在停止录音后我们要将录音文件保存下来,同时将音频文件上传到云端(这里我们直接进行音频文件的存储,实际上存储音频文件应在爆文提交时才执行),保存音频文件时,为了让用户的每个音频文件文件名唯一,我们用用户的openid+语音文件数来命名,使用云函数获取和修改用户语音数量,使用云存储API上传文件到云,下面我们来进行云函数和云存储的操作介绍。
云函数的使用与环境配置:
1、创建云函数
右键cloudfunctions文件选择新建Node.js云函数,云函数命名为updateVoice用于修改用户语音数量。

2、安装node.js及npm:
一:从Node.js官网下载对应平台的安装程序
二:一键安装
三:打开cmd,输入node -v,npm -v如果出现版本号,证明安装成功
注意:在使用npm可能会出现“npm不是内部或外部命名,与不是可运行程序”的提示,这是由于环境变量问题,需对node进行环境变量配置。
3、安装wx-server-sdk
右键updataVoice在终端中打开,运行:


安装成功后云函数文件夹中会有多一个文件(package-lock.json):

右键上传并部署:所有文件

打开云端控制台可以看到我们云函数中已经有一个云函数了。

在云函数updateVoice下index.js进行云函数代码编写
console.log("4")
// 云函数入口文件
const cloud = require('wx-server-sdk')
cloud.init()
//声明数据库
const db = cloud.database()
console.log("3")
// 云函数入口函数
exports.main = async (event, context) => {
console.log("2")
//取得传过来的参数
var voice = event.voice, openId = event.openId;
//云函数,更新
try {
return await db.collection('users').where({
_openid: openId
}).update({
data: {
voice: voice
},
success: res => {
console.log('云函数成功')
},
fail: e => {
console.error(e)
}
})
} catch (e) {
console.error(e)
}
}
在云存储中创建保存音频文件的文件夹voice,用来保存上传到云端的音频文件。

上传文件时调用wx.cloud.callFunction文件上传API,在上传时云存储路cloudPath设置为云端文件夹名+文件名,filePath设置为录音停止回调函数中获取的文件路径tempFilePath。
完整的detonation.js代码:
//录音管理
const recorderManager = wx.getRecorderManager()
var tempFilePath;
Page({
data: {
navber: ['文字记录', '语音记录'],//导航数组
currentTab: 0,//导航判断
wtext: '',//文本
wmood: '红色',//心情red,black
ytempFilePath: '',
ymood: '红色',
theplay: true,//监听是否在录音
},
//监听页面显示,判断是否登录
onShow: function () {
//如果本地没有用户登录时保存的openId则提示登录且自动跳转到user页面
let userOpenId = wx.getStorageSync('openId')
if (!userOpenId) {
wx.showToast({
title: '请先登录~'
})
setTimeout(() => {
wx.switchTab({
url: '../user/user',
})
}, 1500)
} else {
console.log(userOpenId,"登录状态")
}
},
//文本记录与语音记录切换
navbarTap: function (e) {
this.setData({
currentTab: e.currentTarget.dataset.index
})
},
// 文字记录,输入文本事件
textInput: function (e) {
this.setData({
wtext: e.detail.value
})
},
//文字记录,单选按钮组
changeMood: function (e) {
this.setData({
wmood: e.detail.value
})
},
//文字记录,点爆按钮跳转
detonation: function (e) {
let wtext = this.data.wtext
let wmood = this.data.wmood
var wy = 'w'
if (this.data.currentTab == 0) {
if (wtext == '') {
wx.showToast({
title: '请输入点爆内容',
})
} else {
//将数据保存到本地,保存文爆判断
wx.setStorageSync('wtext', wtext)
wx.setStorageSync('wmood', wmood)
wx.setStorageSync('wy', wy)
//跳转页面
wx.navigateTo({
url: '../selectbao/selectbao'
})
}
}
},
//音爆,单选按钮组
changeMoody: function (e) {
this.setData({
ymood: e.detail.value
})
},
//按钮点下开始录音
touchdown: function () {
const options = {
duration: 300000,//指定录音的时长,单位 ms
sampleRate: 16000,//采样率
numberOfChannels: 1,//录音通道数
encodeBitRate: 96000,//编码码率
format: 'mp3',//音频格式,有效值 aac/mp3
frameSize: 50,//指定帧大小,单位 KB
}
//开始录音
recorderManager.start(options);
recorderManager.onStart(() => {
console.log('recorder start')
})
//错误回调
recorderManager.onError((res) => {
console.log(res)
})
},
//停止录音
touchup: function () {
//显示加载
wx.showLoading({
title: '',
mask: true
})
recorderManager.stop();
recorderManager.onStop((res) => {
this.tempFilePath = res.tempFilePath
//使用解构,获取音频文件
const { tempFilePath } = res
//查询用户已有语音,记录,并为文件赋值
//获取数据库引用
const db = wx.cloud.database()
const _ = db.command
//查找数据库,获得用户语音数量
db.collection('users').where({
_openid: wx.getStorageSync('openId')
}).get({
success(res) {
// res.data 是包含以上定义的记录的数组
//将名字定为id号+个数号+.mp3
var newvoice = res.data[0].voice + 1
var filename = wx.getStorageSync('openId') + newvoice + '.mp3'
console.log(wx.getStorageSync('openId'),res)
//调用云函数,修改语音数量,向云函数传值
wx.cloud.callFunction({
name: 'updateVoice',
data: {
openId: wx.getStorageSync('openId'),
voice: newvoice
},
success: res => {
console.log("1",res)
//上传录制的音频到云
wx.cloud.uploadFile({
cloudPath: 'voice/' + filename,
filePath: tempFilePath, // 文件路径
success: res => {
console.log("5")
//保存fileID用于播放云文件语音
wx.setStorageSync('fileIDy', res.fileID)
//将数据保存到本地
wx.setStorageSync('filename', filename)
wx.setStorageSync('ytempFilePath', tempFilePath)
//关闭加载
wx.hideLoading()
//跳转到听语音的页面
wx.navigateTo({
url: '../voicebao/voicebao'
})
},
fail: err => {
// handle error
console.error(err)
}
})
}
})
},
fail: err => {
}
})
})
setTimeout((() => {
//关闭加载
wx.hideLoading()
}), 4000)
},
//音爆,点爆按钮跳转
ydetonation: function (e) {
wx.showToast({
title: '请输入点爆语音',
})
}
})
运行效果图:


语音试听页面制作
在文本记录方式下的点爆按钮点击后直接进入点爆方式选择界面,而语音记录方式中,为了让用户能试听自己的录音,我们多加一个试听页面。语音试听页面与语音记录页面几乎相同,只是改变录音按钮为语音播放按钮。
配置app.json新建vicebao页面
为语音播放按钮增加一个点击事件play方法
<view class="the_header">
<text>点爆-抑制不住的心情</text>
<image src="/images/fencun.png"></image>
</view>
<view class="the_nav">
<text class="item">文字记录</text>
<text class="item active">语音记录</text>
</view>
<form class="show">
<view class="the_main">
<text space="ensp"> 我们在路上,点爆,让时间忘不掉你的脚步!</text>
<view class="yuyin">
<image src="/images/yuyin.png" bindtap="play"></image>
</view>
</view>
<view class="the_check">
<radio-group bindchange="changeMood">
<radio checked="checked" value='红色'>红色心情</radio>
<radio value='黑色'>黑色心情</radio>
</radio-group>
</view>
<view class="the_button">
<button bindtap="detonation">点爆</button>
</view>
</form>
在vicebao.js中实现音频播放,创建一个内部audio上下文InnerAudioContext对象,用于播放音频,设置音频自动播放与音频路径。通过onUnload和onHide对音频播放进行控制,进入点爆方式选择界面时将爆文信息保存到本地。
//音频组件控制
const innerAudioContext = wx.createInnerAudioContext()
Page({
data: {
navber: ['文字记录', '语音记录'],
currentTab: 2,
ymood: '红色',
theplay: true
},
//播放声音
play: function () {
if (this.data.theplay) {
this.setData({
theplay: false
})
innerAudioContext.autoplay = true
innerAudioContext.src = wx.getStorageSync('ytempFilePath'),
innerAudioContext.onPlay(() => {
console.log('开始播放')
}),
innerAudioContext.onEnded(() => {
this.setData({
theplay: true
})
})
innerAudioContext.onError((res) => {
console.log(res.errMsg)
})
}
},
//页面被卸载时执行
onUnload: function () {
innerAudioContext.stop()
},
//当点击下一步后如果语音在播放则关闭
onHide: function () {
innerAudioContext.stop()
},
//音爆,单选按钮组
changeMood: function (e) {
this.setData({
ymood: e.detail.value
})
},
//音爆,点爆按钮跳转
detonation: function (e) {
let ymood = this.data.ymood
var wy = 'y'
//将数据保存到本地,保存语音判断
wx.setStorageSync('ymood', ymood)
wx.setStorageSync('wy', wy)
//跳转页面
wx.navigateTo({
url: '../selectbao/selectbao'
})
},
})

完成语音试听页面的制作后,我们现在可以进行录音功能的测试,在语音记录界面中对录音进行授权后,按住录音按钮开始录音,当松开录音按钮后页面会自动跳转到录音试听页面。我们打开云开发控制台查看云存储中的voice文件,可以发现成功保存了一条语音文件,说明录音功能已成功。

项目源码:https://github.com/xiedong2016/dbx
第二章 "我要点爆"微信小程序点爆页面的实现与云函数和云存储的应用的更多相关文章
- 第六章 “我要点爆”微信小程序云开发实例之爆文详情页制作
爆文详情页制作 从首页中数据列表打开相应详情页面的方法: 给数据列表中每个数据项加一个点击事件,同时将当前数据项的id暂时记录在本地,然后跳转到详情页面detail goopen: function ...
- 第一章 “我要点爆”微信小程序云开发之项目建立与我的页面功能实现
第一章 “我要点爆”微信小程序云开发之项目建立与我的页面功能实现 开发环境搭建 使用自己的AppID新建小程序项目,后端服务选择小程序·云开发,点击新建,完成项目新建. 新建成功后跳转到开发者工具界面 ...
- “我要点爆”微信小程序云开发实例
使用云开发进行微信小程序“我要点爆”的制作 下一章:“我要点爆”微信小程序云开发之项目建立与我的页面功能实现 接下来我将对“我要点爆”微信小程序进行完整的开源介绍 小程序名称: 我要点爆 查看方式:从 ...
- (十二)微信小程序实现登陆页面+登陆逻辑
微信小程序实现登陆页面 实现上面两个页面 第一个页面 <view> <!-- 上侧部分 --> <view class="top-view"> ...
- Java Web项目,Android和微信小程序的初始页面配置
Java Web项目 我们在Eclipse里开了Java Web项目之后,Run As Tomcat或者Apache服务器,本地运行,如果直接用http://localhost:8080访问项目,会发 ...
- 完整微信小程序授权登录页面教程
完整微信小程序授权登录页面教程 1.前言 微信官方对getUserInfo接口做了修改,授权窗口无法直接弹出,而取而代之是需要创建一个button,将其open-type属性绑定getUseInfo方 ...
- 微信小程序开发 [02] 页面注册和基本组件
1.页面注册 既然我们希望跳转到新的页面,那自然要新建页面相关的文件才行.在开篇已经讲过,一个小程序页面由四个文件组成,假如我们的页面名为welcome,那么这四个文件则是: welcome.js w ...
- 微信小程序之实现页面缩放式侧滑效果
效果图: 实现原理:点击按钮,往需要动画的div中添加或移除拥有动画效果的class. 由于微信小程序中不能操作page这个根节点,所以,只有用一个div(view)来模仿page根节点. 1.结构 ...
- 手持式停车收费管理系统全套案例,支持车牌识别,包含了android版app,微信小程序查询,响应式管理后台,云端大数据存储
先展示几个app效果图片吧,使用起来非常方便,关联了机器的快捷键操作,操作速度提高了不少,摄像头车牌自动识别,车牌识别无网络情况下离线也可以使用 再来一张后台截图,停车场信息完整显示,今日数据实时 ...
随机推荐
- java基础知识查漏 二
一.java基本数据类型所占的内存大小 在Java中一共有8种基本数据类型,其中有4种整型,2种浮点类型,1种用于表示Unicode编码的字符 单元的字符类型和1种用于表示真值的boolean类型.( ...
- r squared
multiple r squared adjusted r squared http://web.maths.unsw.edu.au/~adelle/Garvan/Assays/GoodnessOfF ...
- 当半导体的工艺制程走到7nm后
https://mp.weixin.qq.com/s/LjFTtEKFX2o8kLjn3y6GbQ 深度学习的异构加速技术1:效率因通用而怠,构架为AI而生 一方面,当半导体的工艺制程走到7nm后,已 ...
- BZOJ3627: [JLOI2014]路径规划
BZOJ3627: [JLOI2014]路径规划 Description 相信大家都用过地图上的路径规划功能,只要输入起点终点就能找出一条最优路线.现在告诉你一张地图的信息,请你找出最优路径(即最短路 ...
- imagemap的推荐使用方法,前端自适应image maps库
1.map在浏览器的兼容性相对来说是比较好的,这是我在项目中的一个处理方法 推荐到下面网站去画map http://imagemap-generator.dariodomi.de/ 2.画完去gith ...
- R in Action(1) 基本数据结构
一数据类型 R的数据类型包括数值型.字符型.逻辑型(布尔).复数型和原生型,同时R有好多存储数据的对象类型,包括标量.向量.矩阵.数组.数据框和列表,如下图所示下图(图的版权神马的归原作者跟原出版社所 ...
- Machine Learning No.1: Linear regression with one variable
1. hypothsis 2. cost function: 3. Goal: 4. Gradient descent algorithm repeat until convergence { (fo ...
- 浅淡!important对CSS的重要性
SS中的!important是一个非常重要的属性,有时候发挥着非常大的作用,52CSS.com这方面的知识并不是非常多,我们看下面的文章,对它作比较感观的了解. 前几天写一些CSS代码的时候又难为我了 ...
- Gym - 100676E —— 基础题
题目链接:https://odzkskevi.qnssl.com/1110bec98ca57b5ce6aec79b210d2849?v=1490453767 题解: 这种方法大概跟离散化扯上点关系:首 ...
- Java聊天室[长轮询]
今天看到有人分享java实现的聊天室,想起很久以前还在热衷于java的时候也做过一个web聊天室,不拿出来晒晒,可能再也不为人知了,单纯是一个兴趣作品,稳定性不好,也没有考虑连接数和并发的问题,拿出来 ...