プロが教える店舗&オフィスのセキュリティ対策術

縦長のHTMLコンテンツで下にスクロールした時にそのスクロール位置によって
目次のリンクにselectedクラスをDOMで追加し、現在どの部分を表示しているのかを視覚的にわかりやすくしたいのですが、
方法がわからず悩んでおります。そもそもHTMLの構造的に可能どうかもわからない素人ですが、どなたかご教授頂きたいと存じます。

現在のHTMLの構造は、
コンテンツのHTMLの前に目次の記述があり、その目次部分はposition:fixedで常に見える位置に表示してあります。
構造を簡単にしますと以下のようになっております。


<!-- 目次 START -->
<div id="toc">
<ul class="toc">
<li class="toc_lebel_1">
<a href="#見出し1"> class="toc">見出し1</a>
</li>
<li class="toc_lebel_1">
<a href="#見出し2"> class="toc">見出し2</a>
</li>
<li class="toc_lebel_1">
<a href="#見出し3"> class="toc">見出し3</a>
</li>
</ul>
</div>
<!-- 目次 END -->

<!-- コンテンツ START -->
<h1>
<a name="見出し1" id="見出し1">見出し1</a>
</h1>
・・・
<h2>
<a name="見出し2" id="見出し2">見出し2</a>
</h2>
・・・
<h2>
<a name="見出し3" id="見出し3">見出し3</a>
</h2>
・・・
<!-- コンテンツ END -->


このページはかなり縦長のページになっており、下にスクロールした際に現在表示している位置(例えば、見出し1と見出し2の間を表示している場合の位置)によって
目次の該当箇所の<a>タグにselectedのようなクラスを追加したいです。

よろしくお願いします。

A 回答 (3件)

こんばんは、



こんなかんじでしょうか? ie では、うごきません。firefox でうごきました。
Array.reduce, document.querySelector(All), classList がつかえないとだめです。
いちのかんちは、たいまーをつかいました。

ぜんかくくうはくは、はんかくにしてください。

<!DOCTYPE html>
<title></title>
<meta charset="UTF-8"/>
<style>
body {
 padding-left:8em;
}
#toc {
 position:fixed;
 left : 0;
}
p {
 height : 20em;
}
a.selected {
 border-bottom: 2px red solid;
 color : red;
}
</style>
<body>
<div id="toc">
 <ul class="toc">
  <li class="toc_lebel_1">
   <a href="#見出し1" class="toc selected">見出し1</a>
  <li class="toc_lebel_1">
   <a href="#見出し2" class="toc">見出し2</a>
  <li class="toc_lebel_1">
   <a href="#見出し3" class="toc">見出し3</a>
 </ul>
</div>

<h1 id="見出し1">見出し1</h1>
<p>1<p>2<p>3<p>4<p>5

<h2 id="見出し2">見出し2</h2>
<p>1<p>2<p>3<p>4<p>5


<h2 id="見出し3">見出し3</h2>
<p>1<p>2<p>3<p>4<p>5




<script>

//対象のアンカータグを集める
var a = document.querySelectorAll ('div#toc > ul > li > a');

//対象のstyle.top の絶対値を求める
var b = function (c) {
 for (var d = 0; c; c = c.offsetParent)
  d += c.offsetTop;
 return d;
};

//aで集めた.helf をidとした要素を集め、b() を求め、配列にする
var c = Array.prototype.reduce.call (a, function (d, e) {
 var f = e.getAttribute ('href'), g;
 if (/^#.+$/.test (f))
  if (g = document.querySelector (f))
   d.push ({ e: e, height: b (g) });
 return d;
}, []);


var offset = 20;

var d = function () {
 var f = 0, g = window.pageYOffset + offset, h;
 for (var i = c.length; h = c[--i]; )
  h.e.classList[(f += h.height <= g) === 1 ? 'add': 'remove']('selected');
};


setInterval (d, 500);

</script>

この回答への補足

babu_babooさん

困ったことにDOMが正常に動作するページと同じような構造のHTMLでありながら

結果が異なるページがあるのです。

そのページを読み込むとdiv#toc内のすべてのaがselectedになった状態で表示されてしまいます。

下にスクロールしていくと上の方から徐々にselectedが解除されていきます。

キャッシュをクリアし、何度読込しても特定の数ページだけ必ずそのような状態になります。

何か良い対処法はないでしょうか??

補足日時:2013/04/16 03:35
    • good
    • 0
この回答へのお礼

babu_babooさん
はじめましてこんばんわ!

早速ご回答くださいましてありがとうございます。

スクリプトを手前のHTMLで試してみましたが問題なく動作しております。

babu_babooさんの仰る通りIE9では動きませんでしたがchromeとOperaでは動きました。

質問の時にメジャーなライブラリ(Jqueryなど)を利用する場合でもOKですと記載するのを忘れていたのですが

そんなことも必要なくとても感動です。

querySelectorAllのところを少し変えるだけで他のサイトにも流用出来そうで非常に満足です。


他の方のご教授がなければこの質問は本日中に締め切りとさせていただきます。

お礼日時:2013/04/16 00:56

まいかい おもいつきで すみません。


setInterval のまえに、いかの いちぶんを じっこうしてみてはどうだろうか?

Array.prototype.slice.call (document.getElementsByClassName ('selected'), 0).forEach (function (e) { e.classList.remove ('selected'); });
    • good
    • 0
この回答へのお礼

babu_babooさん

自サイトでいろいろとテストしてみると、CMSに使用しているプラグインが影響しているようでした。
このプラグインをOFFにすると問題なく該当のページ全てが正常にDOMが動くようになりました。
なので当面はこのプラグインを使用せず運用していこうと考えております。

それとは別に自サイトの訪問者のブラウザを調べてみるとIE使用者が7割りを超えている状況でしたので
今回のDOMについては時間があるときにbabu_babooさんにご教授頂いた手法を参考にIE対応出来るようにシたいと考えております。

改めてありがとうございました。

お礼日時:2013/04/16 20:08

おはようございます。


すいしょうをながめてみます。

a,b は、c のためにあり、c は、そのごへんかしません。

>下にスクロールしていくと上の方から徐々にselectedが解除
と、あるので c はせいじょう。
なので、うがたがうは しょきのよみこみだんかいでおこなわれているとすいそく。
'selected' がついたままの、あんかーを node.cloneNode などをつかってこぴーしている。


h.e.classList[(f += h.height <= g) === 1 ? 'add': 'remove']('selected');
これは、かさんされていく f が、1 の場合のみ設定されるものであり、むしろ remove のほうがおおい。

css で、たかさのしていがないものをつかっている?
float だとか…



けつろん!
よくわからない。ごめん。


--
あと、23歳OL女子ならゆるせるが
Syntax error 'こんばんわ!'


あっ!ふだん えらーを りょうさんするのは、俺かっ。
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!