Lazy <option> loading

对着背影说爱祢 提交于 2019-12-04 03:04:16

I'm sorry for my bad English, but as I'm understanding this question I can present this solution:

$(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

Here's how you do it:

It will only load when the element is visible.

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>

You can pass the element/option to below funtion to check if the element is visible and to execute your AJAX function call.

function isVisible(element) {
  var bx = element.getBoundingClientRect();
  var viewh = Math.max(document.documentElement.clientHeight, window.innerHeight);
  return !(bx.bottom < 0 || bx.top - viewHeight >= 0);
}

Execution will be like

if(isVisible(document.getElementById("select_id")))
{
/* Execute your ajax call here */
}

You can try this. It doesn't really use a select. It recreates its behaviour using JS. You should try out of jsfiddle since it has problem with http requests.

The handling for the ajax loaded elements is not working yet, it is easy to fix.

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="" />

something like this might work for you, it basically just checks the option's offsets, but also makes sure you're not sending multiple ajax requests

$(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')
})

see the JSFiddle here, it loads kind of fast, you could comment out the triggerHandler to prevent it sending requests on page load

edit: also i updated the ids of the option elements since ids shouldn't start with a number

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!