なお、これはvue-cliで作成したプロジェクトではありません。vue.jsを参照して記述したHTMLファイルです。HTMLファイルに貼り付けるだけで使用できます。私の音楽リンクは一定期間後に無効になります。音楽は自分で用意する必要があります。ドラッグとクリックで再生進行を切り替える機能があります。 デモ写真 コード <!DOCTYPE html> <html lang="ja"> <ヘッド> <メタ文字セット="UTF-8"> <meta http-equiv="X-UA-compatible" content="IE=edge"> <meta name="viewport" content="width=デバイス幅、初期スケール=1.0"> <title>ドキュメント</title> </head> <本文> <div id="アプリ"> <audio ref="audioRef" 自動再生 @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="プログレスバーラッパー"> <cpn :progress=進捗状況 @progress-changing="onProgressChanging" @progress-changed='progressChanged'> </cpn> </div> <span class="time time-l">{{formatTime(duration)}}</span> </div> </div> <!-- 子コンポーネント --> <テンプレートid="myCpn"> <div class="プログレスバー"> <!-- 後ろに黒い帯があります --> <div class="bar-inner" @click="clickProgress"> <!-- プレイ済みのエリア --> <div class="progress" :style='progressStyle' ref="progress"> </div> <!-- ボタン --> <div class="progress-btn-wrapper" :style='btnStyle' @touchstart.preventDefault='onTouchStart' @touchmove.preventDefault='onTouchMove' @touchend.preventDefault='onTouchEnd' > <div class="progress-btn"></div> </div> </div> </div> </テンプレート> <script src="../../js/vue.js"></script> <スクリプト> オーディオEl = null 定数プログレスボタン幅 = 16 // サブコンポーネント const cpn = { テンプレート: "#myCpn", 小道具: { 進捗: タイプ: 数値、 デフォルト: 0 } }, データ() { 戻る { オフセット: 0 } }, マウント() { }, 作成された() { this.touch = {} }, 計算: { 進捗スタイル() { `width: ${this.offset}px` を返します }, btnスタイル() { // コンソールログ('fds'); `transform: translate3d(${this.offset}px,0,0)` を返します }, }, 時計: 進捗状況(新しい進捗状況) { // プログレスバーの幅 const barWidth = this.$el.clientWidth - progressBtnWidth this.offset = barWidth * newProgress } }, メソッド: { onTouchStart(e) { // コンソールログ(e); this.touch.x1 = e.changedTouches[0].clientX // 黄色のプログレスバーの初期幅 this.touch.beginWidth = this.$refs.progress.clientWidth コンソールにログを記録します。 }, onTouchMove(e) { // コンソールログ(e); // x オフセット const delta = e.changedTouches[0].clientX - this.touch.x1 // 前回の幅 + 今回ドラッグして追加されたオフセット = 黄色のバーの予想される長さ const tempWidth = this.touch.beginWidth + delta // barWidthを再度取得する const barWidth = this.$el.clientWidth - progressBtnWidth // 黄色のバーの長さ/バー幅 = 進行状況 現在の進行状況は const progress = tempWidth / barWidth である必要があります this.offset = barWidth * 進捗状況 this.$emit('progress-changing', 進行状況) // console.log("tempWidth", tempWidth); // console.log("barWidth", barWidth); // console.log("進行状況", 進行状況); }, onTouchEnd(e) { // コンソールログ(e); const barWidth = this.$el.clientWidth - progressBtnWidth const progress = this.$refs.progress.clientWidth / barWidth this.$emit('progress-changed', 進行状況) }, // プログレスバーをクリック clickProgress(e){ // コンソールログ("fds"); console.log('getBoundingClientRect', this.$el.getBoundingClientRect()); 定数rect = this.$el.getBoundingClientRect() // 黄色のバーの幅 const offsetWidth = e.pageX - rect.x const barWidth = this.$el.clientWidth - progressBtnWidth const 進捗 = offsetWidth / barWidth this.$emit('progress-changed', 進行状況) console.log(オフセット幅) } }, } constアプリ = 新しいVue({ el: "#app", データ: { コンテンツ: 'fdasdf'、 ソース: 'https://music.163.com/song/media/outer/url?id=1463165983.mp3', 現在の時刻: 0, 期間: 0, 表示: false, 進捗状況の変更: false }, コンポーネント: cpn }, マウント() { this.$nextTick(() => { audioEl = this.$refs.audioRef audioEl.src = this.src // デフォルトで一時停止 audioEl.pause() }) }, 計算: { 進捗() { this.currentTime / this.duration を返します console.log("進行状況", this.currentTime / this.duration); }, }, メソッド: { 遊ぶ() { audioEl.play() this.isplay = true }, 一時停止() { audioEl.一時停止() this.isplay = false // コンソールログ(); }, 再生可能(e) { // コンソール.log(123456); コンソールログ(e); this.duration = e.target.duration }, 更新(e) { if(!this.progressChanging){ this.currentTime = e.target.currentTime } }, onProgressChanging(e) { // console.log("onProgressChanging", e); this.progressChanging = true // リアルタイムで currentTime 値を変更します this.currentTime = this.duration * e }, 進捗状況が変更されました(e){ // コンソールログ(e); this.progressChanging = false audioEl.currentTime = this.currentTime = this.duration * e if(!this.isplay){ コンソールログ("------"); audioEl.play() } }, フォーマット時間(間隔) { // 間隔を切り捨てた interval = interval | 0 // 2桁未満の場合は0で埋める 分 = ((間隔 / 60 | 0) + '') とします。 秒 = ((間隔 % 60 | 0) + '') とします len = 分.長さとする (; 長さ < 2; 長さ++) { 分 = '0' + 分 } len = 秒.長さ (; 長さ < 2; 長さ++) { 秒 = '0' + 秒 } `${分}:${秒}` を返します }, }, }) </スクリプト> </本文> <スタイル> #アプリ { 幅: 100%; } .progress-wrapper { ディスプレイ: フレックス; 幅: 80%; パディング: 10px 0; アイテムの位置を中央揃えにします。 マージン: 0 自動; } 。時間 { 幅: 40px; フレックス: 0 0 40px; フォントサイズ: 8px; マージン: 0 自動; パディング: 0 8px; } .time-l { テキスト配置: 左; } .time-l { テキスト配置: 右; } .プログレスバーラッパー{ フレックス: 1; } /* サブコンポーネントスタイル */ .プログレスバー{ 高さ: 30px; } .bar-inner { 位置: 相対的; 上: 11px; 高さ: 8px; 背景色: rgba(87, 82, 82, 0.062); 境界線の半径: 5px; } 。進捗 { 位置: 絶対; 高さ: 100%; 背景色: rgb(238, 238, 136); } .progress-btn-wrapper { 位置: 絶対; 左: -8px; 上: -11px; 幅: 30ピクセル; 高さ: 30px; } .progress-btn { 位置: 相対的; 上: 7px; 左: 7px; ボックスのサイズ: 境界線ボックス; 幅: 16px; 高さ: 16px; 境界線: 3px実線rgb(189, 189, 218); 境界線の半径: 50%; 背景: rgb(123, 192, 212); } </スタイル> </html> 解説 https://developer.mozilla.org/zh-CN/docs/Web/API/TouchEvent 中央の進行状況バーは進行状況バー コンポーネントです。黒い背景は進行状況の合計の長さです。左側の黄色のバーは、現在の再生の進行状況です。中央のスライダーを左右にドラッグして、進行状況バーを手動で変更できます。再生中は、進行状況バーが長くなり、スライダーが右に移動します。スライダーを左右にドラッグして再生の進行状況を変更すると、左側の時間が変わります。 再生プロセスを実現するために、進行状況バーも再生されます。コンポーネントの状態を決定するものは何ですか?進行状況によって決定できます。コンポーネントの任意の状態は進行状況に基づいて決定できます。親コンポーネントはデジタルタイプの進行状況を渡します ボタンの位置と進行状況を示す黄色のバーの幅は進行状況に基づいて計算されます。幅はデータ オフセット (データの定義) で表すことができます。次に、進行状況を監視する必要があります。 https://cn.vuejs.org/v2/api/#vm-el ルートDOM要素を取得するための知識 時計: 進捗状況(新しい進捗状況) { // プログレスバーの幅 const barWidth = this.$el.clientWidth - progressBtnWidth //オフセット this.offset = barWidth * newProgress } } もちろん、computed を使ってもよいですが、el の幅は最初に取得できないので注意が必要です。computed は最初に 1 回計算し、テンプレートがレンダリングされるときに offset にアクセスして、el の幅を計算します。このとき、コンポーネントはマウントされておらず、取得できません。watch を使用すると、進捗が変わったときに実際にレンダリングされているため、clientWidth を取得できます。また、一部のロジックは後で処理する必要があるため、ロジックの記述に傾きやすいため、watch を使用して実装する必要があります。 オフセットを取得したら、DOM をマップし、黄色のプログレス バーとボタンの動的なスタイルを設定する必要があります。 どちらのスタイルもオフセットに基づいて計算されます。 計算: { 進捗スタイル(){ `width: ${this.offset}px` を返します }, btnスタイル() { `transform: translate3d(${this.offset}px,0,0)` を返します } }, 次に、オフセットに基づいてスタイルを計算します。progress 属性を受け入れます。外部の進捗状況が変化すると、進捗状況に基づいてオフセットが計算されます。オフセットにより、スタイルを変更できます。 質問: flex 0 0 40px と width は同様の効果がありますが、場合によっては flex レイアウトが圧縮されたり折りたたまれたりして幅が圧縮されてしまうことがあります。そのため、width を設定することで幅が変化しないようにすることができます。 再生可能なイベントモニターはこちら 親コンポーネントは、再生の進行状況プロパティ(再生時間/合計時間)を計算します。合計時間が取得されました。再生時間は、イベントtimeupdateで監視できます。 現在の効果 これは秒数であり、時間をフォーマットする必要があることがわかります。ツール関数を定義します IIFE: 自己実行関数のカリー化といくつかのビット演算 https://www.jianshu.com/p/a3202bc3f7a4 質問: なぜ xxx.yyy|0 は xxx に等しいのですか? ここでの or 演算子が丸め機能を持つのはなぜですか? ナレッジパッドスタートメソッド formatTime 関数 フォーマット時間(間隔) { // 間隔を切り捨てた interval = interval | 0 // 2桁未満の場合は0で埋める 定数分 = ((間隔 / 60 | 0) + '').padstart(2, '0') 定数秒 = ((間隔 % 60 | 0) + '').padstart(2, '0') `${分}:${秒}` を返します } しかし、パッドスタート方式は認識できません。 だから自分で書いたんだ フォーマット時間(間隔) { // 間隔を切り捨てた interval = interval | 0 // 2桁未満の場合は0で埋める 分 = ((間隔 / 60 | 0) + '') とします。 秒 = ((間隔 % 60 | 0) + '') とします len = 分.長さとする for(;len<2;len++){ 分='0'+分 } len = 秒.長さ for(;len<2;len++){ 秒='0'+秒 } `${分}:${秒}` を返します } 次に、プログレスバーのインタラクティブロジックを記述します。 ドラッグとクリックをサポート モバイルデバイスで最も一般的なものは、ontouchstart、ontouchmove、ontouchendです。 知識防止修飾子 スライダーに3つのイベントを追加する メソッド: { onTouchStart(e) { コンソールログ(e); }, onTouchMove(e) { コンソールログ(e); }, onTouchEnd(e) { コンソールログ(e); } }, 取得する必要がある情報は 2 つあります。1 つはクリックされた場所、つまりその水平座標を知ることです。左側のプログレスバーの幅(オフセット) [画面X クライアントX ページX コンセプト touchmove 中に水平軸の位置も取得する必要があるため、データを共有オブジェクトにバインドすることができます。作成されたフック関数内でオブジェクトを定義できます。 作成された() { this.touch = {} }, 黄色のバーに参照を与えた後 onTouchStart(e) { // コンソールログ(e); this.touch.x1=e.changedTouches[0].clientX // 黄色のプログレスバーの初期幅 this.touch.beginWidth = this.$refs.progress.clientWidth コンソールにログを記録します。 }, onTouchStart(e) { // コンソールログ(e); this.touch.x1=e.changedTouches[0].clientX // 黄色のプログレスバーの初期幅 this.touch.beginWidth = this.$refs.progress.clientWidth コンソールにログを記録します。 }, onTouchMove(e) { // コンソールログ(e); // x オフセット const delta = e.changedTouches[0].clientX-this.touch.x1 // 前回の幅 + 今回ドラッグして追加されたオフセット = 黄色のバーの予想される長さ const tempWidth = this.touch.beginWidth + delta // barWidthを再度取得する const barWidth = this.$el.clientWidth - progressBtnWidth // 黄色のバーの長さ/バー幅 = 進行状況 現在の進行状況 const progress = tempWidth/barWidth this.offset = barWidth * 進捗状況 // console.log("tempWidth", tempWidth); // console.log("barWidth", barWidth); // console.log("進行状況", 進行状況); }, 整理してみましょう。最終的な目標はオフセットを取得することです。オフセットは、進捗状況と barWidth によって決まります。ここで進捗状況を計算するにはどうすればよいでしょうか。黄色のバーの現在の幅を合計幅で割る必要があります。黄色のバーの幅は、このスライドの初期幅 + x 距離です。次に、barWidth を取得するのは簡単で、計算できます。 これは冗長だと思いますか? 元の黄色のバーの幅 + このスライドの長さを使用すればよいのではないでしょうか? なぜ進行状況を計算する必要があるのでしょうか? 曲の進行状況が変わったことを外部に知らせる必要があり、それらを対応させる必要があるためです。 最終的には、オーディオを変更する必要があります。 これは親コンポーネントで行われます。 今はドラッグのみを実装しているので、イベントをディスパッチする必要があります。 ここでは、2 つのカスタム イベントをディスパッチします。1 つは進行状況変更イベントで、指がまだドラッグ中であり、離れていないことを意味します。 指が離れると、進行状況変更イベントがディスパッチされ、新しい進行状況が渡されます。 currentTimeの値をリアルタイムで変更する これはドラッグ時に現在の時間を変更するためのもので、手を離した時に音楽が変更されます。 しかし、一時停止中はドラッグできるものの、再生中にドラッグすると不具合が発生することがわかりました。 最適化: 変更時に、エフェクトが一時停止している場合は再生します。このとき、再生/一時停止をクリックしたときに反転する isplay を定義する必要があります。 では、バグを修正しましょう。再生中に、進行状況をドラッグすると問題が発生します。なぜでしょうか? progressChanging を監視することで、currentTime を変更します。currentTime が変更されると、progress は currentTime に基づいて新しい計算を行い、それを子コンポーネントに渡します。子コンポーネントはこのロジックに入ります。 オフセットが再計算されます。 最後に、 更新中に何らかの制御を行う必要があり、変更プロセス中にフラグを追加する必要があります。 つまり、更新機能では、変更がドラッグの過程にある場合、currentTime を変更しません。変更の過程では、プログレス バーが変更されたと見なされ、プログレス バーを変更する優先度が高くなります。自身の再生によって引き起こされる currentTime の変更の優先度は比較的低くなります。 それでおしまい。 ドラッグするだけでなく、クリックして対応する位置にジャンプすることもできます。 Knowledge webapi --getBoundingClientRect メソッドは、要素のサイズとビューポートに対する位置を返します (短い方を取得します)。 長いものを取得するにはpagexを使用します クリックプログレス(e){ // コンソールログ("fds"); console.log('getBoundingClientRect', this.$el.getBoundingClientRect()); 定数rect = this.$el.getBoundingClientRect() // 黄色のバーの幅 const offsetWidth = e.pageX - rect.x const barWidth = this.$el.clientWidth - progressBtnWidth const 進捗 = offsetWidth / barWidth this.$emit('progress-changed', 進行状況) console.log(オフセット幅) } これで、vue ソング プログレス バー デモに関するこの記事は終了です。vue ソング プログレス バーに関するより関連性の高いコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後も 123WORDPRESS.COM を応援していただければ幸いです。 以下もご興味があるかもしれません:
|
>>: MySQL 8.0.22 zip圧縮パッケージ版(無料インストール)のダウンロード、インストール、および構成手順の詳細
Linux には、マウントされたハードディスクとマウントされていないハードディスクの 2 種類のハー...
目次1. rsync、cpでファイルをコピーする2. xxxをoutfile構文に選択する3. 遅延...
1. コンポーネント First.js にはサブコンポーネントがあります。 './Admin...
1. 4つのrpmパッケージをダウンロードする mysql-コミュニティクライアント-5.7.26-...
序文Boost ライブラリは、標準ライブラリのバックアップとして機能し、C++ 標準化プロセスの開発...
目次シナリオ効果コード要約するシナリオ登録ページに携帯電話番号を入力し、登録インターフェイスを要求す...
Cocos Creator バージョン: 2.3.4デモのダウンロード: https://files...
1 HTML入門1.1 初めてのコード体験、最初のウェブページの作成XML/HTML コードコンテン...
結果: html <nav id="nav-1"> <a cl...
MySQL 5.7コマンドを使用するMySQLコマンドラインクライアント1. パスワードを入力してく...
シナリオリクエストが 10 件あるが、同時リクエストの最大数は 5 件で、リクエスト結果が必要である...
目次(1)はじめに: (2)クリップボードの内容をコピーする方法は次のとおりです。 (3)関数演算に...
Windowsでのインストールの紹介:こちらもご覧ください –》WindowsでのMySQL 8.0...
Web ページの制作では、要素の表示と非表示は非常に一般的な要件です。この記事では、要素を表示したり...
この記事では、二次リンク効果を実現するためのReact+tsの具体的なコードを参考までに共有します。...