Progress bar function

update

  • Made back to the clicker, this article with vue3 implementation of the relevant code here
  • Another article, the implementation of lyrics scrolling and dragging positioning functions

A list,

Some zero-based learning vuE3 development records, the goal is to achieve web end music player. Github development code, welcome to exchange and learn together.

Ii. Relevant preparations

Demand analysis:

  1. When the song is playing, the progress bar is displayed and progresses with time
  2. Drag the progress bar to locate the corresponding position of the song to play
  • <video>Tags can be accessed by listeningH5The triggerMedia related events, precise control of audio content
  • Speaking of progress bars, inhtmlThe first thing that comes to mind isinputComponent, of whichThe range typePass properties through vue props to easily implement the desired functions.
  • Dragging the progress bar is the first thought of the two-way binding of VUE, but there is a problem: dragging the data in the two-way binding changes the time, but the song is still playing, and the data passing through causes the progress bar to move forward. There is a clear conflict between the two.

Third, the implementation process

Scroll bar display

Get relevant data

Properties currentTime and Duration in

The relevant codes are as follows:

<template>
  <audio
    ref="audio"
    class="audio-player"
    :src="src"... @timeupdate="timeupdateListener"
    @durationchange="durationchangeListener"... / ></ template> export default { name: "Audio", emits: { "update-currentTime": null, "update:duration": payload => { if (payload ! == 0) { return true; } console.warn(" Failed to fetch song length, payload); return false; }}, ·· methods: {timeupdateListener(e) {// The element's currentTime attribute indicates that the time has changed. this.$emit("update-currentTime", this.$refs.audio.currentTime); }, durationchangeListener() {this.$emit("update:duration", this.$refs.audio-duration); },...}};Copy the code

Display progress bar with data

Here refer to the relevant documents to modify the progress bar style, the related style is not shown here. Then there is no problem displaying the values received through props.

The relevant codes are as follows:

<template>
  <div class="player-content">
    <div class="progress-bar">
      <input
        type="range"
        ref="progress"
        :class="{ active: isTouch }"
        min="0"
        v-model="currentTime"// It will be removed later:max="duration"
        step="0.05"... / >
      <div class="progerss-time">
        <span class="left">{{ parseTimeString(currentTime) }}</span>
        <span class="right">{{ parseTimeString(duration) }}</span>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: "PlayerContent".props: {
    currentTime: {
      type: Number.default: 0
    },
    duration: {
      type: Number.default: 1}},data() {
    return {
      isTouch: false
    };
  },
  methods: {
    parseTimeString(num) {
      let min = Math.floor(num / 60);
      let sec = Math.floor(num - min * 60);
      return `${min}:${sec}`; },...}};</script>
Copy the code

Drag the progress bar positioning function

Considering problem 2, we decided to display the same input tag again, binding temporary variables for one-way control. That is, the value from video displays a progress bar. The temporary progress bar drags the bidirectional binding value back to video to set currentTime.

After the test, it was found that bidirectional binding could not be implemented after analysis. In this way, the data flow forms a closed loop, and the Time generated by dragging and the currentTime passed will interfere with each other.

After analysis, I think as long as the currentTime transmitted is received when there is no control, but cancel the reception when there is control, then send the Time generated by dragging to video for setting.

Checking in the VUE documentation, the $watch instance method will return an unwatch unlisten function when listening, so it is easy to implement the desired function.

CurrentTime = v-model=”currentTime”

export default {
  name: "PlayerContent".emits: {
    "set-currentTime": null},...data() {
    return {
      isTouch: false
    };
  },
  created() {
    this.unwatch = this.progressWatcher();
  },
  methods: {...progressWatcher() {
      return this.$watch("currentTime".(newVal, oldVal) = > {
        this.$refs.progress.value = newVal;
      });
    },
    touchStart(e) {
      // Pause listening on value
      this.unwatch();
      this.isTouch = true;
    },
    touchEnd(e) {
      // Jump to the corresponding time
      this.$emit("set-currentTime".Number.parseFloat(e.target.value));
      // Start listening
      this.unwatch = this.progressWatcher();
      // Change the style
      this.isTouch = false; }}};Copy the code

Four, achieve the effect

Here is no texture, the complete detailed code in github code, can be pulled down to test the effect

5. Reference materials sorting

  • Video Label Related media events
  • Input tag of type range
  • Vue document Watch instance method