将 html 写入带有回调的 iframe
Write html into iframe with callback
我们正在从后端获取数据,需要将其写入 iframe
。我们必须将 iframe
高度设置为内容的高度。在内容实际位于 iframe
之前,我们无法获得正确的高度,这对于大量内容来说不是瞬时的。是否有回调知道写入何时完成?
现在,我们有一个计时器,但它是脆弱的代码:
//data received from backend
//write data to iframe
//$iframe is a jQuery DOM element
$iframe[0].contentDocument.open();
$iframe[0].contentDocument.write(data);
$iframe[0].contentDocument.close();
setTimeout(function (){
var scrollHeight = $iframe.contents().find('body')[0].scrollHeight
$iframe.css("height", scrollHeight );
}, 1000);
iframe 确实有一个 onload 事件:
$iframe[0].contentDocument.open();
$iframe[0].contentDocument.write(data);
$iframe[0].contentDocument.close();
$iframe.onload = function() {
var scrollHeight = $iframe.contents().find('body')[0].scrollHeight
$iframe.css("height", scrollHeight);
};
您是否试过在 iframe
上监听 load
事件?
var doc = $iframe[0].contentDocument
doc.open()
doc.write(data)
doc.close()
$iframe.on('load', function () {
this.style.height = doc.body.scrollHeight + 'px'
})
也许 postMessage 会对您有所帮助。
var testData = 'test\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\n';
var $iframe = document.querySelector('#test-iframe');
var $button = document.querySelector('button');
// listen the callback message from iframe
window.self.addEventListener('message', function(ev) {
if (ev.data && ev.data.status === 'ready') {
$iframe.style.height = ev.data.height + 'px';
}
});
$button.addEventListener('click', function() {
// render content
$iframe.contentDocument.body.innerText = testData;
// send message to the top window
window.self.postMessage({
status: 'ready',
height: $iframe.contentDocument.body.scrollHeight
}, '*');
});
`
您最好的选择是在 iFrame 中使用 mutationObserver。恐怕这不像回调那么简单。
这是 iFrame-resizer 库用来解决这个问题的代码。您需要更改调用 sendSize
的行来调用您的回调方法。
function setupBodyMutationObserver(){
function addImageLoadListners(mutation) {
function addImageLoadListener(element){
if (false === element.complete) {
console.log('Attach listeners to ' + element.src);
element.addEventListener('load', imageLoaded, false);
element.addEventListener('error', imageError, false);
elements.push(element);
}
}
if (mutation.type === 'attributes' && mutation.attributeName === 'src'){
addImageLoadListener(mutation.target);
} else if (mutation.type === 'childList'){
Array.prototype.forEach.call(
mutation.target.querySelectorAll('img'),
addImageLoadListener
);
}
}
function removeFromArray(element){
elements.splice(elements.indexOf(element),1);
}
function removeImageLoadListener(element){
console.log('Remove listeners from ' + element.src);
element.removeEventListener('load', imageLoaded, false);
element.removeEventListener('error', imageError, false);
removeFromArray(element);
}
function imageEventTriggered(event,type,typeDesc){
removeImageLoadListener(event.target);
sendSize(type, typeDesc + ': ' + event.target.src, undefined, undefined);
}
function imageLoaded(event) {
imageEventTriggered(event,'imageLoad','Image loaded');
}
function imageError(event) {
imageEventTriggered(event,'imageLoadFailed','Image load failed');
}
function mutationObserved(mutations) {
sendSize('mutationObserver','mutationObserver: ' + mutations[0].target + ' ' + mutations[0].type);
//Deal with WebKit asyncing image loading when tags are injected into the page
mutations.forEach(addImageLoadListners);
}
function createMutationObserver(){
var
target = document.querySelector('body'),
config = {
attributes : true,
attributeOldValue : false,
characterData : true,
characterDataOldValue : false,
childList : true,
subtree : true
};
observer = new MutationObserver(mutationObserved);
console.log('Create body MutationObserver');
observer.observe(target, config);
return observer;
}
var
elements = [],
MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
observer = createMutationObserver();
return {
disconnect: function (){
if ('disconnect' in observer){
console.log('Disconnect body MutationObserver');
observer.disconnect();
elements.forEach(removeImageLoadListener);
}
}
};
}
我们正在从后端获取数据,需要将其写入 iframe
。我们必须将 iframe
高度设置为内容的高度。在内容实际位于 iframe
之前,我们无法获得正确的高度,这对于大量内容来说不是瞬时的。是否有回调知道写入何时完成?
现在,我们有一个计时器,但它是脆弱的代码:
//data received from backend
//write data to iframe
//$iframe is a jQuery DOM element
$iframe[0].contentDocument.open();
$iframe[0].contentDocument.write(data);
$iframe[0].contentDocument.close();
setTimeout(function (){
var scrollHeight = $iframe.contents().find('body')[0].scrollHeight
$iframe.css("height", scrollHeight );
}, 1000);
iframe 确实有一个 onload 事件:
$iframe[0].contentDocument.open();
$iframe[0].contentDocument.write(data);
$iframe[0].contentDocument.close();
$iframe.onload = function() {
var scrollHeight = $iframe.contents().find('body')[0].scrollHeight
$iframe.css("height", scrollHeight);
};
您是否试过在 iframe
上监听 load
事件?
var doc = $iframe[0].contentDocument
doc.open()
doc.write(data)
doc.close()
$iframe.on('load', function () {
this.style.height = doc.body.scrollHeight + 'px'
})
也许 postMessage 会对您有所帮助。
var testData = 'test\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\ntest\n';
var $iframe = document.querySelector('#test-iframe');
var $button = document.querySelector('button');
// listen the callback message from iframe
window.self.addEventListener('message', function(ev) {
if (ev.data && ev.data.status === 'ready') {
$iframe.style.height = ev.data.height + 'px';
}
});
$button.addEventListener('click', function() {
// render content
$iframe.contentDocument.body.innerText = testData;
// send message to the top window
window.self.postMessage({
status: 'ready',
height: $iframe.contentDocument.body.scrollHeight
}, '*');
});
`
您最好的选择是在 iFrame 中使用 mutationObserver。恐怕这不像回调那么简单。
这是 iFrame-resizer 库用来解决这个问题的代码。您需要更改调用 sendSize
的行来调用您的回调方法。
function setupBodyMutationObserver(){
function addImageLoadListners(mutation) {
function addImageLoadListener(element){
if (false === element.complete) {
console.log('Attach listeners to ' + element.src);
element.addEventListener('load', imageLoaded, false);
element.addEventListener('error', imageError, false);
elements.push(element);
}
}
if (mutation.type === 'attributes' && mutation.attributeName === 'src'){
addImageLoadListener(mutation.target);
} else if (mutation.type === 'childList'){
Array.prototype.forEach.call(
mutation.target.querySelectorAll('img'),
addImageLoadListener
);
}
}
function removeFromArray(element){
elements.splice(elements.indexOf(element),1);
}
function removeImageLoadListener(element){
console.log('Remove listeners from ' + element.src);
element.removeEventListener('load', imageLoaded, false);
element.removeEventListener('error', imageError, false);
removeFromArray(element);
}
function imageEventTriggered(event,type,typeDesc){
removeImageLoadListener(event.target);
sendSize(type, typeDesc + ': ' + event.target.src, undefined, undefined);
}
function imageLoaded(event) {
imageEventTriggered(event,'imageLoad','Image loaded');
}
function imageError(event) {
imageEventTriggered(event,'imageLoadFailed','Image load failed');
}
function mutationObserved(mutations) {
sendSize('mutationObserver','mutationObserver: ' + mutations[0].target + ' ' + mutations[0].type);
//Deal with WebKit asyncing image loading when tags are injected into the page
mutations.forEach(addImageLoadListners);
}
function createMutationObserver(){
var
target = document.querySelector('body'),
config = {
attributes : true,
attributeOldValue : false,
characterData : true,
characterDataOldValue : false,
childList : true,
subtree : true
};
observer = new MutationObserver(mutationObserved);
console.log('Create body MutationObserver');
observer.observe(target, config);
return observer;
}
var
elements = [],
MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
observer = createMutationObserver();
return {
disconnect: function (){
if ('disconnect' in observer){
console.log('Disconnect body MutationObserver');
observer.disconnect();
elements.forEach(removeImageLoadListener);
}
}
};
}