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

onclickを使わずにイベント処理をする方法について。

【<h1>をクリックすると同じ<div>を親に持つ<p>が表示/非表示】
されるようにしたいのですが、IEで動作せず、困っています。

下記は現在のコードです。
--------------------------------------------------------------------------
var divs = document.getElementsByTagName('div');

var listener = function(ev){
if(/(?:^|\s)text(?:$|\s)/.test(ev.target.className)){

var next = ev.target.nextSibling.nextSibling;
if(next.style.display != "none"){
next.style.display = "none";
}else{
next.style.removeProperty("display");
}
}
};
if (document.addEventListener) {
document.addEventListener('click', listener, false);// IE以外
} else {
document.attachEvent("onclick", listener);// IE
}
--------------------------------------------------------------------------
<div>
<h1 class="text">見出し</h1>
<p>本文</p>
</div>
<div>
<h1 class="text">見出し</h1>
<p>本文</p>
</div>
<div>
<h1 class="text">見出し</h1>
<p>本文</p>
</div>
--------------------------------------------------------------------------

ev.target.classNameあたりが怪しく…
window.event.srcElement.classNameに変更してみましたが動作しませんでした。

html側の制約があり、出来れば上記のようなclassのみのhtmlで、
更にわがままを言うと

<div class="text">
<h1>見出し</h1>
<p>本文</p>
</div>

のようにdivにclassを振った形で実現したいです。

なお、現在のコードは複数のサンプルコードを参考に試行錯誤したものですので
不要なコードが混ざっているかもしれません。

動作確認環境はIE7、IE8、Firefox、Safari(Windows)です。

納期が迫り大変困っています。アドバイスを頂けますと嬉しいです。
宜しくお願い致します。

A 回答 (11件中1~10件)

>> #9 yuu_xさん



なるほど…。スタイルシートのルールを書き換えればいいんですね!

質問者さんの動作確認環境はIE7以上だから、兄弟セレクタが使える、と。
(全角空白を半角空白に置換してください)

<script type="text/javascript"><!--
(function(){
 var styleSheets = this.document.styleSheets;
 var lastStyleSheet = styleSheets[styleSheets.length - 1];

 try{
  lastStyleSheet.insertRule('.text + p { display: none; }', lastStyleSheet.cssRules.length);
 } catch(e){
  lastStyleSheet.addRule('.text + p', 'display: none;', -1);
 }
})();
//--></script>

stylesheet.insertRule - MDC
https://developer.mozilla.org/En/DOM/Stylesheet. …
document.styleSheets
https://developer.mozilla.org/ja/DOM/document.st …

CSSStyleSheet Prototype (style)
http://msdn.microsoft.com/en-us/library/dd347054 …
addRule Method (styleSheet, CSSStyleSheet Constructor)
http://msdn.microsoft.com/ja-jp/library/aa358796 …

Javascript cssRules - とみぞーノート
http://wiki.bit-hive.com/tomizoo/pg/Javascript%2 …

# 最後に質問者さんにアドバイス。
質問当初に知らないことがあるのは別にいいんですが、回答をもらってそこかしこにある知らないキーワードをGoogle検索してみたり、MDCの資料に目を通したり、Firebugで検証したり…、といろいろやった方が自分のためになると思います。
それから再質問すれば、質問が具体的になって回答も寄せられやすくなると思いますよ。

実際、私も調べながら回答しています。(このスレッドが立つ前から、ここに書いたことを全部知っていたわけではありません)
    • good
    • 0
この回答へのお礼

think49様、ありがとうございます。

仰る通りです。結果を急いでしまいました。
情報不足の中、何度も相談しお手数をおかけしました。

MDCやFirebugという言葉も知りませんでした。。!本当に勉強になります。
期日にも余裕が出たので、ひとつひとつ分からない点をじっくり勉強したいと思います。

今回はこれにて締め切らせていただきます。
有難うございました!

お礼日時:2010/06/01 09:53

#4,5,7,8 です。



以下、#8の補足より引用。

> 以前のご回答と今回のご回答を両方参考にすれば実現可能でしょうか?
ヒントは十分に出ていると思います。
    • good
    • 0
この回答へのお礼

了解です!

お礼日時:2010/06/01 09:43

... click が抜けとる。

いぁ、しょーもないことで、連投して申し訳ない。
[javascript]
/*@cc_on@*/
document./*@if(1)attachEvent('on'+@else@*/addEventListener(/*@end@*/'click', function(ev) {
var t = ev./*@if(1)srcElement@else@*/target/*@end@*/;

if (t.tagName === 'H1' && /(?:^|\s)text(?:\s|$)/.test(t.parentNode.className)) {
while ((t = t.nextSibling) && t.tagName !== 'P');
t && (t.style.display = t.style.display === 'block' ? 'none' : 'block');
}
}, false);

