iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >如何使用Vue3+TS实现语音播放组件
  • 415
分享到

如何使用Vue3+TS实现语音播放组件

2023-06-29 16:06:07 415人浏览 泡泡鱼
摘要

这篇文章主要介绍如何使用vue3+TS实现语音播放组件,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!该功能将使用Vue3 + TS来实现语音播放组件,使用什么技术不重要,重要的是看懂了核心逻辑后,通过原生js、Rea

这篇文章主要介绍如何使用vue3+TS实现语音播放组件,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

该功能将使用Vue3 + TS来实现语音播放组件,使用什么技术不重要,重要的是看懂了核心逻辑后,通过原生jsReact、vue2等都可以轻松实现

所涉及到重要点有以下几个:

(1)进度条的实现:拖拽进度条、点击进度条

(2)操作audio语音播放:通过js操作audio媒体

(3)播放进度与进度条紧密关联:播放的进度改变时,进度条也随之改变;进度条改变时,播放的进度也随之改变

效果图:

如何使用Vue3+TS实现语音播放组件

开始我们的设计吧!

第一步:点击拖拽进度条

进度条的CSS样式如下:

父元素设置灰色背景色,圆圈进行position定位,使用left百分比,同时黑色进度条的width也是百分比,这样圆圈的left值是多少,黑色进度条的width就是多少。

