2012-04-17 31 views
13

Tôi có ứng dụng Html/JavaScript chứa N cột cần đủ lớn chứa tất cả các phần tử LI có thể có từ tất cả các cột.JavaScript không thay đổi kích thước chiều cao của phần tử UL đôi khi khi chèn các phần tử LI bằng cách sử dụng Jquery

Giải pháp đơn giản dường như đếm chiều cao của tất cả các mục trong mỗi cột, bù cho đệm, sau đó đặt chiều cao cho tổng số đó cho từng cột.

Điều này hoạt động tốt khi các phần tử LI chứa văn bản thuần túy. Thật không may, khi các yếu tố LI chứa hình ảnh thay vào đó, các trình duyệt khác nhau có vấn đề. Ví dụ, khi tôi lần đầu tiên tải trang trong FireFox, nó trông giống như ảnh chụp màn hình dưới đây, nhưng khi làm mới khác, nó hoạt động tốt. Nó không hoạt động như mong đợi trong Chrome.

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

ứng dụng của tôi không điền trước các yếu tố LI khi tải trang - nó sử dụng JavaScript, như sau:

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; 
} 

Khi trang web được thực hiện tải, một yêu cầu ajax lấy về tất cả của các đối tượng được đưa vào các phần tử LI và sau đó gọi hàm đầu tiên ở trên.

Sau khi tất cả các yếu tố LI được tạo ra, tôi gọi chức năng này ngay sau khi nó:

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"); 
} 

Có cách nào để nói với jQuery, "Đừng gọi thay đổi kích thước() cho đến khi tất cả các của LI là được tải đầy đủ và hình ảnh đã hiển thị "? Tôi nghĩ rằng những gì đang xảy ra là khi tải trang ban đầu, chiều cao của các phần tử LI là 0 hoặc một giá trị nhỏ vì nó không chứa hình ảnh, vì vậy chức năng thay đổi kích thước của tôi đang tính toán kết quả sai (tôi đã thử nghiệm điều này). với một số báo cáo cảnh báo). Miễn là các LI được điền và các hình ảnh đã được tải, tổng chiều cao được tính toán tốt.

Bất kỳ trợ giúp nào? Cảm ơn

+0

Trường hợp chính xác trong mã của bạn, bạn đang gọi hàm 'resize()'? Từ những gì tôi có thể thấy ở đây, bạn chỉ có thể gọi nó ở cuối 'populateUnsetAnswers()' và 'JavaScript' sẽ làm thay đổi kích cỡ vừa phải. –

+0

@KemalFadillah Có, thay đổi kích thước() được gọi ngay sau khi điền vàoUnsetAnswers() rồi. Điều này chỉ hoạt động trong firefox khi bạn làm mới trang. Nó vẫn không hoạt động chút nào trong Chrome. –

+0

@FireEmblem bạn không cần đặt chiều cao, các cột sẽ mở rộng theo chiều dọc để vừa với nội dung. –

Trả lời

1

