Glitchy JavaScript

时间:2013-04-21 09:28:11

标签: javascript html

我对与之相关的网页设计和编程非常陌生。我正在使用JavaScript创建一个简单的库,我知道使用jQuery非常容易。但是我不允许使用它(作业)。

以下是问题所在的代码:

var img = new Array(); //declared globally, accessed by other functions
function displayImage(){

var img_num = document.getElementById('img_num').getAttribute("value");

for(j=0;j<img_num;j++)
  img.push(document.getElementById('h'+j).getAttribute("value"));


var list_width = 0;
for(var i=0;i<img_num;i++) 
{      
   document.getElementById('list_holder').innerHTML += "<img src='" +img[i]+ "'onclick=\"show(this.id);\" height = \"70%;\"id='"+i+"'/>";
   list_width += document.getElementById(i).offsetWidth + 15;
}

document.getElementById('list_holder').style.width = list_width+"px";
return false;
}

ID为h0,h1,h2 ......等的元素是隐藏的输入类型,包含图像的路径,ID为0,1,2 ..是标记。

我在JS中使用它们来使用img将路径存储在数组img.push中。然后我使用数组中的值来精确创建许多<img>标签(指定高度,宽度左侧为宽高比决定。现在我有必要计算总宽度div代码的父img('list_width'),因此我考虑使用list_width+=document.getElementById(i).offsetWidth

但是发生的事情是,当我第一次打开页面时,实际的宽度没有被返回。它返回4,这基本上是我想到的标签的最小宽度。仅在刷新页面时才能按预期工作。我知道我可以通过在加载页面后刷新页面来使用解决方法,但我想知道是否有任何“首选”或“专业”方式来执行此操作。

提前致谢。

3 个答案:

答案 0 :(得分:2)

您必须等到图像加载完毕。您是Javascript的新手,但您必须面对异步编程。我们在评论中看到这一点:

var img = []; // faster to type, use this syntax if you
              // don't define an initial length
function displayImage() {
    // The attribute value defines the initial value of the input element, and
    // it may differ from the actual value. So use the value property, not the
    // attribute.
    var img_num = document.getElementById('img_num').value;

    for(var j=0; j<img_num; j++) // Watch out, without var j is global!
        img.push(document.getElementById('h'+j).value);


    var list_width = 0,
        // We're referincing this element a lot, better store it
        lholder = document.getElementById('list_holder'),
        htmllist = []; // See the trick
    for(var i=0; i<img_num; i++)
        htmllist.push("<img src='" +img[i]
            + "'onclick=\"show(this.id);\" height = \"70%;\"id='"+i+"'/>");

    // Every time you set innerHTML, using = or +=, the browser has to parse
    // the code and rebuild the content, and it's an expensive task. Set this
    // property only once you already computed all the HTML you need.
    lholder.innerHTML = htmllist.join("");

    var loaded = 0;
    for(var i=0; i<img_num; i++)
        // You don't know when the images will be loaded. But when an image is
        // loaded, it triggers the load event that you can listen setting the
        // onload property (or, in a more modern way, setting an event listener
        // with addEventListener or attachEvent in older IE). Count the images
        // that are loaded, and when they're all loaded do your stuff.
        lholder.childNodes[i].onload = function() {
            if (++loaded < img_num) return;
            for(var i=0; i<img_num; i++)
                list_width += lholder.childNodes[i].offsetWidth;
            lholder.style.width = list_width + "px";
        };

    return false;
}

答案 1 :(得分:2)

如上所述,在查询属性之前,您必须等待图像完成加载。以下是正在发生的事情的一个例子。

img {
    width: 50px;
    height: auto;
    float: left;
    border-style:solid;
    border-width:1px;
}
img:hover {
    width: 300px;
}

<div id="display" class="main"></div>

var display = document.getElementById("display"),
    images = {
        "F12berlinetta": "http://www.ferrari.com/Site_Collection_Image_115x55/f12_thumb_home_115x55.png",
            "458 Spider": "http://www.ferrari.com/Site_Collection_Image_115x55/110823_458_spider_menu.png",
            "FF": "http://www.ferrari.com/Site_Collection_Image_115x55/ff_thumb_home_115x55.png",
            "458 Italia": "http://www.ferrari.com/Site_Collection_Image_115x55/458_italia_menu_1_dx_ok.png",
            "Ferrari California": "http://www.ferrari.com/Site_Collection_Image_115x55/california_menu_3_sx.png"
    },
    keys = Object.keys(images),
    loaded = 0,
    menuWidth = 0,
    noWaitWidth = 0;

function clickedIt(evt) {
    alert("You chose the " + evt.target.title);
}

function onLoaded(evt) {
    loaded += 1;
    menuWidth += evt.target.offsetWidth;
    evt.target.addEventListener("click", clickedIt, false);
    if (loaded === keys.length) {
        console.log("Waited load width", menuWidth);
    }
}

keys.forEach(function (key, index) {
    var newDiv = document.createElement("div"),
        newImg = document.createElement("img");

    newImg.id = "thumb" + index;
    newImg.src = images[key];
    noWaitWidth += newImg.offsetWidth;
    newImg.title = key;
    newImg.addEventListener("load", onLoaded, false);

    newDiv.appendChild(newImg);
    display.appendChild(newDiv);
});

console.log("Didn't wait load width", noWaitWidth);

on jsfiddle

添加:如果这是你的意思,这会以标准的javascript方式将HTML图像标记放在文档中。如果没有你描述你不理解的东西,很难简化任何解释;有一个对象保存图像标题及其URL。我们遍历对象并将图像与标题一起放在文档中并获得不正确的图像宽度,在每个图像上我们设置一个等待图像加载的事件监听器,当它加载时我们得到正确的图像宽度。我们还在每个图像上设置了单击侦听器,以提供您单击的图像的警报。 CSS演示了其标准的悬停方法,因此当您将移动放在图像上时,它会缩放该图像。

答案 2 :(得分:0)

这一行存在问题:

for(var i=0;i<img_num;i++)       
   document.getElementById('list_holder').innerHTML += "<img src='" +img[i]+ "'onclick=\"show(this.id);\" height = \"70%;\"id='"+i+"'/>";
   list_width += document.getElementById(i).offsetWidth + 15;

因为你没有curley括号,它只会在循环中运行第一行,将其更改为:

for(var i=0;i<img_num;i++){     
   document.getElementById('list_holder').innerHTML += "<img src='" +img[i]+ "'onclick=\"show(this.id);\" height = \"70%;\"id='"+i+"'/>";
   list_width += document.getElementById(i).offsetWidth + 15;
}