写点什么

微信小程序实训|基于云数据库的语文听写工具

作者:TiAmo
  • 2023-01-30
    江苏
  • 本文字数:12714 字

    阅读完需:约 42 分钟

微信小程序实训|基于云数据库的语文听写工具

本实训项目结合云开发的云数据库和 “微信同声传译”插件,制作一个可真实运营的小学生语文听写工具,页面效果如图 1 所示。


▍图 1 “听写小助手”页面

基于云开发的微信小程序具有众多优势,云开发模式真正解放了开发者,使得开发效率大大提升,其模式下的小程序开发和交付流程也更加便捷;云开发建立了小程序端通向腾讯云和小程序端通向微信的捷径,也为连接其他更多的腾讯云资源提供了捷径,还可以打通云到云、端到端的界限,其计算资源计费更合理,成本也更低。

在小程序互联网飞速发展的时代,教育场景被重塑,教育类小程序迎来猛增。2020 年的新冠疫情为在线教育带来了新活力,推动了用户对在线教育的需求。因此,本团队基于在线教育需求研发了“听写好助手”这款小程序。

“听写好助手”是一个以语文为核心,以微信小程序为窗口,以学生及其家长为服务对象的全语音化教学平台。“听写好助手”集语音听写、错题分析、每日十词、复习提醒、个性定制、阶段复习六项功能于一身,采用语音播报模式,减少学生用眼,大大提高了学生的学习效率,同时也减轻了家长在为孩子辅导听写作业上的压力。

本案例以云开发的云数据库为基础,制作一个面向小学语文听写的微信小程序。

01、开发内容

为了实现“听写小助手”的语音播放功能,需要添加插件“微信同声传译”,具体步骤为:登录微信平台,选择“设置”→“第三方设置”→“插件管理”→“搜索插件”并完成添加。添加插件后打开“控制台”→“数据库”,将数据库文件导入数据库,从而完成了小学六年课后的所有单词的储存。最后为了前后端的用户互动需要用云函数来进行操作,为此要完成同步云函数列表以及上传并部署 getContent 和 getUserCollectList 云函数操作,重新编译后选择一年级上册的书,即可实现听写功能。同样的导入剩余的数据库集合即可实现所有书册的听写功能。

听写数据单个集合每条记录包含的字段,如图 2 所示。


▍图 2 rn_11 集合导入完成

本案例开发主要包括添加插件、数据库页面、云函数上传部署三个步骤。

1、添加插件

听写好助手的代码中使用了微信同声传译的插件,这是由于听写好助手需要将存在数据库中的文字转换成语音,要让代码正常跑起来,需要登录微信公众平台,在“设置”→“第三方设置”→“插件管理”中,添加插件“微信同声传译”,添加插件后,如图 3 所示。


▍图 3 添加插件“微信同声传译”

2、页面数据库

添加完插件后再进行重新编译,会发现还有报错,原因是云开发数据库里没有需要的课本对应的数据记录,因此需要进行数据库的导入。数据库文件具体如图四所示。其中,rn_11 对应的是一年级上册的听写数据,rn_12 对应的是一年级下册的听写数据,以此类推。


▍图 4 数据库文件

3、云函数的上传部署

右击 cloudfunctions,选择“同步云函数列表”,完成同步云函数列表以及上传并部署 getContent 和 getUserCollectList 云函数操作,重新编译后选择一年级上册的书,即可实现听写功能。同样的导入剩余的数据库集合即可实现所有书册的听写功能,如图 5 所示。


▍图 5 同步云函数列表

02、项目代码

pages/chooseBook/chooseBook.wxml 的代码如下:

