Lazy

2020-07-07 11:30发布

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

huge upload for small download

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

5条回答
你好瞎i
2楼-- · 2020-07-07 11:51

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

查看更多
We Are One
3楼-- · 2020-07-07 12:01

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

查看更多
放荡不羁爱自由
4楼-- · 2020-07-07 12:02

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>

查看更多
疯言疯语
5楼-- · 2020-07-07 12:02

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

查看更多
倾城 Initia
6楼-- · 2020-07-07 12:07

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 */
}
查看更多
登录 后发表回答