如何使用字符串文字中的 onclick 将对象传递给另一个函数

How to pass an object to another function with an onclick in a string literal

我有点被这个难住了。当我点击一个按钮时,我想将一个对象传递给另一个函数。这样我就可以在最终函数中使用该对象。

在这个例子中,我想将 car 对象从 renderCar 函数传递给 makeEditable 当我点击编辑按钮时的功能。

我试过的:
<button onclick="makeEditable(${car})">Edit</button>
<button onclick="makeEditable(car)">Edit</button>
<button onclick="makeEditable('${car}')">Edit</button>

我可以传入一个字符串,比如
<button onclick="makeEditable('${car.type}')">Edit</button>
但没有成功传递整个对象。

这里我写了一个我想要做的例子。

Fiddle: https://jsfiddle.net/kyleteeter/v8gs05e1/10/

HTML

<div id="root" ></div>

JS

let cars = [
  {
    "color": "purple",
    "type": "minivan",
    "capacity": 7
  },
  {
    "color": "red",
    "type": "station wagon",
    "capacity": 5
  }
]

cars.map(car => {
    this.root.innerHTML += this.renderCar(car)
    });
    

function renderCar(car) {
    return `<div><div data-type="color">${car.color}</div><div data-type="type">${car.type}</div><div data-type="capacity">${car.capacity}</div><button onclick="makeEditable('${car}')">Edit</button></div>`
}

function makeEditable(car){
  console.log(car)
} 

如果您查看生成的 HTML,问题就会变得非常明显。在其中,您将拥有 '[object Object]' 只是因为如果您尝试将对象转换为字符串会发生这种情况,并且很明显,从这一点开始您不能调用 makeEditable() 并期望对象神奇地出现 - 你最终调用函数时使用 '[object Object]' 作为参数,好吧,这不是你要找的对象。

我看到了两种可能的方法:

  1. 尝试像这样将整个对象推入 HTML:
function renderCar(car) {
  return `<div><div data-type="color">${car.color}</div><div data-type="type">${car.type}</div><div data-type="capacity">${car.capacity}</div><button onclick="makeEditable('${encodeURI(JSON.stringify(car))}')">Edit</button></div>`;
}

...然后,要正确检索它,您必须在 makeEditable() 函数中反转该过程:

function makeEditable(data) {
  let car = JSON.parse(decodeURI(data));
  console.log(car);
}

...但这有点丑陋,可能并不总是有效。

编辑: 使用 btoa()atob()(而不是分别使用 encodeURI(JSON.stringify()JSON.parse(decodeURI(data)))如果走这条路可能会更好,我只是在撰写本文时没有想到这一点。

  1. 将一些唯一 ID 与数据一起存储,仅将其传递到 HTML,然后使用它对数组进行查找:
let cars = [
  {
    color: "purple",
    type: "minivan",
    capacity: 7,
    id: "2a93d4e1-9ee9-4490-b4a8-da836cf81d7f",
  },
  {
    color: "red",
    type: "station wagon",
    capacity: 5,
    id: "aa207e90-08d1-434f-afeb-aed1dbd1dab9",
  }
];

cars.map((car) => {
  this.root.innerHTML += this.renderCar(car);
});

function renderCar(car) {
  return `<div><div data-type="color">${car.color}</div><div data-type="type">${car.type}</div><div data-type="capacity">${car.capacity}</div><button onclick="makeEditable('${car.id}')">Edit</button></div>`;
}

function findById(id, array) {
  return array.find((e) => e.id === id);
}

function makeEditable(id) {
  let car = findById(id, cars);
  console.log(car);
}

我认为您可以创建一个文档片段或只是一个元素并将事件侦听器附加到它。这样您将更灵活地传递任何类型的参数。

但是,如果您真的想让它按照您尝试过的方式工作,请考虑下面的示例。

我会说它的实现有点矫枉过正,但它确实有效。

基本上,通过这种方式传递的任何参数都会被转换为字符串(因为它用引号引起来)。要利用它,您可以将对象字符串化并对其进行 base64 编码(以将其保留为字符串),然后在目标函数中以相同的方式解码和解析它。

const cars = [
  {
    color: 'purple',
    type: 'minivan',
    capacity: 7,
  },
  {
    color: 'red',
    type: 'station wagon',
    capacity: 5,
  },
];

cars.forEach((car) => {
  this.root.innerHTML += renderCar(car);
});

function makeEditable(car) {
  const parsed = JSON.parse(atob(car));
  console.log(parsed);
}

function renderCar(car) {
  const stringified = btoa(JSON.stringify(car));
  return `
    <div>
      <div data-type='color'>${car.color}</div>
      <div data-type='type'>${car.type}</div>
      <div data-type='capacity'>${car.capacity}</div>
      <button onclick="makeEditable('${stringified}')">Edit</button>
    </div>
  `;
}
<div id="root"></div>