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

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

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

Rank: 9Rank: 9Rank: 9

跳转到指定楼层
1#
发表于 2011-3-15 22:12:01 |只看该作者 |倒序浏览
通过Google搜索iframe 自适应高度,结果5W多条,搜索iframe 高度自适应,结果2W多条。 , b; y; H3 i* [3 C
我翻了前面的几十条,刨去大量的转载,有那么三五篇是原创的。而这几篇原创里面,基本上只谈到如何自适应静的东西,就是没有考虑到JS操作DOM之后,如何做动态同步的问题。另外,在兼容性方面,也研究的不彻底。 " {% g. m0 c* l% q5 W
这篇文章,希望在这两个方面再做一些深入。
% P5 L7 p, R  j) R# M! R可能有人还没接触到这个问题过,先说明一下,什么是高度自适应吧。所谓iframe高度自适应,就是,基于界面美观和交互的考虑,隐藏了iframe的border和scrollbar,让人看不出它是个iframe。如果iframe始终调用同一个固定高度的页面,我们直接写死iframe高度就可以了。而如果iframe要切换页面,或者被包含页面要做DOM动态操作,这时候,就需要程序去同步iframe高度和被包含页的实际高度了。
& f3 h+ r* o- @2 e4 Z& s- j- v顺便说下,iframe在迫不得已的时候才去用,它会给前端开发带来太多的麻烦。 , T  B8 x- o4 X4 e1 F
传统做法大致有两个: % A4 y) A: \2 W! R
方法一,在每个被包含页在本身内容加载完毕之后,执行JS取得本页面的高度,然后去同步父页面的iframe高度。
6 A: b1 v1 _  T1 P2 S/ I. O方法二,在主页面iframe的onload事件中执行JS,去取得被包含页的高度内容,然后去同步高度。 6 i7 `4 ^* g4 R
在代码维护角度考虑,方法二是优于方法一的,因为方法一,每个被包含页都要去引入一段相同的代码来做这个事情,创建了好多副本。 " p) v8 w9 @% E. B1 j
两个方法都只处理了静的东西,就是只在内容加载的时候执行,如果JS去操作DOM引起的高度变化,都不太方便。
0 p5 |9 ?5 ^/ s! U如果在主窗口做一个Interval,不停的来获取被包含页的高度,然后做同步,是不是即方便,又解决了JS操作DOM的问题了呢?答案是肯定的。 8 _: _. u+ X" N# M
Demo页面:主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
1 T$ [( D$ D& f6 k! T$ C主页面代码示例:
  C! a; V" x/ ]$ S; N<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0"></iframe> + k8 |0 ?  n: T5 k( M7 U# b
<script type="text/javascript"> ) x! m9 `% V6 R1 n1 a+ M' X
function reinitIframe(){ * t* J* ?3 r6 [0 m, I
var iframe = document.getElementById("frame_content"); / j0 G6 A( w0 q( f
try{
  s& u  H$ J' B+ kiframe.height =  iframe.contentWindow.document.documentElement.scrollHeight; 0 Q8 b0 A' }# U! t9 O
}catch (ex){}
4 V8 S% k2 X5 K} & @$ ?$ T& U- j1 X# `# n) i$ {
window.setInterval("reinitIframe()", 200);
1 g! b6 v- y# p</script>一直执行,效率会不会有问题? 6 S" i- ?. K9 n4 L2 I2 M" ]
我做了测试,同时开5个窗口(IE6、IE7、FF、Opera、Safari)执行这个代码,不会对CPU有什么影响,甚至调整到2ms,也没影响(基本维持在0%占用率)。
( N7 [, B1 `' a, s! S/ q; ]) k下面谈谈各浏览器的兼容性问题,如何获取到正确的高度,主要是对body.scrollHeight和documentElement.scrollHeight两个值得比较。注意本文用的是这个doctype,不同的doctype应该不会影响结果,但是假如你的页面没有申明doctype,那还是先去加一个吧。
. T0 |5 W# S% H' g' Q<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">在主页面追加以下测试代码,以输出这两个值,代码示例:
. R" g( g8 ]# H7 e: P7 `' c0 C! \" @<div><button >Check Height</button></div> ; L% i$ l4 l7 D# p
<script type="text/javascript">
8 a: t4 J$ x, E) ^' V* h9 x5 e* dfunction checkHeight() {
, w1 o: u" }1 [- e# q# h% S9 ^( q3 F: Dvar iframe = document.getElementById("frame_content"); / V* J9 k8 X+ c0 }+ ?/ D/ K
var bHeight = iframe.contentWindow.document.body.scrollHeight;   S$ e7 x$ A& O, E) W" I3 w5 Z
var dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
5 E- f- X7 z6 |9 oalert("bHeight:" + bHeight + ", dHeight:" + dHeight);
9 h5 W) C/ Z& q7 d& J2 m# `}
5 G5 a7 F, z6 H4 U" `/ U4 R</script>被加载页面,可以切换一个绝对定位的层,来使页面高度动态改变。如果层展开,则会撑高页面高度。代码示例: + N* x5 J5 B1 ^. t0 X/ ?1 a2 n
<div>
* }- t) L8 m% K$ d  W<button >Toggle Overlay</button>
7 ?; N1 v, S' z: f</div> 8 {$ i: e& `/ A: d; o7 b
<div style="height:160px;position:relative"> # ]) V4 x! |  g/ x# P: j& A
<div id="overlay" style="position:absolute;width:280px;height:280px;display:none;"></div>
7 w8 y2 k3 L4 u1 ?</div>
, [( f* v& ?' k" H" h<script type="text/javascript"> ' O; B* W7 c& M# Q
function toggleOverlay() { ' o5 M! O* f. [1 Q5 I+ U9 q7 M
var overlay = document.getElementById('overlay');
4 |+ |. E; h! C2 d' m7 Eoverlay.style.display = (overlay.style.display == 'none') ? 'block' : 'none'; - C4 ~1 }% ^* l" B& x) d
}
1 W$ h2 j% ?7 p( W( w! M+ B, ?2 J</script>下面列出以上代码在各浏览器的测试值: ; W# ?2 A% D6 W9 A  Y# D$ }, u1 j
(bHeight = body.scrollHeight, dHeight = documentElement.scrollHeight, 红色 = 错误值, 绿色 = 正确值) 7 C/ r5 \5 u: x. [
/ 层隐藏时 层展开时
+ w* u2 D* R6 g1 h$ JbHeight dHeight bHeight dHeight
; M% _0 \" C7 Z, T, A' |IE6 184 184 184 303 + E: S& Y# H- k. ?1 q: S' b& P6 D
IE7 184 184 184 303 3 A# u& M$ V7 z2 x5 u* n' ^
FF 184 184 184 303
% J: p/ r! D& h' MOpera 181 181 300 300 . }1 x, A( V9 S1 |( O# ^6 s% r
Safari 184 184 303 184
4 ]* V/ Z! A5 a  G暂且无视Opera比别人少3像素的问题…可以看出,如果没有绝对定位的东西,两个值是相等的,取哪个都无所谓。
( d. s3 [/ F8 \4 i9 A6 A但是如果有,那么各个浏览器的表现不太相同,单取哪个值都不对。但可以找到了一条规律,那就是取两个值得最大值可以兼容各浏览器。所以我们的主页面代码就要改造成这样了:
1 m& \3 ^5 ^2 b2 e* U) V) Yfunction reinitIframe(){ $ I0 ?5 @8 O1 i# F) ^' L
var iframe = document.getElementById("frame_content");
( f, A4 n4 ~6 `try{ % V5 u# P2 ^" U4 B) U8 _
var bHeight = iframe.contentWindow.document.body.scrollHeight; 5 j4 d3 L4 q" ^3 n" R6 x
var dHeight = iframe.contentWindow.document.documentElement.scrollHeight;
0 o  I: a  f' i  E' g8 Dvar height = Math.max(bHeight, dHeight); : [7 ^' @# k8 Q- ?; C& b6 U& h
iframe.height =  height;
2 N( j2 [6 ?* g' G- t* T}catch (ex){}
7 b9 w+ P% y- j} 5 ]0 b& d0 Y& k
window.setInterval("reinitIframe()", 200);这样子,基本解决了兼容性问题。顺便说下,不光绝对定位的层会影响到值,float也会导致两个值的差异。
" f+ V! }6 Z8 v3 E' R如果你演示Demo后,会发现,除了IE,其他浏览器中,当层展开后再隐藏,取到的高度值还是维持在展开的高度303,而非隐藏回去的真正值184,就是说长高了之后缩不回去了。这个现象在不同被包含页面之间做切换也会发生,当从高的页面切换到矮页面的时候,取到的高度还是那个高的值。 " f% ^$ ~1 g4 G7 v" Y
可以归纳为,当iframe窗体高度高于文档实际高度的时候,高度取的是窗体高度,而当窗体高度低于实际文档高度时,取的是文档实际高度。因此,要想办法在同步高度之前把高度设置到一个比实际文档低的值。所以,在iframe的添加 onload=”this.height=100″,让页面加载的时候先缩到足够矮,然后再同步到一样的高度。
6 \* `6 {: z7 M7 e, T9 E+ K这个值,在实际应用中决定,足够矮但又不能太矮,否则在FF等浏览器里会有很明显的闪烁。DOM操作的时候主页面无法监听到,只能DOM操作完了之后把高度变小了。 9 P  B0 o; l+ s; X2 S
在我的一个实际项目中,在成本和收益之间权衡,我并没有做这个事情,因为每个DOM函数中都要插入这个代码,代价太高,其实层缩回去不缩掉也不是那么致命。包括Demo里,也没有去做这个事情。如果读者有更好的方法,请告诉我。 * X" v, a; j+ |  f4 [  g( M* x
这是最终的主页面的代码: 2 M4 h2 Q0 C# X8 R8 h/ P
<iframe id="frame_content" src="iframe_b.html" scrolling="no" frameborder="0" 0 P( Y  W6 N% p& K
></iframe> ) B+ j2 H9 L& |) ]: z
<script type="text/javascript">
/ R$ d8 E5 a7 i+ m3 Tfunction reinitIframe(){
3 I* r/ V1 ^" x" hvar iframe = document.getElementById("frame_content"); - A. V# c+ H4 q4 W- q) G
try{
! C! p! L% P3 |; h9 I! s: h, \2 V- Bvar bHeight = iframe.contentWindow.document.body.scrollHeight; 9 q# E; ?% M) d. Y  T0 T; a
var dHeight = iframe.contentWindow.document.documentElement.scrollHeight; - a7 {% p! @; D! D
var height = Math.max(bHeight, dHeight); , o' T1 j; t2 @4 u& l. O1 f
iframe.height =  height;
+ y' Y& r' k' W( n6 A) x}catch (ex){} 7 @$ a; u, e1 p* J: x2 D8 _
}
( y7 D  h  {* dwindow.setInterval("reinitIframe()", 200); 3 n# p+ \" n. r7 t
</script>附Demo页面: 主页面 iframe_a.html ,被包含页面 iframe_b.htm 和 iframe_c.html
您需要登录后才可以回帖 登录 | 注册


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

GMT+8, 2025-11-27 01:21 , Processed in 0.022001 second(s), 9 queries .

Powered by Discuz! X2

© 2001-2011 MinHang.CC.

回顶部