欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue歌曲進度條示例代碼

 更新時間:2021年10月12日 10:32:36   作者:傷心小王子  
這篇文章主要介紹了vue歌曲進度條demo,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

注意這個不是vue-cli創(chuàng)建的項目 是一個引用vue.js寫的html文件 ,直接粘到一個html文件就能用了,我的音樂鏈接隔一段時間會失效,需要自己準備音樂
有拖動和點擊切換播放進度的功能

demo圖片

在這里插入圖片描述

代碼

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <div id="app">
    <audio ref="audioRef" autoplay @canplay='canplay' @timeupdate='update'></audio>
    <button @click="play">播放</button>
    <button @click="pause">暫停</button>
    <div class="progress-wrapper">
      <span class="time time-l">{{formatTime(currentTime)}}</span>
      <div class="progress-bar-wrapper">
        <cpn :progress=progress 
          @progress-changing="onProgressChanging" 
          @progress-changed='progressChanged'>
       </cpn>
      </div>
      <span class="time time-l">{{formatTime(duration)}}</span>
    </div>

  </div>

  <!-- 子組件 -->
  <template id="myCpn">

    <div class="progress-bar">
      <!-- 后面黑色的一條 -->
      <div class="bar-inner" @click="clickProgress">
        <!-- 已經(jīng)播放的區(qū)域 -->
        <div class="progress" :style='progressStyle' ref="progress">
        </div>
        <!-- btn -->
        <div class="progress-btn-wrapper" :style='btnStyle' @touchstart.preventDefault='onTouchStart'
          @touchmove.preventDefault='onTouchMove' @touchend.preventDefault='onTouchEnd' >
          <div class="progress-btn"></div>
        </div>
      </div>
    </div>
  </template>


  <script src="../../js/vue.js"></script>

  <script>
    audioEl = null
    const progressBtnWidth = 16
    // 子組件
    const cpn = {
      template: "#myCpn",
      props: {
        progress: {
          type: Number,
          default: 0
        }
      },
      data() {
        return {
          offset: 0
        }
      },
      mounted() {

      },
      created() {
        this.touch = {}
      },
      computed: {
        progressStyle() {
          return `width: ${this.offset}px`
        },
        btnStyle() {
          // console.log('fds');
          return `transform: translate3d(${this.offset}px,0,0)`
        },
      },
      watch: {
        progress(newProgress) {
          // 進度條寬度
          const barWidth = this.$el.clientWidth - progressBtnWidth
          this.offset = barWidth * newProgress
        }
      },
      methods: {
        onTouchStart(e) {
          // console.log(e);
          this.touch.x1 = e.changedTouches[0].clientX
          // 黃色進度條初始寬度
          this.touch.beginWidth = this.$refs.progress.clientWidth
          console.log(this.touch);
        },
        onTouchMove(e) {
          // console.log(e);
          // x偏移量
          const delta = e.changedTouches[0].clientX - this.touch.x1
          // 之前的width+這次拖動增加的偏移量=應有的黃條長度
          const tempWidth = this.touch.beginWidth + delta
          // 再拿到barWidth
          const barWidth = this.$el.clientWidth - progressBtnWidth
          // 黃條長度/barwidth = progress 現(xiàn)在應該有的進度
          const progress = tempWidth / barWidth
          this.offset = barWidth * progress
          this.$emit('progress-changing', progress)
          // console.log("tempWidth", tempWidth);
          // console.log("barWidth", barWidth);
          // console.log("progress", progress);

        },
        onTouchEnd(e) {
          // console.log(e);
          const barWidth = this.$el.clientWidth - progressBtnWidth
          const progress = this.$refs.progress.clientWidth / barWidth
          this.$emit('progress-changed', progress)
        },
        // 點擊進度條
        clickProgress(e){
          // console.log("fds");
          console.log('getBoundingClientRect', this.$el.getBoundingClientRect());
          const rect = this.$el.getBoundingClientRect()
          // 黃條應有的寬度
          const offsetWidth = e.pageX - rect.x
          const barWidth = this.$el.clientWidth - progressBtnWidth
          const progress = offsetWidth/barWidth
          this.$emit('progress-changed', progress)
          console.log(offsetWidth)
        }
      },
    }

    const app = new Vue({
      el: "#app",
      data: {
        content: 'fdasdf',
        src: 'https://music.163.com/song/media/outer/url?id=1463165983.mp3',
        currentTime: 0,
        duration: 0,
        isplay: false,
        progressChanging : false
      },
      components: {
        cpn
      },

      mounted() {
        this.$nextTick(() => {
          audioEl = this.$refs.audioRef
          audioEl.src = this.src
          // 默認暫停
          audioEl.pause()
        })
      },
      computed: {
        progress() {
          return this.currentTime / this.duration
          console.log("progress", this.currentTime / this.duration);
        },

      },
      methods: {
        play() {
          audioEl.play()
          this.isplay = true
        },
        pause() {
          audioEl.pause()
          this.isplay = false
          // console.log();
        },
        canplay(e) {
          // console.log(123456);
          console.log(e);
          this.duration = e.target.duration
        },
        update(e) {
          if(!this.progressChanging){
            this.currentTime = e.target.currentTime
          }
        },
        onProgressChanging(e) {
          // console.log("onProgressChanging", e);
          this.progressChanging = true
          // 實時修改currentTime值
          this.currentTime = this.duration * e 
        },
        progressChanged(e){
          // console.log(e);
          this.progressChanging = false
          audioEl.currentTime = this.currentTime= this.duration * e 
          if(!this.isplay){
            console.log("------");
            audioEl.play()
          }
        },
        formatTime(interval) {
          // interval 向下取整
          interval = interval | 0
          // 不足兩位的話就向前填充一個0
          let minute = ((interval / 60 | 0) + '')
          let second = ((interval % 60 | 0) + '')
          let len = minute.length
          for (; len < 2; len++) {
            minute = '0' + minute
          }
          len = second.length
          for (; len < 2; len++) {
            second = '0' + second
          }
          return `${minute}:${second}`
        },

      },
    })
  </script>
