質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

解決済

動的に追加した要素のsrc, srcsetをjsで設定できない

erp
erp

総合スコア45

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

2回答

0評価

0クリップ

595閲覧

投稿2021/10/15 02:57

編集2021/10/20 09:10

前提・実現したいこと

動的に追加した要素について、画像の遅延読み込みを loading="lazy" に対応しているブラウザでは、lazysizes を読み込まず、data-src の値を src にセットしたいです。
また、インクルードするパーツは別のhtmlファイルにまとめているものを用いています。

発生している問題・エラーメッセージ

エラーは特にないです。

該当のソースコード

// インクルード

js

if (document.getElementsByClassName("nav") != null) { window.addEventListener('DOMContentLoaded', function () { fetch('/assets/include/nav.html') .then(response => response.text()) .then(data => { const parser = new DOMParser(); const html = parser.parseFromString(data, "text/html"); const p_elements = html.getElementsByClassName('nav')[0]; const file_area = document.getElementsByClassName("nav")[0]; file_area.innerHTML = p_elements.innerHTML; }); }); }

// lazyload の読み込み

js

document.addEventListener('DOMContentLoaded', function () { if ("loading" in HTMLImageElement.prototype) { var images = document.querySelectorAll('img[loading="lazy"]'); var sources = document.querySelectorAll("source[data-srcset]"); sources.forEach(function (source) { source.srcset = source.dataset.srcset; // ここが効かない }); images.forEach(function (img) { img.src = img.dataset.src; // ここが効かない }); } else { var script = document.createElement("script"); script.src = "https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.3.2/lazysizes.min.js"; script.async = true; document.body.appendChild(script); var script_02 = document.createElement("script"); script_02.src = "https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.3.2/plugins/object-fit/ls.object-fit.min.jss"; script_02.async = true; document.body.appendChild(script_02); } })

// インクルードするパーツ

HTML

<div class="nav"> <picture> <source type="image/webp" data-srcset="/images/7.png.webp"> <img class="lazyload" loading="lazy" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="/images/7.png"> </picture> </div>

試したこと

js

document.addEventListener('DOMContentLoaded', function () {

で囲んでもダメだったのでどうすればいいでしょうか。

コールバックを使ってみてもダメでした。

js

function fetchApi(func) { // インクルードjs func(); }; var lazyload = function () { // lazyload 読み込み }; fetchApi(lazyload);

追記

js

document.addEventListener('DOMContentLoaded', () => { function lazyload(node) { if ("loading" in HTMLImageElement.prototype) { let images = node.querySelectorAll('img[loading="lazy"]'); let sources = node.querySelectorAll("source[data-srcset]"); // 省略 } else { let script = document.createElement("script"); // 省略 } } lazyload(document); if (document.getElementsByClassName("nav")[0] != null) { fetch('/assets/include/nav.html') .then(response => response.text()) .then(data => { const parser = new DOMParser(); const html = parser.parseFromString(data, "text/html"); const p_elements = html.getElementsByClassName('nav')[0]; const file_area = document.getElementsByClassName("nav")[0]; file_area.innerHTML = p_elements.innerHTML; }).then(node => { lazyload(node) }); } });

として、fetchの順番を守ったのですが、エラーが出てしまいました。

error

TypeError: node is undefined

node が未設定となっているようです。
let images = node.querySelectorAll('img[loading="lazy"]'), のところです。
node に何を設定すればいいでしょうか。

補足情報(FW/ツールのバージョンなど)

Firefox 最新版、Safari 604.1

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

dameo

2021/10/16 02:58

Windows 10の chrome バージョン: 94.0.4606.81(Official Build) (64 ビット) firefox 93.0 (64 ビット) で、以下のHTMLを試しました。 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <script> document.addEventListener( 'DOMContentLoaded', (ev) => { if ("loading" in HTMLImageElement.prototype) { document.querySelectorAll('img[loading="lazy"]').forEach((img) => { img.src = img.dataset.src; }); } else { console.log('cannot be lazy'); } }); </script> </head> <body> <div style='padding-top: 1000em;'> <img loading="lazy" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="https://gahag.net/img/201607/13s/gahag-0105896765-1.jpg"> <img loading="lazy" src="https://gahag.net/img/201607/27s/gahag-0110296134-1.jpg" data-src="https://gahag.net/img/201607/13s/gahag-0105896765-1.jpg"> </div> </body> </html> 結果はchrome/firefoxともにgahag-0105896765-1.jpgが正しく表示されました。 mac or iOS製品及びsafariはないので分かりませんが、lazyに対応していないのでしょうか? ソースのコメントを見ると、対応している前提で「ここが効かない」と書いているように見えるのですが・・・
dameo

2021/10/16 03:40

早とちりしてました。動的に追加したものに限定した話で、lazy未対応のブラウザの話ではなかったんですね。基本的にfetchが非同期で読み込んでる間に書き換えてるのが問題なので、fetch完了して要素を追加した後に再度書き換えればいいと思います。 <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <script> document.addEventListener( 'DOMContentLoaded', (ev) => { function changeImageSrcToDataSrc(node) { if ("loading" in HTMLImageElement.prototype) { node.querySelectorAll('img[loading="lazy"]').forEach((img) => { img.src = img.dataset.src; }); } else { console.log('cannot be lazy'); } } changeImageSrcToDataSrc(document); if (document.getElementsByClassName("nav") != null) { function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } delay(0) .then(() => { const file_area = document.getElementsByClassName("nav")[0]; file_area.innerHTML = '\ <img loading="lazy" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="\ data-src="https://gahag.net/img/201607/13s/gahag-0105896765-1.jpg">\ <img loading="lazy" src="https://gahag.net/img/201607/27s/gahag-0110296134-1.jpg"\ data-src="https://gahag.net/img/201607/13s/gahag-0105896765-1.jpg">' return file_area; }) .then((node)=> { // ここで再び呼べばOK //changeImageSrcToDataSrc(node); }); } }); </script> </head> <body> <div style='padding-top: 1000em;'> <img loading="lazy" src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="https://gahag.net/img/201607/13s/gahag-0105896765-1.jpg"> <img loading="lazy" src="https://gahag.net/img/201607/27s/gahag-0110296134-1.jpg" data-src="https://gahag.net/img/201607/13s/gahag-0105896765-1.jpg"> </div> <div class="nav"></div> </body> </html> fetchの代わりにsetTimeoutで非同期を作りましたが、コメントのままなら同じ現象が出ます。 コメントを外せば期待した結果になるようです。
erp

2021/10/20 08:00

回答に気づくのが遅れてしまいすみません。回答ありがとうございます。 実はインクルードするパーツはhtmlで別ファイルにまとめており、js で呼び出しています。できれば、呼び出しのコードとパーツは別にしたいとと考えています。その旨追記しておきます。 せっかく回答くださったのにすみません。
dameo

2021/10/20 08:06

回答ではなく、原因と思しきものを単体で実行できるコードで説明したつもりです。 erpさんのコードは単体で動作しないので。 原因が違っていればお付き合いしますが、対策はご自分で行ってください。
erp

2021/10/20 09:30

fetchに順番を追記することで思ったように実装できました。原因についてのご指摘大変助かりました。ありがとうございます。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。