微信小程序实训|基于云数据库的语文听写工具(代码片段)

TiAmozhang TiAmozhang     2022-11-29     676

关键词:

 本实训项目结合云开发的云数据库和 “微信同声传译”插件,制作一个可真实运营的小学生语文听写工具,页面效果如图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*90px'>
            <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+135rpx;' 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()函数实现文字转语音,并在该页面实现了上下切换和重复播放功能。

基于云开发的微信小程序实战教程(代码片段)

基于云开发的微信小程序实战教程(二)上篇文章中,简单介绍了下小程序云开发的概念,还有开发工具的安装和配置,云开发环境已经搭建完毕。本章主要内容:微信开发者工具如何使用,小程序云... 查看详情

基于云开发的微信小程序实战教程(代码片段)

基于云开发的微信小程序实战教程(二)上篇文章中,简单介绍了下小程序云开发的概念,还有开发工具的安装和配置,云开发环境已经搭建完毕。本章主要内容:微信开发者工具如何使用,小程序云... 查看详情

基于云开发的微信小程序实战教程(代码片段)

上篇文章中,简单介绍了下微信开发者工具是怎么去用的,还介绍了项目的基础目录结构,以及每个文件的作用,还配带了一些例子说明。最后还剩下cloudfunctions目录,也就是云开发的文件夹介绍。本章主要内... 查看详情

基于云开发的微信小程序实战教程(代码片段)

上篇文章中,简单介绍了下微信开发者工具是怎么去用的,还介绍了项目的基础目录结构,以及每个文件的作用,还配带了一些例子说明。最后还剩下cloudfunctions目录,也就是云开发的文件夹介绍。本章主要内... 查看详情

基于云开发的微信小程序实战教程(代码片段)

上篇文章中,简单介绍了下微信开发者工具是怎么去用的,还介绍了项目的基础目录结构,以及每个文件的作用,还配带了一些例子说明。最后还剩下cloudfunctions目录,也就是云开发的文件夹介绍。本章主要内... 查看详情

基于云开发的微信小程序实战教程(代码片段)

上篇文章中,简单介绍了下微信开发者工具是怎么去用的,还介绍了项目的基础目录结构,以及每个文件的作用,还配带了一些例子说明。最后还剩下cloudfunctions目录,也就是云开发的文件夹介绍。本章主要内... 查看详情

微信小程序notes|常用开发事例基于云平台导出excel(代码片段)

历史文章回顾:微信小程序|开发常用事例(一)微信小程序|开发常用事例(二)微信小程序Notes|开发常用事例(三)微信小程序Notes|开发常用事例(四)一、前言最近一直... 查看详情

微信小程序-基于云开发cms+vantweapp电商demo来了!(代码片段)

...已经实现的本地页面效果图:由于每个用户只能拥有5个微信小程序,我个人原因只能在之前已经上线的一个小程序《黎族文化传承》中进行修改,也是由于这个小程序是个人类型小程序,我后来加的这些属于电商功能,个人小... 查看详情

基于云开发的微信小程序实战教程

基于云开发的微信小程序实战教程(一)最近刚开发了款小程序,在开发过程中发现,基于云开发的教程资源不是很多,而且很不详细。所以边实战边总结了下云开发的简单教程,希望对你有所帮助。本章... 查看详情

微信小程序云开发1-数据库(代码片段)

微信小程序云开发最重要的有两点:1、云数据库;2、云函数;学会这两点基本就能够进行微信小程序的云开发;首先,我们先看微信小程序云数据库的基本操作:1)打开微信开发者工具,创建一... 查看详情

微信小程序云开发入门教程-全局文件介绍(代码片段)

...的技术概念,但最终在发布成小程序的时候也是按照微信的规范去生成的,把微信开发者工具学会了也可以更深入的了解低代码的相关概念。全局文件小程序中是分为全局和页面级两部分。全局是在 查看详情

微信小程序云开发之云数据操作(代码片段)

本文主要讲述“微信小程序云开发”中的云数据库的用法第一节:小程序云开发之数据库文章目录前言一、小程序云开发数据库与传统SQL数据库有什么区别?二、云数据库开发的使用1.全局APP.js配置2.数据库的创建3.数据... 查看详情

毕业设计微信小程序购物商城系统含代码(代码片段)

文章目录0前言1开发工具2总体架构3项目规划4云数据库5项目解构5.1购买首页5.2商品详情页5.3搜索页5.4品牌分类页5.5筛选排序页6最后0前言Hi,同学们好呀,学长今天带大家做一做小程序开发仿得物微信小程序1开发工具微信... 查看详情

轻松入门微信小程序云开发(详细)(代码片段)

...页面交互JS3、小程序云开发3-1、小程序云开发介绍3-2、云数据库3-3、云函数3-4、云存储(1)3-5、云存储(2)4、电影小程序案例4-1、功能介 查看详情

微信小程序云开发入门教程-服务开通(代码片段)

...介绍一下如何开通云开发。步骤一:开通云开发打开微信开发者工具,可以看到工具栏里有个云开发的图标一开始我的这个图标是灰色的,提示已经授权给第三方,因为我平时喜欢探索一些低代码工具,有时... 查看详情

微信小程序云开发入门教程-服务开通(代码片段)

...介绍一下如何开通云开发。步骤一:开通云开发打开微信开发者工具,可以看到工具栏里有个云开发的图标一开始我的这个图标是灰色的,提示已经授权给第三方,因为我平时喜欢探索一些低代码工具,有时... 查看详情

微信小程序之基于云开发的定时任务实现定时数据汇总

参考技术A定时任务有很多用途,譬如数据汇总产生报表数据、数据清理、文件清理等等。云开发提供了定时触发器功能(triggers),提供了类似unix/Linux下crontab的触发表达式。triggers语法如下:其中name是自定义,config按照cron表达... 查看详情

最新最全的云开发入门教程,微信小程序云开发,云函数,云数据库学习,微信小程序云开发扩展功能学习(代码片段)

写在前面1,讲解视频https://edu.csdn.net/course/detail/265722,配套笔记配套笔记会在csdn上免费给到大家,欢迎关注,笔记会持续更新。https://blog.csdn.net/qiushi_19903,支持石头哥😊3-1,源码和配套资源获取目前... 查看详情