</body>
<style>
  #app {
    width: 100%;
  }

  .progress-wrapper {
    display: flex;
    width: 80%;
    padding: 10px 0;
    align-items: center;
    margin: 0 auto;
  }

  .time {
    width: 40px;
    flex: 0 0 40px;
    font-size: 8px;
    margin: 0 auto;
    padding: 0 8px;
  }

  .time-l {
    text-align: left;
  }

  .time-l {
    text-align: right;
  }

  .progress-bar-wrapper {
    flex: 1;
  }

  /* 子組件樣式 */
  .progress-bar {
    height: 30px;
  }

  .bar-inner {
    position: relative;
    top: 11px;
    height: 8px;
    background-color: rgba(87, 82, 82, 0.062);
    border-radius: 5px;
  }

  .progress {
    position: absolute;
    height: 100%;
    background-color: rgb(238, 238, 136);
  }

  .progress-btn-wrapper {
    position: absolute;
    left: -8px;
    top: -11px;
    width: 30px;
    height: 30px;
  }

  .progress-btn {
    position: relative;
    top: 7px;
    left: 7px;
    box-sizing: border-box;
    width: 16px;
    height: 16px;
    border: 3px solid rgb(189, 189, 218);
    border-radius: 50%;
    background: rgb(123, 192, 212);
  }
</style>

</html>

解說

https://developer.mozilla.org/zh-CN/docs/Web/API/TouchEvent

中間的進度條是一個進度條組件,一個黑色的背景是進度的總長度,左側黃色的條是當前播放的進度,中間的滑塊是可以左右拖動的,可以手動改變進度條,在播放的過程中,進度條是會變長的,并且滑塊是向右偏移的,可以左右拖動滑塊,拖動也是改變了播放進度,并且左側的時間是會發(fā)生變化的

來實現(xiàn)播放過程中,進度條也會隨之播放 組件的狀態(tài)靠什么決定呢 可以靠進度來決定,組件的任何狀態(tài)都可以根據(jù)進度來決定,父組件傳入一個數(shù)字類型的progress

btn的位置,以及progress黃條的寬度都是根據(jù)progress計算而來的,寬度可以用一個數(shù)據(jù)offset來表示(定義個data),之后要監(jiān)聽progess,

