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

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

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

Rank: 9Rank: 9Rank: 9

跳转到指定楼层
1#
发表于 2011-3-15 22:12:01 |只看该作者 |正序浏览
通过Google搜索iframe 自适应高度,结果5W多条,搜索iframe 高度自适应,结果2W多条。
7 G) z! I6 D" @( ^. f. z, {我翻了前面的几十条,刨去大量的转载,有那么三五篇是原创的。而这几篇原创里面,基本上只谈到如何自适应静的东西,就是没有考虑到JS操作DOM之后,如何做动态同步的问题。另外,在兼容性方面,也研究的不彻底。
! f. x/ H4 {% \" g" E: Y这篇文章,希望在这两个方面再做一些深入。
1 l) k) N0 G- o! X4 N& a- d  m3 C可能有人还没接触到这个问题过,先说明一下,什么是高度自适应吧。所谓iframe高度自适应,就是,基于界面美观和交互的考虑,隐藏了iframe的border和scrollbar,让人看不出它是个iframe。如果iframe始终调用同一个固定高度的页面,我们直接写死iframe高度就可以了。而如果iframe要切换页面,或者被包含页面要做DOM动态操作,这时候,就需要程序去同步iframe高度和被包含页的实际高度了。 " n6 h/ @. Y, r2 |5 j1 Z
顺便说下,iframe在迫不得已的时候才去用,它会给前端开发带来太多的麻烦。
, n5 u/ A7 p+ w/ ?* O: q传统做法大致有两个:
3 S' e: }$ s& \( S5 P) u1 m: k8 f方法一,在每个被包含页在本身内容加载完毕之后,执行JS取得本页面的高度,然后去同步父页面的iframe高度。 5 o; F( b- }. ^3 ^
方法二,在主页面iframe的onload事件中执行JS,去取得被包含页的高度内容,然后去同步高度。
8 Y. ^! ^$ E. a3 f# I! x在代码维护角度考虑,方法二是优于方法一的,因为方法一,每个被包含页都要去引入一段相同的代码来做这个事情,创建了好多副本。 + d8 r! V- D' E4 W! n
两个方法都只处理了静的东西,就是只在内容加载的时候执行,如果JS去操作DOM引起的高度变化,都不太方便。
: Q9 [& a+ F5 `) e; z% ^6 P" }如果在主窗口做一个Interval,不停的来获取被包含页的高度,然后做同步,是不是即方便,又解决了JS操作DOM的问题了呢?答案是肯定的。
' y3 G, e3 e5 U- {! a2 {Demo页面:主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html , F9 i; p) e# I$ w6 s
主页面代码示例:
0 j1 _5 _6 d0 k0 [; L9 ~<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0"></iframe> 2 G) m4 ]5 \! y/ j# }/ N5 s
<script type="text/javascript"> ) D( `% f. ^) |6 q' h
function reinitIframe(){
: V, M& _8 w/ N) c, Xvar iframe = document.getElementById("frame_content");
  h; ^& e7 b' dtry{ $ a+ j' I' o- Z' u% r* q6 R7 J
