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

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

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

Rank: 9Rank: 9Rank: 9

跳转到指定楼层
1#
发表于 2011-3-15 22:12:01 |只看该作者 |倒序浏览
通过Google搜索iframe 自适应高度,结果5W多条,搜索iframe 高度自适应,结果2W多条。
2 Z3 W# t. ~. [; c  A我翻了前面的几十条,刨去大量的转载,有那么三五篇是原创的。而这几篇原创里面,基本上只谈到如何自适应静的东西,就是没有考虑到JS操作DOM之后,如何做动态同步的问题。另外,在兼容性方面,也研究的不彻底。 8 S; J( V& o& R) _( ]9 e5 ]
这篇文章,希望在这两个方面再做一些深入。
& s4 B' E1 x) B# f4 w3 O3 x可能有人还没接触到这个问题过,先说明一下,什么是高度自适应吧。所谓iframe高度自适应,就是,基于界面美观和交互的考虑,隐藏了iframe的border和scrollbar,让人看不出它是个iframe。如果iframe始终调用同一个固定高度的页面,我们直接写死iframe高度就可以了。而如果iframe要切换页面,或者被包含页面要做DOM动态操作,这时候,就需要程序去同步iframe高度和被包含页的实际高度了。 : p# z6 ^; E& e7 W2 }$ B) [# ^" s
顺便说下,iframe在迫不得已的时候才去用,它会给前端开发带来太多的麻烦。 5 y/ h0 ?: L: d( s
传统做法大致有两个: 4 l8 T3 D2 D, U1 H/ O1 E4 s3 e
方法一,在每个被包含页在本身内容加载完毕之后,执行JS取得本页面的高度,然后去同步父页面的iframe高度。
# |9 r2 j. \6 }! s; N1 w% i" u方法二,在主页面iframe的onload事件中执行JS,去取得被包含页的高度内容,然后去同步高度。 8 ?8 F, |5 s  ~% H# W9 m6 ~6 ]
在代码维护角度考虑,方法二是优于方法一的,因为方法一,每个被包含页都要去引入一段相同的代码来做这个事情,创建了好多副本。 - A' q1 S( |6 j' |' C) R9 h3 B
两个方法都只处理了静的东西,就是只在内容加载的时候执行,如果JS去操作DOM引起的高度变化,都不太方便。
* G7 W! L7 M, b' U如果在主窗口做一个Interval,不停的来获取被包含页的高度,然后做同步,是不是即方便,又解决了JS操作DOM的问题了呢?答案是肯定的。
8 {) b& r, N9 j, B$ S  E% c' dDemo页面:主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
  r' x7 [# R$ U# @! J主页面代码示例: . `6 D3 W7 X( D& i& r
<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0"></iframe> $ j9 @: b; ^9 p: E
<script type="text/javascript">
! M  I. t# I* V3 |( }* K, G( y1 D; ufunction reinitIframe(){ : x4 H3 S/ j/ N# V
var iframe = document.getElementById("frame_content"); - v, m8 A; c  C8 D( q: `
try{ . F& {) j  w: D" E  c
iframe.height =  iframe.contentWindow.document.documentElement.scrollHeight; 0 r* U* L$ F/ s! }, L' o
}catch (ex){}
1 I' M0 q: N$ [% o. _}
/ q0 C) z7 _1 Y& F: _! Qwindow.setInterval("reinitIframe()", 200);
( P, R) w% }' P! W3 {3 D</script>一直执行,效率会不会有问题?
1 W' M# T( U3 o) q2 M我做了测试,同时开5个窗口(IE6、IE7、FF、Opera、Safari)执行这个代码,不会对CPU有什么影响,甚至调整到2ms,也没影响(基本维持在0%占用率)。
, l; _  h' i+ b/ O+ i  [) S下面谈谈各浏览器的兼容性问题,如何获取到正确的高度,主要是对body.scrollHeight和documentElement.scrollHeight两个值得比较。注意本文用的是这个doctype,不同的doctype应该不会影响结果,但是假如你的页面没有申明doctype,那还是先去加一个吧。
  u/ C- R* q. y" Y2 p  ^9 L<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">在主页面追加以下测试代码,以输出这两个值,代码示例: $ C. a2 l% V$ A( Q" E/ g
<div><button >Check Height</button></div> $ y' h# o9 s1 T
<script type="text/javascript"> ) N/ M) m& o$ G0 b( O
function checkHeight() {
; o: g6 b* F) W$ x2 `7 Y3 n/ b+ yvar iframe = document.getElementById("frame_content");
2 H; N, B, ]1 }& y* k5 e7 _% Kvar bHeight = iframe.contentWindow.document.body.scrollHeight;
! v1 ^0 a$ C% i9 u3 C+ q4 xvar dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
  G/ U2 i" F9 _4 b3 Lalert("bHeight:" + bHeight + ", dHeight:" + dHeight);
