首页 > 解决方案 > 添加到 display:none 元素时未显示 Data-id 属性

问题描述

我正在使用引导弹出窗口构建一个通知弹出窗口。弹出框为每个通知都有一个 div,每个通知都有相同的类(除了文本内容之外相同)。

<% notifs.each do |notif| %>
  <div class="media n-media notif-popup-container notif-display" data-id=<%= notif.id %> >
    Content
  </div>
<% end %>

结果是:

通知弹出

但是,当我单击任何通知 div(在图片中)时,我的单击侦听器的 $(this) 将始终引用第一个 div。我知道这一点,因为当我打印 ID 时,即使单击第三个,它也会打印第一个通知 div 的 ID。

在其他地方找不到类似的问题。这是相关的jquery代码。我正在使用 $(body).on("click") 而不是 $(".className").click 因为后者不会附加到所需的 div,因为 div 有 display:none 直到它弹出。

$('body').on("click", ".popover-body .notif-popup-container", function() {
    console.log("notif popup container clicked");

    // prints <div class="media n-media notif-popup-container notif-display"></div> 
    console.log($(this)[0]);

    // prints {}
    console.log($(this).data());

    // prints first element's id
    console.log($('.notif-popup-container').data("id"));

    // prints undefined
    console.log($(this).data("id"));
 })

这是弹出框代码。我注意到 data-id 属性没有显示在 Chrome 开发工具中,仅适用于我的 style="display:none" div。这些 div 被插入到弹出框标题和内容的选项中,因此它们必须被隐藏。

$(document).ready(function(){
  $("#notificationsBell").popover({
    'title' : $('.notifications-title-header').html(), // display:none for html div
    'html' : true,
    'placement' : 'left',
    'content' : $(".notifications-list").html() // display:none for this as well
  });
});

JS 可能会给出一些提示。使用 Rails 构建,但这似乎无关紧要。任何见解表示赞赏。

编辑:它没有得到第一个 div,它得到了正确的。它只是没有保留 data-id 属性。所以现在我将把它存储在“id”属性中,该属性将显示在 chrome 开发工具上。我仍然想知道为什么 data-id 没有出现,而 id 属性却出现了。

编辑2:这是相关的html代码:

  <%= link_to "javascript:void(0);", class: "dropdown-toggle", id: "notificationsBell" do %>
    <i class="fa fa-bell dropdown-toggle" aria-hidden="true"></i>
    <span id="notifUnreadCount">
      <%= Notification.unread_count(current_user) %>
    </span>
  <% end %>

  <div style="display:none" class="notifications-title-header" data-id="sup">
    <p class="notifications-title">
      Notifications
      <span class="see-all-notifs"><u><%= link_to "See all", notifications_path %></u></span>
    </p>
  </div>

  <div style="display:none" class="notifications-list">

    <% unread_notifications = Notification.unread_count(current_user) %>
    <% if unread_notifications === 0 %>

      No notifications to display! You are up to date.

    <% else %>
      <% notifs = current_user.notifications.where(read_at: nil).order("created_at DESC") %>
      <% notifs.each do |notif| %>

        <div class="media n-media notif-popup-container notif-display" id=<%= notif.id %> >

          <%= image_tag "bell.svg", class: "notification-icon-small mr-3" %>

          <div class="media-body noti-info">
            <b><p><%= notif.notify_type %></p></b>
            <span class="n-date trans-timestamp dateTime" data-momentiz="(<%= notif.momentize %>)"></span>
            <p><%= notif.message %></p>
          </div>

          <div class="actions">
            <% if notif.status == 'pending' && notif.target.present? %>
              <%= link_to update_request_wager_path(notif.target.try(:wager), member_id: notif.target_id, type: "accept", notif_id: notif.id), method: :put, class: "btn table-link acceptBtn red-btn-small", data: { confirm: 'Are you sure you want to accept?' } do %>
                <i class="fa fa-check" aria-hidden="true"></i>
              <% end %>
              <%= link_to update_request_wager_path(notif.target.wager, member_id: notif.target_id, type: "reject", notif_id: notif.id), method: :put,class: "btn table-link rejectBtn red-btn-small", data: { confirm: 'Are you sure you want to reject?' } do %>
                <i class="fa fa-times" aria-hidden="true"></i>
              <% end %>
            <% end %>
            <%= link_to get_notification_url(notif) + "#" + notif.notify_type.downcase + "Notif", class: "btn red-btn-small" do %>
                <i class="fa fa-eye" aria-hidden="true"></i>
            <% end %>
          </div>


        </div>


      <% end %>

    <% end %>

  </div>

标签: javascriptjqueryhtmltwitter-bootstrapbootstrap-4

解决方案


事件委托

事件委托是一种编程模式,它允许我们通过将(又名注册)事件绑定到所有目标标签共有的单个标签来监听多个(无限量)目标标签(例如buttons,等)的事件inputs作为祖先。我将其称为“共同祖先”—— window、、documentbody始终有效,但在大多数情况下不是最佳选择。

除了调用堆栈中只有一个事件处理程序之外,任何在页面加载后动态添加到页面的目标标记都会对已注册的触发事件做出反应——无法将事件绑定到页面加载后创建的标记。

jQuery.on()方法在提供实际选择器时委托事件:

$('.btn-group').on('click',...

.btn-group是绑定到事件的标签(共同祖先),并且在其任何后代标签(目标标签)上触发时将侦听这些事件。在处理程序中有多种引用方式.btn-group

$('.btn-group')

this                   // Used with plain JavaScript properties and methods
$(this)[0]             // As above
$(this).get()          // As above
event.currentTarget    // As above*
$(this)                // Used with jQuery properties and methods
$(event.currentTarget) // As above*

*event.currentTarget将始终引用绑定到事件的标签,但对于this. 如果调用的第二个参数event.data被定义为选择器,那么this将引用event.data.

$('.btn-group').on('click', '.btn-modal', openModal);

$(.btn-modal)也是$(this)现在,不是$('.btn-group')。任何被点击的后代标签$('.btn-group')都会触发点击事件,从而调用处理函数openModal()。处理程序将确定哪个标签启动行为或被忽略。点击时触发的标签可以通过以下方式引用:

事件来源- 用户点击、更改、悬停等的标签。

event.target    // Used with plain JavaScript properties and methods
this            // As above if `event.data` is defined
$(this)[0]      // As above
$(this).get()   // As above
$(event.target) // Used with jQuery properties and methods
$(this)         // As above if `event.data` is defined

event.target将始终引用用户与之交互的标签(例如点击)。


演示

注: demo中注释的详细信息

/*
If there are multiple tags to target

  ex. 3 button.btn-modal
  
Determine the closest parent tag that the target tags have in common. 

  ex. fieldset.btn-group
  
Delegate the event to the "common ancestor". Add the handler function 
(ie `openModal()`) without the parenthesis.

  ex. $('.btn-group').on('click', openModal);
  
*/
$('.btn-group').on('click', openModal);

/*
Pass thru the event object
Use the event object property .target to determine which tag the user clicked. 
Make it into a jQuery object by wrapping it into $(...)

  ex. let clicked = $(event.target);
  
If the clicked tag has a .btn-modal class...

  ex. if (clicked.hasClass('btn-modal')) {...
  
...get the clicked tag data-open value...

  ex. let ID = clicked.data('open');
  
...Finally, use previous value, ID, as a reference to a modal using the Bootstrap 
method .modal() to open said modal.*

  ex. $('#'+ID).modal();
  
*/
function openModal(event) {
  let clicked = $(event.target);
  if (clicked.hasClass('btn-modal')) {
    let ID = clicked.data('open');
    $('#' + ID).modal();
  }
  return false;
}

/*
*Note: Patterns involving .btn-modal classes and data-open attributes 
are of my own design
*/
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" 
rel="stylesheet">
</head>

<body>
  <main class="container">
    <section class='row'>

      <fieldset class='btn-group btn-group-lg mx-auto mt-5'>
        <button class="btn btn-primary btn-modal" data-open="noticeA" type="button">
          Notice A
        </button>
        <button class="btn btn-warning btn-modal" data-open="noticeB" type="button">
          Notice B
        </button>
        <button class="btn btn-danger btn-modal" data-open="noticeC" type="button">
          Notice C
        </button>
      </fieldset>

      <dialog id="noticeA" class="modal fade">
        <div class="modal-dialog modal-dialog-centered modal-lg">
          <div class="modal-content">
            <header class="modal-header bg-primary">
              <h4 class="modal-title text-white">Notice A</h4>
              <button class="close" type="button" data-dismiss="modal">
                &times;
              </button>
            </header>
            <article class="modal-body">
              <p class='display-1 text-center'>HEY!</p>
            </article>
            <footer class="modal-footer">
     <button class="close btn btn-primary p-3" type="button" data-dismiss="modal">
       Close
     </button>
            </footer>
          </div>
        </div>
      </dialog>

      <dialog id="noticeB" class="modal fade">
        <div class="modal-dialog modal-dialog-centered modal-sm">
          <div class="modal-content">
            <header class="modal-header bg-warning">
              <h4 class="modal-title">Notice B</h4>
              <button class="close" type="button" data-dismiss="modal">
                &times;
              </button>
            </header>
            <article class="modal-body">
              <p class='display-1 text-center'>HEY!</p>
            </article>
            <footer class="modal-footer">
     <button class="close btn btn-warning p-3" type="button" data-dismiss="modal">
       Close
     </button>
            </footer>
          </div>
        </div>
      </dialog>

      <dialog id="noticeC" class="modal fade">
        <div class="modal-dialog modal-dialog-centered modal-lx">
          <div class="modal-content">
            <header class="modal-header bg-danger">
              <h4 class="modal-title text-white">Notice C</h4>
              <button class="close" type="button" data-dismiss="modal">
                &times;
              </button>
            </header>
            <article class="modal-body">
              <p class='display-1 text-center'>HEY!</p>
            </article>
            <footer class="modal-footer">
     <button class="close btn btn-danger p-3" type="button" data-dismiss="modal">
       Close
     </button>
            </footer>
          </div>
        </div>
      </dialog>

    </section>
  </main>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js">
  </script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0
/umd/popper.min.js">
  </script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js">
  </script>
</body>

</html>


推荐阅读