質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
if

if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

Q&A

解決済

1回答

2009閲覧

Javasprictのみで動画と画像の混ざったスライドショーの適切な無限ループの方法での質問です

songnakai

総合スコア18

if

if文とは様々なプログラミング言語で使用される制御構文の一種であり、条件によって処理の流れを制御します。

PHP

PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

ループ

ループとは、プログラミングにおいて、条件に合致している間、複数回繰り返し実行される箇所や、その制御構造を指します

再帰

情報工学における再帰とは、プログラムのあるメソッドの処理上で自身のメソッドが再び呼び出されている処理の事をいいます。

0グッド

0クリップ

投稿2020/02/07 12:05

前提・実現したいこと

サーバーにアップロードした動画(mp4)と画像(jpg)をPHPで動的に表示させ、JavaScriptにてスライドショーにしてループさせるプログラムを作ろうとしています。

/mediaのディレクトリ内にあるファイルがmp4,jpgなら数や順番にかかわらず自動再生し、動画は最後まで再生、画像は4秒でスライドする仕組みです。
動画は再生が終わったらcurrenTime = 0;で再生ヘッドを戻し、pause()で一時停止させて次のスライドに進めています。

リストである<li>にはposition: absoluteを適応してすべて重ねており、showクラスを与奪することで表示を切り替えさせています。

発生している問題・エラーメッセージ

1巡目は想定通りの挙動なのですが、2巡目から動画が再生し終わると次のようなエラーメッセージが表示されるようになり、その後のshowクラスの付与に誤作動が出てしまいます。

console

1Uncaught TypeError: slideList[num].pause is not a function at HTMLVideoElement.<anonymous> (javascript2.js:22)

そしてこのエラーメッセージは3巡目には2つ、4巡目には3つ重なって出てきます。
showクラスの誤作動はshowクラスが消えずに残ったり、2つ同時に与えられたりするような感じです。

該当のソースコード

PHP

1<!doctype html> 2<html> 3<head> 4<meta charset="utf-8"> 5<title>無題ドキュメント</title> 6<link rel="stylesheet" type="text/css" href="style.css"> 7<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0"> 8</head> 9 10<body> 11 <div class="media-space"> 12 <ul> 13 <?php $media = glob('media/*'); 14 15 foreach($media as $key => $file): //ファイルのインデックス番号とファイル名取得 16 17 if(is_file($file)): 18 19 $mediaPass = htmlspecialchars($file); //ファイル名 20 21 if(preg_match_all('/.jpg/',$mediaPass)): //拡張子がjpgなら?> 22 23 <li><img id="imgControl<?php echo $key ?>" src="<?php echo $mediaPass; ?>" class="img-control" alt=""></li> 24 25 <?php elseif(preg_match_all('/.mp4/',$mediaPass)): //拡張子がmp4なら ?> 26 27 <li><video id="videoControl<?php echo $key ?>" src="<?php echo $mediaPass; ?>" class="img-control" muted="muted" 28 style="margin: auto"></video></li> 29 30 <?php else: //拡張子がどちらでもなければ ?> 31 32 <p>jpg、mp4ではないファイルです</p> 33 </ul> 34 <?php endif; ?> 35 <?php endif; ?> 36 <?php endforeach ;?> 37 </div> 38 39 <script src="javascript.js"></script> 40 </body> 41</html>

JavaScript

1// JavaScript Document 2 3var slideList = document.querySelectorAll('li *'); 4var slideListParent = document.querySelectorAll('li'); 5var num = -1; 6 7function slideShow(){ 8 if(num === (slideListParent.length - 1)){ 9 num = 0; 10 }else{ 11 num ++; 12 }//end if 13 14 if(slideList[num].matches('video')){ 15 16 slideListParent[num].classList.toggle('show'); 17 slideList[num].play(); 18 slideList[num].addEventListener('ended',function(){ 19 20 slideListParent[num].classList.toggle('show'); 21 slideList[num].currentTime = 0; 22 slideList[num].pause(); 23 slideShow(); 24 });//end addEventListener 25 }else{ 26 slideListParent[num].classList.toggle('show'); 27 setTimeout(nextSlide,4000); 28 function nextSlide(){ 29 30 slideListParent[num].classList.toggle('show'); 31 slideShow(); 32 }// end function nextSlide() 33 }//end if 34 if(num === 0){ 35 return; 36 } 37 }// end function slideshow() 38 39 40addEventListener('load',slideShow);// end addEventListener

試したこと

