如何为HTML类添加事件监听器?

9
如果我有以下这样的HTML代码:
<a href="#" class="movieImg"><div class="previewBulk"></div></a>
<a href="#" class="movieImg"><div class="previewBulk"></div></a>

以及像这样的JavaScript:

var movie = document.getElementsByClassName("movieImg");
var preview = document.getElementsByClassName("preview");

有没有办法将 addEventListener 添加到 2 个电影的 a 标签和预览 div 标签中?我尝试使用 for 循环,但当我进行如下操作时:
for(var i = 0, j=movie.length; i<j; i++){
 movie[i].style.left = 100;
 preview[i].style.left = 100;
}

我遇到了 Uncaught TypeError: Cannot read property 'style' of undefined 的错误。

将预览更改为批量预览后,我仍然遇到错误,我的代码实际上是这样的:

(function(){
        var movie = document.getElementsByClassName("movieImg"),
        preview = document.getElementsByClassName("previewBulk");
        //result = [];

        for(var i = 0, j=movie.length; i<j; i++){
            movie[i].addEventListener("mouseover", function(){

                preview[i].style.left = ((movie[i].offsetWidth-preview[i].offsetWidth)/2)+20;
                preview[i].style.top = -(movie[i].offsetHeight+preview[i].offsetHeight);
                preview[i].style.visibility = "visible";
            });

            movie[i].addEventListener("mouseout", function(){
                preview[i].style.visibility = "hidden";
            });
        }
    }());

1
CSS的left属性(如您所示通过DOM访问)需要一个长度而不是整数。除非值为0,否则需要单位 - Quentin
你的意思是字符串值吗?例如 "100px"? - bitokeev
您不能在值不是字符串的情况下包含单位。它不必使用像素。规则与直接应用CSS的规则相同。 - Quentin
5个回答

8

document.getElementsByClassName并不返回一个数组,而是返回一个节点列表,它的遍历方式类似于XML文件。

    <a href="#" class="movie"><div class="previewBulk"></div></a>
    <a href="#" class="movie"><div class="previewBulk"></div></a>

    <script>

    var movie = document.getElementsByClassName("movie");

    for(var i = 0; i<movie.length; i++){
      movie.item(i).style.width = "100px";
    }​

    </script>

请查看jsfiddle:http://jsfiddle.net/Uy5fk/

7
// for each iterates over a list and runs a function for each element
var forEach = Array.prototype.forEach,
    // query selector all runs a CSS selector and returns a list of elements
    // matching the selector
    $$ = document.querySelectorAll.bind(document);

// for each element in the list returned by the CSS selector    
forEach.call($$('.movieImg, .preview'), function(v) {
  // add an event listener to the click event
  v.addEventListener('click', function(e) {
    // and run some event handling code.    
  }, false);
});

当然,浏览器兼容性是个问题。它们需要支持ES5和DOM2事件。使用shims来解决浏览器兼容性问题。
如果你包含了 它应该修复浏览器支持。当然,FF4 / Chrome / Safari5 / ie9 / Opera10+ 已经支持这些。
编辑:
问题实际上是 "循环内的闭包问题",如 javascript garden 中所述。

必须支持Es5和Dom2吗?因为这是我的作业,我不确定我的讲师的浏览器是否支持。顺便说一下,谢谢。 - bitokeev
@bitokeev 已更新以匹配您的更新。是 for 循环中的闭包导致了您的错误。 - Raynos
谢谢您的帮助,但是我有点不理解这段代码,对我来说太高级了。 - bitokeev

3
没有带有类名为preview的标签。
var preview = document.getElementsByClassName("preview");

会导致错误

这一行必须按照以下方式编写

var preview = document.getElementsByClassName("previewBulk");

正如@raym0nd所说,div标签的数量必须等于a标签的数量。

编辑

你代码的问题在于你在匿名函数内使用了for循环的索引,但是这个函数会在mouseoutmouseover事件中被调用,在完成for循环后,请尝试以下操作:

var movie = document.getElementsByClassName("movieImg");

    for(var i = 0, j=movie.length; i<j; i++){
        movie[i].addEventListener("mouseover", function(){
        var preview = this.getElementsByClassName("previewBulk")[0];
                          preview.style.left = ((this.offsetWidth-preview.offsetWidth)/2)+20;
            preview.style.top = -(this.offsetHeight+preview.offsetHeight);
            preview.style.visibility = "visible";
        });

        movie[i].addEventListener("mouseout", function(){
            var preview = this.getElementsByClassName("previewBulk")[0];
            preview.style.visibility = "hidden";
        });
    }

jsFiddle中进行测试。

在从预览更改为previewBulk后,我仍然遇到错误,我已经编辑并发布了完整的代码在问题中,您能帮我找出问题吗? - bitokeev
谢谢,它有效。关于代码 "var preview = this.getElementsByClassName("previewBulk")[0]" ,我想知道 [0] 是什么意思?是通过访问第一个元素来引用数组吗? - bitokeev

1
for(var i = 0, j=movie.length; i<j; i++){
 movie[i].style.left = 100;
 preview[i].style.left = 100;
}

预览的长度和电影一样吗?如果不是,这会导致错误。


是的,预览与电影长度相同。 - bitokeev

1

你有 class="previewBulk"document.getElementsByClassName("preview");

你的代码假设类preview的元素个数与类movieImg相同,但由于你将类名写错了,因此不会有这样的元素。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接