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

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

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

Rank: 9Rank: 9Rank: 9

跳转到指定楼层
1#
发表于 2011-3-15 22:12:01 |只看该作者 |倒序浏览
通过Google搜索iframe 自适应高度,结果5W多条,搜索iframe 高度自适应,结果2W多条。
+ V2 }$ o5 f# e我翻了前面的几十条,刨去大量的转载,有那么三五篇是原创的。而这几篇原创里面,基本上只谈到如何自适应静的东西,就是没有考虑到JS操作DOM之后,如何做动态同步的问题。另外,在兼容性方面,也研究的不彻底。 ' u9 _1 i8 h: E  a! Z* t
这篇文章,希望在这两个方面再做一些深入。
% y& O2 J. D  s0 E0 A可能有人还没接触到这个问题过,先说明一下,什么是高度自适应吧。所谓iframe高度自适应,就是,基于界面美观和交互的考虑,隐藏了iframe的border和scrollbar,让人看不出它是个iframe。如果iframe始终调用同一个固定高度的页面,我们直接写死iframe高度就可以了。而如果iframe要切换页面,或者被包含页面要做DOM动态操作,这时候,就需要程序去同步iframe高度和被包含页的实际高度了。
  E2 Q+ \! }0 Z+ T) J! _9 m顺便说下,iframe在迫不得已的时候才去用,它会给前端开发带来太多的麻烦。 ' P+ p+ c$ I( v
