2012-04-17 75 views
13

我有一個包含N列的Html/JavaScript應用程序,它需要足夠大,包含所有列中所有可能的LI元素。JavaScript不調整UL元素的高度有時使用Jquery插入LI元素

簡單的解決方案似乎計算每列中所有項目的高度,補償填充,然後將高度設置爲每個列的總數。

當LI元素包含純文本時,這很有用。不幸的是,當LI元素包含圖像時,各種瀏覽器都有問題。例如,當我第一次在FireFox中加載頁面時,它看起來像下面的屏幕截圖,但在另一次刷新時,它工作正常。它在Chrome中無法正常工作。

Screenshot Showing the height of the UL element is not in sync with the LI elements

我的應用程序不會預先填充LI元素時,頁面加載 - 它使用JavaScript,具體如下:

function populateUnsetAnswers(unsetCategoryAnswers) { 
    for (i in unsetCategoryAnswers) { 
     if (unsetCategoryAnswers.hasOwnProperty(i.toString())) { 
      $('#categoryQuestionArea #possibleAnswers').append(
       categoryAnswerLiTag(unsetCategoryAnswers[i]) 
      ); 
     } 
    } 
} 

function categoryAnswerLiTag(unsetCategoryAnswer) { 
    var html = '<li id="' + unsetCategoryAnswer.id + '">'; 

    if (unsetCategoryAnswer.image) { 
     html += '<img class="categoryAnswerImage" title="'; 
     html += unsetCategoryAnswer.text; 
     html += '" src="/trainingdividend/rest/streaming/'; 
     html += unsetCategoryAnswer.image.fileName; 
     html += '" style="height: '; 
     html += unsetCategoryAnswer.image.height; 
     html += ';'; 
     html += '" />'; 
    } else { 
     html += unsetCategoryAnswer.text 
    } 

    html += '</li>'; 

    return html; 
} 

當頁面加載完成,一個Ajax請求獲取所有要放入LI元素中的對象,然後調用上面的第一個函數。

所有的LI元素之後創建的,我調用此函數後馬上:

function resize() { 
    var currentHeight, totalHeight; 
    totalHeight = 0; 

    $("#categoryQuestionArea ul").children().each(function() { 
     currentHeight = $(this).height(); 

     totalHeight += currentHeight + 13; 
    }); 

    $("#categoryQuestionArea ul").height(totalHeight); 
    $("#categoryQuestionArea div#separator").css("padding-top", (totalHeight/2) + "px"); 
} 

有沒有辦法告訴jQuery的,「不要叫調整(),直到所有的LI的是完全加載和圖像已呈現「?

我認爲發生的事情是,在初始頁面加載時,這些LI元素的高度爲0或較小的值,因爲它不包含圖像,所以我的resize函數正在計算錯誤的結果(我測試了這個帶有一些警報聲明)。只要LI被填充並且圖像已經加載,總高度就可以很好地計算出來。

任何幫助?謝謝

+0

在代碼中究竟是在調用'resize()'函數?從我在這裏可以看到的,你可以在'populateUnsetAnswers()'末尾調用它,'JavaScript'將調整大小。 – 2012-04-19 17:05:56

+0

@KemalFadillah是的,resize()在populateUnsetAnswers()之後被調用。這隻有在你刷新頁面時才能在Firefox中使用。在Chrome中它依然不起作用。 – 2012-04-19 17:27:00

+0

@FireEmblem您根本不需要設置高度,這些列將垂直擴展以適應內容。 – 2012-04-23 15:24:38

回答

1

