懒加载<选项>

11

假设我有一个如下所示的选择器:

<select size="4">
  <option id="1">Please wait ...</option>
  <option id="2">Please wait ...</option>
  <option id="3">Please wait ...</option>
  <option id="4">Please wait ...</option>
  <option id="5">Please wait ...</option>
</select>

我希望能看到一个有4个元素并且右侧有滚动条的列表。

现在我想做的是,如果选项以某种方式变得可见(通过滚动和/或初始),则通过ajax加载文本。

编辑:

最终,由于元数据传输量巨大,我不会进行懒加载。这是我必须上传(发送到服务器)的请求:

huge upload for small download

对于单个元素的懒加载而言,这是无法接受的。


你可以通过JSON和/或Ajax轻松地将数据拉入<select><option>标签中,但要获得稳定的滚动效果,你可能需要使用JS将你的<select><option>转换为<ul><li>。 - Coastal-Cam
5个回答

6

非常抱歉我的英语不太好,但是我理解这个问题并可以提供解决方案:

$(document).ready(function(){
  $('select').on('scroll', function(){
    var sel = $(this);
    var lasto = sel.find('option:last');
    var s = sel.position().top + sel.height();
    var o = lasto.height() + lasto.position().top - 4;
    setTimeout(function(){
      if(o < s){console.log('We need AJAX!');}
    }, 2200);
  });
});

Link


4

这是如何做到的:

只有在元素可见时才会加载。

function loadSelect() {
  elementsDisplayed = Math.ceil(($(this).scrollTop() + Number($(this).css("padding-top").slice(0,-2))) / $(this).find("option:first").height() + parseFloat($(this).attr("size")));

  $(this).find("option").slice(0,elementsDisplayed).not(".loaded").each(function () {
    $(this).addClass("loaded"); //prevents spam reloading certain elements

    /*$.post("fetch.php", {
              dataId : $(this).attr("id")
          }, function (data) {
              //Yay, we are now loaded
          });*/

    console.log("Loading : " + $(this).attr("id"));
  });
}

$("select").on("scroll", loadSelect);

loadSelect.bind($("select"))();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select size="4" style="padding:14px">
  <option id="1">Please wait ...</option>
  <option id="2">Please wait ...</option>
  <option id="3">Please wait ...</option>
  <option id="4">Please wait ...</option>
  <option id="5">Please wait ...</option>
  <option id="6">Please wait ...</option>
  <option id="7">Please wait ...</option>
  <option id="8">Please wait ...</option>
  <option id="9">Please wait ...</option>
  <option id="10">Please wait ...</option>
</select>


  1. 那些在开始时可见的内容,在滚动之前不会被加载。
  2. 它们会提前加载一个元素。
- Grim
1
如果您不想让它“提前加载”,我可以更新代码,使用Math.floor而不是Math.ceil。 - Neil
好的,但是如果我将选择框的 padding 设置为 14px,我可以看到尚未加载的第五个。 - Grim
好的,下一个问题是,如果选项是 float:left,它就无法正常工作。 - Grim
我已经为你提供了一个很好的起点。这是我的最终答案。而且你应该在原始帖子中明确那些规格要求。 - Neil
显示剩余5条评论

1
你可以尝试this。它并不真正使用选择器,而是使用JS重新创建了其行为。你应该在jsfiddle中尝试,因为它在http请求方面存在问题。
ajax加载的元素处理还没有工作,但很容易修复。

function loadMoreItems() {
  var requestStr = "http://randomword.setgetgo.com/get.php";
  alert("load triggered")
  $.ajax({
    type: "GET",
    url: requestStr,
    dataType: "jsonp",
    jsonpCallback: 'RandomWordComplete'
  });
};

function RandomWordComplete(data) {
  var op = $("li.option.last")
  op.removeClass("last")
  var li = $("<li>"+data.Word+"</li>")
  li.addClass("option")
  li.addClass("last")
  li.data("value", op.data("value") + 1)
  $("#select").append(li)
  li.slideDown()
}

$("document").ready(function() {
  $(".option").click(function() {
    $(".option").slideDown();
  });

  $(".option:not(.selected)").click(function() {
    $(".option:not(.selected)").slideUp();

    $(".option.selected").text($(this).text())
    $("#selectVal").val($(this).data("value"))
  });

  $("#select").scroll(function() {
    var div = $(this);
    if (div[0].scrollHeight - div.scrollTop() == div.height()) {
      loadMoreItems();
    }

  });
});
li {
  list-style: none
}

.option {
  display: none;
  margin: 10px 0
}

.option:first-child {
  display: block
}

.option:not(.selected):hover {
  background: red
}

#select {
  border: 1px solid black;
  width: 180px;
  cursor: pointer;
  max-height: 60px;
  overflow: auto
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="select">
  <li class="option selected">--</li>
  <li class="option" data-value="0">Spain</li>
  <li class="option last" data-value="1">Portugal</li>

</ul>
<input id="selectVal" type="hidden" value="" />


好的,但它不是选项标签。 - Grim
我知道。但是这种行为类似,而且比典型的选择(select)更加可定制化。 - Iván Rodríguez Torres
另一个选项是使用插件。这里有解决方案的说明:https://dev59.com/n43da4cB1Zd3GeqP5t10#32094259 - Iván Rodríguez Torres

1
你可以将元素/选项传递给下面的函数,以检查元素是否可见并执行你的AJAX函数调用。
function isVisible(element) {
  var bx = element.getBoundingClientRect();
  var viewh = Math.max(document.documentElement.clientHeight, window.innerHeight);
  return !(bx.bottom < 0 || bx.top - viewHeight >= 0);
}

执行将会是这样的:
if(isVisible(document.getElementById("select_id")))
{
/* Execute your ajax call here */
}

这个必须被调用,但我想注册一个处理程序。 - Grim

0

这样的东西可能适合您,它基本上只检查选项的偏移量,但也确保您不会发送多个ajax请求。

$(function () {

  var api = 'https://jsonplaceholder.typicode.com'
  var url = api + '/posts/1'

  var select = $('select')
  var option = select.find('option')
  var selectTop = select.offset().top
  var selectHeight = select.height()
  var inview, optionTop

  select.on('scroll', function () {
    option.each(function () {

      var _this = $(this)

      optionTop = _this.offset().top
      inview = optionTop >= selectTop && optionTop < selectTop + selectHeight

      // check that the option element is in range
      if (inview) {

        // don't send multiple requests if already triggered
        if (
          _this.attr('data-status') !== 'success'
          && _this.attr('data-status') !== 'loading'
          && _this.attr('data-status') !== 'error'
        ) {
          _this.attr('data-status', 'loading')
          _this.text('Loading ...')
          $.ajax({
            url: url,
            method: 'GET',
            success: function ajaxSuccess(resp) {
              _this.attr('data-status', 'success')
              _this.text(resp.title)
            },
            error: function ajaxError(xhr) {
              _this.attr('data-status', 'error')
              _this.text('Error ...')
              console.log(xhr.responseText)
            }
          })
        }
      }
    })
  })

  // bootstrap
  select.triggerHandler('scroll')
})

请查看这里的JSFiddle,它加载得相当快,您可以注释掉triggerHandler以防止在页面加载时发送请求

编辑:我还更新了选项元素的ID,因为ID不应该以数字开头


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接