[英]Changing source of image inside a class on click Cannot set property 'src' of undefined
I am trying to do a really simple code where every time I click on an image it changes the source. 我正在尝试编写一个非常简单的代码,每次单击图像时,它都会更改源代码。 I Want also to display this image in hover but that would be the next step after I can make it work on click.
我也希望将图像悬停显示,但这将是我可以单击使它工作的下一步。
This is my HTML 这是我的HTML
<div class="seats-row-A">
<img id="A1" class="seat-unique" src="chair.svg" >
<img id="A2" class="seat-unique" src="chair.svg" >
<img id="A3" class="seat-unique" src="chair.svg" >
<img id="A4" class="seat-unique" src="chair.svg" >
<img id="A5" class="seat-unique" src="chair.svg" >
<img id="A6" class="seat-unique" src="chair.svg" >
<img id="A7" class="seat-unique" src="chair.svg">
</div>
This is my JS 这是我的JS
seatsUnclicked= document.getElementsByClassName("seat-unique");
for(var i = 0; i < seatsUnclicked.length; i++)
{
seatsUnclicked[i].onclick = function(){
seatsUnclicked[i].src = "chairhover.svg";
}
}
This is typical problem of the scope of the variable.In your case onclick event will occur sometime in future.By that time the for-loop have finished its execution and the value of i
is set to the length of the html collection. 这是变量范围的典型问题。在您的情况下,onclick事件将在将来的某个时候发生。到那时,for循环已完成其执行,并且
i
的值设置为html集合的长度。
Before let
one of the solution was to create an Immediately invoking function expression and pass the value of the i
, This value will be accepted as a parameter.In this way with closure the value of i
is preserved. 之前
let
的解决方案之一是建立一个立即调用的函数表达式和传递的价值i
,这个值将被这种方式与封闭的价值接受为parameter.In i
被保留。
In ES6 with new keyword let
there is no need of creating a closure and IIFE
在带有新关键字
let
ES6中,无需创建闭包和IIFE
var seatsUnclicked = document.getElementsByClassName("seat-unique"); //SOLUTION 1 for (var i = 0; i < seatsUnclicked.length; i++) { (function(x) { seatsUnclicked[x].onclick = function() { seatsUnclicked[x].src = "chairhover.svg"; } }(i)) } //SOLUTION 2 for (let i = 0; i < seatsUnclicked.length; i++) { seatsUnclicked[i].onclick = function() { seatsUnclicked[i].src = "chairhover.svg"; } }
<div class="seats-row-A"> <img id="A1" class="seat-unique" src="chair.svg"> <img id="A2" class="seat-unique" src="chair.svg"> <img id="A3" class="seat-unique" src="chair.svg"> <img id="A4" class="seat-unique" src="chair.svg"> <img id="A5" class="seat-unique" src="chair.svg"> <img id="A6" class="seat-unique" src="chair.svg"> <img id="A7" class="seat-unique" src="chair.svg"> </div>
You can choose to use event propagation instead, then you do not need to attach an event handler to all separate images 您可以选择使用事件传播 ,而不需要将事件处理程序附加到所有单独的图像
let seatContainer = document.querySelectorAll('.seats-row-A')[0]; // use event-propagation catch all clicks on seats-row-a, and handle clicks that wait seatContainer.addEventListener('click', function(e) { if (!e.target.src) { // no image return; } if (e.target.src.includes('chair.svg')) { e.target.src = 'chairhover.svg'; } else { e.target.src = 'chair.svg'; } });
<div class="seats-row-A"> <img id="A1" class="seat-unique" src="chair.svg" > <img id="A2" class="seat-unique" src="chair.svg" > <img id="A3" class="seat-unique" src="chair.svg" > <img id="A4" class="seat-unique" src="chair.svg" > <img id="A5" class="seat-unique" src="chair.svg" > <img id="A6" class="seat-unique" src="chair.svg" > <img id="A7" class="seat-unique" src="chair.svg"> </div>
Or, you can create i
as a block scoped variable , using let
as declaration as opposed to your current var
(function scoped variable) 或者,您可以使用
let
作为声明来创建i
作为块作用域变量 ,而不是当前的var
(函数作用域变量)
for (let i = 0; i < seatsUnclicked.length; i++) {
seatsUnclicked[i].onclick = function() {
seatsUnclicked[i].src = "chairhover.svg";
}
}
Or you could use the event argument , that points to your element (a bit like the event propagation in the first example) 或者,您可以使用事件参数 ,它指向您的元素(有点像第一个示例中的事件传播)
function handleElementClicked( e ) {
if (e.target.src.includes('chair.svg')) {
e.target.src = 'chairhover.svg';
} else {
e.target.src = 'chair.svg';
}
}
for (var i = 0; i < seatsUnclicked.length; i++) {
seatsUnclicked[i].onclick = handleElementClicked;
}
Or, you could bind your indexer to your calling function 或者,您可以将索引器绑定到调用函数
for (var i = 0; i < seatsUnclicked.length; i++) {
seatsUnclicked[i].onclick = function( index ) {
seatsUnclicked[index].src = "chairhover.svg";
}.bind( null, i );
}
The getElementsByClassName()
method returns a collection of all elements in the document with the specified class name, as a NodeList object. getElementsByClassName()
方法以NodeList对象的形式返回文档中具有指定类名的所有元素的集合。
To avoid unecessary class names and inline onClick js, you can use querySelectorAll
instead and add a click listener to each one like this: 为了避免不必要的类名和内联onClick js,可以改用
querySelectorAll
,并向每个侦听器添加一个click侦听器,如下所示:
let seatsUnclicked = document.querySelectorAll("img");
function changeImage() {
this.src="chairhover.svg";
}
seatsUnclicked.forEach(img => {
img.addEventListener('click', changeImage);
})
jsFiddle: https://jsfiddle.net/AndrewL64/866vf8a1/ jsFiddle: https ://jsfiddle.net/AndrewL64/866vf8a1/
Couple of things I observed: 我观察到的几件事:
You have to use setAttribute to set the attribute 您必须使用setAttribute设置属性
inside the function you used : seatsUnclicked[i].src = "chairhover.svg"; 在您使用的函数中:seatsUnclicked [i] .src =“ chairhover.svg”;
here i is always equal = seatsUnclicked.length 在这里我总是等于= SeatsUnclicked.length
so it gives undefined element. 因此它给出了undefined元素。 so you get error cannot set the property of undefined.
因此,您将收到错误消息,无法设置undefined属性。
user event.currentTarget.setAttribute: 用户event.currentTarget.setAttribute:
Check this https://jsfiddle.net/hgfeh9zw/ 检查此https://jsfiddle.net/hgfeh9zw/
<div class="seats-row-A">
<img id="A1" class="seat-unique"
src="http://icons.iconarchive.com/icons/paomedia/small-n-flat/64/sign-check-icon.png" >
<img id="A2" class="seat-unique" src="http://icons.iconarchive.com/icons/paomedia/small-n-flat/64/sign-check-icon.png" >
<img id="A3" class="seat-unique" src="http://icons.iconarchive.com/icons/paomedia/small-n-flat/64/sign-check-icon.png" >
<img id="A4" class="seat-unique" src="http://icons.iconarchive.com/icons/paomedia/small-n-flat/64/sign-check-icon.png" >
<img id="A5" class="seat-unique" src="http://icons.iconarchive.com/icons/paomedia/small-n-flat/64/sign-check-icon.png" >
<img id="A6" class="seat-unique" src="http://icons.iconarchive.com/icons/paomedia/small-n-flat/64/sign-check-icon.png" >
<img id="A7" class="seat-unique" src="http://icons.iconarchive.com/icons/paomedia/small-n-flat/64/sign-check-icon.png">
</div>
<script>
window.onload= function(){
seatsUnclicked= document.getElementsByClassName("seat-unique");
for(var i = 0; i < seatsUnclicked.length; i++)
{
seatsUnclicked[i].onclick = function(event){
event.currentTarget.setAttribute('src', 'https://www.gravatar.com/avatar/b43bbab9d16d030a8744f17ca9c1da8d?s=32&d=identicon&r=PG');
}
}
}
</script>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.