使用模板文字中的参数调用函数时出现 JS 错误

JS Error when calling function with argument from Template Literal

我正在使用模板文字将内容插入页面:

entries.forEach((entry) => {
  let id = entry.id;
  entryList.innerHTML += `
  <div class="entry">
      <button class="delete-btn" onclick="deleteEntry(${id})">D</button>
  </div>`;
});

点击按钮时出现“未捕获的语法错误:无效或意外标记”。

但是如果我改为在按钮中执行:

<button class="delete-btn" onclick="deleteEntry(3)">D</button>

错误没有发生。

你能告诉我这里有什么问题吗?谢谢。

对于字符串文字,您必须使用 `` 引号

onclick=`deleteEntry(${id})`

这是工作示例:

const entries = [{id: 1, text:'Hello World!'}, {id: 2, text:'ABC'}, {id: 3, text:'XYZ'}];

const entryList = document.querySelector('#entryList');

deleteEntry = function(id) {
  console.log('clicked id : ', id);
}

entries.forEach((entry) => {
  let id = entry.id;
  entryList.innerHTML += `
    <div class="entry">
      <button class="delete-btn" onclick="deleteEntry(${id})">D${id}</button>
    </div>`;
});
<div id="entryList"></div>

您的 id 值需要用引号引起来。你说过:

the HTML generated is just what I wanted: <button class="delete-btn" onclick="deleteEntry(e5f7ce9a-1383-5d7c-9a9b-e8ce73d09041)">D</button>

但是看看属性中的代码:

deleteEntry(e5f7ce9a-1383-5d7c-9a9b-e8ce73d09041)

这是语法错误。字符串需要用引号引起来。

最小的变化是在 ${id} 周围添加 ',假设您知道 ' 永远不会出现在 id 值中:

entries.forEach((entry) => {
  let id = entry.id;
  entryList.innerHTML += `
    <div class="entry">
      <button class="delete-btn" onclick="deleteEntry('${id})'">D</button>
    </div>`;

...但正如我在评论中所说,使用 +=innerHTML 以及使用 onxyz-attribute-style 事件处理程序通常都是坏主意:

  • 当您执行 element.innerHTML += "some string" 时,浏览器必须遍历 element 中的整个 DOM 结构并构建一个 HTML 字符串以传递给您的 JavaScript代码。然后您的 JavaScript 代码必须附加到字符串并将其返回给浏览器。然后浏览器必须完全删除 element 的所有内容,解析 JavaScript 代码给它的字符串,并为曾经存在的元素构建新元素(然后也为新元素) .这是很多不必要的工作,而且是有损的:事件处理程序丢失,用户的焦点元素(如果它在 element 中)丢失,并且表单元素中的当前选择丢失。相反,请考虑 createElementappendChildinsertBeforeinsertAdjacentHTML、insertAdjacenText` 和其他各种 DOM 方法。
  • onxyz-attribute-style 事件处理程序要求您发出 syntactically-valid 代码 对其进行编码,以便它可以在属性中正确显示, 也只能使用全局函数。通常,最好避免使用全局函数。而是考虑使用现代事件处理,addEventListener 等。这也可以防止导致问题的问题(不输出 syntactically-valid 代码)。

例如:

entries.forEach(({id}) => {
    entryList.insertAdjacentHTML(
        "beforeend",
        `<div class="entry">
            <button class="delete-btn">D</button>
        </div>`
    );
    entryList.lastElementChild.querySelector("button").addEventListener(
        "click", () => deleteEntry(id)
    );
    // ...

这是我在那里所做的:

  1. 我在参数列表中使用解构来挑选出对象的 id 属性,这样代码就不会关闭对象引用。
  2. 我使用 insertAdjacentHTML 将 DOM 结构添加到 entryList 的末尾,而没有 破坏并重新创建所有以前的元素。
  3. 我在新元素 (entryList.lastElementChild) 上使用 querySelector 来获取按钮并使用 addEventListener 向其添加事件处理程序。这避免了将 id 值用引号引起来的任何顾虑,并允许您根据需要使用 deleteEntry non-global。