为什么我用这个JavaScript箭头函数获取不到被点击元素的属性?
Why can't I get the attribute of the clicked element with this JavaScript arrow function?
我正在使用从对象数组“提取”的数据填充 HTML table:
let cars = [{
licensee: '23456 NY',
arrival: new Date(2020, 9, 16, 11, 34, 30),
leave: new Date(),
isParked: true
},
{
licensee: '56456 NY',
arrival: new Date(2020, 8, 24, 10, 33, 30),
leave: new Date(2020, 8, 24, 13, 50, 35),
isParked: false
},
{
licensee: '56780 NY',
arrival: new Date(2020, 5, 12, 20, 33, 30),
leave: new Date(2020, 5, 12, 21, 33, 30),
isParked: false
}
];
const formatDate = (date) => {
var hours = date.getHours();
var minutes = date.getMinutes();
var ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12;
hours = hours ? hours : 12;
minutes = minutes < 10 ? '0' + minutes : minutes;
var strTime = hours + ':' + minutes + ' ' + ampm;
return date.getDate() + "/" + (date.getMonth() + 1) + "/" + date.getFullYear() + " " + strTime;
}
const secondsToHours = (d) => {
d = Number(d);
let h = Math.ceil(d / 3600);
return h;
}
const makeBill = (car) => {
let arrivedAt = new Date(car.arrival).getTime();
let leftAt = new Date(car.leave).getTime();
//duration in seconds
let duration = (leftAt - arrivedAt) / 1000;
let hoursBilled = secondsToHours(duration);
let billValue = car.isParked ? "-" : 10 + (hoursBilled - 1) * 5 + " LEI";
return billValue;
}
const renterTable = () => {
// Show new on top
cars.reverse();
let results = '';
for (var i = 0; i < cars.length; i++) {
results += `<tr>
<td>${cars[i].licensee}</td>
<td>${formatDate(cars[i].arrival)}</td>
<td>${formatDate(cars[i].leave)}</td>
<td class="text-center">${showStatus(cars[i])}</td>
<td class="text-right">${makeBill(cars[i])}</td>
<td class="text-right">
<button data-row="${i}" onclick="changeStatus(e)" class="btn btn-sm btn-success">Summary</button>
</td>
</tr>`;
}
document.querySelector("#parking tbody").innerHTML = results;
}
const showStatus = (car) => {
return car.isParked ? "In" : "Out";
}
const changeStatus = (e) => {
let car = cars[e.target.dataset.row];
console.log(car);
}
renterTable();
#parking th,
#parking td {
white-space: nowrap;
font-size: 14px;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" />
<div class="table-responsive">
<table id="parking" class="table table-striped m-0">
<thead>
<tr>
<th>Registration plate</th>
<th>Arrived</th>
<th>Deaparted</th>
<th>Status</th>
<th class="text-right">Pay</th>
<th class="text-right">Actions</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
这个小函数的目的是将 clicked“Summary”按钮对应的汽车记录到控制台:
const changeStatus = (e) => {
let car = cars[e.target.dataset.row];
console.log(car);
}
然而,我得到的不是想要的结果,而是 Cannot read property 'target' of undefined"
.
我的错误在哪里?
你未定义是因为你没有传递事件对象。变化:
onclick="changeStatus()"
至:
onclick="changeStatus(event)"
另请注意,使用内联处理程序不是一个好的做法。如果您关心良好做法,请不要使用内联事件处理程序。 改为 select javascript 中的元素并将点击事件侦听器附加到它:
const btns = document.querySelectorAll('.btn')
btns.forEach(btn => btn.addEventListener("click", e => {
let car = cars[btn.dataset.row];
console.log(car);
}));
问题出在您的按钮标签中:尝试将 onclick="changeStatus()"
替换为 onclick="changeStatus"
您应该将函数的引用传递给按钮,这就是事件(您的变量 e
)未设置的原因
const changeStatus = (e) => {
let car = cars[e.target.dataset.row];
它说无法读取 undefined
的 target
。
因此,e
是undefined
。
所以看看调用函数的地方:
onclick="changeStatus()"
您没有传递任何参数,因此 e
获得默认值 undefined
。
不要使用固有事件属性。他们有很多问题。
如果您使用 addEventListener
添加事件处理程序,那么它将获得一个事件对象作为第一个参数。
const buttons = document.querySelector(".btn-success");
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener("click", changeStatus);
}
考虑使用 event delegation 而不是将事件处理程序单独绑定到每个按钮。
首先你必须传递一些东西来运行:
onclick="changeStatus(this)"
你的 THIS 表示此刻 'this element'(这个答案中有这么多 'this'!)。
这意味着你没有event.target,但是元素:
const changeStatus = (element) => {
let car = cars[element.dataset.row];
console.log(car);
}
工作代码位于:
https://jsfiddle.net/jmz37261/
顺便说一句。更好的选择是 addEventListener 而不是 onclick。
@编辑:
也许最好采用此解决方案(在这种特定情况下):
<button data-row="${i}" onclick="changeStatus(${i})" class="btn btn-sm btn-success">Summary</button>
然后:
const changeStatus = (row) => {
let car = cars[row];
console.log(car);
}
我正在使用从对象数组“提取”的数据填充 HTML table:
let cars = [{
licensee: '23456 NY',
arrival: new Date(2020, 9, 16, 11, 34, 30),
leave: new Date(),
isParked: true
},
{
licensee: '56456 NY',
arrival: new Date(2020, 8, 24, 10, 33, 30),
leave: new Date(2020, 8, 24, 13, 50, 35),
isParked: false
},
{
licensee: '56780 NY',
arrival: new Date(2020, 5, 12, 20, 33, 30),
leave: new Date(2020, 5, 12, 21, 33, 30),
isParked: false
}
];
const formatDate = (date) => {
var hours = date.getHours();
var minutes = date.getMinutes();
var ampm = hours >= 12 ? 'PM' : 'AM';
hours = hours % 12;
hours = hours ? hours : 12;
minutes = minutes < 10 ? '0' + minutes : minutes;
var strTime = hours + ':' + minutes + ' ' + ampm;
return date.getDate() + "/" + (date.getMonth() + 1) + "/" + date.getFullYear() + " " + strTime;
}
const secondsToHours = (d) => {
d = Number(d);
let h = Math.ceil(d / 3600);
return h;
}
const makeBill = (car) => {
let arrivedAt = new Date(car.arrival).getTime();
let leftAt = new Date(car.leave).getTime();
//duration in seconds
let duration = (leftAt - arrivedAt) / 1000;
let hoursBilled = secondsToHours(duration);
let billValue = car.isParked ? "-" : 10 + (hoursBilled - 1) * 5 + " LEI";
return billValue;
}
const renterTable = () => {
// Show new on top
cars.reverse();
let results = '';
for (var i = 0; i < cars.length; i++) {
results += `<tr>
<td>${cars[i].licensee}</td>
<td>${formatDate(cars[i].arrival)}</td>
<td>${formatDate(cars[i].leave)}</td>
<td class="text-center">${showStatus(cars[i])}</td>
<td class="text-right">${makeBill(cars[i])}</td>
<td class="text-right">
<button data-row="${i}" onclick="changeStatus(e)" class="btn btn-sm btn-success">Summary</button>
</td>
</tr>`;
}
document.querySelector("#parking tbody").innerHTML = results;
}
const showStatus = (car) => {
return car.isParked ? "In" : "Out";
}
const changeStatus = (e) => {
let car = cars[e.target.dataset.row];
console.log(car);
}
renterTable();
#parking th,
#parking td {
white-space: nowrap;
font-size: 14px;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet" />
<div class="table-responsive">
<table id="parking" class="table table-striped m-0">
<thead>
<tr>
<th>Registration plate</th>
<th>Arrived</th>
<th>Deaparted</th>
<th>Status</th>
<th class="text-right">Pay</th>
<th class="text-right">Actions</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
这个小函数的目的是将 clicked“Summary”按钮对应的汽车记录到控制台:
const changeStatus = (e) => {
let car = cars[e.target.dataset.row];
console.log(car);
}
然而,我得到的不是想要的结果,而是 Cannot read property 'target' of undefined"
.
我的错误在哪里?
你未定义是因为你没有传递事件对象。变化:
onclick="changeStatus()"
至:
onclick="changeStatus(event)"
另请注意,使用内联处理程序不是一个好的做法。如果您关心良好做法,请不要使用内联事件处理程序。 改为 select javascript 中的元素并将点击事件侦听器附加到它:
const btns = document.querySelectorAll('.btn')
btns.forEach(btn => btn.addEventListener("click", e => {
let car = cars[btn.dataset.row];
console.log(car);
}));
问题出在您的按钮标签中:尝试将 onclick="changeStatus()"
替换为 onclick="changeStatus"
您应该将函数的引用传递给按钮,这就是事件(您的变量 e
)未设置的原因
const changeStatus = (e) => { let car = cars[e.target.dataset.row];
它说无法读取 undefined
的 target
。
因此,e
是undefined
。
所以看看调用函数的地方:
onclick="changeStatus()"
您没有传递任何参数,因此 e
获得默认值 undefined
。
不要使用固有事件属性。他们有很多问题。
如果您使用 addEventListener
添加事件处理程序,那么它将获得一个事件对象作为第一个参数。
const buttons = document.querySelector(".btn-success");
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener("click", changeStatus);
}
考虑使用 event delegation 而不是将事件处理程序单独绑定到每个按钮。
首先你必须传递一些东西来运行:
onclick="changeStatus(this)"
你的 THIS 表示此刻 'this element'(这个答案中有这么多 'this'!)。
这意味着你没有event.target,但是元素:
const changeStatus = (element) => {
let car = cars[element.dataset.row];
console.log(car);
}
工作代码位于:
https://jsfiddle.net/jmz37261/
顺便说一句。更好的选择是 addEventListener 而不是 onclick。
@编辑:
也许最好采用此解决方案(在这种特定情况下):
<button data-row="${i}" onclick="changeStatus(${i})" class="btn btn-sm btn-success">Summary</button>
然后:
const changeStatus = (row) => {
let car = cars[row];
console.log(car);
}