Lazy <option> loading

被刻印的时光 ゝ 提交于 2019-12-21 09:10:45

问题


Assuming I have a select like this:

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

I should see a List of 4 elements having a scrollbar on the right.

What i like to do now is to load the text via ajax if the option becomes visible somehow (scrolling and/or initial).

EDIT:

At the end, I do not load them lazy because of the huge metadata transfer. This is the request I must upload (send to the server):

This is inacceptable for the lazy-load of single elements.


回答1:


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




回答2:


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>



回答3:


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 */
}



回答4:


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



回答5:


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



来源:https://stackoverflow.com/questions/42326897/lazy-option-loading

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