小程序网易云(四)
一,视频模块,上一个视频在播放,下一个视频点击播放,上一个视频需要暂停播放
1,1,此时有个bug,点击下一个视频,上一个视频还在继续播放
1.2,wx.createVideoContext(string id, Object this),创建 video 上下文 VideoContext 对象,video 组件的 id,
VideoContext.play()
播放视频
VideoContext.pause()
暂停视频
bindplay, 当开始/继续播放时触发play事件
poster,视频封面的图片网络资源地址或云文件ID(2.3.0)。若 controls 属性值为 false 则设置 poster 无效
button的open-type属性,授权行为,share合法值,触发用户转发
onShareAppMessage(Object object),只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮
监听用户点击页面内转发按钮(button 组件 open-type="share")或右上角菜单“转发”按钮的行为,并自定义转发内容。
1.3,上一个视频在播放,点击下一个视频,上一个视频暂停
<video class="common" id="{{'video'+item.data.vid}}" src="{{item.data.urlInfo.url}}" bindplay="handlePlay" ></video>
js代码,
//用于监视视频的播放状态 handlePlay(event){ //记录当前正在播放的视频的id->vid let vid = event.target.id; // 要过滤当前视频vid,不然当前点击当前视频一直是暂停的 this.videoContext &&vid!==this.data.vid&& this.videoContext.pause(); this.setData({ vid }); //停止上一个视频的播放 //1.拿到上一个视频的videoContext上下文对象 this.videoContext = wx.createVideoContext(vid); // 延迟两秒钟后暂停该视频 // let videoContext = wx.createVideoContext(vid); // setTimeout(videoContext.pause,10000); // console.log(event) // console.log('playing') },
1,4 视频模块,性能优化
同一页面存在多个video时,video无法正常播放一直在加载转圈
不建议同个页面使用多个video组件,建议不超过3个video,如果要实现video列表功能,请进行优化(image列表,选中时将image替换成video)
视频模块(性能优化) 问题:官方建议通个页面不超过3个video组件,但是我们项目中视频列表明显不符合 解决:可以用image列表替换成视频列表,当用户点击某个的image组件的时候在将他切换成video组件,进行视频播放 1)通过给video组件添加标签属性poster,实现视频默认显示某个画面 2)新增一个image组件,显示与视频相同的图片,并设置相同样式 3)页面刚显示时,默认显示image组件,video组件隐藏(image组件和video组件显示切换用状态控制) 4)给image组件绑定点击事件,当用户点击image组件,隐藏当前image组件,显示对应的video组件 5)效果完成,提升用户体验!!! 问题:目前点击image组件会切换显示video组件,但是还需要再点击video组件,才能进行播放 解决:创建videoContext,调用play方法进行,实现video组件自动播放 6)优化代码!!! 需求:将handlePlay与image的handleTrigger合并为一个函数 7)提升用户体验!!! 问题:当前video组件内显示的画面左右有黑色"边框",并未填充完整,与image组件切换时有些突兀 解决方案1(效果较差):将video组件上的标签属性object-fit设置为fill 缺点:会使部分竖屏视频效果会被拉伸是去原有比例,效果较差 解决方案2(效果较好):将video标签宽度和高度的比例设置的跟图片原有高度相同,通过video标签宽度计算高度
当图片的id和video的id相同时,显示video组件。
<view class="videoItem" wx:for="{{videoList}}" wx:key="id"> <video class="common" id="{{'video'+item.data.vid}}" src="{{item.data.urlInfo.url}}" bindplay="handleTrigger" poster="{{item.data.coverUrl}}" wx:if="{{'video'+item.data.vid===vid}}" ></video> <image wx:else class="common" bindtap="handleTrigger" id="{{'video'+item.data.vid}}" src="{{item.data.coverUrl}}"></image>
js, 点击图片切换到video组件时,通过videoContext.play();自动播放
data: { videoGroup:[], id:null, trigger:false, videoList:[], vid: "" }, //用于切换image组件与video组件的函数 handleTrigger(event){ // console.log('handleTrigger'); let vid = event.target.id; // console.log(vid) this.setData({ vid }); // 生成当前图片对应视频的videoContext let videoContext = wx.createVideoContext(vid); //通过videoContext的play方法,控制视频播放 videoContext.play(); },
1.5,视频模块分享功能
视频模块(分享功能) 1)需要注意,由于项目还在开发期间,分享小程序给好友,好友必须要有体验权限才可以点开(可以在小程序开发中心设置) 2)通过给button组件添加标签属性open-type,设置为share,点击之后就会自动触发页面的事件函数onShareAppMessage 3)在onShareAppMessage中,return对象,自定义标题等数据 4)通过event.target的值区分当前的分享功能的来源 到底是点击右上角的分享触发的,还是点击button触发的 1.如果是右上角分享的就显示默认的小程序截图 2.如果是点击button触发的,就分享按钮对应的图片以及标题
button的open-type属性,授权行为,share合法值,触发用户转发 onShareAppMessage(Object object),只有定义了此事件处理函数,右上角菜单才会显示“转发”按钮 监听用户点击页面内转发按钮(button 组件 open-type="share")或右上角菜单“转发”按钮的行为,并自定义转发内容。 from参数, 转发事件来源。 button:页面内转发按钮; menu:右上角转发菜单 此事件处理函数需要 return 一个 Object,用于自定义转发内容
<button open-type="share" data-title="{{item.data.title}}" data-imageurl="{{item.data.coverUrl}}" class="item btn"> <text class="iconfont icon-gengduo"></text> </button>
js代码,获取自定义的属性时,需要小写,比如imageurl
/** * 用户点击右上角分享 */ onShareAppMessage: function (shareObj) { // console.log(shareObj) // 1.通过传入的实参内部的from属性进行判断,区分分享的来源 // button代表button组件,menu代表右上角分享 if(shareObj.from==="button"){ let { title,imageurl } = shareObj.target.dataset; console.log('我是通过button分享的') //通过return一个配置对象,配置分享的内容 return { title, path:"/pages/video/video", imageUrl:imageurl } } else if (shareObj.from === "menu") { console.log('我是通过右上角转发分享的') } }
二,每日推荐模块,数据动态渲染
接口地址 : /recommend/songs 调用例子 : /recommend/songs 注意事项: 需要登录,携带cookie 数据量大,可自行整合 返回数据:
2.1,日期获取
<view class="header"> <image src="/static/images/recommendSong/recommendSong.jpg"></image> <view class="date"> <text class="day">{{day}} /</text> <text class="month">{{month}}</text> </view> </view>
this.setData({ day: new Date().getDate(), month: new Date().getMonth() + 1 })
2.2,发送请求,获取数据
let result = await request('/recommend/songs'); // console.log(result) this.setData({ recommendList: result.recommend })
data: { month:"", day:"", recommendList:[] },
2.3,页面数据渲染
<!-- 音乐列表 --> <scroll-view class="scrollView" scroll-y> <view class="recommendItem" bindtap="toSong" data-id="{{item.id}}" wx:for="{{recommendList}}" wx:key="id"> <!-- data-index="{{index}}" 可行 data-item="{{item}}" 不可行,数据体积太大,转换成json字符串传不过去 --> <image src="{{item.album.picUrl}}"></image> <view class="musicContent"> <text class="musicName">{{item.name}}</text> <text class="author">{{item.artists[0].name}}</text> </view> <view class="radio"> <text class="iconfont icon-gengduo"></text> </view> </view> </scroll-view>
2.4,页面加载音乐列表页,如果没有登录,也就没有携带cookie,需要弹框,指引去登录
wx.showModal(Object object),显示模态对话框(API--界面-交互)
wx.navigateBack(Object object),关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。
只有登录过后,歌曲信息才会请求成功
onLoad: async function (options) { // console.log(new Date().getDate()) // console.log(new Date().getMonth()+1) //获取当前最新时间,并更新到状态中 this.setData({ day: new Date().getDate(), month: new Date().getMonth() + 1 }) // 没有登录过 if(!wx.getStorageSync('cookies')){ wx.showModal({ title:"请先登录", content:"该功能需要登录帐号", cancelText:"回到首页", confirmText:"去登陆", success(res){ // 去登录按钮 if(res.confirm){ wx.redirectTo({ url: '/pages/login/login', }) }else{ wx.navigateBack(); } // console.log(res) } }) } let result = await request('/recommend/songs'); // console.log(result) this.setData({ recommendList: result.recommend }) },
在index页,点击每日推荐按钮,跳转到每日推荐页recommendSong
<view class="headerItem" bindtap="toRecommendSong"> <text class="iconfont icon-meirituijian-"></text> <text>每日推荐</text> </view>
toRecommendSong(){ wx.navigateTo({ url: '/pages/recommendSong/recommendSong' }) },
三,播放歌曲静态页面搭建song以及动态交互
获取音乐详情 必选参数 : ids: 音乐 id, 如 ids=347230 接口地址 : /song/detail 调用例子 : /song/detail?ids=347230 返回数据格式:
在每日推荐歌曲中,点击一条歌曲,跳转到歌曲播放页面,此时需要传递id到歌曲详情页
在推荐歌曲页
<scroll-view class="scrollView" scroll-y> <view class="recommendItem" bindtap="toSong" data-id="{{item.id}}" wx:for="{{recommendList}}" wx:key="id"> <!-- data-index="{{index}}" 可行 data-item="{{item}}" 不可行,数据体积太大,转换成json字符串传不过去 --> <image src="{{item.album.picUrl}}"></image> <view class="musicContent"> <text class="musicName">{{item.name}}</text> <text class="author">{{item.artists[0].name}}</text> </view> <view class="radio"> <text class="iconfont icon-gengduo"></text> </view> </view> </scroll-view>
js代码,query路由传参,有大小限制
每日推荐模块(重点:路由传参) 1)给每个recommendItem绑定tap事件,当点击之后跳转页面至播放歌曲页面 2)当页面进行跳转时候,要显示对应歌曲内容的播放歌曲页面,出现问题!!! 问题1:如何将即将播放歌曲的数据对象,从每日推荐页面传递至播放歌曲页面 解决:以query格式进行路由传参,播放歌曲页面通过onLoad的形参options接收 问题2:经过问题1,我们成功将数据对象传给了播放歌曲页面,但是由于url长度限制,数据无法完整传到播放歌曲页面 解决:思路出错,更换思路 3)由于能传的数据量有限,所以我们将传的数据从歌曲对象换成歌曲的id 4)在播放歌曲页面的onLoad函数中获取到歌曲的id,并发送请求到服务器,请求数据,并保存到状态中 5)使用状态数据实现页面动态渲染,通过wx.setNavigationBarTitle设置播放歌曲页面标题
// 用于跳转详情页面 toSong(event){ let {id} = event.currentTarget.dataset; // console.log('id',id); wx.navigateTo({
url: '/pages/song/song?songId=' + id }) },
在歌曲播放详情页,发送请求,获取歌曲图片,作者数据
wx.setNavigationBarTitle(Object object),动态设置当前页面的标题
onLoad: async function (options) { // 通过options可以拿到query参数 // 1.跳转页面时,通过query传参,对url进行拼接 // 2.在onLoad中的形参options中,可以或得到所有的query键值对 // console.log(options.songId); let {songId} = options; this.setData({ songId }) //1.请求数据 let result = await request('/song/detail', { ids:songId }); // console.log(result) //2.保存至data中 this.setData({ songObj:result.songs[0] }) // 动态设置顶部标题 wx.setNavigationBarTitle({ title: this.data.songObj.name }) //3.动态渲染 },
数据渲染
<view class="songContainer {{isplaying?'isplaying':''}}"> <text class="name">{{songObj.ar[0].name}}</text> <view class="keng"></view> <image class="needle" src="/static/images/song/needle.png"></image> <view class="discContainer"> <image class="disc" src="/static/images/song/disc.png"></image> <image class="discImg" src="{{songObj.al.picUrl}}"></image> </view>
发送请求,获取歌曲音频连接数据
获取歌曲播放地址 必选参数 : id : 音乐 id 接口地址 : /song/url 调用例子 : /song/url?id=33894312
背景音频,BackgroundAudioManager,BackgroundAudioManager 实例,可通过 wx.getBackgroundAudioManager 获取
获取全局唯一的背景音频管理器。 小程序切入后台,如果音频处于播放状态,可以继续播放。但是后台状态不能通过调用API操纵音频的播放状态
string src
音频的数据源(2.2.3 开始支持云文件ID)。默认为空字符串,当设置了新的 src 时,会自动开始播放,目前支持的格式有 m4a, aac, mp3, wav
string title
音频标题,用于原生音频播放器音频标题(必填)。原生音频播放器中的分享功能,分享出去的卡片标题,也将使用该值
boolean paused
当前是否暂停或停止。(只读
BackgroundAudioManager.pause()
暂停音乐
播放歌曲模块(重点:音乐播放) 1)由于我们请求回来的歌曲数据中没有音频资源的地址,所以需要再请求另一个专门用户获取音频资源地址的接口 2)将请求得到的音频资源数据保存至页面状态 3)优化代码!!! 问题:用户可能点击每日推荐的某个选项,但是跳转到song页面之后并不播放 解决:等用户真的有播放歌曲的意愿,再发送请求(点击播放按钮时) 4)通过wx.getBackgroundAudioManager,获得背景音频的播放器实例 5)给实例添加属性src和title,当src的值为新值时候,背景音频会自动播放,出现问题!!! 问题:控制台报错提示,该功能需要配置才能使用 解决:在app.json中配置requiredBackgroundModes属性
<!-- 底部播放选项区域 --> <view class="musicControl"> <text class="iconfont icon-iconsMusicyemianbofangmoshiShuffle" ></text> <text class="iconfont icon-shangyishou" id="pre"></text> <text class="iconfont {{isplaying?'icon-zanting':'icon-bofang'}} big" bindtap="handlePlay"></text> <text class="iconfont icon-next" id="next"></text> <text class="iconfont icon-iconsMusicyemianbofangmoshiPlayList"></text> </view> </view>
js代码
data: { isplaying:false, songId:null, songObj:{}, musicUrl:"" }, async handlePlay() { let musicUrlData = await request('/song/url', { id: this.data.songId }); this.setData({ isplaying: !this.data.isplaying, musicUrl: musicUrlData.data[0].url }) // 获取音频实例 let backgroundAudioManager = wx.getBackgroundAudioManager(); // console.log('paused',backgroundAudioManager.paused); // paused是只读属性,false是正在播放,true代表已停止或者暂停 // paused值在首次读取时,一定是undefined //pause是方法,调用它可以暂停音频 if (backgroundAudioManager.paused || typeof backgroundAudioManager.paused === "undefined") { // 音频连接 backgroundAudioManager.src = this.data.musicUrl; // 音频标题,必传 backgroundAudioManager.title = this.data.songObj.name; } else { // 暂停播放 backgroundAudioManager.pause(); } // this.setData({ // isplaying: !this.data.isplaying // }) },
此时报了个错
在app.json中配置
"requiredBackgroundModes": ["audio"],