関数内で処理が終わる前に同じ関数を呼び出して処理が重なったことが不具合の原因かと思いますが、if文をJavaScriptコードの末端に持ってきて、一周したら(num === 0)returnで最初の処理が終わるのかなと思いましたが改善されませんでした。

slideshow()の枠の外で同関数を呼び出せばいいのかなと思ったのですが、動画と画像を織り交ぜてスライドさせるには
setInterbal()は一定時間でのスライドになるから使えず、イベントトリガーの中で呼び出さざるを得ない状況です。

どなたかご教授いただけると幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2020/02/07 12:57

>Javasprictのみで でしたらPHP関連の処理はなぜあるのでしょうか。 ブラウザに表示されたHTMLだけ提示でも良いのでは?
songnakai

2020/02/07 14:17

失礼しました。 jQueryなどのライブラリやプラグインを使わないという意味でした。 PHPはファイルの拡張子や数に左右されないように使っております。
guest

回答1

0

ベストアンサー

addEventListener を用いて登録したイベントを削除していないからではないでしょうか。

順番が来るたびにイベントが追加され、イベントが発生するとそれまでのループで追加された過去のイベントも実行されていると思います。試しにイベントハンドラの冒頭でログ出力してみてください。

二週目以降は一度のビデオ終了で二回ログが出力されると思います。

javascript

1slideList[num].addEventListener('ended',function(){ 2 console.log('イベント発火 > ' + num) 3 slideListParent[num].classList.toggle('show'); 4 // ... 省略 5})

イベント登録はループの外で行うようにして、重複して登録されないよう工夫してください。

投稿2020/02/07 12:26

編集2020/02/07 12:38
R.Mizukami

総合スコア1086

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

songnakai

2020/02/07 14:14

おっしゃっていただいたように、`addEventListener`のなかが多重ループしているようで、`num`の部分が連続した数字になり showクラスの与奪に誤作動が出ていたようです! ありがとうございます。 ただこれを解決するには教えていただいたようにループ外でイベントを行う場合(今回だとif文~slideShow()を呼び出すまで)、動画が終了したら次のスライドに移る仕組みになっているため`addEventListener`の`ended`の中にループさせるための再帰であるslideShow()関数を記述しなければならず、ループの中から外せないように思いますが、そもそもの仕組みが悪いんでしょうか? もう一つ`removeEventListener`でイベント削除も試みましたが ```JavaScript slideList[num].addEventListener('ended',function movieEvent(){ console.log('イベント発火>' + num); slideListParent[num].classList.toggle('show'); slideList[num].currentTime = 0; slideList[num].pause(); slideShow(); });//end addEventListener slideList[num].removeEventListener('pause',movieEvent); ``` `removeEventListener`にmovieEvent関数を入れると`undefined`のエラーで渡せないという問題が出ております。
R.Mizukami

2020/02/07 15:01

slideShow() 関数の外から slideShow() 関数を呼び出すことは当然可能です。 slideShow() 関数の外で、slideList 内の全 video 要素に対し、あらかじめイベントを登録すれば、ループ内でイベントを登録する必要がなくなり、問題が解決するはずです。 removeEventListener でエラーがでるのは、 movieEvent 関数にアクセスできるスコープの外にいるからです。 var movieEvent = function() { ... } などとし、 addEventListener( ~, movieEvent) や removeEventListener( ~, movieEvent) などとすればイベントの削除はできます。ただし、その位置でイベントを削除してしまうと、 ended イベントが発生する前にリスナが削除されるので、今度は次のスライドに移動できなくなると思います。 どうも JavaScript の基本的な文法部分に誤解があるようなので、そのあたりを再確認いただくといいと思います(申し訳ございませんが、ここで全てを説明するのは難しい量になります)。
songnakai

2020/02/08 06:55

結論ですが、解決いたしましたのでご報告いたします! 結果的に上記のaddEventListenerのオプションに{once:true}を入れて実行後にイベント削除させるという方法でエラーなく無限ループにすることができました。 まだまだ歴が浅く、スコープや同期、非同期など教えていただいた内容を理解することで解決できました、本当にありがとうございます! ただ個人的に悔しいのは教えていただいた関数外で呼び出してループさせる形がなかなか難しくて結局slideshow関数内で同関数を呼び出す形は変えられず。 Promiseなども調べましたがまだまだ勉強不足だなと実感しました。 回答いただいた内容をしっかり理解できるよう今後も精進してまいります。 この度はしっかり回答いただきありがとうございました! 今後ともよろしくお願いします!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問