微信小程序:真機調(diào)試,控制播放和停止,promise,旋轉(zhuǎn)動畫,底部導(dǎo)航欄【詩書畫唱】

目錄:
例子1:實現(xiàn)音樂播放器的播放和停止等等的完整功能

要根據(jù)當前playing是ture還是false來控制當前音樂是在播放還是暫停。下面的邏輯是:
點擊播放時,觸發(fā)事件,判斷當前的playing是false,當前不是在播放,!playing是true,那么,觸發(fā)事件后就讓其播放,即playing在setData中重新設(shè)置為true
下面就是用三元表達式控制旋轉(zhuǎn)的樣式是否使用,三元表達式很常用
例子2:解決關(guān)閉后臺的音樂后,界面的圖片不停止旋轉(zhuǎn),并且也沒有顯示停止播放bug。解決翻頁,切換時,讓音樂播放不自動停止的bug

wx:if和hidden的邏輯相反,wx:if為false時隱藏,wx:if為ture時顯示,hidden為false時顯示
例子3:給其添加底部導(dǎo)航欄

例子4:用promise來替換回調(diào)函數(shù)等等的代碼,進行代碼重構(gòu)(解決回調(diào)地獄)

例子5:獲取熱門書籍數(shù)據(jù)

例子6:組件化開發(fā),實現(xiàn)熱門書籍界面的數(shù)據(jù)顯示并且實現(xiàn)樣式

例子7:通過使用查看自己手機的局域網(wǎng)的ip地址的cmd命令,通過修改自己項目中的config.js或其他請求路徑的127.0.0.1變?yōu)?span id="s0sssss00s" class="color-pink-03">自己電腦和手機連的同一個局域網(wǎng)的ip地址(比如
192.168.1.104),來實現(xiàn)掃二維碼就可以真機調(diào)試!

例子1:實現(xiàn)音樂播放器的播放和停止,實現(xiàn)播放時圖片旋轉(zhuǎn)等等的完整功能

要根據(jù)當前playing是ture還是false來控制當前音樂是在播放還是暫停。下面的邏輯是:
點擊播放時,觸發(fā)事件,判斷當前的playing是false,當前不是在播放,!playing是true,那么,觸發(fā)事件后就讓其播放,即playing在setData中重新設(shè)置為true



下面就是用三元表達式控制旋轉(zhuǎn)的樣式是否使用,三元表達式很常用


例子2:解決關(guān)閉后臺的音樂后,界面的圖片不停止旋轉(zhuǎn),并且也沒有顯示停止播放bug。解決翻頁,切換時,讓音樂播放不自動停止的bug




記得判斷非空

wx:if和hidden的邏輯相反,wx:if為false時隱藏,wx:if為ture時顯示,hidden為false時顯示





例子3:給其添加底部導(dǎo)航欄



例子4:用promise來替換回調(diào)函數(shù)等等的代碼,進行代碼重構(gòu)(解決回調(diào)地獄)



例子5:獲取熱門書籍數(shù)據(jù)







例子6:組件化開發(fā),實現(xiàn)熱門書籍界面的數(shù)據(jù)顯示并且實現(xiàn)樣式






例子7:通過使用查看自己手機的局域網(wǎng)的ip地址的cmd命令,通過修改自己項目中的config.js或其他請求路徑的127.0.0.1變?yōu)?span id="s0sssss00s" class="color-pink-03">自己電腦和手機連的同一個局域網(wǎng)的ip地址(比如
192.168.1.104),來實現(xiàn)掃二維碼就可以真機調(diào)試!



config.js中
把
export default {
? base_url: 'http://127.0.0.1:9001/',
? img_url: 'http://127.0.0.1:9001/public/images/',
? music_url: 'http://127.0.0.1:9001/public/music/'
}
改成:
export default {
? base_url: 'http://192.168.1.104:9001/',
? img_url: 'http://192.168.1.104:9001/public/images/',
? music_url: 'http://192.168.1.104:9001/public/music/'
}
就可以點真機調(diào)試,掃二維碼后手機上查看(當然,要確保自己的電腦和自己的手機是連同一個網(wǎng)絡(luò))
(192.168.1.104是局域網(wǎng)的ip地址)
查看自己局域網(wǎng)的ip地址的方法:
用管理員身份打開cmd,輸入ipconfig就可以查看到
?“IPv4 地址 . . . . . . . . . . . . : 192.168.1.104”
?真機調(diào)試時,我的說明文件可能上傳不了,不用管


例子8:具體代碼

