小程序网易云(四)

一,视频模块,上一个视频在播放,下一个视频点击播放,上一个视频需要暂停播放

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"],
原文地址:https://www.cnblogs.com/fsg6/p/13640493.html