微音阶 技术篇 —— mpvue 微信小程序实战

介绍

项目介绍

WeScale/微音阶 定位为音阶训练小程序,旨在帮助有需要机械记忆音阶的人通过答题强化记忆,希望能帮助到音乐初学者。

一个月前 上线了 1.0 版本,详细的见这个文章

现有模式:

数字简谱-唱名 字母简谱-唱名 数字简谱-字母简谱 五线谱-唱名(新增) 自定义模式(新增

产品展示

扫描下方小程序码或在微信小程序中搜索 微音阶,即可使用。

人员介绍

Myou Aki:明神,北漂前端,总有奇奇怪怪的想法想要实现,适合做产品的前端 Dr.Chan:老陈,后端、前端通吃,长得帅说话又好听的茂名吃货 Jackliu:大坚,产品、伪前端,不想做前端的产品不是好司机

项目统计

预计两周完成,原型给了五线谱模式、三种听音模式,最后耗时三周,值上线五线谱模式。这次版本拉了个分支,总计提交 99次,上线前合并到 develop 分支,目前已发布 v1.1.1 版本,已审核上线。

"项目统计"

项目总结

讲道理,如果只从功能来说,一天就能实现目前版本所要求的。那么,那么久的时间,那么多的 commit 到底是为啥?

重构、抽象代码 lcm的设计(Local Cache Manager) spriteAudio/雪碧音频的尝试 听音模式的设计 性能优化,体验优化

所以,个人项目还是多注重过程吧,时间允许情况下,多review,多尝试。

重构、抽象代码

这部分主要是我来负责,因为第一个版本的代码,现在来看真的是不忍直视,为了追求速度,把所有的业务逻辑代码都写在一起,代码高耦合、低内聚,简直是反面教材。这次事件也充裕,所以就着手重构代码。

js 的抽象
├─common
  ├─icon // svg 图片
  ├─js
  │      api.js // 封装微信请求
  │      audio.js // 封装音频部分通用方法
  │      config.js // 通用参数配置
  │      errorMana.js // 封装错误处理方法
  │      lcm.js // 封装缓存处理方法 (Local Cache Manager)
  │      list-config.js // 列表页参数配置
  │      loading.js // 封装 loading 的通用方法
  │      training.js // training 相关的方法
  │      util.js // 通用方法
  │
  └─stylus // 样式
vue 组件的抽象
├─components
  ├─carom-bar
  │      carom-bar.vue // 连击条 组件
  │
  ├─model-list
  │      model-list.vue // 模式选择列表 组件
  │
  ├─we-countdown
  │      we-countdown.vue // 得分倒计时 组件
  │
  └─we-picker
          we-picker.vue // 选择框 组件

通过这两部分抽象,只需在实际页面按需引入,可以重复使用组件及代码,实现低耦合,高内聚。 对于重构,推荐阅读这篇文章。

lcm的设计(Local Cache Manager)

在这小程序,业务上的需求是:第一次使用需分块下载音频,在播放音频的时候需要本地的 URL 地址,因此下载之后需要记录这个 URL,保存在 localStorage。 并且为了保证当前缓存的音频是最新的,需要缓存版本的判断。

功能:

检查版本是否最新,是则跳过,否则下载最新 清除文件缓存、localStorage 以 block 的方式添加音频下载,并把 URL 保存在 localStorage。 从 localStorage 获取某个 block 下的音频URL

详细文件看代码片段

spriteAudio/雪碧音频的尝试

仔细数了一下这个小程序一共需要的音频多达 36个,包含吉他音的 14个音阶, 钢琴音的 14个音阶、若干个背景音效。一次性下载 36个音频的时间大概需要 15s。

从雪碧图得到灵感,雪碧图是一种常见的前端优化手段,将多个小图合成一张大图,控制显示的位置,通过减少图片请求量达到优化的目的。 类比雪碧图,创造性地脑洞了雪碧音频,将多个小音频拼合成一个大音频,例如将 14个吉他音的音阶拼成一个大音频,在播放的时候设置播放的起始时间与结束时间。减少了请求量和文件处理数量,最终速度快了一倍多。

结果是:在 PC 微信开发工具调试都 OK,但是移动端真机会出现卡顿现象,应该是这个方法对手机性能消耗太高。毕竟微信本来都不支持多声道,我们硬是完成多声道的 hack,最终不得不忍泪放弃这个想法,另寻优化方法。

最后经小伙伴指点,soundSprite 并非原创啊,其实是比较通用的套路,这个在 SoundJS 有实现

性能优化,体验优化

分时按需加载

除了上面提到通过雪碧音频的优化,还提出了分时按需加载的方案。即在使用前预加载对应音频。在本次项目中,首页会下载 三个小音频,根据 lcm 将这三个打包成一个小 block 来管理。耗时大概 1s 左右,完成这三个小音频,首页即可点击播放动画,在动画的这段时间加载吉他音(默认吉他音)的 14个音频与背景音,这两个 block。耗时大概7-8s。动画大概 4-5 s,中间的空窗期基本可以忽略。在设置钢琴音后去加载钢琴音这个 block,耗时大概 3-4s。

通过这种方式,用户基本无感加载时间。但是特殊情况,无法正常下载,也做了 loading动画及 失败提醒、失败重载等处理。

CDN的使用

服务器只有 1M 带宽小水管,多用户同时下载音频必然受到限制,因此,CDN 是个很好的方式处理这种情况。这次备选是七牛云跟阿里云,这里有个坑便是已经在七牛云上加速的域名无法在阿里云上用 CDN ,提了工单才知道,七牛云与阿里云有合作,两个不允许共存。在七牛云已添加CDN的情况下,再去删除也无法彻底删除,只有在阿里云提工单处理。

错误控制台输出

console.error 可以在控制台输出错误信息,但是无法快速定位错误,因此我们要想法子捕捉错误,上报错误,从错误中恢复过来 通过这个 errorMana 可以让错误更好处理

errorMana 了解一下:

export function getErrorMana (errorMap) {
  return {
    errorMap,
    buildError (code, payload) {
      const msg = this.errorMap[code].replace('@{code}', code)
      const error = new Error(msg)
      error.code = code
      error.payload = payload || {}
      return error
    }
  }
}
const errorMana = getErrorMana({
  '-1001': '[lcm:@{code}]: block id is exist',
  '-2001': '[lcm:@{code}]: block load timeout'
})

errorMana.buildError('-1001')

踩到的坑

上个版本 vuex 留下的坑

上个版本说过,用不了 Vuex 的高级函数 ,看 mpvue 的 issue

解决方案: 需要将vuex挂在vue原型下

Vue.prototype.$store = store

然后可以用 Vuex 管理全局状态,当然常见的是封装 异步请求的 ations。

postcss 处理 svg 背景图

之前说过,小程序不能引入本地的背景图片,所以新的解决方案是 用 postcss 插件转 base64。

解决方案:用 postcss-inline-svg 处理 svg 的背景图, 将其转为 base64。

// input
.nav {
    background: svg-inline(img/nav.svg);
}

// output
.nav {
    background: svg-inline("data:image/svg+xml;XXXXXXX");
}

滑块滑动的处理

“谁高谁低”模式中每个作答滑块有上、下滑动两种交互方式,其实现方式是利用到移动端的三个触摸事件: touchstart(触摸时触发)、touchmove(滑动时触发)、touchend(离开屏幕时粗发)去获取event对象的触控坐标属性,通过触摸前后坐标的运算,判断用户是上滑还是下滑,最后根据不同的情况去为滑块添加不同的CSS3特效,使之在视觉上有上下滑的效果。需要注意的是,touchmove事件在滑动的时候会连续地触发,为避免这种情况,需要在touchmove事件回调方法的逻辑处理后去 赋值一个变量作锁定标记,在touchstart和touchmove事件回调方法入口处根据标记是否执行“答题”逻辑,在touchend事件回调方法中赋值解锁标记。以此确保touchmove事件只执行一次,防止误操作。

致谢

致谢所有参与产品、开发、测试,贡献出创意想法与建议的小伙伴。

我们有个小团队,自嘲为“咸鱼科技”,谁说咸鱼不能有梦想,哈哈。我们还需要 UI、运营等,如果你有想法、有创意、有技能可以加入我们的小团队!2333~

文章来源:

Author:大刀分享站-dddog.com.cn
link:https://www.dddog.com.cn/tutorial/wescale-1.1/