• 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;
            }
  • 相关阅读:
    文件读取
    命名实体识别训练集汇总(一直更新)
    基于PyTorch的Seq2Seq翻译模型详细注释介绍(一)
    python if elif else 区别
    乱码
    dataframe添加元素指定为列表,不同for循环命名空间下的变量重复问题
    tensorflow兼容处理 tensorflow.compat.v1
    Kerberos
    Hadoop集群datanode磁盘不均衡的解决方案
    Saltstack
  • 原文地址:https://www.cnblogs.com/wuqilang/p/12301996.html
Copyright © 2020-2023  润新知