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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript动态按钮onClick事件(变量范围)相关的知识,希望对你有一定的参考价值。

背景

我根据查询数据库的AJAX请求返回的JSON对象动态创建了很多按钮。

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

基本上,网址是"api/{foo}/{bar}/{thing}/",如果我只打电话给"api/"它给了我所有可能的选择foo。如果我打电话给"api/book/"它会给我所有可能的选择bar 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]的工作方式,closures的值始终是你在循环中声明的函数运行时的最后一个值。

要解决这个问题,你可以使用higher order function

我不得不模拟一些函数来使这个片段工作,但是你必须在代码中编写像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" />

以上是关于JavaScript动态按钮onClick事件(变量范围)的主要内容,如果未能解决你的问题,请参考以下文章

javascript的事件响应

动态 OnClick 按钮事件

js动态给按钮增加onclick的函数事件(带参数)

动态创建 onclick 事件锚元素 - Javascript

JS5(事件)

JS事件-让网页交互