问题描述
我正在尝试动态添加 html 代码和 JavaScript 函数。 html 代码基本上是一张卡片,里面有段落,我正在为该段落实现一个阅读更多按钮。所以我有多张这样的卡片,每张卡片都有一个与之关联的 readMore 功能。因此卡片 1 将具有关联的 readMore0 函数,依此类推....
现在添加html内容和javascript函数时,只运行第一张卡对应的函数,其他卡对应的函数报错 rooms.html:1 Uncaught ReferenceError: readMore3 未定义 在 HTMLAnchorElement.onclick (rooms.html:1)
代码如下:-
function display_card() {
var url = "URL";
var script = document.createElement('script');
script.type = 'text/javascript';
var body = document.getElementsByTagName('body')[0];
fetch(url,{
method: 'get',})
.then( (response) => {
return response.json()
})
.then((id_json) => {
// Work with JSON data here
console.log(id_json);
var scripts = "";
var count = 0;
for (i in id_json) {
var room_url = "URL" + id_json[i]._id;
// console.log(i);
fetch(room_url,{
method: 'get',})
.then((resp) => {
return resp.json();
})
.then((room_data) => {
// Work with JSON data here
console.log(count);
scripts += `
function readMore${count}() {
console.log(readMore${count});
var dots = document.getElementById("dots${count}");
var moreText = document.getElementById("more${count}");
var btnText = document.getElementById("readbtn${count}");
if (dots.style.display === "none") {
dots.style.display = "inline";
btnText.innerHTML = "Read more";
moreText.style.display = "none";
} else {
dots.style.display = "none";
btnText.innerHTML = "Read less";
moreText.style.display = "inline";
}
};
`
checkout_html += `
<div class="blog-slider mt-5 " data-aos='fade-up'>
<div class="blog-slider__wrp swiper-wrapper">
<div class="blog-slider__item swiper-slide">
<div class="blog-slider__content">
<div class="blog-slider__text" data-aos="zoom-in">
${room_data.description.slice(0,100)}
<span id="dots${count}">...</span> <span id="more${count}">
${room_data.description.slice(100)}
<br> </span>
<a onclick="readMore${count}($(this))" id="readbtn${count}">Read more</a>
</div>
</div>
</div>
</div>
</div>
`
if (checkout_html == "undefined") {
checkout_html = "";
}
count ++ ;
})
.catch((err) => {
console.log(err);
// Do something for an error here
})
.finally(function () {
script.text = scripts;
body.appendChild(script);
document.getElementById('cards').innerHTML = checkout_html;
})
} //end of for loop
})
.catch((err) => {
console.log(err);
})
}
为什么第一个 readMore0() 函数只在这里工作,而其他 readMore 函数如 readMore1,readMore2.......给这个错误 **Uncaught ReferenceError: readMore3 is not defined at HTMLAnchorElement .onclick **
我试图查看这个 similar 问题,但什么也找不到
解决方法
这是一个通用示例,演示了他在评论中提到的@trincot 模式。
不是在每个动态子项上绑定一个事件侦听器,而是只在所有子项的公共父项上绑定一个侦听器,绑定时需要在页面中并保存所有项。
>当前或未来子项上的任何点击事件都会冒泡到该父项,并且使用 event
参数,您将能够确定点击是否在正确类型的元素/子项上,如果是,执行您的业务逻辑。
// we bind only once on the parent of all future children:
// as you can see,the parent is initially empty
document.getElementById('items').addEventListener('click',function(event) {
if (event.target.nodeName === 'BUTTON') {
const container = event.target.closest('.flexer');
if (container) {
alert(`You clicked on item with id ${container.dataset.id} and userId ${container.dataset.userId}!`);
}
}
});
function fetchItems() {
fetch('https://jsonplaceholder.typicode.com/todos')
.then(response => response.json())
.then(json => {
json.forEach(item => {
const pre = document.createElement('pre');
pre.innerText = JSON.stringify(item,null,2);
const button = document.createElement('button');
button.innerText = 'Click me';
const container = document.createElement('div');
container.dataset.userId = item.userId;
container.dataset.id = item.id;
container.classList.add('flexer');
container.appendChild(pre);
container.appendChild(button);
document.getElementById('items').appendChild(container);
})
})
}
function refreshItems() {
document.getElementById('items').innerHTML = '';
setTimeout(() => {
fetchItems();
},1000)
}
refreshItems() // initial loading of items...
.flexer {
display: flex;
border: 1px solid #f5f5f5;
margin-bottom: .5rem;
align-items: flex-end;
padding: .5rem;
justify-content: space-between;
}
.floating-button {
position: fixed;
left: 1rem;
bottom: 1rem;
}
<button onclick="refreshItems()" class="floating-button">Refresh items</button>
<div id="items"></div>
不仅绑定一个事件而不是数百个事件更有效,而且您还避免了在处理部分更新时必须跟踪哪些元素具有事件绑定而哪些没有的痛苦目前正在处理。
显然,我可以将项目信息直接放在按钮上。我将它放在容器上以演示如何在需要时导航 DOM 以获取您的信息。
让我们用类似“阅读更多”的功能扩展上面的例子:
// we bind only once on the parent of all future children:
// as you can see,function(event) {
if (event.target.nodeName === 'BUTTON') {
fetchItem(event.target.dataset.id,event.target.dataset.userId);
}
});
function fetchItems() {
fetch('https://jsonplaceholder.typicode.com/todos')
.then(response => response.json())
.then(json => {
json.forEach(item => {
const pre = document.createElement('pre');
pre.innerText = JSON.stringify(item,2);
const button = document.createElement('button');
button.innerText = 'Read more';
const container = document.createElement('div');
Object.assign(button.dataset,item);
container.appendChild(pre);
container.appendChild(button);
document.getElementById('items').appendChild(container);
})
})
}
function fetchItem(id,userId) {
Promise.all([
`https://jsonplaceholder.typicode.com/todos/${id}`,`https://jsonplaceholder.typicode.com/users/${userId}`,].map(url => fetch(url).then(r => r.json())))
.then(([item,user]) => {
item.user = user;
const button = [...document.querySelectorAll('button')].find(b => b.dataset.id === id);
const parent = button.closest('div');
const pre = parent.querySelector('pre');
pre.innerHTML = JSON.stringify(item,2);
button.remove();
})
}
function refreshItems() {
document.getElementById('items').innerHTML = '';
setTimeout(() => {
fetchItems();
},1000)
}
refreshItems() // initial loading of items...
#items > div {
padding: .5rem;
position: relative;
box-shadow: 0 1px 3px 0 rgba(0,.20),0 1px 1px 0 rgba(0,.14),0 2px 1px -1px rgba(0,.12);
background-color: white;
border-radius: 4px;
}
#items button {
position: absolute;
bottom: 1rem;
right: 1rem;
}
#items pre {
white-space: pre-wrap;
}
.floating-button {
position: fixed;
left: 1rem;
bottom: 1rem;
z-index: 1;
box-shadow: 0 0 0 10px rgba(255,255,.5);
}
#items {
display: grid;
grid-template-columns: repeat(auto-fit,minmax(320px,1fr));
grid-gap: .5rem;
}
body {
background-color: #f5f5f5;
}
<button onclick="refreshItems()" class="floating-button">Refresh items</button>
<div id="items"></div>