https://cn.vuejs.org/v2/api/#vm-el

知識 獲取根 DOM 元素

      watch: {
        progress(newProgress) {
          // 進度條寬度
          const barWidth = this.$el.clientWidth - progressBtnWidth
          // 偏移量
          this.offset = barWidth * newProgress
        }
      }

知識 當然可以用computed,但是要注意用computed獲取el的寬度一開始肯定是獲取不到的,computed一開始上來就計算一次,在模板被渲染的時候就會訪問offset,然后就會計算一次el寬度,這時候組件還沒有mounted,是獲取不到的;watch的話,progress變化的時候其實已經(jīng)渲染了,所以clientWidth就可以拿到,另外,因為之后還要處理一些邏輯,更偏向邏輯的編寫,所以應該用watch去實現(xiàn)

有了offset之后要去映射dom,給黃色進度條和btn設置一個動態(tài)的style,

在這里插入圖片描述

他們兩個的style都是根據(jù)offset計算而來的,

      computed: {
        progressStyle(){
          return  `width: ${this.offset}px`
        },
        btnStyle() {
          return `transform: translate3d(${this.offset}px,0,0)`
        }
      },

現(xiàn)在來根據(jù)offset來計算出它的樣式是怎么樣的 我們接受progress這個屬性,當外部的progress變了之后,就根據(jù)progress計算出它的offset,有了偏移量,樣式就能發(fā)生變化,

疑問 flex 0 0 40px 與width 兩者效果是類似的,但是在某些場合下,flex布局會出現(xiàn)擠壓或塌陷的現(xiàn)象,導致寬度被擠壓,所以設定width可以保證我們的寬度不變化

這里是監(jiān)聽canplay事件

在這里插入圖片描述

父組件計算屬性 播放進度:已播放時間/總時間 總時間已經(jīng)拿到了,播放時間可以用一個事件:timeupdate來監(jiān)聽

在這里插入圖片描述

現(xiàn)在的效果

可以看出來這是秒數(shù),需要格式化時間,定義一個工具函數(shù)

插播 函數(shù)柯里化 https://www.jianshu.com/p/2975c25e4d71 IIFE:自我執(zhí)行函數(shù) 柯里化
還有位運算一些東西 https://www.jianshu.com/p/a3202bc3f7a4

在這里插入圖片描述

在這里插入圖片描述

一個疑問 xxx.yyy|0 為什么等于xxx 為什么這里或運算符能有取整的作用呢

知識padstart方法

formatTime函數(shù)

formatTime(interval) {
  // interval 向下取整
  interval = interval | 0
  // 不足兩位的話就向前填充一個0
  const minute = ((interval / 60 | 0) + '').padstart(2, '0')
  const second = ((interval % 60 | 0) + '').padstart(2, '0')
  return `${minute}:${second}`
}

但是并不能用 它識別不了這個padstart方法

所以只能自己寫了

        formatTime(interval) {
          // interval 向下取整
          interval = interval | 0
          // 不足兩位的話就向前填充一個0
          let minute = ((interval / 60 | 0) + '')
          let second = ((interval % 60 | 0) + '')
          let len = minute.length
          for( ;len<2;len++){
            minute='0'+minute
          }
          len = second.length
          for( ;len<2;len++){
            second='0'+second
          }
          return `${minute}:${second}`
        }

接下來寫進度條的交互邏輯

支持拖動和點擊

在移動端常見的就是ontouchstart ontouchmove ontouchend
https://developer.mozilla.org/zh-CN/docs/Web/API/TouchEvent

知識 prevent修飾符

給滑塊添加三個事件

      methods: {
        onTouchStart(e) {
          console.log(e);
        },
        onTouchMove(e) {
          console.log(e);
        },
        onTouchEnd(e) {
          console.log(e);
        }
      },

需要獲取兩個信息,一個是要知道它點擊的位置,也就是說要知道他的橫坐標是什么。以及左側進度條的寬度(offset)