document.write('\u003Cstyle type="text/css"\u003E.text p{display:none;}\u003C/style\u003E');
[/javascript]

> 初期に本文を非表示にしたいのでしたら、JavaScriptで display:none; にするのが賢いと思います。
ん~、、、これね、、、該当要素をぐるぐる回すのも嫌だから、分かりきってる場合は、上でいいよ。
特定クラスに限定するなら、スタイルシートを書き換えるのが筋だけど、結局ぐるぐる回さなきゃならない。しかも判定が面倒。StyleSheet API にも、querySelector がほしい。
    • good
    • 0
この回答へのお礼

いえいえ、丁寧に有難うございます。
私の方こそ質問を続けてばかりで申し訳ないです。
document.writeでcssを書く方法もありましたね・・!
bodyタグはいじれないし、onloadをどう書くか…でまたはまってしまっていました;;

お礼日時:2010/06/01 09:43

#4,5,7です。



以下、#5の補足より引用。

> 外部cssでdisplay:noneにしてしまうとjavaScriptで上書き出来ないようです。
> yuu_x様の外部css参照を使えば、実現出来るのでしょうか。
#3でyuu_xさんが紹介された getComputedStyle(currentStyle) は #5 のコードでも使われています。
しかし、そんなこととは関係なく、JavaScriptでしか使われない display:none; を外部CSSで指定するのは好ましくないと思います。

以下、いわゆる「アコーディオンメニュー」を実装する場合で「初期に内容を表示したくない」という前提で書きますが。
下記コードを試してみてください。(全角空白を半角空白に置換してください)

-------
<style type="text/css"><!--
p {
 display: none;
}
--></style>
<script type="text/javascript"><!--
function test(event){
 var target = event.target || event.srcElement;
 var p = target.parentNode.getElementsByTagName('p').item(0);
 p.style.display = (p.style.display === 'none') ? 'block': 'none';
}
//--></script>
</head>
<body>

<div>
<h1 class="text" onclick="test(event);">見出し</h1>
<p>本文</p>
</div>
-------

これはアコーディオンメニューのサンプルとして、よく見られるコードです。
期待通りに動作してくれているように見えますが、スタイルシート、JavaScriptの両方が有効でないと動きません。
CSSが有効でJavaScriptが無効なブラウザで閲覧したとすると、アコーディオンは正しく働かず、「JavaScriptを有効にしない限りは本文を表示できない」という事態になります。
ですので、初期に本文を非表示にしたいのでしたら、JavaScriptで display:none; にするのが賢いと思います。

-------
<script type="text/javascript"><!--
function test(event){
 var target = event.target || event.srcElement;
 var p = target.parentNode.getElementsByTagName('p').item(0);
 p.style.display = (p.style.display === 'none') ? 'block': 'none';
}
function init(event){
 var doc = event.target || document;
 var text = doc.querySelectorAll('.text'); // for Gecko/Webkit/Opera/IE8 (IE7以下は動作しません)
 var p;

 for(var i=0,l=text.length; i<l; i++){
  p = text[i].parentNode.getElementsByTagName('p').item(0);
  p.style.display = 'none';
 }
}
//--></script>
</head>
<body onload="init(event);">

<div>
<h1 class="text" onclick="test(event);">見出し</h1>
<p>本文</p>
</div>
-------

JavaScriptが無効であれば、アコーディオンが働かず、全ての内容が表示されます。
JavaScriptが有効であれば、アコーディオンが働き、初期の本文は非表示になります。
    • good
    • 0
この回答へのお礼

think49様更なるご回答ありがとうございます。

>#3でyuu_xさんが紹介された getComputedStyle(currentStyle) は #5 のコードでも使われています。
なるほど!チェック不足でした。

>JavaScriptでしか使われない display:none; を外部CSSで指定するのは好ましくないと思います。
>「JavaScriptを有効にしない限りは本文を表示できない」
はい、特に後者はユーザを限定してしまう点で今回の制作条件からアウトになってしまいます。

h1にonclickをつけずに実装するには、
以前のご回答と今回のご回答を両方参考にすれば実現可能でしょうか?

お礼日時:2010/05/30 21:16

#4,5 です。


「cssTextをreplaceする」って手もありますね。
これなら全てのスタイルを削除しなくてすみますし、実装依存なコードではないので、最悪catchで拾えます。