' k( B2 P4 ^* P+ T& C8 J9 v} ( o8 C1 U& }* [/ g2 M+ P) ^. h$ c
</script>被加载页面,可以切换一个绝对定位的层,来使页面高度动态改变。如果层展开,则会撑高页面高度。代码示例: 9 o) g  Q* _" p. b( P- X
<div> 0 G  b3 [1 K% V! A/ o" o! a
<button >Toggle Overlay</button> " [. r  i: j+ w* r8 ~
</div>
9 l: s0 ]4 l  K" r4 q0 x<div style="height:160px;position:relative"> ( N! G# H* \$ ~' f6 N# L( L' l
<div id="overlay" style="position:absolute;width:280px;height:280px;display:none;"></div> / }' x+ ^+ I1 C* e: C* d% \' c
</div> ) W/ S7 ?: b, B4 K1 ~
<script type="text/javascript">
$ b# e' O& n7 a* pfunction toggleOverlay() { * G: m6 Z! q6 W% H( I7 }. j5 k
var overlay = document.getElementById('overlay'); ) `) K; `; R$ D( i: X$ \8 x
overlay.style.display = (overlay.style.display == 'none') ? 'block' : 'none';
, ?% E  t+ p* P. t! N. |+ V} 9 x) A$ @- O% [, K3 l5 q5 d- C% D& \
</script>下面列出以上代码在各浏览器的测试值: 6 g$ b1 F- p; Q- I) y
(bHeight = body.scrollHeight, dHeight = documentElement.scrollHeight, 红色 = 错误值, 绿色 = 正确值) & R! c1 n, N% c& b& E- |, W
/ 层隐藏时 层展开时
0 l! E7 o( ]" W7 h- o/ N8 pbHeight dHeight bHeight dHeight ( `4 m1 N( s" |7 c1 `
IE6 184 184 184 303
8 K/ }  X/ U* J$ S! qIE7 184 184 184 303 0 d( P  t( g( |( x6 d/ \
FF 184 184 184 303 3 f$ M  d5 @/ I' P
Opera 181 181 300 300
1 C( Q* z- p/ f8 v: t* rSafari 184 184 303 184
0 C% d% x! s2 M: ~" G' y3 ^暂且无视Opera比别人少3像素的问题…可以看出,如果没有绝对定位的东西,两个值是相等的,取哪个都无所谓。
* Y4 N) @" g: b, v0 o& Y但是如果有,那么各个浏览器的表现不太相同,单取哪个值都不对。但可以找到了一条规律,那就是取两个值得最大值可以兼容各浏览器。所以我们的主页面代码就要改造成这样了: + ]% x" o$ v6 M4 X; ~) `& x
function reinitIframe(){ 7 \$ P$ g0 W( u* p) z! P
var iframe = document.getElementById("frame_content");
2 t* ]. k& g/ q% M* P2 u6 q5 A% Itry{ 1 B! ~3 _& x( E  ?; A  ~
var bHeight = iframe.contentWindow.document.body.scrollHeight; $ S' |% A: w* J2 B# m' k
var dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
2 v  m% V1 [) b9 e* Nvar height = Math.max(bHeight, dHeight); ; |, i5 b5 |5 ~7 _) R( X
iframe.height =  height; ) _& A) h' _. L8 u  d, Y- H% H
}catch (ex){} , C% y3 \9 r6 U
} - J+ w1 r) x( Y
window.setInterval("reinitIframe()", 200);这样子,基本解决了兼容性问题。顺便说下,不光绝对定位的层会影响到值,float也会导致两个值的差异。 0 r2 p; J  d, Y7 J/ t! ]5 P) ~/ }
如果你演示Demo后,会发现,除了IE,其他浏览器中,当层展开后再隐藏,取到的高度值还是维持在展开的高度303,而非隐藏回去的真正值184,就是说长高了之后缩不回去了。这个现象在不同被包含页面之间做切换也会发生,当从高的页面切换到矮页面的时候,取到的高度还是那个高的值。 7 C9 M6 U2 ?% @0 `
可以归纳为,当iframe窗体高度高于文档实际高度的时候,高度取的是窗体高度,而当窗体高度低于实际文档高度时,取的是文档实际高度。因此,要想办法在同步高度之前把高度设置到一个比实际文档低的值。所以,在iframe的添加 onload=”this.height=100″,让页面加载的时候先缩到足够矮,然后再同步到一样的高度。
- g# o5 X- e2 u! a6 m9 D这个值,在实际应用中决定,足够矮但又不能太矮,否则在FF等浏览器里会有很明显的闪烁。DOM操作的时候主页面无法监听到,只能DOM操作完了之后把高度变小了。 ' M- A( F6 O5 M* @3 ]1 f0 }5 t1 @
在我的一个实际项目中,在成本和收益之间权衡,我并没有做这个事情,因为每个DOM函数中都要插入这个代码,代价太高,其实层缩回去不缩掉也不是那么致命。包括Demo里,也没有去做这个事情。如果读者有更好的方法,请告诉我。 + B, K: q3 P6 H+ [. Q* k
这是最终的主页面的代码: & D$ Z. V- Q; I
<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0" + u/ p4 l$ N. ?2 }( V
></iframe> 6 k+ N5 w9 O( w6 r- Y( ^
<script type="text/javascript"> 7 C; S1 R& T9 O0 |
function reinitIframe(){
$ w4 @5 t( \9 y  Uvar iframe = document.getElementById("frame_content"); 0 q; x" O0 @, |- Q7 ]) m
try{ 9 ?# A( H$ R" ~: k3 _
var bHeight = iframe.contentWindow.document.body.scrollHeight; 5 i' {  C* l# }% M+ |# c& g9 X
var dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
  {! z# J" ^) _7 R% |var height = Math.max(bHeight, dHeight); - j' U9 w! x) t3 ]6 r  Y3 b0 `
iframe.height =  height;
& E& a0 p- ]% ~}catch (ex){}
  C0 {( ]7 C" t  j} % u: y0 L) L, t0 g) U& w! D
window.setInterval("reinitIframe()", 200);
% f+ f) u# C) i6 d1 h4 L" U. T</script>附Demo页面: 主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
您需要登录后才可以回帖 登录 | 注册


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

GMT+8, 2025-10-21 16:55 , Processed in 0.022001 second(s), 9 queries .

Powered by Discuz! X2

© 2001-2011 MinHang.CC.

回顶部