Here is the code of the music playing details page of Netease cloud applet .

There are several key points in the music playing interface :

  1, Rotation effect of disk and rocker , It's used here css Animation properties for

  2, Music playback and pause , Next song / Implementation of the last song and other playing effects

  3, Style and control of progress bar

  4, Communicate with the music recommendation list page on the previous page , Leveraging subscriptions and publications Pubsub

HTML Code and key points
<!--pages/songDetail/songDetail.wxml--> <view class="songDetailContainer">
<view class="author">{{[0].name}}</view> <view class="circle"></view>
<image class="needle {{isPlay?'needleRotate':''}}"
src="/static/images/song/needle.png"></image> <view class="discContainer {
{isPlay?'discAnimation':''}}"> <image class="disc"
src="/static/images/song/disc.png"></image> <image class="musicImg" src="{
{}}"></image> </view> <!-- Progress bar control area --> <view
class="progressControl"> <text>{{currentTime}}</text> <!-- General progress bar --> <view
class="barControl"> <!-- Real time progress bar --> <view class="audio-currentTime-Bar"
style="width: {{currentWidth + 'rpx'}}"> <!-- Small ball --> <view
class="audio-circle"></view> </view> </view> <text>{{durationTime}}</text>
</view> <!-- Bottom control playback area --> <view class="musicControl"> <text class="iconfont
icon-iconsMusicyemianbofangmoshiShuffle"></text> <text class="iconfont
icon-shangyishou" id="pre" bindtap="handleSwitch"></text> <text class="iconfont
{{isPlay?'icon-zanting': 'icon-bofang'}} big" bindtap="handleMusicPlay"></text>
<text class="iconfont icon-next" id="next" bindtap="handleSwitch"></text> <text
class="iconfont icon-iconsMusicyemianbofangmoshiPlayList"></text> </view>
HTML main points : 


The ternary expression is used here , When isPlay by true Time , rocker , The disk and play button will start the animation , Otherwise, the opposite .

  The animation of the real-time progress bar takes advantage of the changing style of the width of the red real-time progress bar .

 CSS Code and key points
