jQuery を使ったサンプル
作成日:2015年9月25日
ローディング画面を表示
簡単にページ読み込み中のローディング画面を表示する方法です。ローディング画面に表示するアニメーションは CSS アニメーションを使用しますが、以下のようなサイトにローディングアニメーションが掲載されているのでそれを利用します。
CSS3 Loading Animation などで検索すると色々と見つかります。
以下は HTML と jQuery の読み込みとスクリプト部分(後述)です。
body 要素の先頭にローディング画面の div 要素(クラス page-loader)を配置して、その中にアニメーションの領域の div 要素(クラス spinner)を配置します。
その後に、通常表示するコンテンツを配置します。この例では、大き目の画像を3つ配置しているだけです。
<body> <div class="page-loader"> <div class="spinner"></div> </div> <div> <p><img src="../images/largeImage01.jpg" alt=""></p> <p><img src="../images/largeImage02.jpg" alt=""></p> <p><img src="../images/largeImage03.jpg" alt=""></p> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script> // ページのロード完了時にローディング画面をフェードアウト $(window).on('load', function() { $(".page-loader").fadeOut('fast'); }); </script> </body>
以下は CSS です。
ローディング画面の div 要素(クラス page-loader)は、画面いっぱいに表示するため、position: fixed; top: 0; left: 0; width: 100%; height: 100%; を指定します。 z-index: 10001; は最前面に表示するための指定です。他の要素より大きい値が指定されていれば問題ありません。
background: #f2f2f2; はローディング画面の背景色です。適宜変更します。
11行目から37行目はローディング画面に表示する CSS3 アニメーションの記述です。この部分は前述のサイトからコピーしています。
.page-loader { position: fixed; z-index: 10001; top: 0; left: 0; width: 100%; height: 100%; background: #f2f2f2; //ローディング画面の背景色 } .spinner { width: 40px; height: 40px; margin: 200px auto; background-color: #F24245; //アニメーション画像の色 border-radius: 100%; -webkit-animation: sk-scaleout 1.0s infinite ease-in-out; animation: sk-scaleout 1.0s infinite ease-in-out; } //アニメーション @-webkit-keyframes sk-scaleout { 0% { -webkit-transform: scale(0) } 100% { -webkit-transform: scale(1.0); opacity: 0; } } @keyframes sk-scaleout { 0% { -webkit-transform: scale(0); transform: scale(0); } 100% { -webkit-transform: scale(1.0); transform: scale(1.0); opacity: 0; } }
以下は Spinkit の例です。気に入ったローディングアニメーションがあれば、画面上の「Source」をクリックすると、その HTML と CSS が表示されるので、それをコピーします。
アニメーションの領域のクラス名などは、コピーした内容に合わせて適宜変更します。
以下は jQuery の読み込みとスクリプト部分です。
全ての画像やコンテンツが読み込まれた時点で処理を行うので window の load イベントを使用します。
以下では、単にページのロード(読み込み)が完了した時点で、ローディング画面(クラス page-loader の div 要素)を fadeOut() を使ってフェードアウトさせているだけです。引数にミリ秒の数値を指定してスピードを調整することもできます。
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script> // ページのロード完了時にローディング画面をフェードアウト $(window).on('load', function() { $(".page-loader").fadeOut('fast'); }); /* または、window.onload を利用して window.onload = function() { $(".page-loader").fadeOut('fast'); }*/ </script> </body>
以下は、ローディング画面のフェードアウトのタイミングを調整する例です。3行目では delay(500) を追加してフェードアウトを 0.5秒遅らせています。7行目からは、setTimeout() を使って、万が一ページのロードが完了しない場合でも、強制的にローディング画面をフェードアウトして非表示にしています。
// ページのロード完了時にローディング画面をフェードアウト $(window).on('load', function() { $(".page-loader").delay(500).fadeOut(600); }); // ページのロードが完了しない場合でも10秒たったら強制的にローディング画面をフェードアウト setTimeout('stoploading()', 10000); function stoploading() { $(".page-loader").fadeOut('fast'); }
以下はサンプルです。各ページの最後に HTML、CSS、jQuery を記載してあります。以下のサンプルはローディング画面をある程度の時間表示するため delay() で調整しています。
リンクをクリックすると Google マップを表示
HTML 上に記述してある場所のリストの「地図を表示」と言うリンクをクリックすると、その場所の地図を表示する例です。
Google Map JavaScript API の基本的な使い方に関しては「Google Maps API の使い方・利用方法」をご覧ください。
以下は HTML と CSS です。
HTML には、地図を生成する際に必要な「緯度(lat)」「経度(lng)」「ズームレベル(zoom)」の値を記述しておき、CSS(display:none)で非表示にします。緯度と経度は必須ですが、ズームレベルは指定がなければデフォルトで 16 を適用するようにしています。
<body> <!--緯度(lat)と経度(lng)は https://google-developers.appspot.com/maps/documentation/utils/geocoder/?hl=ja で住所を入力して確認します--> <div class="map_info"> <p class="venue">東京スカイツリー</p> <p class="address">〒131-0045 東京都墨田区押上1−1−2</p> <p class="lat">35.710033</p> <p class="lng">139.810716</p> <p class="web"><a href="http://www.tokyo-skytree.jp/" target="_blank">www.tokyo-skytree.jp</a></p> <p class="zoom">15</p> <p class="show_map"><a href="#">地図を表示</a></p> </div> <div class="map_info"> <p class="venue">東京タワー</p> <p class="address">〒105-0011 東京都港区芝公園4−2−8</p> <p class="lat">35.658593</p> <p class="lng">139.745441</p> <p class="web"><a href="http://www.tokyotower.co.jp/index.html" target="_blank">www.tokyotower.co.jp</a></p> <p class="zoom">16</p> <p class="show_map"><a href="#">地図を表示</a></p> </div> <div class="map_info"> <p class="venue">東京駅</p> <p class="address">東京都千代田区丸の内1丁目</p> <p class="lat">35.681167</p> <p class="lng">139.767052</p> <p class="web"><a href="http://www.jreast.co.jp/estation/station/info.aspx?StationCd=1039" target="_blank">www.jreast.co.jp</a></p> <p class="zoom">18</p> <p class="show_map"><a href="#">地図を表示</a></p> </div> <div id="map_container"> <div id="map_canvas"></div> </div>
/* 個々の場所の情報を記述してある div 要素 */ .map_info { margin-bottom: 50px; } .lat, .lng, .zoom { /* 緯度・経度、ズームレベルを記載した要素(非表示) */ display: none; } #map_container { /* 地図のコンテナ */ clear: both; width: 90%; padding: 4px; border: 1px solid #CCC; display: none; /* 最初は非表示 */ } #map_canvas { /* 地図を表示する要素 幅と高さを指定 */ width: 100%; height: 400px; display: none; /* 最初は非表示 */ } .map_info p.web { display: none; /* 情報ウィンドウにのみ表示 */ } /* 情報ウィンドウ(マーカーをクリックすると表示される領域) */ #map_content { width: 250px; height: 70px; }
初期状態では以下のような表示になります。
「地図を表示」と言うリンクをクリックすると、その下に地図が表示されます。
以下が jQuery の部分です。
jQuery と Google Maps JavaScript API を読み込みます。 Google Maps JavaScript API の読み込みでは「&callback=initMap」でのコールバック関数は指定しません。また「YOUR_API_KEY」の部分は取得した API キーで置き換えます。
リンクをクリックしたら地図を表示する showMap() と言う関数を作成して表示します。この関数の引数は以下の通りです。
- address:場所の住所(情報ウィンドウで表示する際に使用します)
- lat:緯度(地図を生成する際に使用します)
- lng:経度(地図を生成する際に使用します)
- title:マーカーに表示するタイトルです
- url:情報ウィンドウに場所の名前を表示する際に、URL が記述されていればリンクとして表示します
- zoom:ズームレベル
7行目~58行目が関数の定義部分です。60行目~91行目までがクリックイベントの設定です。
90行目の「return false」はリンクのデフォルトの動作を無効にする(クリックするとリンク先へ移動するのを防ぐ)ための記述です。
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script> <!-- 順番に読み込まれる必要があるので「async defer」は指定しない。YOUR_API_KEYの部分は取得した APIキーで置き換えます。 --> <script> jQuery(function($){ var map, map_center; function showMap(_address, _lat, _lng, _title, _url, _zoom) { //表示領域は CSS で非表示にしてあるので表示に $("#map_canvas").css('display', 'block'); //地図の中心位置(引数 _lat, _lng から生成) map_center = new google.maps.LatLng(_lat, _lng); //マップ生成のオプション var opts = { //地図の中心 center: map_center, //初期のズーム レベル zoom: _zoom , //初期マップ タイプ mapTypeId: "roadmap" }; //マップのインスタンスを生成 map = new google.maps.Map(document.getElementById("map_canvas"), opts); //マーカーのインスタンスを生成 var marker = new google.maps.Marker({ //マーカーを配置する Map オブジェクトを指定 map: map, //マーカーの初期の場所を示す LatLng を指定 position: map_center, //マーカーをアニメーションで表示 animation: google.maps.Animation.DROP, title:_title }); //情報ウィンドウに表示するコンテンツを作成 //_urlが指定してあればリンクつきのタイトルを表示(URLがない場合もあるため) var _content; if (_url) { _content = '<div id="map_content"><p><a href="' + _url + '" target="_blank"> ' + _title + '</a><br />' + _address + '</p></div>'; }else { //_urlが指定してなければ、リンクなしのタイトルと住所を表示 _content = '<div id="map_content"><p>' + _title + '<br />' + _address + '</p></div>'; } //情報ウィンドウのインスタンスを生成 var infowindow = new google.maps.InfoWindow({ content: _content, }); //marker をクリックすると情報ウィンドウを表示(リスナーの登録) marker.addListener('click', function() { //第2引数にマーカーを指定して紐付け infowindow.open(map, marker); }); } $('p.show_map a').click(function() { //closeクラスが付与されていれば、地図が表示されているので非表示に if($(this).hasClass('close')) { $('#map_canvas').css('display', 'none'); $('#map_container').css('border-width', 0).fadeOut(500); $('p.show_map a').removeClass('close').text('地図を表示'); }else{ //リンクの文字「地図を表示」を「地図を閉じる」に変更 $(this).addClass('close').text('地図を閉じる'); //それ以外のリンクは「地図を表示」に(別の地図が閉じられていない場合があるため) $('p.show_map a').not(this).removeClass('close').text('地図を表示'); //map_infoクラスの div 要素のインスタンスを変数に代入 var map_info$ = $(this).closest('.map_info'); //緯度・経度の取得 var lat =parseFloat( map_info$.find(".lat").text()); var lng =parseFloat( map_info$.find(".lng").text()); //map_infoクラスの div 要素に地図を表示する領域を移動 append map_info$.append($('#map_container')); var address = map_info$.find('p.address').text(); //console.log(address); if(map_info$.find('p.web').text() != '') { var url = map_info$.find('p.web a').attr('href'); } //地図を表示する領域に枠線を付けてフェードインで表示 $('#map_container').css('border-width', '1px').fadeIn(1000); //zoom を取得 var zoom = map_info$.find(".zoom").text() ? parseInt(map_info$.find(".zoom").text()): 16; //マーカーのタイトル var title = map_info$.find('p.venue').text(); //地図を表示 showMap(address, lat, lng, title, url, zoom); } return false; }); }); </script> </body>
Geocoding API(ジオコーディング)を使う場合
ジオコーディングを使うと住所から緯度・経度を取得できます。以下は前述の例をジオコーディングを使って書き換えたものです。
但し、ジオコーディングを使うと処理が重くなります。API も Map JavaScript API と Geocoding API の2つを利用することになります。Geocoding API に何らかの問題があると、位置を取得できない可能性があるので、前述の例の方が確実な方法と言えます。こちらの利点は場所の情報を記載する際に、緯度・経度を取得して記述する必要がないという点です。
以下が HTML と CSS です。緯度・経度を記述する要素がない以外は、前述の例とほぼ同じです。
<div class="map_info"> <p class="venue">東京スカイツリー</p> <p class="address">〒131-0045 東京都墨田区押上1−1−2</p> <p class="web"><a href="http://www.tokyo-skytree.jp/" target="_blank">www.tokyo-skytree.jp</a></p> <p class="zoom">15</p> <p class="show_map"><a href="#">地図を表示</a></p> </div> <div class="map_info"> <p class="venue">東京タワー</p> <p class="address">〒105-0011 東京都港区芝公園4−2−8</p> <p class="web"><a href="http://www.tokyotower.co.jp/index.html" target="_blank">www.tokyotower.co.jp</a></p> <p class="zoom">17</p> <p class="show_map"><a href="#">地図を表示</a></p> </div> <div class="map_info"> <p class="venue">東京駅</p> <p class="address">東京都千代田区丸の内1丁目</p> <p class="web"></p> <p class="zoom"></p> <p class="show_map"><a href="#">地図を表示</a></p> </div> <div id="map_container"> <div id="map_canvas"></div> </div>
#map_container { clear: both; width: 90%; padding: 4px; border: 1px solid #CCC; display: none; /* 最初は非表示 */ } #map_canvas { /* 高さ(と幅)を指定しないと地図は表示されない */ width: 100%; height: 400px; display: none; /* 最初は非表示 */ } .map_info p.web { display: none; /* 情報ウィンドウにのみ表示 */ } .zoom { display: none; /* 非表示 */ } /* 情報ウィンドウ(マーカーをクリックすると表示される領域) */ #map_content { width: 250px; height: 70px; }
以下が jQuery の部分です。
7行目~68行目が、地図を表示する関数の定義です。70行目~103行目がクリックイベントの設定です。ジオコーディングを使っている以外は、前述の例とほぼ同じです。
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script> <!-- 順番に読み込まれる必要があるので「async defer」は指定しない。YOUR_API_KEYの部分は取得した APIキーで置き換えます。 --> <script> jQuery(function($){ var map, map_center; function showMap(_address, _title, _url, _zoom) { //表示領域は CSS で非表示にしてあるので表示に $("#map_canvas").css('display', 'block'); //マップ生成のオプション //center は Geolocation から取得して後で設定 var opts = { //初期のズーム レベル zoom: _zoom, //初期マップ タイプ mapTypeId: "roadmap" }; //マップのインスタンスを生成 map = new google.maps.Map(document.getElementById("map_canvas"), opts); //ジオコーディングのインスタンスの生成 var geocoder = new google.maps.Geocoder(); //geocoder.geocode() にアドレスを渡して、コールバック関数を記述して処理 geocoder.geocode( { 'address': _address}, function(results, status) { if (status === 'OK' && results[0]) { //results[0].geometry.location に緯度・経度のオブジェクトが入っている map_center = results[0].geometry.location; //地図の中心位置を設定 map.setCenter(map_center); //マーカーのインスタンスを生成 var marker = new google.maps.Marker({ //マーカーを配置する Map オブジェクトを指定 map: map, //マーカーの初期の場所を示す LatLng を指定 position: map_center, //マーカーをアニメーションで表示 animation: google.maps.Animation.DROP, title:_title }); //情報ウィンドウに表示するコンテンツを作成 //_urlが指定してあればリンクつきのタイトルと住所を表示(URLがない場合もあるため) var _content; if (_url) { _content = '<div id="map_content"><p><a href="' + _url + '" target="_blank"> ' + _title + '</a><br />' + _address + '</p></div>'; }else { //_urlが指定してなければ、リンクなしのタイトルと住所を表示 _content = '<div id="map_content"><p>' + _title + '<br />' + _address + '</p></div>'; } //情報ウィンドウのインスタンスを生成 var infowindow = new google.maps.InfoWindow({ content: _content, }); //marker をクリックすると情報ウィンドウを表示(リスナーの登録) google.maps.event.addListener(marker, 'click', function() { //第2引数にマーカーを指定して紐付け infowindow.open(map, marker); }); } else { alert("住所から位置の取得ができませんでした。: " + status); } }); } $('p.show_map a').click(function() { //closeクラスが付与されていれば、地図が表示されているので非表示に if($(this).hasClass('close')) { $('#map_canvas').css('display', 'none'); $('#map_container').css('border-width', 0).fadeOut(500); $('p.show_map a').removeClass('close').text('地図を表示'); }else{ //リンクの文字「地図を表示」を「地図を閉じる」に変更 $(this).addClass('close').text('地図を閉じる'); //それ以外のリンクは「地図を表示」に(別の地図が閉じられていない場合があるため) $('p.show_map a').not(this).removeClass('close').text('地図を表示'); //map_infoクラスの div 要素のインスタンスを変数に代入 var map_info$ = $(this).closest('.map_info'); //map_infoクラスの div 要素に地図を表示する領域を移動 append map_info$.append($('#map_container')); var address = map_info$.find('p.address').text(); var my_reg = /〒\s?\d{3}(-|ー)\d{4}/; //郵便番号を含めるとおかしくなる場合があったので、郵便番号は削除 address = address.replace(my_reg, ''); //URL を取得 if(map_info$.find('p.web').text() != '') { var url = map_info$.find('p.web a').attr('href'); } //地図を表示する領域に枠線を付けてフェードインで表示 $('#map_container').css('border-width', '1px').fadeIn(1000); //zoom を取得 var zoom = map_info$.find(".zoom").text() ? parseInt(map_info$.find(".zoom").text()): 16; //マーカーのタイトル var title = map_info$.find('p.venue').text(); //地図を表示 showMap(address, title, url, zoom); } return false; }); }); </script>
スパム対策
ウェブ上にメールアドレスを掲載すると、スパム(迷惑)メールが届くようになることがあります。以下はメールアドレス収集プログラムに収集されるのを防止する方法の1つの例です。
メールアドレス用のリンク
メールアドレスをウェブ上に掲載する場合、a 要素を使ってリンク先として href 属性値に「mailto:」から始まる文字列を記述してメールアドレス用のリンクを作ることができます。
<a href="mailto:info@example.com">info@example.com</a>
表題(subject)付きのアドレスの場合は ?subject= を追加して以下のように記述します。
<a href="mailto:info@example.com?subject=お問い合わせ">info@example.com</a>
更に本文(body)も追加するには、以下のように記述します。
<a href="mailto:info@example.com?subject=件名&body=本文">info@example.com</a>
以下のような書式になっています。
mailto:メールアドレス?subject=件名&body=本文
- ? … メールアドレスとその後の文字列を ? で区切ります
- subject= … メールの件名を記述します
- body= … メールの本文を記述します
- & … 件名と本文を & マークで区切ります(文字参照の & を使用します)
また、表示する文字をメールアドレス以外にする場合は以下のように記述できます。
<a href="mailto:info@example.com?subject=お問い合わせ">カスタマーサービス</a>
しかし、上記の方法でメールアドレスを公開すると、HTML ソース中にメールアドレス(xxxx@xxx.xxx)を掲載することになり、また a 要素の href 属性に「mailto:」を記述していることからメールアドレスであることがわかってしまい、メールアドレス収集プログラムに簡単に収集されてしまいます。
JavaScriptでメールリンクを生成
JavaScript(jQuery)を使ってメールリンクを生成すると、HTML ソースや JavaScript ソースに直接メールアドレスは含まれないので、(自動収集プログラムが、単にファイルの中身を読むだけであれば)自動収集をある程度防ぐことができます。
以下は、件名や本文を含まない単純なメールリンクを生成する例です。
まず、HTML への記述の方法を決めておく必要がるので、以下のようなルールにします。
- メールアドレスを表示する部分は span 要素で記述し、クラスを「nsm」(no spam mail の略)とすることとします(任意の値でかまいません)。
- メールアドレスの「@」を半角英字のカンマ「,」に換えて記述します。
<!-- メールアドレスの記述 --> <span class="nsm">info,example.com</span>
info,example.com
以下は、JavaScript(jQuery)を使ってメールリンクを生成する記述例です。
@ マークはそのまま記述せず、文字参照の @ を使用しています。
以下のスクリプトは外部ファイルとして保存して、読み込むようにします。
jQuery(function($){ var delimiter = ","; //分割文字をカンマに設定 if($('span.nsm').length !== 0) { //メールアドレスがある場合のみ実行 if($('span.nsm').text() !== ''){ var nsm_strings = $('span.nsm').text().split(delimiter);//分割文字で分割 var pre = $.trim(nsm_strings[0]); //最初の部分から空白を削除 var domain = "@" + $.trim(nsm_strings[1]); //@(@)と後ろの部分から空白を削除したものを連結 var nsm_address = pre + domain; //メールアドレスを組み立てる $('span.nsm').html('<a href="ma' + 'ilto:' + nsm_address + '">' + nsm_address + '</a>'); } } });
- split() メソッドは、指定された区切り文字(分割文字)で文字列を分割します。
- $.trim() メソッドは、文字列の前後の空白を取り除きます。
同じページにメールアドレスが複数必要な場合は、each() メソッド を利用して以下のようにします。
jQuery(function($){ var delimiter = ","; //分割文字をカンマに設定 if($('span.nsm').length !== 0) { //メールアドレスがある場合のみ実行 $('span.nsm').each(function() { if($(this).text() !== ''){ var nsm_strings = $(this).text().split(delimiter); //分割文字で分割 var pre = $.trim(nsm_strings[0]); //最初の部分から空白を削除 var domain = "@" + $.trim(nsm_strings[1]); //@(@)と後ろの部分から空白を削除したものを連結 var nsm_address = pre + domain; //メールアドレスを組み立てる $(this).html('<a href="ma' + 'ilto:' + nsm_address + '">' + nsm_address + '</a>'); } }); } });
表題(subject)付きや表示する文字をメールアドレス以外にする場合に対応
表題(subject)付きや表示する文字をメールアドレス以外にする場合に対応させる方法です。まず、HTML への記述の方法を以下のように決めておきます。
- メールアドレスを表示する部分は span 要素で記述し、クラスを「nsm」(no spam mail の略)とすることとします(任意の値でかまいません)。
- メールアドレスの「@」を半角英字のカンマ「,」に換えて記述します。
- 表題(subject)と表示する文字もそれぞれカンマ「,」で区切って表題、表示する文字の順番で記述します。
以下のように記述するようにします。
<span class="nsm">info, example.com, お問い合わせ, カスタマーサービス</span>
info, example.com, お問い合わせ, カスタマーサービス
表題が不要な場合はその部分を空にしておきます。
<span class="nsm">info, example.com, , カスタマーサービス</span>
info, example.com, , カスタマーサービス
表示する文字と表題も不要な場合はメールアドレス部分をカンマで区切って記述します。
<span class="nsm">info, example.com</span>
info, example.com
以下がスクリプトの記述例です。同じページにメールアドレスが複数必要な場合にも対応しています。
jQuery(function($){ if($('span.nsm').length !== 0) { $('span.nsm').each(function() { if($(this).text() !== ''){ var nsm_strings = $(this).text().split(delimiter); //分割文字で分割 nsm_strings = $.map(nsm_strings, function(value){ return $.trim(value);//分割した文字列から前後の空白を削除 }); var pre = nsm_strings[0]; //アドレスの@マークの前の文字列 var domain = "@" + nsm_strings[1]; //@(@)と後ろの部分を連結 var nsm_address = pre + domain; //メールアドレスを組み立てる var addressWithSubject = nsm_address; if(nsm_strings[2]){ //表題が指定されていれば addressWithSubject += "?subject=" + nsm_strings[2]; } if(nsm_strings[3]){ //表示する文字が指定されていれば $(this).html('<a href="ma' + 'ilto:' + addressWithSubject + '">' + nsm_strings[3] + '</a>'); }else{ $(this).html('<a href="ma' + 'ilto:' + addressWithSubject + '">' + nsm_address + '</a>'); } } }); } });
5行目:span 要素内の文字列を分割文字で分割して、それらの文字列の配列を変数に代入しています。
6行目~8行目:$.map() メソッドを使って、配列の要素(分割された文字列)の前後の空白を削除しています。
13行目:変数 addressWithSubject には、アドレス部分と表題部分になります。まずアドレス部分を代入しておきます。
14行目:もし表題が指定されていれば、nsm_strings[2] にその文字列が入っているはずです。その文字列が空白でなければ、addressWithSubject に表題の文字列を追加します。if 文で空白文字や null, undefined は false と判定されます。
17行目:表示する文字(nsm_strings[3])が指定されていれば、それを表示するようにしています。
21行目:表示する文字(nsm_strings[3])が指定されていなければ、メールアドレスを表示します。
クリッカブル・マップを使う場合
以下は、クリッカブル・マップを使ってメールを送信する場合の例です。
この場合、メールリンクは area 要素の href に記述します。
また、クリッカブル・マップを作成する場合、img 要素の usemap 属性は map 要素の id(name) の値に「#」を付けて指定します。
<p id="contactphoto"> <img src="../images/flower.jpg" usemap="#contactMap" alt=""> <map id="contactMap" name="contactMap"> <area alt="contact" href="info,example.com" coords="4,1,494,218" shape="rect"> </map> </p>
var delimiter = ","; var nsm_map_strings = $('map#contactMap area').attr('href').split(delimiter); //分割文字で分割 var pre = $.trim(nsm_map_strings[0]); var domain = "@" + $.trim(nsm_map_strings[1]); var nsm_map_address = pre + domain; //"@"はHTML上では @ に変換されるがこの時点では"@"のままなので @ に変換 $('map#contactMap area').attr('href', 'ma' + 'ilto:' + nsm_map_address.replace(/@/, '@'));
スムーズスクロール
ページ内リンクへプラグインを使わずにアニメーションで移動するスムーズスクロールの設定方法です。
animate メソッドと scrollTop プロパティ
画面をスクロールさせる場合 animate メソッドと scrollTop プロパティを利用しますが、どのセレクタに対して実行すべきかはブラウザ(WebKit かそれ以外)により異なります。
- WebKit : body 要素
- それ以外 : html 要素
$('body').animate({ scrollTop: 0 }); // WebKit $('html').animate({ scrollTop: 0 }); // WebKit以外
scrollTop() はメソッドですが、scrollTop は jQueryが用意した CSS 用のプロパティで、 animate() で使用します。値にはトップからの距離を数値(ピクセル。但し px は付けない)で指定します。
以下のように両方を指定して全てのブラウザに対応することができますが、単純なスクロールだけなら問題はないですが、両方指定するとコールバックを指定している場合など、コールバックが2回呼ばれてしまうという副作用があります。
$('html, body').animate({ scrollTop: 0 });
そのためブラウザを判定する必要がありますが、jQuery 1.9 になって $.browser が使えなくなっているため、「使用したい機能が機能するか」で判定する必要があります。
スクロールさせることができる要素が html か body かを判定するには、以下のように実際にどちらの要素でスクロールするかを調べます。
var isHtmlScrollable = (function(){ var html = $('html'), top = html.scrollTop(); var el = $('<div/>').height(10000).prependTo('body'); html.scrollTop(10000); //alert(html.scrollTop()); 表示される値は 0 または 10000 var rs = !!html.scrollTop(); html.scrollTop(top); el.remove(); return rs; })(); //スクロールのアニメーション $(isHtmlScrollable ? 'html' : 'body').animate({scrollTop:100});
- 2行目:html 要素の jQuery オブジェクトを変数 html に格納して、現在の top の値を変数 top に格納
- 3行目:div 要素を生成して高さを 10000 に設定し、body 要素に追加
- 4行目:html を 10000px スクロールさせる
- 6行目:html がスクロールしていれば、html.scrollTop() の値は 10000 になり、スクロールしていなければ値は 0 になるので、2重否定(※)で真偽値を変数 rs に格納
- 7行目:html を最初の高さ(top)に戻す
- 8行目:生成した div 要素(el)を削除
- 9行目:真偽値を返す
上記の結果、変数 isHtmlScrollable には、html 要素がスクロールしているかどうかの真偽値が格納されています。
この結果を利用して、13行目のように animate メソッドの対象を html 要素または body 要素に対して実行します。
13行目の isHtmlScrollable ? 'html' : 'body' は条件演算子(三項演算子)を使用して、isHtmlScrollable の値が true であれば html 要素を、false であれば body 要素を使用するように設定しています。
二重否定(※)
“undefined” や object 等が返る可能性がある値を二重否定を行うことで真偽値(Boolean)として取得するイディオムのようなものです。
var foo = undefined; console.log(foo); //undefined console.log(!foo); //true console.log(!!foo); //false var bar = {}; console.log(bar); // Object {} console.log(!bar); //false console.log(!!bar); //true var baz = null; console.log(baz); // null console.log(!baz); //true console.log(!!baz); //false var zero = 0; console.log(zero); // 0 console.log(!zero); //true console.log(!!zero); //false var empty = ""; console.log(empty); // 空文字列 console.log(!empty); //true console.log(!!empty); //false
ページトップへの移動
href 属性の値が「#」の場合、ページトップへアニメーションで移動するようにするには、以下のように記述します。
※ jQuery3 を使用する場合の注意: jQuery3 からは、$('a[href=#]') の部分を $('a[href="#"]') のように # を引用符で囲む必要があります。そうしないと「Syntax error, unrecognized expression: [href^=#]」のようなエラーが発生します。(jQuery3 では "#"のみのセレクタは不正な文法としてエラーになることと関係しているかも知れません)
jQuery(document).ready(function($) { $('a[href="#"]').click(function () { $(isHtmlScrollable ? 'html' : 'body').animate({ scrollTop: 0 }, 500); return false; }); var isHtmlScrollable = (function(){ var html = $('html'), top = html.scrollTop(); var el = $('<div/>').height(10000).prependTo('body'); html.scrollTop(10000); //alert(html.scrollTop()); 表示される値は 0 または 10000 var rs = !!html.scrollTop(); html.scrollTop(top); el.remove(); return rs; })(); });
但し、href 属性の値が「#」でも、アニメーションを適用したくない場合もあるので、それらに関しては not() メソッドを使って除外するようにします。
(注意)除外しないと、return false を使ってデフォルトの動作をキャンセルしようとしても、できなくなってしまいます。
以下は、noScroll というクラスを持つ要素を除外する場合の例です。
jQuery(document).ready(function($) { $('a[href="#"]').not('.noScroll').click(function () { $(isHtmlScrollable ? 'html' : 'body').animate({ scrollTop: 0 }, 500); return false; }); var isHtmlScrollable = (function(){ ・・・省略・・・ })(); });
ページ内リンクとページトップへの移動
ある要素の id 属性へのリンクへの移動もアニメーションさせるようにします。
<a href=”#someElement” > のような場合にも対応するには以下のようにします。
- $(“[属性名^=’値’]”):特定の属性が指定した値で始まっている要素
- not() 除外する要素を指定(除外するものがなければ不要)
- 要素の href 属性の値を「hrefval」に格納
- 「hrefval」はページトップの場合「#」、その他の場合は要素の id「#id名」になっています
- 対象となる要素「targetelement」を生成
- 要素のポジションを取得
- その位置までアニメーション
jQuery(document).ready(function($) { $('a[href^="#"]').not('アニメーションさせない a 要素').click(function(){ var hrefval= $(this).attr('href'); var targetelement = hrefval == "#" ? $('html') : $(hrefval); var positiontop = targetelement.offset().top; //移動先のポジションを取得 $(isHtmlScrollable ? 'html' : 'body').animate({ scrollTop: positiontop }, 500); return false; }); var isHtmlScrollable = (function(){ ・・・省略・・・ })(); });
「先頭へ」というリンクを表示
ある程度スクロールすると「先頭へ」というリンクを表示させて、そのリンクをクリックするとページ先頭にアニメーションで移動させるには、以下のようにします。
jQuery(document).ready(function($) { $('#footer').after('<div class="tothetop"><a href="#">先頭へ</a></div>'); var topBtn = $('.tothetop'); topBtn.hide(); $(window).scroll(function () { if ($(this).scrollTop() > 500) { topBtn.fadeIn(); } else { topBtn.fadeOut(); } }); //ページ内リンクとページトップへのアニメーション $('a[href^="#"]').not('アニメーションさせない a 要素').click(function(){ ・・・省略・・・ }); var isHtmlScrollable = (function(){ ・・・省略・・・ })(); });
- フッターなどの最後の要素の後に「先頭へ」というリンク(クラス名:”tothetop”)を追加します。
- 最初はリンクを非表示にします topBtn.hide();
- スクロールの値(以下の例では500px)に応じてリンクをアニメーションで表示・非表示にします。
- その後に前述のアニメーションでの移動に関する記述をします。
「先頭へ」というリンクには、後でスタイルを指定しやすいようにクラスを付与しておきます(この例ではクラス名:”tothetop”)。
2行目は、id 属性が「footer」の要素の後に after() を使って追加していますが、以下のように body 要素に append() を使って追加しても同じです。
$('body').append('<div class="tothetop"><a href="#">先頭へ</a></div>');
スピードやポジションの調整
スピードは animate() メソッドのパラメータにミリ秒で指定していますが、移動する距離に応じてスピードを調整したり、ページ内リンクへの移動の場合は環境によっては位置を調整する必要があるかも知れません。そのような場合は、以下のようにして調整することができます。
以下の例では、スピードの調整で移動距離を30で割っていますが、この値はそれぞれの環境に合わせて調整してください。
位置の調整では、その要素のポジションより少し上にスクロールするようにすると良いと思います。これも環境に合わせて調整してください。
jQuery(document).ready(function($) { $('a[href^="#"]').not().click(function(){ var hrefval= $(this).attr('href'); var positiontop; var speed; if(hrefval == "#") { //Top への移動の場合 positiontop = 0; speed = 200 + $(this).offset().top /30; //スピードを調整 }else{ //ページ内リンクへの移動の場合 var targetelement = $(hrefval); positiontop = targetelement.offset().top -120; //位置を調整 speed = 200 + (positiontop + 120) / 30; //スピードを調整 } $(isHtmlScrollable ? 'html' : 'body').animate({ scrollTop: positiontop }, speed); return false; }); ・・・省略・・・ });
「ページ先頭へ」というリンクの CSS の例です。固定した位置に表示するため「position: fixed;」は必須です。(jQuery で設定することもできますが)
div.tothetop { position: fixed; /* 必ず fixed に設定します。 */ right: 5%; bottom: 7%; z-index: 150; opacity: .6; } div.tothetop a { display: block; color: #fff; margin: 0; background-color: #fdfdfd; background-color: #555; font-size: 0.9em; outline: none; text-decoration: none; -webkit-border-radius: 30px; -moz-border-radius: 30px; -ms-border-radius: 30px; -o-border-radius: 30px; border-radius: 30px; -webkit-transition: 0.3s; -moz-transition: 0.3s; -o-transition: 0.3s; transition: 0.3s; height: 60px; width: 60px; line-height: 60px; text-align: center; } div.tothetop a:hover { background-color: #222; color: #789ACD; } div.tothetop a:active { background-color: #888888; color: #fff; border: 1px solid #a2a2a2; }
最終的なスクリプトは以下のようになります。
jQuery(document).ready(function($) { //「先頭へ」というリンクを表示 $('body').append('<div class="tothetop"><a href="#">先頭へ</a></div>'); var topBtn = $('.tothetop'); topBtn.hide(); $(window).scroll(function () { if ($(this).scrollTop() > 500) { topBtn.fadeIn(); } else { topBtn.fadeOut(); } }); //スクロールのアニメーション $('a[href^="#"]').not().click(function(){ var hrefval= $(this).attr('href'); var positiontop; var speed; if(hrefval == "#") { //Top への移動の場合 positiontop = 0; speed = 200 + $(this).offset().top /30; //スピードを調整 }else{ //ページ内リンクへの移動の場合 var targetelement = $(hrefval); positiontop = targetelement.offset().top -120; //位置を調整 speed = 200 + (positiontop + 120) / 30; //スピードを調整 } $(isHtmlScrollable ? 'html' : 'body').animate({ scrollTop: positiontop }, speed); return false; }); //ブラウザの機能判定 var isHtmlScrollable = (function(){ var html = $('html'), top = html.scrollTop(); var el = $('<div/>').height(10000).prependTo('body'); html.scrollTop(10000); var rs = !!html.scrollTop(); html.scrollTop(top); el.remove(); return rs; })(); });
ページ外へのリンク
ページ内リンクではなく、外部からページのアンカー(#)へアクセスがあった場合にスムーズスクロールする方法です。
URL の # を含むアンカーの文字列(ハッシュ)は Location オブジェクトの hash プロパティで取得できます。
取得したハッシュが空文字でなければ、それを元にそのポジション target.offset().top を取得して animate() でアニメーションを実行します。
var hash = window.location.hash; //Location オブジェクト hash プロパティ if (hash !== "") { var target = $(hash); var pos = target.offset().top - 100; //100px 上に調整 $(isHtmlScrollable ? 'html' : 'body').animate({ scrollTop: pos }, 800); }
ページ内リンクの場合はページの読み込みが完了しているので jQuery の処理なども終了していますが、外部からページへアクセスした場合は記述する位置によっては、他の jQuery の処理などに影響されて期待した位置にスクロールされない可能性があります。
その場合は、記述する位置を他の JavaScript の処理の後にしてみると良いかも知れません。
ドロップダウンメニュー
ドロップダウンメニューのサンプルです。
基本的なドロップダウンメニュー
サブメニューの1階層目までの表示に対応した基本的なドロップダウンメニューです。
以下はメニューバーの HTML です。
メインメニューを ul li 要素で記述します。そしてメインメニューの li 要素の中にサブメニューを ul li 要素で入れ子にして記述します。
メインメニューの ul 要素にはクラス「menu」を、サブメニューの ul 要素にはクラス「sub」を指定しておきます。
<ul class="menu"> <li><a href="#">Menu A </a> <ul class="sub"> <li><a href="#">Sub Menu A </a></li> <li><a href="#">Sub Menu A </a></li> <li><a href="#">Sub Menu A </a></li> </ul> </li> <li><a href="#">Menu B </a> <ul class="sub"> <li><a href="#">Sub Menu B </a></li> <li><a href="#">Sub Menu B </a></li> <li><a href="#">Sub Menu B </a></li> </ul> </li> <li><a href="#">Menu C </a> <ul class="sub"> <li><a href="#">Sub Menu C </a></li> <li><a href="#">Sub Menu C </a></li> <li><a href="#">Sub Menu C </a></li> </ul> </li> </ul>
以下は CSS の記述です。jQuery の記述なしでも動作するように、基本的な機能を CSS で設定します。
メニューの ul 要素の padding, margin を 0 に設定してリセットしておきます。
メインメニューの li 要素は、float: left で横並びにして、幅と高さ、背景色を指定します。また、子要素の基準とするため、position: relative を指定します。
box-sizing:border-box は、サブメニューの li 要素にボーダーを設定するので指定しています。box-sizing:border-box を使用しない場合は、サブメニューの li 要素の幅をボーダー分(1+1=2px)引いた width: 148px に指定します。
a 要素はクリックできる範囲を li 要素と同じ範囲に拡大するため display: block でブロックレベル要素に変換します。また、line-height を li 要素の height と同じ値に設定します。
a:hover には、マウスオーバー時の背景色を設定します。
サブメニューの ul 要素は display: none で非表示にしておきます。また、サブメニューを開いた際に、マウスイベントが動作しなくなる現象を回避するために、position: absolute を指定します。
メインメニューの li 要素にマウスオーバー時は、ul.menu li:hover ul.sub に display: block でサブメニューを表示するように設定します。
最後に、メインメニューの回りこみ(float: left)を解除するために、 clearfix を設定します。
ul.menu { padding: 0 ; margin: 0; } ul.menu li { float: left; /*メインメニューは横並びに*/ width: 150px; height: 40px; background-color: #2F4B97; position: relative; /*子要素の基準とするために指定*/ list-style-type: none; box-sizing:border-box; } ul.menu li a { display: block; line-height: 40px; text-align: center; text-decoration: none; color: #fff; } ul.menu li a:hover { background-color: #5169A8; } ul.menu li ul.sub { display: none; position: absolute; /*サブメニューを開いた際に、背後の要素の影響を受けないようにする*/ padding: 0; margin: 0; } ul.menu li:hover ul.sub { display: block; } ul.menu li ul.sub li:first-child{ border-top: 1px solid #1C2973; /*最初の要素のみボーダートップを指定*/ } ul.menu li ul.sub li { border: 1px solid #1C2973; /*ボーダーの指定*/ border-top: none; /*ボーダートップは重なって太くなるので解除*/ } ul.menu { zoom:1; /*Clearfix IE6-7 対応*/ } ul.menu:after { /*Clearfix*/ height:0; visibility:hidden; content:"."; display:block; clear:both; }
上記の HTML と CSS で以下のようなメニューが表示されます。
jQuery の記述は以下のようになります。
CSS でサブメニューの ul 要素は display: none で非表示にしてありますが、jQuery でも hide() で非表示にします。
続いて、hover() イベントで、マウスオーバーとマウスアウトのイベントを設定します。
マウスオーバー時に何度もアニメーションが繰り返し実行されるのを防ぐために、:not(:animated) を使って slideDown() を設定します。
$('ul:not(:animated)', this) のコンテクストの this は、'ul.menu>li' になります。
jQuery(function($){ $('ul.sub').hide(); $('ul.menu>li').hover(function(){ $('ul:not(:animated)', this).slideDown(400); }, function(){ $('ul',this).hide(); }); });
多階層ドロップダウンメニュー
以下は、多階層(マルチレベル)対応のドロップダウンメニューのサンプルです。
基本的なドロップダウンメニューと同様にメインメニューを ul li 要素で記述します。そしてメインメニューの li 要素の中にサブメニューを ul li 要素で入れ子にして記述します。
メインメニューの ul 要素にはクラス「menu」を、サブメニューの ul 要素にはクラス「sub」を指定しておきます。
<ul class="menu"> <li><a href="#">Menu A</a> <ul class="sub"> <li><a href="#">Sub Menu A</a></li> <li><a href="#">Sub Menu A</a></li> <li><a href="#">Sub Menu A</a> <ul class="sub"> <li><a href="#">Sub Menu A2</a></li> <li><a href="#">Sub Menu A2</a></li> <li><a href="#">Sub Menu A2</a></li> </ul> </li> </ul> </li> <li><a href="#">Menu B</a> <ul class="sub"> <li><a href="#">Sub Menu B</a></li> <li><a href="#">Sub Menu B</a> <ul class="sub"> <li><a href="#">Sub Menu B2</a></li> <li><a href="#">Sub Menu B2</a></li> <li><a href="#">Sub Menu B2</a></li> </ul> </li> <li><a href="#">Sub Menu B</a></li> </ul> </li> <li><a href="#">Menu C</a> <ul class="sub"> <li><a href="#">Sub Menu C</a></li> <li><a href="#">Sub Menu C</a></li> <li><a href="#">Sub Menu C</a> <ul class="sub"> <li><a href="#">Sub Menu C2</a></li> <li><a href="#">Sub Menu C2</a></li> <li><a href="#">Sub Menu C2</a> <ul class="sub"> <li><a href="#">Sub Menu C3</a></li> <li><a href="#">Sub Menu C3</a></li> <li><a href="#">Sub Menu C3</a></li> </ul> </li> </ul> </li> </ul> </li> </ul>
2階層目以降のサブメニューは、position で表示位置をずらすので a 要素に position: relative を指定しておきます。
サブメニュー内の li 要素(ul.sub li)は横並びにならないように float: none でフロートを解除します。
2階層目以降のサブメニュー (ul.sub li ul.sub)は position: absolute で絶対配置にして、親要素の左上を座標の基準として配置します。left: 150px と top: 0 と指定することで、親要素の li 要素と横並びに配置します。
ul.menu, ul.sub { padding: 0 ; margin: 0; } ul.menu li { float: left; width: 150px; height: 40px; background-color: #2F4B97; position: relative; /*子要素の基準とするために指定*/ list-style-type: none; box-sizing: border-box; } ul.menu li a { display: block; line-height: 40px; color: white; text-decoration: none; text-align: center; position: relative; /* 2階層目以降のサブメニューのため */ } ul.menu li a:hover { background: #5169A8; } ul.sub { display: none; } ul.sub li { float: none; } /* この部分は、jQuery でドロップダウンを表示する際は不要なので削除 ul.menu li:hover > ul.sub { display: block; } */ /* 2階層目以降のサブメニュー */ ul.sub li ul.sub { position: absolute; /* 親要素の左上が座標の基準になる */ left: 148px; /* ボーダー分2pxを調整 */ top: 0; } /* 一番右側のメニュー */ ul.menu li:last-child ul.sub li ul.sub { /* メニューを展開したときに、表示範囲内に収めるために向きを反転 */ left: -150px; } ul.menu li ul.sub { position: absolute; /* サブメニューを開いた際にマウスイベントが動作しなくなる現象を防止 */ } ul.menu li ul.sub li:first-child { border-top: 1px solid #1C2973; /*最初の要素のみボーダートップを指定*/ } ul.menu li ul.sub li { border: 1px solid #1C2973; /*ボーダーの指定*/ border-top: none; /*ボーダートップは重なって太くなるので解除*/ } ul.menu { zoom:1; /*IE6-7 対応*/ } ul.menu:after { height: 0; visibility: hidden; content: "."; display: block; clear: both; }
IE6 と IE7 に対応するためには、レイアウト機能にバグがあるため、以下の CSS を追加します。* html は IE6 用で、*+html は IE7 用の CSS です。
* html ul.menu li { display: inline; zoom: 1; } *+html ul.menu li { display: inline; zoom: 1; } * html ul.sub { zoom: 1; position: relative; } *+html ul.sub { zoom: 1; position: relative; }
以下は、まだ jQuery を使用していない場合の状態のサンプルです。
jQuery の記述は、基本的なドロップダウンメニューと同じですが、子セレクタ(>)を利用して、マウスオーバーした li 要素の直接の子の(直下の) ul 要素のみ表示・非表示を切り替えるようにしています。
jQuery(function($){ $("ul.menu li").hover(function(){ $(">ul:not(:animated)", this).slideDown(400); }, function(){ $(">ul", this).slideUp("fast"); }); });
縦にスライドするメニュー
親メニューをクリックすると、それに属するサブメニューをスライドアニメーションで表示するメニューのサンプルです。
- 「+」「-」「■」の3つの画像を用意します。
- 親メニュー(div.parentmenu)にマウスオーバーすると「+」印が表示され、選択(クリック)すると「-」印に変わり、サブメニュー(ul.submenu li)が表示されます。
- サブメニューが表示されている場合は、親メニューにマウスオーバーすると「-」印が表示され、クリックするとサブメニューは非表示になります。
- サブメニューがないもの(a 要素)は、マウスオーバーすると「■」印が表示され、クリックするとリンク先にジャンプします。
以下はメニューの HTML です。
親メニューは li 要素の中に、クラス属性「parentmenu」を付与した div 要素でマークアップします。
サブメニューは親メニューの li 要素の中に ul li 要素で入れ子にして記述します。
<ul class="navi"> <li><a href="#">Home</a></li> <li><div class="parentmenu">News</div> <ul class="submenu"> <li><a href="#">Events</a></li> <li><a href="#">Activities</a></li> </ul> </li> <li><div class="parentmenu">Gallery</div> <ul class="submenu"> <li><a href="#">Gold</a></li> <li><a href="#">Silver</a></li> <li><a href="#">Crystal</a></li> </ul> </li> <li><div class="parentmenu">About</div> <ul class="submenu"> <li><a href="#">Artist</a></li> <li><a href="#">Past Exhibitions</a></li> </ul> </li> <li><a href="#">Contact</a></li> </ul>
以下は CSS の記述です。
ul, li { margin: 0; padding:0; } ul.navi{ width: 220px; /*メニューの幅全体を指定*/ list-style-type: none; } ul.navi li div.parentmenu { padding-left: 25px; /*マウスオーバー時に背景に画像を表示するためパディングを指定*/ cursor: pointer; /*マウスオーバー時にカーソルをポインターに*/ font-size: 16px; color: #777; } ul.navi li div.parentmenu:hover { background: url(../images/jquery/menu_plus.png) no-repeat left center; /*マウスオーバー時に背景に「+」印の画像を表示*/ } ul.navi li div.selected:hover { background: url(../images/jquery/menu_minus.png) no-repeat left center; /*サブメニューをすでに表示している時は、マウスオーバー時に背景に「-」印の画像を表示*/ } ul.navi li div.selected { color: #333; /*サブメニューを表示している時は、親メニューの色を変更*/ } ul li { font-size: 13px; font-size: 1.3rem; line-height: 20px; } ul li a { outline: 0; /*リンクをクリックした際、リンクの回りに点線が表示されないように*/ padding-left: 25px; /*マウスオーバー時に背景に画像を表示するためパディングを指定*/ display: block; text-decoration: none; color: #777; font-size: 16px; } ul li a:hover { color: #3E74AD; background: url(../images/jquery/menu_square.png) no-repeat left center; /*マウスオーバー時に背景に「■」印の画像を表示*/ } ul.submenu { padding-left: 30px; /*サブメニューはインデントして表示*/ list-style-type: none; } .navi > li{ border: 1px solid #999; margin: 3px 0; padding: 5px 0 5px 5px; border-radius: 3px; } ul.submenu a { margin: 5px 0; }
以下は、jQuery の記述です。
親メニューをクリックしたとき、サブメニューが開かれていなければ、サブメニューを表示し、サブメニューが開かれていれば、サブメニューを閉じます。
また、サブメニューが開かれている親メニューにクラス「selected」を付与して、マウスオーバー時に背景に「-」印の画像を CSS で表示するようにします。
jQuery(function($){ $('ul.submenu').hide(); $('ul.navi li div.parentmenu').click(function() { $('ul.submenu').slideUp(200); $('ul.navi li div.parentmenu').removeClass('selected'); if($('+ul', this).css('display') == 'none') { $('+ul', this).slideDown(200); $(this).addClass('selected'); } }); });
2行目:サブメニューをすべて非表示にします。
3行目以降:親メニューをクリックした場合の処理を記述しています。
4行目:親メニューをクリックしたとき、サブメニューが開いていれば、まず一度、slideUp でそれらを全て閉じます。
5行目:一度クラス「selected」を削除します。(親メニューがすでにクリックされサブメニューが表示されている場合)
6行目と7行目:クリックした親メニュー(this)に隣接する ul 要素(サブメニュー)が表示されていなければ、slideDown で表示します。
8行目:親メニュー(this)にクラス「selected」を追加します。
LightBox モーダルウィンドウ
サムネイル画像をクリックすると、モーダルウィンドウで拡大画像を表示するサンプルです。
関連ページ:Bootstrap4 モーダルを使った LightBox
半透明のモーダルウィンドウの領域(id 属性が bg_layer の div 要素)と拡大画像を表示する領域(id 属性が over_layer の div 要素)は jQuery で追加(挿入)します。
サムネイル画像は a 要素で囲み、href 属性にモーダルウィンドウで表示する拡大画像のパスを記述し、class 属性に myLbox (任意のクラス名)を設定します。
「閉じる」ボタンも jQuery で追加(挿入)します。
また、拡大画像の高さと幅を a 要素の data-h, data-w 属性に指定しておきます。
このサンプルでは、p 要素及び ul/li 要素でサムネイル画像をマークアップしています。
以下は HTML です。
<p class="lbox"> <a href="images/sample_01.jpg" class="myLbox" data-h="398" data-w="600"> <img src="images/sample_01_thumb.jpg" alt="beach"> </a> </p> <ul> <li> <a href="images/sample_02.jpg" class="myLbox" data-h="531" data-w="800"> <img src="images/sample_02_thumb.jpg" alt="beach"> </a> </li> <li> <a href="images/sample_03.jpg" class="myLbox" data-h="797" data-w="1200"> <img src="images/sample_03_thumb.jpg" alt="beach"> </a> </li> </ul>
以下は CSS の記述です。
半透明のモーダルウィンドウをブラウザいっぱいに表示するために、body 要素及び html 要素を height: 100% に設定し、ブラウザによって異なる body 要素及び html 要素の余白(margin、padding)は 0 に設定しておきます。
#bg_layer(半透明のモーダルウィンドウ)に、height: 100%; width: 100%; を指定し、position: fixed; top: 0; left: 0; でブラウザの左上を基点とします。また背景色を黒にして、opacity で半透明にします。
#over_layer(拡大画像を表示する領域)も、position: fixed; を指定します。また、top: 50%; left: 50%; を指定しておき、スクリプトで margin-top, margin-left を指定して画面中央に表示するようにします。
#bg_layer(半透明のモーダルウィンドウ)と #over_layer(拡大画像を表示する領域)は display:none で初期状態では非表示にします。
「閉じる」ボタンもスクリプトで追加しますが、絶対配置で拡大画像の右上に表示するように調整し、マウスオーバーした際にマウスの形状が変わるように、cursor: pointer を指定します。
html, body { margin: 0; padding: 0; height: 100%; } #bg_layer { display: none; position: fixed; top: 0; left: 0; height: 100%; width: 100%; background: #000; opacity: 0.80; filter: alpha(opacity=80); z-index: 10; } #over_layer { display: none; position: fixed; top: 50%; left: 50%; z-index: 15; } p.close { margin: 0; padding: 0; position: absolute; top: -15px; right: -10px; cursor: pointer; font-size: 24px; color: white; z-index: 20; } p.close:hover { color: #F5CFD0; }
以下は jQuery の記述です。
3行目では、append() メソッドで、半透明のモーダルウィンドウの領域と拡大画像を表示する領域を body 要素の後ろに挿入しています。
6行目からは、class 属性が myLbox の a 要素にクリックイベントを設定しています。
7行目は #over_layer(拡大画像を表示する領域)が非表示かどうかの条件判定で、非表示の場合それ以降を実行します。
8行目は、show() メソッドで #bg_layer(半透明の領域)を表示します。
10行目、11行目は拡大画像の高さと幅を data-h, data-w 属性から取得しています。
13行目、14行目はブラウザの高さと幅を取得しています。
15行目から24行目では、ブラウザの高さと幅と、拡大画像の高さと幅を比較して、表示する拡大画像のサイズを調整しています。
26行目からは、拡大画像を表示する領域(#over_layer)を fadeIn() メソッドで表示して、html() メソッドを使って #over_layer に img 要素と「閉じる」ボタンを挿入しています。
img 要素の src 属性には、a 要素の href 属性から取得した値: $(this).attr("href") を設定しています。
また、css() メソッドで拡大画像を表示する領域(#over_layer)の位置(marginTop、marginLeft)を調整します。
#over_layer の位置は、CSS で top: 50%; left: 50%; と設定し、css() メソッドで marginTop (margin-top) に拡大画像の高さの半分のネガティブマージン(マイナスの値のマージン)を、 marginLeft (margin-left) に拡大画像の横幅の半分のネガティブマージンを設定すると、画面中央に配置できます。
38行目から41行目は、on() メソッドを使って、 #bg_layer(半透明の領域)か「閉じる」ボタンがクリックされた場合に、hide() で非表示にしています。
jQuery(function($){ //#bg_layer(半透明の領域)と #over_layer(拡大画像を表示する領域)を挿入 $("body").append("<div id='bg_layer'></div><div id='over_layer'></div>"); //サムネイルをクリックした際の処理 $('a.myLbox').click(function() { if($('#over_layer').css('display') == 'none') { $('#bg_layer').show(); var height = $(this).data('h'); var width = $(this).data('w'); var wh =$(window).height(); var ww = $(window).width(); if(height > wh * .9) { var original_height = height; height = wh * .9; width = width * height / original_height; } if(width > ww * .9) { var original_width = width; width = ww * .9; height = height * width / original_width; } $('#over_layer').fadeIn(400).html("<img src='" + $(this).attr("href") + "' width='" + width + "' height='" + height + "'><p class='close'><i class='fa fa-times-circle-o'></i></p>") .css({ marginTop: '-' + height/2 + 'px', marginLeft: '-' + width/2 + 'px' }); } return false; }); //非表示にする(閉じる)処理 $(document).on('click', '#bg_layer, p.close', function(){ $('#over_layer,#bg_layer ').hide(); }); });
画像の先読み(プリロード)
拡大表示する画像の先読み(プリロード)しておくと、拡大画像の表示がスムーズになります。
このサンプルの場合、クラス属性が「myLbox」の a 要素の href 属性に画像のパスが記述されているのでそれを利用します。
<p class="lbox"> <a href="images/sample_01.jpg" class="myLbox" data-h="398" data-w="600"> <img src="images/sample_01_thumb.jpg" alt="beach"> </a> </p>
以下のように、each() を使って<img>の src 属性に画像のパスを設定することで拡大表示する画像のプリロードができます。
$('a.myLbox').each(function() { $("<img>").attr("src", $(this).attr('href')); });
画像の先読みとサイズの取得
前述のサンプルでは、拡大画像の高さと幅を a 要素の data-h, data-w 属性に記述しましたが、以下のサンプルでは拡大画像の幅と高さをスクリプトを使って取得します。
但し、このサンプルのように拡大画像の img 要素が直接 HTML には記述されていない場合は少し工夫が必要です。
1つの方法は、JavaScript を使って画像を先読みしてその画像のオリジナルのサイズを取得するようにします。
前述の jQuery を使った先読みでは、画像のサイズは取得できません。
Image オブジェクトを使い、下記のようにすることで、画像の元の(オリジナルの)サイズを取得することができます。
var img = new Image(); //Image オブジェクトの生成 img.onload = function () { //生成した Image オブジェクトを読み込み var height = img.height; // 画像の高さ var width = img.width; // 画像の幅 }; img.src = "images/sample.jpg";
以下は、画像を先読みして、その際に画像のサイズを取得する記述です。
push() は配列に要素を付け加えるメソッドです。
クラス属性が「myLbox」の a 要素に対して each() を使って先読みをします。
var h_array = []; //画像の高さを格納する配列 var w_array = []; //画像の幅 を格納する配列 $('a.myLbox').each(function(n) { var img = new Image(); img.onload = function () { var height = img.height; // 画像の高さ var width = img.width; // 画像の幅 h_array.push(height); w_array.push(width); }; img.src = $(this).attr('href'); });
以下のように for 文を使って、先読みしようとしてもうまく行かないので注意が必要です。
// うまくいかない例 var myLbox = $('a.myLbox'); for(var i = 0; i < myLbox.length; i++) { var img = new Image(); img.onload = function () { var height = img.height; // 画像の高さ var width = img.width; // 画像の幅 h_array.push(height); w_array.push(width); }; img.src = $(this).attr('href'); }
以下は、画像の先読みと Lightbox の記述全体です。
Lightbox の記述では、画像の高さと幅は画像の先読みの際に取得した値を利用しています。
そのために、var index = $(this).index('a.myLbox');でそれぞれの画像に対応するインデックスを取得しています。
jQuery(function($){ var h_array = []; //画像の高さを格納する配列 var w_array = []; //画像の幅 を格納する配列 $('a.myLbox').each(function(n) { var img = new Image(); img.onload = function () { var height = img.height; // 画像の高さ var width = img.width; // 画像の幅 h_array.push(height); w_array.push(width); }; img.src = $(this).attr('href'); }); $("body").append("<div id='bg_layer'></div><div id='over_layer'></div>"); $('a.myLbox').click(function() { var index = $(this).index('a.myLbox'); if($('#over_layer').css('display') == 'none') { $('#bg_layer').show(); var height = h_array[index]; var width = w_array[index]; var wh =$(window).height(); var ww = $(window).width(); if(height > wh * .9) { var original_height = height; height = wh * .9; width = width * height / original_height; } if(width > ww * .9) { var original_width = width; width = ww * .9; height = height * width / original_width; } $('#over_layer').fadeIn(400).html("<img src='" + $(this).attr("href") + "' width='" + width + "' height='" + height + "'><p class='close'><i class='fa fa-times-circle-o'></i></p>") .css({ marginTop: '-' + height/2 + 'px', marginLeft: '-' + width/2 + 'px' }); } return false; }); //非表示にする(閉じる)処理 $(document).on('click', '#bg_layer, p.close', function(){ $('#over_layer,#bg_layer ').hide(); }); });
スライドショー
スライドショーのサンプルです。
関連ページ:Bootstrap4 カルーセル
クロスフェードを使ったスライドショー
Beach
以下は、スライドショーの HTML です。
<div id="mainphoto"> <img src="../images/001.jpg" width="480" height="360" alt="Beach"> <p id="title">Beach</p> </div><!-- end of #mainphoto --> <ul id="photolist"> <li><img src="../images/001.jpg" alt="Beach"></li> <li><img src="../images/002.jpg" alt="Clear water"></li> <li><img src="../images/003.jpg" alt="Bay view"></li> <li><img src="../images/004.jpg" alt="Cloud in the sky"></li> <li><img src="../images/005.jpg" alt="Pool side"></li> <li><img src="../images/006.jpg" alt="Palm tree"></li> </ul>
id が mainphoto の div 要素に写真を表示します。最初に表示する写真を配置しておき、絶対配置に設定します。
id が title の p 要素には、写真のタイトルを表示します。写真のタイトルは、それぞれの img 要素の alt 属性の値を使用します。
id が photolist の ul 要素にスライドショーで使用する写真を記述しておき、この部分は非表示にしておきます。
以下が、CSS です。このスライドショーでは、480px X 360px の画像を使用しています。
#mainphoto { width: 480px; height: 360px; padding: 0; margin: 20px auto; position: relative; /*---基点とします。---*/ border: 5px solid #CCC; } /*---img 要素---*/ #mainphoto img { position: absolute; /*---絶対配置します---*/ top: 0; left: 0; } /*---写真のタイトルを表示する p 要素---*/ p#title { position: absolute; z-index: 10; bottom: 10px; right: 30px; font-size: 11px; color: #FFF; } /*---表示する写真を記述しておく ul 要素---*/ #photolist { display: none; }
以下は、スライドショーの基本的な部分の jQuery の記述です。
変数 nextphoto は、次に表示する img 要素のインデックスを格納します。最初は 0 にしておきます。
変数 photolist$ は、id が photolist の ul 要素内に記述されている img 要素のラップ集合です。
変数 photocount は、表示する画像要素の総数になります。
showphoto() はスライドショーを表示するための関数です。
変数 src、alt は次に表示する画像の src 属性と alt 属性を eq() を使って、取得しています。
変数 nextimg は次に表示する img 要素の HTML を生成しています。
jQuery(function($){ var nextphoto = 0; //次に表示する写真のインデックス var photolist$ = $('#photolist li img'); //画像要素のラップ集合 var photocount = photolist$.length; //画像要素の数 var timer; function showphoto() { //スライドショーの関数 var src = photolist$.eq(nextphoto).attr('src'); var alt = photolist$.eq(nextphoto).attr('alt'); var nextimg = '<img src="' + src + '" width="480" height="360" alt="' + alt + '">'; $('#mainphoto img').before(nextimg); $('#title').text(alt).hide().fadeIn(1000); $('#mainphoto img:last').fadeOut(1000, function(){ $(this).remove(); }); nextphoto = ( ++ nextphoto) % photocount; timer = window.setTimeout(showphoto,3000); } showphoto(); $(window).unload(function(){ window.clearTimeout(timer); }); });
10行目では、before() を使って、現在表示されている img 要素の前に、次に表示する画像を配置します。この時、img 要素は絶対配置を指定しているので、2つの画像は完全に重なって配置されます。(現在表示されている画像が手前になります)
11行目は、画像のタイトルをフェードインで表示しています。
12行目は、手前に表示されている画像を fadeOut() でフェードアウトして非表示にしていきます。これにより、10行目で配置された画像が少しずつ表示されて、クロスフェード効果ができます。
フェードアウトが完了しても、元の img 要素は display プロパティが none になっただけで HTML 要素としては存在しているので、13行目のコールバック関数内で、remove() を使って削除しています。
15行目は、次に表示する画像のインデックスを1つ増やしてします。
16行目は、window.setTimeout() を使って繰り返し処理するように設定しています。
20行目、21行目は、ページを閉じた際に、一応念のため、繰り返し処理を停止しています。
以下は、ここまでの記述で表示されるスライドショーのサンプルのリンクです。
また、上記の jQuery の記述は、window.setInterval() を使って以下のように記述することも可能です。
jQuery(function($){ var nextphoto = 1; var photolist$ = $('#photolist li img'); var photocount = photolist$.length; function showphoto() { var src = photolist$.eq(nextphoto).attr('src'); var alt = photolist$.eq(nextphoto).attr('alt'); var nextimg = '<img src="' + src + '" width="480" height="360" alt="' + alt + '">'; $('#mainphoto img').before(nextimg); $('#title').text(alt).hide().fadeIn(1000); $('#mainphoto img:last').fadeOut(1000, function(){ $(this).remove(); }); nextphoto = ( ++ nextphoto) % photocount; //nextphoto ++; //if(nextphoto == photocount ) nextphoto = 0; } var timer = window.setInterval(showphoto, 3000); });
コントロールの追加
続いて、再生ボタンやそれぞれの画像に対応する丸いアイコンを追加します。これらは、直接 HTML には記述せず、jQuery で追加します。
以下は、再生ボタンや丸いアイコンの CSS です。
#icons_wrapper { position: relative; width: 480px; height: 80px; margin: auto; } #icons { width: 20px; margin: 0 auto; } .icon { display: inline-block; background-color: #FFF; width: 8px; height: 8px; margin:5px 5px -20px 10px; cursor: pointer; border: 1px solid #999; border-radius: 5px; } .icon.icon_selected { background-color: #666; cursor: default; } .icon.icon_hover { border: 1px solid #666; background-color: #CCC; } #start { display: none; cursor: pointer; color: #999; position: absolute; top: 5px; left: 350px; }
以下は、再生ボタンや丸いアイコンを追加する jQuery の記述です。
丸いアイコンは、for 文で append() 使って画像の数だけ生成します。
var div_icons_wrapper$ = $('<div id="icons_wrapper"></div>'); var div_icons$ = $('<div id="icons"></div>'); div_icons_wrapper$.append(div_icons$); div_icons_wrapper$.append('<p id="start"><i class="fa fa-play-circle"></i></p>'); $('#mainphoto').after(div_icons_wrapper$ ); for(var i = 0; i < photocount; i++){ var icon_alt = photolist$.eq(i).attr('alt'); div_icons$.append('<div class="icon" title="' + icon_alt + '">'); } var icon$ = $('div.icon'); var icon_count = icon$.length; div_icons$.width(25 * icon_count); icon$.eq(nextphoto).attr('class', 'icon icon_selected');
上記の jQuery の記述により、以下のような HTML が生成されます。
<div id="icons_wrapper"> <div id="icons"> <div class="icon icon_selected" title="Beach"></div> <div class="icon" title="Clear water"></div> <div class="icon" title="Bay view"></div> <div class="icon" title="Cloud in the sky"></div> <div class="icon" title="Pool side"></div> <div class="icon" title="Palm tree"></div> </div> <p id="start"> <i class="fa fa-play-circle"></i> </p> </div>
以下は、jQuery の全文です。
丸いアイコンをクリックすると、そのアイコンに対応する画像をクロスフェードで表示するように関数 cross_fade() を追加しています。
また、スクリプトで追加した要素のクリックやマウスオーバーイベントを on() を使って設定しています。
jQuery(function($){ var nextphoto = 0; var photolist$ = $('#photolist li img'); var photocount = photolist$.length; var timer; var div_icons_wrapper$ = $('<div id="icons_wrapper"></div>'); var div_icons$ = $('<div id="icons"></div>'); div_icons_wrapper$.append(div_icons$); div_icons_wrapper$.append('<p id="start"><i class="fa fa-play-circle"></i></p>'); $('#mainphoto').after(div_icons_wrapper$ ); for(var i = 0; i < photocount; i++){ var icon_alt = photolist$.eq(i).attr('alt'); div_icons$.append('<div class="icon" title="' + icon_alt + '">'); } var icon$ = $('div.icon'); var icon_count = icon$.length; div_icons$.width(25 * icon_count); icon$.eq(nextphoto).attr('class', 'icon icon_selected'); function showphoto() { cross_fade(nextphoto); nextphoto = ( ++ nextphoto) % photocount; timer = window.setTimeout(showphoto,3000); } showphoto(); var is_animated; function cross_fade(index) { is_animated = true; icon$.attr('class', 'icon').css({cursor: 'pointer'}); icon$.eq(index).attr('class', 'icon icon_selected').css({cursor: 'default', opacity: 0.4}).animate({opacity: 1.0}, 1300); var src = photolist$.eq(index).attr('src'); var alt = photolist$.eq(index).attr('alt'); var nextimg = '<img src="' + src + '" width="480" height="360" alt="' + alt + '">'; $('#mainphoto img').before(nextimg); $('#title').text(alt).hide().fadeIn(1000); $('#mainphoto img:last').fadeOut(1000, function(){ $(this).remove(); is_animated = false; }); } $(document).on('click', '#start', function() { showphoto(); $(this).css("display", "none"); return false; }); $(document).on('click', 'div.icon', function() { if($(this).hasClass('icon_selected') || is_animated) { return false; } var icon_index = icon$.index($(this)); window.clearTimeout(timer); cross_fade(icon_index); nextphoto = icon_index; $('#start').css("display", "block"); }); $(document).on('mouseover', 'div.icon', function() { if(!$(this).hasClass('icon_selected')) { $(this).addClass('icon_hover'); } }); $(document).on('mouseout', 'div.icon', function() { if(!$(this).hasClass('icon_selected')) { icon$.removeClass('icon_hover'); } }); $(window).unload(function(){ window.clearTimeout(timer); }); });
以下は、関数 cross_fade() の記述です。
変数 is_animated は、現在アニメーション中かどうかを判定するために使用します(アニメーション中に、アイコン画像をクリックされると問題があるため)。
関数 cross_fade() では、画像のインデックスを引数に取ります。
最初に、変数 is_animated を true に設定してアニメーション中であることにします。
4行目では、アイコン画像の CSS をリセットしています。
5行目では、インデックスに対応するアイコンの画像にクラス「icon_selected」を設定して表示を変更し、さらにアニメーションで透明度を変更しています。
後は、showphoto() のクロスフェードと同じ処理です。
但し、fadeOut() のコールバック関数の中で、変数 is_animated を false に変更しています。
var is_animated; function cross_fade(index) { is_animated = true; icon$.attr('class', 'icon').css({cursor: 'pointer'}); icon$.eq(index).attr('class', 'icon icon_selected').css({cursor: 'default', opacity: 0.4}).animate({opacity: 1.0}, 1300); var src = photolist$.eq(index).attr('src'); var alt = photolist$.eq(index).attr('alt'); var nextimg = '<img src="' + src + '" width="480" height="360" alt="' + alt + '">'; $('#mainphoto img').before(nextimg); $('#title').text(alt).hide().fadeIn(1000); $('#mainphoto img:last').fadeOut(1000, function(){ $(this).remove(); is_animated = false; }); }
以下は、丸いアイコンをクリックした際のイベント処理です。この要素は、スクリプトで追加しているので on() を使う必要があります。
2~4行目では、もしクリックされたアイコンのクラスが「icon_selected」である場合と、アニメーション中の場合は何もしないで終了します。
変数 icon_index にクリックされたアイコンのインデックスを格納します。
6行目で、スライドショーの繰り返し処理を停止しています。
続いて関数 cross_fade(icon_index) を実行して、クリックされたアイコンに対応する画像をクロスフェードで表示します。
変数 nextphoto に icon_index の値を代入します。
スライドショーは停止されているので、最後にスタートボタンを表示します。
$(document).on('click', 'div.icon', function() { if($(this).hasClass('icon_selected') || is_animated) { return false; } var icon_index = icon$.index($(this)); window.clearTimeout(timer); cross_fade(icon_index); nextphoto = icon_index; $('#start').css("display", "block"); });
以下は、スライドショーサンプルのリンクです。
スライダー
以下はスライダーのサンプルです。
以下は、スライダーの HTML です。
id が slider の div 要素に写真を表示します。
id が photo_list の ul 要素内の li 要素にスライダーで表示する画像要素を記述しておき、CSS で float: left を指定します。
id が slider_inner の div 要素は、配下の li 要素がフロートで横並びになっているので、画像が一列に並んだものが配置されています。この要素の幅は画像の枚数が変わっても良いように jQuery で指定します。
<div id="slider_wrap"> <div id="slider"> <div id="slider_inner"> <ul id="photo_list"> <li><img src="../images/001.jpg" alt="Beach"></li> <li><img src="../images/002.jpg" alt="Clear water"></li> <li><img src="../images/003.jpg" alt="Bay view"></li> <li><img src="../images/004.jpg" alt="Cloud in the sky"></li> <li><img src="../images/005.jpg" alt="Pool side"></li> <li><img src="../images/006.jpg" alt="Palm tree"></li> </ul> </div><!-- end of #slider_inner --> </div><!-- end of #slider --> </div><!-- end of #slider_wrap -->
以下が、CSS です。このスライドショーでは、480px X 360px の画像を使用しています。
#slider は画像を表示する領域です。画像の横幅は 480px ですが、左右に 5px ずつのマージンと、5px のボーダーがあるので幅は 500px に設定します。高さは 5px のボーダーがあるので 370px に設定します。
#slider には、overflow: hidden を指定して、領域をはみ出した部分は非表示にします。
#photo_list は ul 要素ですが、配下の li 要素をフロートで横並びにしているのと、画像の枚数が変わる可能性があるので横幅は指定しません。
ul, li { margin: 0; padding: 0; } #slider_wrap { margin: 20px auto; width: 500px; height: 370px; padding: 20px; } #slider { width: 500px; height: 370px; overflow: hidden; } #photo_list { /*幅は指定しない*/ height: 370px; list-style-type: none; } #photo_list li { float: left; margin: 0 5px; cursor: pointer; } #photo_list img { border: 5px solid #ccc; }
以下はスライダーのイメージです。
id が slider_inner の div 要素を、animate() で左マージン(marginLeft)の値を変更して、左側に移動させます。
左側に移動して、非表示になっている部分(#photo_list li:first)を appendTo() を使って、最後に移動させます。
animate() で変更した左マージン(marginLeft)の値を元の値(0px)に戻します。
以下が jQuery の記述です。
4行目は、li 要素の総数を変数 li_count に代入しています。これは表示する写真の数と同じです。
6行目では、li 要素1つの幅を求めています。li 要素の幅自体は width() で取得できますが、実際はマージンが設定してあるのでその分も幅に加えます。
parseInt() は文字列を数値に変換する JavaScript のメソッドです。css('margin-left') で取得できる値は "200px" のような文字列なので、計算に使用するために数値に変換する必要があります。
9行目では、id が slider_inner の div 要素の幅を設定しています。6行目で取得した li 要素の幅を使用して全体の幅を設定しています。
jQuery(function($){ var photo_list$ = $('#photo_list'); var li$ = $('#photo_list li'); var li_count = li$.length; //写真の数 //li 要素の幅 + その左右マージン var li_width = li$.width() + parseInt(li$.css('margin-left'), 10) + parseInt(li$.css('margin-right'), 10); var slider_inner$ = $('#slider_inner'); //slider_innerの幅を設定(li 要素の幅 * その個数) slider_inner$.css('width', (li_width * li_count) + 'px'); var timer; function slideshow() { slider_inner$.stop().animate({ marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - li_width + 'px' }, 800, 'easeInOutExpo', function(){ slider_inner$.css('margin-left', '0px'); $('#photo_list li:first').appendTo(photo_list$); }); timer = window.setTimeout(slideshow,2500); } var start_timer = window.setTimeout(slideshow,2500); });
12行目からはスライダー(スライドショー)の関数 slideshow() の設定です。
animate() で、marginLeft の値を li 要素の幅1つ分左に移動させます。また、表示に効果を与えるためイージング easing に「easeInOutExpo」を設定しています。
animate() のコールバック関数では、marginLeft の値を元に戻して、左側に移動した li 要素を #photo_list の一番最後に移動させています。
window.setTimeout(slideshow,2500) で繰り返し処理するように設定します。
以下は、ここまでの記述で表示されるスライダーのサンプルのリンクです。
コントロールの追加
続いて、再生ボタンやそれぞれの画像に対応する丸いアイコンを追加します。これらは、直接 HTML には記述せず、jQuery で追加します。(前述のサンプルと同じです)
以下は、再生ボタンや丸いアイコンの CSS です。
#icons_wrapper { position: relative; width: 480px; height: 80px; margin: auto; } #icons { width: 20px; margin: 0 auto; } .icon { display: inline-block; background-color: #FFF; width: 8px; height: 8px; margin:5px 5px -20px 10px; cursor: pointer; border: 1px solid #999; border-radius: 5px; } .icon.icon_selected { background-color: #666; cursor: default; } .icon.icon_hover { border: 1px solid #666; background-color: #CCC; } #start { display: none; cursor: pointer; color: #999; position: absolute; top: 5px; left: 350px; }
12行目は、次の画像のインデックスを変数「nextphoto」に代入しています(最初は 0 で初期化しておきます)。
13行目から25行目でコントロールを追加しています(クロスフェードのサンプルと同じ)。
28行目の変数「is_animated」はアニメーション中かどうかを判定するものです(アニメーション中に、アイコン画像をクリックされると問題があるため)。
30行目では、変数「is_animated」に true を設定して、アニメーション中であるとします。
31行目は、変数「nextphoto」の値を1増加しています。
32行目は、一旦全てのアイコン画像の CSS をデフォルトに設定しています。
33行目では、変数「nextphoto」の値に対応するアイコン画像の要素にクラス「icon_selected」を追加してアニメーションを設定しています。
34行目から41行目はスライダーのアニメーションの記述です。
46行目から50行目は、スタートボタンをクリックした際の記述で、slideshow() を呼び出してスライダーを開始させています。
52行目から86行目は、各画像に対応するアイコン画像をクリックした際の処理の記述です(詳細は別途記述)。
88行目から98行目は、アイコン画像にマウスオーバーした際の処理の記述です(クラスの追加及び削除でスタイルを変更)。
100行目から103行目は、ページを閉じた際に繰り返し処理を終了させる記述です。
jQuery(function($){ var photo_list$ = $('#photo_list'); var li$ = $('#photo_list li'); //写真の数 var li_count = li$.length; //li 要素の幅 + その左右マージン var li_width = li$.width() + parseInt(li$.css('margin-left'), 10) + parseInt(li$.css('margin-right'), 10); var slider_inner$ = $('#slider_inner'); //slider_innerの幅を設定(li 要素の幅 * その個数) slider_inner$.css('width', (li_width * li_count) + 'px'); var nextphoto = 0; var div_icons_wrapper$ = $('<div id="icons_wrapper"></div>'); var div_icons$ = $('<div id="icons"></div>'); div_icons_wrapper$.append(div_icons$); div_icons_wrapper$.append('<p id="start"><i class="fa fa-play-circle"></i></p>'); $('#slider_wrap').append(div_icons_wrapper$ ); for(var i = 0; i < li_count; i++){ var icon_alt = li$.eq(i).find("img").attr('alt'); div_icons$.append('<div class="icon" title="' + icon_alt + '">'); } var icon$ = $('div.icon'); var icon_count = icon$.length; div_icons$.width(25 * icon_count); icon$.eq(nextphoto).attr('class', 'icon icon_selected'); var timer; var is_animated; function slideshow() { is_animated = true; nextphoto = ( ++ nextphoto) % li_count; icon$.attr('class', 'icon').css({cursor: 'pointer'}); icon$.eq(nextphoto).attr('class', 'icon icon_selected').css({cursor: 'default', opacity: 0.4}).animate({opacity: 1.0}, 1300); slider_inner$.stop().animate({ marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - li_width + 'px' }, 800, 'easeInOutExpo', function(){ slider_inner$.css('margin-left', '0px'); $('#photo_list li:first').appendTo(photo_list$); is_animated = false; }); timer = window.setTimeout(slideshow,2500); } var start_timer = window.setTimeout(slideshow,2500); $(document).on('click', '#start', function() { slideshow(); $(this).css("display", "none"); }); $(document).on('click', 'div.icon', function() { if($(this).hasClass('icon_selected') || is_animated) { return false; } is_animated = true; var icon_index = icon$.index($(this)); window.clearTimeout(start_timer); window.clearTimeout(timer); icon$.attr('class', 'icon').css({cursor: 'pointer'}); icon$.eq(icon_index).attr('class', 'icon icon_selected').css({cursor: 'default', opacity: 0.4}).animate({opacity: 1.0}, 1300); var diff = icon_index - nextphoto; var is_diff_negative = diff < 0 ? true : false; diff = Math.abs(diff); if(is_diff_negative) { for(var i = 0; i < diff; i ++) { $('#photo_list li:last').prependTo(photo_list$); slider_inner$.css('margin-left', '-' + li_width * diff + 'px'); } } var dist = is_diff_negative ? li_width * diff * -1 : li_width * diff slider_inner$.stop().animate({ marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - dist + 'px' }, 800, 'easeInOutExpo', function(){ if(!is_diff_negative) { for(var i = 0; i < diff; i ++) { $('#photo_list li:first').appendTo(photo_list$); } } slider_inner$.css('margin-left', '0px'); is_animated = false; }); nextphoto = icon_index; $('#start').css("display", "block"); }); $(document).on('mouseover', 'div.icon', function() { if(!$(this).hasClass('icon_selected')) { $(this).addClass('icon_hover'); } }); $(document).on('mouseout', 'div.icon', function() { if(!$(this).hasClass('icon_selected')) { icon$.removeClass('icon_hover'); } }); $(window).unload(function(){ window.clearTimeout(start_timer); window.clearTimeout(timer); }); });
アイコン画像をクリックした際の処理
以下は、前述のスクリプトの52行目から86行目を抜粋したものです。
2行目から4行目は、クリックしたアイコンにクラス「icon_selected」が設定されているか、またはアニメーション中の場合(is_animated が true の場合)は何もせずに、終了する記述です。
5行目は、変数「is_animated」に true を設定して、アニメーション中であるとしています。
6行目は、index() を使ってクリックされたアイコン画像のインデックスを取得して変数「icon_index」に代入しています。
7行目、8行目は、clearTimeout() でスライダーの繰り返し処理を停止しています。
9行目、10行目は、アイコン画像のスタイルを初期化して、その後アニメーションでアイコン画像の透明度を変更しています。
11行目は、クリックされたアイコン画像のインデックスと、次に表示する画像のインデックスの差分を変数「diff」に代入しています。
12行目は、条件演算子(三項演算子)を使ってインデックスの差分「diff」の値が正の値か負の値かを判定して、負の場合は変数「is_diff_negative」に true を、正の場合は false を設定しています。
13行目は、「diff」の値の絶対値を取得しています(後の処理の計算で使用するため)。
14行目から19行目は、変数「is_diff_negative」の値が true (負の値)の場合の処理です。
変数「is_diff_negative」の値が true (負の値)の場合、スライドする方向が逆になるため、画像を移動させる必要があります。
20行目では、条件演算子(三項演算子)を使って移動(スライド)する距離(marginLeft)を算出して変数「dist」に代入しています。変数「is_diff_negative」の値が true (負の値)の場合は -1 をかけて、方向を逆転しています。
21行目から32行目はスライダーのアニメーションの記述です。
31行目では、アニメーションが終了しているので、変数「is_animated」に false を設定しています。
$(document).on('click', 'div.icon', function() { if($(this).hasClass('icon_selected') || is_animated) { return false; } is_animated = true; var icon_index = icon$.index($(this)); window.clearTimeout(start_timer); window.clearTimeout(timer); icon$.attr('class', 'icon').css({cursor: 'pointer'}); icon$.eq(icon_index).attr('class', 'icon icon_selected').css({cursor: 'default', opacity: 0.4}).animate({opacity: 1.0}, 1300); var diff = icon_index - nextphoto; var is_diff_negative = diff < 0 ? true : false; diff = Math.abs(diff); if(is_diff_negative) { for(var i = 0; i < diff; i ++) { $('#photo_list li:last').prependTo(photo_list$); } slider_inner$.css('margin-left', '-' + li_width * diff + 'px'); } var dist = is_diff_negative ? li_width * diff * -1 : li_width * diff slider_inner$.stop().animate({ marginLeft: parseInt(slider_inner$.css('margin-left'), 10) - dist + 'px' }, 800, 'easeInOutExpo', function(){ if(!is_diff_negative) { for(var i = 0; i < diff; i ++) { $('#photo_list li:first').appendTo(photo_list$); } } slider_inner$.css('margin-left', '0px'); is_animated = false; }); nextphoto = icon_index; $('#start').css("display", "block"); });
逆方向に画像を2つ分スライドさせるには、以下のようにまず画像を2つ移動させ、margin-left の値をその分設定して、その後2つ分の距離スライドさせます。(14行目~19行目)
通常の方向に画像を2つ分スライドさせるには、以下のように画像を2つ分の距離スライドさせて、その後2つの画像を移動させます。(25行目~30行目)
リンクの target 属性の制御
リンク(a 要素)の target 属性に「_blank」を指定すると、そのリンクをクリックすると新しいウィンドウまたはタブでリンク先のページを開きます。
この「ウィンドウを別に開くかどうかは、利用者が決めること」というのが一般的な見解のようです。
理由としては、別ウィンドウを開く機能は、ブラウザに備わっていますが、逆に、別ウィンドウを「開かないようにする」という機能はブラウザにはないためです。
個人的には、ブラウザの設定で「新しいウィンドウではなく新しいタブに開く」と言うオプションを選択して、参考情報などのリンクは新しいタブで開く(target="_blank" rel="noopener" を指定する)方法を好んでいます。
但し、その動作を煩わしいと思うユーザーもおられるのと、前述の通り、別ウィンドウを「開かないようにする」という機能はブラウザにはないので、そのようなオプションをページに追加する例です。(ページの右上にある「リンクを別タブで開かない」のチェックボックス。)
全てのページにこのオプションを記述するのは、面倒なので jQuery を使って以下のような要素を追加しています。
チェックボックスの input 要素を使ってチェックが入れられれば、別ウィンドウを開かないようにします。以下の例では、id 属性が container の要素の先頭に「prependTo()」を使って追加します。
$('<div id="link-control"><p><input type="checkbox" name="linkoption" id="linkoption"> <label for="linkoption">リンクを別タブで開かない</label></p></div>').prependTo("#container");
以下のような HTML が挿入されます。jQuery を使わずに以下を直接ページに記述しておいても同じです。
<div id="link-control"> <p><input type="checkbox" name="linkoption"> リンクを別タブで開かない</p> </div>
また、毎回ページを開くたびに、このオプションを選択するのは、面倒なので、Cookie を使ってユーザーの設定を保存するようにします。
以下は、Cookie を設定及び Cookie の値を取得する関数です。(詳細は Cookie を使う を参照ください)
function setCookie(name, value, expires, domain, path, secure) { var cookie = ''; cookie += name + '=' + encodeURIComponent(value); if(expires){ var exps = new Date(); exps.setDate(exps.getDate() + expires); cookie += '; expires=' + exps.toGMTString(); } if(domain) { cookie += '; domain' + domain;} if(path) { cookie += '; path=' + path; } if(secure) { cookie += '; secure'; } document.cookie = cookie; } function getCookie(name) { var cookies = document.cookie.split(';'); for(var i = 0; i < cookies.length; i ++) { var key_value = cookies[i].split('='); var key = $.trim(key_value[0]); var value = $.trim(key_value[1]); //console.log(key); if(key === name) { return decodeURIComponent(value); } } return null; } var link_option = getCookie("link_option"); //初回アクセス時の link_option の値は「null」
ユーザーによってチェックボックス($("[name='linkoption']"))がチェックされたり、チェックを外したりした際のイベント「change」を使って、Cookie を設定します。
以下の2行目は、チェックボックスがチェックされているかの判定で、チェックされている場合は、target 属性を削除し、「removed_target」というクラスを付加し、Cookie を設定します。
「removed_target」というクラスを付加するのは、チェックが外された際に、逆に target 属性を設定する際の目印にするためです。
チェックボックスがチェックされていない(または外された)場合は、「removed_target」というクラスの付けられた a 要素に target="_blank" rel="noopener" を設定し、「removed_target」というクラスを削除し、Cookie を設定します。
Cookie の設定では、以下を設定しています。
- クッキー名:link_option
- 値:No(リンクを別タブで開かない場合)または、Yes(リンクを別タブで開く場合)
- expires(クッキーの有効期限):7(7日間)
- domain:"" 省略(現在のドメイン)
- path(クッキーの有効範囲):/pr/ (/pr/配下のみ有効)
$("[name='linkoption']").on("change",function(){ if($("[name='linkoption']:checked").val()) { //:checkedはチェックが入っている要素 $("[target='_blank']").removeAttr("target").addClass("removed_target"); setCookie("link_option", "No", 7, "", "/pr/"); }else{ $(".removed_target").attr("target", "_blank").removeClass("removed_target"); setCookie("link_option", "Yes", 7, "", "/pr/"); } });
すでに、Cookie の値が No に設定されていれば(他のページから移動してきた場合など)、prop() を使って input 要素に checked 属性を設定します。
if(link_option ==="No") { $("[name='linkoption']").prop("checked", true); $("[target='_blank']").removeAttr("target").addClass("removed_target"); //No は新規タブで開かない setCookie("link_option", "No", 7, "", "/pr/"); }
全体としては、以下のようになります。
function setCookie(name, value, expires, domain, path, secure) { var cookie = ''; cookie += name + '=' + encodeURIComponent(value); if(expires){ var exps = new Date(); exps.setDate(exps.getDate() + expires); cookie += '; expires=' + exps.toGMTString(); } if(domain) { cookie += '; domain' + domain;} if(path) { cookie += '; path=' + path; } if(secure) { cookie += '; secure'; } document.cookie = cookie; } function getCookie(name) { var cookies = document.cookie.split(';'); for(var i = 0; i < cookies.length; i ++) { var key_value = cookies[i].split('='); var key = $.trim(key_value[0]); var value = $.trim(key_value[1]); //console.log(key); if(key === name) { return decodeURIComponent(value); } } return null; } var link_option = getCookie("link_option"); $('<div id="link-control"><p><input type="checkbox" name="linkoption" id="linkoption"> <label for="linkoption">リンクを別タブで開かない</label></p></div>').prependTo("#container"); if(link_option ==="No") { $("[name='linkoption']").prop("checked", true); $("[target='_blank']").removeAttr("target").addClass("removed_target"); //No は新規タブで開かない setCookie("link_option", "No", 7, "", "/pr/"); } //チェックボックスが操作された場合 $("[name='linkoption']").on("change",function(){ if($("[name='linkoption']:checked").val()) { $("[target='_blank']").removeAttr("target").addClass("removed_target"); setCookie("link_option", "No", 7, "", "/pr/"); }else{ $(".removed_target").attr("target", "_blank").removeClass("removed_target"); setCookie("link_option", "Yes", 7, "", "/pr/"); } });
ページ内のリンクにアイコンを表示
別ページへのリンクとページ内のリンクを区別するために、ページ内のリンクにアイコンを表示する例です。アイコンを表示するため Font Awesome を利用するので、読み込む必要があります。
ページ内のリンクの href 属性は「#」から始まっているので、CSS の ::after 擬似要素を使って以下のようにすればページ内のリンクに「(ページ内リンク)」という文字を追加することができます。
a[href^="#"]::after { content:"(ページ内リンク)"; color:#5988BF; }
但し、href 属性が「#」から始まっていてもアイコンを表示したくない場合など、柔軟にアイコンを表示するには jQuery を使うと簡単です。
以下が、基本的なコードです。
each() を使って href 属性が「#」から始まる全ての要素に対して処理を行います。
target は、リンク先の要素を格納する変数です。
この例の場合、ページ内のリンクでもページトップへのリンク(href = "#")は除外しています。
- 3行目:href 属性が「#」のみ(ページトップへのリンク)かどうかの判定です。
- 4行目:変数 target に、リンク先の要素を代入しています。(href 属性の値は、リンク先の要素の # から始まる id になります)
- 6行目:href 属性が「#」のみ(ページトップへのリンク)の場合は、変数 target に false を代入して、後ほどの処理で対象外にします。
- 8行目:リンク先の要素が false ではなく、かつ offset() の値が undefined でない場合に処理を継続します。
- 9行目:リンク先の要素の位置が、リンク要素より後の場合、アイコンフォント を追加します。
- 11行目:リンク先の要素の位置が、リンク要素より前の場合、アイコンフォント を追加します。
$("[href^='#']").each(function(){ var target; if($(this).attr("href") !== "#") { target = $($(this).attr("href")); }else{ target = false; } if(target && target.offset() !== undefined) { if(target.offset().top >= $(this).offset().top) { $(this).html($(this).html() + ' <i class="fa fa-chevron-circle-down"></i> '); }else{ $(this).html($(this).html() + ' <i class="fa fa-chevron-circle-up"></i> '); } } });
href 属性が「#」のみの要素以外を対象外とするには、not() を使って特定のクラスやIDが付与されているリンクを除外することができます。
以下は noicon というクラスのリンクを除外する場合の例です。
$("[href^='#']").not(".noicon").each(function(){ var target; if($(this).attr("href") !== "#") { target = $($(this).attr("href")); }else{ target = false; } if(target && target.offset() !== undefined) { if(target.offset().top >= $(this).offset().top) { $(this).html($(this).html() + ' <i class="fa fa-chevron-circle-down"></i> '); }else{ $(this).html($(this).html() + ' <i class="fa fa-chevron-circle-up"></i> '); } } });
また、特定のリンク先の文字列を含むリンクを対象外とする場合は、filter() を使うことができます。
以下は、正規表現の match() を使って h3_index や h4_index のような文字列を含むリンクを対象外とする例です。
match() は、マッチの結果を含む配列を返しますが、何も見つからなければ、null を返します。戻り値に論理否定演算子(!)を利用して真偽値に変換しています。以下の場合、マッチすれば false が、マッチしなければ true が返ります。
$("[href^='#']").not(".noicon").filter(function() { return !$(this).attr("href").match(/#h[23456]_index/); }).each(function(){ var target; if($(this).attr("href") !== "#") { target = $($(this).attr("href")); }else{ target = false; } if(target && target.offset() !== undefined) { if(target.offset().top >= $(this).offset().top) { $(this).html($(this).html() + ' <i class="fa fa-chevron-circle-down"></i> '); }else{ $(this).html($(this).html() + ' <i class="fa fa-chevron-circle-up"></i> '); } } });
ページの最終更新日を表示
JavaScript を使って Web ページの最終更新日時を取得するには、document.lastModified プロパティ(Document オブジェクトのプロパティ)を使います。
但し、有効な値を取得できるのは、静的な HTML の場合で、PHP などの動的なファイルの場合、取得できるのは現在時刻になってしまいます。
また、document.lastModified は HTTP レスポンスヘッダの「Last-Modified」の値になるため、サーバ側のレスポンスに依存します。「Last-Modified」がない場合は、現在の時刻が返されたりします。
例えば、以下のような HTML がある場合、次のような コードを記述すると、そのページの最終更新日が表示されます。
<p id="lm_date"></p>
$("#lm_date").text("最終更新:" + document.lastModified);
上記が表示結果ですが、document.lastModified で返されるのは、Date オブジェクトでなく文字列です。
日時の形式を変更するには、Date オブジェクトのコンストラクタとメソッドを使って以下のようにします。getMonth() で取得する値は 0~11 なので1を足します。
var modified = new Date(document.lastModified); var year = modified.getFullYear(); var month= modified.getMonth() + 1; var date = modified.getDate(); $("#lm_date2").text("最終更新日:" + year + "年" + month + "月" + date + "日");
例えば、全てのページで読み込む共通の JavaScript ファイルがあれば、そのファイルに以下を記述すれば、全てのページの content と言う id の要素の先頭に最終更新日を表示することができます。
var modified = new Date(document.lastModified); var year = modified.getFullYear(); var month= modified.getMonth() + 1; var date = modified.getDate(); $("#content").prepend("<p id='last_modified'>最終更新:" + year + "年" + month + "月" + date + "日</p>");
以下は、サイト内に PHP のファイルがあり、それらのファイルには更新日時を表示しないようにする場合の例です。
isPHP() は、現在のファイルの拡張子が php かどうかを判定する独自関数です。また、この例では更新日を表示する id 属性が「last_modified」の p 要素がすでに存在する場合は出力しないようにしています。
function isPHP() { var filename = window.location.href.match(".+/(.+?)([\?#;].*)?$")[1]; var file_extension = filename.split('.')[1]; if(file_extension === "php") { return true; } } var modified = new Date(document.lastModified); var year = modified.getFullYear(); var month= modified.getMonth() + 1; var date = modified.getDate(); if(!isPHP() && $("#last_modified").length === 0) { $("#content").after("<p id='last_modified'>最終更新:" + year + "年" + month + "月" + date + "日</p>"); }
現在のページのファイル名は、Location オブジェクトから取得することができます。
(関連項目:ファイル名の取得)
ファイルの拡張子は、split() メソッドを使ってファイル名から取得しています。
PHP を使った更新日の表示は「ディレクトリとファイルの操作/更新日 getlastmod()」を参照ください。
HTML特殊文字変換
「&」や「<」 「>」 「"」 「'」 の文字を JavaScript の正規表現を使って、それぞれ &, <, >, ", ' に変換する方法です。
以下は受け取った値の HTML 特殊文字を変換する関数の例です。
受け取った文字列を replace() メソッドを使って変換しています(5行目)。
第1パラメータの検索する文字列の正規表現には、RegExp() コンストラクタ関数を使用します(正規表現リテラルを使ってはうまく行きません)。
function escape_html(val) { var targets = ["&", "<", ">" ,'"', "'"]; var escapes = ["&", "<", ">", """, "'"]; for(var i=0; i<targets.length; i++){ val = val.replace(new RegExp(targets[i], 'g'), escapes[i]); } return val; }
[追記]上記はもっと簡単に記述することができます。
function escape_spacial_chars(str){ return str.replace(/&/g,"&") .replace(/"/g,""") .replace(/'/g,"'") .replace(/</g,"<") .replace(/>/g,">"); }
以下は上記の関数を使って入力された文字列の特殊文字を変換して出力する例です。
以下は HTML のマークアップです。Bootstrap のクラスを指定してスタイルを適用しています。
<div id="entity_convertor" style="max-width: 500px;"> <div> <input type="text" id="input" class="form-control" placeholder="変換するテキスト"> </div> <button id="convert" class="btn btn-primary btn-sm">変換</button> <button id="clear" class="btn btn-success btn-sm">クリア</button> <div> <pre id="escapeHTML"><span>変換結果</span></pre> </div> </div>
以下は jQuery の記述です。
jQuery(function($){ function escape_html(val) { var targets = ["&", "<", ">" ,'"', "'"]; var escapes = ["&", "<", ">", """, "'"]; for(var i=0; i<targets.length; i++){ val = val.replace(new RegExp(targets[i], 'g'), escapes[i]); } return val; } $('#convert').click(function() { var converted = escape_html($('#input').val()) ; $('#escapeHTML').text(converted).css('display', 'block'); }); $('#clear').click(function() { $('#input').val(''); $('#escapeHTML').html('<span>変換結果</span>'); }); });
[追記]以下の方が簡潔です(サニタイズする関数を書き換えたもの)。
jQuery(function($){ function escape_spacial_chars(str){ return str.replace(/&/g,"&") .replace(/"/g,""") .replace(/'/g,"'") .replace(/</g,"<") .replace(/>/g,">"); } $('#convert').click(function() { var converted = escape_spacial_chars($('#input').val()) ; $('#escapeHTML').text(converted).css('display', 'block'); }); $('#clear').click(function() { $('#input').val(''); $('#escapeHTML').html('<span>変換結果</span>'); }); });
変換結果
関連ページ:HTML特殊文字変換ツールの作成方法