繁体   English   中英

JavaScript 动态按钮 onClick 事件(可变范围)

[英]JavaScript Dynamic Button onClick event (variable scope)

背景

我正在根据从查询数据库的 AJAX 请求返回的 JSON 对象动态创建相当多的按钮。

然后,每个按钮都需要对同一个数据库进行后续 AJAX 调用,具体取决于我放入每个按钮的onClick函数中的信息。

基本上,url 是"api/{foo}/{bar}/{thing}/" ,如果我只调用"api/"它给了我所有可能的选项foo 如果我调用"api/book/"它将为我提供bar where foo = "book"所有可能的选项......

我正在尝试的方法。

//getJSON is a promise function that returns a JSON object
getJSON("api")
         // volumes is the JSON object that contains an array of objects
         // each object is {book:"someTitle",url:"titleShorthand"}
        .then((volumes) => {
            for (var vol in volumes) {
                //create Button returns a document.crateElement(input) 
                   //with type=button and value = the passed in param.
                var btn = createButton(volumes[vol].book)
                btn.addEventListener('click', function(){
                    getJSON("api/" + volumes[vol].url)
                    .then((books) => {
                        console.log(books)
                    })
                })
                volumeDiv.appendChild(btn)
            }
        })

问题

所有 button.onClick 事件都是相同的,因为在console.log(books) ,无论我单击哪个按钮,都只会给我最后一组书籍。 volumes[vol].url似乎随着 for 循环的每次迭代而被重写,对于每个按钮,而不仅仅是新创建的按钮。

那是因为您在for循环中声明了一个函数。 由于闭包的工作方式,当您在循环中声明的函数运行时, volume[vol]值始终是最后一个值。

为了解决这个问题,您可以使用高阶函数

我必须模拟一些函数才能使此代码段起作用,但是您必须在代码中编写像getEventListener这样的函数才能使其正常工作。

 var volumeDiv = document.getElementById('container') function getJSON (url) { return new Promise (resolve => { var vol1 = { book: "vol1", url: "vol1" } var vol2 = { book: "vol2", url: "vol2" } var map = { 'api': { vol1, vol2 }, 'api/vol1': vol1, 'api/vol2': vol2 } resolve(map[url]) }) } function createButton (name) { console.log(`creating button ${name}`) var btn = document.createElement('input') btn.type = 'button' btn.value = name return btn } function getEventListener (url) { return () => { getJSON(url) .then((books) => { console.log(books) }) } } getJSON("api") .then(volumes => { for (var vol in volumes) { var volumeUrl = volumes[vol].url var btn = createButton(volumes[vol].book) btn.addEventListener('click', getEventListener("api/" + volumeUrl)) volumeDiv.appendChild(btn) } })
 <div id="container" />

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM