jQuery 工具提示不适用于动态加载的 HTML 内容

jQuery tooltip not working on dynamically loaded HTML content

站点由 3 个页面组成,index.html、1.html、2.html。
目标是从包含工具提示和其他一些 html 的 1.html 加载 html 并将其显示在 div 中,鼠标悬停在加载的工具提示上后,我希望工具提示文本从 2.html.
中获取 但是此代码不起作用,未显示任何错误并且 AJAX 从未执行。

$(document).ready(function(){
    $( ".content span" ).tooltip({
        track:true,
        open: function( event, ui ) {
              var id = this.id; 
              var userid = $(this).attr('data-id');
              
              $.ajax({
                  url:'2.html',
                  type:'post',
                  data:{userid:userid},
                  success: function(response){
                      $("#"+id).tooltip('option','content',response);
                  }
              });
        }
    }); 
});
.container{
    margin: 0 auto;
    width: 30%;
}

.content{
    border: 1px solid black;
    padding: 5px;
    margin-bottom: 5px;
}
.content span{
    width: 250px;
}

.content span:hover{
    cursor: pointer;
}
<!doctype html>
<html>
    <head>
        <title>Dynamically show data in the Tooltip using AJAX</title>      
        <link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> 
        <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>      
    </head>
    <body>
    <input type="button" id="btnLoad" value="Load"/>
        <div class='container' id="container"></div>
    </body>
<script>
$( "#btnLoad" ).click(function() {
$.ajax({
  url: "1.html",
  context: document.body
}).done(function( msg ) {
    $('#container').html(msg);
    $(this).tooltip();
  });
});
</script>
</html>

1.html 文件的样本 HTML

            <div class='content'>
            <span title='Please wait..' data-id='1' id='user_1'>Pepsi</span>
        </div>

        <div class='content'>
            <span title='Please wait..' data-id='2' id='user_2'>7 Up</span>
        </div>

2.html 文件的样本 HTML

This Tooltip text will be replaced with texts from Database

你能尝试将这一行推送到你的代码中吗?

$('body').tooltip({selector: '.content span'});

紧接着

