Ok I've been searching and searching for an answer, but have yet to find one in the general area I am looking for. Not being supremely familiar with iScroll (a former developer on this project added it in, and I am now taking it over). I have been trying to figure out where to begin with iScroll.
Right now all seems to work accordingly as far as scrolling up and down. But I want to add some functionality to the overall app thats been developed, such as getting older data and appending it to the more recent data thats listed at that time. An infinite scroll.
Pulling in the data via ajax, and working with it to append it to and refresh iScroll length isn't so much the issue (I think, well for the moment at the least). What is my issue is finding that moment when the bottom is reached and firing off the function I will make to get said data and append it.
I can't find any examples anywhere so I am hoping someone here can throw me some ideas
Since this question is pretty old. This solution is for any future references.
Using iScroll v4.2.5:
var scroll = new iScroll('scroll-wrapper');
scroll.options.onScrollEnd = function(){
if(Math.abs(this.maxScrollY) - Math.abs(this.y) < 10){
// RUN CODE if scroll is 10px from the bottom.
}
};
After along day, i have implemented a smooth infinite scroll and pull to refresh sample app using iscroll4. these two functionality were implemented in one sample app i created. hope its useful to this mobile app developer community.
first it is assumed that:
- you are familiar with iscroll4 functions (Not much of a necessity cos am not a guru either).
- you know how to make ajax calls to a json file or json/php file
my app summary:
when user loads my app, it makes an ajax call to json/php file on my server and some values are returned.
Problem nature: i want infinite scrolling alongside pull to refresh functions and i dont want to use any other framework apart from iscroll4.
my solution:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<link href="http://fonts.googleapis.com/css?family=Headland+One%7COpen+Sans:400,300&subset=latin,cyrillic" rel="stylesheet" type="text/css"></link>
<link href="css/mystylesheet.css" rel="stylesheet">
<style>
/**
*
* Horizontal Scrollbar
*
*/
.myScrollbarH {
position:absolute;
z-index:100;
height:8px;
bottom:1px;
left:2px;
right:7px
}
.myScrollbarH > div {
position:absolute;
z-index:100;
height:100%;
/* The following is probably what you want to customize */
background:-webkit-gradient(linear, 0 0, 100% 0, from(#226BF4), to(#226B8F));
background-image:-moz-linear-gradient(top, #226BF4, #226B8F);
background-image:-o-linear-gradient(top, #226BF4, #226B8F);
border:1px solid #226BF4;
-webkit-background-clip:padding-box;
-moz-background-clip:padding-box;
-o-background-clip:padding-box;
background-clip:padding-box;
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
-o-box-sizing:border-box;
box-sizing:border-box;
-webkit-border-radius:4px;
-moz-border-radius:4px;
-o-border-radius:4px;
border-radius:4px;
-webkit-box-shadow:inset 1px 1px 0 rgba(255,255,255,0.5);
-moz-box-shadow:inset 1px 1px 0 rgba(255,255,255,0.5);
-o-box-shadow:inset 1px 1px 0 rgba(255,255,255,0.5);
box-shadow:inset 1px 1px 0 rgba(255,255,255,0.5);
}
/**
*
* Vertical Scrollbar
*
*/
.myScrollbarV {
position:absolute;
z-index:100;
width:8px;bottom:7px;top:2px;right:1px
}
.myScrollbarV > div {
position:absolute;
z-index:100;
width:100%;
/* The following is probably what you want to customize */
background:-webkit-gradient(linear, 0 0, 100% 0, from(#226BF4), to(#226B8F));
background-image:-moz-linear-gradient(top, #226BF4, #226B8F);
background-image:-o-linear-gradient(top, #226BF4, #226B8F);
border:1px solid #226BF4;
-webkit-background-clip:padding-box;
-moz-background-clip:padding-box;
-o-background-clip:padding-box;
background-clip:padding-box;
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
-o-box-sizing:border-box;
box-sizing:border-box;
-webkit-border-radius:4px;
-moz-border-radius:4px;
-o-border-radius:4px;
border-radius:4px;
-webkit-box-shadow:inset 1px 1px 0 rgba(255,255,255,0.5);
-moz-box-shadow:inset 1px 1px 0 rgba(255,255,255,0.5);
-o-box-shadow:inset 1px 1px 0 rgba(255,255,255,0.5);
box-shadow:inset 1px 1px 0 rgba(255,255,255,0.5);
}
/**
*
* Pull down styles
*
*/
#pullDown, #pullUp {
background:#fff;
height:40px;
line-height:40px;
padding:5px 10px;
border-bottom:1px solid #ccc;
font-weight:bold;
font-size:14px;
color:#888;
}
#pullDown .pullDownIcon, #pullUp .pullUpIcon {
display:block; float:left;
width:40px; height:40px;
background:url(images/pull-icon@2x.png) 0 0 no-repeat;
-webkit-background-size:40px 80px; background-size:40px 80px;
-webkit-transition-property:-webkit-transform;
-webkit-transition-duration:250ms;
}
#pullDown .pullDownIcon {
-webkit-transform:rotate(0deg) translateZ(0);
}
#pullUp .pullUpIcon {
-webkit-transform:rotate(-180deg) translateZ(0);
}
#pullDown.flip .pullDownIcon {
-webkit-transform:rotate(-180deg) translateZ(0);
}
#pullUp.flip .pullUpIcon {
-webkit-transform:rotate(0deg) translateZ(0);
}
#pullDown.loading .pullDownIcon, #pullUp.loading .pullUpIcon {
background-position:0 100%;
-webkit-transform:rotate(0deg) translateZ(0);
-webkit-transition-duration:0ms;
-webkit-animation-name:loading;
-webkit-animation-duration:2s;
-webkit-animation-iteration-count:infinite;
-webkit-animation-timing-function:linear;
}
@-webkit-keyframes loading {
from { -webkit-transform:rotate(0deg) translateZ(0); }
to { -webkit-transform:rotate(360deg) translateZ(0); }
}
</style>
</head>
<body style="overflow: hidden;" onload="do_refresh();">
<div class="wrap">
<div id="wrapper">
<div id="scroller">
<div id="pullDown">
<span class="pullDownIcon"></span><span class="pullDownLabel">Pull down to refresh...</span>
</div>
<div class="content">
<input type="hidden" id="last_id">
<div id="responsecontainer"></div>
</div>
<span class="load_more_loading" ></span>
</div>
</div>
</div>
<script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
<script src="js/iscroll.js"></script>
<script src="js/pulltorefresh.js"></script>
<script src="js/infinitescroll.js></script>
<script src="js/myinitialloadscript.js"></script>
<script src="js/mymobileframework.js"></script> <!--independent of this script. eg. whormhole from mosync-->
</body>
</html>
next is to create the myinitialloadscript.js script. this allows content to be loaded into the app for the first time on that page.
function do_refresh()
{
var url = "http://localhost/public_html/landing.php?token=908765789897867567687989089786768980&validator=jhjhjjhjhkhj"; //just url params
// -------------------------------------------
$.ajax({
type: 'GET',
url: url,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
// Evaluate text as a json expression
converters: {"text jsonp": jQuery.parseJSON},
timeout:30000,
async: true,
jsonp: true,
jsonpCallback: "myJsonMethod",
beforeSend: function()
{
//add loading image i dint bcos the image or values becomes double in a case of network delay
$("#responsecontainer").html("images/loader.gif").show();
},
success: function(data)
{
ajax.parseJSONP(data);
},
error: function(jqXHR, textStatus, errorThrown)
{
console.log(errorThrown);
alert("Could Not Refresh.");
$("#responsecontainer").html("");//remove loading image
//$("#responsecontainer").load("refresh_h.html"); //load a page with refresh option.
}
});
$.ajaxSetup({ cache: false }); //fetch data from db not cache content
}
//if data is fectched successfully then
var ajax = {
parseJSONP:function(data){
$.each(data, function(i, row) {
if (i==0){
$("#responsecontainer").html('');
}
var ul = '<li>'+row.myjsondatakey+'</li>'; //could be <div></div> This only displays your values from db in a styled manner
$(ul).appendTo('#responsecontainer');// append the value to the responsecontainer
//Now watch closely. remember it was assumed you have a json file or json/php file, and in
//most cases you get your json data format from PHP file. so we assume its from a php file.
//also note that php calls to db can have a LIMIT. so in this case my PHP file data LIMIT
//was set to 5. because of infinite scrolling, i need to know the id of the last element
//from my returned data. so i write the following. note that my row.id_comments which is my
//value i want to get was written into an input whose visibility is hidden. this is to
//enable me over write its value when the last id changes.
if (i==4)
{
//set last id value
$('#last_id').val(row.id_comments);
}
});
}
}
next is to implement pulltorefresh.js much woun't be said about this because the example in iscroll4 is clear.
var myScroll,
pullDownEl, pullDownOffset,
pullUpEl, pullUpOffset,
generatedCount = 0;
function pullDownAction () {
var el;
el = document.getElementById('responsecontainer');
var url = "http://localhost/public_html/landing.php?token=78654567897654356789976546789&valid=jhjhjjhjhkhj";
$.ajax({
type: 'GET',
url: url,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
// Evaluate text as a json expression
converters: {"text jsonp": jQuery.parseJSON},
timeout:30000,
async: true,
jsonp: true,
jsonpCallback: "myJsonMethod",
error: function(){
myScroll.refresh(); //do nofin
},
success: function(data){
//console.dir('success');
ajax.parseJSONP(data);
}
});
$.ajaxSetup({ cache: false }); //fetch data from db not cache content
var ajax = {
parseJSONP:function(data){
$.each(data, function(i, row) {
if (i==0){
$("#responsecontainer").html('');
}
var ul = '<li>'+row.myjsondatakey+'</li>';
$(ul).appendTo(el);
if (i==4)
{
//set last id value
$('#last_id').val(row.id_comments);
}
myScroll.refresh(); // Remember to refresh when contents are loaded (ie: on ajax completion)
});
}
}
}
function loaded() {
pullDownEl = document.getElementById('pullDown');
pullDownOffset = pullDownEl.offsetHeight;
myScroll = new iScroll('wrapper', {
scrollbarClass: 'myScrollbar',
useTransition: true,
topOffset: pullDownOffset,
onRefresh: function () {
if (pullDownEl.className.match('loading')) {
pullDownEl.className = '';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh...';
}
},
onScrollMove: function () {
if (this.y > 5 && !pullDownEl.className.match('flip')) {
pullDownEl.className = 'flip';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Release to refresh...';
this.minScrollY = 0;
} else if (this.y < 5 && pullDownEl.className.match('flip')) {
pullDownEl.className = '';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh...';
this.minScrollY = -pullDownOffset;
}
},
//here is where infinite scroll comes in
onScrollEnd: function () {
//infinite scroll started
if(Math.abs(this.maxScrollY) - Math.abs(this.y) < 10)
{
// Do infinite if scroll is 10px from the bottom.
doInfinite_scroll();
}
//infinite scroll ended
if (pullDownEl.className.match('flip')) {
pullDownEl.className = 'loading';
pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Loading...';
pullDownAction(); // Execute custom function (ajax call?)
}
}
});
setTimeout(function () { document.getElementById('wrapper').style.left = '0'; }, 800);
}
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
document.addEventListener('DOMContentLoaded', function () { setTimeout(loaded, 200); }, false);
and last but not the least the main infinitescroll.js recall that we had previously placed a call to this function in pulltorefresh.js where we said if scroll bar is 10px to the end inifite scroll should be triggered. Then we have this as the shot to be fired.
function doInfinite_scroll()
{
var last_id = $('#last_id').val();
var searching = false;
if (!searching) { // only initiate a new ajax request if this variable is false this is to avoid data duplication.
var el;
el = document.getElementById('responsecontainer');
var url = "http://localhost/public_html/landing_more.php?last_id="+last_id+"&token=9876543456789765432456789876543&valid=jhjhjjhjhkhj";
// -------------------------------------------
$.ajax({
type: 'GET',
url: url,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
// Evaluate text as a json expression
converters: {"text jsonp": jQuery.parseJSON},
timeout:30000,
async: true,
jsonp: true,
jsonpCallback: "myJsonMethod",
error: function(){
myScroll.refresh(); //do nofin
},
beforeSend: function()
{
//add loading image i dint bcos the image or values becomes double in a case of network delay
searching = true; // set variable to true
},
success: function(data){
searching = false; // set variable to false
//console.dir('success');
ajax.parseJSONP(data);
}
});
$.ajaxSetup({ cache: false });//fetch data from db not cache content
var ajax = {
parseJSONP:function(data){
$.each(data, function(i, row) {
var ul = '<ul>'+row.comments+'</ul>';
if (i==1) //bcos its php data limit was set to 2 so its always N-1 i.e yourlimit - 1
{
//resset lastdeed id value
$('#lastdeed_id').val(row.id_comments); //update the value in the hidden input field to enable the next set of data load properly
}
$(ul).appendTo(el);
myScroll.refresh(); // Remember to refresh when contents are loaded (ie: on ajax completion)
});
}
}
}
}
so just in case you are lost with what the php file should look like here you go. This file is landing.php
<?php
// Prevent caching.
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 01 Jan 1996 00:00:00 GMT');
if ((isset($_GET['token'])) && (isset($_GET['valid']))) {
@require_once('connect/connectionfile.php');
$token=htmlspecialchars($_GET['token'],ENT_QUOTES);
$token= mysql_real_escape_string($token);
$valid=htmlspecialchars($_GET['valid'],ENT_QUOTES);
$valid= mysql_real_escape_string($valid);
//now validating the token
$sql="SELECT * FROM bla WHERE blabla='$token'";
$result=mysql_query($sql);
//if token exists
if(mysql_num_rows($result))
{
header('Content-type: application/json');
//valid token
$fakevalue = mysql_fetch_assoc($result);
$uid = $fakevalue['id'];
$results = array();
$query = "SELECT * FROM bla bal WHERE bla bla bla DESC LIMIT 0, 5";
$rsult = mysql_query($query);
while($value = mysql_fetch_assoc($rsult, MYSQL_ASSOC))
$results[] = $value;
{
echo "myJsonMethod".'('.json_encode($results).')'; //ECHO RESULTS IN JSONP FORMAT
}
}
else
{
//Invalid token
header('Content-type: application/json');
echo "myJsonMethod({\"token\":".utf8_encode(json_encode('failed'))."})";
}
}
else {
header('Content-type: application/json');
echo "myJsonMethod({\"token\":".utf8_encode(json_encode('Invalid token check parameters'))."})";
}
?>
this next file is for infinite scrolling and it is called landing_more.php
<?php
// Prevent caching.
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 01 Jan 1996 00:00:00 GMT');
if ((isset($_GET['token'])) && (isset($_GET['validator']))) {
@require_once('connect/connectionfile.php');
$token=htmlspecialchars($_GET['token'],ENT_QUOTES);
$token= mysql_real_escape_string($token);
$validator=htmlspecialchars($_GET['validator'],ENT_QUOTES);
$validator= mysql_real_escape_string($validator);
$last_id=htmlspecialchars($_GET['last_id'],ENT_QUOTES);
$last_id=mysql_real_escape_string($last_id);
//now validating the token
$sql="SELECT * FROM bla WHERE blabla='$token'";
$result=mysql_query($sql);
//if token exists
if(mysql_num_rows($result))
{
header('Content-type: application/json');
//valid token
$fakevalue = mysql_fetch_assoc($result);
$uid = $fakevalue['id'];
$results = array();
$query = "SELECT * FROM bla bla WHERE bla && bla bla && a.id_comments < '$last_id' ORDER BY a.id_comments DESC LIMIT 0, 2";
$rsult = mysql_query($query);
while($value = mysql_fetch_assoc($rsult, MYSQL_ASSOC))
$results[] = $value;
{
echo "myJsonMethod".'('.json_encode($results).')'; //ECHO RESULTS IN JSONP FORMAT
}
}
else
{
//Invalid token
header('Content-type: application/json');
echo "myJsonMethod({\"token\":".utf8_encode(json_encode('failed'))."})";
}
}
else {
header('Content-type: application/json');
echo "myJsonMethod({\"token\":".utf8_encode(json_encode('Invalid token check parameters'))."})";
}
?>
来源:https://stackoverflow.com/questions/13838384/iscroll-lite-find-when-i-have-reached-the-end-of-the-scroll-or-bottom-of-the-ele