如果你在第一頁加載時遇到圖像問題,可能是因爲它們沒有被緩存,因此不能立即使用。因此,測量他們的身高會導致不好的結果......你調試是通過jQuery(獲取例如

currentHeight = $(this).height(); 
console.log(currentHeight); 

做到這一點的唯一方法是,我認爲,觀察所有圖像的加載事件(高度也可能是錯誤的孔),並計算所有請求是否已經完成

+0

是的,我調試了當前的高度。在首頁加載時,高度通常爲0.在後續頁面刷新時,高度是正確的。 – 2012-04-19 17:25:26

+1

那麼當你試圖讀取它們的高度時圖像沒有被完全請求......因爲服務器響應沒有靜態的時間來完成我懷疑你可以實現你想要的東西,除非你正在使用加載/錯誤事件的圖片 – 2012-04-19 17:40:59

+0

@FireEmblem - 我在下面的回答中提供了代碼,用於跟蹤所有圖像何時加載並在所有高度有效時調用'resize()'。 – jfriend00 2012-04-26 22:34:16

0

嘗試使用

$('img').load(function(){ 
    //put code here 
}); 
0

我猜你的HTML被搞砸了。特別是你的<img>標籤。

widthheight屬性添加到<img>標籤。一切都將神奇地解決。

看到這個的jsfiddle明白我的意思:http://jsfiddle.net/Ralt/Vwg7P/

即使有是沒有圖像的widthheight屬性將佔據圖像所需的空間。一旦DOM被加載。

2

下面是檢查圖像已加載的jQuery插件:對於你的情況https://github.com/alexanderdickson/waitForImages

樣品用法是:

$('#categoryQuestionArea').waitForImages(function() { 
    resize(); 
}); 

我也只是檢查爲<ul>,而不是總高度循環顯示列表項,因爲如果填充,頁邊距或列表項邊框稍後發生更改,您將不得不手動更改腳本。

+0

這在嘗試計算瀏覽器從服務器加載圖像之前計算高度時肯定是個問題。 (在第二個請求中,圖像被緩存。)解決方案是延遲計算,直到所有圖像加載(或者在每個圖像加載後甚至更新它)之後。 – 2012-04-25 17:31:41

-1

我認爲瀏覽器不知道圖像的尺寸,因爲它們沒有加載。

可嘗試包裹的resize調用在

jQuery(document).load(function funcName() { 
    ... 
}) 

或給圖像中的HTML標籤imgwidth屬性height

也許都

+0

這是行不通的,因爲圖像是通過javascript代碼動態插入到頁面中的。 – jfriend00 2012-04-26 22:36:02

+0

然後你應該加載圖像尺寸,以及通過JS插入圖像。 – HerrSerker 2012-04-27 06:58:24

0

這是相當一個CSS問題,最有可能是由於固定高度,與項目無論是浮動或絕對定位。

有很多方法可以解決這個問題。

  1. 給一個min-height而不是固定一個高度。

    #container { min-height: 100px; } 
    
  2. 清除float並沒有設置任何高度

    #container { overflow: hidden; } 
    
  3. 使用腳本加起來的高度,連用元素添加。像jQuery的片斷低於

    $("#container").append($("#theimg")); 
    $("#container").height($("#container").height()+$("#theimg").height()); 
    
0

我想我會爲你提供一個解決方案。

我的解決方案的主要思想在於CSS。你想擁有3列相同的高度,對吧?你可以有這樣的事情:http://jsfiddle.net/agilius/NvzZp/46/

有相當多的CSS的出現,但主要的思路是這樣的:

  1. 我模擬實際內容下3欄佈局,與.inner和.column類。
  2. 將內容放置在(通過z-index 2> .inner zindex 1)上,其寬度與所在列的寬度相同。
  3. 將內容添加到內容區域後,主#container的高度會更新。
  4. 由於.inner是頂部,左側,右側,底部= 0,它會更新,並且由於.columns的高度爲100%,因此它們會更新高度以匹配#containers高度。

觀察。

如果您認爲合適,您可以在.column類中添加填充,邊框和邊距。

No javascript is required。

3

爲了從字面上回答你問的問題,如果你想只調用resize()當所有圖像都已完成加載,那麼你需要安裝onload處理程序這些圖像,當您錄製的是,最後一個是現在加載,你可以調用resize()函數。你可以做,像這樣(代碼如下解釋):

var remainingAnswerImages = 0; 

function categoryAnswerImageLoadHandler() { 
    --remainingAnswerImages; 
    if (remainingAnswerImages === 0) { 
     resize(); 
    } 
} 

function populateUnsetAnswers(unsetCategoryAnswers) { 
    // add one extra to the image count so we won't have any chance 
    // at getting to zero before loading all the images 
    ++remainingAnswerImages; 
    var possibleAnswers$ = $('#categoryQuestionArea #possibleAnswers'); 
    for (i in unsetCategoryAnswers) { 
     if (unsetCategoryAnswers.hasOwnProperty(i.toString())) { 
      possibleAnswers$.append(categoryAnswerLiTag(unsetCategoryAnswers[i])); 
     } 
    } 
    // remove the one extra 
    --remainingAnswerImages; 
    // if we hit zero on the count, then there either were no images 
    // or all of them loaded immediately from the cache 
    // if the count isn't zero here, then the 
    // categoryAnswerImageLoadHandler() function will detect when it does hit zero 
    if (remainingAnswerImages === 0) { 
     resize(); 
    } 
} 

function categoryAnswerLiTag(unsetCategoryAnswer) { 
    var obj = document.createElement("li"); 
    obj.id = unsetCategoryAnswer.id; 

    if (unsetCategoryAnswer.image) { 
     // count this image 
     ++remainingAnswerImages; 
     var img = new Image(); 
     img.onload = img.onerror = img.onabort = categoryAnswerImageLoadHandler; 
     img.title = unsetCategoryAnswer.text; 
     img.style.height = unsetCategoryAnswer.image.height; 
     img.src = "/trainingdividend/rest/streaming/" + unsetCategoryAnswer.image.fileName; 
     obj.appendChild(img); 
    } else { 
     obj.innerHTML = unsetCategoryAnswer.text; 
    } 
    return obj; 
} 

通過解釋,該代碼進行以下更改:

  • 添加一個變量remainingAnswerImages跟蹤的多少圖像仍然需要被加載。
  • 爲每個<img>標籤添加一個onload處理程序,以便我們隨時瞭解它的加載時間。
  • 每次我們使用onload處理程序爲標記生成HTML時,都會增加remainingAnswerImages
  • 完成添加所有HTML後,請檢查remainingAnswerImages計數以確定它是否爲零(如果沒有圖像或從瀏覽器緩存中立即加載所有圖像,則只會出現這種情況)。如果是這樣,請立即調用resize()。
  • 在將爲每個圖像調用的onload處理程序中,遞減remainingAnswerImages,如果計數已達到零,請致電resize()
  • 在添加圖像時,添加一個額外的remainingAnswerImages作爲一個門,以防止達到零計數,直到我們完成添加圖像。完成添加圖像後,請多加一個。
  • 我還重寫了categoryAnswerLiTag()函數,直接創建DOM對象,而不是將一堆字符串連接成HTML。在這種情況下,代碼更易於閱讀和維護。
  • 我也將$('#categoryQuestionArea #possibleAnswers')for循環中移出,因爲它每次都解決相同的問題。最好在循環之前做一次。另外,在大多數情況下,這可以簡化爲$('#possibleAnswers'),因爲id應該在頁面中是唯一的。
0

另一個簡單相等的高度CSS溶液:

LOGIC是非常簡單 - 所有列/ LI的浮起 與.eH {填充底:X;邊距:-X}和 包裝/ UL是.EW {溢出:隱藏}

X =任意大PX的爲安全因子量

實施例: http://jsfiddle.net/rahen/TXVYD/4/

0

這聽起來就像我編碼SudoSlider時遇到的問題之一。

下面我複製了我解決它的代碼。請在您的resize()函數內調用autoheightwidth(i, 0, true)

基本的想法是,你不知道瀏覽器何時完成加載圖像,所以不必依靠單一的高度調整,而是每次發生某些事情時調整高度(大部分只是圖像已加載) 。

如果在前兩種方法中更改「obj」和「li」的引用,它應該可以工作。

它的可讀性不是很好,但是當我編碼時它的重點在於大小。

// Automaticly adjust the height and width, i love this function. 
// Before i had one function for adjusting height, and one for width. 
function autoheightwidth(i, speed, axis) // Axis: true == height, false == width. 
{ 
    obj.ready(function() {// Not using .load(), because that only triggers when something is loaded. 
     adjustHeightWidth (i, speed, axis); 
     // Then i run it again after the images has been loaded. (If any) 
     // I know everything should be loaded, but just in case. 
     runOnImagesLoaded (li.eq(i), falsev, function(){ 
      adjustHeightWidth (i, speed, axis); 
     }); 
    }); 
}; 
function adjustHeightWidth (i, speed, axis) 
{ 
    var i = getRealPos(i); // I assume that the continuous clones, and the original element is the same height. So i allways adjust acording to the original element. 
    var target = li.eq(i); 
    // First i run it. In case there are no images to be loaded. 
    var b = target[axis ? "height" : "width"](); 
    obj.animate(
     axis ? {height : b} : {width : b}, 
     { 
      queue:falsev, 
      duration:speed, 
      easing:option[8]/*ease*/ 
     } 
    ); 
} 
function runOnImagesLoaded (target, allSlides, callback) // This function have to be rock stable, cause i use it ALL the time! 
{ 
    var elems = target.add(target.find('img')).filter('img'); 
    var len = elems.length; 
    if (!len) 
    { 
     callback(); 
     // No need to do anything else. 
     return this; 
    } 
    function loadFunction(that) 
    { 
     $(that).unbind('load').unbind('error'); 
     // Webkit/Chrome (not sure) fix. 
     if (that.naturalHeight && !that.clientHeight) 
     { 
      $(that).height(that.naturalHeight).width(that.naturalWidth); 
     } 
     if (allSlides) 
     { 
      len--; 
      if (len == 0) 
      { 
       callback(); 
      } 
     } 
     else 
     { 
      callback(); 
     } 
    } 
    elems.each(function(){ 
     var that = this; 
     $(that).load(function() { 
      loadFunction(that); 
     }).error(function() { 
      loadFunction(that); 
     }); 
     /* 
     * Start ugly working IE fix. 
     */ 
     if (that.readyState == "complete") 
     { 
      $(that).trigger("load");  
     } 
     else if (that.readyState) 
     { 
      // Sometimes IE doesn't fire the readystatechange, even though the readystate has been changed to complete. AARRGHH!! I HATE IE, I HATE IT, I HATE IE! 
      that.src = that.src; // Do not ask me why this works, ask the IE team! 
     } 
     /* 
     * End ugly working IE fix. 
     */ 
     else if (that.complete) 
     { 
      $(that).trigger("load"); 
     } 
     else if (that.complete === undefined) 
     { 
      var src = that.src; 
      // webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f 
      // data uri bypasses webkit log warning (thx doug jones) 
      that.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=="; // This is about the smallest image you can make. 
      that.src = src; 
     } 
    }); 
}