iPhone Scrollbars with iScroll
Since we've had web browsers and JavaScript, we've been intent on replacing native browser functionalities, and for many reasons. Whether it be that the native look or functionality is ugly, doesn't work the same across browsers, or isn't as feature-rich as it should be, we've always pushed the browser's limits to do better. One functionality we've tried desperately to emulate is scrollbars. iScroll , a fairly new scrolling lib, has done an exceptional job in emulating scrolling both within desktop and mobile browsers. iScroll also allows for scrolling of elements with overflow on older versions of Mobile Safari. Let's have a look at iScroll!
The HTML
iScroll requires a two-DIV pattern for declaring where iScroll will be used. The first DIV is the wrapper, the second DIV is the scrollable area:
<div id="wrapper">
<div id="scroller">
<div style="padding:15px 30px;"> <!-- padding for content -->
<!-- content goes here -->
</div>
</div>
</div>
iScroll will create and inject the scrollbar within the wrapper
DIV. The content is held within the scroller
DIV.
The CSS
The CSS is where iScroll can get a bit fuzzy. For iScroll to work optimally, both the wrapper and scroller DIVs need to be positioned absolutely and be styled to widths of 100%:
#wrapper { position:absolute; z-index:1; top:0; bottom:0; left:0; width:100%; overflow:auto; } #scroller { position:absolute; z-index:1; /* -webkit-touch-callout:none;*/ -webkit-tap-highlight-color:rgba(0,0,0,0); width:100%; padding:0; }
As a result, the third DIV of the structure needs the contain enough padding-right to keep the text and scrollbar far enough way from each other. Be sure to position those elements properly or iScroll wont work at all (as I found out the hard way) !
The JavaScript
The most obvious piece of using iScroll is including its .js file:
<script type="text/javascript" src="iscroll/src/iscroll.js"></script>
With iScroll now available within the page, the next step is creating the iScroll instance that suits the needs of your desired usage. The most simple of uses provides only the wrapper ID:
var scroller = new iScroll('wrapper');
Awesome; the page's native scrollbar disappears and is replaced by an iOS-style scrollbar! But like every good JavaScript lib, iScroll provides a host of features that allow you to customize your scrollbar. Options include setting flags for bounce, momentum, fade and hide settings, and whether scrollbars should be allowed both vertically and horizontally. Here's another example of how you can create a pull-to-refresh scrollbar:
var myScroll, pullDownEl, pullDownOffset, pullUpEl, pullUpOffset, generatedCount = 0; function pullDownAction () { setTimeout(function () { // <-- Simulate network congestion, remove setTimeout from production! var el, li, i; el = document.getElementById('thelist'); for (i=0; i<3; i++) { li = document.createElement('li'); li.innerText = 'Generated row ' + (++generatedCount); el.insertBefore(li, el.childNodes[0]); } myScroll.refresh(); // Remember to refresh when contents are loaded (ie: on ajax completion) }, 1000); // <-- Simulate network congestion, remove setTimeout from production! } function pullUpAction () { setTimeout(function () { // <-- Simulate network congestion, remove setTimeout from production! var el, li, i; el = document.getElementById('thelist'); for (i=0; i<3; i++) { li = document.createElement('li'); li.innerText = 'Generated row ' + (++generatedCount); el.appendChild(li, el.childNodes[0]); } myScroll.refresh(); // Remember to refresh when contents are loaded (ie: on ajax completion) }, 1000); // <-- Simulate network congestion, remove setTimeout from production! } function loaded() { pullDownEl = document.getElementById('pullDown'); pullDownOffset = pullDownEl.offsetHeight; pullUpEl = document.getElementById('pullUp'); pullUpOffset = pullUpEl.offsetHeight; myScroll = new iScroll('wrapper', { useTransition: true, topOffset: pullDownOffset, onRefresh: function () { if (pullDownEl.className.match('loading')) { pullDownEl.className = ''; pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Pull down to refresh...'; } else if (pullUpEl.className.match('loading')) { pullUpEl.className = ''; pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more...'; } }, 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; } else if (this.y < (this.maxScrollY - 5) && !pullUpEl.className.match('flip')) { pullUpEl.className = 'flip'; pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Release to refresh...'; this.maxScrollY = this.maxScrollY; } else if (this.y > (this.maxScrollY + 5) && pullUpEl.className.match('flip')) { pullUpEl.className = ''; pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Pull up to load more...'; this.maxScrollY = pullUpOffset; } }, onScrollEnd: function () { if (pullDownEl.className.match('flip')) { pullDownEl.className = 'loading'; pullDownEl.querySelector('.pullDownLabel').innerHTML = 'Loading...'; pullDownAction(); // Execute custom function (ajax call?) } else if (pullUpEl.className.match('flip')) { pullUpEl.className = 'loading'; pullUpEl.querySelector('.pullUpLabel').innerHTML = 'Loading...'; pullUpAction(); // Execute custom function (ajax call?) } } }); setTimeout(function () { document.getElementById('wrapper').style.left = '0'; }, 800); }
Since we live in the world of AJAX-driven websites that allow content to come and go, calling the refresh method is all you need to do for iScroll to reevaluate the scrollbar position and size:
// When the AJAX is done, refresh the scrollbar sizing and positioning... scroller.refresh();
It's also important to point out that iScroll allows zooming and pinching, as well as snapping to elements:
var myScroll = new iScroll('wrapper', { /* snap: true, */ // Would snap logically snap: "p", // Snaps to each "P" tag momentum: false, hScrollbar: false, vScrollbar: false });
Lastly, iScroll-Lite is available for those looking to support only mobile browsers (iScroll allows for desktop support as well). The mischievous part of me would prefer iOS-style scrollbars instead of native browser scrollbars!
Possibly my favorite part of iScroll is that it's a standalone library; no external JavaScript library is required. iScroll has many configuration parameters so I encourage you to visit the iScroll page to check out everything you can do. Matteo Spinelli's iScroll is an outstanding piece of work; grab iScroll and start controlling your scrollbars today!
原文 http://davidwalsh.name/iphone-scrollbars
this is a demo .
<!DOCTYPE html>
<html>
<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">
<title>上拉下拉动态加载例子</title>
<link href="css/jquery.mobile.structure-1.3.2.css" rel="stylesheet" type="text/css"/>
<link href="css/jquery.mobile-1.3.2.css" rel="stylesheet" type="text/css"/>
<script src="js/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
$("#list").bind('pageinit', function () {
$.ajax({
type: "get",
async: false,
url: "http://www.57lehuo.com/index.php?a=index&m=api&method=itemsSearchGet&keyword=连衣裙&sign=5cb85c3eed22c1908e05c584813c8dd2",
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback:"itemsSearchGet",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
success: function(json){
var content='';
$.each( json['result'], function(i, n){
var url=n.url!='undefined'?n.url:'';
var bimg=n.bimg!='undefined'?n.bimg:'';
var title=n.title!='undefined'?n.title:'';
content = content + "<li>";
content = content + "<a target=\"_blank\" href=\"http://s.click.taobao.com/t?e=zGU34CA7K%2BPkqB05%2Bm7rfGGjlY60oHcc7bkKOQiRddrNEyGLx31dnc6%2Fz%2BaQS2UNDUWpebTcEEjBuk1W5odmLS8%3D&pid=mm_30949159_0_0\">";
content = content + "<img src=\""+bimg+"_100x100.jpg\" />";
content = content + "<h2>";
content = content + "连衣裙";
content = content + "</h2>";
content = content + "<p>";
content = content + title;
content = content + "</p>";
content = content + "</a>";
content = content + "</li>";
});
$("#thelist").append(content).listview('refresh');
},
error: function(){
//alert('fail');
}
});
});
$("#list").bind("pagebeforeshow", function(){
setTimeout(loaded, 10);
});
//http://www.57lehuo.com/index.php?a=index&m=api&method=itemsListGet×tamp=12121512&cid=773&sign=8d6fda3f30ea3517341e1820cd719784
})
</script>
<script src="js/jquery.mobile-1.3.2.min.js" type="text/javascript"></script>
<script type="text/javascript" src="js/iscroll.js"></script>
<script type="text/javascript">
var myScroll,
pullDownEl, pullDownOffset,
pullUpEl, pullUpOffset,
generatedCount = 0;
/**
* 下拉刷新 (自定义实现此方法)
* myScroll.refresh(); // 数据加载完成后,调用界面更新方法
*/
var p=2;
function pullDownAction () {
$.ajax({
type: "get",
async: false,
url: "http://www.57lehuo.com/index.php?a=index&m=api&method=itemsSearchGet&keyword=连衣裙&p="+p+"",
dataType: "jsonp",
jsonp: "callback",//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
jsonpCallback:"itemsSearchGet",//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
success: function(json){
var content='';
$.each( json['result'], function(i, n){
var url=n.url!='undefined'?n.url:'';
var bimg=n.bimg!='undefined'?n.bimg:'';
var title=n.title!='undefined'?n.title:'';
content = content + "<li>";
content = content + "<a target=\"_blank\" href=\"http://s.click.taobao.com/t?e=zGU34CA7K%2BPkqB05%2Bm7rfGGjlY60oHcc7bkKOQiRddrNEyGLx31dnc6%2Fz%2BaQS2UNDUWpebTcEEjBuk1W5odmLS8%3D&pid=mm_30949159_0_0\">";
content = content + "<img src=\""+bimg+"_100x100.jpg\" />";
content = content + "<h2>";
content = content + "连衣裙";
content = content + "</h2>";
content = content + "<p>";
content = content + title;
content = content + "</p>";
content = content + "</a>";
content = content + "</li>";
});
$("#thelist").prepend(content).listview('refresh');
},
error: function(){
// alert('fail');
}
});
p++;
myScroll.refresh(); //数据加载完成后,调用界面更新方法 Remember to
}
/**
* 滚动翻页 (自定义实现此方法)
* myScroll.refresh(); // 数据加载完成后,调用界面更新方法
*/
function pullUpAction () {
setTimeout(function () { // <-- Simulate network congestion, remove setTimeout from production!
/*
var el, li, i;
el = document.getElementById('thelist');
for (i=0; i<3; i++) {
li = document.createElement('li');
li.innerText = 'Generated row ' + (++generatedCount);
el.appendChild(li, el.childNodes[0]);
}
*/
var content = "";
for (var i=1;i<3;i++){
content = content + "<li>";
content = content + "<a href=\"#\">";
content = content + "<img src=\"images/album-bb.jpg\" />";
content = content + "<h2>";
content = content + "下拉新增内容<br/>"+new Date();
content = content + "</h2>";
content = content + "<p>";
content = content + "Broken Bells";
content = content + "</p>";
content = content + "</a>";
content = content + "</li>";
}
$("#thelist").append(content).listview('refresh');
myScroll.refresh(); // 数据加载完成后,调用界面更新方法 Remember to refresh when contents are loaded (ie: on ajax completion)
}, 1000); // <-- Simulate network congestion, remove setTimeout from production!
}
/**
* 初始化iScroll控件
*/
function loaded() {
//清除所占的内存空间
if(myScroll!=null){
myScroll.destroy();
}
pullDownEl = document.getElementById('pullDown');
pullDownOffset = pullDownEl.offsetHeight;
pullUpEl = document.getElementById('pullUp');
pullUpOffset = pullUpEl.offsetHeight;
myScroll = new iScroll('wrapper', {
useTransition: true, //默认为true
//useTransition: false,
topOffset: pullDownOffset,
onRefresh: function () {
if (pullDownEl.className.match('loading')) {
pullDownEl.className = '';
pullDownEl.querySelector('.pullDownLabel').innerHTML = '下拉刷新...';
} else if (pullUpEl.className.match('loading')) {
pullUpEl.className = '';
pullUpEl.querySelector('.pullUpLabel').innerHTML = '上拉加载更多...';
}
},
onScrollMove: function () {
if (this.y > 5 && !pullDownEl.className.match('flip')) {
pullDownEl.className = 'flip';
pullDownEl.querySelector('.pullDownLabel').innerHTML = '松手开始更新...';
this.minScrollY = 0;
} else if (this.y < 5 && pullDownEl.className.match('flip')) {
pullDownEl.className = '';
pullDownEl.querySelector('.pullDownLabel').innerHTML = '下拉刷新...';
this.minScrollY = -pullDownOffset;
} else if (this.y < (this.maxScrollY - 5) && !pullUpEl.className.match('flip')) {
pullUpEl.className = 'flip';
pullUpEl.querySelector('.pullUpLabel').innerHTML = '松手开始更新...';
this.maxScrollY = this.maxScrollY;
} else if (this.y > (this.maxScrollY + 5) && pullUpEl.className.match('flip')) {
pullUpEl.className = '';
pullUpEl.querySelector('.pullUpLabel').innerHTML = '上拉加载更多...';
this.maxScrollY = pullUpOffset;
}
},
onScrollEnd: function () {
if (pullDownEl.className.match('flip')) {
pullDownEl.className = 'loading';
pullDownEl.querySelector('.pullDownLabel').innerHTML = '加载中...';
pullDownAction(); // Execute custom function (ajax call?)
} else if (pullUpEl.className.match('flip')) {
pullUpEl.className = 'loading';
pullUpEl.querySelector('.pullUpLabel').innerHTML = '加载中...';
pullUpAction(); // Execute custom function (ajax call?)
}
}
});
setTimeout(function () { document.getElementById('wrapper').style.left = '0'; }, 800);
}
//初始化绑定iScroll控件
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
//document.addEventListener('DOMContentLoaded', function () { setTimeout(loaded, 200); }, false);
document.addEventListener('DOMContentLoaded', loaded, false);
</script>
<link rel="stylesheet" type="text/css" href="css/iscroll.css">
</head>
<body>
<div data-role="page" id="list">
<div id="header"><a href="#">产品列表页</a></div>
<div id="wrapper">
<div id="scroller">
<div id="pullDown">
<span class="pullDownIcon"></span><span class="pullDownLabel">Pull down to refresh...</span>
</div>
<ul data-role="listview" data-icon="false" id="thelist">
<li><a href="#">
<img src="images/album-p.jpg">
<h3> Amadeus Phoenix</h3>
<p>Phoenix</p></a>
</li>
</ul>
<div id="pullUp">
<span class="pullUpIcon"></span><span class="pullUpLabel">Pull up to refresh...</span>
</div>
</div>
</div>
<div data-role="footer" data-position="fixed">
<div data-role="navbar" data-grid="a">
<ul>
<li><a href="index.html" class="ui-btn-active" data-ajax="false">首页</a></li>
</ul>
</div>
</div>
</div>
</body>
</html>
demo 下载