<!--components/book/index.wxml-->
<view?class="container">
????<image?class="container-image"?src="{{book.image}}"/>
????<view?class="description">
????????<text?class="title">{{book.title}}</text>
????????<text?class="author">{{book.author}}</text>
????????<view?class="foot">
????????????<text?class="footer">{{book.fav_nums}}?喜歡</text>
????????</view>
????</view>
</view>

/*?components/book/index.wxss?*/
.container?{
??margin-top:?30rpx;
??display:?flex;
??position:?relative;
??box-shadow:?2px?2px?3px?#e3e3e3;
??flex-direction:?column;
??width:?240rpx;
??height:?360rpx;
}
.container-image?{
??width:?100%;
??height:?100%;
??border-radius:?2px;
}
.description?{
??width:?216rpx;
??position:?absolute;
??bottom:?0;
??background-color:?#fff;
??padding:?5rpx?10rpx?8rpx?15rpx;
??font-size:?24rpx;
??display:?flex;
??flex-direction:?column;
??border-bottom-right-radius:?2px;
??border-bottom-left-radius:?2px;
}
.title?{
??margin-top:?10rpx;
??text-overflow:?ellipsis;
??white-space:?nowrap;
??overflow:?hidden;
}
.author?{
??font-size:?20rpx;
??color:?#999999;
??margin-bottom:?10rpx;
??text-overflow:?ellipsis;
??white-space:?nowrap;
??overflow:?hidden;
}
.foot?{
??font-size:?20rpx;
??display:?flex;
??flex-direction:?row;
??justify-content:?flex-end;
}
.footer?{
??color:?#666666;
}

//?components/classic/music/index.js
import?classicBeh?from?'../classic_beh.js'
import?config?from?'../../../config.js'
//獲取音頻管理器對象?START
const?mMgr?=?wx.getBackgroundAudioManager()
//獲取音頻管理器對象?END
Component({
??behaviors:?[classicBeh],
??/**
???*?組件的屬性列表
???*/
??properties:?{
????src:?String,
????title:?String,
??},
??/**
???*?組件的初始數(shù)據(jù)
???*/
??data:?{
????pauseSrc:?'images/player@pause.png',
????playSrc:?'images/player@play.png',
????playing:?false,//是否播放音樂
??},
//后臺播放器和界面播放器同步的是否播放的狀態(tài)的部分?START
??
??lifetimes:?{//組件的生命周期函數(shù)
????attached?()?{//當組件被加載到當前頁面時執(zhí)行
??????this._recoverStatus()
??????this._monitorMmgr()
????}
??},
//后臺播放器和界面播放器同步的是否播放的狀態(tài)的部分?START
??methods:?{
????onPlay?()?{
??????if(!this.data.playing)?{
????????//更新播放狀態(tài)
????????this.setData({
??????????playing:?true
????????})
????????//如果需要播放音樂,只需要設(shè)置mMgr的src和title屬性
????????mMgr.src?=?config.music_url?+?this.properties.src
????????mMgr.title?=?this.properties.title
??????}?else?{//當音樂正在播放時
????????this.setData({
??????????playing:?false
????????})
????????//讓音樂暫停
????????mMgr.pause()
??????}?????
????},
????_recoverStatus()?{//獲取音樂播放器狀態(tài)的函數(shù)
??????if(mMgr.paused)?{
????????this.setData({
??????????playing:?false
????????})
????????return
??????}
??????//如果切換期刊以后播放的音樂就是當前期刊的音樂
??????if(mMgr.src?&&?mMgr.src.includes(this.properties.src))?{
????????this.setData({
??????????playing:?true
????????})
??????}
????},
????_monitorMmgr()?{//給音樂播放器綁定事件
??????//點擊播放時
??????mMgr.onPlay(()?=>?{
????????this._recoverStatus()
??????})
??????//點擊暫停時
??????mMgr.onPause(()?=>?{
????????this._recoverStatus()
??????})
??????//強行關(guān)閉音樂時
??????mMgr.onStop(()?=>?{
????????this._recoverStatus()
??????})
??????//音樂自然播放完成時
??????mMgr.onEnded(()?=>?{
????????this._recoverStatus()
??????})
????}
??}
//后臺播放器和界面播放器同步的是否播放的狀態(tài)的部分?END
})


