动态创建的js脚本onClick函数变量不绑定当前值

时间:2015-08-12 23:04:41

标签: javascript function variables dynamically-generated

newButton.onclick = function() {
  launchForm(
    this, 
    incoming[(10 * (incoming.length / fields)) + z],
    incoming[(48 * (incoming.length / fields)) + z]);
};

因此,当我动态生成其中4个按钮时,四个按钮中的每一个都将第一个按钮的信息传递给函数launchForm。我怀疑这是因为当变量z完成它的for语句时它会回到0.如果是这样的情况,而不是+ z对于按钮1是+ 1而对于按钮2是+ z是+ 2,它变为+ z为+ 0对于所有按钮。

我该如何解决这个问题?感谢。

编辑:添加以响应更多信息的请求:

    var newButton = document.createElement('button');
    newButton.className = 'pure-button pure-button-primary mikeButton';
    newButton.innerHTML='Launch Form';
    newDiv4.appendChild(newButton);

所以我对这一切都很新,所以我可能使用了错误的术语。我理解在加载页面后创建的项目被认为是动态的。 ---虽然我是新人,但我相信这个问题在于我最初提出的问题。通过设置警报和测试,我可以看到第一个按钮完全正常工作,所有适当的参数都完美地传递。只需按钮2,3和4也可以启动按钮启动按钮。 Incoming.length不会更改,字段不会更改。与第二个实例创建newButton的第一个实例时唯一不同的是z。 ---当我在创建第2个,第3个和第4个按钮后立即设置警报时,它们会准确显示应该传递的参数。但是在创建它们的函数完成之后,它基于使用z作为变量的for语句,它们转换回来就好像z是0并使用按钮1的参数(因为z在按钮1的参数中等于0)。我只需将+ 1,+ 2,+ 3硬编码到代码而不是z中,但创建的按钮数量取决于查询。有时1个按钮,有时10个。所以这真的不是一个选择。

我希望这会有所帮助。

2 个答案:

答案 0 :(得分:0)

ES5不使用块上下文,而是在函数上下文中运行。这意味着在for循环中你必须立即使用索引变量,否则如果你(例如)在回调函数中引用它,你将获得该变量的值,就像它在回调执行期间一样。

有多种方法可以解决这个问题,可能最容易在代码中进行演示:

"use strict";

// first off, using [].forEach.call has some cons so we should have 
// a way to convert a NodeList to an Array
var toArray = function(input) {
  var output = [];
  // check if we have an array-like object
  if (input && typeof input.length === 'undefined') { return; }
  for (var i = 0; i < input.length; i++) {
    output.push(input[i]);
  }
  return output;
}

// we get lists that contain links to parse
var linkLists = document.getElementsByClassName('link-list');
// and one div to store buttons
var buttonDiv = document.getElementById('buttons');

// we convert the NodeLists to arrays to get the forEach function
toArray(linkLists).forEach(function(list) {

  // now we iterate over the list children
  toArray(list.children).forEach(function(link, index) {

    var clickHandler = function(e) {
      e.preventDefault(); // prevent navigating anywhere
      alert("Hi! I'm a link named '" + link.textContent +
            "' and my forEach index is: " + index +
            " (" + typeof index + ")");
    }

    link.onclick = clickHandler;

    // now let's use the link list as a mock data source and generate buttons
    var newButton = document.createElement('button');
    newButton.textContent = link.textContent;
    newButton.onclick = clickHandler;
    buttonDiv.appendChild(newButton);
    
  });
});
<ul class="link-list">
  <li><a href="#">link 1</a></li>
  <li><a href="#">link 2</a></li>
  <li><a href="#">link 3</a></li>
</ul>
<div id="buttons"></div>

有关why [].forEach.call is discouraged的更多详情。

现在来说明通常存在的陷阱:

"use strict";

// we get lists that contain links to parse
var linkLists = document.getElementsByClassName('link-list');
// and one div to store buttons
var buttonDiv = document.getElementById('buttons');

// let's switch the forEach calls to for loops
// variables added for naming sanity
for (var x = 0; x < linkLists.length; x++) {
  var children = linkLists[x].children;
  
  for (var y = 0; y < children.length; y++) {
    var link = children[y],
        index = y;
    
    // everything is fine up to this point
    // now as there's no block context that would keep the variable
    // values for the handler we'll get the last value it had
    var clickHandler = function(e) {
      e.preventDefault(); // prevent navigating anywhere
      alert("Hi! I'm (possibly) a link named '" + link.textContent +
            "' and my for index is: " + index +
            " (" + typeof index + ") \n\n :(");
    }

    link.onclick = clickHandler;
  }
  
}

// now, what few beginners remember is that when there's no block
// context then all of the variables used above are available outside

// let's reuse the buttons div to get all variable values here
buttons.innerHTML = "Variable values after parsing for loops:" +
                    "<br/>x = " + x +
                    "<br/>y = " + y +
                    "<br/>link.textContent = " + link.textContent + 
                    "<br/>index = " + index;

// so now when we click the link the callback function gets
// the variables from above and not from it's block context
// as it would in other programming languages
<ul class="link-list">
  <li><a href="#">link 1</a></li>
  <li><a href="#">link 2</a></li>
  <li><a href="#">link 3</a></li>
</ul>
<div id="buttons"></div>

答案 1 :(得分:0)

所有处理程序在单击时引用z的当前值。要在定义时使用z的值,我建议

  1. 通过调用Function作为构造函数来创建onclick处理程序,并在正文字符串中计算z的currrent值:

    newButton.onclick = new Function("launchForm(this, incoming[(10 * (incoming.length / fields)) + "+ z + "], incoming[(48 * (incoming.length / fields)) + " + z  + "]);");
    
  2. 或者在创建onclick处理程序时将z的值保存在按钮对象上:

    newButton["data-z"] = z;
    newButton.onclick = function() {....};
    
  3. 但替换对&#34; z&#34;的引用用&#34;这[&#39; data-z&#39;]&#34;在功能体中。