<view id="chooseBook">  <button     class='toCollect'     bindtap='toCollect'  >错题</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'>左右滑动切换哦</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,//当前所在滑块的 index    navlist: ["一二年级", "三四年级", "五六年级"],    //课本列表    conlist: []  },  //tab切换  tab: function (event) {    this.setData({ current: event.target.dataset.current })    //锚点处理  },  //滑动事件  eventchange: function (event) {    this.setData({ current: event.detail.current })    //锚点处理  },  //生命周期函数--监听页面加载  onLoad: function (options) {    this.setData({      conlist: [        {          moudles: [            {              url: './chooseLesson/chooseLesson?book=rn_11',              src: '/img/book/ch_rn_11.jpg',              text: '部编版一年级上册'            },            {              url: './chooseLesson/chooseLesson?book=rn_12',              src: '/img/book/ch_rn_12.jpg',              text: '部编版一年级下册'            },            {              url: './chooseLesson/chooseLesson?book=rn_21',              src: '/img/book/ch_rn_21.jpg',              text: '部编版二年级上册'            },            {              url: './chooseLesson/chooseLesson?book=rn_22',              src: '/img/book/ch_rn_22.jpg',              text: '部编版二年级下册'            }          ]        },        {          moudles: [            {              url: './chooseLesson/chooseLesson?book=rn_31',              src: '/img/book/ch_rn_31.jpg',              text: '部编版三年级上册'            },            {              url: './chooseLesson/chooseLesson?book=rn_32',              src: '/img/book/ch_rn_32.jpg',              text: '部编版三年级下册'            },            {              url: './chooseLesson/chooseLesson?book=rn_41',              src: '/img/book/ch_rn_41.jpg',              text: '人教版四年级上册'            },            {              url: './chooseLesson/chooseLesson?book=rn_42',              src: '/img/book/ch_rn_42.jpg',              text: '人教版四年级下册'            }          ]        },        {          moudles: [            {              url: './chooseLesson/chooseLesson?book=rn_51',              src: '/img/book/ch_rn_51.jpg',              text: '人教版五年级上册'            },            {              url: './chooseLesson/chooseLesson?book=rn_52',              src: '/img/book/ch_rn_52.jpg',              text: '人教版五年级下册'            },            {              url: './chooseLesson/chooseLesson?book=rn_61',              src: '/img/book/ch_rn_61.jpg',              text: '人教版六年级上册'            },            {              url: './chooseLesson/chooseLesson?book=rn_62',              src: '/img/book/ch_rn_62.jpg',              text: '人教版六年级下册'            }          ]        },      ],    })  },  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;}/* 书本选项 */#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;}/* 服务选项 */#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()函数为 conlist 列表中每个元素设置对应的 url、src 和 text 内容,以此将这些数据绑定在 chooseBook.wxml 中,运行程序便可渲染显示出来。

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'>左右滑动切换哦</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,//当前所在滑块的 index    scrollLeft: -90,//滚动条的位置,一个选项卡宽度是90(自定义来自css),按比例90*n设置位置    conlist: [],  },  //tab切换  tab: function (event) {    // console.log(event.target.dataset.current);    this.setData({ current: event.target.dataset.current })    //锚点处理    this.setData({      scrollLeft: event.target.dataset.current * 90 - 90,    })  },  //滑动事件  eventchange: function (event) {    console.log(event.detail.current)    this.setData({ current: event.detail.current })    //锚点处理    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 = '语文';    let bookLevel = {      "11": "一年级上册",      "12": "一年级下册",      "21": "二年级上册",      "22": "二年级下册",      "31": "三年级上册",      "32": "三年级下册",      "41": "四年级上册",      "42": "四年级下册",      "51": "五年级上册",      "52": "五年级下册",      "61": "六年级上册",      "62": "六年级下册",    }    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 = [];    // 使用云函数,能读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%;/*动态高度*/  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;}/* 词语 */#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%;}/* 服务选项 */#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()函数自动执行对云数据库的查询操作,获取到云数据库中课本的数据,并赋值给“book”,然后通过数据绑定的方式在 chooseLesson.wxml 中进行渲染显示。

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"            >上一个</image>            <view class="icon-box__ctn">                <view class="icon-box__title">上一个</view>            </view>        </view>        <view class="icon-box" bindtap='nextWord'>            <image               class='icon'               src="/img/{{(i==-1?'start':i==sum-1?'end':'next')}}.png"            >下一个</image>            <view class="icon-box__ctn">                <view class="icon-box__title">下一个</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;">请校对:</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}}'>提交错题</button>      <button class="weui-btn weui_btn_primary" style='color:#fff;background-color:#33CC99' plain="" type="default" bindtap="submitAndAgain" disabled='{{submit}}'>再听一遍</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  },  // 文字转语音(语音合成)  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({          // 提交时取消注释          mask: true,          title: '正在播放',        })      },      fail: function (res) {        console.log("fail tts", res)      }    })  },  // 下一个  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]);  },  // 上一个  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: '没有上一个了!',      })    }  },  // 重复  again: function (e) {    i = this.data.i;    if (i > -1) {      that.wordToSpeak(this.data.speak[i]);    } else {      wx.showToast({        icon: 'none',        title: '请先开始噢!',      })    }  },  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('开始播放')    })    innerAudioContext.onError((res) => {      if (res) {        console.log(res)        wx.hideLoading(),          wx.showToast({            title: '文本格式错误',            image: '/images/fail.png',          })      }    })    innerAudioContext.onEnded(function () {      manager.start({        lang: "zh_CN"      })      wx.hideLoading()    })  },  checkboxChange: function (e) {    console.log('checkbox发生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}
复制代码

代码讲解

detail.js 获取到 chooseLesson.js 传入的书本数据,利用微信同声传译插件提供的功能,调用 wordToSpeak()函数实现文字转语音,并在该页面实现了上下切换和重复播放功能。

发布于: 刚刚阅读数: 2
用户头像

TiAmo

关注

有能力爱自己,有余力爱别人! 2022-06-16 加入

CSDN全栈领域优质创作者;阿里云创作者社区专家博主、技术博主、星级博主、阿里云ACE;华为云享专家;

评论

发布
暂无评论
微信小程序实训|基于云数据库的语文听写工具_微信小程序_TiAmo_InfoQ写作社区