关于小程序模仿微信语音发送功能的Wepy代码

<style lang="scss">
page {
  height: 100%;
}

.main {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.output-audio {
  width: 160rpx;
  margin: 5rpx 30rpx;

    .audio {
      position: relative;
      top: 0;
      left: 0;
      height: 28rpx;
      padding: 20rpx;
      border-radius: 35rpx;
      background-color: #226fe3;
      border: 1px solid #f0f0f0;

      .ico {
        width: 26rpx;
        height: 28rpx;
        float: left;
      }

      .time {
        position: absolute;
        top: 18rpx;
        right: -50rpx;
        font-size: 24rpx;
      }
    }
}

.section {
  flex: 0 0 100rpx;
  width: 100%;
  height: 100rpx;
  padding: 15rpx;
  box-sizing: border-box;
  z-index: 1;
  background-color: #ffffff;

  .input-view {
    width: 100%;
    height: 70rpx;

    .input-icon {
      display: inline-block;

      .audio-icon {
        width: 70rpx;
        height: 70rpx;
      }
    }

    .audio-btn {
      display: inline-block;
      width: 700rpx;
      height: 70rpx;
      font-size: 32rpx;
      color: #747474;
      background-color: #f7f6f6;
      line-height: 70rpx;
      margin: 0 auto;
    }
  }
}
</style>
<template>
  <view class="main">

    <!-- 录音音频区 -->
    <block
      wx:for="{{audioArr}}"
      wx:key="content"
      wx:for-item="item"
      wx:for-index="index"
      data-state="{{item.state}}"
    >
      <view class="output-audio" style="width: {{item.time < 8 ? 64 : item.time * 8}}rpx;">
        <view class="audio" wx:if="{{item.state==false}}" data-index="{{index}}" @tap="audioPlay">
          <image
            class="ico"
            src="../images/play-icon.png"
          />
          <label class="time">{{item.time}}"</label>
        </view>

        <view class="audio" wx:if="{{item.state==true}}" data-index="{{index}}" @tap="audioStop">
          <image
            class="ico"
            src="../images/play-icon-gif.gif"
          />
          <label class="time">{{item.time}}"</label>
        </view>
      </view>
    </block>
    <!-- 录音点击区域 -->
    <view class="section">
      <view class="input-view">
        <button
          class="audio-btn"
          @longpress="handleRecordStart"
          @touchend="handleRecordStop"
          @touchmove="handleTouchMove"
        >{{text}}</button>
      </view>
    </view>
  </view>
</template>

<script>
import wepy from "wepy";
import qiniuUploader from "../common/qiniuUploader.js"; // 七牛Js

export default class Index extends wepy.page {
  config = {
    navigationBarTitleText: "语音测试",
    navigationBarBackgroundColor: "#181b24",
    navigationBarTextStyle: "white"
  };

  mixins = [];

  data = {
    showAudioState: false, // 是否显示底部按住说话状态
    recorderManager: null, // 录音对象
    innerAudioContext: null, // 音频对象
    text: "按住 说话", // 按钮文本
    options: {
      duration: 10000, //指定录音的时长,单位 ms
      sampleRate: 16000, //采样率
      numberOfChannels: 1, //录音通道数
      encodeBitRate: 96000, //编码码率
      format: "mp3", //音频格式,有效值 aac/mp3
      frameSize: 50 //指定帧大小,单位 KB
    },
    startPoint: {}, //记录长按录音开始点信息,用于后面计算滑动距离。
    touchLengt: 0, // 上滑的距离
    audioArr: [
      {
        src: "http://mp3.djwma.com/mp3/爆袭全站欢快节奏感觉那是杠杠滴.mp3",
        time: 30,
        state: false
      },
      {
        src: "http://mp3.djwma.com/mp3/好听的欧美男声 网络流行.mp3",
        time: 50,
        state: false
      }
    ] // 音频数据数组
  };

  computed = {};

  methods = {
    // 是否显示底部按住说话
    showAudio () {
      this.showAudioState = !this.showAudioState
      this.$apply()
    },

    // 触摸按住说话进行录音
    handleRecordStart(e) {
      this.touchLengt = 0;
      this.startPoint = e.touches[0];
      this.text = "松开结束";
      this.$apply();
      this.recorderManager.start(this.options); //开始录音
      this.recorderManager.onStart(() => {
        console.log("已经开始了哦~");
      });
      wepy.showToast({
        title: "正在录音,上划取消发送",
        icon: "none",
        duration: 60000 //先定义个60秒,后面可以手动调用wx.hideToast()隐藏
      });
    },

    // 松开触摸按住说话进行判断是否发送或取消
    handleRecordStop() {
      if (this.touchLengt > 50) {
        this.recorderManager.stop();
        this.recorderManager.onStop(res => {
          console.log("停止录音", res.tempFilePath);
        });
        this.text = "按住说话";
        wepy.hideToast(); //结束录音、隐藏Toast提示框
      } else {
        this.recorderManager.stop();
        this.recorderManager.onStop(res => {
          const { tempFilePath } = res; // 获得临时音频链接
          const duration = Math.ceil(res.duration / 1000) // 计算出时长
          this.audioArr.push({ // 添加到音频展示列表中
            src: tempFilePath,
            time: duration,
            state: false
          });
          this.setData({
            audioArr: this.audioArr
          });
          // 以下是上传到服务器的代码,如七牛
          // let audioURL = ''
          // API.getQiniuToken().then(data => { // 七牛请求获得token校验
          //   qiniuUploader.upload(tempFilePath, (res) => {
          //       audioURL = 'https://...(这里写域名)' + res.key
          //       this.audioArr.push({
          //         src: audioURL,
          //         time: duration,
          //         state: false
          //       });
          //       this.setData({
          //         audioArr: this.audioArr
          //       });
          //     }, (error) => {
          //       console.error('error: ' + JSON.stringify(error));
          //     },
          //     {
          //       uptoken: data.token,
          //       region: 'ECN', // 华东区
          //       key: `slls/audio/${Math.random().toString(36).slice(2,10)}_${Date.parse(new Date())}.mp3` // 音频路径命名
          //     },
          //     // (progress) => {
          //     //   console.log('上传进度', progress.progress)
          //     //   console.log('已经上传的数据长度', progress.totalBytesSent)
          //     //   console.log('预期需要上传的数据总长度', progress.totalBytesExpectedToSend)
          //     // },
          //   );
          // })
        });
        this.text = "开始录音";
        wepy.hideToast(); //结束录音、隐藏Toast提示框
      }
    },

    // 监听触摸向上滑动距离
    handleTouchMove(e) {
      const moveLenght =
        e.touches[e.touches.length - 1].clientY - this.startPoint.clientY; //移动距离
      if (Math.abs(moveLenght) > 50) {
        wepy.showToast({
          title: "松开手指,取消发送",
          icon: "none",
          duration: 60000
        });
        this.touchLengt = Math.abs(moveLenght);
        console.log(this.touchLengt);
      } else {
        wepy.showToast({
          title: "正在录音,上划取消发送",
          icon: "none",
          duration: 60000
        });
      }
    },

    //音频播放
    audioPlay(e) {
      const index = e.currentTarget.dataset.index;
      const audioArr = this.audioArr;
      this.innerAudioContext.autoplay = true;
      this.innerAudioContext.src = audioArr[index].src;

      // 切换显示状态
      for (let i = 0; i < audioArr.length; i++) {
        audioArr[i].state = false;
      }
      audioArr[index].state = true;

      this.innerAudioContext.play();
      //开始监听
      this.innerAudioContext.onPlay(() => {
        this.setData({
          audioArr: audioArr
        });
      });

      //结束监听
      this.innerAudioContext.onEnded(() => {
        audioArr[index].state = false;
        this.setData({
          audioArr: audioArr
        });
      });
      console.log("1", audioArr[index].src);
    },
    // 音频停止
    audioStop(e) {
      const index = e.currentTarget.dataset.index;
      const audioArr = this.audioArr;
      //切换显示状态
      for (let i = 0; i < audioArr.length; i++) {
        audioArr[i].state = false;
      }
      audioArr[index].state = false;

      this.innerAudioContext.stop();
      //开始监听
      this.innerAudioContext.onStop(() => {
        audioArr[index].state = false;
        this.setData({
          audioArr: audioArr
        });
      });

      //结束监听
      this.innerAudioContext.onEnded(() => {
        audioArr[index].state = false;
        this.setData({
          audioArr: audioArr
        });
      });
      console.log("2", audioArr);
    }
  };

  events = {};

  onLoad(options) {
    this.recorderManager = wepy.getRecorderManager();
    this.innerAudioContext = wepy.createInnerAudioContext();
    this.$apply();
  }
}
</script>

附带七牛上传的JS如下:

// created by gpake
(function() {

var config = {
    qiniuRegion: '',
    qiniuImageURLPrefix: '',
    qiniuUploadToken: '',
    qiniuUploadTokenURL: '',
    qiniuUploadTokenFunction: null,
    qiniuShouldUseQiniuFileName: false
}

module.exports = {
    init: init,
    upload: upload,
}

// 在整个程序生命周期中,只需要 init 一次即可
// 如果需要变更参数,再调用 init 即可
function init(options) {
    config = {
        qiniuRegion: '',
        qiniuImageURLPrefix: '',
        qiniuUploadToken: '',
        qiniuUploadTokenURL: '',
        qiniuUploadTokenFunction: null,
        qiniuShouldUseQiniuFileName: false
    };
    updateConfigWithOptions(options);
}

function updateConfigWithOptions(options) {
    if (options.region) {
        config.qiniuRegion = options.region;
    } else {
        console.error('qiniu uploader need your bucket region');
    }
    if (options.uptoken) {
        config.qiniuUploadToken = options.uptoken;
    } else if (options.uptokenURL) {
        config.qiniuUploadTokenURL = options.uptokenURL;
    } else if(options.uptokenFunc) {
        config.qiniuUploadTokenFunction = options.uptokenFunc;
    }
    if (options.domain) {
        config.qiniuImageURLPrefix = options.domain;
    }
    config.qiniuShouldUseQiniuFileName = options.shouldUseQiniuFileName
}

function upload(filePath, success, fail, options, progress, cancelTask) {
    if (null == filePath) {
        console.error('qiniu uploader need filePath to upload');
        return;
    }
    if (options) {
      updateConfigWithOptions(options);
    }
    if (config.qiniuUploadToken) {
        doUpload(filePath, success, fail, options, progress, cancelTask);
    } else if (config.qiniuUploadTokenURL) {
        getQiniuToken(function() {
            doUpload(filePath, success, fail, options, progress, cancelTask);
        });
    } else if (config.qiniuUploadTokenFunction) {
        config.qiniuUploadToken = config.qiniuUploadTokenFunction();
        if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) {
            console.error('qiniu UploadTokenFunction result is null, please check the return value');
            return
        }
        doUpload(filePath, success, fail, options, progress, cancelTask);
    } else {
        console.error('qiniu uploader need one of [uptoken, uptokenURL, uptokenFunc]');
        return;
    }
}

function doUpload(filePath, success, fail, options, progress, cancelTask) {
    if (null == config.qiniuUploadToken && config.qiniuUploadToken.length > 0) {
        console.error('qiniu UploadToken is null, please check the init config or networking');
        return
    }
    var url = uploadURLFromRegionCode(config.qiniuRegion);
    var fileName = filePath.split('//')[1];
    if (options && options.key) {
        fileName = options.key;
    }
    var formData = {
        'token': config.qiniuUploadToken
    };
    if (!config.qiniuShouldUseQiniuFileName) {
      formData['key'] = fileName
    }
    var uploadTask = wx.uploadFile({
        url: url,
        filePath: filePath,
        name: 'file',
        formData: formData,
        success: function (res) {
          var dataString = res.data
          if(res.data.hasOwnProperty('type') && res.data.type === 'Buffer'){
            dataString = String.fromCharCode.apply(null, res.data.data)
          }
          try {
            var dataObject = JSON.parse(dataString);
            //do something
            var imageUrl = config.qiniuImageURLPrefix + '/' + dataObject.key;
            dataObject.imageURL = imageUrl;
            // console.log(dataObject);
            if (success) {
              success(dataObject);
            }
          } catch(e) {
            console.log('parse JSON failed, origin String is: ' + dataString)
            if (fail) {
              fail(e);
            }
          }
        },
        fail: function (error) {
            console.error(error);
            if (fail) {
                fail(error);
            }
        }
    })

    uploadTask.onProgressUpdate((res) => {
        progress && progress(res)
    })

    cancelTask && cancelTask(() => {
        uploadTask.abort()
    })
}

function getQiniuToken(callback) {
  wx.request({
    url: config.qiniuUploadTokenURL,
    success: function (res) {
      var token = res.data.uptoken;
      if (token && token.length > 0) {
        config.qiniuUploadToken = token;
        if (callback) {
            callback();
        }
      } else {
        console.error('qiniuUploader cannot get your token, please check the uptokenURL or server')
      }
    },
    fail: function (error) {
      console.error('qiniu UploadToken is null, please check the init config or networking: ' + error);
    }
  })
}

function uploadURLFromRegionCode(code) {
    var uploadURL = null;
    switch(code) {
        case 'ECN': uploadURL = 'https://up.qbox.me'; break;
        case 'NCN': uploadURL = 'https://up-z1.qbox.me'; break;
        case 'SCN': uploadURL = 'https://up-z2.qbox.me'; break;
        case 'NA': uploadURL = 'https://up-na0.qbox.me'; break;
        case 'ASG': uploadURL = 'https://up-as0.qbox.me'; break;
        default: console.error('please make the region is with one of [ECN, SCN, NCN, NA, ASG]');
    }
    return uploadURL;
}

})();

以上就是全部代码,干货。不多说。

posted @ 2019-11-28 10:33  爱上大树的小猪  阅读(1146)  评论(0编辑  收藏  举报