0

我对网页设计和与之相关的编程非常陌生。我正在使用 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('list_width')这些img标签,所以我想到了使用list_width+=document.getElementById(i).offsetWidth.

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

提前致谢。

4

3 回答 3

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;
}
于 2013-04-21T10:38:22.617 回答
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);

jsfiddle上

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

于 2013-04-21T11:11:57.453 回答
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;

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

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;
}
于 2013-04-21T09:34:23.357 回答