回顾我们智密科技前面发布的干货代码实操文章,把如何在uni-app中利用《HbuilderX + uni-app + 智密原生仿抖音上下滑动插件》快速创建自己的短视频APP demo,并讲解分析了代码以后呢,一个最基础的短视频APP就可以成功上线了(我们就叫他"瓜皮视频"吧),让我们来看一下瓜皮视频和抖系APP的画面对比吧!(如果你还没看过,戳这里➡️代码实战:10分钟搞定uni-app框架下短视频APP开发,干货满满
实际还是有一些细微的区别的,但是呢相似度和流畅度已经算得上是不错的了。实现了基础的功能,我们不免要看看还有啥功能可以附带上。这里我们看了下,短视频App不免在视频页增加了“小红包”和“购物车”的功能,这是两个流量收割利器,这里我们接着上回的项目,继续来扩展功能。
小红包 界面分析
智密原生仿抖音上下滑动插件使用的是给asv_list_player组件传入控件配置的方式去控制原生控件的展示,所以界面上很简单只有这写代码
<template> <view> <asv_list_player ref="listPlayer" class="player"></asv_list_player> <bottom-popover v-if="showBottomPopover" ref="popover" @close="onClosePopover"> <t-pop-commit-list></t-pop-commit-list> </bottom-popover> </view> </template>
实现小红包
在这里我们实现“小红包”的功能固然也可以使用传入控件配置的方式,但是考虑到还有红包进度条以及控制显隐,这里我们可以用nvue布局,自己实现一个红包控件,上代码
<template> <view> <asv_list_player ref="listPlayer" class="player"></asv_list_player> <!-- 这下面就是我们新增的红包控件,为了方便我们使用了简单的组件,圈圈 + 红包 --> <view class="float-red-paper"> <image class="float-red-paper-elem" mode="widthFix" src="../../static;></image> </view> <bottom-popover v-if="showBottomPopover" ref="popover" @close="onClosePopover"> <t-pop-commit-list></t-pop-commit-list> </bottom-popover> </view> </template>
.float-red-paper { position: fixed; top: 80px; left: 15px; width: 60px; height: 60px; align-items: center; justify-content: center; background-color: rgba(0, 0, 0, 0.6); border-radius: 100%; } .float-red-paper-elem { width: 40px; }
在这里需要注意几点,首先nvue的控件是从上到下依次从前到后的层级排序的,并且无法通过zindex调整元素层级,因此我们插入“小红包”要在asv_list_player之后。css的话不支持层级语法,因此这里我们还是采用BEM命名的方式来写样式。现在我们看看加上“小红包”的效果,虽然这里我们还没添加完点击事件啥的,后面再来补充嘛。
购物车 界面分析
实现完成了小红包,接下来我们要实现购物车的功能,因为这里购物车是可能每个视频都会有的,并且每个视频关联的数据可能不一样,因此我们直接通过插件自带的配置JSON来处理。
在这里我们构思的是将购物车设置在昵称简介下面,也就是绿色的区域,然后将昵称信息向上调整,也就是蓝色区域。
实现购物车
首先我们改造之前得先看一下原先的配置。
a('titleBox').isLayer().position(['left', 'bottom']).width(screenWidth * 0.6).height(100).bgc('#55000000').marginLeft(15).marginBottom(15).radius(10) .children([ a('userBox').isLayer().position(['left']).width('100%').height('auto').marginLeft(10).marginTop(10) .children([ a('userIcon').isImage().position('left').width(15).height(15).marginTop(3).radius(10).toJSON(), a('userName').isText().position('left').width('100%').height(20).lines(2).color('#ffffff').marginLeft(20).toJSON(), ]) .toJSON(), a('title').isText().position('left').width('100%').height('auto').color('#ffffff').marginLeft(10).marginTop(35).marginBottom(10).fontSize(14).marginRight(10).toJSON(), ]) .toJSON(),
在原先的配置中,昵称信息这里是距离底部15px,也就是如下代码。
a('titleBox').isLayer().position(['left', 'bottom']).width(screenWidth * 0.6).height(100).bgc('#55000000').marginLeft(15).marginBottom(15)
而我们需要给购物车留出大概40像素的地方,再加上上下间隔之后,我们把这块的15px调整成为75px就可以完美留出来购物车的地方,如下所示。
a('titleBox').isLayer().position(['left', 'bottom']).width(screenWidth * 0.6).height(100).bgc('#55000000').marginLeft(15).marginBottom(75)
然后我这里直接给出购物车部分相关的代码,首先是json配置部分:
a('goodCar').isLayer().position(['left', 'bottom']).width(110).height(40).bgc('#55000000').marginLeft(15).marginBottom(15).radius(30) .children([ a('goodCarImage').isImage().position(['left']).width(30).height(30).marginTop(5).marginLeft(5).toJSON(), a('goodCarText').isText().position(['left']).width(80).height(30).marginLeft(45).marginTop(5).lines(1).fontSize(16).color('#ffffff') ]) .toJSON()
这里我们设计大概是110px的宽度,然后购物车标记是30px,留出来80px左右的位置提供给视频,这里就先写上购物车三个字,然后这里我在给绑定数据部分的代码。
().forEach(item => { let data = a) .video) .cover) .bindImage('head', ';fm=15&gp=0.jpg', true) .bindImage('like', i ? ';:';) .bindText('likeText', parseInt( * 1 + 1) * (new Date().getTime()) / 1000000000000) + '.4w') .bindImage('commit', ';) .bindText('commitText', parseInt( * 1 + 1) * (new Date().getTime()) / 10000000000) + '') .bindImage('share', ';) .bindText('shareText', '分享') .bindText('userName', `UserName`) .bindImage('userIcon', ';) .bindText('title', `这是第${i * 1}个视频,悄悄是离别的笙箫,沉默是今晚的康桥,再别康桥,再见我终将逝去的青春,愿一切安好,愿你永远都在。`) .bindImage('goodCarImage', ';) .bindText('goodCarText', '购物车') .toJSON() da(data) })
这里新增的关键就是最后俩个,也就是下面俩个:
.bindImage('goodCarImage', ';) .bindText('goodCarText', '购物车')
不得不说,插件本身已经帮我们做好大量配置的工作了,这里我只需要bindImage和bindText就可以将购物车标记的图片和文字绑定完成啦。虽然这里我们还没有绑定事件,但是长城也不是一日建成的,一步步扩展功能呗。先看看效果图。
虽然不能说很完美,但是已经开始有那味道了,现在我把改造一半的代码直接给大家,有意思的可以继续接着扩展我们的瓜皮视频哦。
<template> <view> <asv_list_player ref="listPlayer" class="player"></asv_list_player> <view class="float-red-paper"> <image class="float-red-paper-elem" mode="widthFix" src="../../static;></image> </view> <bottom-popover v-if="showBottomPopover" ref="popover" @close="onClosePopover"> <t-pop-commit-list></t-pop-commit-list> </bottom-popover> </view> </template> <script> import asvListPlayer from '.; import bottomPopover from '.; import tPopCommitList from '../../components/nPopCommitList' export default { components: { bottomPopover, tPopCommitList }, data() { return { asvListPlayer: false, viewHeight: uni.getSystemInfoSync().windowHeight - 50, presetCur: 0, list: [], loading: false, showBottomPopover: false } }, onShow () { && .play() }, mounted() { uni.$on('pause-video', () => { .pause() = false }) //初始化 this.$nextTick(e => { = new asvListPlayer(this.$re) // this.$re.setScaleMode(0) let screenWidth = uni.getSystemInfoSync().screenWidth let views = [ a('rightBox').isLayer().position(['right', 'bottom']).width(60).height('auto').marginRight(15).marginBottom(15) .children([ a('head').isImage().position(['right', 'bottom']).width(50).height(50).marginBottom(245).radius(30).toJSON(), a('like').isImage().position(['right', 'bottom']).width(50).height(45).marginBottom(185).radius(0).toJSON(), a('likeText').isText().position(['right', 'bottom']).width(50).height(20).marginBottom(165).textAlign('center').fontSize(14).toJSON(), a('commit').isImage().position(['right', 'bottom']).width(50).height(50).marginBottom(111).radius(0).toJSON(), a('commitText').isText().position(['right', 'bottom']).width(50).height(20).marginBottom(90).textAlign('center').fontSize(14).toJSON(), a('share').isImage().position(['right', 'bottom']).width(50).height(50).marginBottom(38).radius(0).toJSON(), a('shareText').isText().position(['right', 'bottom']).width(50).height(20).marginBottom(15).textAlign('center').fontSize(14).toJSON(), ]) .toJSON(), a('titleBox').isLayer().position(['left', 'bottom']).width(screenWidth * 0.6).height(100).bgc('#55000000').marginLeft(15).marginBottom(75).radius(10) .children([ a('userBox').isLayer().position(['left']).width('100%').height('auto').marginLeft(10).marginTop(10) .children([ a('userIcon').isImage().position('left').width(15).height(15).marginTop(3).radius(10).toJSON(), a('userName').isText().position('left').width('100%').height(20).lines(2).color('#ffffff').marginLeft(20).toJSON(), ]) .toJSON(), a('title').isText().position('left').width('100%').height('auto').color('#ffffff').marginLeft(10).marginTop(35).marginBottom(10).fontSize(14).marginRight(10).toJSON(), ]) .toJSON(), a('goodCar').isLayer().position(['left', 'bottom']).width(110).height(40).bgc('#55000000').marginLeft(15).marginBottom(15).radius(30) .children([ a('goodCarImage').isImage().position(['left']).width(30).height(30).marginTop(5).marginLeft(5).toJSON(), a('goodCarText').isText().position(['left']).width(80).height(30).marginLeft(45).marginTop(5).lines(1).fontSize(16).color('#ffffff') ]) .toJSON() ] con(views) .setViewConfig({ views }) (); .on('onClick', ) .on('onLoadMore', ) .on('onRefresh', ) }) }, methods: { uuid() { var s = []; var hexDigits = "0123456789abcdef"; for (var i = 0; i < 36; i++) { s[i] = () * 0x10), 1); } s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010 s[19] = ((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01 s[8] = s[13] = s[18] = s[23] = "-"; var uuid = s.join(""); return uuid; }, genData () { let len = let presetDatas = [ { v: ';, c: '; }, { v: ';, c: '; }, { v: ';, c: '; }, { v: ';, c: '; }, ] let newDatas = [] for (let i = len; i < len + 10; i++) { let item = JSON.parse(presetDatas[])) i = i + '' i = i % 3 === 0 newDa(item) = + 1 if ( >= ) { = 0 } } = .concat(newDatas) return newDatas }, onRefresh() { = [] = 0 var datas = [] ().forEach(item => { let data = a) .video) .cover) .bindImage('head', ';fm=15&gp=0.jpg', true) .bindImage('like', i ? ';:';) .bindText('likeText', parseInt( * 1 + 1) * (new Date().getTime()) / 1000000000000) + '.4w') .bindImage('commit', ';) .bindText('commitText', parseInt( * 1 + 1) * (new Date().getTime()) / 10000000000) + '') .bindImage('share', ';) .bindText('shareText', '分享') .bindText('userName', `UserName`) .bindImage('userIcon', ';) .bindText('title', `这是第${i * 1}个视频,悄悄是离别的笙箫,沉默是今晚的康桥,再别康桥,再见我终将逝去的青春,愿一切安好,愿你永远都在。`) .bindImage('goodCarImage', ';) .bindText('goodCarText', '购物车') .toJSON() da(data) }) .loadDatas(datas) }, onLoadMore() { if ) { return } = true var datas = [] ().forEach(item => { let data = a) .video) .cover) .bindImage('head', ';fm=15&gp=0.jpg', true) .bindImage('like', i ? ';:';) .bindText('likeText', parseInt( * 1 + 1) * (new Date().getTime()) / 1000000000000) + '.4w') .bindImage('commit', ';) .bindText('commitText', parseInt( * 1 + 1) * (new Date().getTime()) / 10000000000) + '') .bindImage('share', ';) .bindText('shareText', '分享') .bindText('userName', `UserName`) .bindImage('userIcon', ';) .bindText('title', `这是第${i * 1}个视频,悄悄是离别的笙箫,沉默是今晚的康桥,再别康桥,再见我终将逝去的青春,愿一切安好,愿你永远都在。`) .toJSON() da(data) }) .loadMoreDatas(datas) setTimeout(e => { = false }, 1000) }, onClick({ type, data }) { uni.showToast({ icon: 'none', position: 'bottom', title: '您点击了第' + + 1) + '个视频的控件,控件名为:' + da }) let index = da let [item] = .filter((R,I) => I === index) switch (da) { case 'like': i = !i .setItemData(index,a) .video) .cover) .bindImage('head', ';fm=15&gp=0.jpg', true) .bindImage('like', i ? ';:';) .bindText('likeText', parseInt( * 1 + 1) * (new Date().getTime()) / 1000000000000) + '.4w') .bindImage('commit', ';) .bindText('commitText', parseInt( * 1 + 1) * (new Date().getTime()) / 10000000000) + '') .bindImage('share', ';) .bindText('shareText', '分享66') .bindText('userName', `UserName`) .bindImage('userIcon', ';) .bindText('title', `这是第${i * 1}个视频,悄悄是离别的笙箫,沉默是今晚的康桥,再别康桥,再见我终将逝去的青春,愿一切安好,愿你永远都在。`) .toJSON()) break case 'commit': = true break default: uni.showActionSheet({ itemList: ['分享到微信'] }) break } }, onClosePopover (e) { = false } } } </script> <style> .player { position: fixed; top: 0; bottom: 0; width: 750rpx; } .float-red-paper { position: fixed; top: 80px; left: 15px; width: 60px; height: 60px; align-items: center; justify-content: center; background-color: rgba(0, 0, 0, 0.6); border-radius: 100%; } .float-red-paper-elem { width: 40px; } </style>
智密科技,专业开发各类Uniapp原生插件、目前交付给客户的插件已经超过100个各类插件,正在陆续整理上架并分享一切关于Uni-app的教程、资讯。欢迎加入QQ群与作者一起讨论uni-app!