vue09----vuex辅助函数、Detail.vue跳转Player.vue、封装mutations中的函数名、utils工具的使用、&符号、audio标签的timeupdate事件和ended事件、点击play按钮实现播放和暂停,同时img对应旋转或暂停旋转、上一曲(prev)和下一曲(next)、props传值以对象形式对象接收、watch监听控制进度条的宽度、点击滚动条控制播放时间
### 样式作用域
scoped
### vuex的辅助函数(Player.vue)
mapState:将state值直接映射到计算属性
原来拿到state中的songList:
computed: { songList(){ return this.$store.state.songList; } }
通过mapState拿到state中的songList:
computed: { ...mapState(["songList"]) }
步骤:
①引入
import {mapState,mapMutations,mapActions,mapGetters} from "vuex";
②computed中使用...mapState()拿到store中state中的属性,使用...mapGetters拿到store中getters中的方法
computed: { // songList(){ // return this.$store.state.songList.length; // } ...mapState(["songList","fullScreen","currentIndex"]), // currentSong(){ // return this.$store.getters.currentSong // } ...mapGetters(["currentSong"]) }
### 点击Detail.vue列表歌曲,跳转至Player.vue
①在store.js中,声明歌单列表和当前播放歌曲的下标
const store=new Vuex.Store({ state:{ playing:false, fullScreen:false, songList:[], // 歌单列表 currentIndex:-1, // 当前正在播放的歌曲 }, mutations:{ setSongList(state,list){ state.songList=list; }, setCurrentIndex(state,index){ state.currentIndex=index; } }, getters:{ currentSong(state){ // 根据下标获取当前播放歌曲的信息 return state.songList[state.currentIndex]; } } })
②Detail.vue中通过goPlayer()方法中的commit()触发mutations中的方法,将当前歌手的歌单列表和当前下标分别传过去
goPlayer(index){ this.$store.commit("setSongList",this.list); this.$store.commit("setCurrentIndex",index); }
③Player.vue中,可以通过getters拿到
{{this.$store.getters.currentSong}}
这个取值的方法太繁琐了,可以通过辅助函数mapGetters拿到:
computed: { ...mapGetters(["currentSong"]) }
然后就{{currentSong}}就可以了
最好是通过actions来触发,稍作修改:
store.js中:
actions:{ addSongList({commit},{index,list}){ commit("setSongList",list); commit("setCurrentIndex",index); } },
Detail.vue中:
goPlayer(index){ // this.$store.commit("setSongList",this.list); // this.$store.commit("setCurrentIndex",index); this.$store.dispatch("addSongList",{list:this.list,index:index}); }
注意:actions的用途就是处理异步和做多个commit的封装。
### 利用const将mutations中函数的名字做封装,避免命名重复(store.js)
①store文件夹下新建mutations-type.js文件:
const SET_SONG_LIST="SET_SONG_LIST"; const SET_CURRENT_INDEX="SET_CURRENT_INDEX"; export default{ SET_SONG_LIST, SET_CURRENT_INDEX }
②store.js中用常量名替代原来的函数名:
引入:
import type from "./mutations-type.js"
mutations和actions中:
mutations:{ [type.SET_SONG_LIST](state,list){ state.songList=list; }, [type.SET_CURRENT_INDEX](state,index){ state.currentIndex=index; } }, actions:{ addSongList({commit},{index,list}){ commit(type.SET_SONG_LIST,list); commit(type.SET_CURRENT_INDEX,index); } },
### utils工具的使用(Player.vue)
①在src下新建utils/formatUrl.js:
// 专辑 export const albumUrl=(albumMid)=>{ return `https://y.gtimg.cn/music/photo_new/T002R300x300M000${albumMid}.jpg?max_age=2592000`; } // 歌曲 export const songUrl=(songMid)=>{ return `http://aqqmusic.tc.qq.com/amobile.music.tc.qq.com/C400${songMid}.m4a?guid=4887996690&vkey=16121C6B6E73C564FA01F98651C808B32B6D8788E8C7A1FCCFD030B194EC90658BB78D0A988B6DBC9F0C6E1535FD194E2C459CE01510E438&uin=0&fromtag=38`; }
②引入:(Player.vue)
import * as urlObj from "utils/formatUrl.js";
或
import {albumUrl,songUrl} from "utils/formatUrl.js";
注意:
1、export default{} 只能抛出一个对象,如果要抛出多个用 export const ...
2、引入的时候加上 * as,或者通过解构:import {albumUrl,songUrl} from "utils/formatUrl.js";
### &符号的意思(Player.vue)
img{ .w(300); .h(300); border-radius: 50%; border: 10px solid hsla(0,0%,100%,.1); box-sizing: border-box; &.play{ animation: rotate 20s linear infinite; } &.paused{ animation-play-state: paused; } }
加&表示play、paused和img是同级的,不加&表示play、paused是img的子级。
### audio标签的timeupdate事件:当前播放时间(Player.vue)
audio绑定timeupdate事件,可以通过e.target.currentTime拿到当前播放时间
①定义timeupdate事件
<audio controls @timeupdate="timeUpdate"></audio>
②将当前时间赋给current当前时间
timeUpdate(e){ console.log("时间变化",e.target.currentTime) this.current=e.target.currentTime; }
### 点击play按钮,实现播放和暂停,播放时img旋转,暂停时img暂停旋转(Player.vue)
①给img标签绑定类名playClass
<img :class="playClass" v-if="currentSong" :src="albumUrl">
②按钮添加点击事件play
<div class="control"> <button @click="play">play</button> </div>
③data中声明playing为false
data() { return { playing:false } }
④设置play和paused类名的样式
img{ .w(300); .h(300); border-radius: 50%; border: 10px solid hsla(0,0%,100%,.1); box-sizing: border-box; &.play{ animation: rotate 20s linear infinite; } &.paused{ animation-play-state: paused; } }
⑤computed中将playing的值赋给playClass类
playClass(){ return this.playing?"play":"play paused"; }
接下来控制playing的布尔值就可以控制img的旋转
⑥play()方法中判断是否处于暂停中,如果是点击播放,否则点击暂停,同时设置playing值
play(){ let audio=this.$refs.audio; if(audio.paused){ audio.play(); this.playing=true; }else{ audio.pause(); this.playing=false; } console.log(audio.__proto__) }
注意:
1、添加类名的时候不可以写 return this.playing?"play":"paused"; 这样会造成暂停过后,img重新开始旋转。
2、打印audio标签的__proto__对象,可以获取audio的一系列属性和方法。
### 上一曲(prev)和下一曲(next)(Player.vue)
①添加prev和next按钮:
<div class="control"> <button @click="prev">prev</button> <button @click="play">play</button> <button @click="next">next</button> </div>
②通过commit()触发mutations中的SET_CURRENT_INDEX方法:
next(){ let index=this.currentIndex+1; this.$store.commit("SET_CURRENT_INDEX",index); }, prev(){ let index=this.currentIndex-1; this.$store.commit("SET_CURRENT_INDEX",index); }
③边界判断,当SET_CURRENT_INDEX方法中判断当index大于列表最后一项时,让index为0;当index小于列表第一项时,让index为列表最后一项。这就是循环播放:
[type.SET_CURRENT_INDEX](state,index){ if(index>state.songList.length-1){ index=0; }else if(index<0){ index=state.songList.length-1; } state.currentIndex=index; },
### audio标签的ended事件:播放完成触发(Player.vue)
①
<audio controls @ended="ended"></audio>
②
ended(){ console.log("播放完成") }
### props传值(Player.vue、P-scrollBar.vue)
props用于父传子传值。
传递:当子组件在父组件中当做标签传值使用的时候,给当前子组件绑定一个自定义属性,值为需要传递的数据。
<one :val="msg"></one>
接收:在子组件内部通过props属性来进行接收。props接收的方式有数组和对象两种:
数组接收:
props:["msg"]
对象接收:
props:{ msg:{ type:Number, default:0, required:true } }
type:限制外部数据的类型
default:默认值,当父组件没有给子组件传值时用默认值
required:布尔值,当前属性是不是必传的值,如果值为true,不传msg属性时会报错
传递:(Player.vue)
<PScrollBar :current="current" :duration="duration"></PScrollBar>
接收:(P-scrollBar.vue)
props:{ "current":{type:Number,default:0}, "duration":{type:Number,default:0}, }
### watch监听控制进度条的宽度(P-scrollBar.vue)
watch: { current(newValue){ let percentage=(newValue/this.duration)*100; this.$refs.container.style.width=`${percentage}%`; } }
注意:watch中的方法是data中的属性,watch依赖于data,当data中的属性发生改变的时候,触发watch中函数执行。current()是data中的属性,这里它是由props传递过来的,当current()执行时,进度条宽度被不断地重新定义。
### 点击滚动条控制播放时间(P-scrollBar.vue)
①给wrapper盒子绑定点击事件clickDarg
<div class="wrapper" @click="clickDarg" ref="wrapper"> <div class="container" ref="container"> </div> </div>
②将比例赋给container盒子,并将这个百分比传给父组件Player.vue
clickDarg(e){ let percentage=(e.offsetX/this.$refs.wrapper.clientWidth)*100; this.$refs.container.style.width=`${percentage}%`; // 派发jump事件给Player.vue this.$emit("jump",percentage); }
③给PScrollBar组件绑定jump事件
<PScrollBar :current="current" :duration="duration" @jump="jump"></PScrollBar>
④audio的currentTime属性可读也可写
jump(percentage){ this.$refs.audio.currentTime=this.duration*percentage/100; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· 地球OL攻略 —— 某应届生求职总结