航空论坛_航空翻译_民航英语翻译_飞行翻译

 找回密码
 注册
搜索
查看: 1530|回复: 0
打印 上一主题 下一主题

关于js控制 iframe 自动伸缩问题 [复制链接]

Rank: 9Rank: 9Rank: 9

跳转到指定楼层
1#
发表于 2011-3-15 22:12:01 |只看该作者 |倒序浏览
通过Google搜索iframe 自适应高度,结果5W多条,搜索iframe 高度自适应,结果2W多条。 . k# F8 U$ X) D, u8 e( \+ y$ Q. {) W
我翻了前面的几十条,刨去大量的转载,有那么三五篇是原创的。而这几篇原创里面,基本上只谈到如何自适应静的东西,就是没有考虑到JS操作DOM之后,如何做动态同步的问题。另外,在兼容性方面,也研究的不彻底。
$ i+ b9 r# O+ A3 }5 t7 N这篇文章,希望在这两个方面再做一些深入。 9 f- y0 _$ s( V' |5 s+ N- m/ v
可能有人还没接触到这个问题过,先说明一下,什么是高度自适应吧。所谓iframe高度自适应,就是,基于界面美观和交互的考虑,隐藏了iframe的border和scrollbar,让人看不出它是个iframe。如果iframe始终调用同一个固定高度的页面,我们直接写死iframe高度就可以了。而如果iframe要切换页面,或者被包含页面要做DOM动态操作,这时候,就需要程序去同步iframe高度和被包含页的实际高度了。 0 y, q9 z  f# E# G. s
顺便说下,iframe在迫不得已的时候才去用,它会给前端开发带来太多的麻烦。
5 U" N2 h8 n6 j3 T. S传统做法大致有两个: # I' Z3 n' H! i& q/ b" i% Y
方法一,在每个被包含页在本身内容加载完毕之后,执行JS取得本页面的高度,然后去同步父页面的iframe高度。 " }4 G/ e! E9 r5 a1 m1 F6 b
方法二,在主页面iframe的onload事件中执行JS,去取得被包含页的高度内容,然后去同步高度。
5 @% b- m! K+ I7 ~在代码维护角度考虑,方法二是优于方法一的,因为方法一,每个被包含页都要去引入一段相同的代码来做这个事情,创建了好多副本。
/ E! n& [+ o  h7 L7 w) l$ Z( w两个方法都只处理了静的东西,就是只在内容加载的时候执行,如果JS去操作DOM引起的高度变化,都不太方便。 3 M3 l4 E) y; ]' [7 K, @! ~
如果在主窗口做一个Interval,不停的来获取被包含页的高度,然后做同步,是不是即方便,又解决了JS操作DOM的问题了呢?答案是肯定的。
8 S7 U/ H9 G: t. w8 @Demo页面:主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
; Q% P) P1 X! `6 o) Z( v7 X主页面代码示例: $ a; l. g  V. ^" t. K) z% C6 z
<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0"></iframe>
, b9 k# ?  C) B' `- u, {<script type="text/javascript">
) r6 l. U+ }" X5 ?7 W/ vfunction reinitIframe(){ 1 z$ J2 J; g6 s, h
var iframe = document.getElementById("frame_content"); 7 P1 s4 v  L4 `' X( j6 f) M
try{
. P: y8 j5 f' L0 P( p8 _iframe.height =  iframe.contentWindow.document.documentElement.scrollHeight; ' c# H# {* R8 a0 \& ^3 y
}catch (ex){} : @) _) [; {) y( i$ ~, B* P
} $ z+ I$ Z6 A6 q! v* Z
window.setInterval("reinitIframe()", 200); " m: c1 @4 Y, j/ F5 k4 L
</script>一直执行,效率会不会有问题? 5 {7 P: h# g; D- U) E
我做了测试,同时开5个窗口(IE6、IE7、FF、Opera、Safari)执行这个代码,不会对CPU有什么影响,甚至调整到2ms,也没影响(基本维持在0%占用率)。
4 N! p6 W0 Q- _$ G4 g( b8 f下面谈谈各浏览器的兼容性问题,如何获取到正确的高度,主要是对body.scrollHeight和documentElement.scrollHeight两个值得比较。注意本文用的是这个doctype,不同的doctype应该不会影响结果,但是假如你的页面没有申明doctype,那还是先去加一个吧。
8 ]. g; Y3 d) {2 H' i  E6 V<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">在主页面追加以下测试代码,以输出这两个值,代码示例: 7 L' `+ z  d/ z: f
<div><button >Check Height</button></div> ! O" I. |" A2 `' N, O9 R: K1 ~0 [1 x
<script type="text/javascript"> 8 b1 ~9 u/ x+ ^
function checkHeight() {
% P/ a) |4 J% @7 l/ B' vvar iframe = document.getElementById("frame_content"); & k4 I9 C! l: }$ ^
var bHeight = iframe.contentWindow.document.body.scrollHeight;
4 ?8 b- P% k  v( r+ c" bvar dHeight = iframe.contentWindow.document.documentElement.scrollHeight; 1 u% c; [2 K9 y$ F( i5 m
alert("bHeight:" + bHeight + ", dHeight:" + dHeight);
6 K) K5 @) s- {  s" R& n3 B} 6 Q3 ?) _# D! ?& ~8 S# R8 u. i! n
</script>被加载页面,可以切换一个绝对定位的层,来使页面高度动态改变。如果层展开,则会撑高页面高度。代码示例: - s, v8 M8 b5 Z  T3 A# a& ^" O% n
<div>
7 p& g3 H/ s0 j  V- p<button >Toggle Overlay</button> 3 s4 ]! I2 Q0 \6 Q
</div> ' ~+ |% k/ r' v6 ~  {
<div style="height:160px;position:relative">
2 o: p5 m0 r$ C& k<div id="overlay" style="position:absolute;width:280px;height:280px;display:none;"></div> ) H: n4 Q2 K; f; s
</div> 0 [$ A( s: E4 p% `# n. z0 G
<script type="text/javascript">
. ]. z3 k/ f8 K; I* ?function toggleOverlay() { : A2 V4 C, ~- I1 X  p+ x% g
var overlay = document.getElementById('overlay');
: m" V# f& q5 p& @8 B3 d5 Doverlay.style.display = (overlay.style.display == 'none') ? 'block' : 'none';
7 T. {( v- p% p, {9 O( S! a3 d}
! Z+ h2 c% x/ a; H( y</script>下面列出以上代码在各浏览器的测试值:
# `3 k! s7 R6 k* \(bHeight = body.scrollHeight, dHeight = documentElement.scrollHeight, 红色 = 错误值, 绿色 = 正确值) 2 n# S1 r, Y3 u% U7 J) o& B
/ 层隐藏时 层展开时 - ^3 @% f. O$ W2 [0 Y, r
bHeight dHeight bHeight dHeight % }; U0 I" J* @% W* B' [: `0 w
IE6 184 184 184 303
% z8 q0 q8 ^6 O8 v7 `IE7 184 184 184 303 * R- S/ v" k! m8 C$ b* y% [
FF 184 184 184 303
* ?  K# x! ?& X9 e" I% kOpera 181 181 300 300
  M2 D) K( k/ e9 M) l+ x. q, HSafari 184 184 303 184 * S1 L, R+ n. A
暂且无视Opera比别人少3像素的问题…可以看出,如果没有绝对定位的东西,两个值是相等的,取哪个都无所谓。
0 a" v! ~6 J( A( {7 o1 L但是如果有,那么各个浏览器的表现不太相同,单取哪个值都不对。但可以找到了一条规律,那就是取两个值得最大值可以兼容各浏览器。所以我们的主页面代码就要改造成这样了: . a7 h7 ], R7 D7 n/ ?
function reinitIframe(){
/ j2 v0 U3 |8 [; C$ wvar iframe = document.getElementById("frame_content");
/ G, [" w, B. @; btry{
3 {/ f9 J6 M% \& u7 [+ ~0 |% Fvar bHeight = iframe.contentWindow.document.body.scrollHeight;
8 _  H; @- s2 A6 kvar dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
5 F1 u6 m3 Y8 U7 bvar height = Math.max(bHeight, dHeight); 9 o9 e& X# }1 k' f7 Y8 U3 l+ X
iframe.height =  height; ) N( U  i- q4 h1 \- t6 X
}catch (ex){} * a0 w4 }4 i9 N2 w% z' B5 |
}
  Q3 _, {! p1 M: l1 dwindow.setInterval("reinitIframe()", 200);这样子,基本解决了兼容性问题。顺便说下,不光绝对定位的层会影响到值,float也会导致两个值的差异。 5 F. o. L. y2 R1 y: [* u: R9 Q
如果你演示Demo后,会发现,除了IE,其他浏览器中,当层展开后再隐藏,取到的高度值还是维持在展开的高度303,而非隐藏回去的真正值184,就是说长高了之后缩不回去了。这个现象在不同被包含页面之间做切换也会发生,当从高的页面切换到矮页面的时候,取到的高度还是那个高的值。 / ]6 F+ e& v" P3 H
可以归纳为,当iframe窗体高度高于文档实际高度的时候,高度取的是窗体高度,而当窗体高度低于实际文档高度时,取的是文档实际高度。因此,要想办法在同步高度之前把高度设置到一个比实际文档低的值。所以,在iframe的添加 onload=”this.height=100″,让页面加载的时候先缩到足够矮,然后再同步到一样的高度。
# W5 O: S& a) Y0 `) D8 W% S这个值,在实际应用中决定,足够矮但又不能太矮,否则在FF等浏览器里会有很明显的闪烁。DOM操作的时候主页面无法监听到,只能DOM操作完了之后把高度变小了。
) E/ Q3 {  v: ^" @) |; \2 i$ Y# l在我的一个实际项目中,在成本和收益之间权衡,我并没有做这个事情,因为每个DOM函数中都要插入这个代码,代价太高,其实层缩回去不缩掉也不是那么致命。包括Demo里,也没有去做这个事情。如果读者有更好的方法,请告诉我。 & `# l8 ]% x9 y) L4 B* ]& {! z
这是最终的主页面的代码:
$ @( x7 p  f; b7 G5 c7 r$ A, q<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0" 7 O0 @& P( Y1 w4 M8 p7 ?
></iframe>
. b1 l3 p* p, Z" v; l) F3 |<script type="text/javascript"> 5 y6 w! a: X9 \8 W$ g! V/ o$ T6 Y& u
function reinitIframe(){ 8 }, d1 A" S6 s) `. W
var iframe = document.getElementById("frame_content");
# e( ?; ~5 g# G( S( Ltry{
  t& ~, x9 a4 Qvar bHeight = iframe.contentWindow.document.body.scrollHeight;
4 d+ F. |# _5 N: k2 W9 A/ S' qvar dHeight = iframe.contentWindow.document.documentElement.scrollHeight; 2 l8 @5 d) }; A9 O$ M- c7 d
var height = Math.max(bHeight, dHeight); 3 f. h( {9 K: @- ~# g$ }; I
iframe.height =  height;
1 |, l/ ]+ w/ {2 P}catch (ex){} 1 O+ _$ q) y! f7 l' v/ u& Q5 ~! ]
}
" q, E% y" Y1 J9 w, Qwindow.setInterval("reinitIframe()", 200);
) `: f* X! T# ?% q% ?( s7 [6 b</script>附Demo页面: 主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
您需要登录后才可以回帖 登录 | 注册


Archiver|航空论坛 ( 渝ICP备10008336号 )

GMT+8, 2026-1-12 04:48 , Processed in 0.023001 second(s), 9 queries .

Powered by Discuz! X2

© 2001-2011 MinHang.CC.

回顶部