【jQuery】チェックボックスで画像を切り替える

「規約を読んで同意」的なチェックボックスにチェックをすると画像が切り替わるようにしてみます。

今回はシチュエーションとして、aタグで囲まれた画像(ボタン)が、チェックマークにチェックを付ける前は押せない状態になっていて、チェックを付けた時のみ押せるようになる…的な効果を実装してみます。

ここで使うボタン用のリンク付き画像ファイル名は以下のようにしてください。
【クリックできる状態のボタン画像】~~~~.jpg(拡張子は任意)
【クリック出来ない状態のボタン画像】~~~_off.jpg(拡張子は任意)
2種類とも拡張子は自由ですが、必ず揃えてくださいね~

では、コードを書きます。

チェックボックスで画像を切り替えるサンプル

HTML

			  			

  • ボタン1
  • ボタン2
  • ボタン3

ボタンだけのサンプル

単純に、チェックボックスとリストタグの中に画像があるだけです。

あとでサンプルを添付するので、CSSは省略します。
JSを見てみましょう。事前にjQeuryは読むようにしてくださいね。
https://code.jquery.com/jquery-1.8.3.min.js

JS

$(function(){//チェックボックス    	var chk = $('.checkbox');    	chk.prop("checked" , false); //初期状態で絶対にチェックを外しておく    	$('.s-enter').find('img').each(function(){    		var $this = $(this);  		var src = $this.attr('src'); //デフォルトの画像  		var url = $this.parent('a').attr('href'); //リンク保存  		var blank = $this.parent('a').attr('target');  		var offSrc = src.replace(/(\.)([a-zA-z].+)$/ , '_off$1$2'); //$1ヒットした文字(.) $2は拡張子    		checkAction($this); //一回処理してクリックできなくしておく。    		function checkAction(obj){ //チェックした時の動作をさせる関数	  			if(chk.prop('checked')){  				obj.wrap('').attr("src" , src).parent()  				.attr("href",url).attr("target" , blank);  				  			}else{  				obj.attr("src" , offSrc).unwrap();  			}  		}    		chk.change(function(){ //イベント連動  				checkAction($this);  		})  	});    });

チェックマークでボタンが切り替わるサンプル

さいしょに

最初に変数chkでイベントを発生させるチェックマークを取得します。

chk.prop(“checked” , false )で事前にチェックを全て外しますが、ここは.attr(“checked” , false)とかでもいいと思います。

続いて、リンクの貼ってある画像の分だけ処理したいのでeach()を使います。
.s-enterはチェックマークも含む、ボタン部分を包む要素ですが、imgだけをfindしましょう!
.find() | jQuery 1.9 日本語リファレンス | js STUDIO

each()の中で、imgやその親のaタグに設定されている必要そうな要素をバンバン変数にぶち込んで保存しておきます。
each()で処理することで、該当する要素の各々のデータが取得できます。

ちなみにリンクを保存する理由としては、このあと「チェックマークにチェックしてない状態ではクリック出来ない」という状況をつくるために、aタグを消してしまうからです。(消すという表現は正しくないんですが)

aタグの情報を保存するためには、imgを基準とした処理なので.parent()を使って、直接の親要素に一時的に処理を移します。
親要素の取得にはいくつか種類があるので、軽く知りたい方はコチラ!

url(a href=”ここ”)とblank(target=”ここ”)を格納したところで、入れ替え用の画像のパスを指定します。

切り替え用の画像のパスを探す

ただ指定するだけではナンセンスなので、each()処理の中で自然な形で、それぞれのパスを入れ替えます。

ここで注意です。
画像ファイル名は以下のようにしてください。
【クリックできる状態のボタン画像】~~~~.jpg(拡張子は任意)
【クリック出来ない状態のボタン画像】~~~_off.jpg(拡張子は任意)
2種類とも拡張子は自由ですが、必ず揃えてくださいね~

では、本題に戻り、画像のパスを入れ替えます。
それぞれのimgタグのsrcに、「_off」を忍ばせます。.replace()と正規表現を使います。

var offSrc = src.replace(/(\.)([a-zA-z].+)$/ , '_off$1$2'); //$1ヒットした文字(.) $2は拡張子

eachで処理が回ってきたimgのsrcから、(\.)([a-zA-z].+)という条件に合致する部分を探します。

これは何かというと、「ドットで始まってaからzまでの大文字小文字が数個自由に続いて終わる部分」という意味です。
そのあとに続いている_off$1$2の部分で_offを付加しています。
どうしても_offが嫌だという方はここを変えてください。
正規表現の基礎は以下のサイトが解りやすいです。

これで変数offSrcが、「クリック出来ない状態のボタン画像」のパスとなりました。

チェックマークでon/off判断をする関数を作って処理を円滑にする

チェックマークにチェックした時に

  • 画像のパスを入れ替える
  • aリンクを消したり元にもどしたりする(元のa href=””は変数hrefに保存済み)

処理をする、関数をつくります。こうすることで同じ命令をすることが減り、少しだけ処理が軽くなります。

		function checkAction(obj){ //チェックした時の動作をさせる関数	  			if(chk.prop('checked')){  				obj.wrap('').attr("src" , src).parent()  				.attr("href",url).attr("target" , blank);  				  			}else{  				obj.attr("src" , offSrc).unwrap();  			}  		}

checkAction関数というのを造ります。引数には、$thisで、処理中のimgを渡す想定です。

最初のifで、チェックマークにチェックがあるかどうかを判断しています。

チェックがあった場合はクリックが可能になり、更にそれが視覚的に判るために画像を切り替えます。

obj.wrap('').attr("src" , src).parent()  .attr("href",url).attr("target" , blank);

まずリンクを付けるために、.wrap()を使い引数で渡ってきたオブジェクト(処理中のimg)をaで包みます。
そのオブジェクトのsrc属性に変数srcを指定。これは、もともとの(クリック可な状態の)画像のパスです。

続けて、オブジェクトのhref属性を変数urlに。これで、チェックマークをつけた場合に、もともと指定してあったリンクが再度同じ場所に挿入されます。

そのあとに同様にattr()を使い、target属性でウィンドウの開き方も再現します。

逆に、チェックマークがついていないときはelse{}処理となります。

obj.attr("src" , offSrc).unwrap();

先ほどの正規表現で_offに入れ替えたそれぞれのパスをオブジェクトのsrc属性に指定します。
これで画像が切り替わりました。

さらに、.unwrap()関数を使っています。
これは対象のオブジェクトの親要素のみを消去する、アンラップするものです。ここだと、a要素が無くなることになります。

つまり、クリックしてもURLにジャンプしないことになります。

これでクリック時の処理は完成です。

初期状態を作っておく

今回の目的は「チェックマークが付いていない状態だとボタンがクリック出来ない=アクションが取れない」というものでした。

このままだと最初ページを見た時にリンクが付与されたままですので、一度、先ほどのcheckAction関数を実行しておきます。

これで、ページを開いた時から「チェックマークにチェックが付いていないので、ボタンがクリック出来ない」状態にすることが出来ます!

チェックマークでボタンが切り替わるサンプル

しかし問題があります。

たとえばこのボタンのセクションが2つあった場合、エライことになるのです…

ボタンが2セットあった場合のエラーのデモ

2番めのセクションのチェックマークをクリックすると、レイアウトがバッキバキに崩れます。

これはチェックがついたチェックマークと、そうでないチェックマークのエリアが違う動作をしているからです。
aタグとその要素をうまく取得できてないんですね。

というわけで、こうします。

$(function(){//チェックボックス    	$('.s-enter').find('img').each(function(){    		var $this = $(this);  		var src = $this.attr('src'); //デフォルトの画像  		var url = $this.parent('a').attr('href'); //リンク保存  		var blank = $this.parent('a').attr('target');  		var offSrc = src.replace(/(\.)([a-zA-z].+)$/ , '_off$1$2'); //$1ヒットした文字(.) $2は拡張子  		var chk = $this.closest('.s-enter').find('.checkbox'); //closestで親要素を遡る    		checkAction($this); //一回処理してクリックできなくしておく。    		function checkAction(obj){ //チェックした時の動作をさせる関数	  			if(chk.prop('checked')){  				obj.wrap('').attr("src" , src).parent()  				.attr("href",url).attr("target" , blank);  				  			}else{  				obj.attr("src" , offSrc).unwrap();  			}  		}      		chk.change(function(){ //イベント連動  				checkAction($this);  		});  		  	});    });

チェックマークの取得の仕方を変えています。

var chk = $this.closest('.s-enter').find('.checkbox'); //closestで親要素を遡る

each()で処理中のimgと同じセクションにあるチェックボックスを基準としています。
なので、チェックマークがついたからといって見た目だけ連動してしまうのではなく、それぞれが独立して処理されるようになるのです。

チェックマークがついたセクションのボタンのみ切り替わる、マルチなデモ

長くなりましたが、以上です。
販売用ページなんかに良いんじゃないですかね?クーリングオフできませんよ、みたいなことを事前に承諾させておいて…

 

デモのダウンロードはこちら

 

でわ!

投稿者 satohmsys