【问题标题】:JavaScript querySelector versions of JqueryJquery 的 JavaScript querySelector 版本
【发布时间】:2019-07-12 15:20:17
【问题描述】:

我正在尝试摆脱 JQuery。

我有一个名为“clientProfiles”的 div

<div class="paperlist" data-role='listview' data-inset='true' data-split-icon='delete' id='clientProfiles'></div>

我的应用程序会用这样的按钮填充“div”。

function getClientHtml(device) {

                var html = "";
                html += '<div data-name="' + device.Name + '" data-id="' + device.Id + '"data-app="' + device.AppName + '" style="border-radius: 2px; border: 1px solid rgba(0,0,0,0.158)" class="clientProfile listItem">';
                html += '<img style="float-left; width:3%;" src="' + deviceNameImage(device.Name) + '"/>';
                html += '<div class="listItemBody">';
                html += '<h3 class="listItemBodyText">' + device.Name + ' - ' + device.AppName + '</h3>';
                html += '</div>';
                html += '<i class="md-icon btnDeleteProfile" data-index="0">close</i>';
                html += '</div>';
                html += '<br />';
                return html;
            };

用户添加按钮后的 html 如下所示:

<div class="paperlist" data-role="listview" data-inset="true" data-split-icon="delete" id="clientProfiles">
<div data-name="Xbox One" data-id="mcX7xXZksA1fJooKY2SRS5soNbFgM4lQurFx3bxr2s" data-app="Theater" style="border-radius: 2px; border: 1px solid rgba(0,0,0,0.158)" class="clientProfile listItem">
<img style="float-left; width:3%;" src="../images/devices/xboxone.png"><div class="listItemBody"><h3 class="listItemBodyText">XBLAHBLAHNAME</h3>
</div>
<i class="md-icon btnDeleteProfile" data-index="0">close</i>
</div>
<br>
</div>

这些动态创建的按钮可以从页面中删除,方法是单击主按钮内标有“.btnDeleteProfile”类的图标。

当我想在 JQuery 中向我的“btnDeleteProfile”添加一个点击事件时,我可以使用这个:

 $('#clientProfiles', page).on('click', '.btnDeleteProfile', function () {});

但现在我没有使用 JQuery,我遇到了针对“.btnDeleteProfile”的问题。

document.querySelector('.btnDeleteProfile').addEventListener('click', function() {});

但是 MDN 说 querySelector 只会找到第一个实例,而且很可能会创建大量这些按钮,所有这些按钮都附加了不同的配置文件信息。

查询选择器找不到“btnDeleteProfile”。

我遇到的错误是'can't add click event to null.

【问题讨论】:

  • 在 stackoverflow 中搜索“没有 jquery 的事件委托”。 on() 不是普通的 javascript 方法。
  • 对不起,我的意思是 addEventListeners。我仍然无法定位图标。
  • 对,因为它不存在。这就是您在 jQuery 中使用绑定的委托形式的原因。
  • 在按钮创建时添加事件监听器。不是之前...我想我明白了。
  • 不,您没有这样做,前提是事件冒泡。这就是存在事件委托的原因。 learn.jquery.com/events/event-delegation 同样的逻辑可以在原版 javascript 中完成,但需要做一些工作。

标签: javascript jquery


【解决方案1】:

你可以使用:

Event​.target:Event 接口的 target 属性是对调度事件的对象的引用。

sn-p:

function getClientHtml(device) {

    var html = "";
    html += '<div data-name="' + device.Name + '" data-id="' + device.Id + '"data-app="' + device.AppName + '" style="border-radius: 2px; border: 1px solid rgba(0,0,0,0.158)" class="clientProfile listItem">';
    html += '<img style="float-left; width:3%;" src="../images/devices/xboxone.png"/>';
    html += '<div class="listItemBody">';
    html += '<h3 class="listItemBodyText">' + device.Name + ' - ' + device.AppName + '</h3>';
    html += '</div>';
    html += '<i class="md-icon btnDeleteProfile" data-index="0">close</i>';
    html += '</div>';
    html += '<br />';
    return html;
}

 var clientProfiles = document.querySelector('#clientProfiles');

clientProfiles.innerHTML += getClientHtml({Name: 'Xbox One', id: "mcX7xXZksA1fJooKY2SRS5soNbFgM4lQurFx3bxr2s", AppName: 'Theater'});
clientProfiles.addEventListener('click', function(e) {
    if (e.target.classList.contains('btnDeleteProfile')) {
        e.target.closest('div').remove();
        console.log('Do it');
    }
})
<div class="paperlist" data-role="listview" data-inset="true" data-split-icon="delete" id="clientProfiles">
    <div data-name="Xbox One" data-id="mcX7xXZksA1fJooKY2SRS5soNbFgM4lQurFx3bxr2s" data-app="Theater" style="border-radius: 2px; border: 1px solid rgba(0,0,0,0.158)" class="clientProfile listItem">
        <img style="float-left; width:3%;" src="../images/devices/xboxone.png"><div class="listItemBody"><h3 class="listItemBodyText">XBLAHBLAHNAME</h3>
    </div>
        <i class="md-icon btnDeleteProfile" data-index="0">close</i>
    </div>
    <br>
</div>