<!--components/classic/music/index.wxml-->
<view?class="container"?hidden="{{hn}}">
????<!--?<image?src="{{base_img?+?img}}"?class="img"/>?-->
<!--?播放時旋轉(zhuǎn)圖片的設(shè)置?START?-->
????<image?src="{{base_img?+?img}}"?class="img?{{playing???'rotation'?:?''}}"/>
????<!--?播放時旋轉(zhuǎn)圖片的設(shè)置?END?-->
????<image?src="{{playing???pauseSrc?:?playSrc}}"?class="player"?bind:tap="onPlay"/>
????<image?src="./images/music@tag.png"?class="tag"/>
????<text?class="content">{{content}}</text>
</view>

/*?components/classic/music/index.wxss?*/
/*?@import?'../common.wxss'?*/
.container?{
????display:?flex;
????flex-direction:?column;
????align-items:?center;
??}
??.img?{
????width:?422rpx;
????height:?422rpx;
????margin-top:?60rpx;
????border-radius:?50%;
??}
??.player?{
????width:?120rpx;
????height:?120rpx;
????position:?relative;
????bottom:?270rpx;
??}
??.tag?{
????width:?44rpx;
????height:?128rpx;
????position:?relative;
????bottom:?160rpx;
????right:?310rpx;
??}
??
/*音樂播放時的圖片旋轉(zhuǎn)效果*/
.rotation?{
??-webkit-transform:?rotate(360deg);
??animation:?rotation?12s?linear?infinite;
??-moz-animation:?rotation?12s?linear?infinite;
??-webkit-animation:?rotation?12s?linear?infinite;
??-o-animation:?rotation?12s?linear?infinite;
}
@-webkit-keyframes?rotation?{
??from?{
????-webkit-transform:?rotate(0deg);
??}
??to?{
????-webkit-transform:?rotate(360deg);
??}
}

//models/book.js
import?HTTP?from?'../utils/pmsHttp'
import?config?from?'../config'
export?default?class?BookModel?extends?HTTP?{
??getHotList?()?{
????return?this.ajax({
??????url:?`${config.base_url}getHotList`
????})
??}
}

//?pages/book/index.js
import?BookModel?from?'../../models/book'
const?bookModel?=?new?BookModel()
Page({
??/**
???*?頁面的初始數(shù)據(jù)
???*/
??data:?{
????bookList:?[]
??},
??/**
???*?生命周期函數(shù)--監(jiān)聽頁面加載
???*/
??onLoad:?function?(options)?{
????bookModel.getHotList()
??????.then(data?=>?{
????????console.log(data)
????????this.setData({
??????????bookList:?data
????????})
??????})
??},
??/**
???*?生命周期函數(shù)--監(jiān)聽頁面初次渲染完成
???*/
??onReady:?function?()?{
??},
??/**
???*?生命周期函數(shù)--監(jiān)聽頁面顯示
???*/
??onShow:?function?()?{
??},
??/**
???*?生命周期函數(shù)--監(jiān)聽頁面隱藏
???*/
??onHide:?function?()?{
??},
??/**
???*?生命周期函數(shù)--監(jiān)聽頁面卸載
???*/
??onUnload:?function?()?{
??},
??/**
???*?頁面相關(guān)事件處理函數(shù)--監(jiān)聽用戶下拉動作
???*/
??onPullDownRefresh:?function?()?{
??},
??/**
???*?頁面上拉觸底事件的處理函數(shù)
???*/
??onReachBottom:?function?()?{
??},
??/**
???*?用戶點擊右上角分享
???*/
??onShareappMessage:?function?()?{
??}
})

{
??"usingComponents":?{
????"cmp-book":"/components/book"
??}
}

<!--pages/book/index.wxml-->
<!--?<text>pages/book/index.wxml</text>?-->
<view?class="books-container">
????<block?wx:key="id"?wx:for="{{bookList}}">
????????<!--?列表渲染指令wx:for中的循環(huán)變量名就是item?-->
????????<cmp-book?book="{{item}}"?/>
????</block>
</view>

/*?pages/book/index.wxss?*/
.books-container?{
????margin-top:?10rpx;
????display:?flex;
????flex-direction:?row;
????flex-wrap:?wrap;
????justify-content:?space-between;
????padding:?0?90rpx;
??}
??.books-container?cmp-book{
????margin-bottom:?10rpx;
??}