$(document).ready(function() {
    // push the above line here
    ... your current code

}

已更新

您更新后的问题更加清晰,并帮助我追踪发生了什么。我原来的回答解决了其中一个问题,但不是全部。其实还有一系列的问题。

问题 1

第一个问题是我之前描述的问题:jQuery 选择器仅匹配页面加载时 存在的页面元素 $(".content span").tooltip() 只会在页面加载时初始化存在于 .content 中的 span 的工具提示。如果您稍后注入新的 spans(或内部带有 spans 的新 .contents),它们将不包括在内,并且不会有工具提示。

最简单的修复方法是使用 (apparently undocumented?) selector 工具提示选项。在页面加载 时存在的 HTML 元素 上初始化工具提示,然后使用 selector 选项进行过滤以仅匹配您真正想要具有工具提示的元素在。关键是过滤部分是实时发生的,所以会匹配新添加的元素。

对于您的情况,我们不能使用 .content 作为工具提示,因为它在页面加载时也不存在。在您的任何 AJAX 事情发生之前,我们需要一些 parent 元素存在于页面上。假设您有一个 parent,例如 <div class="parent">,并且您的 HTML 将被注入其中(我想您也可以使用 bodydocument)。所以我们在 parent div:

上初始化工具提示
$(".parent").tooltip({
    // the selector option filters the elements that will actually have tooltips
    selector: '.content span'
});

问题 2

现在我们可以使用基本的工具提示功能,即使对于注入到页面中的新内容也是如此。下一步是通过 AJAX 动态加载内容,并使用该内容更新工具提示的标题。通常你会这样做:

$(selector).tooltip('option', 'content', 'New tooltip text!');

其中 selector 与 individual span 匹配,我们目前正在查看其工具提示。但在我们的例子中,这不起作用 - span 没有附加工具提示! 因为我们正在 .parent 上初始化工具提示,所以 individual spans 显示工具提示的地方没有附加工具提示,调用 .tooltip() 将失败并出现如下错误:

cannot call methods on tooltip prior to initialization; attempted to call method 'option'

要引用现有的工具提示,我们需要做 $('.parent').tooltip(),但如果我们这样做:

// Don't do this
$('.parent').tooltip('option', 'content', 'New tooltip text!');

它会将页面上的 每个 工具提示更改为相同的 'New tooltip text!',我们不希望这样。

您用来触发 AJAX receives the jQuery event as a parameter.open 事件处理程序。 event 包含有关当前目标元素的信息。使用它,我们可以找到我们当前正在查看的页面上的哪个跨度:

open: function(event, ui) {
  // Find real targeted tooltip
  let target = $(event.originalEvent.target);

现在我们可以操作该元素的标题了:

$target.attr('title', 'New tooltip!');

我们也可以把它做成工具提示!

$target.tooltip();

实际上这还不够,因为 .parent 工具提示已经打开并显示“请稍候...”。上述步骤确实更新了标题,但您必须将鼠标移开然后再移回才能看到它。我们希望内容立即刷新,实时。我尝试了一些实验,发现效果很好:

// Temporarily disabling the parent tooltip hides the one that was already open
$('.parent').tooltip('disable');

// Update our target's title
$target.attr('title', 'New tooltip!');

// Initialise a tooltip on our target, and immediately open it
$target.tooltip().tooltip('open');

// Re-enable the parent tooltips, so this process will work again for other spans
$('.parent').tooltip('enable');

所以我们实际上是在页面中添加新的工具提示实例,每次我们 mouse-over 一个匹配的范围。这种方法具有额外的优势,即新的工具提示取代了旧的 parent 特定 span 的工具提示。这意味着 parent 工具提示选项不再适用于已加载其工具提示内容的 span,这意味着如果您第二次 mouse-over 它,它不会触发 AJAX 第二次请求 span。我们从第一个 AJAX 调用中获得的内容已经存在,只是 re-used.

这是演示所有这些的工作片段。

我使用了 https://www.npoint.io/ 这是一个 JSON 存储箱,来模拟您的 AJAX 呼叫。我与它没有任何关系,它看起来只是一个方便的工具。不幸的是,它似乎不太可靠,并且在我工作时对它的请求失败了几次。如果发生这种情况,请重试。

我添加了一些包含与您的 1.html2.html 文件匹配的数据的容器,下面的代码加载它们并使用它们的内容:

  • This bin 包含您的 HTML 内容;
  • This bin 包含用户 ID 0 的虚拟数据;
  • This bin 包含用户 ID 1 的虚拟数据;
  • This bin 包含用户 ID 2 的虚拟数据;

$(document).ready(function () {

    // This URL returns a JSON response including HTML like your 1.html,
    // this way we can realistically simulate your 1.html AJAX call.
    let htmlContentUrl = 'https://api.npoint.io/6893d2fd7632835742cf';

    // These URLs return JSON responses including plain text like your
    // 2.html file, this way we can realistically simulate AJAX calls 
    // loading and using data from your DB
    let userContentUrls = [
        'https://api.npoint.io/06cf752b395286e41cb4',
        'https://api.npoint.io/2a3e0a338f92a803b3fc',
        'https://api.npoint.io/a9a4296244c36e8d5bfc'
    ];

    // We use this selector a few times, it is good practice to cache it
    var $parent = $('.parent');

    $("#btnLoad").click(function () {
        $.ajax({
            url: htmlContentUrl,
        }).done(function (msg) {
            $('#container').html(msg.content);
        });
    });

    $parent.tooltip({
        selector: '.conten span',
        track: true,
        open: function (event, ui) {
            // Find real targetted tooltip
            var $target = $(event.originalEvent.target);
            var userid = $target.attr('data-id');
            url = userContentUrls[userid];
            console.log('For userid', userid, 'url is', url);

            $.ajax({
                url: url,
                type: 'get',
                data: {
                    userid: userid
                },
                success: function (response) {
                    // We can't simply update the tooltip for $target, because
                    // it *has* no tooltip!  The tooltip is actually attached
                    // to .parent.  To refresh the already visible tooltip, we
                    // need to take a few steps.
                    $parent.tooltip('disable');
                    $target.attr('title', response.content);
                    $target.tooltip().tooltip('open');
                    $parent.tooltip('enable');
                }
            });
        }
    });
});
.container {
  margin: 0 auto;
  width: 30%;
}

.content {
  border: 1px solid black;
  padding: 5px;
  margin-bottom: 5px;
}

.content span {
  width: 250px;
}

.content span:hover {
  cursor: pointer;
}
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/themes/smoothness/jquery-ui.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>

<div class="parent">

  <div class="container">
    <div class="content">
      <span id="user_0" title="Please wait ..." data-id="0">Water</span>
    </div>
  </div>

  <input type="button" id="btnLoad" value="Load" />

  <div class='container' id="container"></div>

</div>

旁注:

  • 我添加了一个在页面加载时可见的工具提示(用户 ID 0),只是为了演示在页面加载时和注入新内容后一切正常;

  • Convention是获取数据时使用GET,更改数据时使用POST。您的 AJAX 调用只是检索要显示的数据,所以实际上应该是 GET;

  • 我不确定你为什么要 context: document.body,但我认为没有必要,为了简单起见,我删除了它;

  • 如果您要多次使用 jQuery 选择器,it makes sense to cache them。我为 $parent$target.

    这样做了