【讨论】:

    【解决方案2】:

    使用事件委托。使用事件委托,您可以将事件处理程序添加到将在添加动态内容之前存在的元素。动态添加的元素发生的所有事件都会使 DOM 冒泡到您已将处理程序附加到的现有元素。然后,您的事件处理程序将需要检查该事件以了解它是否应该执行它应该执行的操作。

    在我的简单示例中,我已将委托处理程序附加到 #list。它等待具有.close 类的元素被单击,发出click 事件,从列表中删除li

    var addItemToList = function addItemToList( listNode, text ) {
      
      var li          = document.createElement( 'li' );
      var spanClose   = document.createElement( 'span' );
      var spanNothing = document.createElement( 'span' );
      
      li.textContent = text;
    
      spanClose.className = 'close';
      spanClose.innerHTML = '⨯';
    
      spanNothing.className = 'nothing';
      spanNothing.innerHTML = '★';
    
      li.appendChild( spanClose )
      li.appendChild( spanNothing );
      listNode.appendChild( li );
    
    };
    
    var getRandomText = function getRandomText() {
      return randomText[ Math.floor(Math.random() * 3) ];
    };
    
    var removeListItem = function removeListItem( e ) {
    
      // e.target = <span>
      if ( e.target.classList.contains( 'close' ) ) {
      
        var li = e.target.parentNode; 
        var ul = li.parentNode;
    
        ul.removeChild( li );
    
      }
    
    }
    
    var addToListBtn = document.querySelector( 'button' );
    var theList      = document.querySelector( '#list' );
    var randomText   = [ 'Hello!', 'Huh?', 'Okay' ];
    
    addToListBtn.addEventListener( 'click', function ( e ) {
      addItemToList( theList, getRandomText() );
    } );
    
    theList.addEventListener( 'click', removeListItem );
    li {
      line-height: 1.5;
    }
    
    li span {
      border: 1px solid #ccc;
      margin-left: 1rem;
      padding: 0.25rem 0.5rem;
      cursor: pointer;
    }
    <button>Add to List</button>
    
    <ul id="list"></ul>

    【讨论】:

      【解决方案3】:

      您可以通过创建自己的委托事件侦听器逻辑来概括这一点。

      • 将事件监听器绑定到父级
      • 当事件发生时,找到所有匹配子选择器的父子节点
      • 如果事件源自的元素在该子列表中,则对其应用事件回调。

      Element.prototype.addDelegateEventListener = function (eventType, childSelector, callback) {
        var parentElement = this;
        
        parentElement.addEventListener(eventType, function(event){
          var children = [...parentElement.querySelectorAll(childSelector)];
          
          if (children.includes(event.target)) {
            callback.apply(event.target, arguments);
          }
        });
      };
      
      
      document.getElementsByTagName('button')[0].addEventListener('click', function(){
        document.querySelector('#parent').innerHTML += `<div class="clickMe" data-created-on="${Date.now()}">Click Me</div>`;
      });
      
      document.getElementById('parent').addDelegateEventListener( 'click', '.clickMe', function(e){
        console.log(this);
        console.log(e.target);
      });
      <button>Add Element</button>
      <div id="parent">
        <div>No Match</div>
        <div>
          <div class="clickMe">Indirect Child</div>
        </div>
      </div>

      【讨论】:

        【解决方案4】:

        好的,如果您只是想让该代码正常工作,gaetanoM 的回答非常棒。

        但是,您的问题的核心似乎是如何定位 所有 的删除按钮以附加该功能。因此,为了将来参考,您可以使用 querySelectorAllforEach,如 MDN 所示:

        https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelectorAll#Accessing_the_matches

        // use querySelectorAll to get a node list of the elements, similar to how you would get a jQuery object in jQuery
        var deleteButtons = document.querySelectorAll(".btnDeleteProfile");
        
        // iterate over the node list just like you would in jQuery with .each()
        deleteButtons.forEach(function(button) {
          // do something with the individual element
          console.log(button);
        });
        
        

        【讨论】:

        • 这个逻辑没有实现委托实践。
        • 很多人已经回答了事件委托,但似乎 OP 主要是想弄清楚如何定位所有按钮,就像在 jQuery 中可以轻松做到的那样。这就是为什么我把我的回答集中在他问题的那个方面,以保持清楚。如果您想对我的回答提出修改,也包括授权问题,那就去吧。
        • 他们正试图将委托形式的 jQuery on() 转换为非 jQuery 版本。我看不出它在哪里说他们不想再使用代表了。他们对为什么在尝试选择不存在的元素时逻辑不起作用的整个误解完全与为什么首先使用委托有关。
        • @JoSchMO 虽然您对 OP 缺少 querySelectorAll 功能的看法是正确的,但作为 Taplar 的答案的旁注,您的答案会更好,该答案已经提到了 querySelectorAll
        • @MrLister 是的,这本来是要走的路,但我们都或多或少地同时回答,这是一个新问题。我仍然相信 OP 甚至没有意识到事件委托正在发挥作用,并且真的在问诸如“我试图摆脱对 jQuery 的依赖,我如何选择所有这些按钮?”之类的问题。因此,与其编辑我的答案以包含事件委托,我想提供一个答案,教 OP 如何完成该任务。
        猜你喜欢
        • 2015-10-12
        • 2011-11-25
        • 2015-05-24
        • 1970-01-01
        • 1970-01-01
        • 2013-06-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多