<!--pages/classic/index.wxml-->
<view?class="container">
????<view?class="header">
????????<cmp-epsoide?class="epsoide"?index="{{classicData.index}}"></cmp-epsoide>
????????<!--?下面的話就是調(diào)用了點贊的組件:?-->?????
????????<!--?<cmp-like?count="{{classicData.fav_nums}}"?like="{{classicData.like_status}}"?
????????bind:myLike="onLike"></cmp-like>?-->
????????<!--?關(guān)于更新緩存的fav_num,like_status等的綁定?START?-->
????????<cmp-like?class="like"?count="{{fav_nums}}"?
????????????like="{{like_status}}"?bind:myLike="onLike"></cmp-like>
????????????<!--?關(guān)于更新緩存的fav_num,like_status等的綁定?END?-->
????</view>
????<!--?<cmp-movie?wx:if="{{classicData.image}}"?content="{{classicData.content}}"?
????img="{{classicData.image}}"></cmp-movie>?-->
<!--?3個子組件部分?START?-->
????<cmp-movie?wx:if="{{classicData.content}}"?content="{{classicData.content}}"?
????????img="{{classicData.image}}"?hn="{{classicData.type?!=?100}}"></cmp-movie>
????<cmp-essay?wx:if="{{classicData.content}}"?content="{{classicData.content}}"?
????????img="{{classicData.image}}"?hn="{{classicData.type?!=?300}}"></cmp-essay>
????<!--?<cmp-music?wx:if="{{classicData.image}}"?content="{{classicData.content}}"?
????????img="{{classicData.image}}"?hn="{{classicData.type?!=?200}}"
????????src="{{classicData.url}}"?title="{{classicData.title}}"></cmp-music>?-->
????????<!--?wx:if代替hidden的部分,讓其可以觸發(fā)lifetimes這個生命周期函數(shù)?START?-->
????????<cmp-music?wx:if="{{classicData.content}}"?content="{{classicData.content}}"?
????????img="{{classicData.image}}"?wx:if="{{classicData.type?==?200}}"
????????src="{{classicData.url}}"?title="{{classicData.title}}"></cmp-music>
????????<!--?wx:if代替hidden的部分,讓其可以觸發(fā)lifetimes這個生命周期函數(shù)?END?-->
????????<!--?3個子組件部分?END?-->
????<cmp-navi?class="navi"?title="{{classicData.title}}"?isFirst="{{isFirst}}"??
????isLatest="{{isLatest}}"?bind:myLeft="onNext"
????????bind:myRight="onPrev"></cmp-navi>
</view>


/*?pages/classic/index.wxss?*/
.container{
????width:?100%;
????display:?flex;
????flex-direction:?column;
????align-items:?center;
??}
??.header?{
????width:?100%;
????display:?flex;
????flex-direction:?row;
????height:?100rpx;
????align-items:?center;
????justify-content:?space-between;
????border-top:?1px?solid?#f5f5f5;
????border-bottom:?1px?solid?#f5f5f5;
??}
??.epsoide?{
????margin-left:?20rpx;
????margin-top:?4rpx;
??}
??.like?{
????margin-top:?6rpx;
??}
??.navi?{
????position:?absolute;
????bottom:?40rpx;
??}

//utils/pmsHttp.js
export?default?class?HTTP?{
??ajax({url,method='GET',data={}})?{
????return?new?Promise((resolve,reject)?=>?{
??????wx.request({
????????url,
????????method,
????????data,
????????header:?{
??????????'content-type':?'application/json'
????????},
????????success:?res?=>?{
??????????//獲取請求的狀態(tài)碼:200,404,500
??????????let?code?=?res.statusCode.toString()
??????????//判斷code是否是以2開頭的,如果以2開頭的才可以調(diào)用回調(diào)函數(shù)
??????????if(code.startsWith('2'))?{
????????????resolve(res.data)
??????????}?else?{
????????????//彈出一個警告框
????????????this._showErr(code)
????????????reject()
??????????}?
????????},
????????fail:?err?=>?{
??????????this._showErr(err.errMsg)
??????????reject()
????????}?
??????})????
????})
??}
??//私有的方法
??_showErr(msg){
????wx.showToast({
??????title:?`錯誤代碼:${msg}`,
??????icon:?'none',
??????duration:?2000
????})
??}
}


??"tabBar":?{
????"selectedColor":?"#000000",
????"backgroundColor":?"#ffffff",
????"color":?"#c7c7c7",
????"list":?[
??????{
????????"selectedIconPath":?"/images/tab/classic@highlight.png",
????????"pagePath":?"pages/classic/index",
????????"text":?"流行",
????????"iconPath":?"/images/tab/classic.png"
??????},
??????{
????????"pagePath":?"pages/book/index",
????????"selectedIconPath":?"/images/tab/book@highlight.png",
????????"iconPath":?"/images/tab/book.png",
????????"text":?"書籍"
??????},
??????{
????????"pagePath":?"pages/my/index",
????????"selectedIconPath":?"/images/tab/my@highlight.png",
????????"iconPath":?"/images/tab/my.png",
????????"text":?"喜歡"
??????}
????]
??},

