编辑textContent或innerHTML会导致eventListener失效

时间:2015-10-28 20:14:14

标签: javascript forms select input

我从js开始,所以请原谅我明显的错误。我试图重新创建选择输入,只有很少的选项可用于标记样式。

简要介绍一下我要做的事情:

  1. 隐藏选择
  2. 使用第一个选项的文本创建父div,并将其附加到原始隐藏选择。
  3. 在点击切换类(它显示并隐藏子元素)上添加eventListener
  4. 使用原始隐藏选择中的值和选项文本创建内部div。
  5. 为每个人添加eventListener以替换select。
  6. 的值

    这几行js和几行css让我很容易选择样式。

    
    
    // Define select and options
    var select = document.getElementById('select');
    var children = select.children;
    
    // Recreate select via divs and keep same class
    select.style.display = 'none';
    var selectNew = document.createElement('div');
    selectNew.className = select.classList;
    selectNew.textContent = select.children[0].text;
    select.parentNode.insertBefore(selectNew, select);
    selectNew.addEventListener('click', function() {
      toggleChildren();
    });
    
    function toggleChildren() {
      selectNew.classList.toggle('active');
    }
    
    // remap children
    var childArray = [];
    for (var i = 0; i < children.length; i++) {
      var child = document.createElement('div');
      child.innerHTML = select.children[i].text;
      child.dataset.value = select.children[i].value;
      selectNew.appendChild(child);
      childArray.push(child);
    
      child.addEventListener("click", function () {
        selectChoice();
      });
    }
    
    function selectChoice() {
      var which = childArray.indexOf( event.target || event.srcElement);
      select.value = children[which].value;
      // selectNew.textContent = children[which].text;
    }
    &#13;
    .select {
      position: relative;
      width: 100%;
      line-height: 3em;
      background: #eee;
    }
    .select > div {
      position: absolute;
      display: none;
      width: 100%;
    }
    .select > div:nth-child(1) {
      top: 2em;
    }
    .select > div:nth-child(2) {
      top: 4em;
    }
    .select > div:nth-child(3) {
      top: 6em;
    }
    .select > div:nth-child(4) {
      top: 8em;
    }
    .select > div:nth-child(5) {
      top: 10em;
    }
    .select > div:hover {
      background: #eee;
    }
    .select.active > div {
      display: block;
    }
    &#13;
    <select name="sortby" id="select" class="select">
      <option value="val1">Value 1</option>
      <option value="val2">Value 2</option>
      <option value="val3">Value 3</option>
      <option value="val4">Value 4</option>
      <option value="val5">Value 5</option>
    </select>
    &#13;
    &#13;
    &#13;

    每当我尝试更新父元素中的文本时,通过以下方式显示所选选项的文本:

    selectNew.textContent = children[which].text;
    

    它会杀死此元素之前添加的事件Listener。有人能帮助我理解我做错了什么吗?我在eventListeners的行为中错过了什么?

2 个答案:

答案 0 :(得分:1)

您引用的行确实会导致问题,但不会因为它会导致侦听器失败。它实际上用文本替换了selectNew的全部内容。 你想要的是替换第一个子节点的文本,即textContent节点。

如果您将行更改为:

selectNew.firstChild.textContent = children[which].text;

然后一切都按预期工作。

JSFiddle here

奖励回答 至于添加侦听器以更改事件的其他问题: 您不仅可以在div上使用侦听器来处理'change'事件,而且只能在输入等表单元素上使用。

但是,您可以检测点击处理程序中的更改,如下所示:

function selectChoice() {
    var which = childArray.indexOf(event.target || event.srcElement);
    select.value = children[which].value;
    if (selectNew.firstChild.textContent != children[which].text) {
        alert('select value has been changed');
        selectNew.firstChild.textContent = children[which].text;
    }
}

更新了fiddle here

答案 1 :(得分:1)

它不会终止您的事件,您通过设置textContent删除选项元素,因此单击div时无需显示任何内容。您需要设置div的第一个TextNode的textContent。

// Define select and options
var select = document.getElementById('select');
var children = select.children;

// Recreate select via divs and keep same class
select.style.display = 'none';
var selectNew = document.createElement('div');
selectNew.className = select.classList;
selectNew.textContent = select.children[0].text;
select.parentNode.insertBefore(selectNew, select);
selectNew.addEventListener('click', function(e) {
  toggleChildren(e);
});

function toggleChildren() {
  selectNew.classList.toggle('active');
}

// remap children
var childArray = [];
for (var i = 0; i < children.length; i++) {
  var child = document.createElement('div');
  child.innerHTML = select.children[i].text;
  child.dataset.value = select.children[i].value;
  selectNew.appendChild(child);
  childArray.push(child);

  child.addEventListener("click", function () {
    selectChoice();
  });
}

function selectChoice() {
  var which = childArray.indexOf( event.target || event.srcElement);
  select.value = children[which].value;

  //get the first textnode and set its textContent
  selectNew.childNodes[0].textContent = children[which].text;
}
.select {
  position: relative;
  width: 100%;
  line-height: 3em;
  background: #eee;
}
.select > div {
  position: absolute;
  display: none;
  width: 100%;
}
.select > div:nth-child(1) {
  top: 2em;
}
.select > div:nth-child(2) {
  top: 4em;
}
.select > div:nth-child(3) {
  top: 6em;
}
.select > div:nth-child(4) {
  top: 8em;
}
.select > div:nth-child(5) {
  top: 10em;
}
.select > div:hover {
  background: #eee;
}
.select.active > div {
  display: block;
}
<select name="sortby" id="select" class="select">
  <option value="val1">Value 1</option>
  <option value="val2">Value 2</option>
  <option value="val3">Value 3</option>
  <option value="val4">Value 4</option>
  <option value="val5">Value 5</option>
</select>