一天之后,我使用 iscroll4 实现了平滑的无限滚动并拉动以刷新示例应用程序。这两个功能是在我创建的一个示例应用程序中实现的。希望它对这个移动应用程序开发者社区有用。
首先假设:
- 您熟悉 iscroll4 函数(没有太大必要,因为我也不是大师)。
- 你知道如何对 json 文件或 json/php 文件进行 ajax 调用
我的应用摘要:
当用户加载我的应用程序时,它会对我服务器上的 json/php 文件进行 ajax 调用,并返回一些值。
问题性质:我希望在拉动的同时进行无限滚动以刷新功能,并且我不想使用除 iscroll4 之外的任何其他框架。
我的解决方案:
<!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>
接下来是创建 myinitialloadscript.js 脚本。这允许在该页面上首次将内容加载到应用程序中。
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);
}
});
}
}
接下来是实现pulltorefresh.js,这个就不多说了,因为iscroll4 中的例子很清楚。
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);
最后但并非最不重要的一点是主要的infinitescroll.js 记得我们之前在pulltorefresh.js 中调用了这个函数,我们说如果滚动条到最后10px 则应该触发inifite 滚动。然后我们将其作为要发射的镜头。
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)
});
}
}
}
}
因此,以防万一您迷失了 php 文件的外观。这个文件是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'))."})";
}
?>
下一个文件用于无限滚动,它被称为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'))."})";
}
?>