使用jQuery動態調整iframe高度,以及jQuery對dom元素的監聽

  你們可能會遇到子頁面內容較多但iframe高度不夠的狀況。給iframe設置scrolling="no"的話子頁面內容顯示不全,不設置又會出現滾動條從而影響美觀。當咱們點擊不一樣的菜單讓iframe加載不一樣的html文件時,iframe的高度就須要作相應的調整。html

主體思路:子頁面加載完成後根據具體body的高度給iframe設置一個適合的高度

狀況1:各個子頁面內容與高度比較固定

<script>
$(function(){
  $("#Frame_Content").load(function(){
    var frame_content = $(this);
    //獲取子頁面body的高度 並適量增長
    var mainheight = frame_content.contents().find("body").height()+30;
    //給iframe設置高度(不低於350)
    frame_content.height(Math.max(mainheight,350));
  });
});
</script>
<iframe class="main" onload="this.height=350" frameborder="0" scrolling="no" id="Frame_Content" name="content"></iframe>

  這樣每次加載完子頁面,就能夠根據實際的內容來給iframe設置相應的高度。jquery

 

狀況2:子頁面自己內容在不斷變化

  有的狀況下,子頁面發起Ajax請求,從後臺拿到新的數據後增長或減小子頁面的內容,若是隻是在iframe load完成後設定好高度依然沒辦法真正地動態調整。到這裏,我想你們確定第一反應是使用監聽事件。若是能夠對子頁面body的高度進行監聽,那麼每當內容有所調整的時候觸發事件並對iframe的高度進行設置。不過這裏有個問題,window對象有onresize事件,但普通的dom元素是沒有的,也就是說想監聽也沒辦法監聽。想要解決這個問題,兩條路擺在咱們面前:segmentfault

1.寫一個輪詢來不停的獲取子頁面body的高度,若是發生了變化就給iframe高度賦新的值;  

 

2.利用jquery的事件機制來模擬一個普通元素上的resize事件。(固然只要能實現resize事件,怎麼弄均可以,這裏只說jquery)

  仔細來看,其實1和2的原理是同樣的,事件監聽本質上其實應該也是輪詢。但完整的事件機制確定是比咱們本身去寫一個輪詢要成熟的,並且適用全部的dom元素,若是本身寫個輪詢確定能作的事就很單一,只有針對性的功能。由於我這裏的頁面只有一個主iframe,外面就一個框架,橫向的主菜單和左側縱向的二級、三級菜單,頁面的主要內容都在iframe根據不一樣菜單加載的子頁面裏,等於說只要把惟一的iframe高度調整ok就行。這裏咱們不妨先簡單搞一個輪詢:app

<script>
$(function(){
    var timer;
    $("#Frame_Content").load(function(){
        if (timer){
            clearInterval(timer);
        }
        //pre_height用於記錄上次檢查時body的高度
        //mainheight用於獲取本次檢查時body的高度,並賦予iframe的高度
        var mainheight,pre_height;
        var frame_content = $(this);
        timer = setInterval(function(){
            mainheight = frame_content.contents().find("body").height() + 30;
            if (mainheight != pre_height){
                pre_height = mainheight;
                frame_content.height(Math.max(mainheight,350));
             }
        },500);//每0.5秒檢查一次
    });
});
</script>

  若是場景比較簡單,一個輪詢就能夠搞定iframe動態調整高度的問題,比起本身寫一個jquery的插件來實現resize事件確定要輕量不少。但這樣的作法畢竟是不夠完善的,若是有的頁面須要對多個dom元素(不侷限於iframe)的高度進行監聽,搞不少輪詢看起來可能很不規範,同時也不便於管理。框架

  http://www.javashuo.com/article/p-gydxbqac-bs.html這篇文章裏提到一個插件已經實現了上述的功能,並貼出了核心代碼。代碼長度很短也很簡單,感興趣的話能夠研究一下,實際上插件也是使用輪詢來不斷地檢查所須要監聽的dom元素的高度和寬度,我也在下面貼出來:dom

(function($, window, undefined) {
  var elems = $([]),
    jq_resize = $.resize = $.extend($.resize, {}),
    timeout_id,
    str_setTimeout = 'setTimeout',
    str_resize = 'resize',
    str_data = str_resize + '-special-event',
    str_delay = 'delay',
    str_throttle = 'throttleWindow';
  jq_resize[str_delay] = 250;
  jq_resize[str_throttle] = true;
  $.event.special[str_resize] = {
    setup: function() {
      if (!jq_resize[str_throttle] && this[str_setTimeout]) {
        return false;
      }
      var elem = $(this);
      elems = elems.add(elem);
      $.data(this, str_data, {
        w: elem.width(),
        h: elem.height()
      });
      if (elems.length === 1) {
        loopy();
      }
    },
    teardown: function() {
      if (!jq_resize[str_throttle] && this[str_setTimeout]) {
        return false;
      }
      var elem = $(this);
      elems = elems.not(elem);
      elem.removeData(str_data);
      if (!elems.length) {
        clearTimeout(timeout_id);
      }
    },
    add: function(handleObj) {
      if (!jq_resize[str_throttle] && this[str_setTimeout]) {
        return false;
      }
      var old_handler;
      function new_handler(e, w, h) {
        var elem = $(this),
          data = $.data(this, str_data);
        data.w = w !== undefined ? w : elem.width();
        data.h = h !== undefined ? h : elem.height();
        old_handler.apply(this, arguments);
      }
      if ($.isFunction(handleObj)) {
        old_handler = handleObj;
        return new_handler;
      } else {
        old_handler = handleObj.handler;
        handleObj.handler = new_handler;
      }
    }
  };

  function loopy() {
    timeout_id = window[str_setTimeout](function() {
      elems.each(function() {
        var elem = $(this),
          width = elem.width(),
          height = elem.height(),
          data = $.data(this, str_data);
        if (width !== data.w || height !== data.h) {
          elem.trigger(str_resize, [data.w = width, data.h = height]);
        }
      });
      loopy();
    }, jq_resize[str_delay]);
  }
})(jQuery, this);
View Code

 

  jquery的事件機制和插件的寫法這裏就不具體解析了,網上搜一下均可以找到。這方面我也沒有深刻的學習,不過只要瞭解一下要點就能看明白上面的插件代碼了。ide

  不想了解,也能夠直接拿來用:函數

//bind resize事件
$("body").bind('resize',function(){
    //callback
    //...
    //...
});

 

ps:

  正常狀況下對頁面中的dom元素高寬進行監聽使用上面的插件應該是沒什麼問題的,但若是有和我同樣是對iframe子頁面的body進行監聽可能會遇到報錯。oop

  看過插件的源碼後,會發現當咱們對n個dom元素bind resize事件時,實際上有一個隊列,輪詢中會對隊列的每個元素都檢查高寬有沒有變化,若是高寬改變了就觸發resize事件,從而執行咱們本身定義的回調函數。unbind後會把相應的元素從隊列中踢掉。我這裏的場景是,每一個菜單項的target都指向同一個iframe,點擊不一樣的菜單項主iframe加載不一樣的頁面。我在iframe完成load的時候給子頁面的body bind resize事件。當切換菜單時,新的子頁面加入隊列,但老的子頁面此時已經不存在了,遍歷隊列去取對應元素的高寬就會出錯。對插件的源碼進行修改能夠解決這個問題,但我我的認爲爲了這個單一的目的去修改插件的源碼還不如最初的時候就用一個簡單的輪詢搞定。因此不改源碼的狀況下,建議把bind放到子頁面中去作,回調中調用父頁面的接口來給iframe高度賦值。學習

相關文章
相關標籤/搜索