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

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

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

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

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Q&A

解決済

3回答

13891閲覧

jQueryによるメニュー切り替え時の不具合

abell

総合スコア12

JavaScript

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

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

0グッド

0クリップ

投稿2016/04/05 15:03

編集2016/04/06 02:38

jQueryの質問になります。
JSの経験がほぼないため、具体的な修正方法を教えていただければと思います。

ウィンドウサイズが860以上の場合は横並びメニューを表示(親メニューのホバーで子メニューが表示)し、860以下になった場合はハンバーガーメニューに切り替わることを想定し、以下のような記述をしました。

jQuery

1$(window).on("load resize", 2 function() { 3 var w = $(window).width(); 4 var x = 860; 5 if (w > x) { 6 $(".navi_parents").hover(function() { 7 $(this).children(".navi_child").slideDown(); 8 }, function() { 9 $(this).children(".navi_child").slideUp(); 10 }); 11 } 12 if (w <= x) { 13 $("#global_navi").hide() 14 $(".nav_toggle").show(); 15 $(".navi_parents").children("a").removeAttr("href"); 16 $(".nav_toggle").click(function() { 17 $(this).toggleClass("open"); 18 $("#global_navi").toggleClass("open"); 19 }); 20 $(".navi_parents").click(function() { 21 $(this).find(".navi_child").toggleClass("open"); 22 }); 23 } 24}); 25

上記を実行したところ、下記のような現象が起きています。

(その1)
ウィンドウサイズが860以上のところから860以下に狭めると、ハンバーガーメニューが表示され、想定通りの挙動となるが、860以下から860以上に変更してもハンバーガーメニューのままになっている。

(その2)
ハンバーガーメニュー表示時、メニューからリンク先へ飛んだときにメニューをクリックすると開閉されるが、画面をスクロールした途中でメニューをクリックするとメニューの開閉がされない。

自分でも色々試してみたのですが、原因がわからず行き詰まっております。
よろしくお願いします。。

【追記】
説明不足で申し訳ございません。
メニュー部分ですが、以下のようになっています。

HTML

1<div class="navi"> 2 <div class="nav_toggle"> <!-- ハンバーガーメニュー表示用 --> 3 </div> 4 <nav id="global_navi"> <!-- ナビゲーション部分 --> 5 <ul> 6 <li class="navi_parents"><a>メニュー1</a> <!-- 親メニュー --> 7 <ul class="navi_child"> <!-- 子メニュー(親メニュークリックで開閉) --> 8 <li><a>子メニュー1</a></li> 9 <li><a>子メニュー2</a></li> 10 </ul> 11 </li> 12 <li><a>メニュー2</a></li> 13 <li><a>メニュー3</a></li> 14 </ul> 15 </nav> 16</div>

860以下で#global_naviが非表示となり.nav_toggleが表示されます。
.nav_toggleをクリック(タップ)することで#global_naviが開閉でき、さらに親メニューをクリック(タップ)することで子メニューが開閉できるようになる想定です。

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

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

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

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

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

manabufukai

2016/04/05 16:31

・どの要素が親メニューで子メニューか ・どの要素がハンバーガーメニューになるのか を明示していただいたほうが、正確な回答が得られると思います。
abell

2016/04/06 02:39

情報を追記させていただきました。 説明不足で申し訳ございません。
guest

回答3

0

今頃ですがCSSを利用する方法はいかがでしょうか?
動的なページは作れませんし、記述量は多くなりますが、かなり簡単に行えます。

CSS

1@media screen and (max-width: 860px){ .sp {display:none} } 2@media screen and (min-width: 861px){ .pc {display:none} }

HTML

1<div class="sp"> 2ここに860px以下で表示したいものを記入 3</div>

HTML

1<div class="pc"> 2ここに861px以上で表示したいものを記入 3</div>

Javascript に関しては当方は無知に近いので…

投稿2018/03/11 02:44

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

0

ベストアンサー

(その1)

他の回答者様もおっしゃっているように「切り替えが無い」のがポイントです。
以前に回答したものに大部分が流用できるコードがあるので
こちらも参照してみてください。
https://teratail.com/questions/31341
※上記回答の4/3追記:画面リサイズでも動くようにの箇所

