Apprenez étape par étape à écrire un lecteur en utilisant Vue3
Cet article vous apporte des connaissances pertinentes sur Vue3. Il explique principalement comment écrire un lecteur avec Vue3. Les amis intéressés peuvent jeter un œil ci-dessous. J'espère que cela sera utile à tout le monde.
ps : La lecture de la musique peut échouer. La raison en est que le lien audio est temporaire et peut être remplacé manuellement.
TODO
- réaliser la lecture/pause ;
- réaliser l'heure de début/fin et les changements dynamiques de la barre de défilement en fonction de la dynamique de lecture ; réaliser la progression des clics bar Aller à la position de lecture spécifiée ;
- Cliquez sur le point et faites glisser la barre de défilement.
css
sont les suivants
<template> <div class="song-item"> <audio src="" /> <!-- 进度条 --> <div class="audio-player"> <span>00:00</span> <div class="progress-wrapper"> <div class="progress-inner"> <div class="progress-dot" /> </div> </div> <span>00:00</span> <!-- 播放/暂停 --> <div style="margin-left: 10px; color: #409eff; cursor: pointer;" > 播放 </div> </div> </div></template><style lang="scss"> * { font-size: 14px; } .song-item { display: flex; flex-direction: column; justify-content: center; height: 100px; padding: 0 20px; transition: all ease .2s; border-bottom: 1px solid #ddd; /* 进度条样式 */ .audio-player { display: flex; height: 18px; margin-top: 10px; align-items: center; font-size: 12px; color: #666; .progress-wrapper { flex: 1; height: 4px; margin: 0 20px 0 20px; border-radius: 2px; background-color: #e9e9eb; cursor: pointer; .progress-inner { position: relative; width: 0%; height: 100%; border-radius: 2px; background-color: #409eff; .progress-dot { position: absolute; top: 50%; right: 0; z-index: 1; width: 10px; height: 10px; border-radius: 50%; background-color: #409eff; transform: translateY(-50%); } } } } }</style>
implémenter la lecture/pause
css
样式如下const audioIsPlaying = ref(false); // 用于同步当前的播放状态const audioEle = ref<HTMLAudioElement | null>(null); // audio 元素/** * @description 播放/暂停音乐 */const togglePlayer = () => { if (audioEle.value) { if (audioEle.value?.paused) { audioEle.value.play(); audioIsPlaying.value = true; } else { audioEle.value?.pause(); audioIsPlaying.value = false; } } };onMounted(() => { // 页面点击的时候肯定是加载完成了,这里获取一下没毛病 audioEle.value = document.querySelector('audio'); });
实现播放/暂停
思路:给 ”播放“ 注册点击事件,在点击事件中通过
audio
的属性及方法来判定当前歌曲是什么状态,是否播放或暂停,然后声明一个属性同步这个状态,在模板中做出判断当前应该显示 ”播放/暂停“。关键性 api:
audio.paused
:当前播放器是否为暂停状态
audio.play()
:播放
audio.pause()
:暂停
<div style="margin-left: 10px; color: #409eff; cursor: pointer;" @click="togglePlayer"> {{ audioIsPlaying ? '暂停' : '播放'}}</div>
最后把属性及事件应用到模板中去。
import dayjs from 'dayjs';const audioCurrentPlayTime = ref('00:00'); // 当前播放时长const audioCurrentPlayCountTime = ref('00:00'); // 总时长const pgsInnerEle = ref<HTMLDivElement | null>(null);/** * @description 更新进度条与当前播放时间 */const updateProgress = () => { const currentProgress = audioEle.value!.currentTime / audioEle.value!.duration; pgsInnerEle.value!.style.width = `${currentProgress * 100}%`; // 设置进度时长 if (audioEle.value) audioCurrentPlayTime.value = dayjs(audioEle.value.currentTime * 1000).format('mm:ss'); };/** * @description 播放完成重置播放状态 */const audioPlayEnded = () => { audioCurrentPlayTime.value = '00:00'; pgsInnerEle.value!.style.width = '0%'; audioIsPlaying.value = false; };onMounted(() => { pgsInnerEle.value = document.querySelector('.progress-inner'); // 设置总时长 if (audioEle.value) audioCurrentPlayCountTime.value = dayjs(audioEle.value.duration * 1000).format('mm:ss'); // 侦听播放中事件 audioEle.value?.addEventListener('timeupdate', updateProgress, false); // 播放结束 event audioEle.value?.addEventListener('ended', audioPlayEnded, false); });
实现开始/结束时间及开始时间和滚动条动态跟随播放动态变化
思路:获取当前已经播放的时间及总时长,然后再拿当前时长 / 总时长及得到歌曲播放的百分比即滚动条的百分比。通过侦听
audio
元素的timeupdate
事件以做到每次当前时间改变时,同步把 DOM 也进行更新。最后播放完成后把状态初始化。关键性api:
audio.currentTime
:当前的播放时间;单位(s)
audio.duration
:音频的总时长;单位(s)
timeupdate
:currentTime
变更时会触发该事件。
/** * @description 点击滚动条同步更新音乐进度 */const clickProgressSync = (event: MouseEvent) => { if (audioEle.value) { // 保证是正在播放或者已经播放的状态 if (!audioEle.value.paused || audioEle.value.currentTime !== 0) { const pgsWrapperWidth = pgsWrapperEle.value!.getBoundingClientRect().width; const rate = event.offsetX / pgsWrapperWidth; // 同步滚动条和播放进度 audioEle.value.currentTime = audioEle.value.duration * rate; updateProgress(); } } };onMounted({ pgsWrapperEle.value = document.querySelector('.progress-wrapper'); // 点击进度条 event pgsWrapperEle.value?.addEventListener('mousedown', clickProgressSync, false); });// 别忘记统一移除侦听onBeforeUnmount(() => { audioEle.value?.removeEventListener('timeupdate', updateProgress); audioEle.value?.removeEventListener('ended', audioPlayEnded); pgsWrapperEle.value?.removeEventListener('mousedown', clickProgressSync); });
实现点击进度条跳转指定播放位置
思路:给滚动条注册鼠标点击事件,每次点击的时候获取当前的
offsetX
以及滚动条的宽度,用宽度 /offsetX
最后用总时长 * 前面的商就得到了我们想要的进度,再次更新进度条即可。关键性api:
event.offsetX
:鼠标指针相较于触发事件对象的 x 坐标。
/** * @method useSongProgressDrag * @param audioEle * @param pgsWrapperEle * @param updateProgress 更新滚动条方法 * @param startSongDragDot 是否开启拖拽滚动 * @description 拖拽更新歌曲播放进度 */const useSongProgressDrag = ( audioEle: Ref<HTMLAudioElement | null>, pgsWrapperEle: Ref<HTMLDivElement | null>, updateProgress: () => void, startSongDragDot: Ref<boolean>) => { const audioPlayer = ref<HTMLDivElement | null>(null); const audioDotEle = ref<HTMLDivElement | null>(null); const dragFlag = ref(false); const position = ref({ startOffsetLeft: 0, startX: 0, maxLeft: 0, maxRight: 0, }); /** * @description 鼠标点击 audioPlayer */ const mousedownProgressHandle = (event: MouseEvent) => { if (audioEle.value) { if (!audioEle.value.paused || audioEle.value.currentTime !== 0) { dragFlag.value = true; position.value.startOffsetLeft = audioDotEle.value!.offsetLeft; position.value.startX = event.clientX; position.value.maxLeft = position.value.startOffsetLeft; position.value.maxRight = pgsWrapperEle.value!.offsetWidth - position.value.startOffsetLeft; } } event.preventDefault(); event.stopPropagation(); }; /** * @description 鼠标移动 audioPlayer */ const mousemoveProgressHandle = (event: MouseEvent) => { if (dragFlag.value) { const clientX = event.clientX; let x = clientX - position.value.startX; if (x > position.value.maxRight) x = position.value.maxRight; if (x < -position.value.maxLeft) x = -position.value.maxLeft; const pgsWidth = pgsWrapperEle.value?.getBoundingClientRect().width; const reat = (position.value.startOffsetLeft + x) / pgsWidth!; audioEle.value!.currentTime = audioEle.value!.duration * reat; updateProgress(); } }; /** * @description 鼠标取消点击 */ const mouseupProgressHandle = () => dragFlag.value = false; onMounted(() => { if (startSongDragDot.value) { audioPlayer.value = document.querySelector('.audio-player'); audioDotEle.value = document.querySelector('.progress-dot'); // 在捕获中去触发点击 dot 事件. fix: 点击原点 offset 回到原点 bug audioDotEle.value?.addEventListener('mousedown', mousedownProgressHandle, true); audioPlayer.value?.addEventListener('mousemove', mousemoveProgressHandle, false); document.addEventListener('mouseup', mouseupProgressHandle, false); } }); onBeforeUnmount(() => { if (startSongDragDot.value) { audioPlayer.value?.removeEventListener('mousedown', mousedownProgressHandle); audioPlayer.value?.removeEventListener('mousemove', mousemoveProgressHandle); document.removeEventListener('mouseup', mouseupProgressHandle); } }); };
实现点击圆点拖拽滚动条。
思路:使用
hook
管理这个拖动的功能,侦听这个滚动条的 鼠标点击、鼠标移动、鼠标抬起事件。点击时: 获取鼠标在窗口的
x
坐标,圆点距离窗口的left
距离及最大的右移距离(滚动条宽度 - 圆点距离窗口的left
)。为了让移动式不随便开始计算,在开始的时候可以弄一个开关flag
移动时: 实时获取鼠标在窗口的
x
坐标减去 点击时获取的x
坐标。然后根据最大移动距离做出判断,不要让它越界。最后: 总时长 * (圆点距离窗口的left
+ 计算得出的x
/ 滚动条长度) 得出百分比更新滚动条及进度抬起时:将
flag
重置。
// 是否显示可拖拽 dot// 可以在原点元素上增加 v-if 用来判定是否需要拖动功能const startSongDragDot = ref(true);useSongProgressDrag(audioEle, pgsWrapperEle, updateProgress, startSongDragDot);
最后调用这个 hook
audio
pour déterminer l'état de la chanson en cours, qu'elle soit en lecture ou en pause, puis déclarez un attribut pour synchroniser cet état, et faites un jugement dans le modèle selon lequel la chanson actuelle doit afficher "Play/pause".
audio.paused
: indique si le lecteur actuel est en pause audio.play()
: lecture 🎜🎜audio.pause ()
: Pause🎜🎜rrreee🎜Enfin, appliquez les attributs et les événements au modèle. 🎜rrreeeRéalisez l'heure de début/fin, l'heure de début et la barre de défilement pour suivre dynamiquement la dynamique de lecture
🎜🎜Idée : Obtenez la durée de lecture actuelle et la durée totale, et puis obtenez la durée actuelle/durée totale et obtenez le pourcentage de lecture de la chanson, qui est le pourcentage de la barre de défilement. En écoutant l'événementtimeupdate
de l'élément audio
, chaque fois que l'heure actuelle change, le DOM est également mis à jour de manière synchrone. Une fois la lecture finale terminée, l'état est initialisé. 🎜🎜API clé : 🎜🎜audio.currentTime
: durée de lecture actuelle ; unité(s) 🎜🎜audio.duration
: durée totale de l'unité(s) audio 🎜🎜 timeupdate
: cet événement est déclenché lorsque currentTime
change. 🎜🎜rrreeeRéalisez en cliquant sur la barre de progression pour accéder à la position de lecture spécifiée
🎜🎜Idée : enregistrez un événement de clic de souris pour la barre de défilement et obtenez le courantoffsetX
et la largeur de la barre de défilement, utilisez width / offsetX
et enfin utilisez la durée totale * pour obtenir la progression souhaitée, et mettez simplement à jour la progression bar à nouveau. 🎜🎜API clé : 🎜🎜event.offsetX
: La coordonnée x du pointeur de la souris par rapport à l'objet événement déclencheur. 🎜🎜rrreeeCliquez sur le point pour faire glisser la barre de défilement.
🎜🎜Idée : utilisezhook
pour gérer cette fonction de déplacement et écouter les événements de clic de souris, de mouvement de la souris et de soulèvement de la souris de cette barre de défilement. 🎜🎜Lorsque vous cliquez : Obtenez les coordonnées x
de la souris dans la fenêtre, la distance entre le point et la gauche
de la fenêtre et la distance maximale de déplacement à droite (barre de défilement largeur - la distance entre le point et la fenêtre) gauche
). Afin d'éviter que le mobile ne démarre le calcul par hasard, vous pouvez définir un commutateur drapeau
au début🎜🎜Lors du déplacement : Récupérez les coordonnées x
de la souris dans la fenêtre dans temps réel moins le clic. La coordonnée x
de . Ensuite, faites un jugement en fonction de la distance de déplacement maximale et ne la laissez pas sortir des limites. Enfin : Durée totale * (distance du point depuis gauche
de la fenêtre + x
calculé / longueur de la barre de défilement) Le pourcentage est obtenu pour mettre à jour la barre de défilement et progresser🎜🎜lorsqu'elle est levée :Réinitialiser le drapeau
. 🎜🎜rrreee🎜Enfin, appelez ce hook
🎜rrreee🎜[Recommandation associée : 🎜tutoriel vidéo vue.js🎜]🎜🎜Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

Video Face Swap
Échangez les visages dans n'importe quelle vidéo sans effort grâce à notre outil d'échange de visage AI entièrement gratuit !

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds





tinymce est un plug-in d'éditeur de texte riche entièrement fonctionnel, mais l'introduction de tinymce dans vue n'est pas aussi fluide que les autres plug-ins de texte riche de Vue. tinymce lui-même ne convient pas à Vue, et @tinymce/tinymce-vue doit être introduit, et Il s'agit d'un plug-in de texte riche étranger et n'a pas passé la version chinoise. Vous devez télécharger le package de traduction depuis son site officiel (vous devrez peut-être contourner le pare-feu). 1. Installez les dépendances associées npminstalltinymce-Snpminstall@tinymce/tinymce-vue-S2. Téléchargez le package chinois 3. Introduisez le skin et le package chinois Créez un nouveau dossier tinymce dans le dossier public du projet et téléchargez le.

vue3+vite:src utilise require pour importer dynamiquement des images et des rapports d'erreurs et des solutions. vue3+vite importe dynamiquement plusieurs images. Si vue3 est développé à l'aide de TypeScript, il y aura un message d'erreur indiquant que requireisnotdefined ne peut pas être utilisé comme imgUrl. :require(' .../assets/test.png') est importé car TypeScript ne prend pas en charge require, donc l'importation est utilisée. Voici comment le résoudre : utilisez waitimport.

Pour réaliser un rafraîchissement partiel de la page, il suffit d'implémenter le re-rendu du composant local (dom). Dans Vue, le moyen le plus simple d'obtenir cet effet est d'utiliser la directive v-if. Dans Vue2, en plus d'utiliser l'instruction v-if pour restituer le dom local, nous pouvons également créer un nouveau composant vierge. Lorsque nous devons actualiser la page locale, accéder à cette page de composant vierge, puis y revenir. la garde beforeRouteEnter dans la page d’origine vierge. Comme le montre la figure ci-dessous, comment cliquer sur le bouton d'actualisation dans Vue3.X pour recharger le DOM dans la zone rouge et afficher l'état de chargement correspondant. Puisque la garde dans le composant dans la syntaxe scriptsetup dans Vue3.X n'a que o

Pour implémenter le front-end du blog avec Vue, vous devez implémenter l'analyse markdown. S'il y a du code, vous devez implémenter la mise en évidence du code. Il existe de nombreuses bibliothèques d'analyse de démarques pour Vue, telles que markdown-it, vue-markdown-loader, Markdown, vue-markdown, etc. Ces bibliothèques sont toutes très similaires. Marked est utilisé ici et highlight.js est utilisé comme bibliothèque de mise en évidence du code. Les étapes d'implémentation spécifiques sont les suivantes : 1. Installez les bibliothèques dépendantes. Ouvrez la fenêtre de commande sous le projet vue et entrez la commande suivante npminstallmarked-save//marked pour convertir le markdown en htmlnpmins.

vue3+ts+axios+pinia réalise un rafraîchissement insensé 1. Téléchargez d'abord aiXos et pinianpmipinia dans le projet--savenpminstallaxios--save2 Encapsuler la requête axios-----Télécharger js-cookienpmiJS-cookie-s//Introduire aixosimporttype{AxiosRequestConfig , AxiosResponse}de"axios";importaxiosfrom'axios';import{ElMess

Préface Que ce soit vue ou réagir, lorsque nous rencontrons plusieurs codes répétés, nous réfléchirons à comment réutiliser ces codes, au lieu de remplir un fichier avec un tas de codes redondants. En fait, Vue et React peuvent être réutilisés en extrayant des composants, mais si vous rencontrez quelques petits fragments de code et que vous ne souhaitez pas extraire un autre fichier, en comparaison, React peut être utilisé dans le même Déclarez le widget correspondant dans le fichier. , ou implémentez-le via la fonction de rendu, telle que : constDemo:FC=({msg})=>{returndemomsgis{msg}}constApp:FC=()=>{return(

L'effet final est d'installer le composant VueCropper filaddvue-cropper@next. La valeur d'installation ci-dessus est pour Vue3 ou si vous souhaitez utiliser d'autres méthodes de référence, veuillez visiter son adresse officielle npm : tutoriel officiel. Il est également très simple de le référencer et de l'utiliser dans un composant. Il suffit d'introduire le composant correspondant et son fichier de style. Je ne le référence pas globalement ici, mais j'introduis uniquement import{userInfoByRequest}from'../js/api. ' dans mon fichier de composant import{VueCropper}from'vue-cropper&.

Une fois le projet vue3 empaqueté et publié sur le serveur, la page d'accès affiche un 1 vide. Le publicPath dans le fichier vue.config.js est traité comme suit : const{defineConfig}=require('@vue/cli-service') module.exports=defineConfig({publicPath :process.env.NODE_ENV==='production'?'./':'/&
