C'est une réponse très tardive, mais je vais la laisser à quelqu'un qui en a besoin.
Tâche : charger le contenu d'origine croisée d'une iframe, émettre onLoaded
sur le succès et onError
sur l'erreur de chargement .
C'est la solution la plus indépendante de l'origine des navigateurs que j'ai pu développer. Mais tout d'abord, je vais vous parler brièvement des autres approches que j'ai eues et pourquoi elles sont mauvaises.
1. iframe C'était un petit choc pour moi, cette iframe a seulement onload
et il est appelé au chargement et à l'erreur, aucun moyen de savoir si c'est une erreur ou non.
2. performance.getEntriesByType('resource') . Cette méthode renvoie les ressources chargées. Cela ressemble à ce dont nous avons besoin. Mais quelle honte, firefox ajoute toujours la ressource dans le tableau des ressources, qu'elle soit chargée ou non. Pas moyen de savoir par Resource
l'instance a été un succès. Comme d'habitude. Au fait, cette méthode ne fonctionne pas dans ios<11.
3. script J'ai essayé de charger le html en utilisant <script>
tag. Emet onload
y onerror
correctement, malheureusement, seulement dans Chrome.
Et quand j'étais prêt à abandonner, mon collègue plus âgé m'a parlé de la balise html4. <object>
. C'est comme <iframe>
sauf qu'il dispose de solutions de repli lorsque le contenu n'est pas chargé. Cela ressemble à ce dont nous avons besoin ! Malheureusement, ce n'est pas aussi simple qu'il n'y paraît.
CODE SECTION
var obj = document.createElement('object');
// we need to specify a callback (i will mention why later)
obj.innerHTML = '<div style="height:5px"><div/>'; // fallback
obj.style.display = 'block'; // so height=5px will work
obj.style.visibility = 'hidden'; // to hide before loaded
obj.data = src;
Après cela, nous pouvons définir certains attributs pour <object>
comme nous avions voulu le faire avec iframe
. La seule différence, c'est que nous devons utiliser <params>
ne sont pas des attributs, mais leurs noms et leurs valeurs sont identiques.
for (var prop in params) {
if (params.hasOwnProperty(prop)) {
var param = document.createElement('param');
param.name = prop;
param.value = params[prop];
obj.appendChild(param);
}
}
Maintenant, la partie difficile. Comme beaucoup d'éléments similaires, <object>
n'a pas de spécifications pour les rappels, de sorte que chaque navigateur se comporte différemment.
-
Chrome . Sur erreur et sur charge émet
load
événement.
-
Firefox . Emet
load
y error
correctement.
-
Safari . N'émet rien....
On dirait que ce n'est pas différent de iframe
, getEntriesByType
, script
.... Mais, nous avons le fallback du navigateur natif ! Donc, parce que nous définissons directement le fallback (innerHtml), nous pouvons savoir si <object>
est chargé ou non
function isReallyLoaded(obj) {
return obj.offsetHeight !== 5; // fallback height
}
/**
* Chrome calls always, Firefox on load
*/
obj.onload = function() {
isReallyLoaded(obj) ? onLoaded() : onError();
};
/**
* Firefox on error
*/
obj.onerror = function() {
onError();
};
Mais que faire avec Safari ? Le bon vieux setTimeout
.
var interval = function() {
if (isLoaded) { // some flag
return;
}
if (hasResult(obj)) {
if (isReallyLoaded(obj)) {
onLoaded();
} else {
onError();
}
}
setTimeout(interval, 100);
};
function hasResult(obj) {
return obj.offsetHeight > 0;
}
Ouais.... pas si vite. Le truc c'est que, <object>
quand les échecs ont un comportement non mentionné dans les spécifications :
- Essayer de charger (size=0)
- Échecs (taille = quelconque) vraiment
- Fallback (taille = comme dans innnerHtml)
Donc, le code a besoin d'une petite amélioration
var interval = function() {
if (isLoaded) { // some flag
return;
}
if (hasResult(obj)) {
if (isReallyLoaded(obj)) {
interval.count++;
// needs less then 400ms to fallback
interval.count > 4 && onLoadedResult(obj, onLoaded);
} else {
onErrorResult(obj, onError);
}
}
setTimeout(interval, 100);
};
interval.count = 0;
setTimeout(interval, 100);
Bien, et pour commencer à charger
document.body.appendChild(obj);
C'est tout . J'ai essayé d'expliquer le code dans tous les détails, pour que ça n'ait pas l'air si stupide.
P.S. WebDev craint