Nếu bạn gặp sự cố với hình ảnh khi tải trang đầu tiên có thể là do chúng không được lưu trong bộ nhớ cache và do đó không có sẵn ngay lập tức. Vì vậy, đo chiều cao của họ sẽ dẫn đến kết quả xấu ... bạn đã gỡ chiều cao đã được lấy qua jQuery (ví dụ

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

Cách duy nhất để làm điều đó là tôi nghĩ rằng để quan sát các sự kiện load của tất cả các hình ảnh (và có lẽ là lỗi cũng) và đếm xem tất cả yêu cầu đã được hoàn thành

+0

Có, tôi đã gỡ lỗi chiều cao hiện tại. Khi tải trang đầu tiên, chiều cao thường là 0. Khi làm mới trang tiếp theo, chiều cao là chính xác. –

+1

thì thực tế là hình ảnh không được yêu cầu đầy đủ khi bạn đang cố gắng đọc chiều cao của chúng ... vì phản hồi của máy chủ không có thời gian tĩnh để hoàn thành tôi nghi ngờ bạn có thể đạt được những gì bạn muốn trừ khi bạn đang sử dụng sự kiện tải/lỗi của hình ảnh –

+0

@FireEmblem - Tôi đã cung cấp mã trong câu trả lời của tôi dưới đây để theo dõi khi tất cả các hình ảnh được tải và gọi 'resize()' khi tất cả các chiều cao là hợp lệ. – jfriend00

0

hãy thử sử dụng

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

tôi đoán HTML của bạn là hơi say lên. Đặc biệt, <img> thẻ của bạn.

Thêm các thuộc tính widthheight vào các thẻ <img> của bạn. Mọi thứ sẽ được giải quyết một cách kỳ diệu.

Xem jsfiddle này để hiểu những gì tôi có nghĩa là: http://jsfiddle.net/Ralt/Vwg7P/

Mặc dù không có hình ảnh trong đó, các widthheight thuộc tính sẽ chiếm không gian cần thiết cho hình ảnh. Ngay sau khi DOM được tải.

2

Đây là một plugin jquery để kiểm tra những hình ảnh đã tải: sử dụng https://github.com/alexanderdickson/waitForImages

mẫu cho trường hợp của bạn sẽ là:

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

Tôi cũng sẽ chỉ kiểm tra tổng chiều cao của <ul> thay vì looping thông qua các mục danh sách như bạn sẽ phải tự thay đổi kịch bản nếu một trong hai padding, lề, hoặc biên giới trên các mục danh sách thay đổi sau này.

+0

Điều này chắc chắn là một vấn đề với việc cố gắng tính toán chiều cao trước khi trình duyệt tải hình ảnh từ máy chủ. (Trên yêu cầu thứ hai, các hình ảnh được lưu trữ.) Giải pháp là trì hoãn việc tính toán cho đến sau khi tất cả các hình ảnh đã được tải (hoặc thậm chí cập nhật nó sau mỗi lần tải hình ảnh). –

-1

Tôi nghĩ Trình duyệt không biết kích thước của hình ảnh, vì chúng không được tải.

Hoặc là cố gắng quấn gọi của resize trong một

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

hoặc cung cấp cho các hình ảnh widthheight thuộc tính trong HTML img thẻ.

Có thể cả hai

+0

Điều này sẽ không hoạt động vì hình ảnh được chèn động vào trang thông qua mã javascript. – jfriend00

+0

Sau đó, bạn cũng nên tải kích thước hình ảnh, khi chèn hình ảnh qua JS. – HerrSerker

0

Đây là vấn đề về CSS, có thể do chiều cao cố định, với các mục được thả nổi hoặc được định vị hoàn toàn.

Có nhiều cách để khắc phục sự cố này.

  1. Viết min-height thay vì sửa chiều cao.

    #container { min-height: 100px; } 
    
  2. Xóa float và không đặt bất kỳ đỉnh cao

    #container { overflow: hidden; } 
    
  3. Sử dụng Scripts để thêm lên đến đỉnh cao, một khi mọi phần tử được thêm vào. Giống như jQuery đoạn mã dưới đây

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

Tôi nghĩ rằng tôi có thể có một giải pháp cho bạn.

Ý tưởng chính của giải pháp của tôi nằm trong CSS. Bạn muốn có 3 cột có cùng chiều cao, phải không? Bạn có thể có một cái gì đó như thế này: http://jsfiddle.net/agilius/NvzZp/46/

Có khá nhiều CSS ở đó, nhưng ý tưởng chính là thế này:

  1. tôi mô phỏng một bố cục 3 cột dưới nội dung thực tế, với sự .inner và .column classes.
  2. Nội dung được đặt trên (thông qua z-index 2>. Zindex 1), có cùng chiều rộng với các cột dưới.
  3. Khi nội dung được thêm vào vùng nội dung, chiều cao của #container chính sẽ được cập nhật.
  4. Vì .inner ở trên cùng, bên trái, bên phải, dưới = 0, nó cập nhật và vì các cột .có độ cao 100%, chúng cập nhật chiều cao của chúng để phù hợp với chiều cao #containers.

Quan sát.

Bạn có thể có đệm, đường viền, lề trong lớp .column như bạn thấy phù hợp.

Không yêu cầu javascript.

3

Để trả lời câu hỏi bạn yêu cầu, nếu bạn chỉ muốn gọi resize() khi tất cả hình ảnh đã tải xong, bạn cần cài đặt các bộ xử lý onload cho những hình ảnh đó và khi bạn đã ghi bạn có thể gọi hàm resize(). Bạn có thể làm điều đó như thế này (mã giải thích dưới đây):

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; 
} 