/* pages/songDetail/songDetail.wxss */ @import
"/static/iconfont/iconfont.wxss"; page { height: 100%; } .songDetailContainer{
height: 100%; background: rgba(0,0,0,0.5); display: flex; flex-direction:
column; align-items: center; } /* base */ .circle { position: relative; z-index:
100; width: 60rpx; height: 60rpx; border-radius: 50%; background: #fff; margin:
10rpx 0; } /* rocker */ .needle{ position: relative; z-index: 99; top:-40rpx; left:
60rpx; width:192rpx; height:274rpx; /* Set the center point of rotation first */ transform-origin:40rpx 0;
transform: rotate(-20deg); transition: transform 1s; } /* Joystick animation during playback */
.needleRotate{ transform: rotate(0deg); } /* disk */ .discContainer{ position:
relative; top:-170rpx; width: 598rpx; height: 598rpx; } .discAnimation{
animation: disc 3s linear infinite; animation-delay:1s; } /* @keyframes: Set animation frame
1,from to Use for simple animation , Only start frame and end frame 2, percentage Mostly used for complex animation , The animation is more than two frames */ @keyframes disc{ from{
transform: rotate(0deg); } to{ transform: rotate(360deg); } } .disc{ width:
598rpx; height: 598rpx; } .musicImg{ position: absolute; top:0; right:0;
bottom:0; left:0; margin: auto; width: 370rpx; height: 370rpx; border-radius:
50%; } /* Bottom control area */ .musicControl { position: absolute; bottom: 40rpx; left: 0;
border-top: 1rpx solid #fff; width: 100%; display: flex; } .musicControl text {
width: 20%; height: 120rpx; line-height: 120rpx; text-align: center; color:
#fff; font-size: 50rpx; } .musicControl text.big{ font-size: 80rpx; } /*
Progress bar control area */ .progressControl { position: absolute; bottom: 200rpx; width:
640rpx; height: 80rpx; line-height: 80rpx; display: flex; } .barControl {
position: relative; width: 450rpx; height: 4rpx; background: rgba(0, 0, 0,
0.4); margin: auto; } .audio-currentTime-Bar { position: absolute; top: 0;
left: 0; z-index: 1; height: 4rpx; background: red; } /* Small ball */ .audio-circle {
position: absolute; right: -12rpx; top: -4rpx; width: 12rpx; height: 12rpx;
border-radius: 50%; background: #fff; }
CSS main points : 


It's used here transform animation , First, set the center point of rotation , utilize transform-origin attribute ,  The red box in the picture above represents the range of the rocker picture , Blue dots are the ones that need to be rotated
Center point , Location is x Coordinates are 40rpx, The ordinate is 0. The rocker should rotate counterclockwise from the original picture position 20 degree , So set to transform:rotate(-20deg). add
Transition effect , utilize transition:transform 1s.

The rotation of the disk takes advantage of css Inside animation,linear Representative linearity ,infinite The representative keeps moving .

To animate frames @keyframes, from 0 Degree to 360 degree , Represents the rotation of the disk . 

 JS Code and key points
// pages/songDetail/songDetail.js import request from '../../../utils/request'
import PubSub from 'pubsub-js' import moment from 'moment' // Get global instance const
appInstance = getApp(); Page({ /** * Initial data of the page */ data: { isPlay:false, // Playback status
song:{},// Song detail object musicId:'', // music id musicLink:'',// Music links
currentTime:'00:00',// Real time durationTime:'00:00',// Total time currentWidth:0, // Real time progress bar width
}, /** * Life cycle function -- Listening page loading */ onLoad: function (options) {
//options: Method for receiving route jumps query parameter // Path passing parameters in native applet , There are restrictions on the length of parameters , If the length is too long, it will be automatically intercepted //
console.log(options) // console.log(musicId) let musicId = options.musicId;
this.setData({ musicId }) // Get music details this.getMusicInfo(musicId); /** *
problem : If the user's operating system controls music playback / Pause button , Page don't know , The status of whether the page is playing is inconsistent with the actual music playing status * Solution : *
By controlling the instance of audio backgroundAudioManager To monitor the music pause / suspend */ // Judge whether the music on the current page is playing
if(appInstance.globalData.isMusicPlay && appInstance.globalData.musicId ===
musicId){ // Modify the music playing status of the current page to true this.setData({ isPlay:true }) } // Create instances that control music playback
this.backgroundAudioManager = wx.getBackgroundAudioManager(); // Monitor music playback / suspend / stop it
this.backgroundAudioManager.onPlay(()=>{ // Modify the status of whether the music is played
this.changePlayState(true); // Modify the status of global music playback appInstance.globalData.musicId =
musicId; }); this.backgroundAudioManager.onPause(() => {
this.changePlayState(false); }); this.backgroundAudioManager.onStop(() => {
this.changePlayState(false); }); // Listening music plays naturally
this.backgroundAudioManager.onEnded(() => { // Automatically switch to the next music , And play it automatically
PubSub.publish('switchType','next') // Restore real-time progress bar to 0 this.setData({ currentWidth:0,
currentTime: '00:00' }) }) // Monitor the progress of music playing in real time
this.backgroundAudioManager.onTimeUpdate(()=>{ // Format real-time playback time let currentTime =
moment(this.backgroundAudioManager.currentTime*1000).format('mm:ss') let
currentWidth = this.backgroundAudioManager.currentTime /
this.backgroundAudioManager.duration*450 this.setData({ currentTime,
currentWidth }) }) }, // Function to modify playback status changePlayState(isPlay){ this.setData({
isPlay }) // Modify the status of global music playback appInstance.globalData.isMusicPlay = isPlay; },
// Function to get music details async getMusicInfo(musicId){ let songData = await
request('/song/detail',{ids:musicId}); //songData.songs[0].dt Company ms let
durationTime = moment(songData.songs[0].dt).format('mm:ss') this.setData({
song:songData.songs[0], durationTime }) // Dynamically modify window title wx.setNavigationBarTitle({ }) }, // Click play / Paused callback handleMusicPlay(){ let isPlay =
!; // // Modify the status of whether to play // this.setData({ // isPlay // }) let
{musicId,musicLink} =; this.musicControl(isPlay,musicId,musicLink);
}, // Control music playback / Suspended function async musicControl(isPlay, musicId, musicLink){ if(isPlay){
// Music playing if(!musicLink){ // Get music playback link let musicLinkData = await
request('/song/url', { id: musicId }); musicLink =[0].url;
this.setData({ musicLink }) } this.backgroundAudioManager.src = musicLink;
this.backgroundAudioManager.title =; }else{ // Pause music
this.backgroundAudioManager.pause(); } }, // Click to switch the callback of the previous song and the next song handleSwitch(event){
// Get the type of cut song let type =; // Turn off the currently playing music
this.backgroundAudioManager.stop() // Subscription from recommendsong Page published musicId news
PubSub.subscribe('musicId',(msg,musicId)=>{ // console.log(musicId) // Get music details
this.getMusicInfo(musicId) // Automatically play the switched current music this.musicControl(true,musicId) // Unsubscribe
PubSub.unsubscribe('musicId') }) // Publish message data to recommendSong
PubSub.publish('switchType',type) }, })
JS main points : 

  Put global data in app.js in :


It's used here  

©2019-2020 Toolsou All rights reserved,
C++ of string of compare usage Python Study notes ( one )evo Tool usage problems ——Degenerate covariance rank, Umeyama alignment is not possibleRISC-V_GD32VF103-TIMER0 timer interrupt java Array subscript variable _Java Basic grammar : array be based on stm32 Control four-wheel trolley motor drive ( one ) be based on redis Design of liking function Software engineering career planning mysql Query random data by conditions _MySQL Random query of several qualified records centos7 install RabbitMq