Keyup 功能仅对输入的第一个字母起作用

Keyup function is only working once for first letter of input

我有一个文本输入框,用户可以在其中输入所需的页面名称

<input type='text' id='pageName'  name='PageName' class='form-control pageName'>

我正在尝试使用 keyup 函数来触发 Ajax 以检查页面是否存在,但是当键入类似 index 的内容时 Ajax 仅发送 I(第一个字母)而不是 运行。

脚本:

<script>
  $("#pageName").keyup(function() {
    $.ajax({
      type: "GET",
      async: false,
      url: "CheckPageName.php",
      data: {
        'PageName': jQuery(this).val()
      },
      cache: false,
      success: function(html) {
        $("#NotAllowed").replaceWith(html);
        $('#loader_image').hide();
      }
    });
  });
</script>

如果我添加 console.log(html); 它会在日志中正确显示值,但 $("#NotAllowed").replaceWith(data); 仅显示第一个字母或 2(如果我键入速度快!)

我错过了什么?

您应该将 keyup 函数包装在 debounce 中。当从服务器请求数据时,这将节省您一些时间和负载。

const debounce = (callback, wait) => {
  let timeoutId = null;
  return (...args) => {
    const [ { target } ] = args;
    window.clearTimeout(timeoutId);
    timeoutId = window.setTimeout(() => {
      callback.apply(target, args);
    }, wait);
  };
}

const handleKeyUp = debounce(function() {
  $('#loader-image').show();
  $.ajax({
    type: 'GET',
    async: false,
    url: 'CheckPageName.php',
    data: { 'PageName': $(this).val() },
    cache: false,
    success: function(data, textStatus, jqXHR) {
      $('#not-allowed').html(data);
      $('#loader-image').hide();
    },
    error: function(jqXHR, textStatus, errorThrown) {
      $('#not-allowed').html('<p>Not found...</p>');
      // Hide the mask after 1 second, to mimic waiting for a response
      // Remove this timeout once the response is hooked-up
      setTimeout(function() {
        $('#loader-image').hide();
      }, 1000);
    }
  });
}, 250); // Search only after 250ms once typing has stopped

$('#loader-image').hide();
$('#page-name').on('keyup', handleKeyUp);
#loader-image {
  display: flex;
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
  margin: 0;
  padding: 0;
  z-index: 999;
  background: rgba(0, 0, 0, 0.5);
  justify-content: center;
  align-items: center;
  font-weight: bold;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js"></script>
<div class="container">
  <form>
    <div class="mb-3">
      <label for="page-name" class="form-label">Search existing page name</label>
      <input type="text" id="page-name" name="page-name" class="form-control">
      <div id="page-name-help" class="form-text">Check for an existing page.</div>
    </div>
  </form>
  <hr />
  <div id="not-allowed"></div>
</div>
<div id="loader-image">Loading...</div>

此问题与您的 AJAX 调用无关(尽管 async:false 仍然是不必要的,并且通常是不好的做法)。

问题在于 jQuery replaceWith 函数的作用。根据文档,它删除了它匹配的元素,并将整个元素替换为您提供给函数的内容。请注意,它替换了 整个元素,而不仅仅是其内部内容!

所以它只工作一次的原因很简单,因为在第一次执行后,“NotAllowed”元素不再存在 - replaceWith 已删除它并用您的 AJAX 请求的响应替换它!

如果你想更新一个元素的内容而不删除它,在jQuery中你可以使用.html().text()(取决于内容是否是HTML 或纯文本)。在这种情况下 .text() 就可以了:

success: function(response) {
    $("#NotAllowed").text(response);
    $('#loader_image').hide();
}

演示:https://jsfiddle.net/k3461n7h/2/