初めに
Shopifyのサイトを構築していて、Javascriptの条件分岐を記述していたのですが、思ったように動作してくれずに2時間ロスしました...
前提と実装したいことは以下の通りです。
- 商品メタフィールドにアイコンのテキスト(複数リスト)を登録(test1、test2、test3)して、各商品に0~3個のアイコンテキストを設定(ネームスペースとキー:custom.icon)
- 商品にアイコンが設定されていたら、そのアイコンに紐付くアイコン画像を表示
- アイコンに説明があれば、アイコン画像をクリックした時に説明文を表示(test-text1〜3)
- クリックするとis-activeクラスを追加・削除を行い、is-activeクラスに対してdisplay:none;を設定
問題
問題のコードは以下の記述です
<div class="product-icon">
<ul class="product-icon__list">
{% for icon in product.metafields.custom.icon.value %}
{% if icon == "test1" %}
<li class="product-icon__item">
<img src="https://test1-image" alt="アイコン画像1">
<div class="product-icon__container">
<p class="product-icon__text">test1-text</p>
</div>
</li>
{% endif %}
{% if icon == "test2" %}
<li class="product-icon__item">
<img src="https://test2-image" alt="アイコン画像2">
<div class="product-icon__container">
<p class="product-icon__text">test2-text</p>
</div>
</li>
{% endif %}
{% if icon == "test3" %}
<li class="product-icon__item">
<img src="https://test3-image" alt="アイコン画像3">
<div class="product-icon__container">
<p class="product-icon__text">test3-text</p>
</div>
</li>
{% endif %}
{% endfor %}
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
//for文で取得したすべてのliタグを取得
const items = document.querySelectorAll(".product-icon__item");
//それぞれのliタグに対してクリックイベントをつける
items.forEach((item) => {
item.addEventListener("click" , () => {
//アイコンの説明文を格納するpタグを取得
const text = document.querySelectorAll(".product-icon__text");
//アイコンの説明文があれば、アイコン画像をクリックして説明文を表示させるように設定
if(text.innerText !== ""){
//説明文を格納するdivタグを取得
const textBox = item.querySelector(".product-icon__container");
//is-activeクラスがあればクラスを削除、なければ追加の設定
textBox.classList.toggle("is-active");
//他のアイコン画像をクリックしたときに、現在のアイコンの説明文が表示されたままだったら、そのクラス(is-active)を削除してクリックしたアイコンの説明文を表示
items.forEach((otherItem) => {
if (otherItem !== item) {
const otherTextBox = otherItem.querySelector(".product-icon__container");
//クリックしたアイコン以外のアイコンが、説明文が表示されたままだったらクラス名(is-active)を削除して説明文を非表示にする
otherTextBox.classList.remove("is-active");
}
});
}
});
});
})
</script>
こちらのコードはアイコンの説明文(<p class="product-icon__text">test1-text</p>
の部分)がなければクラスを付与する関数を実行しない、という意図で記述していましたが、説明文の有無に関わらず、is-activeクラスが付与されました。
解決策
今回の問題点はconst text = document.querySelectorAll(".product-icon__text");
この部分でした。
クリックしたアイコンの、説明文を格納するpタグを取得する、という意図で変数宣言していましたが、document.querySelectorAll(".product-icon__text")
と記述したために、すべてのproduct-icon__textクラスを持つ要素を取得していました。
つまりクリックした要素ではなく、取得したすべての要素の中の一番最初の要素に対して、その後に続く条件分岐を設定していました。
正しい記述としてはconst text = document.querySelectorAll(".product-icon__text");
ではなくconst text = item.querySelector(".product-icon__text");
としなければいけませんでした。
終わりに
javascriptの記述量としてはそんなに多くはありませんが、この量でも間違いを見つけるのにはかなり時間がかかりました。
html、cssの記述は間違っていたら、割とすぐに見つけられるのでパパッと書いてしまうことが多いのですが、javascriptに関してはミスの内容に丁寧に書いていこうと思いました。