[screenX clientX pageX概念

因為橫坐標的位置在touchmove的時候也需要獲取,所以可以把數(shù)據(jù)綁定到一個可以被共享的對象上,可以在created鉤子函數(shù)中定義一個對象,

      created() {
        this.touch = {}
      },

給黃條一個ref 之后

        onTouchStart(e) {
          // console.log(e);
          this.touch.x1=e.changedTouches[0].clientX
          // 黃色進度條初始寬度
          this.touch.beginWidth = this.$refs.progress.clientWidth
          console.log(this.touch);
        },
        onTouchStart(e) {
          // console.log(e);
          this.touch.x1=e.changedTouches[0].clientX
          // 黃色進度條初始寬度
          this.touch.beginWidth = this.$refs.progress.clientWidth
          console.log(this.touch);
        },
        onTouchMove(e) {
          // console.log(e);
          // x偏移量
          const delta = e.changedTouches[0].clientX-this.touch.x1
          // 之前的width+這次拖動增加的偏移量=應有的黃條長度
          const tempWidth = this.touch.beginWidth + delta
          // 再拿到barWidth
          const barWidth = this.$el.clientWidth - progressBtnWidth
          // 黃條長度/barwidth = progress 現(xiàn)在應該有的進度
          const progress = tempWidth/barWidth
          this.offset = barWidth * progress
          // console.log("tempWidth", tempWidth);
          // console.log("barWidth", barWidth);
          // console.log("progress", progress);

        },

來整理一下,最終目的是要拿到offset,offset是由progress和barWidth共同決定的,這里progress怎么算呢需要拿到當前黃條應該的寬度除總寬度,黃條應該的寬度就是一開始的寬度+這次滑動的x距離,然后barWidth的獲取是簡單的,之后就可以算出來了

會不會覺得多此一舉呢 直接原來的黃條寬度+這次滑動的長度不就可以了嗎 為什么還要算progress呢,因為要讓外部知道,歌曲的進度發(fā)生了改變,要讓他們對應上才可以,最終是要修改audio的,這個是用父組件做的,現(xiàn)在只是實現(xiàn)了拖動,所以需要派發(fā)事件,這里派發(fā)兩個自定義事件,一個progress-changing事件,表示手指還在拖動的過程中,還沒有離開,當手指離開的時候還要派發(fā)一個progress-change 把新的progress傳出去

實時修改currentTime的值

在這里插入圖片描述

這是拖動的時候修改currentTIme,修改音樂的時間是在手松開的時候,

在這里插入圖片描述

但是我們暫停的時候發(fā)現(xiàn)是可以拖動的,但是播放的時候拖動發(fā)現(xiàn)是有問題的,

優(yōu)化:在change的時候,如果是暫停的效果就讓他播放,這時候就要定義一個isplay在點擊播放暫停的時候翻轉

在這里插入圖片描述

現(xiàn)在來改bug,在播放的時候,拖動進度會出問題,為什么呢,監(jiān)聽progressChanging,我們修改了currentTime,這個currentTime一旦發(fā)生了改變,progress會根據(jù)currentTime做一個新的計算,然后傳給子組件,子組件他就會進入到這個邏輯

在這里插入圖片描述

offset就會重新做一次計算,

最后這里會覆蓋

在這里插入圖片描述

應該在update的時候需要做一些控制,在changing的過程加一個標志位,

在這里插入圖片描述

就是說在update函數(shù)中,如果changing在拖動的過程中,不要去修改currentTime,在changing的過程中,就認為是進度條改變,他修改進度條的優(yōu)先級高,自身播放導致的currentTime改變優(yōu)先級比較低,

這樣就ok了

除了拖動,我們還希望點擊它跳轉到對應位置,

知識webapi --getBoundingClientRect 方法返回元素的大小及其相對于視口的位置(獲取短的那一條)。

在這里插入圖片描述

用pagex獲取長的那一條

        clickProgress(e){
          // console.log("fds");
          console.log('getBoundingClientRect', this.$el.getBoundingClientRect());
          const rect = this.$el.getBoundingClientRect()
          // 黃條應有的寬度
          const offsetWidth = e.pageX - rect.x
          const barWidth = this.$el.clientWidth - progressBtnWidth
          const progress = offsetWidth/barWidth
          this.$emit('progress-changed', progress)
          console.log(offsetWidth)
        }

到此這篇關于vue歌曲進度條demo的文章就介紹到這了,更多相關vue歌曲進度條內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論