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

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

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

Rank: 9Rank: 9Rank: 9

跳转到指定楼层
1#
发表于 2011-3-15 22:12:01 |只看该作者 |倒序浏览
通过Google搜索iframe 自适应高度,结果5W多条,搜索iframe 高度自适应,结果2W多条。 ) j4 D9 @: L! `5 `
我翻了前面的几十条,刨去大量的转载,有那么三五篇是原创的。而这几篇原创里面,基本上只谈到如何自适应静的东西,就是没有考虑到JS操作DOM之后,如何做动态同步的问题。另外,在兼容性方面,也研究的不彻底。
( M' x& v& U2 Z2 q. L7 W( Y这篇文章,希望在这两个方面再做一些深入。 . j( T8 e' z( E  b1 A9 p
可能有人还没接触到这个问题过,先说明一下,什么是高度自适应吧。所谓iframe高度自适应,就是,基于界面美观和交互的考虑,隐藏了iframe的border和scrollbar,让人看不出它是个iframe。如果iframe始终调用同一个固定高度的页面,我们直接写死iframe高度就可以了。而如果iframe要切换页面,或者被包含页面要做DOM动态操作,这时候,就需要程序去同步iframe高度和被包含页的实际高度了。 ; C1 |0 Z5 }" _/ a7 |
顺便说下,iframe在迫不得已的时候才去用,它会给前端开发带来太多的麻烦。
- E9 Z+ U0 A. P1 c+ J传统做法大致有两个:
0 n  z- t# _1 X' u' s方法一,在每个被包含页在本身内容加载完毕之后,执行JS取得本页面的高度,然后去同步父页面的iframe高度。 6 e4 B6 E5 n1 i
方法二,在主页面iframe的onload事件中执行JS,去取得被包含页的高度内容,然后去同步高度。 ! F' g4 y' Z5 N- y4 D+ {  L! R, c
在代码维护角度考虑,方法二是优于方法一的,因为方法一,每个被包含页都要去引入一段相同的代码来做这个事情,创建了好多副本。
5 i( m, ~/ {, o0 @3 F/ B两个方法都只处理了静的东西,就是只在内容加载的时候执行,如果JS去操作DOM引起的高度变化,都不太方便。 : M; O7 J1 L/ ?5 R( I" O8 j
如果在主窗口做一个Interval,不停的来获取被包含页的高度,然后做同步,是不是即方便,又解决了JS操作DOM的问题了呢?答案是肯定的。 1 S/ J, U4 U. [* p
Demo页面:主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
- i6 p% K! `  p# ?0 E3 y" ~主页面代码示例: 9 e* U( S' U: c+ }' o
<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0"></iframe>
. A+ L% k; g- j0 |9 C. n7 \, o' K<script type="text/javascript">
3 G5 E5 f" y- Y1 g% c# g# ^. G3 `4 \function reinitIframe(){ & o+ {2 v3 _% t5 z# F
var iframe = document.getElementById("frame_content"); : S0 p1 I$ z; e: u
try{ $ p  @0 U  e7 o. l1 o  x5 q
iframe.height =  iframe.contentWindow.document.documentElement.scrollHeight; $ k2 i3 \2 {/ D$ n, U
}catch (ex){} ) E1 e# E3 i3 m) P6 T
}
" F" n. [( A! F% bwindow.setInterval("reinitIframe()", 200);
5 s; I% x2 ?" A/ b</script>一直执行,效率会不会有问题? $ H7 X) V  \0 E- k( b, w) |
我做了测试,同时开5个窗口(IE6、IE7、FF、Opera、Safari)执行这个代码,不会对CPU有什么影响,甚至调整到2ms,也没影响(基本维持在0%占用率)。 ( M* O( A2 i9 f' e
下面谈谈各浏览器的兼容性问题,如何获取到正确的高度,主要是对body.scrollHeight和documentElement.scrollHeight两个值得比较。注意本文用的是这个doctype,不同的doctype应该不会影响结果,但是假如你的页面没有申明doctype,那还是先去加一个吧。
( ^' t. K' C9 j<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">在主页面追加以下测试代码,以输出这两个值,代码示例:
  R2 l" U* t% j  u5 x<div><button >Check Height</button></div> 5 t" j1 h8 k1 i$ j  A2 J, b
<script type="text/javascript"> / [. k( m& H$ v# h2 `
function checkHeight() {
* x" W) O* y9 k- d0 r- Dvar iframe = document.getElementById("frame_content"); & I5 q4 h3 e" G6 E; e
var bHeight = iframe.contentWindow.document.body.scrollHeight;
( L6 {2 e! C  D) U8 }6 W+ D0 Gvar dHeight = iframe.contentWindow.document.documentElement.scrollHeight; ! G3 S0 P  i$ n9 x
alert("bHeight:" + bHeight + ", dHeight:" + dHeight); . I! n0 T! P# F& H/ X6 B! d. P
} " P6 f! e$ b! H9 S( g/ Q! O
</script>被加载页面,可以切换一个绝对定位的层,来使页面高度动态改变。如果层展开,则会撑高页面高度。代码示例:
! V; j$ P# B1 `<div> " z* C9 Y- t) Q$ s% z: V
<button >Toggle Overlay</button>
9 n0 d0 [$ v' @" ~% J* ^* D</div> . L, _7 p- s4 S0 X* Y' x
<div style="height:160px;position:relative"> & j: I. ~0 y: r
<div id="overlay" style="position:absolute;width:280px;height:280px;display:none;"></div> , f) C/ k% o, G5 r# D8 O
</div> 6 d! _$ G& ?! [* E+ w. w; y
<script type="text/javascript">
& y* X/ j  ^8 Q. afunction toggleOverlay() {
! `! U5 p1 T; T  T: B, Pvar overlay = document.getElementById('overlay'); 2 V; P" n& M( ?) G0 x. `! i5 L! g
overlay.style.display = (overlay.style.display == 'none') ? 'block' : 'none'; ' x* n; i( ]/ ^1 |( T* P4 a
} & C* q- Y/ `9 y% m, t
</script>下面列出以上代码在各浏览器的测试值:   p( r- `! g+ J2 Z; f$ Q
(bHeight = body.scrollHeight, dHeight = documentElement.scrollHeight, 红色 = 错误值, 绿色 = 正确值)
0 ]& ?7 {' s. }# b8 l/ 层隐藏时 层展开时 3 `  M$ U" D% N
bHeight dHeight bHeight dHeight
5 p+ a5 o! v$ g% O- E, R8 w: a' n7 O! LIE6 184 184 184 303
) U! E$ w+ o) e! k* dIE7 184 184 184 303
. V, F2 a. w/ k4 j! cFF 184 184 184 303 % t1 K3 k2 ]1 v; ^
Opera 181 181 300 300 % n$ _* I0 d& B8 _/ J, e( P" M
Safari 184 184 303 184
! W) W6 c9 l; \3 _8 c暂且无视Opera比别人少3像素的问题…可以看出,如果没有绝对定位的东西,两个值是相等的,取哪个都无所谓。
; p, B, P  P3 c1 T9 o; J7 m' W但是如果有,那么各个浏览器的表现不太相同,单取哪个值都不对。但可以找到了一条规律,那就是取两个值得最大值可以兼容各浏览器。所以我们的主页面代码就要改造成这样了: " D& B; ^: k. P% r/ {# h# j3 f) v( B* |
function reinitIframe(){
6 i$ k4 s; @! }0 ^( r& {$ a$ zvar iframe = document.getElementById("frame_content");
# ], V* Z/ I$ `* [try{ 1 N! L6 {8 p6 `
var bHeight = iframe.contentWindow.document.body.scrollHeight; + u, Z! `2 @& W+ M  H  A4 G$ A1 [
var dHeight = iframe.contentWindow.document.documentElement.scrollHeight; , m. }  S9 a% Y+ y+ ~1 ~/ }, _
var height = Math.max(bHeight, dHeight); 4 z8 H5 D  B: T. W
iframe.height =  height;
+ Q, c: e' s, a9 b2 }6 {+ l}catch (ex){}
# x$ y' C' \7 l1 Q9 Y% r& E; f* `} # P! ^! }# e+ ?) y
window.setInterval("reinitIframe()", 200);这样子,基本解决了兼容性问题。顺便说下,不光绝对定位的层会影响到值,float也会导致两个值的差异。
$ X6 |/ X0 k1 n4 ~, s! @  k如果你演示Demo后,会发现,除了IE,其他浏览器中,当层展开后再隐藏,取到的高度值还是维持在展开的高度303,而非隐藏回去的真正值184,就是说长高了之后缩不回去了。这个现象在不同被包含页面之间做切换也会发生,当从高的页面切换到矮页面的时候,取到的高度还是那个高的值。
0 H* [2 G# I, _可以归纳为,当iframe窗体高度高于文档实际高度的时候,高度取的是窗体高度,而当窗体高度低于实际文档高度时,取的是文档实际高度。因此,要想办法在同步高度之前把高度设置到一个比实际文档低的值。所以,在iframe的添加 onload=”this.height=100″,让页面加载的时候先缩到足够矮,然后再同步到一样的高度。 7 t4 J; i4 t$ l+ Y$ Z- x' T  @
这个值,在实际应用中决定,足够矮但又不能太矮,否则在FF等浏览器里会有很明显的闪烁。DOM操作的时候主页面无法监听到,只能DOM操作完了之后把高度变小了。 * U! }2 x1 e/ y. j
在我的一个实际项目中,在成本和收益之间权衡,我并没有做这个事情,因为每个DOM函数中都要插入这个代码,代价太高,其实层缩回去不缩掉也不是那么致命。包括Demo里,也没有去做这个事情。如果读者有更好的方法,请告诉我。
! M" w4 B2 o5 d5 C$ ^- q5 U% T5 P$ X这是最终的主页面的代码:
$ @6 h' v2 T2 ?3 c* S' R0 g+ Y7 g1 M<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0" - b2 O! \; I7 _" w6 L, S" I+ T
></iframe>
) J# }0 W# M/ \5 s1 y3 D<script type="text/javascript">
6 d! k( h2 v& }* d' Y3 Z7 zfunction reinitIframe(){
5 w& v6 k4 h3 X; D+ l4 o, kvar iframe = document.getElementById("frame_content");
8 ], \6 z, e  T3 y6 k1 c6 T6 Ytry{
1 O, o# u5 L& B4 E1 U2 G! ]3 Wvar bHeight = iframe.contentWindow.document.body.scrollHeight; ' E+ Z5 X$ e/ g% i* D& N; A
var dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
6 g( j1 ~" Q5 M; f, r: `7 j( Fvar height = Math.max(bHeight, dHeight); ) ]+ j* ^# c( J% d
iframe.height =  height;
: E( R' U! H* E6 s}catch (ex){} . r6 h: _9 o# a+ L- o/ ~3 q
} ! K7 a* |1 r( V6 g7 V. Z" A  h6 y
window.setInterval("reinitIframe()", 200); 0 V6 `7 h. ]9 ]$ K
</script>附Demo页面: 主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
您需要登录后才可以回帖 登录 | 注册


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

GMT+8, 2025-12-15 04:46 , Processed in 0.022001 second(s), 9 queries .

Powered by Discuz! X2

© 2001-2011 MinHang.CC.

回顶部