1. 上一篇语音播报其实是不完美的,就是如何停止上一个音频开始下一个音频的问题,我在此做一下修改

 比如说:现在正在播放1,我点击2让2开始播放,1停止播放,我上面的写法是有问题的:
- 通过 innerAudioContext.pause() 是可以停止播放音频的;
 - wx.createInnerAudioContext()的实例,我是在readStart方法里面创建的
 - 再次执行readStart方法,会重新创建wx.createInnerAudioContext()实例
 - 我们如果在点击播放图标的时候执行pause() 方法,执行的不是正在播放的音频的实例
 
因此:我们需要创建一个全局的实例,这样我们执行pause() 方法时,在同一个实例下,就是停止正在播放的音频
 代码如下:
	data:{
	dialogue:'您好,我是您的健康管家"向我提问。您好,我是您的健康管家"质迹"!您有什么疑问都可以在此向我提问。',
	type:'play'
	}
	// 在onLoad中创建一个全局的实例
	onLoad(){
		this.innerAudioContext = wx.createInnerAudioContext();
	}
  // 阅读文字
  readText: async function () {
    const that = this;
    // ------------------------------在点击播放图标之前,我们先执行一个pause()方法,停止上一段音频--------------------
    that.innerAudioContext.pause()
    that.setData({
      type :'pause'
    })
    // 将文字按照每200个长度截取成一段,组成一个数组
    // 切片处理,将超过1000个字符的文字,截取成几段
    let list =this.splitStringByLength(dialogue, 200)
    // 循环遍历数组,将文字转化成音频
    let radioList = list.map(el => {
      return new Promise(resolve => {
        plugin.textToSpeech({
          lang: "zh_CN",
          tts: true,
          content: el,
          success: function (res) {
            resolve(res.filename)
          },
          fail: function (res) {
            wx.showToast({
              title: '语音转换失败',
            })
          }
        })
      })
    })
    // 将promise执行结果放在一起执行(解决for循环中有异步操作的方法之一,经典面试题)
    // 有个弊端: 如果前面的promise有一个执行错误,Promise.all就不会执行,因此:可以用map/filter将radioList过滤一遍(本项目中有一个Promise执行失败,就应该失败)
    Promise.all(radioList).then(res => {
      that.readStart(res)
    })
  },
	// 将字符串每隔length个就截取一段
   splitStringByLength :function (str, length)  {
	  let result = [];
	  for (let i = 0; i < str.length; i += length) {
	    result.push(str.substring(i, i + length));
	  }
	  return result;
	},
	// 开始阅读
  readStart: async function (radioList) {
    const that = this
    for (let text of radioList) {
    // --------------------------在此就不需要再次创建实例了---------------------------
      // const innerAudioContext = wx.createInnerAudioContext();
      that.innerAudioContext.src = text;
      that.innerAudioContext.onPlay(() => {
        console.log('开始播放当前片段', 'onPlay');
      });
      that.innerAudioContext.onError((err) => {
        console.error('音频播放出错', err);
      });
      that.innerAudioContext.onEnded(async () => {
        // 如果是最后一个片段,这里可以结束,否则不需要await
        if (text === radioList[radioList.length - 1]) {
          that.setData({
            type: 'play',
          })
        }
      });
      // 确保前一个音频播放结束后再播放下一个
      await new Promise(resolve => {
        that.innerAudioContext.onEnded(resolve);
        that.innerAudioContext.play();
      });
    }
  },
  // 暂停阅读
  readPause: function () {
    this.innerAudioContext.pause()
    const that = this;
    that.setData({
      type: 'play',
    })
  }
 
2. 对于splitStringByLength方法,我也进行了一些优化 (wx.createInnerAudioContext()只支持1000个字符以内的文字转为音频)
下面一段代码是无脑按照长度切割,在进行语音播报的时候,第一段语音和第二段语音之前的衔接会有1-2秒的停顿,语音播报不流畅
 比如:您好,我是您的健康管家"向我提问。您好,我是您的健康 | 管家"质迹"!您有什么疑问都可以在此向我提问。
 在 | 处切成两段,语音在播放到‘康’的时候,会停顿1-2秒,在开始播放‘管家…’
splitStringByLength :function (str, length)  {
	  let result = [];
	  for (let i = 0; i < str.length; i += length) {
	    result.push(str.substring(i, i + length));
	  }
	  return result;
	},
 
在此,我对切割方法进行了一下优化
- 不超过length的长度,不进行切割
 - 超过length的长度,首先找中文句号,在中文句号处切割
 - 如果整个文本都没有中文句号,则在中文逗号处切割
 - 语音在逗号和句号处本来就是会停顿的,在此处切割,这样用户的体验更好一些
 
const splitStringByLength = (text, length) => {
  const MAX_LENGTH = length;  // 最大长度
  const CHINESE_PERIOD = '。'; // 首个切割条件
  const CHINESE_COMMA = ',';  // 当首个切割条件不存在时的次要切割条件
  let result = [];
  let startIndex = 0;
  // 文本长度不超过最大长度,就不切割,直接返回
  if (text.length < MAX_LENGTH) {
    return [text]
  }
  while (startIndex < text.length) {
    // 查找下一个中文句号的位置,若找不到则返回-1
    let periodIndex = text.indexOf(CHINESE_PERIOD, startIndex);
    if (periodIndex === -1 || periodIndex - startIndex > MAX_LENGTH) {
      // 如果没有找到句号,或者句号距离起始点超过了300个字符
      // 则查找中文逗号的位置,同样,若找不到则返回-1
      let commaIndex = text.lastIndexOf(CHINESE_COMMA, startIndex + MAX_LENGTH);
      if (commaIndex === -1 || commaIndex <= startIndex) {
        // 如果也没有找到逗号,或者逗号位置不满足条件,则直接在MAX_LENGTH处截断
        result.push(text.substring(startIndex, startIndex + MAX_LENGTH));
        startIndex += MAX_LENGTH;
      } else {
        // 找到了逗号并且位置合适,就在逗号后分割
        result.push(text.substring(startIndex, commaIndex + 1));
        startIndex = commaIndex + 1;
      }
    } else {
      // 找到了句号并且位置合适,就在句号后分割
      result.push(text.substring(startIndex, periodIndex + 1));
      startIndex = periodIndex + 1;
    }
  }
  return result;
}
                


















