第二章 "我要点爆"微信小程序点爆页面的实现与云函数和云存储的应用

点爆页面的实现与云函数和云存储的应用以及录音功能讲解

点爆页面制作

点爆页面主要提供文字记录和语音记录两种爆文记录方式,在本页面内输入文字或录入语音后选择心情点击点爆按钮,跳转到点爆方式选择界面。

首先,我们来实现页面布局,将文字记录和语音记录使用导航切换的方式放在一个页面内。

导航中在js中设置一个currentTab变量通过数据绑定判断显示文字记录和语音记录的切换,<text class="item {{currentTab==index ? 'active' : ''}}" wx:for="{{navber}}" data-index="{{index}}" wx:key="unique" bindtap="navbarTap">{{item}}</text>,使用列表渲染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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345