<script type="text/javascript">
<!--
document./*@cc_on @if(@_jscript_version <= 5.8) attachEvent('on' + @else @*/addEventListener(/*@end @*/ 'click', function(event){
 var h1 = event.target || event.srcElement;
 var p, style;
 if(h1.nodeName !=='H1' || (' '+h1.className+' ').indexOf(' text ') === -1){ return false; }

 p = h1.parentNode.getElementsByTagName('p').item(0);

 if(p.style.display !== 'none'){
  p.style.display = 'none';
 } else {

  try{ // for Gecko/Webkit/Opera
   p.style.removeProperty('display');
  } catch(e) { // for IE
   p.style.cssText = p.style.cssText.replace(/(^|[ ;])display *: *none(?: *;|$)/i, '$1');
  }
 }
}, false);
//-->
</script>


>> #6 yuu_xさん
> IE の場合、属性名 ではなく、プロパティ名を使ってるから、きっとそのせいだろうね。
多分、そうですね…。

自分から書いておいて何ですが、element.style.removeAttribute() はやっぱりお勧めしがたいコードに思えてきました。
問題はIEがWeb標準に準拠し始めているってことだと思います。
例えば、IE9から addEventListener() に対応しますが、同じ流れで「removeAttribute() の対象がプロパティ」というバグ(仕様?)も修正されるかもしれません。
すると、こういう可能性もありえます。

// IE9がやってくる
try{
 child.style.removeProperty('display'); // IE9は removeProperty() に対応しないので、catchへ
} catch(e) {
 child.style.removeAttribute('display'); // removeAttribute() の対象が属性ではないので、シンタックスエラー!
}

IE9が中途半端な実装をしなければ起こりえないことではありますが…。
    • good
    • 0
この回答へのお礼

IE9まで考えないといけないなんて…
cssだけでなくJavaScriptも…!
生半可な知識でJavaScript書けないですね。後々怖いです。

お礼日時:2010/05/30 21:18

なんてこった。

まだあった。
[javascript]
while (t && t.nodeType !== 1) t = t.nextSibling;
t && (t.style.display = t.style.display === 'block' ? 'none' : 'block');
}
[/javascript]



[javascript]
while ((t = nextSibling) && t.nodeType !== 1);
t && (t.style.display = t.style.display === 'block' ? 'none' : 'block');
}
[/javascript]

> なぜか element.style.removeAttribute('display') が有効なIEの仕様
IE の場合、属性名 ではなく、プロパティ名を使ってるから、きっとそのせいだろうね。

IE の場合、無理に標準化するより、まったく別に書いたほうが、と思っている今日この頃。

2度同じものを書かなきゃいけないのは手間だけど、欠点はそれくらいで、利点のが大きい気がする。
    • good
    • 0
この回答へのお礼

yuu_x様沢山の回答ありがとうございます。
取り急ぎのお礼になりますが、後日全ての回答をもとに勉強させていただきます。

お礼日時:2010/05/30 21:08

#4です。



#4では(いわゆる)クロージャを取り上げましたが、クロージャに各々の要素のデフォルトスタイルを保持するのは難しそうなので、className に保持してみました。
以下、全角空白は半角空白にしてください。

<script type="text/javascript">
<!--
/*@cc_on @if(@_jscript_version <= 5.8) attachEvent('on' + @else @*/addEventListener(/*@end @*/ 'load', function(event){
 var doc = event.target || document;
 var text = doc.querySelectorAll('.text') || doc.getElementsByClassName('.text');// IE6を踏まえるなら、この部分は getElemensByTagName() で得るなど適宜修正してください。
 var p, defaultDisplay;

 for(var i=0,l=text.length; i<l; i++){
  p = text[i].parentNode.getElementsByTagName('p').item(0);
  defaultDisplay = doc.defaultView ? doc.defaultView.getComputedStyle(p, '').display : p.currentStyle.display;
  p.className += ' defaultDisplay_'+defaultDisplay;
 }
}, false);

document./*@cc_on @if(@_jscript_version <= 5.8) attachEvent('on' + @else @*/addEventListener(/*@end @*/ 'click', function(event){
 var h1 = event.target || event.srcElement;
 var p, className;
 if(h1.nodeName !=='H1' || (' '+h1.className+' ').indexOf(' text ') === -1){ return false; }

 p = h1.parentNode.getElementsByTagName('p').item(0);

 if(className = (' '+p.className+' ').match(/ defaultDisplay_(\w+) /)){
  if(p.style.display !== 'none'){
   p.style.display = 'none';
  } else {
   p.style.display = className[1];
  }
 }
}, false);
//-->
</script>
    • good
    • 0
