?本實(shí)訓(xùn)項(xiàng)目結(jié)合云開(kāi)發(fā)的云數(shù)據(jù)庫(kù)和 “微信同聲傳譯”插件,制作一個(gè)可真實(shí)運(yùn)營(yíng)的小學(xué)生語(yǔ)文聽(tīng)寫(xiě)工具,頁(yè)面效果如圖1所示。
?▍圖1 “聽(tīng)寫(xiě)小助手”頁(yè)面
基于云開(kāi)發(fā)的微信小程序具有眾多優(yōu)勢(shì),云開(kāi)發(fā)模式真正解放了開(kāi)發(fā)者,使得開(kāi)發(fā)效率大大提升,其模式下的小程序開(kāi)發(fā)和交付流程也更加便捷;云開(kāi)發(fā)建立了小程序端通向騰訊云和小程序端通向微信的捷徑,也為連接其他更多的騰訊云資源提供了捷徑,還可以打通云到云、端到端的界限,其計(jì)算資源計(jì)費(fèi)更合理,成本也更低。
在小程序互聯(lián)網(wǎng)飛速發(fā)展的時(shí)代,教育場(chǎng)景被重塑,教育類(lèi)小程序迎來(lái)猛增。2020年的新冠疫情為在線教育帶來(lái)了新活力,推動(dòng)了用戶對(duì)在線教育的需求。因此,本團(tuán)隊(duì)基于在線教育需求研發(fā)了“聽(tīng)寫(xiě)好助手”這款小程序。
“聽(tīng)寫(xiě)好助手”是一個(gè)以語(yǔ)文為核心,以微信小程序?yàn)榇翱?,以學(xué)生及其家長(zhǎng)為服務(wù)對(duì)象的全語(yǔ)音化教學(xué)平臺(tái)?!奥?tīng)寫(xiě)好助手”集語(yǔ)音聽(tīng)寫(xiě)、錯(cuò)題分析、每日十詞、復(fù)習(xí)提醒、個(gè)性定制、階段復(fù)習(xí)六項(xiàng)功能于一身,采用語(yǔ)音播報(bào)模式,減少學(xué)生用眼,大大提高了學(xué)生的學(xué)習(xí)效率,同時(shí)也減輕了家長(zhǎng)在為孩子輔導(dǎo)聽(tīng)寫(xiě)作業(yè)上的壓力。
本案例以云開(kāi)發(fā)的云數(shù)據(jù)庫(kù)為基礎(chǔ),制作一個(gè)面向小學(xué)語(yǔ)文聽(tīng)寫(xiě)的微信小程序。
01、開(kāi)發(fā)內(nèi)容
為了實(shí)現(xiàn)“聽(tīng)寫(xiě)小助手”的語(yǔ)音播放功能,需要添加插件“微信同聲傳譯”,具體步驟為:登錄微信平臺(tái),選擇“設(shè)置”→“第三方設(shè)置”→“插件管理”→“搜索插件”并完成添加。添加插件后打開(kāi)“控制臺(tái)”→“數(shù)據(jù)庫(kù)”,將數(shù)據(jù)庫(kù)文件導(dǎo)入數(shù)據(jù)庫(kù),從而完成了小學(xué)六年課后的所有單詞的儲(chǔ)存。最后為了前后端的用戶互動(dòng)需要用云函數(shù)來(lái)進(jìn)行操作,為此要完成同步云函數(shù)列表以及上傳并部署getContent和getUserCollectList云函數(shù)操作,重新編譯后選擇一年級(jí)上冊(cè)的書(shū),即可實(shí)現(xiàn)聽(tīng)寫(xiě)功能。同樣的導(dǎo)入剩余的數(shù)據(jù)庫(kù)集合即可實(shí)現(xiàn)所有書(shū)冊(cè)的聽(tīng)寫(xiě)功能。
聽(tīng)寫(xiě)數(shù)據(jù)單個(gè)集合每條記錄包含的字段,如圖2所示。
▍圖2 rn_11集合導(dǎo)入完成
本案例開(kāi)發(fā)主要包括添加插件、數(shù)據(jù)庫(kù)頁(yè)面、云函數(shù)上傳部署三個(gè)步驟。
1、添加插件
聽(tīng)寫(xiě)好助手的代碼中使用了微信同聲傳譯的插件,這是由于聽(tīng)寫(xiě)好助手需要將存在數(shù)據(jù)庫(kù)中的文字轉(zhuǎn)換成語(yǔ)音,要讓代碼正常跑起來(lái),需要登錄微信公眾平臺(tái),在“設(shè)置”→“第三方設(shè)置”→“插件管理”中,添加插件“微信同聲傳譯”,添加插件后,如圖3所示。
▍圖3添加插件“微信同聲傳譯”
2、頁(yè)面數(shù)據(jù)庫(kù)
添加完插件后再進(jìn)行重新編譯,會(huì)發(fā)現(xiàn)還有報(bào)錯(cuò),原因是云開(kāi)發(fā)數(shù)據(jù)庫(kù)里沒(méi)有需要的課本對(duì)應(yīng)的數(shù)據(jù)記錄,因此需要進(jìn)行數(shù)據(jù)庫(kù)的導(dǎo)入。數(shù)據(jù)庫(kù)文件具體如圖四所示。其中,rn_11對(duì)應(yīng)的是一年級(jí)上冊(cè)的聽(tīng)寫(xiě)數(shù)據(jù),rn_12對(duì)應(yīng)的是一年級(jí)下冊(cè)的聽(tīng)寫(xiě)數(shù)據(jù),以此類(lèi)推。
▍圖4 數(shù)據(jù)庫(kù)文件
3、云函數(shù)的上傳部署
右擊cloudfunctions,選擇“同步云函數(shù)列表”,完成同步云函數(shù)列表以及上傳并部署getContent和getUserCollectList云函數(shù)操作,重新編譯后選擇一年級(jí)上冊(cè)的書(shū),即可實(shí)現(xiàn)聽(tīng)寫(xiě)功能。同樣的導(dǎo)入剩余的數(shù)據(jù)庫(kù)集合即可實(shí)現(xiàn)所有書(shū)冊(cè)的聽(tīng)寫(xiě)功能,如圖5所示。
▍圖5 同步云函數(shù)列表
02、項(xiàng)目代碼
pages/chooseBook/chooseBook.wxml的代碼如下:
<view id="chooseBook">
<button
class='toCollect'
bindtap='toCollect'
>錯(cuò)題</button>
<button class='button' open-type="feedback">
<icon type="info_circle" color='rgba(255, 0, 0, 0.6)' size="16" style='margin-right:2px;'></icon>
<text class='button_title'>反饋建議</text>
</button>
<view class='tab'>
<scroll-view scroll-x="true" class='tab-nav' scroll-left='{{scrollLeft}}' scroll-with-animation="true">
<view wx:for="{{navlist}}" wx:key="unique" class='{{current==index?"on":""}}' data-current="{{index}}" bindtap='tab'>{{item}}</view>
</scroll-view>
<swiper class='tab-box'zz current="{{current}}" bindchange="eventchange">
<swiper-item wx:for="{{conlist}}" wx:key="unique">
<view class='tip'>左右滑動(dòng)切換哦</view>
<view class="module-container">
<view class="box-wrapper" wx:for="{{item.moudles}}" wx:key="index">
<navigator url="{{item.url}}" hover-class="none">
<view class="servicebox">
<image src="{{item.src}}" class="box-img"/>
<text style='font-size: 35rpx;'>{{item.text}}</text>
</view>
</navigator>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
?pages/chooseBook/chooseBook.js的代碼如下:
const app = getApp()
Page({
data: {
current: 0,//當(dāng)前所在滑塊的 index
navlist: ["一二年級(jí)", "三四年級(jí)", "五六年級(jí)"],
//課本列表
conlist: []
},
//tab切換
tab: function (event) {
this.setData({ current: event.target.dataset.current })
//錨點(diǎn)處理
},
//滑動(dòng)事件
eventchange: function (event) {
this.setData({ current: event.detail.current })
//錨點(diǎn)處理
},
//生命周期函數(shù)--監(jiān)聽(tīng)頁(yè)面加載
onLoad: function (options) {
this.setData({
conlist: [
{
moudles: [
{
url: './chooseLesson/chooseLesson?book=rn_11',
src: '/img/book/ch_rn_11.jpg',
text: '部編版一年級(jí)上冊(cè)'
},
{
url: './chooseLesson/chooseLesson?book=rn_12',
src: '/img/book/ch_rn_12.jpg',
text: '部編版一年級(jí)下冊(cè)'
},
{
url: './chooseLesson/chooseLesson?book=rn_21',
src: '/img/book/ch_rn_21.jpg',
text: '部編版二年級(jí)上冊(cè)'
},
{
url: './chooseLesson/chooseLesson?book=rn_22',
src: '/img/book/ch_rn_22.jpg',
text: '部編版二年級(jí)下冊(cè)'
}
]
},
{
moudles: [
{
url: './chooseLesson/chooseLesson?book=rn_31',
src: '/img/book/ch_rn_31.jpg',
text: '部編版三年級(jí)上冊(cè)'
},
{
url: './chooseLesson/chooseLesson?book=rn_32',
src: '/img/book/ch_rn_32.jpg',
text: '部編版三年級(jí)下冊(cè)'
},
{
url: './chooseLesson/chooseLesson?book=rn_41',
src: '/img/book/ch_rn_41.jpg',
text: '人教版四年級(jí)上冊(cè)'
},
{
url: './chooseLesson/chooseLesson?book=rn_42',
src: '/img/book/ch_rn_42.jpg',
text: '人教版四年級(jí)下冊(cè)'
}
]
},
{
moudles: [
{
url: './chooseLesson/chooseLesson?book=rn_51',
src: '/img/book/ch_rn_51.jpg',
text: '人教版五年級(jí)上冊(cè)'
},
{
url: './chooseLesson/chooseLesson?book=rn_52',
src: '/img/book/ch_rn_52.jpg',
text: '人教版五年級(jí)下冊(cè)'
},
{
url: './chooseLesson/chooseLesson?book=rn_61',
src: '/img/book/ch_rn_61.jpg',
text: '人教版六年級(jí)上冊(cè)'
},
{
url: './chooseLesson/chooseLesson?book=rn_62',
src: '/img/book/ch_rn_62.jpg',
text: '人教版六年級(jí)下冊(cè)'
}
]
},
],
})
},
toCollect: function () {
wx.navigateTo({
url: "../user/collectList/collectList",
})
},
onReady: function () {},
onShow: function () {},
onHide: function () {},
onUnload: function () {},
onPullDownRefresh: function () {},
onReachBottom: function () {},
onShareAppMessage: function () {}
})
?pages/chooseBook/chooseBook.wxss的代碼如下:
.button {
position: fixed;
left: 20rpx;
bottom: 30rpx;
background: #FAF0E6;
border: none;
text-align: left;
margin: 0px;
line-height: 1.6;
border-radius: 0;
}
.button::after {
border: none;
border-radius: 0;
}
.button_title {
font-size: 12px;
color: rgb(114, 112, 112);
}
.toCollect {
position: fixed;
bottom: 100rpx;
right: 40rpx;
font-size: 40rpx;
height: 70rpx;
line-height: 70rpx;
background-color: rgba(255, 213, 124, 0.925);
z-index: 999;
box-shadow: 2px 2px 2px #bbb;
}
/* tab切換效果 */
swiper {
height: 1000rpx;
}
.tab{ padding: 20rpx 0;}
.tab-nav{
height: 80rpx;
line-height: 80rpx;
}
.tab-nav view{
float: left;
height: 80rpx;
line-height: 80rpx;
background: #FAF0E6;
width: 33.33%;
font-size: 30rpx;
text-align: center;
color: #000;
}
.tab-nav view.on{
background: #FAF0E6;
color: rgb(255, 201, 18);
position: relative;
}
.tab-nav view.on:after{
content: "";
display: block;
height: 6rpx;
width: 26px;
background: rgb(243, 189, 10);
position: absolute;
bottom: 2px;
left: calc(50% - 12px);
border-radius: 16rpx;
}
.tip {
color: #aaa;
text-align: center;
font-size: 35rpx;
margin-top: 20rpx;
}
/* 書(shū)本選項(xiàng) */
#chooseBook .module-container {
width: 100%;
display: flex;
flex-wrap:wrap;
box-sizing: border-box;
flex-direction:row;
justify-content: center;
margin-top: 55rpx;
}
#chooseBook .module-container .box-wrapper{
height: 300rpx;
width: 200rpx;
margin: 0 70rpx;
margin-bottom: 95rpx;
}
/* 服務(wù)選項(xiàng) */
#chooseBook .module-container .box-wrapper .servicebox{
display:flex;
flex-direction:column;
justify-content:center;
align-items:center;
text-align: center;
}
#chooseBook .module-container .box-wrapper .servicebox .box-img{
height:250rpx;
width: 100%;
margin-bottom: 10rpx;
box-shadow: 2px 2px 3px #aaa;
}
?代碼講解
chooseBook.js的onLoad()函數(shù)為conlist列表中每個(gè)元素設(shè)置對(duì)應(yīng)的url、src和text內(nèi)容,以此將這些數(shù)據(jù)綁定在chooseBook.wxml中,運(yùn)行程序便可渲染顯示出來(lái)。
pages/chooseBook/chooseLesson/chooseLesson.wxml的代碼如下:
<view id="listen">
<view class='tab'>
<scroll-view scroll-x="true" class='tab-nav' scroll-left='{{scrollLeft}}' scroll-with-animation="true">
<view class='tab-nav-c' style='width:{{conlist.length*90}}px'>
<view wx:for="{{conlist}}" wx:key="unit" class='{{current==index?"on":""}}' data-current="{{index}}" bindtap='tab'>第{{index==0?'一':index==1?'二':index==2?'三':index==3?'四':index==4?'五':index==5?'六':index==6?'七':index==7?'八':index==8?'九':index==9?'十':''}}單元</view>
</view>
</scroll-view>
</view>
<view class='swiper-box'>
<swiper class='swiper' style='height:{{conlist[current].length*150+135}}rpx;' current="{{current}}" bindchange="eventchange">
<swiper-item wx:for="{{conlist}}" wx:key="unit">
<view class='tip'>左右滑動(dòng)切換哦</view>
<view class="module-container">
<view class="box-wrapper" wx:for="{{item}}" wx:key="index">
<view class="text-box">
<text>{{item.title}}</text>
</view>
<view class="img-box" data-content='{{item}}' bindtap='toDetail'>
<image src='/img/listen2.png' mode="widthFix"></image>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
?pages/chooseBook/chooseLesson/chooseLesson.js的代碼如下:
const db = wx.cloud.database();
const _ = db.command;
let plugin = requirePlugin("WechatSI");
let manager = plugin.getRecordRecognitionManager();
const innerAudioContext = wx.createInnerAudioContext();
let that;
let book;
Page({
data: {
current: 0,//當(dāng)前所在滑塊的 index
scrollLeft: -90,//滾動(dòng)條的位置,一個(gè)選項(xiàng)卡寬度是90(自定義來(lái)自css),按比例90*n設(shè)置位置
conlist: [],
},
//tab切換
tab: function (event) {
// console.log(event.target.dataset.current);
this.setData({ current: event.target.dataset.current })
//錨點(diǎn)處理
this.setData({
scrollLeft: event.target.dataset.current * 90 - 90,
})
},
//滑動(dòng)事件
eventchange: function (event) {
console.log(event.detail.current)
this.setData({ current: event.detail.current })
//錨點(diǎn)處理
this.setData({
scrollLeft: event.detail.current * 90 - 90,
})
},
toDetail: function (e) {
let content = '';
let speak = '';
for (let word of e.currentTarget.dataset.content.content) {
content = content + word + '/';
}
if (e.currentTarget.dataset.content.speak) {
for (let word of e.currentTarget.dataset.content.speak) {
speak = speak + word + '/';
}
}
wx.navigateTo({
url: './detail/detail?content=' + content + '&speak=' + speak + '&book=' + book,
})
},
onLoad: function (options) {
wx.showLoading({
title: '加載中',
});
book = options.book;
that = this;
// setNavigationBarTitle
let bookName = '語(yǔ)文';
let bookLevel = {
"11": "一年級(jí)上冊(cè)",
"12": "一年級(jí)下冊(cè)",
"21": "二年級(jí)上冊(cè)",
"22": "二年級(jí)下冊(cè)",
"31": "三年級(jí)上冊(cè)",
"32": "三年級(jí)下冊(cè)",
"41": "四年級(jí)上冊(cè)",
"42": "四年級(jí)下冊(cè)",
"51": "五年級(jí)上冊(cè)",
"52": "五年級(jí)下冊(cè)",
"61": "六年級(jí)上冊(cè)",
"62": "六年級(jí)下冊(cè)",
}
if (book.search("su") != -1) { bookName += '蘇教版' } else if (book.search("zh") != -1) { bookName += '浙教版' } else if (book.search("rn") != -1 && (book.search("4") != -1 || book.search("5") != -1 || book.search("6") != -1)) { bookName += '人教版' } else { bookName += '部編版' }
for (let key in bookLevel) {
if (book.search(key) != -1) {
bookName += bookLevel[key]
}
}
wx.setNavigationBarTitle({
title: bookName
})
let dbBook = book;
let conlist = [];
// 使用云函數(shù),能讀100條
wx.cloud.callFunction({
name: 'getContent',
data: {
dbBook: dbBook
}
}).then(res => {
that.setData({
conlist: res.result
});
wx.hideLoading();
})
},
onReady: function () {
},
onShow: function () {
},
onHide: function () {
},
onUnload: function () {
innerAudioContext.offPlay();
},
onPullDownRefresh: function () {
},
onReachBottom: function () {},
onShareAppMessage: function () {
}
})
?pages/chooseBook/chooseLesson/chooseLesson.wxss的代碼如下:
page?{
??background-color:?#fff;
}
/* tab切換效果 */
.swiper-box?{
??/* overflow-y: scroll; */
??height:?90%;
??position: absolute;
??width:?100%;
}
.swiper?{
??min-height:?100%;
??width:?100%;
??height:?100%;
}
.tip?{
??color:?#888;
??/* border-bottom: 1px solid #f2f2f2; */
??text-align: center;
??font-size:?35rpx;
??line-height:?35rpx;
??padding:?30rpx;
}
scroll-view{
??width:?100%;
??height:?100%;/*動(dòng)態(tài)高度*/
??overflow-y: scroll;
}
/* 頂部tab */
.tab{
??height:?80rpx;
??box-shadow:?0px?2px?3px?#888888;
}
.tab-nav{
??height:?80rpx;
??line-height:?80rpx;
??width:?100%;
??background-color:?#FAF0E6;
}
.tab-nav?.tab-nav-c?view{
??height:?80rpx;
??line-height:?80rpx;
??float: left;
??width:?90px;
??font-size:?30rpx;
??text-align: center;
??color:?#000;
}
.tab-nav?view.on{
??background:?#FAF0E6;
??color:?rgb(255, 201, 18);
??position: relative;
}
.tab-nav?view.on:after{
???content:?"";
???display: block;
???height:?6rpx;
???width:?26px;
???background:?rgb(243, 189, 10);
???position: absolute;
???bottom:?2px;
???left:?32px;
???border-radius:?16rpx;
}
/* 詞語(yǔ) */
#listen?.module-container?{
??width:?100%;
??display: flex;
??flex-wrap:nowrap;
??flex-direction:column;
??justify-content: center;
??align-items: center;
}
#listen?.module-container?.box-wrapper{
??background-color:?#f2f2f2;
??border-bottom:?1px?solid?#c2c2c2;
??display: flex;
??flex-direction: row;
??align-items: center;
??flex-wrap:nowrap;
??width:?100%;
??height:?150rpx;
??justify-content: center;
}
#listen?.module-container?.box-wrapper?.text-box{
??display: flex;
??width:?70%;
??flex-direction: row;
??flex-wrap: wrap;
??justify-content: center;
}
#listen?.module-container?.box-wrapper?.text-box?text{
??font-size:?40rpx;
??text-align: center;
??line-height:?60rpx;
}
#listen?.module-container?.box-wrapper?.img-box?{
??width:?20%;
}
#listen?.module-container?.box-wrapper?.img-box?image?{
??width:?100%;
}
/* 服務(wù)選項(xiàng) */
#listen?.module-container?.box-wrapper?.servicebox{
??display:flex;
??flex-direction:column;
??justify-content:center;
??align-items:center;
??text-align: center;
}
#listen?.module-container?.box-wrapper?.servicebox?.box-img{
??height:250rpx;
??width:?100%;
??margin-bottom:?5rpx;
}
?代碼講解
chooseLesson .js的onLoad()函數(shù)自動(dòng)執(zhí)行對(duì)云數(shù)據(jù)庫(kù)的查詢(xún)操作,獲取到云數(shù)據(jù)庫(kù)中課本的數(shù)據(jù),并賦值給“book”,然后通過(guò)數(shù)據(jù)綁定的方式在chooseLesson.wxml中進(jìn)行渲染顯示。
pages/chooseBook/chooseLesson/detail/detail.wxml的代碼如下:
<view id='detail'>
<van-transition name="fade" duration='1000' show="{{show}}" style="{{i==sum?'display:none':''}}">
<view style="width:80%;margin:0 auto;position:relitive;top:-80rpx;">
<van-steps
steps="{{ steps }}"
active="{{ active }}"
/>
</view>
<view class="page__bd">
<view class="icon-box" bindtap='preWord'>
<image
class='icon'
style=' width: 150rpx;height: 150rpx;'
src="/img/pre.png"
>上一個(gè)</image>
<view class="icon-box__ctn">
<view class="icon-box__title">上一個(gè)</view>
</view>
</view>
<view class="icon-box" bindtap='nextWord'>
<image
class='icon'
src="/img/{{(i==-1?'start':i==sum-1?'end':'next')}}.png"
>下一個(gè)</image>
<view class="icon-box__ctn">
<view class="icon-box__title">下一個(gè)</view>
</view>
</view>
<view class="icon-box" style='margin-bottom: 0;' bindtap='again'>
<image
class='icon'
style=' width: 150rpx;height: 150rpx;'
src="/img/again.png"
>再讀一遍</image>
<view class="icon-box__ctn">
<view class="icon-box__title">再讀一遍</view>
</view>
</view>
</view>
</van-transition>
<view style="{{i<sum?'display:none':''}}">
<view class="weui-cells__title" style="font-size:16px;color:#000;margin-bottom:40rpx;">請(qǐng)校對(duì):</view>
<view class="weui-cells weui-cells_after-title">
<checkbox-group bindchange="checkboxChange">
<label class="weui-cell weui-check__label" wx:for="{{content}}" wx:key="index">
<checkbox class="weui-check" value="{{item.value}}" checked="{{item.checked}}"/>
<view class="weui-cell__hd weui-check__hd_in-checkbox">
<icon class="weui-icon-checkbox_circle" type="circle" size="23" wx:if="{{!item.checked}}"></icon>
<icon class="weui-icon-checkbox_success" type="cancel" size="23" wx:if="{{item.checked}}"></icon>
</view>
<view class="weui-cell__bd">{{item.name}}</view>
</label>
</checkbox-group>
</view>
<view class="weui-btn-area">
<button class="weui-btn" style='background-color:#fff' plain="" type="default" bindtap="submit" disabled='{{submit}}'>提交錯(cuò)題</button>
<button class="weui-btn weui_btn_primary" style='color:#fff;background-color:#33CC99' plain="" type="default" bindtap="submitAndAgain" disabled='{{submit}}'>再聽(tīng)一遍</button>
</view>
</view>
</view>
?pages/chooseBook/chooseLesson/detail/detail.js的代碼如下:
const db = wx.cloud.database();
const _ = db.command;
let plugin = requirePlugin("WechatSI");
let manager = plugin.getRecordRecognitionManager();
const innerAudioContext = wx.createInnerAudioContext();
let that;
let i;
let active;
let oriSpeak;
let oriContent;
let book;
Page({
data: {
i: -1,
sum: 99,
userCollect: [],
content: [],
speak: [],
steps: [],
active: -1,
show: true,
submit: false
},
// 文字轉(zhuǎn)語(yǔ)音(語(yǔ)音合成)
wordToSpeak: function (word) {
let that = this;
plugin.textToSpeech({
lang: "zh_CN",
tts: true,
content: word,
success: function (res) {
console.log(" tts", res)
innerAudioContext.autoplay = true
innerAudioContext.src = res.filename
wx.showLoading({
// 提交時(shí)取消注釋
mask: true,
title: '正在播放',
})
},
fail: function (res) {
console.log("fail tts", res)
}
})
},
// 下一個(gè)
nextWord: function (e) {
active = this.data.active;
i = this.data.i;
this.setData({
active: ++active,
i: i+1
});
that.wordToSpeak(this.data.speak[i+1]);
},
// 上一個(gè)
preWord: function (e) {
i = this.data.i;
i = this.data.i;
if (i > 0) {
this.setData({
active: --active,
i: i - 1
});
that.wordToSpeak(this.data.speak[i-1]);
} else {
wx.showToast({
icon: 'none',
title: '沒(méi)有上一個(gè)了!',
})
}
},
// 重復(fù)
again: function (e) {
i = this.data.i;
if (i > -1) {
that.wordToSpeak(this.data.speak[i]);
} else {
wx.showToast({
icon: 'none',
title: '請(qǐng)先開(kāi)始噢!',
})
}
},
onLoad: function (options) {
oriSpeak = options.speak;
oriContent = options.content;
book = options.book;
let content = [];
let speak = [];
let contentTemp = [];
console.log(options);
that = this;
speak = options.speak.split('/');
speak.pop();
content = options.content.split('/');
content.pop();
this.setData({
sum: content.length,
speak: (speak.length == 0 ? content : speak),
steps: content
})
for (let name of content) {
let o = {};
o['name'] = name;
o['value'] = name;
contentTemp.push(o);
}
that.setData({
content: contentTemp
})
innerAudioContext.onPlay(() => {
console.log('開(kāi)始播放')
})
innerAudioContext.onError((res) => {
if (res) {
console.log(res)
wx.hideLoading(),
wx.showToast({
title: '文本格式錯(cuò)誤',
image: '/images/fail.png',
})
}
})
innerAudioContext.onEnded(function () {
manager.start({
lang: "zh_CN"
})
wx.hideLoading()
})
},
checkboxChange: function (e) {
console.log('checkbox發(fā)生change事件,攜帶value值為:', e.detail.value);
var checkboxItems = this.data.content, values = e.detail.value;
for (var i = 0, lenI = checkboxItems.length; i < lenI; ++i) {
checkboxItems[i].checked = false;
for (var j = 0, lenJ = values.length; j < lenJ; ++j) {
if (checkboxItems[i].value == values[j]) {
checkboxItems[i].checked = true;
break;
}
}
}
this.setData({
content: checkboxItems,
userCollect: e.detail.value
});
},
submit: function () {
this.setData({
submit: true
})
wx.showLoading({
title: '提交中...',
mask:true
})
let userCollectID;
if (that.data.userCollect) {
db.collection('userCollectList').add({
data: {
collect: that.data.userCollect,
book: book,
createTime: db.serverDate()
},
success(res) {
wx.hideLoading();
wx.showToast({
title: '提交成功!',
duration: 3000,
mask: true
})
setTimeout(() => {
wx.navigateBack({
})
}, 1000)
}
})
} else {
wx.hideLoading();
wx.showToast({
title: '提交成功!',
duration: 3000,
mask: true
})
setTimeout(() => {
wx.navigateBack({
})
},1000)
}
},
submitAndAgain: function () {
this.setData({
submit: true
})
wx.showLoading({
title: '提交中...',
mask: true
})
let userCollectID;
if (that.data.userCollect) {
db.collection('userCollectList').add({
data: {
collect: that.data.userCollect,
book: book,
createTime: db.serverDate()
},
success(res) {
wx.hideLoading();
wx.showToast({
title: '提交成功!',
duration: 3000,
mask: true
})
setTimeout(() => {
wx.redirectTo({
url: './detail?content=' + oriContent + '&speak=' + oriSpeak
})
}, 300)
}
})
} else {
wx.hideLoading();
wx.showToast({
title: '提交成功!',
duration: 3000,
mask: true
})
setTimeout(() => {
wx.redirectTo({
url:'./detail?content=' + oriContent + '&speak=' + oriSpeak
})
}, 800)
}
},
onReady: function () {},
onShow: function () {},
onHide: function () {},
onUnload: function () {
innerAudioContext.offPlay();
innerAudioContext.offEnded();
innerAudioContext.offError();
innerAudioContext.stop();
wx.stopBackgroundAudio();
manager.start({
lang: "zh_CN"
})
wx.hideLoading()
},
onPullDownRefresh: function () {},
onReachBottom: function () {},
onShareAppMessage: function () {}
})
pages/chooseBook/chooseLesson/detail/detail.wxss的代碼如下:
#detail {
position: relative;
}
.weui-cell {
width: 40%;
}
checkbox-group {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}
.weui-cell__bd {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
#detail .content-box {
width: 80%;
margin: 0 auto;
margin-top: 220rpx;
display: flex;
align-items: center;
flex-direction: row;
flex-wrap: wrap;
}
#detail .content-box .content {
font-size: 60rpx;
margin: 0 20rpx;
display: line-block;
}
.page__bd {
margin-top: 90rpx;
padding: 0 30px;
text-align: left;
}
.icon-box{
margin-bottom: 80rpx;
display: flex;
align-items: center;
border: 2px solid #FF9933;
border-radius: 80rpx;
box-shadow: 4px 4px 4px #ddd;
background-color: rgba(255, 224, 51, 0.329);
padding: 30rpx 20rpx;
justify-content: center;
}
.icon-box__ctn{
flex-shrink: 100;
}
.icon-box__title{
font-size: 20px;
}
.icon {
width: 250rpx;
height: 250rpx;
margin-right: 30rpx
}
代碼講解文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-404953.html
detail.js獲取到chooseLesson.js傳入的書(shū)本數(shù)據(jù),利用微信同聲傳譯插件提供的功能,調(diào)用wordToSpeak()函數(shù)實(shí)現(xiàn)文字轉(zhuǎn)語(yǔ)音,并在該頁(yè)面實(shí)現(xiàn)了上下切換和重復(fù)播放功能。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-404953.html
到了這里,關(guān)于微信小程序?qū)嵱?xùn)|基于云數(shù)據(jù)庫(kù)的語(yǔ)文聽(tīng)寫(xiě)工具的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!