代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满


代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

当前短视频的大爆发,导致几乎所有的App都恨不得加入短视频的圈子中分一杯羹,前有快手抖音打得难舍难分,后有火山西瓜紧随而入。如今的互联网仿佛全民短视频,每一个团队都喜欢通过短视频收集用户的碎片时光,以便分得互联网流量收益,那么我们又如何快速创建属于自己的第一个短视频App呢?

代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

工欲善其事,必先利其器,在开发之前我们首先需要明确使用什么语言,什么框架,什么SDK去打造我们的短视频App,具体如下:

  1. 开发工具:HbuilderX (https://www.dcloud.io/hbuilderx.html)
  2. 开发框架:uni-app (https://uniapp.dcloud.io/)
  3. SDK: 智密原生仿抖音上下滑动插件(https://ext.dcloud.net.cn/plugin?id=5289)

在这里我们选择使用hbx + uni-app的方式,使得整个短视频App的开发更具备灵活性,而js的特殊性让短视频App的迭代更加舒服,选择使用智密原生仿抖音上下滑动插件则进一步简化开发工作,由于智密原生仿抖音上下滑动插件本身附带Demo工程,我们下载之后稍加改造就可以实现属于我们自己的短视频App,站在巨人的肩膀总归能减少我们的工作。

代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

创建短视频Demo项目

首先这里假设开发者已经下载开发工具并且登陆账号,此时打开智密原生仿抖音上下滑动插件的详情页(https://ext.dcloud.net.cn/plugin?id=5289)

代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

点击导入之后,系统将会自动打开hbx,并且提示新建导入项目,导入成功之后开发者将会看到这样的一个目录结构,这我们就创建完成基础项目。

代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

试用插件

创建完成项目之后,根据uniapp的官方要求,我们并不能直接使用插件,我们还需要先申请试用,然后打包自定义基座才可以使用。

代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

点击确认申请试用之后,我们还需要回到hbx中选择云端插件并且打包自定义基座,运行的时候我们也需要选择自定义基座,具体操作如下:

代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

至此我们完成了打包自定义基座以及以自定义基座运行的方式了,接下来就是我们最重要的代码实战阶段了,有需要的记得收藏!


代码实战

首先我们先看一下demo,demo中提供的/pages/ui/index.nvue是ui展示界面,这里我们可以来分析代码的情况,智密科技会划分几个部分,分别给大家分析。

代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

1.界面控件


  
  
    此处可以展示评论内容
  

在这里asv_list_player是展示短视频的主体,用于接受界面控件配置数据以及承载视频播放,上下滑动视频的控件,而bottom-popover是demo内部自带的底部弹出覆盖层,用于展示弹窗业务逻辑。

2.初始化控件

mounted() {
  uni.$on('pause-video', () => {
    this.asvListPlayer.pause()
    this.showBottomPopover = false
  })
  this.$nextTick(e => {
    // 创建jssdk示例
    this.asvListPlayer = new asvListPlayer(this.$refs.listPlayer)
    this.$refs.listPlayer.setScaleMode(0)

    let screenWidth = uni.getSystemInfoSync().screenWidth
    // 这里开始是初始化界面布局信息
    let views = [
      asvListPlayer.getView('rightBox').isLayer().position(['right', 'bottom']).width(60).height('auto').marginRight(15).marginBottom(15)
      .children([
        asvListPlayer.getView('head').isImage().position(['right', 'bottom']).width(50).height(50).marginBottom(245).radius(30).toJSON(),
        asvListPlayer.getView('like').isImage().position(['right', 'bottom']).width(50).height(45).marginBottom(185).radius(0).toJSON(),
        asvListPlayer.getView('likeText').isText().position(['right', 'bottom']).width(50).height(20).marginBottom(165).textAlign('center').fontSize(14).toJSON(),
        asvListPlayer.getView('commit').isImage().position(['right', 'bottom']).width(50).height(50).marginBottom(111).radius(0).toJSON(),
        asvListPlayer.getView('commitText').isText().position(['right', 'bottom']).width(50).height(20).marginBottom(90).textAlign('center').fontSize(14).toJSON(),
        asvListPlayer.getView('share').isImage().position(['right', 'bottom']).width(50).height(50).marginBottom(38).radius(0).toJSON(),
        asvListPlayer.getView('shareText').isText().position(['right', 'bottom']).width(50).height(20).marginBottom(15).textAlign('center').fontSize(14).toJSON(),
      ])
      .toJSON(),
      asvListPlayer.getView('titleBox').isLayer().position(['left', 'bottom']).width(screenWidth * 0.6).height(100).bgc('#55000000').marginLeft(15).marginBottom(15).radius(10)
      .children([
        asvListPlayer.getView('userBox').isLayer().position(['left']).width('100%').height('auto').marginLeft(10).marginTop(10)
        .children([
          asvListPlayer.getView('userIcon').isImage().position('left').width(15).height(15).marginTop(3).radius(10).toJSON(),
          asvListPlayer.getView('userName').isText().position('left').width('100%').height(20).lines(2).color('#ffffff').marginLeft(20).toJSON(),
        ])
        .toJSON(),
        asvListPlayer.getView('title').isText().position('left').width('100%').height('auto').color('#ffffff').marginLeft(10).marginTop(35).marginBottom(10).fontSize(14).marginRight(10).toJSON(),
      ])
      .toJSON(),
    ]
    this.asvListPlayer.setViewConfig({ views })
    // 这是初始化视频数据
    this.onRefresh();
    // 这是初始化控件的监听器
    this.asvListPlayer.on('onClick', this.onClick)
    this.asvListPlayer.on('onLoadMore', this.onLoadMore)
    this.asvListPlayer.on('onRefresh', this.onRefresh)
  })
}

在demo中提供的mounted函数中,主要划分为3个阶段,对于3个阶段的代码注释我已经写在其中了。主要的流程是先使用new asvListPlayer(this.$refs.listPlayer)的方式初始化仿抖音控件,然后通过提供的asvListPlayer.getView的方法构建界面布局对象this.asvListPlayer.setViewConfig将布局信息绑定到控件中,然后通过初始化视频数据和初始化控件监听器完成业务逻辑。

3.初始化视频数据

上面我们提到demo用的是this.onRefresh()初始化视频数据,现在我们上俩段代码解析一下控件初始化视频数据都需要执行那些操作。

onRefresh() {
  this.list = []
  this.presetCur = 0
  var datas = []
  this.genData().forEach(item => {
    let data = asvListPlayer.getItem(item.i)
    .video(item.v)
    .cover(item.c)
    .bindImage('head', 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3533321036,2623280788&fm=15&gp=0.jpg', true)
    .bindImage('like', item.like ? 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/c94c1a75-094a-482a-9acf-f1eefbd24792.png':'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/5a17a78c-f923-41f3-8916-271b4d5d528f.png')
    .bindText('likeText', parseInt((item.i * 1 + 1) * (new Date().getTime()) / 1000000000000) + '.4w')
    .bindImage('commit', 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/003910f2-92cf-40c5-9d8a-870401be6e41.png')
    .bindText('commitText', parseInt((item.i * 1 + 1) * (new Date().getTime()) / 10000000000) + '')
    .bindImage('share', 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/353edf1a-c2f1-481a-87fc-b9d5df98fb9e.png')
    .bindText('shareText', '分享')
    .bindText('userName', `UserName`)
    .bindImage('userIcon', 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/89898f94-c3b8-4e14-9d06-7ccb1f27d3ab.png')
    .bindText('title', `这是第${item.i * 1}个视频,悄悄是离别的笙箫,沉默是今晚的康桥,再别康桥,再见我终将逝去的青春,愿一切安好,愿你永远都在。`)
    .toJSON()
    datas.push(data)
  })
  this.asvListPlayer.loadDatas(datas)
}
genData () {
  let len = this.list.length
  let presetDatas = [
    { v: 'http://txfile-30121.sz.gfp.tencent-cloud.com/1603991410685_8240447_29b1d0770d6cdf43a1dd1fd3a992f96f.mp4', c: 'http://txfile-30121.sz.gfp.tencent-cloud.com/1604043258739_635757_8fd725d85d2b42ad1a8d878ef286d0bf.png' },
    { v: 'http://txfile-30121.sz.gfp.tencent-cloud.com/1611758544058_4702548_5047449b104091e5dd3acfa00ed7eb99.mp4', c: 'http://txfile-30121.sz.gfp.tencent-cloud.com/1611758623279_1481920_89d5f27064f39fee56e663b050d28d8c.png' },
    { v: 'http://txfile-30121.sz.gfp.tencent-cloud.com/1604048716240_10046019_6566a337a503919c68f36a9fad9537b0.mp4', c: 'http://txfile-30121.sz.gfp.tencent-cloud.com/1604048732088_557815_c24e7f6276e650174494aa805fd7e45f.jpg' },
    { v: 'http://txfile-30121.sz.gfp.tencent-cloud.com/1604048722437_2185711_6da27ea482ecb28c549250d09c5abdf1.mp4', c: 'http://txfile-30121.sz.gfp.tencent-cloud.com/1604048734024_824230_198eb706d2052ddea6c2814adfe8d798.jpg' },
  ]
  let newDatas = []
  for (let i = len; i < len + 10; i++) {
    let item = JSON.parse(JSON.stringify(presetDatas[this.presetCur]))
    item.i = i + ''
    item.like = item.i % 3 === 0
    newDatas.push(item)
    this.presetCur = this.presetCur + 1
    if (this.presetCur >= presetDatas.length) {
      this.presetCur = 0
    }
  }
  this.list = this.list.concat(newDatas)
  return newDatas
},

结合两段代码我们可以看到,onRefresh函数通过getItem的方法,将获取到的ajax数据构建成为视频对象,然后通过loadDatas方法传入给控件,使得控件可以正常渲染视频,这里我们主要就来看看genData方法:

genData方法采用一个非常简单的方式构造假的ajax数据,这样我们改造起来方便很多,我们只需要把它改成promise的形式,然后通过axios异步获取数据之后重新构造即可,废话不多说,我们直接po出来俩个函数的改造结果。

async onRefresh() {
  uni.showLoading()
  this.list = []
  this.presetCur = 0
  var datas = []
  // 这里注意我没有用try catch,因为我直接用我本地服务器测试的
  let ajaxDatas = await this.genData()
  ajaxDatas.forEach(item => {
    let data = asvListPlayer.getItem(item.i)
    .video(item.v)
    .cover(item.c)
    .bindImage('head', 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3533321036,2623280788&fm=15&gp=0.jpg', true)
    .bindImage('like', item.like ? 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/c94c1a75-094a-482a-9acf-f1eefbd24792.png':'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/5a17a78c-f923-41f3-8916-271b4d5d528f.png')
    .bindText('likeText', parseInt((item.i * 1 + 1) * (new Date().getTime()) / 1000000000000) + '.4w')
    .bindImage('commit', 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/003910f2-92cf-40c5-9d8a-870401be6e41.png')
    .bindText('commitText', parseInt((item.i * 1 + 1) * (new Date().getTime()) / 10000000000) + '')
    .bindImage('share', 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/353edf1a-c2f1-481a-87fc-b9d5df98fb9e.png')
    .bindText('shareText', '分享')
    .bindText('userName', `UserName`)
    .bindImage('userIcon', 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/89898f94-c3b8-4e14-9d06-7ccb1f27d3ab.png')
    .bindText('title', `这是第${item.i * 1}个视频,悄悄是离别的笙箫,沉默是今晚的康桥,再别康桥,再见我终将逝去的青春,愿一切安好,愿你永远都在。`)
    .toJSON()
    datas.push(data)
  })
  this.asvListPlayer.loadDatas(datas)
  uni.hideLoading()
}
async genData () {
  return new Promise(resolve => {
  	let list = await new axios({
    	url: 'http://192.168.0.25:8080/api/getVideoList',
      type: 'post'
    })
    // 这里axios会包一层data,所以需要这样处理
    list = list.data
    let retList = []
    list.forEach(item => {
    	retList.push({ 
        v: item.videoUrl, 
        c: item.coverUrl,
        i: item.id,
        like: item.likes
      })
    })
    resolve(retList)
  })
},

这里通过给两个方法加上async/await,以及给genData加上Promise返回,这样我们就可以无痛地改造让demo支持ajax获取视频数据,对于分页获取,也就是onLoadMore的改造也是如此

4.监听控件点击

mounted () {
	this.asvListPlayer.on('onClick', this.onClick)
}
onClick({ type, data }) {
  uni.showToast({
    icon: 'none',
    position: 'bottom',
    title: '您点击了第' + (data.position + 1) + '个视频的控件,控件名为:' + data.id
  })
  let index = data.position
  let [item] = this.list.filter((R,I) => I === index)
  switch (data.id) {
    case 'like':
      item.like = !item.like
      this.asvListPlayer.setItemData(index,asvListPlayer.getItem(item.i)
                                     .video(item.v)
                                     .cover(item.c)
                                     .bindImage('head', 'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3533321036,2623280788&fm=15&gp=0.jpg', true)
                                     .bindImage('like', item.like ? 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/c94c1a75-094a-482a-9acf-f1eefbd24792.png':'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/5a17a78c-f923-41f3-8916-271b4d5d528f.png')
                                     .bindText('likeText', parseInt((item.i * 1 + 1) * (new Date().getTime()) / 1000000000000) + '.4w')
                                     .bindImage('commit', 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/003910f2-92cf-40c5-9d8a-870401be6e41.png')
                                     .bindText('commitText', parseInt((item.i * 1 + 1) * (new Date().getTime()) / 10000000000) + '')
                                     .bindImage('share', 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/353edf1a-c2f1-481a-87fc-b9d5df98fb9e.png')
                                     .bindText('shareText', '分享66')
                                     .bindText('userName', `UserName`)
                                     .bindImage('userIcon', 'https://files.qiadoo.com/CareBoBo/Common/2021/05/17/89898f94-c3b8-4e14-9d06-7ccb1f27d3ab.png')
                                     .bindText('title', `这是第${item.i * 1}个视频,悄悄是离别的笙箫,沉默是今晚的康桥,再别康桥,再见我终将逝去的青春,愿一切安好,愿你永远都在。`)
                                     .toJSON())
      break
    case 'commit':
      this.showBottomPopover = true
      break
    case 'share':
      uni.showActionSheet({
        itemList: ['分享到微信']
      })
      break
  }
}

在这里的话,控件用的是事件回调的方式,通过onClick返回事件信息,data.id就是我们setViewConfig的时候传入的asvListPlayer.getView('head')这里的字符串,也就是唯一id,我们可以通过id判断用户点击了什么,从而响应对应的事件,甚至是通过setItemData刷新视频的控件布局视频,比如点赞成功之类的。


展示效果

最终部署完后的效果可以参考智密科技之前发布的文章:

如何在Uni-app中快速创建属于自己的第一个短视频App

代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满

智密科技,专业开发各类Uniapp原生插件、目前交付给客户的插件已经超过100个各类插件,正在陆续整理上架并分享一切关于Uni-app的教程、资讯。欢迎加入QQ群与作者一起讨论uni-app!

展开阅读全文

页面更新:2024-03-25

标签:代码   监听器   干货   基座   视频   安好   初始化   控件   函数   实战   布局   插件   框架   界面   方式

1 2 3 4 5

上滑加载更多 ↓
推荐阅读:
友情链接:
更多:

本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828  

© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号

Top