この回答へのお礼

丁寧に有難うございます。組み込んでみたところ、IEで表示/非表示することができました。
感動です!!

記入し忘れていましたが、<p>の内容は初期非表示にしたく、現在試行錯誤中です。
外部cssでdisplay:noneにしてしまうとjavaScriptで上書き出来ないようです。
yuu_x様の外部css参照を使えば、実現出来るのでしょうか。

あと1歩頑張ります。。。

厚かましいですがもしアドバイス頂けましたら嬉しいです。

お礼日時:2010/05/30 18:56

removeProperty() の代替策としては、



・element.style.cssText=''; や element.removeProperty('display'); で上書きする
・clickを定義する前に、getComputedStyle(IEはcurrentStyle)でデフォルトのスタイルを読み込み、クロージャが保持する変数等に保持しておく
・なぜか element.style.removeAttribute('display') が有効なIEの仕様を利用する (実装依存)

以下、全角空白は半角空白にしてください。

<script type="text/javascript">
<!--
document./*@cc_on @if(@_jscript_version <= 5.8) attachEvent('on' + @else @*/addEventListener(/*@end @*/ 'click', function(event){
 var h1 = event.target || event.srcElement;
 var doc, child, childs;
 if(h1.nodeName !=='H1' || (' '+h1.className+' ').indexOf(' text ') === -1){ return false; }

 doc = h1.ownerDocument;
 childs = h1.parentNode.childNodes;

 for(var i=0,l=childs.length; i<l; i++){
  child = childs[i];
  if(child.nodeName === 'P'){
   if(child.style.display !== 'none'){
    child.style.display = 'none';
   } else {
    try{ // for Gecko/Webkit/Opera
     child.style.removeProperty('display');
    } catch(e) { // for IE
     child.removeAttribute('style'); // ただし、styleが保持する全てのプロパティを全てを削除する
//     child.style.cssText = ''; // 同上
//     child.style.removeAttribute('display'); // IEの仕様を利用した実装依存
    }
   }
  }
 }
}, false);
//-->
</script>

cssRule.cssText - MDC
https://developer.mozilla.org/en/DOM/cssRule.css …
getComputedStyle - MDC
https://developer.mozilla.org/ja/DOM/window.getC …
currentStyle
http://msdn.microsoft.com/ja-jp/library/ms535231 …
掲示板/スタイルシート質問板/テキストボックスのスタイル初期化 - TAG index Webサイト
http://www.tagindex.com/cgi-lib/q3bbs/patio.cgi? …
    • good
    • 0
この回答へのお礼

回答ありがとうございます。
大変参考になります!
クロージャという言葉、初めて聞きました。
JavaScript、奥が深いです。

お礼日時:2010/05/30 18:48

抜けがあった。



[javascript]
/*@cc_on@*/
document./*@if(1)attachEvent('on'+@else@*/addEventListener, function(ev) {
var t = ev./*@if(1)srcElement@else@*/target/*@end@*/;

if (t.tagName === 'H1' && t.parentNode.tagName === 'DIV' && /(?:^|\s)text(?:$|\s)/.test(t.parentNode.className)) {
while (t && t.nodeType !== 1) t = t.nextSibling;
t && (t.style.display = t.style.display === 'block' ? 'none' : 'block');
}
}, false);
[/javascript]

> onclickを使わずに

[CSS]
.text > h1 + p {
display : none;
}
.text:hover > h1 + p {
display : block;
}
[/CSS]
結局 IE では、使えないけどね。


ついで。
[javascript]
next.style.display === 'block' ? (next.style.display = 'none') : (next.style.display/*@if(1) = ''@else@*/.removeProperty('display')/*@end@*/;
[/javascript]
# removeProperty をちゃんと使ってるコードを久しぶりに見た気がする。

ちなみに、style プロパティはインラインスタイルを参照するので、外部 CSS の設定を取得する場合は、getComputedStyle(currentStyle)
    • good
    • 0
この回答へのお礼

cssで実現出来たら気持ちいいんですが、またIEの壁がありますね。。。;;
外部スタイルの参照、勉強になります!

お礼日時:2010/05/30 18:45

IE は removeProperty 持ってないから、強引に書くしかないんでない。

    • good
    • 0
この回答へのお礼

有難うございます!IEで使えないコード、沢山あるのですね。

お礼日時:2010/05/30 18:42

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


このQ&Aを見た人がよく見るQ&A