トグル要素が開いている時のみ処理をする方法
解決済
回答 2
投稿
- 評価
- クリップ 0
- VIEW 18K+
以下の構成で「accordion_trigger」要素をトリガーに隣接する「togglearea」がスライドトグルで開閉するアコーディオン要素があります。
開いた時「accordion_trigger」には「active」クラスが付与されます。
$(".accordion_trigger").on("click", function() {
$(this).next().slideToggle();
$(this).toggleClass("active");
});
<div id="anchor01" class="accordion_trigger">トグル要素1のトリガー</div>
<div class="togglearea">トグル要素1で開く内容</div>
<div id="anchor02" class="accordion_trigger">トグル要素2のトリガー</div>
<div class="togglearea">トグル要素2で開く内容</div>
<div id="anchor03" class="accordion_trigger">トグル要素3のトリガー</div>
<div class="togglearea">トグル要素3で開く内容</div>
<div id="anchor04" class="accordion_trigger">トグル要素4のトリガー</div>
<div class="togglearea">トグル要素4で開く内容</div>
さらに、以下「humberger」で「drop_menu」が開くハンバーガーメニューで上記「anchor」IDへのページ内リンクナビゲーションが別途存在します。
<p class="humberger">ハンバーガーメニュー</p>
<div id="drop_menu">
<div>
<ul>
<li><a href="#anchor01">トグル要素1</a></li>
<li><a href="#anchor02">トグル要素2</a></li>
<li><a href="#anchor03">トグル要素3</a></li>
<li><a href="#anchor04">トグル要素4</a></li>
</ul>
</div>
</div>
「drop_menu」の各リンクをクリックした際、遷移先のトグル要素が閉の時のみ開の処理を行いたいです。
$(function(){
$("#drop_menu div ul li:eq(0) a").click(function(){
$("#drop_menu div ul").slideUp('slow');
$(".accordion_trigger:eq(0)").next().slideToggle();
$(".accordion_trigger:eq(0)").toggleClass("active");
});
});
$(function(){
$("#drop_menu div ul li:eq(1) a").click(function(){
$("#drop_menu div ul").slideUp('slow');
$(".accordion_trigger:eq(1)").next().slideToggle();
$(".accordion_trigger:eq(1)").toggleClass("active");
});
});
$(function(){
$("#drop_menu div ul li:eq(2) a").click(function(){
$("#drop_menu div ul").slideUp('slow');
$(".accordion_trigger:eq(2)").next().slideToggle();
$(".accordion_trigger:eq(2)").toggleClass("active");
});
});
$(function(){
$("#drop_menu div ul li:eq(3) a").click(function(){
$("#drop_menu div ul").slideUp('slow');
$(".accordion_trigger:eq(3)").next().slideToggle();
$(".accordion_trigger:eq(3)").toggleClass("active");
});
});
以上の処理を試したのですが、すでに開の時も動作してしまいうまくいかない状態です。ここからすでに開いているときは処理しないという条件分岐の仕方がわからずご質問させていただきました。
ご教授の程よろしくお願いいたします。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
まず、slideToggle()
は表示されていない (slideUp
されている) 要素なら slideDown
し、
表示されている (slideDown
されている) 要素なら slideUp
する、というアニメーションです。
アニメーション終了後は (アニメーション中も) 対象要素に何らかのクラスがつくのではなく、style="..."
の形で属性が付き、要素の高さが変わっていき最終的に style="display: none"
になったりするようです。
ですので、対象要素の開/閉は、その要素の表示/非表示で判断することになるでしょう。
なので、この部分の処理は、
$(function(){
$("#drop_menu div ul li:eq(0) a").click(function(){
// $("#drop_menu div ul").slideUp('slow'); // <- これは不要そうなのでコメントアウトしました
$(".accordion_trigger:eq(0)").next().slideToggle();
$(".accordion_trigger:eq(0)").toggleClass("active");
});
});
次のようにすると、お望みの処理になるのではないかと思います。
$(function(){
$("#drop_menu div ul li:eq(0) a").click(function(){
var $target = $(".accordion_trigger:eq(0)").next();
if ($target.is(':hidden')) { $target.slideDown(); }
$(".accordion_trigger:eq(0)").toggleClass("active");
});
});
さらに、繰り返しが多いので、うまいことプラグイン化しちゃうといいんだろうな、と思います。たとえば、次のように。
!function($){
$.fn.myplugin = function() {
var $body = $('body');
this.each(function() {
var $trigger = $(this);
var $target = $trigger.next();
$trigger.click(function() {
$target.slideToggle();
});
$body.find('a[href=\\#' + $trigger.attr('id') + ']').click(function() {
if ($target.is(':hidden')) { $target.slideDown(); }
});
});
}
}(jQuery);
これを使う HTML 側に書くスクリプトはこうなります。
<script>
$(function() {
$('.accordion_trigger').myplugin();
});
</script>
最後に。もし、active
というクラスで表示を切り替えたいのであれば、slideToggle()
のアニメーション終了時に実行されるコールバックの中で active
をつけたりはずしたりするといいのではないでしょうか。
div.togglearea {
height: 100px;
border: 2px 2px 2px 2px;
border-color: gray;
}
div.active {
background-color: pink;
}
!function($){
$.fn.myplugin = function() {
var $body = $('body');
this.each(function() {
var $trigger = $(this);
var $target = $trigger.next();
$target.hide().removeClass('active');
$trigger.click(function() {
$target.slideToggle(function() {
$target.toggleClass('active');
});
});
$body.find('a[href=\\#' + $trigger.attr('id') + ']').click(function() {
if ($target.is(':hidden')) {
$target.slideDown(function() {
$target.addClass('active');
});
}
});
});
}
}(jQuery);
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+2
自分だったらこうする、という風にしました。
アコーディオントリガーを押すと、スライドトグルで開閉というのは元々の実装でほぼ問題ないと思います。
- 「drop_menu」の各リンクをクリックした際、遷移先のトグル要素が閉の時のみ開の処理を行いたい。
こちらについては、条件分岐させるよりは、トリガーを押すと要素をスライドダウンする機能だけを持つ別物として、設定を作ってしまいます。
なので、ハンバーガーメニューの方に、「accordion_trigger」とは別の「open_trigger」というクラスを当てて、要素を取得するようにしています。
- accordion_triggerをクリック → スライドトグルで開閉する+クラスの付け外し。
- open_triggerをクリック → スライドダウンする+クラスの付与。
上記のような関係にします。スライドダウンであれば、そもそも開いている要素に対して行っても、閉じてしまうことはありません。
なお、ハンバーガーメニューをクリックした時、スライドダウンさせる要素をターゲットとして取得しなければなりません。
そちらについては、aタグのhref属性設定されている「#anchor1」の文字列を利用して、
$('#anchor1')
という形で取得できるように書き、ターゲットとなるトリガーをまず取得しています。
そのトリガーの隣の要素が、ターゲットとなるトグル要素として取得できます。
<p class="humberger">ハンバーガーメニュー</p>
<div id="drop_menu">
<div>
<ul class="drop_menu_list">
<li><a href="#anchor1" class="open_trigger">トグル要素1</a></li>
<li><a href="#anchor2" class="open_trigger">トグル要素2</a></li>
<li><a href="#anchor3" class="open_trigger">トグル要素3</a></li>
<li><a href="#anchor4" class="open_trigger">トグル要素4</a></li>
</ul>
</div>
</div>
<div id="anchor1" class="accordion_trigger">トグル要素1のトリガー</div>
<div class="togglearea">トグル要素1で開く内容</div>
<div id="anchor2" class="accordion_trigger">トグル要素2のトリガー</div>
<div class="togglearea">トグル要素2で開く内容</div>
<div id="anchor3" class="accordion_trigger">トグル要素3のトリガー</div>
<div class="togglearea">トグル要素3で開く内容</div>
<div id="anchor4" class="accordion_trigger">トグル要素4のトリガー</div>
<div class="togglearea">トグル要素4で開く内容</div>
var SAMPLE = SAMPLE || {};
SAMPLE.Accordion = function() {
this.init();
}
SAMPLE.Accordion.prototype = {
init: function() {
this.$toggleTrigger = $('.accordion_trigger');
this.$openTrigger = $('.open_trigger');
this.$dropMenuList = $('.drop_menu_list');
this.bindEvent();
},
bindEvent: function() {
var _self = this;
this.$toggleTrigger.on("click", function(e) {
e.preventDefault();
_self.slideToggle(this);
});
this.$openTrigger.on("click", function(e) {
e.preventDefault();
_self.slideUp();
_self.slideDown(this);
});
},
slideToggle: function(trigger) {
var $trigger = $(trigger),
$targetArea = $trigger.next();
$trigger.toggleClass('active');
$targetArea.slideToggle();
},
slideUp: function(){
this.$dropMenuList.slideUp();
},
slideDown: function(trigger){
var $trigger = $(trigger),
targetId = $trigger.attr('href'),
$targetTrigger = $(targetId),
$targetArea = $targetTrigger.next();
$targetTrigger.addClass('active');
$targetArea.slideDown();
}
};
new SAMPLE.Accordion();
もし、実装するなら私なら上記の書き方をしますが、
投稿者さんの記述スタイルに近い書き方だと、こうなります。
$('.accordion_trigger').on('click', function() {
var $trigger = $(this),
$targetArea = $trigger.next();
$trigger.toggleClass('active');
$targetArea.slideToggle();
});
$('#drop_menu div ul li a').on('click', function() {
var $openTrigger = $(this),
targetId = $openTrigger.attr('href'),
$targetTrigger = $(targetId),
$targetArea = $targetTrigger.next();
$("#drop_menu div ul").slideUp('slow');
$targetTrigger.addClass('active');
$targetArea.slideDown();
});
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.18%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2016/02/02 11:03
=
> // $("#drop_menu div ul").slideUp('slow'); // <- これは不要そうなのでコメントアウトしました
お伝え漏れでしたが、こちらのdrop_menuはハンバーガーメニューから開くスライドメニューであるためメニュー選択後は非表示にする必要があり上記記述はその処理です。
-
>さらに、繰り返しが多いので、うまいことプラグイン化しちゃうといいんだろうな、と思います。たとえば、次のように。
こちらもご説明不足でしたが今回外部jsを読み込みことができないためhtml内に全て記述する必要があります。
=
上記を踏まえ参考に以下の記述で試しましたがうまく動作しませんでした。
=
$(function(){
$("#drop_menu div ul li:eq(0) a").click(function(){
$("#drop_menu div ul").slideUp('slow');
var $target = $(".accordion_trigger:eq(0)").next();
if ($target.is(':hidden')) { $target.slideDown(); }
$(".accordion_trigger:eq(0)").toggleClass("active");
});
$("#drop_menu div ul li:eq(1) a").click(function(){
$("#drop_menu div ul").slideUp('slow');
var $target = $(".accordion_trigger:eq(1)").next();
if ($target.is(':hidden')) { $target.slideDown(); }
$(".accordion_trigger:eq(1)").toggleClass("active");
});
$("#drop_menu div ul li:eq(2) a").click(function(){
$("#drop_menu div ul").slideUp('slow');
var $target = $(".accordion_trigger:eq(2)").next();
if ($target.is(':hidden')) { $target.slideDown(); }
$(".accordion_trigger:eq(2)").toggleClass("active");
});
$("#drop_menu div ul li:eq(3) a").click(function(){
$("#drop_menu div ul").slideUp('slow');
var $target = $(".accordion_trigger:eq(3)").next();
if ($target.is(':hidden')) { $target.slideDown(); }
$(".accordion_trigger:eq(3)").toggleClass("active");
});
});
=
不備などあればご指摘願えませんでしょうか?
2016/02/02 11:11
上記記述は正常に動作しておりました。
他スクリプトの干渉の問題でした。
この度は迅速・的確なご教授誠にありがとうございました。
心から感謝申し上げます。
2016/02/02 16:51
2016/02/02 18:26
再度確認したところ以下の記述では開の場合で「accordion_trigger」にすでに「active」が付与されている場合でも「toggleClass」が実行されてしまいます。
=
$("#drop_menu div ul li:eq(0) a").click(function(){
$("#drop_menu div ul").slideUp('slow');
var $target = $(".accordion_trigger:eq(0)").next();
if ($target.is(':hidden')) { $target.slideDown(); }
$(".accordion_trigger:eq(0)").toggleClass("active");
});
=
おそらく後半のプラグイン化した場合記述を読み解けばいいのでしょうが、上記プラグイン化してない記述への応用方法がわかりませんでした。
知識が足りず誠に恐縮ですがご教授いただけませんでしょうか?
2016/02/02 20:54
(1) is(':hidden') メソッドが true になるか false になるか
(2) slideUp(), slideDown(), slideToggle() で最終的に表示されたり、非表示になったり
というのは、「active」クラスがついているかどうか、には直接関係ありません。「active」クラスにどういうスタイルがついているのかご呈示いただいていないので、間接的に影響があるかどうかは判断できません。「active」クラスを付けたり外したりする意図もまだよくわかっていません。
ご呈示のコードにコメントをつけると次のようになります。
------- ここから
$("#drop_menu div ul li:eq(0) a").click(function(){
$("#drop_menu div ul").slideUp('slow');
var $target = $(".accordion_trigger:eq(0)").next();
if ($target.is(':hidden')) { $target.slideDown(); } // 内容が隠れていればスライドして出す (※)
$(".accordion_trigger:eq(0)").toggleClass("active"); // 上の if のブロックを抜けているので必ず実行される
});
------- ここまで
ご注意いただきたいのは、(※) の部分は「active」クラスがついているかどうかを見ているのではなく、表示されているか否かを見ているということです。
お望みの動きがまだ十分わかっていないのですが、先のコードを書き直すと次のようになるでしょうか。
------- ここから
var $menu_ul = $('#drop_menu div ul');
$menu_ul.find('ul li:eq(0) a').click(function(){
$menu_ul.slideUp('slow');
var $trigger = $('.accordion_trigger:eq(0)');
var $target = $trigger.next();
if ($target.is(':hidden')) { // target が隠れていたら
$target.slideDown($trigger.addClass('active')); // スライドしながら表示して、表示し終わったら「active」クラスをつける
} else { // target が表示されていたら
$trigger.removeClass('active'); // 「active」クラスをはずして
$target.slideUp(); // スライドしながら隠す
}
});
------- ここまで
表示する際、先に「active」クラスをつけ、その後でスライドしながら表示する、というのであれば、slideDown() のコールバックで addClass() を呼ぶのではなく、先に addClass() を呼んでから slideDown() を呼ぶといいと思います。
これでお望みの動きになったでしょうか。
2016/02/05 09:09 編集
度々のご回答ありがとうございます。
ご親切にコメントまで記載して頂き大変助かりました。
ご教授いただいた内容で実現できました!
この度は誠にありがとうございました。