传统做法大致有两个:
; E4 i& N" D! y- L5 o, h7 w( D方法一,在每个被包含页在本身内容加载完毕之后,执行JS取得本页面的高度,然后去同步父页面的iframe高度。
8 ]) \$ h' c8 G方法二,在主页面iframe的onload事件中执行JS,去取得被包含页的高度内容,然后去同步高度。
: l- C8 B  F* K在代码维护角度考虑,方法二是优于方法一的,因为方法一,每个被包含页都要去引入一段相同的代码来做这个事情,创建了好多副本。
3 B5 ]- x7 V6 l/ X' Z两个方法都只处理了静的东西,就是只在内容加载的时候执行,如果JS去操作DOM引起的高度变化,都不太方便。
! T2 n8 q' `/ [7 a* N; J如果在主窗口做一个Interval,不停的来获取被包含页的高度,然后做同步,是不是即方便,又解决了JS操作DOM的问题了呢?答案是肯定的。 1 V& z- T; m% H7 q- ^# Q
Demo页面:主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html ; p7 ?- b, G1 f% g; t  L
主页面代码示例:
% T' C$ @/ f( b) u+ {; G<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0"></iframe> ! j) U5 f8 l  f7 h
<script type="text/javascript"> 6 o8 ?9 K: q' X, A6 A
function reinitIframe(){
8 f! e5 X7 {5 qvar iframe = document.getElementById("frame_content"); + n3 |3 T3 ]6 c+ p/ h1 N
try{
! L/ I! S) Y) a, l* L; aiframe.height =  iframe.contentWindow.document.documentElement.scrollHeight; ; ^/ {: g, X2 y
}catch (ex){}
2 L1 L8 U4 Y# h0 C* R} : z5 C' m* `; b# Y$ a: [
window.setInterval("reinitIframe()", 200);   x! ~& H* q/ g. y
</script>一直执行,效率会不会有问题?
2 s* [+ ?0 ]1 ^: r  I# ~9 U我做了测试,同时开5个窗口(IE6、IE7、FF、Opera、Safari)执行这个代码,不会对CPU有什么影响,甚至调整到2ms,也没影响(基本维持在0%占用率)。
5 \, J# |7 i  h; A  e下面谈谈各浏览器的兼容性问题,如何获取到正确的高度,主要是对body.scrollHeight和documentElement.scrollHeight两个值得比较。注意本文用的是这个doctype,不同的doctype应该不会影响结果,但是假如你的页面没有申明doctype,那还是先去加一个吧。
2 H" {& V" [3 e2 j/ _5 _, T<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">在主页面追加以下测试代码,以输出这两个值,代码示例:
2 o1 y; k/ ^3 o: ]4 ~/ K5 v<div><button >Check Height</button></div>
( r5 {6 z3 Q$ B7 E5 M<script type="text/javascript"> 4 C0 O- ~8 k9 E1 ~6 i
function checkHeight() {
4 z6 c3 `3 B7 S- A3 S/ rvar iframe = document.getElementById("frame_content"); / |" U) D# q; F8 ]% c& m
var bHeight = iframe.contentWindow.document.body.scrollHeight;
6 u/ \! d: [& `8 R4 O7 o; G7 \var dHeight = iframe.contentWindow.document.documentElement.scrollHeight; 1 ?; W# a* a5 b4 `
alert("bHeight:" + bHeight + ", dHeight:" + dHeight); ! q! T7 g, |0 N/ \
} 9 X8 y: ]" f/ @- L1 S( g& B
</script>被加载页面,可以切换一个绝对定位的层,来使页面高度动态改变。如果层展开,则会撑高页面高度。代码示例:
4 i0 L- [/ `& {) i( G9 t: N<div> ; b7 m/ W) x& `% y9 L, R
<button >Toggle Overlay</button>
7 h8 n( T! W6 V* {  `</div>
. o  q4 O' O) o<div style="height:160px;position:relative">
7 u5 k7 Z$ [, v' K" h4 c  s1 K<div id="overlay" style="position:absolute;width:280px;height:280px;display:none;"></div> . a% ?; g" S! H
</div>
" Z1 P# x5 \0 R: _' f' j. H<script type="text/javascript"> 3 ^/ o3 h  }  E
function toggleOverlay() { 9 V/ {2 X1 @7 u1 h! C
var overlay = document.getElementById('overlay');
9 Z: o# S' n, Doverlay.style.display = (overlay.style.display == 'none') ? 'block' : 'none'; 5 K/ B! z+ y- ]" `# T6 r1 T) j
}
0 N* N$ x; T5 j) B! F</script>下面列出以上代码在各浏览器的测试值:
5 j' S# j2 M9 q( w  @7 ](bHeight = body.scrollHeight, dHeight = documentElement.scrollHeight, 红色 = 错误值, 绿色 = 正确值) ; V# o9 K+ S# f( \
/ 层隐藏时 层展开时
+ h  s$ S! O& UbHeight dHeight bHeight dHeight $ h( [9 n+ N' j" m
IE6 184 184 184 303 ; I  [( o8 d6 i1 ~1 a
IE7 184 184 184 303 7 a( y! M+ i% ^9 Z
FF 184 184 184 303
3 C0 b) q8 l3 n, a9 V2 aOpera 181 181 300 300
4 U+ w: q8 {4 \$ |8 a7 Y- h, qSafari 184 184 303 184
. P  f8 e7 X- z* V, X& f# K* L暂且无视Opera比别人少3像素的问题…可以看出,如果没有绝对定位的东西,两个值是相等的,取哪个都无所谓。 ( R5 S5 U. y- X! i
但是如果有,那么各个浏览器的表现不太相同,单取哪个值都不对。但可以找到了一条规律,那就是取两个值得最大值可以兼容各浏览器。所以我们的主页面代码就要改造成这样了:
. H6 w1 q. h' t5 Rfunction reinitIframe(){
- v; T# s( |3 y% J7 A" Yvar iframe = document.getElementById("frame_content"); + s/ g: D0 u& m, Z
try{
5 h) s0 c, w; C/ Svar bHeight = iframe.contentWindow.document.body.scrollHeight; 9 G' @/ ]6 N# j# P8 j; [
var dHeight = iframe.contentWindow.document.documentElement.scrollHeight; 6 n% J; ^- `) D. u9 y% v% W
var height = Math.max(bHeight, dHeight);
- N: I& G3 i$ P6 E6 Z! x* Y1 ziframe.height =  height;
- P2 U, d6 z- a}catch (ex){} $ G( P6 L; A9 \7 C- \* K$ h( ]* d
} * W/ M. x2 c1 G6 W
window.setInterval("reinitIframe()", 200);这样子,基本解决了兼容性问题。顺便说下,不光绝对定位的层会影响到值,float也会导致两个值的差异。 6 c0 h3 k3 Y5 U; q7 U6 D6 h) z
如果你演示Demo后,会发现,除了IE,其他浏览器中,当层展开后再隐藏,取到的高度值还是维持在展开的高度303,而非隐藏回去的真正值184,就是说长高了之后缩不回去了。这个现象在不同被包含页面之间做切换也会发生,当从高的页面切换到矮页面的时候,取到的高度还是那个高的值。 ) B& J3 {3 I( [4 e- z; H3 |
可以归纳为,当iframe窗体高度高于文档实际高度的时候,高度取的是窗体高度,而当窗体高度低于实际文档高度时,取的是文档实际高度。因此,要想办法在同步高度之前把高度设置到一个比实际文档低的值。所以,在iframe的添加 onload=”this.height=100″,让页面加载的时候先缩到足够矮,然后再同步到一样的高度。
1 j6 u9 \: M* Z" x9 s& h这个值,在实际应用中决定,足够矮但又不能太矮,否则在FF等浏览器里会有很明显的闪烁。DOM操作的时候主页面无法监听到,只能DOM操作完了之后把高度变小了。
. k/ h0 n7 I" k& J6 x' i. B在我的一个实际项目中,在成本和收益之间权衡,我并没有做这个事情,因为每个DOM函数中都要插入这个代码,代价太高,其实层缩回去不缩掉也不是那么致命。包括Demo里,也没有去做这个事情。如果读者有更好的方法,请告诉我。
+ P2 p  d7 b- k这是最终的主页面的代码:
" H) y( P- L- f2 q) m! _1 b<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0"
, A' k9 }6 F& W- F: i></iframe>
8 d5 k5 N  X0 `" S: }2 R  o<script type="text/javascript">
% b0 ^' C" {, @  g2 w: u+ O. q# J/ bfunction reinitIframe(){
: z* ]. n4 a4 c- S7 L. Vvar iframe = document.getElementById("frame_content");   {" \! d; N- z0 M$ Z
try{ ( E. h# w+ g% }! s
var bHeight = iframe.contentWindow.document.body.scrollHeight;
/ o6 I9 Y9 p5 M, s9 t# G$ U( ]var dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
2 ~# u1 `$ k) @: \4 M' s' yvar height = Math.max(bHeight, dHeight);
* b" t0 s. R! [- S, oiframe.height =  height; 9 M9 O1 L1 _+ }4 G7 w
}catch (ex){}
- x  }) n# w2 U) h}
% b! R& T) A. Rwindow.setInterval("reinitIframe()", 200);
  s& g3 b( c$ @+ P</script>附Demo页面: 主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
您需要登录后才可以回帖 登录 | 注册


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

GMT+8, 2025-6-19 13:50 , Processed in 0.023001 second(s), 9 queries .

Powered by Discuz! X2

© 2001-2011 MinHang.CC.

回顶部