関数の引数をオブジェクト形式にする実装を試してみます。
対応前
まずは通常の引数の例です。
ボタンをクリックすると、対になる要素にクラスを付け外しするという処理を実装します。
<button data-toggle-switch="target01">ボタン1</button> <div class="contents" data-toggle-target="target01">コンテンツ1</div> <button data-toggle-switch="target02">ボタン2</button> <div class="contents" data-toggle-target="target02">コンテンツ2</div>
.contentsに.is-openというクラスが付くと表示されるようにします。
.contents {
display: none;
}
.contents.is-open {
display: block;
}
JavaScriptでtoggleの関数を作成します。
toggleOnClick();
/**
* 要素をクリック時に、別の要素のclassをtoggle
* @param {string} triggerDataAttr クリック対象要素のdata属性
* @param {string} targetDataAttr classをtoggleする対象要素のdata属性
* @param {string} className toggleするclass名
*/
function toggleOnClick(
triggerDataAttr = 'toggle-switch',
targetDataAttr = 'toggle-target',
className = 'is-open'
) {
document.querySelectorAll(`[data-${triggerDataAttr}]`).forEach(trigger => {
const targetVal = trigger.getAttribute(`data-${triggerDataAttr}`);
trigger.addEventListener('click', () => {
document.querySelector(`[data-${targetDataAttr} = ${targetVal}]`).classList.toggle(className);
});
});
}
これで想定した動作の処理ができました。
通常の引数の場合のデモページ
この実装の問題点として、例えば第三引数のclass名だけ変更したい場合の直接的な方法がないという点です。
例えばデフォルトのis-openの代わりに、is-show-redを使いたいとします。
.contents.is-show-red {
display: block;
color: red;
}
第三引数のみの指定ができないため、第一引数と第二引数にもデフォルト値と同じ値を指定する必要があります。
toggleOnClick('toggle-switch', 'toggle-target', 'is-show-red');
もしくは、undefinedを渡すことでデフォルト値を使用することができます。
toggleOnClick(undefined, undefined, 'is-show-red');
デフォルト値を渡すよりはよさそうですが、ぱっと見て意味が分かりにくいかもしれません。
第一引数と第二引数にundefinedを渡すデモページ
対応方法
こうした問題点を解消するため、タイトルにもある通りオブジェクト形式での実装に変更してみます。
toggleOnClick();
/**
* 要素をクリック時に、別の要素のclassをtoggle
* @param {object} [options] オプション設定
* @param {string} [options.triggerDataAttr] クリック対象要素のdata属性
* @param {string} [options.targetDataAttr] classをtoggleする対象要素のdata属性
* @param {string} [options.className] toggleするclass名
*/
function toggleOnClick({
triggerDataAttr,
targetDataAttr,
className
} = {}) {
if (typeof triggerDataAttr === 'undefined') triggerDataAttr = 'toggle-switch';
if (typeof targetDataAttr === 'undefined') targetDataAttr = 'toggle-target';
if (typeof className === 'undefined') className = 'is-open';
document.querySelectorAll(`[data-${triggerDataAttr}]`).forEach(trigger => {
const targetVal = trigger.getAttribute(`data-${triggerDataAttr}`);
trigger.addEventListener('click', () => {
document.querySelector(`[data-${targetDataAttr} = ${targetVal}]`).classList.toggle(className);
});
});
}
これで引数をオブジェクト形式の1つのみにしつつ、先ほどと同様の処理にできました。
オブジェクト形式に変更するデモページ
ポイントは2つです。
1つ目は引数のオブジェクトで分割代入を使用している点で、関数の引数にオブジェクトを受け取り、そのプロパティをそのまま変数として使用しています。
2つ目は14行目にある引数の末尾の「= {}」で、関数を呼び出した際に引数が渡されなかったときのために、空のオブジェクトをデフォルト値として指定しています。
この方法にすることで、最初に試したようなclassNameのみ変更したい場合でも指定できます。
toggleOnClick({
className: 'is-show-red'
});
最後に、上記例だと関数内でデフォルト値の設定をするようになっているので、最初の例と同様に引数の設定内でデフォルト値を設定してみます。
toggleOnClick();
/**
* 要素をクリック時に、別の要素のclassをtoggle
* @param {object} [options] オプション設定
* @param {string} [options.triggerDataAttr='toggle-switch'] クリック対象要素のdata属性
* @param {string} [options.targetDataAttr='toggle-target'] classをtoggleする対象要素のdata属性
* @param {string} [options.className='is-open'] toggleするclass名
*/
function toggleOnClick({
triggerDataAttr = 'toggle-switch',
targetDataAttr = 'toggle-target',
className = 'is-open'
} = {}) {
document.querySelectorAll(`[data-${triggerDataAttr}]`).forEach(trigger => {
const targetVal = trigger.getAttribute(`data-${triggerDataAttr}`);
trigger.addEventListener('click', () => {
document.querySelector(`[data-${targetDataAttr} = ${targetVal}]`).classList.toggle(className);
});
});
}
呼び出し方は先ほどと同様に使えます。
toggleOnClick({
className: 'is-show-red'
});
コメントが承認されるまで時間がかかります。