该组件封装了图片、视频、语音上传功能,也是最近开发过程中的一个收获,如图:
组件相关代码
uploader.wxml
<scroll-view class="upload-file" scroll-y="true">
<view class="audio-container" wx:if="{{voice}}">
<view class="audio-area" bindtap="voicePlay">
<image src="{{voiceIco}}" mode="widthFix" class="voice-play"></image>
<text class="duration">{{durationShow}}</text>
</view>
</view>
<view class="video-area" wx:if="{{video}}">
<view class="video-container">
<video id="myVideo" class="vd-show" src="{{video.url}}" binderror="videoErrorCallback" show-center-play-btn='true'
show-play-btn="{{true}}" controls picture-in-picture-mode="{{['push', 'pop']}}"
bindenterpictureinpicture='bindVideoEnterPictureInPicture'
bindleavepictureinpicture='bindVideoLeavePictureInPicture'></video>
<view class="del" bindtap="delVideo">
<image src="/images/del.png" class="del-ico"></image>
</view>
</view>
</view>
<view class="image-area" wx:if="{{images.length>0}}">
<block wx:for="{{images}}" wx:key="index">
<view class="up-img">
<image class="uploader-img" src="{{item.url}}" mode="aspectFill"></image>
<view class="del" data-index="{{index}}" bindtap="delThisImg">
<image src="/images/del.png" class="del-ico"></image>
</view>
</view>
</block>
<view class="upload-add" bindtap="uploadImage">
<image class="uploader-img" src="../../images/upadd.png" mode="aspectFill"></image>
</view>
</view>
</scroll-view>
<view class="foot" wx:if="{{send}}">
<view class="upload-area">
<view bindtap="uploadImage" class="up-item">
<image src="../../images/pic.png" mode="widthFix" class="up-ico"></image>
</view>
<view bindtap="uploadVideo" class="up-item">
<image src="../../images/video.png" mode="widthFix" class="up-ico"></image>
</view>
<view bindtap="showAudioIn" class="up-item">
<image src="../../images/icon_voice.png" mode="widthFix" class="up-ico"></image>
</view>
<slot name="at"></slot>
</view>
<slot name="btn"></slot>
</view>
<view class="audio-in" wx:if="{{audioIn}}">
<button bindtouchstart="streamRecord" bindtouchend="streamRecordEnd">按住说话</button>
</view>
uploader.wxss
.foot {
display: flex;
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx;
border-top: 1px solid #eaeaea;
}
.upload-area {
flex: 1;
}
.up-item {
float: left;
margin-right: 30px;
}
.up-ico {
width: 30px;
}
.up-text {
display: block;
font-size: 14px;
}
.audio-in {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 40px;
background-color: #ccc;
}
.image-area {
width: 100%;
}
.image-area:after {
content: "";
display: block;
visibility: hidden;
clear: both;
}
.up-img {
position: relative;
float: left;
margin-right: 8px;
}
.uploader-img {
width: 84px;
height: 84px;
}
.del {
position: absolute;
right: 0;
top: 0;
background-color: rgba(0, 0, 0, 0.8);
width: 20px;
height: 20px;
}
.del-ico {
margin-top: 2px;
margin-left: 2px;
width: 16px;
height: 16px;
}
.upload-add {
float: left;
margin-bottom: 8px;
width: 84px;
height: 84px;
box-sizing: border-box;
background-color: #EDEDEd;
text-align: center;
vertical-align: middle;
}
.audio-container {
width: 100%;
height: 50px;
}
.audio-area {
position: relative;
width: 200px;
height: 36px;
background-color: #21c38f;
border-radius: 18px;
margin-bottom: 10px;
}
.voice-play {
width: 20px;
height: 20px;
margin-top: 8px;
margin-left: 10px;
}
.duration {
position: absolute;
margin-left: 10px;
height: 36px;
line-height: 36px;
font-size: 14px;
font-family: microsoft yahei;
}
.video-container {
width: 60%;
position: relative;
}
.vd-show {
width: 100%;
}
.getted {
color: #222;
max-width: 60%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.upload-file{
height: 300px;
}
uploader.js
const $util = require('../../utils/util.js')
const plugin = requirePlugin("WechatSI")
const manager = plugin.getRecordRecognitionManager()
let app = getApp()
Component({
lifetimes: {
attached: function () {
// 初始化录音
this.initRecord()
this.innerAudioContext = wx.createInnerAudioContext();
this.innerAudioContext.onError(function (res) {
wx.showToast({
title: '语音播放失败',
icon: 'none'
})
})
}
},
options: {
multipleSlots: true
},
/**
* 组件的属性列表
*/
properties: {
images: Array,
video: Object,
voice: Object,
duration: Number,
durationShow: String
},
/**
* 组件的初始数据
*/
data: {
info: null,
recordStatus: false, //录音状态
audioIn: false,
send: true,
images: [],
desc: '',
duration: 0,
voice: null,
video: null,
voiceIco: '../../images/voice.png',
durationShow: ''
},
/**
* 组件的方法列表
*/
methods: {
/**
* 按住按钮开始语音识别
*/
streamRecord: function (e) {
console.log("streamrecord", e)
this.setData({
//录音状态
recordStatus: true
})
//开始识别
manager.start({
lang: 'zh_CN', //识别的语言,目前支持zh_CN en_US zh_HK sichuanhua
duration: 30000, //指定录音的时长,单位ms,最大为60000。如果传入了合法的 duration ,在到达指定的 duration 后会自动停止录音
})
},
/**
* 松开按钮结束语音识别
*/
streamRecordEnd: function (e) {
console.log("streamRecordEnd", e)
manager.stop()
this.hideAudioIn()
},
/**
* 初始化语音识别回调
* 绑定语音播放开始事件
*/
initRecord: function () {
console.log('==语音初始化==', manager)
let that = this
manager.onRecognize = function (res) {
console.log("current result", res.result)
}
manager.onStart = function (res) {
console.log("成功开始录音识别", res)
}
manager.onStop = function (res) {
console.log('..............结束录音')
console.log('录音临时文件地址 -->' + res.tempFilePath);
console.log('录音总时长 -->' + res.duration + 'ms');
console.log('文件大小 --> ' + res.fileSize + 'B');
console.log('语音内容 --> ' + res.result);
if (res.result == '') {
wx.showModal({
title: '提示',
content: '听不清楚,请重新说一遍!',
showCancel: false,
success: function (res) {}
})
return;
}
that.setData({
desc: res.result,
duration: res.duration,
durationShow: $util.formatDuration(res.duration)
})
that.uploadFile('mp3', res.tempFilePath, 'voice')
}
manager.onError = function (res) {
console.error("error msg", res.msg)
}
},
// 上传图片
uploadImage: function () {
let that = this
wx.chooseImage({
success(res) {
const tempFilePaths = res.tempFilePaths
tempFilePaths.forEach((element, index) => {
that.uploadFile('jpg,gif,png', element, 'image')
});
}
})
},
showAudioIn: function () {
this.setData({
audioIn: true,
send: false
})
},
hideAudioIn: function () {
this.setData({
audioIn: false,
send: true
})
},
voicePlay: function () {
let that = this
this.innerAudioContext.src = this.data.voice.url; //链接到音频的地址
this.innerAudioContext.onPlay(() => {
that.setData({
voiceIco: '../../images/play.gif'
})
}); //播放音效
this.innerAudioContext.onEnded(() => {
that.setData({
voiceIco: '../../images/voice.png'
})
});
this.innerAudioContext.play()
},
// 上传视频
uploadVideo: function () {
var that = this;
wx.chooseVideo({
maxDuration: 60,
success: function (res) {
var tempFilePath = res.tempFilePath;
// 上传文件
that.uploadFile('mp4', tempFilePath, 'video')
},
fail: function (e) {
console.error(e);
}
})
},
// 上传文件到服务器
uploadFile: function (uploadExt, path, type) {
let that = this
wx.uploadFile({
url: app.globalData.domain + 'base/upload/index?type=' + uploadExt,
filePath: path,
name: 'file',
formData: {},
success(res) {
let ret = JSON.parse(res.data)
console.log(ret)
if (type == 'image') {
let images = that.data.images
images.push(ret.data)
that.setData({
images: images
})
}
if (type == 'video') {
that.setData({
video: ret.data
})
}
if (type == 'voice') {
that.setData({
voice: ret.data,
})
}
that.triggerEvent("myevent", that.data)
}
})
},
addLocation: function () {
let that = this
qqmapsdk.reverseGeocoder({
success: function (res) {
console.log(res.result);
that.setData({
location: res.result.address,
lat: res.result.location.lat,
lng: res.result.location.lng
})
}
})
},
// 删除上传的图片
delThisImg: function (e) {
let that = this
let images = that.data.images
images.splice(e.currentTarget.dataset.index, 1);
that.setData({
images: images
})
that.triggerEvent("myevent", that.data)
},
delVideo: function () {
this.setData({
video: null
})
this.triggerEvent("myevent", this.data)
}
}
})
调用组件相关代码
json文件
{
"usingComponents": {
"uploader": "/components/uploader/uploader"
}
}
wxml文件
<uploader images="{{images}}" voice="{{voice}}" duration="{{duration}}" durationShow="{{durationShow}}"
video="{{video}}" bindmyevent="getFiles">
<button slot="btn" class="btn" form-type="submit" size="mini" style="width:60px;">发布</button>
</uploader>
js文件
// 获取上传的文件
getFiles: function(e){
this.setData({
images: e.detail.images,
audio: e.detail.voice,
duration: e.detail.duration,
video: e.detail.video
})
}