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

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

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

Rank: 9Rank: 9Rank: 9

跳转到指定楼层
1#
发表于 2011-3-15 22:12:01 |只看该作者 |倒序浏览
通过Google搜索iframe 自适应高度,结果5W多条,搜索iframe 高度自适应,结果2W多条。
; M- A1 y% p9 h我翻了前面的几十条,刨去大量的转载,有那么三五篇是原创的。而这几篇原创里面,基本上只谈到如何自适应静的东西,就是没有考虑到JS操作DOM之后,如何做动态同步的问题。另外,在兼容性方面,也研究的不彻底。
' L% N; e8 k# R9 e; ^0 l* o这篇文章,希望在这两个方面再做一些深入。
5 K& q8 j% v& \" H6 Q' L可能有人还没接触到这个问题过,先说明一下,什么是高度自适应吧。所谓iframe高度自适应,就是,基于界面美观和交互的考虑,隐藏了iframe的border和scrollbar,让人看不出它是个iframe。如果iframe始终调用同一个固定高度的页面,我们直接写死iframe高度就可以了。而如果iframe要切换页面,或者被包含页面要做DOM动态操作,这时候,就需要程序去同步iframe高度和被包含页的实际高度了。
$ w' c- Z% S+ j! J6 k' l% y7 N/ d1 R顺便说下,iframe在迫不得已的时候才去用,它会给前端开发带来太多的麻烦。
! Z2 S' y( T: x! {( r7 O/ F# }# P传统做法大致有两个: 2 c) v4 u. w, |) o
方法一,在每个被包含页在本身内容加载完毕之后,执行JS取得本页面的高度,然后去同步父页面的iframe高度。
5 _: d) P3 P) p- w& x, n方法二,在主页面iframe的onload事件中执行JS,去取得被包含页的高度内容,然后去同步高度。
$ U2 L' P/ c; ?在代码维护角度考虑,方法二是优于方法一的,因为方法一,每个被包含页都要去引入一段相同的代码来做这个事情,创建了好多副本。
' O  d# h+ R0 B! q8 ?! \两个方法都只处理了静的东西,就是只在内容加载的时候执行,如果JS去操作DOM引起的高度变化,都不太方便。 * @: x/ w2 b( f* p
如果在主窗口做一个Interval,不停的来获取被包含页的高度,然后做同步,是不是即方便,又解决了JS操作DOM的问题了呢?答案是肯定的。 4 R" P  J4 a6 u0 G2 |* v" y
Demo页面:主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
# I+ v# w4 Z3 q% A2 K主页面代码示例:
) [9 N( `& B9 Z/ Y) N1 u  x<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0"></iframe>
8 D5 L: ]5 |$ F<script type="text/javascript">   F) f: k5 E2 K! F1 N7 M# W9 V
function reinitIframe(){   `* e/ T  o% x( l9 `+ V* z
var iframe = document.getElementById("frame_content"); 9 G8 g9 p- `* ~# s7 N  ]
try{
, }. A6 M4 \2 p6 v2 piframe.height =  iframe.contentWindow.document.documentElement.scrollHeight;
( A* w) p, j# ]! B- L; b5 {, V0 N- _}catch (ex){} ; }4 \. r1 |: d. _& r
}
! P7 P) G! e( S1 ~" b# J! N) owindow.setInterval("reinitIframe()", 200);
! A% v/ v7 t* K5 g* f8 t, U</script>一直执行,效率会不会有问题?
) F) N! M# N! i: k我做了测试,同时开5个窗口(IE6、IE7、FF、Opera、Safari)执行这个代码,不会对CPU有什么影响,甚至调整到2ms,也没影响(基本维持在0%占用率)。 ; y: p/ J" s8 w* V- n
下面谈谈各浏览器的兼容性问题,如何获取到正确的高度,主要是对body.scrollHeight和documentElement.scrollHeight两个值得比较。注意本文用的是这个doctype,不同的doctype应该不会影响结果,但是假如你的页面没有申明doctype,那还是先去加一个吧。
1 p# i6 B+ ^. E7 S# M6 R: F<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">在主页面追加以下测试代码,以输出这两个值,代码示例: 5 s6 r+ m: _' ?, |/ m6 p; M
<div><button >Check Height</button></div>
' @# J/ ~$ d& p0 @# q. g( D<script type="text/javascript">
- x" E3 t$ ~: Y* h6 Ffunction checkHeight() { 3 g) X9 ^; G& P3 j5 p
var iframe = document.getElementById("frame_content");
* `9 P; y5 _; n2 q) i. d4 Y' Mvar bHeight = iframe.contentWindow.document.body.scrollHeight; # D. p% ^- G5 R, W; g
var dHeight = iframe.contentWindow.document.documentElement.scrollHeight; : S7 e- q% X- _6 O$ Y
alert("bHeight:" + bHeight + ", dHeight:" + dHeight);
$ Y* L' U, I6 P, q  H} % {' ^  j5 u: g5 g% U  F3 A, Z
</script>被加载页面,可以切换一个绝对定位的层,来使页面高度动态改变。如果层展开,则会撑高页面高度。代码示例: $ S$ _, r9 d' y  t0 I& F- E+ Y
<div>
/ _- k8 ?: h7 J' a# z<button >Toggle Overlay</button> 5 w- ~+ }6 c2 u4 m0 m7 Y( Z
</div> . J: a7 V! y! p$ K
<div style="height:160px;position:relative">
% A8 W+ |% J5 p4 r/ p<div id="overlay" style="position:absolute;width:280px;height:280px;display:none;"></div>
9 l8 a7 E- \. B$ F) j</div> ( Z; G4 S, V/ p8 N% {$ ~
<script type="text/javascript">
5 p" s6 C9 ^7 C  g  O. gfunction toggleOverlay() {
7 X. @7 i+ h  ~* J' Cvar overlay = document.getElementById('overlay'); 9 ^7 F2 N' S+ V  ?: X. r
overlay.style.display = (overlay.style.display == 'none') ? 'block' : 'none';
: \- L( ]. A. u- a" p  F! R7 c}
( ]- B8 i4 r6 r, W* m3 q</script>下面列出以上代码在各浏览器的测试值:
" K( s% `+ l' g6 w(bHeight = body.scrollHeight, dHeight = documentElement.scrollHeight, 红色 = 错误值, 绿色 = 正确值) % t( |: s, v) g8 _4 \; u$ {( p0 b& N
/ 层隐藏时 层展开时
* {' @3 _( y+ {2 _! I' X5 R! ?bHeight dHeight bHeight dHeight " w( ~7 \& R4 J- W* a: e
IE6 184 184 184 303
6 Z/ \" v1 z1 i1 \" k7 @6 Q- eIE7 184 184 184 303
& M, J% n; e5 hFF 184 184 184 303
( R  x) u# S0 JOpera 181 181 300 300
! {1 _9 l/ X# K8 iSafari 184 184 303 184 * i6 `. r; c' ^
暂且无视Opera比别人少3像素的问题…可以看出,如果没有绝对定位的东西,两个值是相等的,取哪个都无所谓。
3 I- `0 E& u1 c' P1 V但是如果有,那么各个浏览器的表现不太相同,单取哪个值都不对。但可以找到了一条规律,那就是取两个值得最大值可以兼容各浏览器。所以我们的主页面代码就要改造成这样了:
; b2 _9 T4 B5 K. v6 g$ z1 \! Qfunction reinitIframe(){ + C. @* x% p5 x
var iframe = document.getElementById("frame_content");
  Z0 G$ J0 u  K4 l* etry{ 9 _* M: U( z( k/ s/ l
var bHeight = iframe.contentWindow.document.body.scrollHeight; ) t% a$ ~5 r' G+ e# T
var dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
0 ~' P, d: p% i1 S5 K0 Z. P" ovar height = Math.max(bHeight, dHeight);
2 J0 u8 x# E+ V) J3 p3 Uiframe.height =  height;
$ |0 }) S% v- a3 s( x}catch (ex){} 2 C3 b% I8 y* k7 w- W9 r9 i
} ' b. `+ y0 Q; t: P! h. t
window.setInterval("reinitIframe()", 200);这样子,基本解决了兼容性问题。顺便说下,不光绝对定位的层会影响到值,float也会导致两个值的差异。 ) Z$ G7 F$ q. e, F+ F
如果你演示Demo后,会发现,除了IE,其他浏览器中,当层展开后再隐藏,取到的高度值还是维持在展开的高度303,而非隐藏回去的真正值184,就是说长高了之后缩不回去了。这个现象在不同被包含页面之间做切换也会发生,当从高的页面切换到矮页面的时候,取到的高度还是那个高的值。 . M" n! i, l& l; R/ R% L
可以归纳为,当iframe窗体高度高于文档实际高度的时候,高度取的是窗体高度,而当窗体高度低于实际文档高度时,取的是文档实际高度。因此,要想办法在同步高度之前把高度设置到一个比实际文档低的值。所以,在iframe的添加 onload=”this.height=100″,让页面加载的时候先缩到足够矮,然后再同步到一样的高度。
7 P5 G- z# R4 t; T" M2 o9 u" f这个值,在实际应用中决定,足够矮但又不能太矮,否则在FF等浏览器里会有很明显的闪烁。DOM操作的时候主页面无法监听到,只能DOM操作完了之后把高度变小了。 * N8 r' v# [6 F% _
在我的一个实际项目中,在成本和收益之间权衡,我并没有做这个事情,因为每个DOM函数中都要插入这个代码,代价太高,其实层缩回去不缩掉也不是那么致命。包括Demo里,也没有去做这个事情。如果读者有更好的方法,请告诉我。 & }' |. p! S; b) R$ W9 D
这是最终的主页面的代码: % `* D0 V) ?; Q) L  L
<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0"
- X! b5 y4 a) @9 o. U# [6 \% ~3 w: O></iframe> 4 W4 y6 r" y4 D5 A+ L
<script type="text/javascript"> 9 A6 {4 w" o, \6 Q1 J3 w
function reinitIframe(){
. O: U$ i8 p+ ?3 Z& K5 Qvar iframe = document.getElementById("frame_content");
, x! r! g9 j9 D- Z7 t' Y4 n/ i9 Itry{
5 ~  t& l) p6 x9 w0 j) T' g5 J" ?3 _  rvar bHeight = iframe.contentWindow.document.body.scrollHeight;
8 J1 @6 {8 e9 ^& Y, `5 [9 wvar dHeight = iframe.contentWindow.document.documentElement.scrollHeight; - ]  d( Z+ L) K+ d  j7 l. A4 X+ _
var height = Math.max(bHeight, dHeight);
: z  E  p1 \  d/ \" b5 jiframe.height =  height;
- E% I/ e9 @# N* ~6 T}catch (ex){} ! z$ q' L* \$ ~  r  ~8 ^. _8 H/ E9 ~
}
1 O/ d$ P  d) c( Z  c/ Owindow.setInterval("reinitIframe()", 200); : e& k7 U/ P1 U3 Q) r. L9 s% W
</script>附Demo页面: 主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
您需要登录后才可以回帖 登录 | 注册


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

GMT+8, 2024-6-9 06:08 , Processed in 0.031201 second(s), 10 queries .

Powered by Discuz! X2

© 2001-2011 MinHang.CC.

回顶部