iframe.height =  iframe.contentWindow.document.documentElement.scrollHeight; 7 s6 B; P9 O8 L( T3 }1 b
}catch (ex){}
' q2 S1 {2 L: }! {' t; R! @}
7 q5 r0 R- @4 W9 ?8 M- M, N1 Z) D1 ^window.setInterval("reinitIframe()", 200);
# B& z+ b7 J' g, s</script>一直执行,效率会不会有问题? ' D: m/ K7 i8 l4 Z
我做了测试,同时开5个窗口(IE6、IE7、FF、Opera、Safari)执行这个代码,不会对CPU有什么影响,甚至调整到2ms,也没影响(基本维持在0%占用率)。
2 @" X; W7 c+ w  h' D' O! T3 j8 q下面谈谈各浏览器的兼容性问题,如何获取到正确的高度,主要是对body.scrollHeight和documentElement.scrollHeight两个值得比较。注意本文用的是这个doctype,不同的doctype应该不会影响结果,但是假如你的页面没有申明doctype,那还是先去加一个吧。 " f) s& O' S: v1 v7 X& W+ A8 X
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">在主页面追加以下测试代码,以输出这两个值,代码示例:
0 _3 G& r$ ^6 U1 R8 y<div><button >Check Height</button></div> 0 W, ^! s, \/ R# C
<script type="text/javascript"> 6 [1 M. }* b: Z. n: ~7 K" {0 P
function checkHeight() { $ O! o2 i! C$ Q! W
var iframe = document.getElementById("frame_content"); & S1 |( |6 u- j
var bHeight = iframe.contentWindow.document.body.scrollHeight; 7 B+ c) _: e, M
var dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
( |* Q2 W; Y) walert("bHeight:" + bHeight + ", dHeight:" + dHeight); ; E5 P' V9 O! _0 @) Q0 F! n
}
8 y/ I. i+ K8 U! Z8 e$ n</script>被加载页面,可以切换一个绝对定位的层,来使页面高度动态改变。如果层展开,则会撑高页面高度。代码示例:
' G, ]& T# S  s4 s- _<div> . A- N9 I5 o' P- R: i* {
<button >Toggle Overlay</button>
# @" U* M- l2 \' V! @</div>
" D, j$ N0 e! Y) J8 S<div style="height:160px;position:relative">
/ ?* q2 P7 p% P  J: B, w9 K<div id="overlay" style="position:absolute;width:280px;height:280px;display:none;"></div>   M7 H/ D9 N1 B* O7 v$ P
</div>
9 f9 U( U( _, i4 r<script type="text/javascript"> 3 L6 [, K5 @/ K, E$ ?2 z
function toggleOverlay() { . Y1 X5 C) `% A/ {( V9 w, i1 s
var overlay = document.getElementById('overlay');
7 H9 b4 ?% V  woverlay.style.display = (overlay.style.display == 'none') ? 'block' : 'none'; 5 J0 p5 J7 H& y  O1 {) k
} - v! g. J" M& H4 M. @2 Q# |
</script>下面列出以上代码在各浏览器的测试值:
  V" o5 R1 S# o9 w3 ](bHeight = body.scrollHeight, dHeight = documentElement.scrollHeight, 红色 = 错误值, 绿色 = 正确值)
. I3 e, ^" @, T8 J& e/ 层隐藏时 层展开时 % C# k/ l' D. n, p1 _" i" u+ }
bHeight dHeight bHeight dHeight 2 d( ]$ r5 d; X0 C9 t# Z
IE6 184 184 184 303
3 M  U) ]  m& T. S- x6 Z0 c4 \4 MIE7 184 184 184 303
" g$ p& K9 p* j7 fFF 184 184 184 303
+ y& H( G6 G6 j. j1 ?Opera 181 181 300 300
# m* c/ K, `  F+ b! B) E1 fSafari 184 184 303 184 4 |0 k+ N7 i$ |* {* N3 H
暂且无视Opera比别人少3像素的问题…可以看出,如果没有绝对定位的东西,两个值是相等的,取哪个都无所谓。 8 v7 X4 [! Y1 z  v+ U
但是如果有,那么各个浏览器的表现不太相同,单取哪个值都不对。但可以找到了一条规律,那就是取两个值得最大值可以兼容各浏览器。所以我们的主页面代码就要改造成这样了:
) |, P" e/ }" f9 B4 _function reinitIframe(){
: j& z- ]. f; x# X3 p# x+ q2 \var iframe = document.getElementById("frame_content"); ) B; N3 J9 u- W% G
try{
, r4 ~2 ^) x; Q( B4 r$ p" ivar bHeight = iframe.contentWindow.document.body.scrollHeight;
2 Q7 }& c( K# K. Zvar dHeight = iframe.contentWindow.document.documentElement.scrollHeight; 8 w# x8 _% z+ [' r; l! m* ]
var height = Math.max(bHeight, dHeight);
# R# u: K5 |) l8 T0 o& T% _  m: r; Piframe.height =  height;
! Z1 U4 n/ ]' F5 ?+ Q}catch (ex){}
1 r1 R3 c& g% K% ?, Y& D7 C}
2 g& }# A0 i1 B2 E6 ^window.setInterval("reinitIframe()", 200);这样子,基本解决了兼容性问题。顺便说下,不光绝对定位的层会影响到值,float也会导致两个值的差异。 8 X; @& Z1 Q4 r, c& q6 N
如果你演示Demo后,会发现,除了IE,其他浏览器中,当层展开后再隐藏,取到的高度值还是维持在展开的高度303,而非隐藏回去的真正值184,就是说长高了之后缩不回去了。这个现象在不同被包含页面之间做切换也会发生,当从高的页面切换到矮页面的时候,取到的高度还是那个高的值。
- R. R6 I5 r" u5 r可以归纳为,当iframe窗体高度高于文档实际高度的时候,高度取的是窗体高度,而当窗体高度低于实际文档高度时,取的是文档实际高度。因此,要想办法在同步高度之前把高度设置到一个比实际文档低的值。所以,在iframe的添加 onload=”this.height=100″,让页面加载的时候先缩到足够矮,然后再同步到一样的高度。 ( {& a4 P+ F  h
这个值,在实际应用中决定,足够矮但又不能太矮,否则在FF等浏览器里会有很明显的闪烁。DOM操作的时候主页面无法监听到,只能DOM操作完了之后把高度变小了。 * z; ^4 M2 k' [
在我的一个实际项目中,在成本和收益之间权衡,我并没有做这个事情,因为每个DOM函数中都要插入这个代码,代价太高,其实层缩回去不缩掉也不是那么致命。包括Demo里,也没有去做这个事情。如果读者有更好的方法,请告诉我。
( y# Y1 w: N& n" T1 c这是最终的主页面的代码: & b) |9 L+ W* t3 N* \% H9 _( W, ~
<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0" ! }4 Z7 R6 u/ o7 ?( E8 P! V( n
></iframe> 2 T8 {5 e8 D2 X; t" @* G- B# ]
<script type="text/javascript"> 3 Z) F) Y4 Y9 ]) x- r8 `
function reinitIframe(){
( j2 ]5 X0 e, \/ Nvar iframe = document.getElementById("frame_content");
' D# x) U) p6 P& O( s" I# ?' |try{ 7 s( _8 d2 |5 p9 A
var bHeight = iframe.contentWindow.document.body.scrollHeight;
0 m( ?# I1 k  _var dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
2 j- _9 o! a) D: G: q, S" Ivar height = Math.max(bHeight, dHeight);
9 W/ l* ?1 f" J! ^/ qiframe.height =  height;
! _! d8 I& F" g3 e8 U& x}catch (ex){} 0 T# ~) F, k) H7 d8 g0 c3 Q
}
- R7 m$ k2 w2 f: h5 F/ Vwindow.setInterval("reinitIframe()", 200); - E/ B& K$ B- }0 Z& L0 w- g
</script>附Demo页面: 主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
您需要登录后才可以回帖 登录 | 注册


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

GMT+8, 2025-12-16 05:52 , Processed in 0.023001 second(s), 9 queries .

Powered by Discuz! X2

© 2001-2011 MinHang.CC.

回顶部