Bằng cách giải thích, mã này làm cho những thay đổi sau:

  • Thêm một biến remainingAnswerImages để theo dõi có bao nhiêu hình ảnh vẫn cần Được nạp.
  • Thêm trình xử lý tải trọng cho mỗi thẻ <img> được tạo để chúng tôi có thể theo dõi khi được tải.
  • Mỗi lần chúng tôi tạo HTML cho thẻ có trình xử lý tải lên, tăng remainingAnswerImages.
  • Khi bạn đã hoàn tất việc thêm tất cả HTML, hãy kiểm tra số remainingAnswerImages để xem nếu nó là số không (điều này chỉ xảy ra nếu không có hình ảnh hoặc nếu tất cả hình ảnh được tải ngay từ bộ nhớ cache của trình duyệt). Nếu vậy, hãy gọi lại thay đổi kích thước() ngay lập tức.
  • Trong trình xử lý tải trọng sẽ được gọi cho mỗi hình ảnh, hãy giảm remainingAnswerImages và nếu số lượng đã đạt đến số không, hãy gọi resize().
  • Trong khi thêm hình ảnh, hãy thêm một hình ảnh bổ sung vào remainingAnswerImages làm cổng để không bị tính số không cho đến khi chúng tôi hoàn tất việc thêm hình ảnh. Khi hoàn tất việc thêm hình ảnh, hãy thêm một hình ảnh đó.
  • Tôi cũng viết lại hàm categoryAnswerLiTag() để chỉ tạo các đối tượng DOM trực tiếp thay vì kết hợp một chuỗi các chuỗi lại với nhau thành HTML. Trong trường hợp này, mã là rất nhiều sạch hơn để đọc và duy trì.
  • Tôi cũng đã di chuyển số $('#categoryQuestionArea #possibleAnswers') ra khỏi vòng lặp for của bạn vì nó xử lý cùng một điều mỗi lần. Tốt hơn để làm điều đó một lần trước khi vòng lặp. Ngoài ra, trong hầu hết các trường hợp, điều này có thể được đơn giản hóa thành $('#possibleAnswers') vì id được cho là duy nhất trong trang.
0

Một Equal Chiều cao giải pháp CSS đơn giản:

LOGIC là rất đơn giản - tất cả các cột/LI đang nổi với .eH {padding-bottom: X; margin-bottom: -X} và wrapper/UL là .eW {overflow: hidden}

X = lớn số lượng tùy ý các px cho hệ số an toàn

VÍ DỤ: http://jsfiddle.net/rahen/TXVYD/4/

0

Điều này nghe có vẻ giống như một trong những vấn đề tôi gặp phải khi mã hóa SudoSlider.

Dưới đây tôi đã sao chép mã mà tôi đã giải quyết bằng. Chỉ cần gọi autoheightwidth(i, 0, true) bên trong hàm resize() của bạn.

Ý tưởng cơ bản là bạn không biết khi nào trình duyệt tải xong hình ảnh, do đó, thay vì dựa vào điều chỉnh chiều cao, bạn điều chỉnh chiều cao mỗi khi có điều gì đó xảy ra (chủ yếu chỉ là hình ảnh đã được tải) .

Nó sẽ hoạt động nếu bạn thay đổi tham chiếu của "obj" và "li" trong 2 phương pháp đầu tiên.

Nó không phải là rất dễ đọc, nhưng có một trọng tâm lớn về kích thước khi tôi mã hóa nó.

// 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; 
     } 
    }); 
} 
Các vấn đề liên quan