基礎的なものからちょっとした機能の実装方法など、jQueryに関する個人的なメモ・スニペットリストの第10弾です。
動きをすぐ確認できるデモなどは基本的に用意していないので、実際の動きを確認したい場合などは自身で簡単な環境を作成して試してもらうか「CodePen」や「JSFiddle」などを利用して確認してください。
ul要素内のli要素を分割する
ul
要素内にあるli
要素を指定した数に分割するという動きを実装するもので、何分割するかはul
要素に記述してあるdata-cols
というdata
属性で指定します。
下記サンプルコードのHTMLをそのまま使用した場合は「li
要素を3つのul
要素に分割させる」という動きになり、1〜4がひとつ目、5〜7がふたつ目、8〜10がみっつ目として分割されて、それぞれが異なるul
要素で括られます。
また、jQueryの一番下ではもともとあったul.split-list
をdiv.split-list
に変換させており、これによりul
要素直下にul
要素がきてしまうのを回避しています。
<ul class="split-list" data-cols="3">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>
$('.split-list').each(function() {
var splitCols = $(this).data('cols'),
itemPerCol = [],
$item = $(this).find('li'),
minItemsPerCol = Math.floor( $item.length / splitCols ),
diff = $item.length - (minItemsPerCol * splitCols);
for ( var i = 0; i < splitCols; i++ ) {
if ( i < diff ) {
itemPerCol[i] = minItemsPerCol + 1;
} else {
itemPerCol[i] = minItemsPerCol;
}
$(this).append('<ul class="child-list"></ul>');
for ( var j = 0; j < itemPerCol[i]; j++ ) {
var pointer = 0;
for ( var k = 0; k < i; k++ ) {
pointer += itemPerCol[k];
}
$(this).find('.child-list').last().append($item[j + pointer]);
}
}
$(this).replaceWith('<div class="split-list">' + $(this).html() + '</div>');
});
今回のサンプルではul
を利用していますが、少し記述を変更すればol
をはじめ他の要素でも使用可能です。
data属性を利用したシンプルなフィルタ機能
「4. classを利用したシンプルなフィルタ機能 - jQuery Snippets #5」で紹介した動きをdata
属性を用いて実装したもので、HTMLとjQueryをそれぞれ下記のように記述します。
<div class="filter-nav">
<button data-type="all">all</button>
<button data-type="foo">foo</button>
<button data-type="bar">bar</button>
<button data-type="baz">baz</button>
</div>
<div class="filter-item">
<div data-type="foo">foo</div>
<div data-type="bar">bar</div>
<div data-type="baz">baz</div>
<div data-type="foo">foo</div>
<div data-type="bar">bar</div>
<div data-type="baz">baz</div>
<div data-type="bar">bar</div>
<div data-type="baz">baz</div>
<div data-type="foo">foo</div>
<div data-type="foo">foo</div>
<div data-type="bar">bar</div>
<div data-type="foo">foo</div>
</div>
$('.filter-nav button').on('click', function() {
var type = $(this).data('type');
if ( type == 'all' ) {
$('.filter-item > div').show();
} else {
$('.filter-item > div').hide().filter('[data-type="' + type + '"]').show();
}
});
1度だけ実行させる
例えば.on()
を利用したイベントが用意されていたとして、特定のタイミングでそれを実行されないようにしたいというときは.off()
を利用することで実装できますが、1度だけ実行できる(1回実行されたらその後は実行されたくない)ようにということであれば、下記のように.one()
を用いる形で実装できます。
$('button').one('click', function() {
console.log('hello world');
});
本来の画像サイズを取得
要素のサイズを取得したいときによく利用するのが.width()
や.height()
ですが、これらを利用して画像サイズを取得しようとした場合は現在表示されているサイズの値が取得されるので、例えばその画像がCSSなどで拡大・縮小などされている場合はその値が取得されます。
そうではなく、何らかの理由で本来の画像サイズを取得したいというときは下記の方法で取得できます。
var nativeImage = new Image();
nativeImage.src = $('img').attr('src');
var imageNativeWidth = nativeImage.width,
imageNativeHeight = nativeImage.height;
console.log('native width:' + imageNativeWidth + ', native height:' + imageNativeHeight);
特定の要素が何番目かを取得する
何らかのタイミングで要素が何番目かを取得したいときに使える方法です。
下記はクリックしたli
要素が何番目かを取得するというもので、且つ単純に取得した場合は0から始まるのをわかりやすくするために取得した値に1をプラスしています。
$('ul li').on('click', function() {
var index = $(this).index() + 1;
console.log(index);
});
特定の文字列を置換する
指定した要素内にある特定の文字列を.replace()
を使って任意の文字列に置換する方法で、赤文字で表示しているbeforeの部分に記述した文字列が、同じく赤文字で表示しているafterの部分に記述した文字列に置換されます。
また、afterの部分を空にすれば特定の文字列を削除するという動きにもできます。
$('selector').each(function() {
$(this).html($(this).html().replace(/before/g, 'after'));
});
URL文字列にリンクを設定する
.replace()
を使った応用として、下記のように記述することで指定した要素内にURL文字列があった場合にリンクを設定させることができ、このサンプルコードの場合はtarget="_blank"
付きのリンクが設定されます。
$('selector').each(function() {
$(this).html($(this).html().replace(/((http|https|ftp):\/\/[\w?=&.\/-;#~%-]+(?![\w\s?&.\/;#~%"=-]*>))/g, '<a href="$1" target="_blank">$1</a>'));
});
フラグ判定
例えば、ボタン押下で処理を行う場合にボタンはひとつでも条件によって処理を変えたいときなど、やり方はいろいろあるとは思いますが、そういったときに使えるフラグ判定方法を3パターン紹介します。
ここで紹介しているのは、いずれも先ほど例にあげたようにボタン押下時とフラグ判定を組み合わせたものになります。
フラグ判定(true/false)
あらかじめ用意したフラグがtrue
かfalse
を判断して処理をわけるというものなり、このサンプルコードの場合は、1行目にあるflagがフラグ判定に使用する変数で、初期値はtrue
と設定しています。
あとは、ボタンが押下された際に条件分岐を使用してフラグがtrue
かfalse
かでそれぞれ別の処理を書くことで、同じボタンをクリックした場合でも条件によって異なる処理が実行されるようになります。
また、今回はボタン押下の度に異なる処理を行う必要があるので、条件分岐内のflag = false;
やflag = true;
といった部分でボタンが押下される度に現在のフラグを書き換えるようにしておきます。
var flag = true;
$('button').on('click', function() {
if ( flag ) {
console.log('flag true');
flag = false;
} else {
console.log('flag false');
flag = true;
}
});
フラグ判定(要素の表示・非表示)
こちらは特定の要素が表示されているかどうかで判断して処理をわけるというものなり、このサンプルコードの場合は、特定の要素として用意した$flagElements
が表示されている(display: block;
)ならtrue
、逆に非表示(display: none;
)であればfalse
となります。
var $flagElements = $('selector');
$('button').on('click', function() {
if ( $flagElements.css('display') == 'block' ) {
console.log('flag true');
$flagElements.hide();
} else {
console.log('flag false');
$flagElements.show();
}
});
フラグ判定(classの有無)
こちらは.hasClass()
を使って特定の要素に特定のclassが付いているかで判断して処理をわけるというものなります。
このサンプルコードの場合は、特定の要素をbutton
要素で特定のclassが.is-true
とし、button
要素に.is-true
が付与されていればtrue
、付与されていなければfalse
となります。
var flagClass = 'is-true';
$('button').on('click', function() {
if ( $(this).hasClass(flagClass) ) {
console.log('flag true');
$(this).removeClass(flagClass);
} else {
console.log('flag false');
$(this).addClass(flagClass);
}
});
現在地によってページ内ナビゲーションにclassを追加・削除する
特に長いページなどで各セクションへ容易に移動できるようなナビゲーションを設置することがありますが、そのようなナビゲーションに現在どのセクションにいるかをわかりやすく装飾を付ける動きを実装する方法です。
具体的には現在地によって特定のナビゲーションにclassの追加・削除を行い、そのclassに対してCSSを指定しておくことで、例えば現在見ている部分に対応しているナビゲーションのみカラーが変わるなどの動きを実装できます。
<nav>
<ul>
<li><a href="#section01">section 01</a></li>
<li><a href="#section02">section 02</a></li>
<li><a href="#section03">section 03</a></li>
<li><a href="#section04">section 04</a></li>
<li><a href="#section05">section 05</a></li>
</ul>
</nav>
<section id="section01"> ... </section>
<section id="section02"> ... </section>
<section id="section03"> ... </section>
<section id="section04"> ... </section>
<section id="section05"> ... </section>
$(function() {
var $win = $(window),
sectionArr = [],
$section = $('section'),
$nav = $('nav ul li'),
currentClass = 'is-current';
$section.each(function(i) {
var sectionTop = $(this).offset().top,
sectionBottom = $(this).offset().top + $(this).outerHeight() - 1;
sectionArr[i] = [sectionTop, sectionBottom];
});
function currentPosition() {
var value = $win.scrollTop(),
adjustOffset = 0;
for ( var i = 0; i < sectionArr.length; i++ ) {
if ( sectionArr[i][0] - adjustOffset <= value && sectionArr[i][1] - adjustOffset >= value ) {
$nav.removeClass(currentClass);
$nav.eq(i).addClass(currentClass);
break;
}
};
}
$win.on('load scroll', function() {
currentPosition();
});
});
このサンプルコードの場合は、現在表示されているナビゲーション(li
要素)に.is-current
というclassが付与される動きになっているので、それを利用してスタイルを指定することで現在表示されているのがどこなのかわかりやすくすることができます。
また、classが付与されるタイミングはadjustOffset
という変数部分に任意で数値を指定することで調整でき、例えばadjustOffset = 200;
と指定すれば各セクションのトップから200px
分早くclassの追加・削除される動きになります。
要素をアルファベット順でソートする
<ul>
<li>a</li>
<li>x</li>
<li>c</li>
<li>b</li>
<li>y</li>
<li>z</li>
</ul>
例えば下記のようなHTMLがあったとき、単純にHTMLを表示した場合は上から順に「a → x → c → b → y → z」と表示されますが、これを要素内のテキストを判別・ソートして「a → b → c → x → y → z」のようにアルファベット順にして出力させる方法です。
$('ul li').sort(function(a, b) {
return $(a).text() > $(b).text();
}).appendTo('ul');
上記は昇順指定となるので、降順指定にしたい場合はreturn $(a).text() < $(b).text();
とします。
また、大文字小文字関係なくソートする場合は下記のように.toLowerCase()
を組み合わせます。
$('ul li').sort(function(a, b) {
return $(a).text().toLowerCase() > $(b).text().toLowerCase();
}).appendTo('ul');
こちらも同じく上記は昇順指定となるので、降順指定にしたい場合はreturn $(a).text().toLowerCase() < $(b).text().toLowerCase();
とします。
要素の数字でソートする
こちらは数字の大きさでソートするもので、下記サンプルコードの場合は「0 → 1 → 2 → 5 → 10 → 100」と出力されます。
<ol>
<li>100</li>
<li>10</li>
<li>2</li>
<li>0</li>
<li>1</li>
<li>5</li>
</ol>
$('ol li').sort(function(a, b) {
return $(a).text() - $(b).text();
}).appendTo('ol');
上記は昇順指定となるので、降順指定にしたい場合はreturn $(b).text() - $(a).text();
とします。
その他のjQuery Snippetsに関しては下記ページから確認できます。