前提・実現したいこと
動的に読み込んだ要素のロードが完了したら、高さを取得したい
発生している問題
ロード完了後のアラートがいつまで立っても表示されない
試したこと(console.log()追記)
qiitaの
https://qiita.com/scalewallet/items/939f16d3c85e0e0e5c65
を参考にして、自分の使いたい要素に合わせて改変してみました。
console.log()追記後のコンソールに表示された内容は
consoleLog
1step1 2step2-2 3step3
です。
html
1<!DOCTYPE html> 2<html lang="en"> 3 4<head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>Document</title> 8</head> 9 10<body> 11 12 <div class="first"></div> 13 <script src="/js/jquery-3.4.1.min.js"></script> 14 <script> 15 function main() { 16 // DOMの操作は同期的に行われるため$.whenを利用する必要はない。 17 $('.first').append('<div class="hoge">hoge</div>') 18 19 // 追加されたそれぞれの要素をDeferred化し全てのロードが完了するのを$.whenで待つ 20 $.when.apply($, $('.hoge').map(waitForLoading)).then(function () { 21 alert("読み込み完了"); 22 }) 23 24 } 25 function waitForLoading(index, img) { 26 var dfd = $.Deferred(); 27 console.log("step1"); 28 29 // img要素のロード完了はimg.completeで取得できます。 30 if (img.complete) { 31 console.log("step2-1"); 32 // すでにロードが完了していれば即時resolve。 33 dfd.resolve() 34 } else { 35 console.log("step2-2"); 36 // ロードが完了していなかった場合、イベントリスナー登録しロードの完了を待つ 37 $(img).on('load', function () { 38 console.log("step2-2-1"); 39 resolve(); 40 }) 41 } 42 console.log("step3"); 43 return dfd; 44 } 45 main(); 46 </script> 47</body> 48 49</html>
###Deferredはdivのみのロードには効かないのか
長文にならないようにソースや説明を最低限のものに加工してたのですが、実は
①親ページに元からある「.first」に対して、動的にdiv「.parent」だけを挿入する
②挿入した「.parent」に対して、動的にiframeだけを挿入する
③「.parent」の中身をiframe中のターゲット「.my_content」のhtmlに書き換える(iframeタグ自体は消える)
④サイズを調節した後「.parent」の高さを取る
という流れを想定していました。
moyashidaisuke様のご回答で、Deferredを使った関数はdivだけの場合効かないと知ったので、
①部分はDeferredを使った関数を使わず、そのままappend致しました。
「.my_content」のhtmlは「<div class="my_content">子ページです。</div>」というdivだけなので
Deferredを使った関数は不要かと思ったのですが、
Deferredを使った関数(load_content)を利用してみたところ、divだけなのに作動しました。
divだけだとDeferredが効かない場合と、
divだけなのにDeferredが効く場合の違いは何でしょうか?
html
1<!DOCTYPE html> 2<html lang="en"> 3 4<head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>親ページ</title> 8 <style> 9 *{ 10 box-sizing: border-box; 11 margin: 0; 12 padding: 0; 13 } 14 </style> 15</head> 16 17<body> 18 19 <div class="first"></div> 20 <script src="/js/jquery-3.4.1.min.js"></script> 21 <script> 22 (function () { 23 24 25 function load_iframe() { 26 var deferred = $.Deferred(); 27 var iframe = $('<iframe class="my_iframe" src="child.html"></iframe>'); 28 iframe.on('load', deferred.resolve); 29 iframe.prependTo('.parent'); 30 return deferred.promise(); 31 } 32 33 function load_content(html) { 34 var deferred = $.Deferred(); 35 var load_page = $(html); 36 load_page.on('load', deferred.resolve); 37 $('.parent').html(html); 38 return deferred.promise(); 39 } 40 41 $('.first').append('<div class="parent"></div>'); 42 43 44 var iframe_height; 45 46 47 $.when(load_iframe()).then(function () { 48 49 iframe_height = $('.my_iframe').contents().find('.my_content').outerHeight(); 50 console.log("iframeのターゲットコンテンツの高さ=" + iframe_height); 51 var html = $('.parent .my_iframe').contents().find('.my_content').prop('outerHTML'); 52 console.log(html) 53 load_content(html); 54 55 56 }).then(function () { 57 console.log("読み込み完了"); 58 /*サイズを色々変えてみた後に高さ取得*/ 59 $('.parent').css("padding-top", "100px"); 60 $('.parent').css("height", 100 + iframe_height + "px"); 61 console.log("親の高さ=" + $('.parent').outerHeight()); 62 63 }); 64 65 66 67 }()); 68 </script> 69</body> 70 71</html>
html
1<!DOCTYPE html> 2<html lang="en"> 3 4<head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <title>子ページ</title> 8</head> 9 10<body> 11 12 <div class="my_content">子ページです。</div> 13 14</body> 15 16</html>
consoleLog
1iframeのターゲットコンテンツの高さ=24 2<div class="my_content">子ページです。</div> 3読み込み完了 4親の高さ=124