.slider-wrap {      position: relative;      display: flex;      align-items: center;      height: 4px;      max-width: 194px;      min-width: 36px;      width: 194px;      background-color: rgba(23, 23, 23, 0.15);      cursor: pointer;      .circle {        position: absolute;        width: 14px;        height: 14px;        background-color: #555555;        border-radius: 100%;        cursor: pointer;        user-select: none;        transfORM: translate(-50%);      }      .slider-bar {        height: 4px;        max-width: 200px;        background-color: #555555;      }    }

先说拖拽圆圈,圆圈上绑定mousedown事件,根据事件e.target确定圆圈、黑色进度条、灰色父元素,三者的element。同时知道了圆圈当前的left值,比如30%,还知道了当前鼠标mousedown时,事件e.pageX,即鼠标mousedown时,距离页面左边的水平值,因为对比后续鼠标移动时,触发的mousemove事件的e.pageX可以判断移动了多少。同时还要知道灰色背景的父元素的width。因为鼠标移动的距离 / width 要赋值给圆圈的left。知道移动了%多少。

    const circleMousedown = (e) => {      circleTarget.el = e.target; // 圆圈自身      wrapEle.el = e.target.parentElement; // 圆圈父元素      sliderBar.el = e.target.nextElementSibling; // 圆圈的兄弟节点       circleTarget.circleLeft = e.target.style.left;      circleTarget.pageX = e.pageX;      circleTarget.circleMouseMouve = true;      wrapEle.width = window.getComputedStyle(wrapEle.el, null).getPropertyValue('width');    };

然后,监听document文档的mousemove,注意鼠标是可以在整个文档上移动的,不过圆圈可不能在灰色父元素之外。移动的e.pageX - 鼠标mousedown时的e.pageX 就是鼠标水平移动的距离。超出最大值时,圆圈left设置为100%,小于最小值时,left设置为0%,总之left要在0%~100%之间,才能保证圆圈不超出到外面去。这样圆圈就可以随着鼠标移动了,同时黑色进度条的width值与圆圈的left值一样,所以黑色进度条的width也随着鼠标移动。

document.addEventListener('mousemove', (e) => {      if (circleTarget.circleMouseMouve) {        const nowLeft =          parseFloat(circleTarget.circleLeft) +          getPercentage(e.pageX - circleTarget.pageX, wrapEle.width);        if (nowLeft >= 100) {          circleDragLeft = '100%';        } else if (nowLeft <= 0) {          circleDragLeft = '0%';        } else {          circleDragLeft = `${nowLeft}%`;        }        updateProgressBar(circleDragLeft);        currentTimeByProgressBar(circleDragLeft);      }    });    document.addEventListener('mouseup', () => {      circleTarget.circleMouseMouve = false;    });

再说说点击父元素时,圆圈到指定位置

点击事件在灰色父元素上进行监听,注意e.target可不一定是灰色父元素,e.target表示鼠标点击到哪个元素,随后click冒泡到父元素上的。同样点击事件的e.pageX 可以确定鼠标点击的水平位置,转换为%值,设置圆圈的left值和黑色进度条的width值。

    // 只处理e.target是slider-wrap 或 slider-bar的情况    const clickSliderWrap = (e) => {      if (e.target.getAttribute('target') === 'wrap') {        wrapEle.el = e.target;        circleTarget.el = e.target.firstElementChild;        sliderBar.el = e.target.lastElementChild;      } else if (e.target.getAttribute('target') === 'sliderbar') {        sliderBar.el = e.target;        circleTarget.el = e.target.previousElementSibling;        wrapEle.el = e.target.parentElement;      } else {        return;      }      wrapEle.width = window.getComputedStyle(wrapEle.el, null).getPropertyValue('width');       const styleLeft = `${getPercentage(e.offsetX, wrapEle.width)}%`;      updateProgressBar(styleLeft);      currentTimeByProgressBar(styleLeft);    };

以上就可以实现进度条功能了。

第二步:操作媒体音频

获取audio的element,audioElement上面有play、pause等方法,还有currentTime播放进度时间,以及duration总时长。所以说HTML5的audio标签,上面的方法和属性还是非常直观的,这也正是WEB发展的一个特点,某个新的特性的产生,功能会很明了。

首先当媒体的第一帧加载完成时,我们就获取audio的element:(audio自身的loadeddata事件)

// 当媒体音频第一帧加载完成时    const audioLoadeddata = (e) => {      audioEl = e.target;      audioData.duration = e.target.duration;    };

其次,对播放中进行监听:(audio的timeupdate事件)

    // 播放进度:表示audio正在播放,currentTime在更新    const audioTimeupdate = (e) => {      audioData.currentTime = e.target.currentTime;      progressBarBycurrentTime();    };

最后,播放完成进行监听:(audio的ended事件)

    // 音频播放结束    const audioEnded = () => {      audioData.playing = false;    };

如果对audio标签不是很熟悉,请参考文档

上述操作还是很简单的,audio上的属性、方法、事件都是非常简单明了且实用的。

第三步:进度条和播放进度关联

通过audio当前的播放时间 / 总时长,得到的%值,赋值给圆圈的left和黑色进度条的width。

通过圆圈的left值的% * 总时长,得到audio的当前播放时间。(audio的currentTime属性直接赋值,语音播放就会跳转到指定的时间进行播放,比如 1,就会从1秒的位置开始)

完整代码

<template>  <div class="glowe-audio">    <div class="audio">      <div class="icon-div" @click="playPauseAudio">        <video-play class="icon" v-if="!audioData.playing"></video-play>        <video-pause class="icon" v-else></video-pause>      </div>      <div        class="slider-wrap"        :        target="wrap"        @click="clickSliderWrap"      >        <div class="circle" target="circle"  @mousedown="circleMousedown"></div>        <div class="slider-bar" target="sliderbar" ></div>      </div>      <div class="time-wrap">        <span class="time">{{ durationFormat(Math.round(audioData.duration)) }}</span>      </div>    </div>    <audio      :src="audioData.audiourl"      preload="auto"      @ended="audioEnded"      @timeupdate="audioTimeupdate"      @loadeddata="audioLoadeddata"    ></audio>  </div></template><script lang="ts">import { defineComponent, reactive } from 'vue';import { VideoPause, VideoPlay } from '@element-plus/icons';import { durationToFormat } from '@/utils/refactor'; export default defineComponent({  name: 'GloweAudio',  components: {    VideoPlay,    VideoPause,  },  props: {    audioUrl: {      type: String,      required: true,    },  },  setup(props) {    const audioData = reactive({      audiourl: props.audioUrl,      playing: false,      duration: 0, // 音频总时长      currentTime: 0, // 当前播放的位置    });    let audioEl: htmlAudioElement | null = null;    const wrapEle: {      width: string;      el: any;    } = {      width: '0px',      el: null,    };    const sliderBar: {      width: string;      el: any;    } = {      width: '0%',      el: null,    };    const circleTarget: {      circleMouseMouve: boolean;      pageX: number;      circleLeft: string;      el: any;    } = {      circleMouseMouve: false,      pageX: 0,      circleLeft: '0%',      el: null,    };    let circleDragLeft = '0%'; // 圆圈被鼠标水平拖拽的距离(默认向左)     document.addEventListener('mousemove', (e) => {      if (circleTarget.circleMouseMouve) {        const nowLeft =          parseFloat(circleTarget.circleLeft) +          getPercentage(e.pageX - circleTarget.pageX, wrapEle.width);        if (nowLeft >= 100) {          circleDragLeft = '100%';        } else if (nowLeft <= 0) {          circleDragLeft = '0%';        } else {          circleDragLeft = `${nowLeft}%`;        }        updateProgressBar(circleDragLeft);        currentTimeByProgressBar(circleDragLeft);      }    });    document.addEventListener('mouseup', () => {      circleTarget.circleMouseMouve = false;    });    const circleMousedown = (e) => {      circleTarget.el = e.target; // 圆圈自身      wrapEle.el = e.target.parentElement; // 圆圈父元素      sliderBar.el = e.target.nextElementSibling; // 圆圈的兄弟节点       circleTarget.circleLeft = e.target.style.left;      circleTarget.pageX = e.pageX;      circleTarget.circleMouseMouve = true;      wrapEle.width = window.getComputedStyle(wrapEle.el, null).getPropertyValue('width');    };    // 只处理e.target是slider-wrap 或 slider-bar的情况    const clickSliderWrap = (e) => {      if (e.target.getAttribute('target') === 'wrap') {        wrapEle.el = e.target;        circleTarget.el = e.target.firstElementChild;        sliderBar.el = e.target.lastElementChild;      } else if (e.target.getAttribute('target') === 'sliderbar') {        sliderBar.el = e.target;        circleTarget.el = e.target.previousElementSibling;        wrapEle.el = e.target.parentElement;      } else {        return;      }      wrapEle.width = window.getComputedStyle(wrapEle.el, null).getPropertyValue('width');       const styleLeft = `${getPercentage(e.offsetX, wrapEle.width)}%`;      updateProgressBar(styleLeft);      currentTimeByProgressBar(styleLeft);    };     // 播放或暂停音频    const playPauseAudio = (e) => {      const iconDiv = findParentsEl(e.target.parentElement, 'icon-div');      wrapEle.el = iconDiv?.nextElementSibling;      circleTarget.el = wrapEle.el.firstElementChild;      sliderBar.el = wrapEle.el.lastElementChild;      const parentAudio = findParentsEl(e.target.parentElement, 'audio');      if (parentAudio) {        if (!audioData.playing) {          audioPlay();        } else {          audioPause();        }      }    };     // 计算百分比的分子    function getPercentage(num: number | string, den: number | string): number {      const numerator = typeof num === 'number' ? num : parseFloat(num);      const denominator = typeof den === 'number' ? den : parseFloat(den);      return Math.round((numerator / denominator) * 10000) / 100;    }    // 查找自身或最近的一个父元素有className的    function findParentsEl(el: HTMLElement, classname: string): HTMLElement | null {      // 注意avg className得到一个对象而非字符串      if (el && el.className?.split && el.className.split(' ').includes(classname)) {        return el;      }      if (el.parentElement) {        if (el.parentElement.className.split(' ').includes(classname)) {          return el.parentElement;        } else {          return findParentsEl(el.parentElement, classname);        }      }      return null;    }        function updateProgressBar(percentage: string) {      circleTarget.el.style.left = percentage;      sliderBar.el.style.width = percentage;    }          // 音频播放结束    const audioEnded = () => {      audioData.playing = false;    };    // 播放进度:表示audio正在播放,currentTime在更新    const audioTimeupdate = (e) => {      audioData.currentTime = e.target.currentTime;      progressBarBycurrentTime();    };    // 当媒体音频第一帧加载完成时    const audioLoadeddata = (e) => {      audioEl = e.target;      audioData.duration = e.target.duration;    };     // 播放    function audioPlay() {      if (audioEl) {        audioEl.play();        audioData.playing = true;      }    }     // 暂停播放    function audioPause() {      if (audioEl) {        audioEl.pause();        audioData.playing = false;      }    }     // 进度条和音频播放进度进行关联    function progressBarBycurrentTime() {      const progress = getPercentage(audioData.currentTime, audioData.duration);      updateProgressBar(`${progress}%`);    }        function currentTimeByProgressBar(styleLeft: string) {      if (audioEl) {        const currentTime = (parseFloat(styleLeft) / 100) * audioData.duration;        audioEl.currentTime = currentTime;        audioData.currentTime = currentTime;      }    }     const durationFormat = (num: number): string => {      return durationToFormat(num, 'm:ss');    };    const durationToWidth = (num: number): string => {      return `${Math.ceil((158 / 58) * num + 33)}px`;    };    return {      audioData,      circleMousedown,      clickSliderWrap,      playPauseAudio,      audioEnded,      audioTimeupdate,      audioLoadeddata,      durationFormat,      durationToWidth,    };  },});</script><style scoped lang="scss">.glowe-audio {  .audio {    display: flex;    justify-content: space-evenly;    align-items: center;    max-width: 308px;    height: 48px;    .icon-div {      width: 20px;      height: 20px;      border-radius: 100%;      margin-left: 22px;      margin-right: 17px;      .icon {        cursor: pointer;      }    }    .slider-wrap {      position: relative;      display: flex;      align-items: center;      height: 4px;      max-width: 194px;      min-width: 36px;      width: 194px;      background-color: rgba(23, 23, 23, 0.15);      cursor: pointer;      .circle {        position: absolute;        width: 14px;        height: 14px;        background-color: #555555;        border-radius: 100%;        cursor: pointer;        user-select: none;        transform: translate(-50%);      }      .slider-bar {        height: 4px;        max-width: 200px;        background-color: #555555;      }    }    .time-wrap {      margin-left: 15px;      margin-right: 18px;      .time {        font-size: 12px;      }    }  }}</style>

以上是“如何使用Vue3+TS实现语音播放组件”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网精选频道!

--结束END--

本文标题: 如何使用Vue3+TS实现语音播放组件

本文链接: https://www.lsjlt.com/news/325693.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何使用Vue3+TS实现语音播放组件
    这篇文章主要介绍如何使用Vue3+TS实现语音播放组件,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!该功能将使用vue3 + TS来实现语音播放组件,使用什么技术不重要,重要的是看懂了核心逻辑后,通过原生js、rea...
    99+
    2023-06-29
  • Vue3+TS实现语音播放组件的示例代码
    目录第一步:点击拖拽进度条第二步:操作媒体音频第三步:进度条和播放进度关联完整代码该功能将使用vue3 + TS来实现语音播放组件,使用什么技术不重要,重要的是看懂了核心逻辑后,通过...
    99+
    2022-11-13
  • 如何使用vue3+TS实现简易组件库
    这篇文章主要为大家展示了“如何使用vue3+TS实现简易组件库”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“如何使用vue3+TS实现简易组件库”这篇文章吧。前置首先下载vue-cli,搭建我们...
    99+
    2023-06-29
  • C语言如何实现音乐播放器
    本文小编为大家详细介绍“C语言如何实现音乐播放器”,内容详细,步骤清晰,细节处理妥当,希望这篇“C语言如何实现音乐播放器”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。实例代码如下:#include &l...
    99+
    2023-06-08
  • 如何使用html实现音乐播放
    小编给大家分享一下如何使用html实现音乐播放,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!在html中可以使用“<audio>”标签定义声音,只需要...
    99+
    2023-06-07
  • C#中如何使用DirectX.DirectSound播放语音
    这篇文章主要介绍“C#中如何使用DirectX.DirectSound播放语音”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C#中如何使用DirectX.DirectSound播放语音”文章能帮助大...
    99+
    2023-06-29
  • vue2.0如何实现音乐/视频播放进度条组件
    这篇文章主要为大家展示了“vue2.0如何实现音乐/视频播放进度条组件”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“vue2.0如何实现音乐/视频播放进度条组件...
    99+
    2022-10-19
  • 使用vue3+TS实现简易组件库的全过程
    目录前置组件编写dropdownform验证总结前置 首先下载vue-cli,搭建我们的环境,vue-create-luckyUi,选择vue3和TypeScript 。在...
    99+
    2022-11-13
  • 小程序如何实现开始播放语音
    本文将为大家详细介绍“小程序如何实现开始播放语音”,内容步骤清晰详细,细节处理妥当,而小编每天都会更新不同的知识点,希望这篇“小程序如何实现开始播放语音”能够给你意想不到的收获,请大家跟着小编的思路慢慢深入,具体内容如下,一起去收获新知识吧...
    99+
    2023-06-26
  • C语言使用mciSendString实现播放音乐功能
    目录使用 mciSendString 播放音乐使用 mciSendCommand 播放音乐解决某些 MP3 无法播放的问题使用 PlaySound 函数播放音乐使用 mciSendS...
    99+
    2023-02-14
    C语言mciSendString播放音乐 C语言 播放音乐 C语言mciSendString
  • 怎么使用C语言实现音乐播放器
    本文小编为大家详细介绍“怎么使用C语言实现音乐播放器”,内容详细,步骤清晰,细节处理妥当,希望这篇“怎么使用C语言实现音乐播放器”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。介绍该程序是一个小的DEMO,实现了以...
    99+
    2023-07-05
  • 如何让用Python写一个语音播放软件
    如何让用Python写一个语音播放软件,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。单位经常使用广播进行临时事项的通知(将文字转换为语音然后通过功放广播),但是市面上多数语...
    99+
    2023-06-17
  • 基于SpringBoot和Vue的动态语音播放如何实现
    这篇文章主要介绍“基于SpringBoot和Vue的动态语音播放如何实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“基于SpringBoot和Vue的动态语音播放如何实现”文章能帮助大家解决问题。...
    99+
    2023-07-06
  • 微信小程序中如何实现wx.stopVoice()结束播放语音
    这篇文章主要为大家展示了微信小程序中如何实现wx.stopVoice()结束播放语音,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带大家一起来研究并学习一下“微信小程序中如何实现wx.stopVoice()结束播放语音”这篇...
    99+
    2023-06-26
  • 如何利用Python实现简易的音频播放器
    目录1. 需要用到的Python库2. 简易UI设计3. 功能模块实现3.1 选择音频文件进行播放3.2 控制音频播放、暂停3.3 控制音频音量大小3.4 播放器初始化等细节4. 运...
    99+
    2022-11-13
  • 小程序开发中如何实现暂停正在播放的语音
    本文将为大家详细介绍“小程序开发中如何实现暂停正在播放的语音”,内容步骤清晰详细,细节处理妥当,而小编每天都会更新不同的知识点,希望这篇“小程序开发中如何实现暂停正在播放的语音”能够给你意想不到的收获,请大家跟着小编的思路慢慢深入,具体内容...
    99+
    2023-06-26
  • 如何使用Go语言和Redis开发在线音乐播放器
    如何使用Go语言和Redis开发在线音乐播放器引言:随着互联网的快速发展,音乐播放器已经成为人们日常生活中不可或缺的一部分。本文将介绍如何使用Go语言和Redis开发一个简单的在线音乐播放器。一、准备工作首先,需要确保已经安装了Go语言的开...
    99+
    2023-10-27
    音乐播放器 Go语言 redis
  • Android如何实现仿微信语音消息的录制和播放功能
    小编给大家分享一下Android如何实现仿微信语音消息的录制和播放功能,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一、简述效果:实现功能:长按Button时改变Button显示文字,弹出Dialog(动态更新音量),动态...
    99+
    2023-05-30
    android
  • 腾讯云服务器如何使用u盘播放音乐文件
    如果您的腾讯云服务器使用U盘来播放音乐文件,那么您需要使用以下步骤来使用U盘上的音乐文件: 打开您的电脑并连接至网络。 打开音乐播放器并选择“本地音乐文件”。 点击“开始播放”。 在弹出的“播放器设置”中,选择“U盘模式”。 接下来您就...
    99+
    2023-10-27
    腾讯 如何使用 音乐文件
  • 阿里云服务器如何使用u盘播放音乐文件
    使用云盘播放音乐的方式有多种,包括U盘播放、本地播放、网络播放等。其中,U盘播放是最为常见的一种播放方式,可以将音乐文件复制到U盘中,插入电脑或其他设备中,通过USB接口进行播放。而本地播放则需要将音乐文件上传到云盘,然后通过云盘提供的下载...
    99+
    2023-10-28
    阿里 如何使用 音乐文件
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作