一日を過ごした後、スムーズな無限スクロールを実装し、iscroll4 を使用してプルしてサンプル アプリを更新しました。これら 2 つの機能は、私が作成した 1 つのサンプル アプリに実装されています。このモバイル アプリ デベロッパー コミュニティに役立つことを願っています。
まず、次のことが前提となります。
- あなたはiscroll4関数に精通しています(必要性はあまりありません.cosもグルではありません).
- 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'))."})";
}
?>