2117 lines
68 KiB
JavaScript
2117 lines
68 KiB
JavaScript
/*
|
||
* Jingle v0.4 Copyright (c) 2013 shixy, http://shixy.github.io/Jingle/
|
||
* Released under MIT license
|
||
* walker.shixy@gmail.com
|
||
*/
|
||
var Jingle = J = {
|
||
version : '0.41',
|
||
$ : window.Zepto,
|
||
//参数设置
|
||
settings : {
|
||
//single 单页面工程 muti 多页面工程
|
||
appType : 'single',
|
||
//page默认动画效果
|
||
transitionType : 'slide',
|
||
//自定义动画时的默认动画时间(非page转场动画时间)
|
||
transitionTime : 250,
|
||
//自定义动画时的默认动画函数(非page转场动画函数)
|
||
transitionTimingFunc : 'ease-in',
|
||
//toast 持续时间,默认为3s
|
||
toastDuration : 3000,
|
||
//是否显示欢迎界面
|
||
showWelcome : false,
|
||
//欢迎界面卡片切换时的执行函数,可以制作酷帅吊炸天的欢迎界面
|
||
welcomeSlideChange : null,
|
||
//加载page模板时,是否显示遮罩
|
||
showPageLoading : false,
|
||
//page模板默认的相对位置,主要用于开发hybrid应用,实现page的自动装载
|
||
basePagePath : 'html/',
|
||
basePageSuffix : '.html',
|
||
//page模板的远程路径{#id: href,#id: href}
|
||
remotePage:{}
|
||
},
|
||
//手机或者平板
|
||
mode : window.innerWidth < 800 ? "phone" : "tablet",
|
||
hasTouch : 'ontouchstart' in window,
|
||
//是否启动完成
|
||
launchCompleted : false,
|
||
//是否有打开的侧边菜单
|
||
hasMenuOpen : false,
|
||
//是否有打开的弹出框
|
||
hasPopupOpen : false,
|
||
isWebApp : location.protocol == 'http:',
|
||
/**
|
||
* 启动Jingle
|
||
* @param opts {object}
|
||
*/
|
||
launch : function(opts){
|
||
$.extend(this.settings,opts);
|
||
var hasShowWelcome = window.localStorage.getItem('hasShowWelcome');
|
||
if(!hasShowWelcome && this.settings.showWelcome){
|
||
this.Welcome.show();
|
||
}
|
||
this.Element.init();
|
||
this.Element.initControlGroup();
|
||
this.Router.init();
|
||
this.Menu.init();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 初始化页面组件元素
|
||
*/
|
||
J.Element = (function($){
|
||
var SELECTOR = {
|
||
'icon' : '[data-icon]',
|
||
'scroll' : '[data-scroll="true"]',
|
||
'toggle' : '.toggle',
|
||
'range' : '[data-rangeinput]',
|
||
'progress' : '[data-progress]',
|
||
'count' : '[data-count]',
|
||
'checkbox' : '[data-checkbox]'
|
||
}
|
||
/**
|
||
* 初始化容器内组件
|
||
* @param {String} 父元素的css选择器
|
||
* @param {Object} 父元素或者父元素的zepto实例
|
||
*/
|
||
var init = function(selector){
|
||
if(!selector){
|
||
//iscroll 必须在元素可见的情况下才能初始化
|
||
$(document).on('articleshow','article',function(){
|
||
J.Element.scroll(this);
|
||
});
|
||
};
|
||
var $el = $(selector || 'body');
|
||
if($el.length == 0)return;
|
||
|
||
$.map(_getMatchElements($el,SELECTOR.icon),_init_icon);
|
||
$.map(_getMatchElements($el,SELECTOR.toggle),_init_toggle);
|
||
$.map(_getMatchElements($el,SELECTOR.range),_init_range);
|
||
$.map(_getMatchElements($el,SELECTOR.progress),_init_progress);
|
||
$.map(_getMatchElements($el,SELECTOR.count),_init_badge);
|
||
$.map(_getMatchElements($el,SELECTOR.checkbox),_init_checkbox);
|
||
$el = null;
|
||
}
|
||
|
||
/**
|
||
* 初始化按钮组(绑定事件)
|
||
*/
|
||
var initControlGroup = function(){
|
||
$(document).on('tap','ul.control-group li',function(){
|
||
var $this = $(this);
|
||
if($this.hasClass('active'))return;
|
||
$this.addClass('active').siblings('.active').removeClass('active').parent().trigger('change',[$this]);
|
||
});
|
||
}
|
||
/**
|
||
* 自身与子集相结合
|
||
*/
|
||
var _getMatchElements = function($el,selector){
|
||
return $el.find(selector).add($el.filter(selector));
|
||
}
|
||
/**
|
||
* 初始化iscroll组件或容器内iscroll组件
|
||
*/
|
||
var initScroll = function(selector){
|
||
$.map(_getMatchElements($(selector),SELECTOR.scroll),function(el){J.Scroll(el);});
|
||
}
|
||
/**
|
||
* 构造icon组件
|
||
*/
|
||
var _init_icon = function(el){
|
||
var $el = $(el),$icon=$el.children('i.icon'),icon = $el.data('icon');
|
||
if($icon.length > 0){//已经初始化,就更新icon
|
||
$icon.attr('class','icon '+icon);
|
||
}else{
|
||
$el.prepend('<i class="icon '+icon+'"></i>');
|
||
}
|
||
}
|
||
/**
|
||
* 构造toggle切换组件
|
||
*/
|
||
var _init_toggle = function(el){
|
||
var $el = $(el);
|
||
if($el.find('div.toggle-handle').length>0){//已经初始化
|
||
return;
|
||
}
|
||
var name = $el.attr('name');
|
||
//添加隐藏域,方便获取值
|
||
if(name){
|
||
$el.append('<input style="display: none;" name="'+name+'" value="'+$el.hasClass('active')+'"/>');
|
||
}
|
||
$el.append('<div class="toggle-handle"></div>');
|
||
$el.tap(function(){
|
||
var $t = $(this),v = !$t.hasClass('active');
|
||
$t.toggleClass('active').trigger('toggle',[v]);//定义toggle事件
|
||
$t.find('input').val(v);
|
||
})
|
||
}
|
||
/**
|
||
* 构造range滑块组件
|
||
*/
|
||
var _init_range = function(el){
|
||
var $el = $(el),$input;
|
||
var $range = $('input[type="range"]',el);
|
||
var align = $el.data('rangeinput');
|
||
var input = $('<input type="number" name="test" value="'+$range.val()+'"/>');
|
||
if(align == 'left'){
|
||
$input = input.prependTo($el);
|
||
}else{
|
||
$input = input.appendTo($el);
|
||
}
|
||
var max = parseInt($range.attr('max'),10);
|
||
var min = parseInt($range.attr('min'),10);
|
||
$range.change(function(){
|
||
$input.val($range.val());
|
||
});
|
||
$input.on('input',function(){
|
||
var value = parseInt($input.val(),10);
|
||
value = value>max?max:(value<min?min:value);
|
||
$range.val(value);
|
||
$input.val(value);
|
||
})
|
||
}
|
||
/**
|
||
* 构造progress组件
|
||
*/
|
||
var _init_progress = function(el){
|
||
var $el = $(el),$bar;
|
||
var progress = parseFloat($el.data('progress'))+'%';
|
||
var title = $el.data('title') || '';
|
||
$bar = $el.find('div.bar');
|
||
if($bar.length == 0){
|
||
$bar = $('<div class="bar"></div>').appendTo($el);
|
||
}
|
||
$bar.width(progress).text(title+progress);
|
||
if(progress == '100%'){
|
||
$bar.css('border-radius','10px');
|
||
}
|
||
}
|
||
/**
|
||
* 构造badge组件
|
||
*/
|
||
var _init_badge = function(el){
|
||
var $el = $(el),$count = $el.find('span.count'),count = parseInt($el.data('count')),
|
||
orient = $el.data('orient'), className = (orient == 'left')?'left':'';
|
||
if($count.length>0){
|
||
$count.text(count).show();//更新数字
|
||
}else{
|
||
$count = $('<span class="count '+className+'">'+count+'</span>').appendTo($el);
|
||
}
|
||
if(count == 0){
|
||
$count.hide();
|
||
}
|
||
}
|
||
|
||
var _init_checkbox = function(el){
|
||
var $el = $(el);
|
||
var value = $el.data('checkbox');
|
||
if($el.find('i.icon').length>0){
|
||
return;
|
||
}
|
||
$el.prepend('<i class="icon checkbox-'+value+'"></i>');
|
||
$el.on('tap',function(){
|
||
var status = ($el.data('checkbox') == 'checked') ? 'unchecked':'checked';
|
||
$el.data('checkbox',status).find('i.icon').attr('class','icon checkbox-'+status);
|
||
//自定义change事件
|
||
$el.trigger('change');
|
||
});
|
||
|
||
}
|
||
|
||
return {
|
||
init : init,
|
||
initControlGroup : initControlGroup,
|
||
icon : _init_icon,
|
||
toggle : _init_toggle,
|
||
progress : _init_progress,
|
||
range : _init_range,
|
||
badge : _init_badge,
|
||
scroll : initScroll
|
||
}
|
||
})(J.$);
|
||
/**
|
||
* 侧边菜单
|
||
*/
|
||
J.Menu = (function($){
|
||
var $asideContainer,$sectionContainer,$sectionMask;
|
||
var init = function(){
|
||
$asideContainer = $('#aside_container');
|
||
$sectionContainer = $('#section_container');
|
||
$sectionMask = $('<div id="section_container_mask"></div>').appendTo('#section_container');
|
||
//添加各种关闭事件
|
||
$sectionMask.on('tap',hideMenu);
|
||
$asideContainer.on('swipeRight','aside',function(){
|
||
if($(this).data('position') == 'right'){
|
||
hideMenu();
|
||
}
|
||
});
|
||
$asideContainer.on('swipeLeft','aside',function(){
|
||
if($(this).data('position') != 'right'){
|
||
hideMenu();
|
||
}
|
||
});
|
||
$asideContainer.on('tap','.aside-close',hideMenu);
|
||
}
|
||
/**
|
||
* 打开侧边菜单
|
||
* @param selector css选择器或element实例
|
||
*/
|
||
var showMenu = function(selector){
|
||
var $aside = $(selector).addClass('active'),
|
||
transition = $aside.data('transition'),// push overlay reveal
|
||
position = $aside.data('position') || 'left',
|
||
showClose = $aside.data('show-close'),
|
||
width = $aside.width(),
|
||
translateX = position == 'left'?width+'px':'-'+width+'px';
|
||
if(showClose && $aside.find('div.aside-close').length == 0){
|
||
$aside.append('<div class="aside-close icon close"></div>');
|
||
}
|
||
|
||
//aside中可能需要scroll组件
|
||
J.Element.scroll($aside);
|
||
|
||
if(transition == 'overlay'){
|
||
J.anim($aside,{translateX : '0%'});
|
||
}else if(transition == 'reveal'){
|
||
J.anim($sectionContainer,{translateX : translateX});
|
||
}else{//默认为push
|
||
J.anim($aside,{translateX : '0%'});
|
||
J.anim($sectionContainer,{translateX : translateX});
|
||
}
|
||
$('#section_container_mask').show();
|
||
J.hasMenuOpen = true;
|
||
}
|
||
/**
|
||
* 关闭侧边菜单
|
||
* @param duration {int} 动画持续时间
|
||
* @param callback 动画完毕回调函数
|
||
*/
|
||
var hideMenu = function(duration,callback){
|
||
var $aside = $('#aside_container aside.active'),
|
||
transition = $aside.data('transition'),// push overlay reveal
|
||
position = $aside.data('position') || 'left',
|
||
translateX = position == 'left'?'-100%':'100%';
|
||
|
||
var _finishTransition = function(){
|
||
$aside.removeClass('active');
|
||
J.hasMenuOpen = false;
|
||
callback && callback.call(this);
|
||
};
|
||
|
||
if(transition == 'overlay'){
|
||
J.anim($aside,{translateX : translateX},duration,_finishTransition);
|
||
}else if(transition == 'reveal'){
|
||
J.anim($sectionContainer,{translateX : '0'},duration,_finishTransition);
|
||
}else{//默认为push
|
||
J.anim($aside,{translateX : translateX},duration);
|
||
J.anim($sectionContainer,{translateX : '0'},duration,_finishTransition);
|
||
}
|
||
|
||
$('#section_container_mask').hide();
|
||
}
|
||
return {
|
||
init : init,
|
||
show : showMenu,
|
||
hide : hideMenu
|
||
}
|
||
})(J.$);
|
||
/**
|
||
* section 页面远程加载
|
||
*/
|
||
J.Page = (function($){
|
||
var _formatHash = function(hash){
|
||
return hash.indexOf('#') == 0 ? hash.substr(1) : hash;
|
||
}
|
||
/**
|
||
* 加载section模板
|
||
* @param {string} hash信息
|
||
* @param {string} url参数
|
||
*/
|
||
var loadSectionTpl = function(hash,callback){
|
||
var param = {},query,replaceSection = false;
|
||
if($.type(hash) == 'object'){
|
||
param = hash.param;
|
||
query = hash.query;
|
||
hash = hash.tag;
|
||
}
|
||
var q = $(hash).data('query');
|
||
//已经存在则直接跳转到对应的页面
|
||
if($(hash).length == 1){
|
||
if(q == query){
|
||
callback();
|
||
return;
|
||
}else{
|
||
replaceSection = true;
|
||
}
|
||
}
|
||
var id = _formatHash(hash);
|
||
//当前dom中不存在,需要从服务端加载
|
||
var url = J.settings.remotePage[hash];
|
||
//检查remotePage中是否有配置,没有则自动从basePagePath中装载模板
|
||
url || (url = J.settings.basePagePath+id+J.settings.basePageSuffix);
|
||
J.settings.showPageLoading && J.showMask();
|
||
loadContent(url,param,function(html){
|
||
J.settings.showPageLoading && J.hideMask();
|
||
//添加到dom树中
|
||
$(hash).remove();
|
||
var $h = $(html);
|
||
$('#section_container').append($h);
|
||
if(replaceSection){
|
||
$h.addClass('active');
|
||
}
|
||
//触发pageload事件
|
||
$h.trigger('pageload').data('query',query);
|
||
//构造组件
|
||
J.Element.init(hash);
|
||
callback();
|
||
$h = null;
|
||
});
|
||
}
|
||
var loadSectionRemote = function(url,section){
|
||
var param = J.Util.parseHash(window.location.hash).param;
|
||
loadContent(url,param,function(html){
|
||
$(section).html(html);
|
||
J.Element.init(section);
|
||
});
|
||
}
|
||
/**
|
||
* 加载文档片段
|
||
* @param url
|
||
*/
|
||
var loadContent = function(url,param,callback){
|
||
return $.ajax({
|
||
url : url,
|
||
timeout : 20000,
|
||
data : param,
|
||
success : function(html){
|
||
callback && callback(html);
|
||
}
|
||
});
|
||
}
|
||
return {
|
||
load : loadSectionTpl,
|
||
loadSection : loadSectionRemote,
|
||
loadContent : loadContent
|
||
}
|
||
})(J.$);
|
||
/**
|
||
* 路由控制器
|
||
*/
|
||
J.Router = (function($){
|
||
var _history = [];
|
||
/**
|
||
* 初始化events、state
|
||
*/
|
||
var init = function(){
|
||
$(window).on('popstate', _popstateHandler);
|
||
//阻止含data-target或者href以'#'开头的的a元素的默认行为
|
||
$(document).on('click','a',function(e){
|
||
var target = $(this).data('target'),
|
||
href = $(this).attr('href');
|
||
if(!href || href.match(/^#/) || target){
|
||
e.preventDefault();
|
||
return false;
|
||
}
|
||
});
|
||
$(document).on('tap','a[data-target]',_targetHandler);
|
||
_initIndex();
|
||
}
|
||
|
||
//处理app页面初始化
|
||
var _initIndex = function(){
|
||
var targetHash = location.hash;
|
||
//取页面中第一个section作为app的起始页
|
||
var $section = $('#section_container section').first();
|
||
var indexHash = '#'+$section.attr('id');
|
||
_add2History(indexHash,true);
|
||
if(targetHash != '' && targetHash != indexHash){
|
||
_showSection(targetHash);//跳转到指定的页面
|
||
}else{
|
||
$section.trigger('pageinit').trigger('pageshow').data('init',true).find('article.active').trigger('articleshow');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 处理浏览器的后退事件
|
||
* 前进事件不做处理
|
||
* @private
|
||
*/
|
||
var _popstateHandler = function(e){
|
||
if(e.state && e.state.hash){
|
||
var hash = e.state.hash;
|
||
if(_history[1] && hash === _history[1].hash){//存在历史记录,证明是后退事件
|
||
J.hasMenuOpen && J.Menu.hide();//关闭当前页面的菜单
|
||
J.hasPopupOpen && J.Popup.close();//关闭当前页面的弹出窗口
|
||
back();
|
||
}else{//其他认为是非法后退或者前进
|
||
return;
|
||
}
|
||
}else{
|
||
return;
|
||
}
|
||
|
||
}
|
||
var _targetHandler = function(){
|
||
var _this = $(this),
|
||
target = _this.attr('data-target'),
|
||
href = _this.attr('href');
|
||
|
||
switch(target){
|
||
case 'section' :
|
||
if(J.settings.appType == 'single'){
|
||
_showSection(href);
|
||
}
|
||
break;
|
||
case 'article' :
|
||
_showArticle(href,_this);
|
||
break;
|
||
case 'menu' :
|
||
_toggleMenu(href);
|
||
break;
|
||
case 'back' :
|
||
window.history.go(-1);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 跳转到新页面
|
||
* @param hash 新page的'#id'
|
||
*/
|
||
var _showSection = function(hash){
|
||
if(J.hasMenuOpen){//关闭菜单后再转场
|
||
J.Menu.hide(200,function(){
|
||
_showSection(hash);
|
||
});
|
||
return;
|
||
}
|
||
//读取hash信息
|
||
var hashObj = J.Util.parseHash(hash);
|
||
var current = _history[0];
|
||
//同一个页面,则不重新加载
|
||
if(current.hash === hashObj.hash){
|
||
return;
|
||
}
|
||
//加载模板
|
||
J.Page.load(hashObj,function(){
|
||
var sameSection = (current.tag == hashObj.tag);
|
||
if(sameSection){//相同页面,触发相关事件
|
||
$(current.tag).trigger('pageshow').find('article.active').trigger('articlehide');
|
||
}else{//不同卡片页跳转动画
|
||
_changePage(current.tag,hashObj.tag);
|
||
}
|
||
_add2History(hash,sameSection);
|
||
});
|
||
}
|
||
/**
|
||
* 后退
|
||
*/
|
||
var back = function(){
|
||
if(J.settings.appType == 'single'){
|
||
_changePage(_history.shift().tag,_history[0].tag,true)
|
||
}
|
||
}
|
||
var _changePage = function(current,target,isBack){
|
||
J.Transition.run(current,target,isBack);
|
||
}
|
||
/**
|
||
* 缓存访问记录
|
||
*/
|
||
var _add2History = function(hash,noState){
|
||
var hashObj = J.Util.parseHash(hash);
|
||
if(noState){//不添加浏览器历史记录
|
||
_history.shift(hashObj);
|
||
window.history.replaceState(hashObj,'',hash);
|
||
}else{
|
||
window.history.pushState(hashObj,'',hash);
|
||
}
|
||
_history.unshift(hashObj);
|
||
}
|
||
|
||
/**
|
||
* 激活href对应的article
|
||
* @param href #id
|
||
* @param el 当前锚点
|
||
*/
|
||
var _showArticle = function(href,el){
|
||
var article = $(href);
|
||
if(article.hasClass('active'))return;
|
||
el.addClass('active').siblings('.active').removeClass('active');
|
||
var activeArticle = article.addClass('active').siblings('.active').removeClass('active');
|
||
article.trigger('articleshow');
|
||
activeArticle.trigger('articlehide');
|
||
}
|
||
|
||
var _toggleMenu = function(hash){
|
||
J.hasMenuOpen?J.Menu.hide():J.Menu.show(hash);
|
||
}
|
||
|
||
return {
|
||
init : init,
|
||
goTo : _showSection,
|
||
showArticle : _showArticle,
|
||
back : back
|
||
}
|
||
})(J.$);
|
||
/**
|
||
* 对zeptojs的ajax进行封装,实现离线访问
|
||
* 推荐纯数据的ajax请求调用本方法,其他的依旧使用zeptojs自己的ajax
|
||
* @Deprecated 用J.Cache代替
|
||
*/
|
||
J.Service = (function($){
|
||
var UNPOST_KEY = 'JINGLE_POST_DATA',
|
||
GET_KEY_PREFIX = 'JINGLE_GET_';
|
||
var ajax = function(options){
|
||
if(options.type == 'post'){
|
||
_doPost(options);
|
||
}else{
|
||
_doGet(options);
|
||
}
|
||
}
|
||
|
||
var _doPost = function(options){
|
||
if(J.offline){//离线模式,将数据存到本地,连线时进行提交
|
||
_setUnPostData(options.url,options.data);
|
||
options.success('数据已存至本地');
|
||
}else{//在线模式,直接提交
|
||
$.ajax(options);
|
||
}
|
||
}
|
||
var _doGet = function(options){
|
||
var key = options.url +JSON.stringify(options.data);
|
||
if(J.offline){//离线模式,直接从本地读取
|
||
var result = _getCache(key);
|
||
if(result){
|
||
options.success(result.data,key,result.cacheTime);
|
||
}else{//未缓存该数据
|
||
options.success(result);
|
||
}
|
||
}else{//在线模式,将数据保存到本地
|
||
var callback = options.success;
|
||
options.success = function(result){
|
||
_saveData2local(key,result);
|
||
callback(result,key);
|
||
}
|
||
$.ajax(options);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取本地已缓存的数据
|
||
* @private
|
||
*/
|
||
var _getCache = function(key){
|
||
return JSON.parse(window.localStorage.getItem(GET_KEY_PREFIX+key));
|
||
}
|
||
/**
|
||
* 缓存数据到本地
|
||
* @private
|
||
*/
|
||
var _saveData2local = function(key,result){
|
||
var data = {
|
||
data : result,
|
||
cacheTime : new Date()
|
||
}
|
||
window.localStorage.setItem(GET_KEY_PREFIX+key,JSON.stringify(data));
|
||
}
|
||
|
||
/**
|
||
* 将post的数据保存至本地
|
||
* @param url
|
||
* @param result
|
||
* @private
|
||
*/
|
||
var _setUnPostData = function(url,result){
|
||
var data = getUnPostData();
|
||
data = data || {};
|
||
data[url] = {
|
||
data : result,
|
||
createdTime : new Date()
|
||
}
|
||
window.localStorage.setItem(UNPOST_KEY,JSON.stringify(data));
|
||
}
|
||
/**
|
||
* 获取尚未同步的post数据
|
||
* @param url 没有就返回所有未同步的数据
|
||
*/
|
||
var getUnPostData = function(url){
|
||
var data = JSON.parse(window.localStorage.getItem(UNPOST_KEY));
|
||
return (data && url ) ? data[url] : data;
|
||
}
|
||
/**
|
||
* 移除未同步的数据
|
||
* @param url 没有就移除所有未同步的数据
|
||
*/
|
||
var removeUnPostData = function(url){
|
||
if(url){
|
||
var data = getUnPostData();
|
||
delete data[url];
|
||
window.localStorage.setItem(UNPOST_KEY,JSON.stringify(data));
|
||
}else{
|
||
window.localStorage.removeItem(UNPOST_KEY);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 同步本地缓存的post数据
|
||
* @param url
|
||
*/
|
||
var syncPostData = function(url,success,error){
|
||
var unPostData = getUnPostData(url).data;
|
||
$.ajax({
|
||
url : url,
|
||
contentType:'application/json',
|
||
data : unPostData,
|
||
type : 'post',
|
||
success : function(){
|
||
success(url);
|
||
},
|
||
error : function(){
|
||
error(url);
|
||
}
|
||
})
|
||
}
|
||
/**
|
||
* 同步所有的数据
|
||
* @param callback
|
||
*/
|
||
var syncAllPostData = function(success,error){
|
||
var unPostData = getUnPostData();
|
||
for(var url in unPostData){
|
||
syncPostData(url,success,error);
|
||
}
|
||
removeUnPostData();
|
||
}
|
||
|
||
//copy from zepto
|
||
function parseArguments(url, data, success, dataType) {
|
||
var hasData = !$.isFunction(data)
|
||
return {
|
||
url: url,
|
||
data: hasData ? data : undefined,
|
||
success: !hasData ? data : $.isFunction(success) ? success : undefined,
|
||
dataType: hasData ? dataType || success : success
|
||
}
|
||
}
|
||
|
||
var get = function(url, data, success, dataType){
|
||
return ajax(parseArguments.apply(null, arguments))
|
||
}
|
||
|
||
var post = function(url, data, success, dataType){
|
||
var options = parseArguments.apply(null, arguments)
|
||
options.type = 'POST'
|
||
return ajax(options)
|
||
}
|
||
|
||
var getJSON = function(url, data, success){
|
||
var options = parseArguments.apply(null, arguments);
|
||
options.dataType = 'json'
|
||
return ajax(options)
|
||
}
|
||
var clear = function(){
|
||
var storage = window.localStorage;
|
||
var keys = [];
|
||
for(var i = 0; i< storage.length; i++){
|
||
var key = storage.key(i);
|
||
key.indexOf(GET_KEY_PREFIX) == 0 && keys.push(key);
|
||
}
|
||
for(var i = 0; i < keys.length; i++){
|
||
storage.removeItem(keys[i]);
|
||
}
|
||
storage.removeItem(UNPOST_KEY);
|
||
}
|
||
return {
|
||
ajax : ajax,
|
||
get : get,
|
||
post : post,
|
||
getJSON : getJSON,
|
||
getUnPostData : getUnPostData,
|
||
removeUnPostData : removeUnPostData,
|
||
syncPostData : syncPostData,
|
||
syncAllPostData : syncAllPostData,
|
||
getCacheData : _getCache,
|
||
saveCacheData : _saveData2local,
|
||
clear : clear
|
||
}
|
||
})(J.$);
|
||
/**
|
||
* 提供一些简单的模板,及artTemplate的渲染
|
||
*/
|
||
J.Template = (function($){
|
||
/**
|
||
* 背景模板
|
||
* @param el selector
|
||
* @param title 显示文本
|
||
* @param icon 图标
|
||
*/
|
||
var background = function(el,title,icon){
|
||
var markup = '<div class="back-mask"><div class="icon '+icon+'"></div><div>'+title+'</div></div>';
|
||
$(el).html(markup);
|
||
}
|
||
|
||
/**
|
||
* 无记录背景模板
|
||
* @param el
|
||
*/
|
||
var no_result = function(el){
|
||
background(el,'没有找到相关数据','drawer');
|
||
}
|
||
/**
|
||
* 加载等待背景模板
|
||
* @param el
|
||
*/
|
||
var loading = function(el){
|
||
background(el,'加载中...','cloud-download');
|
||
}
|
||
|
||
/**
|
||
* 借助artTemplate模板来渲染页面
|
||
* @param containerSelector 目标容器
|
||
* @param templateId artTemplate模板ID
|
||
* @param data 模板数据
|
||
* @param type replace|add 渲染好的文档片段是替换还是添加到目标容器中
|
||
*/
|
||
var render = function(containerSelector,templateId,data,type){
|
||
var el = $(containerSelector),
|
||
type = type || 'replace';//replace add
|
||
if($.type(data) == 'array' && data.length == 0 ){
|
||
no_result(el);
|
||
}else{
|
||
var html = template(templateId,data);
|
||
if(type == 'replace'){
|
||
el.html(html);
|
||
}else{
|
||
el.append(html);
|
||
}
|
||
J.Element.init(html);
|
||
}
|
||
}
|
||
return {
|
||
render : render,
|
||
background : background,
|
||
loading : loading,
|
||
no_result : no_result
|
||
}
|
||
})(J.$);
|
||
|
||
/**
|
||
* 消息组件
|
||
*/
|
||
J.Toast = (function($){
|
||
var toast_type = 'toast',_toast,timer,
|
||
//定义模板
|
||
TEMPLATE = {
|
||
toast : '<a href="#">{value}</a>',
|
||
success : '<a href="#"><i class="icon checkmark-circle"></i>{value}</a>',
|
||
error : '<a href="#"><i class="icon cancel-circle"></i>{value}</a></div>',
|
||
info : '<a href="#"><i class="icon info-2"></i>{value}</a>'
|
||
}
|
||
|
||
var _init = function(){
|
||
//全局只有一个实例
|
||
$('body').append('<div id="jingle_toast"></div>');
|
||
_toast = $('#jingle_toast');
|
||
_subscribeCloseTag();
|
||
}
|
||
|
||
/**
|
||
* 关闭消息提示
|
||
*/
|
||
var hide = function(){
|
||
J.anim(_toast,'scaleOut',function(){
|
||
_toast.hide();
|
||
_toast.empty();
|
||
});
|
||
}
|
||
/**
|
||
* 显示消息提示
|
||
* @param type 类型 toast|success|error|info 空格 + class name 可以实现自定义样式
|
||
* @param text 文字内容
|
||
* @param duration 持续时间 为0则不自动关闭,默认为3000ms
|
||
*/
|
||
var show = function(type,text,duration){
|
||
if(timer) clearTimeout(timer);
|
||
var classname = type.split(/\s/);
|
||
toast_type = classname[0];
|
||
_toast.attr('class',type).html(TEMPLATE[toast_type].replace('{value}',text)).show();
|
||
J.anim(_toast,'scaleIn');
|
||
if(duration !== 0){//为0 不自动关闭
|
||
timer = setTimeout(hide,duration || J.settings.toastDuration);
|
||
}
|
||
}
|
||
var _subscribeCloseTag = function(){
|
||
_toast.on('tap','[data-target="close"]',function(){
|
||
hide();
|
||
})
|
||
}
|
||
_init();
|
||
return {
|
||
show : show,
|
||
hide : hide
|
||
}
|
||
})(J.$);
|
||
/**
|
||
* page转场动画
|
||
* 可自定义css动画
|
||
*/
|
||
J.Transition = (function($){
|
||
var isBack,$current,$target,transitionName,
|
||
animationClass = {
|
||
//[[currentOut,targetIn],[currentOut,targetIn]]
|
||
slide : [['slideLeftOut','slideLeftIn'],['slideRightOut','slideRightIn']],
|
||
cover : [['','slideLeftIn'],['slideRightOut','']],
|
||
slideUp : [['','slideUpIn'],['slideDownOut','']],
|
||
slideDown : [['','slideDownIn'],['slideUpOut','']],
|
||
popup : [['','scaleIn'],['scaleOut','']]
|
||
};
|
||
|
||
var _doTransition = function(){
|
||
//触发 beforepagehide 事件
|
||
$current.trigger('beforepagehide',[isBack]);
|
||
//触发 beforepageshow 事件
|
||
$target.trigger('beforepageshow',[isBack]);
|
||
var c_class = transitionName[0]||'empty' ,t_class = transitionName[1]||'empty';
|
||
$current.bind('webkitAnimationEnd.jingle', _finishTransition).addClass('anim '+ c_class);
|
||
$target.addClass('anim animating '+ t_class);
|
||
}
|
||
var _finishTransition = function() {
|
||
$current.off('webkitAnimationEnd.jingle');
|
||
$target.off('webkitAnimationEnd.jingle');
|
||
//reset class
|
||
$current.attr('class','');
|
||
$target.attr('class','active');
|
||
//add custom events
|
||
!$target.data('init') && $target.trigger('pageinit').data('init',true);
|
||
!$current.data('init') && $current.trigger('pageinit').data('init',true);
|
||
//触发pagehide事件
|
||
$current.trigger('pagehide',[isBack]);
|
||
//触发pageshow事件
|
||
$target.trigger('pageshow',[isBack]);
|
||
|
||
$current.find('article.active').trigger('articlehide');
|
||
$target.find('article.active').trigger('articleshow');
|
||
$current = $target = null;//释放
|
||
}
|
||
|
||
/**
|
||
* 执行转场动画,动画类型取决于目标page上动画配置(返回时取决于当前page)
|
||
* @param current 当前page
|
||
* @param target 目标page
|
||
* @param back 是否为后退
|
||
*/
|
||
var run = function(current,target,back){
|
||
//关闭键盘
|
||
$(':focus').trigger('blur');
|
||
isBack = back;
|
||
$current = $(current);
|
||
$target = $(target);
|
||
var type = isBack?$current.attr('data-transition'):$target.attr('data-transition');
|
||
type = type|| J.settings.transitionType;
|
||
//后退时取相反的动画效果组
|
||
transitionName = isBack ? animationClass[type][1] : animationClass[type][0];
|
||
_doTransition();
|
||
}
|
||
|
||
/**
|
||
* 添加自定义转场动画效果
|
||
* @param name 动画名称
|
||
* @param currentOut 正常情况下当前页面退去的动画class
|
||
* @param targetIn 正常情况下目标页面进入的动画class
|
||
* @param backCurrentOut 后退情况下当前页面退去的动画class
|
||
* @param backCurrentIn 后退情况下目标页面进入的动画class
|
||
*/
|
||
var addAnimation = function(name,currentOut,targetIn,backCurrentOut,backCurrentIn){
|
||
if(animationClass[name]){
|
||
console.error('该转场动画已经存在,请检查你自定义的动画名称(名称不能重复)');
|
||
return;
|
||
}
|
||
animationClass[name] = [[currentOut,targetIn],[backCurrentOut,backCurrentIn]];
|
||
}
|
||
return {
|
||
run : run,
|
||
add : addAnimation
|
||
}
|
||
|
||
})(J.$);
|
||
/**
|
||
* 常用工具类
|
||
*/
|
||
J.Util = (function($){
|
||
var parseHash = function(hash){
|
||
var tag,query,param={};
|
||
var arr = hash.split('?');
|
||
tag = arr[0];
|
||
if(arr.length>1){
|
||
var seg,s;
|
||
query = arr[1];
|
||
seg = query.split('&');
|
||
for(var i=0;i<seg.length;i++){
|
||
if(!seg[i])continue;
|
||
s = seg[i].split('=');
|
||
param[s[0]] = s[1];
|
||
}
|
||
}
|
||
return {
|
||
hash : hash,
|
||
tag : tag,
|
||
query : query,
|
||
param : param
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 格式化date
|
||
* @param date
|
||
* @param format
|
||
*/
|
||
var formatDate = function(date,format){
|
||
var o =
|
||
{
|
||
"M+" : date.getMonth()+1, //month
|
||
"d+" : date.getDate(), //day
|
||
"h+" : date.getHours(), //hour
|
||
"m+" : date.getMinutes(), //minute
|
||
"s+" : date.getSeconds(), //second
|
||
"q+" : Math.floor((date.getMonth()+3)/3), //quarter
|
||
"S" : date.getMilliseconds() //millisecond
|
||
}
|
||
if(/(y+)/.test(format))
|
||
format=format.replace(RegExp.$1,(date.getFullYear()+"").substr(4 - RegExp.$1.length));
|
||
for(var k in o)
|
||
if(new RegExp("("+ k +")").test(format))
|
||
format = format.replace(RegExp.$1,RegExp.$1.length==1 ? o[k] : ("00"+ o[k]).substr((""+ o[k]).length));
|
||
return format;
|
||
}
|
||
|
||
return {
|
||
parseHash : parseHash,
|
||
formatDate : formatDate
|
||
}
|
||
|
||
})(J.$);
|
||
/**
|
||
* 欢迎界面,可以制作酷炫吊炸天的欢迎界面哦
|
||
* @module Welcome
|
||
*/
|
||
J.Welcome = (function($){
|
||
/**
|
||
* 显示欢迎界面
|
||
*/
|
||
var showWelcome = function(){
|
||
$.ajax({
|
||
url : J.settings.basePagePath+'welcome.html',
|
||
timeout : 5000,
|
||
async : false,
|
||
success : function(html){
|
||
//添加到dom树中
|
||
$('body').append(html);
|
||
new J.Slider({
|
||
selector : '#jingle_welcome',
|
||
onAfterSlide : J.settings.welcomeSlideChange
|
||
});
|
||
}
|
||
})
|
||
}
|
||
/**
|
||
* 关闭欢迎界面
|
||
*/
|
||
var hideWelcome = function(){
|
||
J.anim('#jingle_welcome','slideLeftOut',function(){
|
||
$(this).remove();
|
||
window.localStorage.setItem('hasShowWelcome',true);
|
||
})
|
||
}
|
||
|
||
return {
|
||
show : showWelcome,
|
||
hide : hideWelcome
|
||
}
|
||
})(J.$);
|
||
(function($){
|
||
/*
|
||
* alias func
|
||
* 简化一些常用方法的写法
|
||
** /
|
||
/**
|
||
* 完善zepto的动画函数,让参数变为可选
|
||
*/
|
||
J.anim = function(el,animName,duration,ease,callback){
|
||
var d, e,c;
|
||
var len = arguments.length;
|
||
for(var i = 2;i<len;i++){
|
||
var a = arguments[i];
|
||
var t = $.type(a);
|
||
t == 'number'?(d=a):(t=='string'?(e=a):(t=='function')?(c=a):null);
|
||
}
|
||
$(el).animate(animName,d|| J.settings.transitionTime,e||J.settings.transitionTimingFunc,c);
|
||
}
|
||
/**
|
||
* 显示loading框
|
||
* @param text
|
||
*/
|
||
J.showMask = function(text){
|
||
J.Popup.loading(text);
|
||
}
|
||
/**
|
||
* 关闭loading框
|
||
*/
|
||
J.hideMask = function(){
|
||
J.Popup.close(true);
|
||
}
|
||
/**
|
||
* 显示消息
|
||
* @param text
|
||
* @param type toast|success|error|info
|
||
* @param duration 持续时间,为0则不自动关闭
|
||
*/
|
||
J.showToast = function(text,type,duration){
|
||
type = type || 'toast';
|
||
J.Toast.show(type,text,duration);
|
||
}
|
||
/**
|
||
* 关闭消息提示
|
||
*/
|
||
J.hideToast = function(){
|
||
J.Toast.hide();
|
||
}
|
||
J.alert = function(title,content){
|
||
J.Popup.alert(title,content);
|
||
}
|
||
J.confirm = function(title,content,okCall,cancelCall){
|
||
J.Popup.confirm(title,content,okCall,cancelCall);
|
||
}
|
||
/**
|
||
* 弹出窗口
|
||
* @param options
|
||
*/
|
||
J.popup = function(options){
|
||
J.Popup.show(options);
|
||
}
|
||
/**
|
||
* 关闭窗口
|
||
*/
|
||
J.closePopup = function(){
|
||
J.Popup.close();
|
||
}
|
||
/**
|
||
* 带箭头的弹出框
|
||
* @param html [可选]
|
||
* @param pos [可选] 位置
|
||
* @param arrowDirection [可选] 箭头方向
|
||
* @param onShow [可选] 显示之前执行
|
||
*/
|
||
J.popover = function(html,pos,arrowDirection,onShow){
|
||
J.Popup.popover(html,pos,arrowDirection,onShow);
|
||
}
|
||
/**
|
||
* 自动渲染模板并填充到页面
|
||
* @param containerSelector 欲填充的容器
|
||
* @param templateId 模板ID
|
||
* @param data 数据源
|
||
* @param type [可选] add|replace
|
||
*/
|
||
J.tmpl = function(containerSelector,templateId,data,type){
|
||
J.Template.render(containerSelector,templateId,data,type);
|
||
}
|
||
})(J.$);
|
||
/**
|
||
* 弹出框组件
|
||
*/
|
||
J.Popup = (function($){
|
||
var _popup,_mask,transition,clickMask2close,
|
||
POSITION = {
|
||
'top':{
|
||
top:0,
|
||
left:0,
|
||
right:0
|
||
},
|
||
'top-second':{
|
||
top:'44px',
|
||
left:0,
|
||
right:0
|
||
},
|
||
'center':{
|
||
top:'50%',
|
||
left:'5%',
|
||
right:'5%',
|
||
'border-radius' : '3px'
|
||
},
|
||
'bottom' : {
|
||
bottom:0,
|
||
left:0,
|
||
right:0
|
||
},
|
||
'bottom-second':{
|
||
bottom : '51px',
|
||
left:0,
|
||
right:0
|
||
}
|
||
},
|
||
ANIM = {
|
||
top : ['slideDownIn','slideUpOut'],
|
||
bottom : ['slideUpIn','slideDownOut'],
|
||
defaultAnim : ['bounceIn','bounceOut']
|
||
},
|
||
TEMPLATE = {
|
||
alert : '<div class="popup-title">{title}</div><div class="popup-content">{content}</div><div id="popup_btn_container"><a data-target="closePopup" data-icon="checkmark">{ok}</a></div>',
|
||
confirm : '<div class="popup-title">{title}</div><div class="popup-content">{content}</div><div id="popup_btn_container"><a class="cancel" data-icon="close">{cancel}</a><a data-icon="checkmark">{ok}</a></div>',
|
||
loading : '<i class="icon spinner"></i><p>{title}</p>'
|
||
};
|
||
|
||
/**
|
||
* 全局只有一个popup实例
|
||
* @private
|
||
*/
|
||
var _init = function(){
|
||
$('body').append('<div id="jingle_popup"></div><div id="jingle_popup_mask"></div>');
|
||
_mask = $('#jingle_popup_mask');
|
||
_popup = $('#jingle_popup');
|
||
_subscribeEvents();
|
||
}
|
||
|
||
var show = function(options){
|
||
var settings = {
|
||
height : undefined,//高度
|
||
width : undefined,//宽度
|
||
opacity : 0.3,//透明度
|
||
url : null,//远程加载url
|
||
tplId : null,//加载模板ID
|
||
tplData : null,//模板数据,配合tplId使用
|
||
html : '',//popup内容
|
||
pos : 'center',//位置 {@String top|top-second|center|bottom|bottom-second} {@object css样式}
|
||
clickMask2Close : true,// 是否点击外层遮罩关闭popup
|
||
showCloseBtn : true,// 是否显示关闭按钮
|
||
arrowDirection : undefined,//popover的箭头指向
|
||
animation : true,//是否显示动画
|
||
timingFunc : 'linear',
|
||
duration : 200,//动画执行时间
|
||
onShow : undefined //@event 在popup内容加载完毕,动画开始前触发
|
||
}
|
||
$.extend(settings,options);
|
||
clickMask2close = settings.clickMask2Close;
|
||
_mask.css('opacity',settings.opacity);
|
||
//rest position and class
|
||
_popup.attr({'style':'','class':''});
|
||
settings.width && _popup.width(settings.width);
|
||
settings.height && _popup.height(settings.height);
|
||
var pos_type = $.type(settings.pos);
|
||
if(pos_type == 'object'){// style
|
||
_popup.css(settings.pos);
|
||
transition = ANIM['defaultAnim'];
|
||
}else if(pos_type == 'string'){
|
||
if(POSITION[settings.pos]){ //已经默认的样式
|
||
_popup.css(POSITION[settings.pos])
|
||
var trans_key = settings.pos.indexOf('top')>-1?'top':(settings.pos.indexOf('bottom')>-1?'bottom':'defaultAnim');
|
||
transition = ANIM[trans_key];
|
||
}else{// pos 为 class
|
||
_popup.addClass(settings.pos);
|
||
transition = ANIM['defaultAnim'];
|
||
}
|
||
}else{
|
||
console.error('错误的参数!');
|
||
return;
|
||
}
|
||
_mask.show();
|
||
var html;
|
||
if(settings.html){
|
||
html = settings.html;
|
||
}else if(settings.url){//远程加载
|
||
html = J.Page.loadContent(settings.url);
|
||
}else if(settings.tplId){//加载模板
|
||
html = template(settings.tplId,settings.tplData)
|
||
}
|
||
|
||
//是否显示关闭按钮
|
||
if(settings.showCloseBtn){
|
||
html += '<div id="tag_close_popup" data-target="closePopup" class="icon cancel-circle"></div>';
|
||
}
|
||
//popover 箭头方向
|
||
if(settings.arrowDirection){
|
||
_popup.addClass('arrow '+settings.arrowDirection);
|
||
_popup.css('padding','8px');
|
||
if(settings.arrowDirection=='top'||settings.arrowDirection=='bottom'){
|
||
transition = ANIM[settings.arrowDirection];
|
||
}
|
||
}
|
||
|
||
_popup.html(html).show();
|
||
J.Element.init(_popup);
|
||
//执行onShow事件,可以动态添加内容
|
||
settings.onShow && settings.onShow.call(_popup);
|
||
|
||
//显示获取容器高度,调整至垂直居中
|
||
if(settings.pos == 'center'){
|
||
var height = _popup.height();
|
||
_popup.css('margin-top','-'+height/2+'px')
|
||
}
|
||
if(settings.animation){
|
||
J.anim(_popup,transition[0],settings.duration,settings.timingFunc);
|
||
}
|
||
J.hasPopupOpen = true;
|
||
}
|
||
|
||
/**
|
||
* 关闭弹出框
|
||
* @param noTransition 立即关闭,无动画
|
||
*/
|
||
var hide = function(noTransition){
|
||
_mask.hide();
|
||
if(transition && !noTransition){
|
||
J.anim(_popup,transition[1],200,function(){
|
||
_popup.hide().empty();
|
||
J.hasPopupOpen = false;
|
||
});
|
||
}else{
|
||
_popup.hide().empty();
|
||
J.hasPopupOpen = false;
|
||
}
|
||
|
||
}
|
||
var _subscribeEvents = function(){
|
||
_mask.on('tap',function(){
|
||
clickMask2close && hide();
|
||
});
|
||
_popup.on('tap','[data-target="closePopup"]',function(){hide();});
|
||
}
|
||
|
||
/**
|
||
* alert组件
|
||
* @param title 标题
|
||
* @param content 内容
|
||
*/
|
||
var alert = function(title,content,btnName){
|
||
var markup = TEMPLATE.alert.replace('{title}',title).replace('{content}',content).replace('{ok}',btnName || '确定');
|
||
show({
|
||
html : markup,
|
||
pos : 'center',
|
||
clickMask2Close : false,
|
||
showCloseBtn : false
|
||
});
|
||
}
|
||
|
||
/**
|
||
* confirm 组件
|
||
* @param title 标题
|
||
* @param content 内容
|
||
* @param okCall 确定按钮handler
|
||
* @param cancelCall 取消按钮handler
|
||
*/
|
||
var confirm = function(title,content,okCall,cancelCall){
|
||
var markup = TEMPLATE.confirm.replace('{title}',title).replace('{content}',content).replace('{cancel}','取消').replace('{ok}','确定');
|
||
show({
|
||
html : markup,
|
||
pos : 'center',
|
||
clickMask2Close : false,
|
||
showCloseBtn : false
|
||
});
|
||
$('#popup_btn_container [data-icon="checkmark"]').tap(function(){
|
||
hide();
|
||
okCall.call(this);
|
||
});
|
||
$('#popup_btn_container [data-icon="close"]').tap(function(){
|
||
hide();
|
||
cancelCall.call(this);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 带箭头的弹出框
|
||
* @param html 弹出框内容
|
||
* @param pos 位置
|
||
* @param arrow_direction 箭头方向
|
||
* @param onShow onShow事件
|
||
*/
|
||
var popover = function(html,pos,arrow_direction,onShow){
|
||
show({
|
||
html : html,
|
||
pos : pos,
|
||
showCloseBtn : false,
|
||
arrowDirection : arrow_direction,
|
||
onShow : onShow
|
||
});
|
||
}
|
||
|
||
/**
|
||
* loading组件
|
||
* @param text 文本,默认为“加载中...”
|
||
*/
|
||
var loading = function(text){
|
||
var markup = TEMPLATE.loading.replace('{title}',text||'加载中...');
|
||
show({
|
||
html : markup,
|
||
pos : 'loading',
|
||
opacity :.1,
|
||
animation : true,
|
||
clickMask2Close : false
|
||
});
|
||
}
|
||
|
||
/**
|
||
* actionsheet组件
|
||
* @param buttons 按钮集合
|
||
* [{color:'red',text:'btn',handler:function(){}},{color:'red',text:'btn',handler:function(){}}]
|
||
*/
|
||
var actionsheet = function(buttons){
|
||
var markup = '<div class="actionsheet">';
|
||
$.each(buttons,function(i,n){
|
||
markup += '<button style="background-color: '+ n.color +' !important;">'+ n.text +'</button>';
|
||
});
|
||
markup += '<button class="alizarin">取消</button>';
|
||
markup += '</div>';
|
||
show({
|
||
html : markup,
|
||
pos : 'bottom',
|
||
showCloseBtn : false,
|
||
onShow : function(){
|
||
$(this).find('button').each(function(i,button){
|
||
$(button).on('tap',function(){
|
||
if(buttons[i] && buttons[i].handler){
|
||
buttons[i].handler.call(button);
|
||
}
|
||
hide();
|
||
});
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
_init();
|
||
|
||
return {
|
||
show : show,
|
||
close : hide,
|
||
alert : alert,
|
||
confirm : confirm,
|
||
popover : popover,
|
||
loading : loading,
|
||
actionsheet : actionsheet
|
||
}
|
||
})(J.$);
|
||
/**
|
||
* 高亮组件
|
||
* 在zepto的tap事件里注入了一个延时器,来实现点击态
|
||
*/
|
||
J.Selected = (function($){
|
||
var DELAY = 100,SELECTOR='[data-selected]';
|
||
var _trigger = $.fn.trigger;
|
||
$.fn.trigger = function (event) {
|
||
var $this = $(this), args = arguments, classname;
|
||
if (event === 'tap' || event.type === 'tap') {
|
||
var match = $this.closest(SELECTOR).get(0);
|
||
if(match){
|
||
match = $(match);
|
||
classname = match.data('selected');
|
||
match.addClass(classname);
|
||
setTimeout(function () {
|
||
match.removeClass(classname);
|
||
_trigger.apply($this, args);
|
||
$this = match = null;
|
||
}, DELAY);
|
||
return this;
|
||
}
|
||
}
|
||
_trigger.apply($this, args);
|
||
return this;
|
||
}
|
||
})(J.$);
|
||
/**
|
||
* 数据缓存
|
||
* todo 对数据进行加密
|
||
*/
|
||
J.Cache = (function($){
|
||
var UNPOST_KEY = '_J_P_',
|
||
GET_KEY_PREFIX = '_J_';
|
||
|
||
/**
|
||
* 缓存从服务端获取的数据
|
||
* @param key
|
||
* @param value
|
||
*/
|
||
var save = function(key,value){
|
||
var data = {
|
||
data : value,
|
||
cacheTime : new Date()
|
||
}
|
||
window.localStorage.setItem(GET_KEY_PREFIX+key,JSON.stringify(data));
|
||
}
|
||
/**
|
||
* 获取本地已缓存的数据
|
||
*/
|
||
var get = function(key){
|
||
return JSON.parse(window.localStorage.getItem(GET_KEY_PREFIX+key));
|
||
}
|
||
|
||
/**
|
||
* 缓存本地待提交到服务端的数据(离线操作)
|
||
* @param url
|
||
* @param result
|
||
*/
|
||
var savePost = function(url,result){
|
||
var data = getPost();
|
||
data = data || {};
|
||
data[url] = {
|
||
data : result,
|
||
createdTime : new Date()
|
||
}
|
||
window.localStorage.setItem(UNPOST_KEY,JSON.stringify(data));
|
||
}
|
||
|
||
/**
|
||
* 获取本地尚未提交到服务端的缓存数据
|
||
* @param url 没有就返回所有未同步的数据
|
||
*/
|
||
var getPost = function(url){
|
||
var data = JSON.parse(window.localStorage.getItem(UNPOST_KEY));
|
||
return (data && url ) ? data[url] : data;
|
||
}
|
||
/**
|
||
* 移除未提交的待提交到服务端的缓存数据
|
||
* @param url 没有就移除所有未提交的数据
|
||
*/
|
||
var removePost = function(url){
|
||
if(url){
|
||
var data = getPost();
|
||
delete data[url];
|
||
window.localStorage.setItem(UNPOST_KEY,JSON.stringify(data));
|
||
}else{
|
||
window.localStorage.removeItem(UNPOST_KEY);
|
||
}
|
||
}
|
||
/**
|
||
* 同步本地未提交的数据到服务端
|
||
* * @param url 没有就同步所有未提交的数据
|
||
*/
|
||
var syncPost = function(url,success,error){
|
||
var dataLen,index = 0;
|
||
if($.type(url) == 'string'){
|
||
dataLen = 1;
|
||
sync(url);
|
||
}else{
|
||
var postData = getPost();
|
||
if(!postData)return;
|
||
dataLen = postData.length;
|
||
for(var url in postData){
|
||
sync(url);
|
||
}
|
||
}
|
||
function sync(url){
|
||
var data = getPost(url).data;
|
||
$.ajax({
|
||
url : url,
|
||
contentType:'application/json',
|
||
data : data,
|
||
type : 'post',
|
||
success : function(){
|
||
index++;
|
||
removePost(url);
|
||
if(index == dataLen)success(url);
|
||
},
|
||
error : function(){
|
||
error(url);
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 清空本地缓存
|
||
*/
|
||
var clear = function(){
|
||
var storage = window.localStorage;
|
||
for(var key in storage){
|
||
if(key.indexOf(GET_KEY_PREFIX) == 0){
|
||
storage.removeItem(key);
|
||
}
|
||
}
|
||
storage.removeItem(UNPOST_KEY);
|
||
}
|
||
|
||
|
||
return {
|
||
get : get,
|
||
save : save,
|
||
getPost : getPost,
|
||
savePost : savePost,
|
||
removePost : removePost,
|
||
syncPost : syncPost,
|
||
clear : clear
|
||
}
|
||
|
||
})(J.$);
|
||
;(function($){
|
||
/**
|
||
* 日历组件
|
||
* @param selector selector
|
||
* @param options 配置参数
|
||
*/
|
||
var calendar = function(selector,options){
|
||
var defaults = {
|
||
months : ["01月", "02月", "03月", "04月", "05月", "06月",
|
||
"07月", "08月", "09月", "10月", "11月", "12月"],
|
||
days : ["日", "一", "二", "三", "四", "五", "六"],
|
||
swipeable : true,//是否可通过手指滑动
|
||
date : new Date(),//日历当前日期
|
||
onRenderDay : undefined,//渲染单元格时的事件
|
||
onSelect : undefined //选中日期时的事件
|
||
},
|
||
_this = this,
|
||
$el = $(selector),
|
||
$yearText,
|
||
$monthText,
|
||
$calendarBody,
|
||
currentDate,currentYear,currentMonth;
|
||
|
||
var _init = function(){
|
||
_this.settings = $.extend({},defaults,options);
|
||
currentYear = _this.settings.date.getFullYear();
|
||
currentMonth = _this.settings.date.getMonth();
|
||
currentDate = new Date(currentYear,currentMonth,_this.settings.date.getDate());
|
||
_render();
|
||
_subscribeEvents();
|
||
}
|
||
|
||
/**
|
||
* 获取月份第一天是星期几[0-6]
|
||
*/
|
||
var _fisrtDayOfMonth = function(date){
|
||
return ( new Date(date.getFullYear(), date.getMonth(), 1) ).getDay();
|
||
}
|
||
/**
|
||
* 获取月份总天数[1-31]
|
||
*/
|
||
var _daysInMonth = function(date){
|
||
return ( new Date(date.getFullYear(),date.getMonth()+1,0) ).getDate();
|
||
}
|
||
|
||
/**
|
||
* 渲染日历
|
||
* @private
|
||
*/
|
||
var _render = function(){
|
||
var html = '';
|
||
html += '<div class="jingle-calendar">';
|
||
html += _renderNav(currentYear,currentMonth);
|
||
html += _renderHead();
|
||
html += '<div class="jingle-calendar-body">';
|
||
html += _renderBody(currentDate);
|
||
html += '</div></div>'
|
||
$el.html(html);
|
||
var $span = $el.find('span');
|
||
$yearText = $span.eq(0);
|
||
$monthText = $span.eq(1);
|
||
$calendarBody = $el.find('.jingle-calendar-body');
|
||
}
|
||
|
||
var _renderNav = function(year,month){
|
||
var html = '<div class="jingle-calendar-nav">';
|
||
html += '<div> <i class="icon previous" data-year='+year+'></i><span>'+year+'</span><i class="icon next" data-year='+year+'></i></div>';
|
||
html += '<div ><i class="icon previous" data-month='+month+'></i> <span>'+_this.settings.months[month]+'</span><i class="icon next" data-month='+month+'></i></div>';
|
||
html += '</div>';
|
||
return html;
|
||
}
|
||
|
||
var _renderHead = function(){
|
||
var html = '<table><thead><tr>';
|
||
for(var i = 0; i < 7; i++){
|
||
html += '<th>'+_this.settings.days[i]+'</th>';
|
||
}
|
||
html += '</tr></thead></table>'
|
||
return html;
|
||
}
|
||
|
||
var _renderBody = function(date){
|
||
var firstDay = _fisrtDayOfMonth(date),
|
||
days = _daysInMonth(date),
|
||
rows = Math.ceil((firstDay+days) / 7),
|
||
beginDate,
|
||
html = '';
|
||
currentYear = date.getFullYear();
|
||
currentMonth = date.getMonth();
|
||
beginDate = new Date(currentYear,currentMonth,1-firstDay);//日历开始的日期
|
||
html += '<table><tbody>';
|
||
for(var i = 0; i < rows; i++){
|
||
html += '<tr>';
|
||
for(var j = 0; j < 7; j++){
|
||
html += _renderDay(beginDate,currentMonth);
|
||
beginDate.setDate(beginDate.getDate() + 1);
|
||
}
|
||
html += '</tr>';
|
||
}
|
||
html += '</tbody></table>';
|
||
return html;
|
||
}
|
||
var _renderDay = function(date,month){
|
||
var otherMonth = (date.getMonth() !== month);
|
||
var dateStr = _this.format(date);
|
||
var classname = (_this.format(_this.settings.date) == dateStr) ? 'active':'';
|
||
var dayStr = date.getDate();
|
||
if(_this.settings.onRenderDay){
|
||
dayStr = _this.settings.onRenderDay.call(null,dayStr,dateStr);
|
||
}
|
||
return otherMonth ? '<td> </td>' : '<td data-selected="selected" class="'+classname+ '" data-date= '+dateStr+'>'+dayStr+'</td>';
|
||
}
|
||
|
||
var _subscribeEvents = function(){
|
||
var $target,$ctarget;
|
||
$el.on('tap',function(e){
|
||
$target = $(e.target);
|
||
if($target.is('[data-year].next')){
|
||
//后一年
|
||
currentDate.setFullYear(currentDate.getFullYear()+1);
|
||
_this.refresh(currentDate);
|
||
}else if($target.is('[data-year].previous')){
|
||
//前一年
|
||
currentDate.setFullYear(currentDate.getFullYear()-1);
|
||
_this.refresh(currentDate);
|
||
}else if($target.is('[data-month].next')){
|
||
//后一月
|
||
currentDate.setMonth(currentDate.getMonth()+1);
|
||
_this.refresh(currentDate);
|
||
}else if($target.is('[data-month].previous')){
|
||
//前一月
|
||
currentDate.setMonth(currentDate.getMonth()-1);
|
||
_this.refresh(currentDate);
|
||
}
|
||
$ctarget = $target.closest('td');
|
||
if(!$target.is('td') && $ctarget.length > 0){
|
||
$target = $ctarget;
|
||
}
|
||
if($target.is('td')){
|
||
var dateStr = $target.data('date');
|
||
if(dateStr && _this.settings.onSelect){
|
||
_this.settings.onSelect.call(_this,dateStr)
|
||
}
|
||
}
|
||
|
||
});
|
||
$el.on('swipeLeft',function(){
|
||
currentDate.setMonth(currentDate.getMonth()+1);
|
||
_this.refresh(currentDate);
|
||
});
|
||
$el.on('swipeRight',function(){
|
||
currentDate.setMonth(currentDate.getMonth()-1);
|
||
_this.refresh(currentDate);
|
||
})
|
||
}
|
||
|
||
/**
|
||
* 刷新日历为指定日期
|
||
* @param date 指定日期
|
||
*/
|
||
this.refresh = function(date){
|
||
var oldDate = new Date(currentYear,currentMonth,1),
|
||
newDate = new Date(date.getFullYear(),date.getMonth(),1),
|
||
transition = undefined,$table;
|
||
|
||
if(oldDate.getTime() == newDate.getTime())return;
|
||
transition = oldDate<newDate ? 'slideLeftRound' : 'slideRightRound';
|
||
|
||
$yearText.text(date.getFullYear());
|
||
$monthText.text(this.settings.months[date.getMonth()]);
|
||
var newbody = _renderBody(date);
|
||
J.anim($calendarBody,transition,function(){
|
||
$calendarBody.html(newbody);
|
||
});
|
||
|
||
}
|
||
_init();
|
||
}
|
||
/**
|
||
* 字符串转化为日期对象,只支持yyyy-MM-dd 和 yyyy/MM/dd
|
||
* @param date
|
||
* @return {*}
|
||
*/
|
||
calendar.prototype.parse = function(date){
|
||
var dateRE = /^(\d{4})(?:\-|\/)(\d{1,2})(?:\-|\/)(\d{1,2})$/;
|
||
return dateRE.test(date) ? new Date(parseInt(RegExp.$1, 10), parseInt(RegExp.$2, 10) - 1, parseInt(RegExp.$3, 10)) : null;
|
||
}
|
||
/**
|
||
* 格式化日期 yyyy-MM-dd
|
||
* @return {String}
|
||
*/
|
||
calendar.prototype.format = function(date){
|
||
var y = date.getFullYear(),m = date.getMonth()+1,d = date.getDate();
|
||
m = (m<10)?('0'+m):m;
|
||
d = (d<10)?('0'+d):d;
|
||
return y + '-' + m + '-' + d;
|
||
}
|
||
J.Calendar = calendar;
|
||
})(J.$);
|
||
/**
|
||
* 哥屋恩动组件(iscroll)
|
||
*/
|
||
;(function($){
|
||
var scrollCache = {},index = 1;
|
||
J.Scroll = function(selector,opts){
|
||
var scroll,scrollId,$el = $(selector),
|
||
options = {
|
||
hScroll : false,
|
||
bounce : false,
|
||
lockDirection : true,
|
||
useTransform: true,
|
||
useTransition: false,
|
||
checkDOMChanges: false,
|
||
onBeforeScrollStart: function (e) {
|
||
var target = e.target;
|
||
while (target.nodeType != 1) target = target.parentNode;
|
||
if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA')
|
||
e.preventDefault();
|
||
}
|
||
};
|
||
scrollId = $el.data('_jscroll_');
|
||
//滚动组件使用频繁,缓存起来节省开销
|
||
if(scrollId && scrollCache[scrollId]){
|
||
scroll = scrollCache[scrollId];
|
||
$.extend(scroll.scroller.options,opts)
|
||
scroll.scroller.refresh();
|
||
return scroll;
|
||
}else{
|
||
scrollId = '_jscroll_'+index++;
|
||
$el.data('_jscroll_',scrollId);
|
||
$.extend(options,opts);
|
||
scroller = new iScroll($el[0],options);
|
||
return scrollCache[scrollId] = {
|
||
scroller : scroller,
|
||
destroy : function(){
|
||
scroller.destroy();
|
||
delete scrollCache[scrollId];
|
||
}
|
||
};
|
||
};
|
||
}
|
||
})(J.$);
|
||
|
||
|
||
/**
|
||
* 幻灯片组件
|
||
*/
|
||
;(function($){
|
||
function slider(selector,showDots){
|
||
var afterSlide = function(){},
|
||
beforeSlide = function(){return true},
|
||
gestureStarted = false,
|
||
index = 0,
|
||
speed = 200,
|
||
wrapper,
|
||
dots,
|
||
container,
|
||
slides,
|
||
slideNum,
|
||
slideWidth,
|
||
deltaX,
|
||
autoPlay
|
||
interval = 0;
|
||
var _this = this;
|
||
|
||
if($.isPlainObject(selector)){
|
||
wrapper = $(selector.selector);
|
||
showDots = selector.showDots;
|
||
beforeSlide = selector.onBeforeSlide || beforeSlide;
|
||
afterSlide = selector.onAfterSlide || afterSlide;
|
||
autoPlay = selector.autoPlay;
|
||
interval = selector.interval || 3000;
|
||
}else{
|
||
wrapper = $(selector);
|
||
}
|
||
/**
|
||
* 初始化容器大小
|
||
*/
|
||
var _init = function() {
|
||
container = wrapper.children().first();
|
||
slides = container.children();
|
||
slideNum = slides.length;
|
||
slideWidth = wrapper.offset().width;
|
||
container.css('width',slideNum * slideWidth);
|
||
slides.css({
|
||
'width':slideWidth,
|
||
'float':'left'
|
||
}).show();
|
||
if(showDots == undefined)showDots = true;
|
||
showDots && _initDots();
|
||
_slide(0, 0);
|
||
afterSlide(0);
|
||
autoPlay && _autoPlay();
|
||
};
|
||
|
||
var _autoPlay = function(){
|
||
setTimeout(function(){
|
||
if(index == slideNum - 1){
|
||
_slide(0);
|
||
}else{
|
||
_this.next();
|
||
}
|
||
_autoPlay();
|
||
},interval);
|
||
}
|
||
|
||
var _initDots = function(){
|
||
dots = wrapper.find('.dots');
|
||
if(dots.length>0){
|
||
dots.show();
|
||
}else{
|
||
var dotsWidth = slideNum*30+20+2;
|
||
var html = '<div class="dots"><ul>';
|
||
for(var i=0;i<slideNum;i++){
|
||
html +='<li index="'+i+'"';
|
||
if(i == 0){
|
||
html += 'class="active"';
|
||
}
|
||
html += '><a href="#"></a></li>';
|
||
}
|
||
html += '</ul></div>';
|
||
wrapper.append(html);
|
||
dots = wrapper.find('.dots');
|
||
dots.children().css('width',dotsWidth+'px');
|
||
dots.find('li').on('tap',function(){
|
||
var index = $(this).attr('index');
|
||
_slide(parseInt(index), speed);
|
||
})
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 滑动到指定卡片
|
||
* @param i
|
||
* @param duration
|
||
* @private
|
||
*/
|
||
var _slide = function(i, duration) {
|
||
duration = duration || speed;
|
||
container.css({
|
||
'-webkit-transition-duration':duration + 'ms',
|
||
'-webkit-transform':'translate3D(' + -(i * slideWidth) + 'px,0,0)'
|
||
});
|
||
if(index != i){
|
||
index = i;
|
||
if(dots) $(dots.find('li').get(index)).addClass('active').siblings().removeClass('active');
|
||
afterSlide(index);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 绑定滑动事件
|
||
*/
|
||
var _bindEvents = function() {
|
||
container.on('touchstart',_touchStart,false);
|
||
container.on('touchmove',_touchMove,false);
|
||
container.on('touchend',_touchEnd,false);
|
||
};
|
||
|
||
var _touchStart = function(event) {
|
||
var e = event.touches[0];
|
||
start = {
|
||
pageX: e.pageX,
|
||
pageY: e.pageY,
|
||
time: Number(new Date())
|
||
};
|
||
isScrolling = undefined;
|
||
deltaX = 0;
|
||
container[0].style.webkitTransitionDuration = 0;
|
||
gestureStarted = true;
|
||
};
|
||
|
||
var _touchMove = function(event) {
|
||
if(!gestureStarted)return;
|
||
var e = event.touches[0];
|
||
deltaX = e.pageX - start.pageX;
|
||
if ( typeof isScrolling == 'undefined') {
|
||
//根据X、Y轴的偏移量判断用户的意图是左右滑动还是上下滑动
|
||
isScrolling = Math.abs(deltaX) < Math.abs(e.pageY - start.pageY)
|
||
}
|
||
if (!isScrolling) {
|
||
event.preventDefault();
|
||
//判定是否达到了边界即第一个右滑、最后一个左滑
|
||
var isPastBounds = !index && deltaX > 0 || index == slideNum - 1 && deltaX < 0;
|
||
if(isPastBounds)return;
|
||
var pos = (deltaX - index * slideWidth);
|
||
container[0].style.webkitTransform = 'translate3D('+pos+'px,0,0)';
|
||
}
|
||
};
|
||
|
||
var _touchEnd = function(e) {
|
||
//判定是否跳转到下一个卡片
|
||
//滑动时间小于250ms或者滑动X轴的距离大于屏幕宽度的1/3,则直接跳转到下一个卡片
|
||
var isValidSlide = (Number(new Date()) - start.time < 250 && Math.abs(deltaX) > 20) || Math.abs(deltaX) > slideWidth/3;
|
||
//判定是否达到了边界即第一个右滑、最后一个左滑
|
||
var isPastBounds = !index && deltaX > 0 || index == slideNum - 1 && deltaX < 0;
|
||
if (!isScrolling) {
|
||
if(beforeSlide(index,deltaX)){
|
||
_slide( index + ( isValidSlide && !isPastBounds ? (deltaX < 0 ? 1 : -1) : 0 ), speed );
|
||
}else{
|
||
_slide(index);
|
||
}
|
||
}
|
||
gestureStarted = false;
|
||
};
|
||
|
||
|
||
_init();
|
||
_bindEvents();
|
||
|
||
this.refresh = function(){
|
||
container.attr('style','');
|
||
_init();
|
||
};
|
||
|
||
this.prev = function() {
|
||
if (index) _slide(index-1, speed);
|
||
};
|
||
|
||
this.next = function() {
|
||
if(index < slideNum-1){
|
||
_slide(index+1, speed);
|
||
}
|
||
};
|
||
this.index = function(i) {
|
||
_slide(i);
|
||
};
|
||
}
|
||
J.Slider = slider;
|
||
})(J.$);
|
||
/**
|
||
* 上拉/下拉组件
|
||
*/
|
||
;(function($){
|
||
var refreshCache = {},index = 1;
|
||
function Refresh(selector,type,callback){
|
||
var iscroll, scroller,refreshEl,iconEl,labelEl,topOffset,isPullDown,
|
||
options = {
|
||
selector : undefined,
|
||
type : 'pullDown',//pullDown|pullUp 默认为pullDown
|
||
minPullHeight : 10,//拉动的像素相对值,超过才会翻转
|
||
pullText: "下拉刷新...",
|
||
releaseText: "松开立即刷新...",
|
||
refreshText: "刷新中...",
|
||
refreshTip : false,//下拉时显示的文本,比如:最后更新时间:2013-....
|
||
onPullIcon : 'arrow-down-2',
|
||
onReleaseIcon : 'icon-reverse',
|
||
onRefreshIcon : 'spinner',
|
||
callback : undefined
|
||
};
|
||
//装载配置
|
||
if(typeof selector === 'object'){
|
||
$.extend(options,selector);
|
||
}else{
|
||
options.selector = selector;
|
||
options.type = type;
|
||
options.callback = callback;
|
||
if(type === 'pullUp'){
|
||
$.extend(options,{
|
||
pullText: "上拉加载更多...",
|
||
releaseText: "松开开立即加载...",
|
||
refreshText: "加载中...",
|
||
onPullIcon : 'arrow-up-3'
|
||
})
|
||
}
|
||
}
|
||
isPullDown = options.type === 'pullDown' ? true : false;
|
||
|
||
/**
|
||
* 初始化dom节点
|
||
* @param opts
|
||
* @private
|
||
*/
|
||
var _init = function(opts){
|
||
scroller = $(opts.selector).children()[0];
|
||
var refreshTpl = '<div class="refresh-container"><span class="refresh-icon icon '+opts.onPullIcon
|
||
+'"></span><span class="refresh-label">'
|
||
+opts.pullText+'</span>'
|
||
+(opts.refreshTip?'<div class="refresh-tip">'+opts.refreshTip+'</div>':'')+'</div>';
|
||
if(isPullDown){
|
||
refreshEl = $(refreshTpl).prependTo(scroller);
|
||
}else{
|
||
refreshEl = $(refreshTpl).appendTo(scroller);
|
||
}
|
||
topOffset = refreshEl.height();
|
||
iconEl = refreshEl.find('.refresh-icon');
|
||
labelEl = refreshEl.find('.refresh-label');
|
||
}
|
||
|
||
/**
|
||
* 构造iscroll组件,并绑定滑动事件
|
||
* @param opts
|
||
* @private
|
||
*/
|
||
var _excuteScroll = function(opts){
|
||
return J.Scroll(opts.selector,{
|
||
topOffset:isPullDown?topOffset:0,
|
||
bounce : true,
|
||
onScrollMove : function(){
|
||
if (this.y > opts.minPullHeight && isPullDown && !iconEl.hasClass(opts.onReleaseIcon)) {
|
||
iconEl.addClass(opts.onReleaseIcon);
|
||
labelEl.html(opts.releaseText);
|
||
this.minScrollY = 0;
|
||
} else if (this.y < opts.minPullHeight && isPullDown && iconEl.hasClass(opts.onReleaseIcon)) {
|
||
iconEl.removeClass(opts.onReleaseIcon);
|
||
labelEl.html(opts.pullText);
|
||
this.minScrollY = -topOffset;
|
||
}else if (this.y < (this.maxScrollY - opts.minPullHeight) && !isPullDown && !iconEl.hasClass(opts.onReleaseIcon)) {
|
||
iconEl.addClass(opts.onReleaseIcon);
|
||
labelEl.html(opts.releaseText);
|
||
this.maxScrollY = this.maxScrollY;
|
||
} else if (this.y > (this.maxScrollY + opts.minPullHeight) && !isPullDown && iconEl.hasClass(opts.onReleaseIcon)) {
|
||
iconEl.removeClass(opts.onReleaseIcon);
|
||
labelEl.html(opts.pullText);
|
||
this.maxScrollY = topOffset;
|
||
}
|
||
},
|
||
onScrollEnd : function(){
|
||
if(iconEl.hasClass(opts.onReleaseIcon)){
|
||
iconEl.removeClass(opts.onReleaseIcon).removeClass(opts.onPullIcon).addClass(opts.onRefreshIcon);
|
||
labelEl.html(opts.refreshText);
|
||
var _this = this;
|
||
setTimeout(function(){//解决在chrome下onRefresh的时候文本无法更改的问题。奇怪的问题!
|
||
opts.callback.call(_this);
|
||
},1);
|
||
|
||
}
|
||
},
|
||
onRefresh: function () {
|
||
iconEl.removeClass(opts.onRefreshIcon).addClass(opts.onPullIcon);
|
||
labelEl.html(opts.pullText);
|
||
}
|
||
});
|
||
}
|
||
|
||
//run
|
||
_init(options);
|
||
iscroll = _excuteScroll(options);
|
||
return iscroll;
|
||
|
||
}
|
||
|
||
/**
|
||
* 刷新组件
|
||
* @param selector selector
|
||
* @param type 类型 pullDown(下拉) pullUp(上拉)
|
||
* @param callback 回调函数
|
||
*/
|
||
J.Refresh = function(selector,type,callback){
|
||
var el,jRefreshId;
|
||
if(selector.selector){
|
||
el = $(selector.selector)
|
||
}else{
|
||
el = $(selector);
|
||
}
|
||
jRefreshId = el.data('_jrefresh_');
|
||
//因上拉下拉可能会使用的比较频繁,故缓存起来节省开销,亦可防止重复绑定
|
||
if(jRefreshId && refreshCache[jRefreshId]){
|
||
return refreshCache[jRefreshId];
|
||
}else{
|
||
jRefreshId = '_jrefresh_'+index++;
|
||
el.data('_jrefresh_',jRefreshId);
|
||
var refresh = new Refresh(selector,type,callback);
|
||
return refreshCache[jRefreshId] = {
|
||
scroller : refresh.scroller,
|
||
destroy : function(){
|
||
delete refreshCache[jRefreshId];
|
||
refresh.scroller.destroy();
|
||
$('.refresh-container',selector).remove();
|
||
}
|
||
};
|
||
}
|
||
}
|
||
})(J.$); |