変更すべき点としては
$(".navi_parents").children("a").removeAttr("href");
でhref属性を削除してしまっているのでリサイズで再度リンクを復帰させることを考えると

$('.navi_parents').children('a').on(‘click’,function(){return false;}

でリンクを無効にし
横並びメニュー時に
$('.navi_parents').children('a').off(‘click’)
で「無効にしたクリックイベント」を削除するのが妥当かと思います。

同様に、.hover()はイベントキャンセルできなかったと思うので(うろおぼえですが)
w > x の時は

$('.navi_parents').on({ 'mouseenter' : function(){ /// }, 'mouseleave' : function(){ /// }, });

にして、w <= xの際は$('.navi_parents').off('mouseenter mouseleave')すると良いでしょう。

.on()で追加したイベントは.off()で削除でき
.on()でまた追加すればいい、といった考え方です。

その2

画面サイズが860未満の際.openを付与することをで開閉するcssを指定しているのだと思いますが
考えられるのは

  1. cssの指定が効いているか
  2. .navi_childのz-index
  3. .navi_childかその親要素のスタイル属性に何か付いている

あたりかと思います。開発者ツールで一度ご確認されてみてはいかがでしょう?
(おそらく#global_naviをhide()しているあたりが怪しいかと)
親要素を非表示にしていると、子要素は表示されないので
非表示のさせ方か、非表示させる要素を変える、等が必要かと思います。


注意点
.on()はイベントを「追加」なので、window.resize時の複数回呼び出しが起こると
その回数分イベントを追加する => 参考の回答にあるような状態判定とresize時の処理ストップ必須。
加えて言うと、モバイルブラウザではスクロール時のアドレスバーの引っ込み⇔表示時にもresizeイベントが発生するので尚処理ストップ必須

投稿2016/04/06 05:17

編集2016/04/06 05:25
manabufukai

総合スコア700

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

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

abell

2016/04/06 08:51

ご回答ありがとうございます。 (その1)につきまして、下記のように設定したところ、860以上のときのドロップダウンの表示と、860以下になったときのハンバーガーメニューの表示がされなくなりました。 こちら、何か記述方法を間違っておりますでしょうか。 $(window).on("load resize", function() { var w = $(window).width(); var x = 860; if (w > x) { $("#global_navi").show(); $(".nav_toggle").hide(); $('.navi_parents').children('a').off("click"); $(".navi_parents").on( { "mouseenter" : function() { $(this).children(".navi_child").slideDown(); } "mouseleave" : function() { $(this).children(".navi_child").slideUp(); } }); } if (w <= x) { $("#global_navi").hide(); $(".nav_toggle").show(); $(".navi_parents").off("mouseenter mouseleave"); $(".navi_parents").children("a").on("click", function(){ return false; }; $(".nav_toggle").click( function() { $(this).toggleClass("open"); $("#global_navi").toggleClass("open"); }); $(".navi_parents").click( function() { $(this).find(".navi_child").toggleClass("open"); }); } }); (その2)につきましては、メニューが非表示となっている関係でまだ確認が取れておりません…。
manabufukai

2016/04/06 12:26

デベロッパーツール等の開発ツールは使用されていないのでしょうか? JavaScriptの開発においてブラウザの開発ツールは必ず使用しましょう。 ブラウザによって違いますが「Option+Cmd +i」や「Shift+ctr+i」(すみません、Winはちょっとうろおぼえです…)などのショートカットかブラウザ右上のハンバーガーメニュー等から表示できます。 ※マウスを使用してらっしゃるなら調べたい要素の上で右クリックから「要素を調査」(ブラウザにより違います)でも出たと思います。 12行目の「}」の後の「,」 $(".navi_parents").children("a").on("click", function(){ return false; }; の「)」等が抜けているためSyntaxErrorが出ているのではないでしょうか…? 試しにコピペしてみてみましたが、やはりこの2箇所がエラーを表示しています。 (その2)について言ったことも開発ツールを使えば分かると思いますので 一度チェックしてみてはいかがでしょうか? .openがどのようなはたらきをするか、 ナビ周りのcssの指定がどうなっているのかが分からないので推測になりますが > 親要素を非表示にしていると、子要素は表示されないので > 非表示のさせ方か、非表示させる要素を変える、等が必要かと思います。 ここがかなり怪しいです。 …あと、結構書き換えないと理想としてらっしゃる動きにはならないかな…と思います。
abell

2016/04/07 02:48

再度のご回答ありがとうございます。 開発者ツールは使用しているのですが、通常CSSの確認でしか使用したことがなく、JSの場合の使用方法がわからず躓いておりました。 開発者ツールの使い方については、勉強します。 (その1)につきましては、解決いたしました。 ありがとうございました。 (その2)についてなのですが、PCのブラウザでは上記の挙動が確認できず、スマホでのみ起こっているようです。 なのですが、実機で確認したところ、以下のような現象が起きています。 ・下にスクロールし、タップした場合は正常に表示される(Chromeの場合) ・上にスクロールし、ブラウザのメニューが消えた状態(Android端末のブラウザメニュー部分です)でタップすると反応しない(Chromeの場合) ・開発者ツールでブラウザメニューが表示されていない状態で上にスクロールしタップすると、正常に表示される(Chromeの場合) ・下にスクロールし、タップした場合、反応しない(Firefoxの場合) ・上にスクロールし、ブラウザのメニューが消えた状態(Android端末のブラウザメニュー部分です)でタップすると正常に表示される(Firefoxの場合) 調べても事例がなく、検証自体もどのように行えばいいのかわからずにいます。
manabufukai

2016/04/07 04:05

まず第一に、 『今見ている部分以外に問題の原因がある』ということも少なくありません。 一つ一つ問題を切り分けていきましょう。 1. タップが反応しない  $(".nav_toggle").click(fun())に対して  alert('タップ' + $(this).hasClass('open'));  console.log('タップ' + $(this).hasClass('open'));  を追記してください。  二つ記述するのは、お話を伺う限りモバイルのデバッグ環境を構築されていないと考えるため、本来使うconsole.log()がモバイルでは閲覧できないからであろうというためです。(alertをモバイル実機でのデバッグ用として)  console.logを使うとデベロッパーツール下部のconsoleの箇所にメッセージが表示されるはずです。  ・表示されない場合はclickできていない=その上に要素が乗っているのではないか?=>global_naviとその兄弟要素等のcssをチェック。  ・出力しようとした内容と違うメッセージ=JSの記述に間違いがある  ・出力された=タップそのものは生きていて、コールバックに渡したtoggleClassに問題がある  ということになります。  これを使ってデバッグしていってください。 2. まずはPCのChromeでブラウザ幅を縮めただけの状態でチェック   その次にChromeデベロッパーツール左上のユーザーエージェント切り替え(モバイルとタブレットのアイコン)をクリックした状態でチェック   それらで問題が出なければ実機でチェック、という流れで行ってみてください。
abell

2016/04/07 05:01

ご丁寧にありがとうございます。 上記のやり方で確認をしてみたところ、3番目の事象のようです。 これは、タップ自体は生きていて、toggleClassもされている(console.logにはfalse, trueが出てきます。正常な場合はfalseとなります)が、toggleの回数が一回多くなっている、ということでしょうか? スクロールしてメニューが開く状態だと、false, true, falseとなり最終的にメニューは開くのですが、classに対する操作の回数が増えています…。
manabufukai

2016/04/07 10:39 編集

なるほど、ではもう少し追求していきましょうか。 あと、可能な限り情報は開示したいただけますでしょうか? かつ正確に伝えていただいたほうが解決は早まります。 1. メニューが開かない際←ここでおっしゃっているメニューというのは子メニュー(.navi_child)のことですね? 2. 開く際というのはnavi_childにopenクラスが付与されている状態で間違いありませんか? 3. 開かない際、.navi_childのクラスはついていますか? 4. > classに対する操作の回数が増えています…。 というのは、『1度のクリックでconsoleに複数回メッセージが出力される』という認識でよろしいですね? ※4が確認できた環境はPCでしょうか?モバイルでしょうか?  前の回答では開かなくなるのはモバイル環境というお話だったかと思いますが  これはalertで「false, true, false」と出力されたということですか? ※もし、2の際にモバイルで付与されているかが確認できない状態、というのであれば  .openに対し{color:red}など、要素を視覚的に変化させるcssを付与して確認してみてください。
abell

2016/04/11 01:07 編集

ありがとうございます。 説明が不足しており申し訳ございません。 環境としては、AndroidのChromeをPCのChromeで確認(Chrome inspectを利用)しています。 PCでのブラウザ幅を縮めただけでは上記問題は検出できなかったのですが、実機のChrome画面をPC上で表示することで再現&開発者ツールでの確認ができました。 その上で、以下を実行し、結果が得られました。 1、860以下でハンバーガーメニュー(.nav_toggle)が表示される 2、スクロールしていない状態およびブラウザのメニューが表示されている状態(Chromeのみ)およびブラウザのメニューが表示されていない状態(Firefoxのみ)の場合、.nav_toggleをタップすることで#global_naviに.openが追加され、メニューが開く  (この時、コンソールログにはfalseが返される) 3、ブラウザのメニューが表示されていない状態(Chromeのみ)およびブラウザのメニューが表示されている状態(Firefoxのみ)の場合、.nav_toggleをタップしても#global_naviに.openが追加されず、コンソールログにはfalse, trueが表示される 4、スクロールし、ブラウザのメニューが表示されている状態(Chromeのみ)およびブラウザのメニューが表示されていない状態(Firefoxのみ)で.nav_toggleをタップすると、#global_naviに.openが追加されるが、コンソールログにはfalse, true, falseが返される ※.navi_childは#global_naviの該当リンクをタップした場合に.openが追加され表示される仕組みとなっていますので、.nav_toggleのタップ時点では表示されておりません。 うまく伝わりますでしょうか…?
manabufukai

2016/04/08 09:29

コードの開示ありがとうございます。 最初の回答でも言っていた通り > window.resize時の複数回呼び出しが起こると その回数分イベントを追加する => 参考の回答にあるような状態判定とresize時の処理ストップ必須。 > 加えて言うと、モバイルブラウザではスクロール時のアドレスバーの引っ込み⇔表示時にもresizeイベントが発生するので尚処理ストップ必須 が原因なのではないでしょうか? 1. モバイルブラウザのアドレスバーが縮小前 => .nav_toggleのクリックイベントは1回 2. モバイルブラウザのアドレスバーが縮小した後 => .nav_toggleのクリックイベントは2回発生 3. モバイルブラウザのアドレスバーが縮小した後、再度ページトップへ戻す等してアドレスバーを縮小前のサイズに => .nav_toggleのクリックイベントは3回発生 ・ ・ ・ 以後この操作を繰り替えす度に、クリック一回につき発生するイベント回数は増加していきました。 $(window).on("resize")を使用する際は以下の注意点を覚えておいてください。 ・画面サイズをドラッグ等で変更した際、一度変えただけで、resizeイベントは4~7回程度発生します(※ドラッグのスピードやブラウザにより差異があります) ・画面のサイズが変更された時に発生する=ブラウザ内の縦幅が変わっても呼び出されます(つまるところ、モバイルブラウザのUIサイズが変わった際、windowのheightは変更されていて、その都度resizeイベントは発生しています) ・window幅によってイベントを分岐させたい際、現在の状態判定を行ったうえ、「状態が〜なら、イベントを繰り返さない」といった処理が必要になります 上記を踏まえて、とりあえず簡単に修正すると var menuType; //メニューの状態を判別する変数 $(window).on("load resize",function() { var w = $(window).width(); var x = 974; if (w > x) { if(menuType === 'horizonMenu') return; //menuTypeがhorizonMenuになっていたら以後の処理を行わない menuType = 'horizonMenu'; //menuTypeを「横並びである」とする $("#global_navi").show(); $(".nav_toggle").hide(); $(".navi_parents").on( { "mouseenter" : function() { $(this).children(".navi_child").stop(true,true).slideDown(); }, "mouseleave" : function() { $(this).children(".navi_child").stop(true,true).slideUp(); } }); } if (w <= x) { if(menuType === 'humburgerMenu') return; //menuTypeがhumburgerMenuになっていたら以後の処理を行わない menuType = 'humburgerMenu'; //menuTypeを「ハンバーガーメニューである」とする $("#global_navi").hide(); $(".nav_toggle").show(); $(".navi_parents").off("mouseenter mouseleave"); $(".navi_child").addClass("open"); $(".nav_toggle").on("click", function() { console.log('トグル' + $(this).hasClass('open')+'/ 親メニュー' + $("#global_navi").hasClass('open')); $(this).toggleClass("open"); $("#global_navi").toggleClass("open"); }); } }); といったところでしょうか。 ●変更点 ・$(window).on("load resize")より上のスコープ(or グローバル)へ状態判別用の変数を作成(中に作成すると意図しない変更が起こるため) ・windowサイズ毎のイベント分岐時に状態判別変数へ状態を格納 ・windowサイズ変更時に状態判別変数による判定を追加 (・.slideDown()や.slideUp()のアニメーション中に重複してイベントを発生させない為.stop(true,true)追加 => 提示のコードでは、ホバーを何度も繰り返すと、繰り返した回数分アニメーションが繰り返されるため)
abell

2016/04/10 03:32

長々とお付き合いいただき、大変感謝しております。 ありがとうございます。 上記の通り修正したところ、期待通りの動きができました。 変数の位置で挙動が変わったり何度もアニメーションさせない記述など、知らなかったことが多くあり、勉強になりました。 本当にありがとうございました。
guest

0

(その1)は、860を超えた時に表示の切り替えが必要では?
こんな感じで。
if (w > x) {
$("#global_navi").show(); // <-追加
$(".nav_toggle").hide(); // <-追加

(その2)は、ちょっとイメージ湧かないですが、
そもそもハンバーガメニューはhoverでのみDropDownするのでは?
あと、メニューはスクロールについてきているという事でしょうか?
その上で、hoverしてもDropDownされない?
もしかして、スマフォやタブレット上での動作、つまりタップ時の動作だったりします?

投稿2016/04/05 17:31

harufumi.abe

総合スコア26

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

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

abell

2016/04/06 02:30

ご回答ありがとうございます。 (その1)については、ご指摘の通りでした。 ありがとうございます。 (その2)ですが、説明不足で申し訳ございません。 ハンバーガーメニューはクリック(タップ)によってドロップダウンする想定です。 メニュー(ヘッダー)部分は画面上部に固定となっており、スクロールしても画面上には常に表示されている状態です。 メニューを開いてタップするとページ内のリンク先へ飛ぶのですが、一度画面をスクロールしてしまうと、タップしてもメニューが開かない、という現象が起きています。 (メニューが開ける状態でリンク先へ飛ぶ→スクロールせずに再びメニューをタップすればメニューの開閉はできます)
harufumi.abe

2016/04/06 03:40

すみません、私も読み違えていました。 確かにクリック(タップ)で表示ですね。 で、ぱっと思いついたのは、"#global_navi"の方がスクロールについてこない仕組みでは? っと思ったのですが、860以上の横幅の時、ついてきますか? あと、"open"クラスでdisplayのnoneとblockを切り替える仕組みでは無いかと思いますが、スクロールした時に、Chromeのf12ツールで".navi_parents"がどこにいるか見てみると答えは出るような気がします。
abell

2016/04/07 02:51 編集

お返事遅くなり申し訳ございません。 (その2)について、上でも回答しているのですが、以下のような現象が起きています。 ・PCのブラウザでは上記の挙動が確認できず、スマホでのみ発生 (Android Chromeで確認) ・下にスクロールし、タップした場合は正常に表示される ・上にスクロールし、ブラウザのメニューが消えた状態(Android端末のブラウザメニュー部分です)でタップすると反応しない ・開発者ツールでブラウザメニューが表示されていない状態で上にスクロールしタップすると、正常に表示される (Android Firefoxで確認) ・下にスクロールし、タップした場合、反応しない ・上にスクロールし、ブラウザのメニューが消えた状態(Android端末のブラウザメニュー部分です)でタップすると正常に表示される ブラウザメニューに依存しているのかと思えるのですが、そこから行き詰まっております。。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問