//config.js
//用來存放常量的文件
//?非真機調(diào)試時用?START
export?default?{
??base_url:?'http://127.0.0.1:9001/',
??img_url:?'http://127.0.0.1:9001/public/images/',
??music_url:?'http://127.0.0.1:9001/public/music/'
}
//?非真機調(diào)試時用?END
//?真機調(diào)試(共同連接對應(yīng)的192.168.1.104或其他ip地址的局域網(wǎng))時用?START
//?export?default?{
//???base_url:?'http://192.168.1.104:9001/',
//???img_url:?'http://192.168.1.104:9001/public/images/',
//???music_url:?'http://192.168.1.104:9001/public/music/'
//?}
//?真機調(diào)試(共同連接對應(yīng)的192.168.1.104或其他ip地址的局域網(wǎng))時用?END
運行效果




講義

準備:后臺代碼處理
一、創(chuàng)建新項目和頁面
二、app.json配置導(dǎo)航欄
三、定義和使用點贊組件
"四、classic在生命周期函數(shù)中請求后臺數(shù)據(jù)
設(shè)置-項目設(shè)置-勾選不校驗..."
五、封裝Http工具類。
六、將classic頁面的數(shù)據(jù)傳遞到like組件中(父組件傳數(shù)據(jù)到子組件)
七、實現(xiàn)movie組件
八、like組件傳遞數(shù)據(jù)到classic頁面(子傳父實現(xiàn)自定義事件)
"九、epsoide組件(組件的生命周期函數(shù)以及data和properties定義數(shù)據(jù)的區(qū)別)
data和properties會被合并成同一個對象,如果有同名屬性,會使用properties中定義的屬性
期刊號補零(observer函數(shù))"
"十、初步完成導(dǎo)航組件
獲取數(shù)據(jù):title,isFirst和isLatest
自定義導(dǎo)航事件onLeft,onRight
禁用左翻頁和右翻頁"
十一、初步實現(xiàn)music組件和essay組件
十二、提取組件的公共部分(組件的行為Behavior實現(xiàn)多繼承)
"十三、初步實現(xiàn)期刊切換前一期效果(后臺getClassic實現(xiàn))
classic頁面的onPrev"
"十四、根據(jù)index判斷是第一期還是最后一期
classicModel中的isFirst和isLatest方法,緩存(Storage)最新期刊號_setLatest方法"
"十五、實現(xiàn)期刊切換后一期效果
classic頁面的onNext
classicModel中的getNext和getPrev代碼重構(gòu)
classic頁面的onPrev和onNext代碼重構(gòu)"
十六、期刊數(shù)據(jù)數(shù)據(jù)緩存實現(xiàn),(model中的回調(diào)函數(shù)處理bug和大圖片顯示bug)
十七、緩存數(shù)據(jù)以后無法顯示更新后的點贊次數(shù)和狀態(tài)(后臺代碼getClassic擴展)
"十八、根據(jù)期刊類型使用組件movie,essay和music組件
組件的自定義屬性控制組件是否顯示"
"十九、movie,essay和music組件樣式代碼的復(fù)用
@import復(fù)用樣式文件common.wxss"
二十、music組件樣式
"二十一、實現(xiàn)播放音樂
后臺提供音頻服務(wù)功能(修改中間件代碼亂碼處理邏輯)
wx.getBackgroundAudioManager()
app.json中添加配置項目:""requiredBackgroundModes"": [""audio""],"
"二十二、切換停止音樂播放并且保證音樂播放的正確狀態(tài)
wx:if和hidden的差別:wx:if會重新運行組件的整個生命周期,而hidden不會
關(guān)聯(lián)文件:music\index.js,music\index.wxml"
"二十三、實現(xiàn)音樂播放的旋轉(zhuǎn)動畫效果
關(guān)聯(lián)文件:music\index.wxss"
"二十四、實現(xiàn)底部導(dǎo)航欄,創(chuàng)建book頁面和my頁面
關(guān)聯(lián)文件:app.json"
"二十五、使用Promise封裝請求
關(guān)聯(lián)文件:utils/pmHttp.js"
"二十六、設(shè)計BookModel:獲取熱門書籍數(shù)據(jù)
關(guān)聯(lián)文件:models/book.js,page/book/index.js"
"二十七、設(shè)計book組件,列表渲染
關(guān)聯(lián)文件:components/book/,page/book/"
