You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1527 lines
43 KiB

7 years ago
  1. /**
  2. * User: jeakeyliang
  3. * Date: 14-08-22
  4. * Time: 下午9:20
  5. */
  6. ;(function($){
  7. var data = {}, dataAttr = $.fn.data, camelize = $.camelCase,
  8. exp = $.expando = 'Zepto' + (+new Date()), emptyArray = []
  9. // Get value from node:
  10. // 1. first try key as given,
  11. // 2. then try camelized key,
  12. // 3. fall back to reading "data-*" attribute.
  13. function getData(node, name) {
  14. var id = node[exp], store = id && data[id]
  15. if (name === undefined) return store || setData(node)
  16. else {
  17. if (store) {
  18. if (name in store) return store[name]
  19. var camelName = camelize(name)
  20. if (camelName in store) return store[camelName]
  21. }
  22. return dataAttr.call($(node), name)
  23. }
  24. }
  25. // Store value under camelized key on node
  26. function setData(node, name, value) {
  27. var id = node[exp] || (node[exp] = ++$.uuid),
  28. store = data[id] || (data[id] = attributeData(node))
  29. if (name !== undefined) store[camelize(name)] = value
  30. return store
  31. }
  32. // Read all "data-*" attributes from a node
  33. function attributeData(node) {
  34. var store = {}
  35. $.each(node.attributes || emptyArray, function(i, attr){
  36. if (attr.name.indexOf('data-') == 0)
  37. store[camelize(attr.name.replace('data-', ''))] =
  38. $.zepto.deserializeValue(attr.value)
  39. })
  40. return store
  41. }
  42. $.fn.data = function(name, value) {
  43. return value === undefined ?
  44. // set multiple values via object
  45. $.isPlainObject(name) ?
  46. this.each(function(i, node){
  47. $.each(name, function(key, value){ setData(node, key, value) })
  48. }) :
  49. // get value from first element
  50. (0 in this ? getData(this[0], name) : undefined) :
  51. // set value on all elements
  52. this.each(function(){ setData(this, name, value) })
  53. }
  54. $.fn.removeData = function(names) {
  55. if (typeof names == 'string') names = names.split(/\s+/)
  56. return this.each(function(){
  57. var id = this[exp], store = id && data[id]
  58. if (store) $.each(names || store, function(key){
  59. delete store[names ? camelize(this) : key]
  60. })
  61. })
  62. }
  63. // Generate extended `remove` and `empty` functions
  64. ;['remove', 'empty'].forEach(function(methodName){
  65. var origFn = $.fn[methodName]
  66. $.fn[methodName] = function() {
  67. var elements = this.find('*')
  68. if (methodName === 'remove') elements = elements.add(this)
  69. elements.removeData()
  70. return origFn.call(this)
  71. }
  72. })
  73. })(window.Zepto);
  74. !function ($) {
  75. var _private = {};
  76. _private.cache = {};
  77. $.tpl = function (str, data, env) {
  78. // 判断str参数,如str为script标签的id,则取该标签的innerHTML,再递归调用自身
  79. // 如str为HTML文本,则分析文本并构造渲染函数
  80. var fn = !/[^\w\-\.:]/.test(str)
  81. ? _private.cache[str] = _private.cache[str] || this.get(document.getElementById(str).innerHTML)
  82. : function (data, env) {
  83. var i, variable = [], value = []; // variable数组存放变量名,对应data结构的成员变量;value数组存放各变量的值
  84. for (i in data) {
  85. variable.push(i);
  86. value.push(data[i]);
  87. }
  88. return (new Function(variable, fn.code))
  89. .apply(env || data, value); // 此处的new Function是由下面fn.code产生的渲染函数;执行后即返回渲染结果HTML
  90. };
  91. fn.code = fn.code || "var $parts=[]; $parts.push('"
  92. + str
  93. .replace(/\\/g, '\\\\') // 处理模板中的\转义
  94. .replace(/[\r\t\n]/g, " ") // 去掉换行符和tab符,将模板合并为一行
  95. .split("<%").join("\t") // 将模板左标签<%替换为tab,起到分割作用
  96. .replace(/(^|%>)[^\t]*/g, function(str) { return str.replace(/'/g, "\\'"); }) // 将模板中文本部分的单引号替换为\'
  97. .replace(/\t=(.*?)%>/g, "',$1,'") // 将模板中<%= %>的直接数据引用(无逻辑代码)与两侧的文本用'和,隔开,同时去掉了左标签产生的tab符
  98. .split("\t").join("');") // 将tab符(上面替换左标签产生)替换为'); 由于上一步已经把<%=产生的tab符去掉,因此这里实际替换的只有逻辑代码的左标签
  99. .split("%>").join("$parts.push('") // 把剩下的右标签%>(逻辑代码的)替换为"$parts.push('"
  100. + "'); return $parts.join('');"; // 最后得到的就是一段JS代码,保留模板中的逻辑,并依次把模板中的常量和变量压入$parts数组
  101. return data ? fn(data, env) : fn; // 如果传入了数据,则直接返回渲染结果HTML文本,否则返回一个渲染函数
  102. };
  103. $.adaptObject = function (element, defaults, option,template,plugin,pluginName) {
  104. var $this= element;
  105. if (typeof option != 'string'){
  106. // 获得配置信息
  107. var context=$.extend({}, defaults, typeof option == 'object' && option);
  108. var isFromTpl=false;
  109. // 如果传入script标签的选择器
  110. if($.isArray($this) && $this.length && $($this)[0].nodeName.toLowerCase()=="script"){
  111. // 根据模板获得对象并插入到body中
  112. $this=$($.tpl($this[0].innerHTML,context)).appendTo("body");
  113. isFromTpl=true;
  114. }
  115. // 如果传入模板字符串
  116. else if($.isArray($this) && $this.length && $this.selector== ""){
  117. // 根据模板获得对象并插入到body中
  118. $this=$($.tpl($this[0].outerHTML,context)).appendTo("body");
  119. isFromTpl=true;
  120. }
  121. // 如果通过$.dialog()的方式调用
  122. else if(!$.isArray($this)){
  123. // 根据模板获得对象并插入到body中
  124. $this=$($.tpl(template,context)).appendTo("body");
  125. isFromTpl=true;
  126. }
  127. }
  128. return $this.each(function () {
  129. var el = $(this);
  130. // 读取对象缓存
  131. var data = el.data('fz.'+pluginName);
  132. if (!data) el.data('fz.'+pluginName,
  133. (data = new plugin(this,$.extend({}, defaults, typeof option == 'object' && option),isFromTpl)
  134. ));
  135. if (typeof option == 'string') data[option]();
  136. })
  137. }
  138. }(window.Zepto);
  139. /**
  140. * User: jeakeyliang
  141. * Date: 14-08-22
  142. * Time: 下午9:20
  143. */
  144. !function($){
  145. // 默认模板
  146. var _dialogTpl='<div class="ui-dialog">'+
  147. '<div class="ui-dialog-cnt">'+
  148. '<div class="ui-dialog-bd">'+
  149. '<div>'+
  150. '<h4><%=title%></h4>'+
  151. '<div><%=content%></div></div>'+
  152. '</div>'+
  153. '<div class="ui-dialog-ft ui-btn-group">'+
  154. '<% for (var i = 0; i < button.length; i++) { %>' +
  155. '<% if (i == select) { %>' +
  156. '<button type="button" data-role="button" class="select" id="dialogButton<%=i%>"><%=button[i]%></button>' +
  157. '<% } else { %>' +
  158. '<button type="button" data-role="button" id="dialogButton<%=i%>"><%=button[i]%></div>' +
  159. '<% } %>' +
  160. '<% } %>' +
  161. '</div>'+
  162. '</div>'+
  163. '</div>';
  164. // 默认参数
  165. var defaults={
  166. title:'',
  167. content:'',
  168. button:['确认'],
  169. select:0,
  170. allowScroll:false,
  171. callback:function(){}
  172. }
  173. // 构造函数
  174. var Dialog = function (el,option,isFromTpl) {
  175. this.option=$.extend(defaults,option);
  176. this.element=$(el);
  177. this._isFromTpl=isFromTpl;
  178. this.button=$(el).find('[data-role="button"]');
  179. this._bindEvent();
  180. this.toggle();
  181. }
  182. Dialog.prototype={
  183. _bindEvent:function(){
  184. var self=this;
  185. self.button.on("tap",function(){
  186. var index=$(self.button).index($(this));
  187. // self.option.callback("button",index);
  188. var e=$.Event("dialog:action");
  189. e.index=index;
  190. self.element.trigger(e);
  191. self.hide.apply(self);
  192. });
  193. },
  194. toggle:function(){
  195. if(this.element.hasClass("show")){
  196. this.hide();
  197. }else{
  198. this.show();
  199. }
  200. },
  201. show:function(){
  202. var self=this;
  203. // self.option.callback("show");
  204. self.element.trigger($.Event("dialog:show"));
  205. self.element.addClass("show");
  206. this.option.allowScroll && self.element.on("touchmove" , _stopScroll);
  207. },
  208. hide :function () {
  209. var self=this;
  210. // self.option.callback("hide");
  211. self.element.trigger($.Event("dialog:hide"));
  212. self.element.off("touchmove" , _stopScroll);
  213. self.element.removeClass("show");
  214. self._isFromTpl&&self.element.remove();
  215. }
  216. }
  217. // 禁止冒泡
  218. function _stopScroll(){
  219. return false;
  220. }
  221. function Plugin(option) {
  222. return $.adaptObject(this, defaults, option,_dialogTpl,Dialog,"dialog");
  223. }
  224. $.fn.dialog=$.dialog= Plugin;
  225. }(window.Zepto)
  226. /**
  227. * User: jeakeyliang
  228. * Date: 14-11-07
  229. * Time: 下午9:20
  230. */
  231. !function($){
  232. // 默认模板
  233. var _loadingTpl='<div class="ui-loading-block show">'+
  234. '<div class="ui-loading-cnt">'+
  235. '<i class="ui-loading-bright"></i>'+
  236. '<p><%=content%></p>'+
  237. '</div>'+
  238. '</div>';
  239. // 默认参数
  240. var defaults={
  241. content:'加载中...'
  242. }
  243. // 构造函数
  244. var Loading = function (el,option,isFromTpl) {
  245. var self=this;
  246. this.element=$(el);
  247. this._isFromTpl=isFromTpl;
  248. this.option=$.extend(defaults,option);
  249. this.show();
  250. }
  251. Loading.prototype={
  252. show:function(){
  253. var e=$.Event('loading:show');
  254. this.element.trigger(e);
  255. this.element.show();
  256. },
  257. hide :function () {
  258. var e=$.Event('loading:hide');
  259. this.element.trigger(e);
  260. this.element.remove();
  261. }
  262. }
  263. function Plugin(option) {
  264. return $.adaptObject(this, defaults, option,_loadingTpl,Loading,"loading");
  265. }
  266. $.fn.loading=$.loading= Plugin;
  267. }(window.Zepto)
  268. ;(function ($) {
  269. var rAF = window.requestAnimationFrame ||
  270. window.webkitRequestAnimationFrame ||
  271. window.mozRequestAnimationFrame ||
  272. window.oRequestAnimationFrame ||
  273. window.msRequestAnimationFrame ||
  274. function (callback) { window.setTimeout(callback, 1000 / 60); };
  275. /*
  276. * 工具类
  277. */
  278. var utils = (function () {
  279. var me = {};
  280. var _elementStyle = document.createElement('div').style;
  281. var _vendor = (function () {
  282. var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],
  283. transform,
  284. i = 0,
  285. l = vendors.length;
  286. for ( ; i < l; i++ ) {
  287. transform = vendors[i] + 'ransform';
  288. if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);
  289. }
  290. return false;
  291. })();
  292. function _prefixStyle (style) {
  293. if ( _vendor === false ) return false;
  294. if ( _vendor === '' ) return style;
  295. return _vendor + style.charAt(0).toUpperCase() + style.substr(1);
  296. }
  297. me.getTime = Date.now || function getTime () { return new Date().getTime(); };
  298. me.extend = function (target, obj) {
  299. for ( var i in obj ) {
  300. target[i] = obj[i];
  301. }
  302. };
  303. me.addEvent = function (el, type, fn, capture) {
  304. el.addEventListener(type, fn, !!capture);
  305. };
  306. me.removeEvent = function (el, type, fn, capture) {
  307. el.removeEventListener(type, fn, !!capture);
  308. };
  309. me.prefixPointerEvent = function (pointerEvent) {
  310. return window.MSPointerEvent ?
  311. 'MSPointer' + pointerEvent.charAt(9).toUpperCase() + pointerEvent.substr(10):
  312. pointerEvent;
  313. };
  314. /**
  315. * 根据一定时间内的滑动距离计算出最终停止距离和时间
  316. * @param current当前滑动位置
  317. * @param starttouchStart 时候记录的开始位置但是在touchmove时候可能被重写
  318. * @param timetouchstart 到手指离开时候经历的时间同样可能被touchmove重写
  319. * @param lowerMargin可移动的最大距离这个一般为计算得出 this.wrapperHeight - this.scrollerHeight
  320. * @param wrapperSize如果有边界距离的话就是可拖动不然碰到0的时候便停止
  321. * @param deceleration匀减速
  322. * @returns {{destination: number, duration: number}}
  323. */
  324. me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {
  325. var distance = current - start,
  326. speed = Math.abs(distance) / time,
  327. destination,
  328. duration;
  329. deceleration = deceleration === undefined ? 0.0006 : deceleration;
  330. destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );
  331. duration = speed / deceleration;
  332. if ( destination < lowerMargin ) {
  333. destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;
  334. distance = Math.abs(destination - current);
  335. duration = distance / speed;
  336. } else if ( destination > 0 ) {
  337. destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;
  338. distance = Math.abs(current) + destination;
  339. duration = distance / speed;
  340. }
  341. return {
  342. destination: Math.round(destination),
  343. duration: duration
  344. };
  345. };
  346. var _transform = _prefixStyle('transform');
  347. me.extend(me, {
  348. hasTransform: _transform !== false,
  349. hasPerspective: _prefixStyle('perspective') in _elementStyle,
  350. hasTouch: 'ontouchstart' in window,
  351. hasPointer: window.PointerEvent || window.MSPointerEvent, // IE10 is prefixed
  352. hasTransition: _prefixStyle('transition') in _elementStyle
  353. });
  354. // This should find all Android browsers lower than build 535.19 (both stock browser and webview)
  355. me.isBadAndroid = /Android /.test(window.navigator.appVersion) && !(/Chrome\/\d/.test(window.navigator.appVersion));
  356. me.extend(me.style = {}, {
  357. transform: _transform,
  358. transitionTimingFunction: _prefixStyle('transitionTimingFunction'),
  359. transitionDuration: _prefixStyle('transitionDuration'),
  360. transitionDelay: _prefixStyle('transitionDelay'),
  361. transformOrigin: _prefixStyle('transformOrigin'),
  362. transitionProperty: _prefixStyle('transitionProperty')
  363. });
  364. me.offset = function (el) {
  365. var left = -el.offsetLeft,
  366. top = -el.offsetTop;
  367. while (el = el.offsetParent) {
  368. left -= el.offsetLeft;
  369. top -= el.offsetTop;
  370. }
  371. return {
  372. left: left,
  373. top: top
  374. };
  375. };
  376. /*
  377. * 配合 config 里面的 preventDefaultException 属性
  378. * 不对匹配到的 element 使用 e.preventDefault()
  379. * 默认阻止所有事件的冒泡包括 click tap
  380. */
  381. me.preventDefaultException = function (el, exceptions) {
  382. for ( var i in exceptions ) {
  383. if ( exceptions[i].test(el[i]) ) {
  384. return true;
  385. }
  386. }
  387. return false;
  388. };
  389. me.extend(me.eventType = {}, {
  390. touchstart: 1,
  391. touchmove: 1,
  392. touchend: 1,
  393. mousedown: 2,
  394. mousemove: 2,
  395. mouseup: 2,
  396. pointerdown: 3,
  397. pointermove: 3,
  398. pointerup: 3,
  399. MSPointerDown: 3,
  400. MSPointerMove: 3,
  401. MSPointerUp: 3
  402. });
  403. me.extend(me.ease = {}, {
  404. quadratic: {
  405. style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
  406. fn: function (k) {
  407. return k * ( 2 - k );
  408. }
  409. },
  410. circular: {
  411. style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1)
  412. fn: function (k) {
  413. return Math.sqrt( 1 - ( --k * k ) );
  414. }
  415. },
  416. back: {
  417. style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
  418. fn: function (k) {
  419. var b = 4;
  420. return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;
  421. }
  422. },
  423. bounce: {
  424. style: '',
  425. fn: function (k) {
  426. if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
  427. return 7.5625 * k * k;
  428. } else if ( k < ( 2 / 2.75 ) ) {
  429. return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
  430. } else if ( k < ( 2.5 / 2.75 ) ) {
  431. return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
  432. } else {
  433. return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
  434. }
  435. }
  436. },
  437. elastic: {
  438. style: '',
  439. fn: function (k) {
  440. var f = 0.22,
  441. e = 0.4;
  442. if ( k === 0 ) { return 0; }
  443. if ( k == 1 ) { return 1; }
  444. return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );
  445. }
  446. }
  447. });
  448. me.tap = function (e, eventName) {
  449. var ev = document.createEvent('Event');
  450. ev.initEvent(eventName, true, true);
  451. ev.pageX = e.pageX;
  452. ev.pageY = e.pageY;
  453. e.target.dispatchEvent(ev);
  454. };
  455. me.click = function (e) {
  456. var target = e.target,
  457. ev;
  458. if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {
  459. ev = document.createEvent('MouseEvents');
  460. ev.initMouseEvent('click', true, true, e.view, 1,
  461. target.screenX, target.screenY, target.clientX, target.clientY,
  462. e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
  463. 0, null);
  464. ev._constructed = true;
  465. target.dispatchEvent(ev);
  466. }
  467. };
  468. return me;
  469. })();
  470. /*
  471. * 构造函数
  472. */
  473. function Scroll(el, options) {
  474. this.wrapper = typeof el == 'string' ? $(el)[0] : el;
  475. this.options = {
  476. startX: 0, // 初始化 X 坐标
  477. startY: 0, // 初始化 Y 坐标
  478. scrollY: true, // 竖向滚动
  479. scrollX: false, // 默认非水平
  480. directionLockThreshold: 5, // 确定滚动方向的阈值
  481. momentum: true, // 是否开启惯性滚动
  482. duration: 300, // transition 过渡时间
  483. bounce: true, // 是否有反弹动画
  484. bounceTime: 600, // 反弹动画时间
  485. bounceEasing: '', // 反弹动画类型:'circular'(default), 'quadratic', 'back', 'bounce', 'elastic'
  486. preventDefault: true, // 是否阻止默认滚动事件(和冒泡有区别)
  487. eventPassthrough: true, // 穿透,是否触发原生滑动(取值 true、false、vertical、horizental)
  488. freeScroll: false, // 任意方向的滚动。若 scrollX 和 scrollY 同时开启,则相当于 freeScroll
  489. bindToWrapper : true, // 事件是否绑定到 wrapper 元素上,否则大部分绑定到 window(若存在嵌套,则绑定在元素上最好)
  490. resizePolling : 60, // resize 时候隔 60ms 就执行 refresh 方法重新获取位置信息(事件节流)
  491. disableMouse : false, // 是否禁用鼠标
  492. disableTouch : false, // 是否禁用touch事件
  493. disablePointer : false, // 是否禁用win系统的pointer事件
  494. tap: true, // 是否模拟 tap 事件
  495. click: false, // 是否模拟点击事件(false 则使用原生click事件)
  496. preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ }, // 当遇到正则内的元素则不阻止冒泡
  497. HWCompositing: true, // Hardware acceleration
  498. useTransition: true, // Transition || requestAnimationFrame
  499. useTransform: true // Translate || Left/Top
  500. };
  501. for ( var i in options ) {
  502. this.options[i] = options[i];
  503. }
  504. // scroller
  505. // ==================================
  506. if (!this.options.role && this.options.scrollX === false) {
  507. this.options.eventPassthrough = 'horizontal'; // 竖直滚动的 scroller 不拦截横向原生滚动
  508. }
  509. // slide
  510. // ==================================
  511. if (this.options.role === 'slider') {
  512. this.options.scrollX = true;
  513. this.options.scrollY = false;
  514. this.options.momentum = false;
  515. this.scroller = $('.ui-slider-content')[0];
  516. $(this.scroller.children[0]).addClass('current');
  517. this.currentPage = 0;
  518. this.count = this.scroller.children.length;
  519. this.scroller.style.width = this.count+"00%";
  520. this.itemWidth = this.scroller.children[0].clientWidth;
  521. this.scrollWidth = this.itemWidth * this.count;
  522. if (this.options.indicator) {
  523. var temp = '<ul class="ui-slider-indicators">';
  524. for (var i=1; i<=this.count; i++) {
  525. if (i===1) {
  526. temp += '<li class="current">'+i+'</li>';
  527. }
  528. else {
  529. temp += '<li>'+i+'</li>';
  530. }
  531. }
  532. temp += '</ul>';
  533. $(this.wrapper).append(temp);
  534. this.indicator = $('.ui-slider-indicators')[0];
  535. }
  536. }
  537. // tab
  538. // ==================================
  539. else if (this.options.role === 'tab') {
  540. this.options.scrollX = true;
  541. this.options.scrollY = false;
  542. this.options.momentum = false;
  543. this.scroller = $('.ui-tab-content')[0];
  544. this.nav = $('.ui-tab-nav')[0];
  545. $(this.scroller.children[0]).addClass('current');
  546. $(this.nav.children[0]).addClass('current');
  547. this.currentPage = 0;
  548. this.count = this.scroller.children.length;
  549. this.scroller.style.width = this.count+"00%";
  550. this.itemWidth = this.scroller.children[0].clientWidth;
  551. this.scrollWidth = this.itemWidth * this.count;
  552. }
  553. else {
  554. this.scroller = this.wrapper.children[0];
  555. }
  556. this.scrollerStyle = this.scroller.style;
  557. this.translateZ = utils.hasPerspective && this.options.HWCompositing ? ' translateZ(0)' : '';
  558. this.options.useTransition = utils.hasTransition && this.options.useTransition;
  559. this.options.useTransform = utils.hasTransform && this.options.useTransform;
  560. this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;
  561. this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;
  562. // If you want eventPassthrough I have to lock one of the axes
  563. this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;
  564. this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;
  565. // With eventPassthrough we also need lockDirection mechanism
  566. this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;
  567. this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;
  568. this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;
  569. this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;
  570. if (this.options.tap === true) {
  571. this.options.tap = 'tap';
  572. }
  573. if (this.options.useTransform === false) {
  574. this.scroller.style.position = 'relative';
  575. }
  576. // Some defaults
  577. this.x = 0;
  578. this.y = 0;
  579. this.directionX = 0;
  580. this.directionY = 0;
  581. this._events = {};
  582. this._init(); // 绑定各种事件
  583. this.refresh();
  584. this.scrollTo(this.options.startX, this.options.startY);
  585. this.enable();
  586. // 自动播放
  587. if (this.options.autoplay) {
  588. var context = this;
  589. this.options.interval = this.options.interval || 2000;
  590. this.options.flag = setTimeout(function(){
  591. context._autoplay.apply(context)
  592. }, context.options.interval);
  593. }
  594. }
  595. Scroll.prototype = {
  596. _init: function () {
  597. this._initEvents();
  598. },
  599. _initEvents: function (remove) {
  600. var eventType = remove ? utils.removeEvent : utils.addEvent,
  601. target = this.options.bindToWrapper ? this.wrapper : window;
  602. /*
  603. * addEventListener 传递 this
  604. * 程序会自动找到 handleEvent 方法作为回调函数
  605. */
  606. eventType(window, 'orientationchange', this);
  607. eventType(window, 'resize', this);
  608. if ( this.options.click ) {
  609. eventType(this.wrapper, 'click', this, true);
  610. }
  611. if ( !this.options.disableMouse ) {
  612. eventType(this.wrapper, 'mousedown', this);
  613. eventType(target, 'mousemove', this);
  614. eventType(target, 'mousecancel', this);
  615. eventType(target, 'mouseup', this);
  616. }
  617. if ( utils.hasPointer && !this.options.disablePointer ) {
  618. eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);
  619. eventType(target, utils.prefixPointerEvent('pointermove'), this);
  620. eventType(target, utils.prefixPointerEvent('pointercancel'), this);
  621. eventType(target, utils.prefixPointerEvent('pointerup'), this);
  622. }
  623. if ( utils.hasTouch && !this.options.disableTouch ) {
  624. eventType(this.wrapper, 'touchstart', this);
  625. eventType(target, 'touchmove', this);
  626. eventType(target, 'touchcancel', this);
  627. eventType(target, 'touchend', this);
  628. }
  629. eventType(this.scroller, 'transitionend', this);
  630. eventType(this.scroller, 'webkitTransitionEnd', this);
  631. eventType(this.scroller, 'oTransitionEnd', this);
  632. eventType(this.scroller, 'MSTransitionEnd', this);
  633. // tab
  634. // =============================
  635. if (this.options.role === 'tab') {
  636. eventType(this.nav, 'touchend', this);
  637. eventType(this.nav, 'mouseup', this);
  638. eventType(this.nav, 'pointerup', this);
  639. }
  640. },
  641. refresh: function () {
  642. var rf = this.wrapper.offsetHeight; // Force reflow
  643. // http://jsfiddle.net/y8Y32/25/
  644. // clientWidth = content + padding
  645. this.wrapperWidth = this.wrapper.clientWidth;
  646. this.wrapperHeight = this.wrapper.clientHeight;
  647. // 添加 wrapper 的 padding 值到 scroller 身上,更符合使用预期
  648. var matrix = window.getComputedStyle(this.wrapper, null);
  649. var pt = matrix['padding-top'].replace(/[^-\d.]/g, ''),
  650. pb = matrix['padding-bottom'].replace(/[^-\d.]/g, ''),
  651. pl = matrix['padding-left'].replace(/[^-\d.]/g, ''),
  652. pr = matrix['padding-right'].replace(/[^-\d.]/g, '');
  653. var matrix2 = window.getComputedStyle(this.scroller, null);
  654. var mt2 = matrix2['margin-top'].replace(/[^-\d.]/g, ''),
  655. mb2 = matrix2['margin-bottom'].replace(/[^-\d.]/g, ''),
  656. ml2 = matrix2['margin-left'].replace(/[^-\d.]/g, ''),
  657. mr2 = matrix2['margin-right'].replace(/[^-\d.]/g, '');
  658. // offsetWidth = content + padding + border
  659. this.scrollerWidth = this.scroller.offsetWidth+parseInt(pl)+parseInt(pr)+parseInt(ml2)+parseInt(mr2);
  660. this.scrollerHeight = this.scroller.offsetHeight+parseInt(pt)+parseInt(pb)+parseInt(mt2)+parseInt(mb2);
  661. // slide
  662. // ==================================
  663. if (this.options.role === 'slider' || this.options.role === 'tab') {
  664. this.itemWidth = this.scroller.children[0].clientWidth;
  665. this.scrollWidth = this.itemWidth * this.count;
  666. this.scrollerWidth = this.scrollWidth;
  667. }
  668. this.maxScrollX = this.wrapperWidth - this.scrollerWidth;
  669. this.maxScrollY = this.wrapperHeight - this.scrollerHeight;
  670. this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0;
  671. this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0;
  672. if ( !this.hasHorizontalScroll ) {
  673. this.maxScrollX = 0;
  674. this.scrollerWidth = this.wrapperWidth;
  675. }
  676. if ( !this.hasVerticalScroll ) {
  677. this.maxScrollY = 0;
  678. this.scrollerHeight = this.wrapperHeight;
  679. }
  680. this.endTime = 0;
  681. this.directionX = 0;
  682. this.directionY = 0;
  683. this.wrapperOffset = utils.offset(this.wrapper);
  684. this.resetPosition();
  685. },
  686. handleEvent: function (e) {
  687. switch ( e.type ) {
  688. case 'touchstart':
  689. case 'pointerdown':
  690. case 'MSPointerDown':
  691. case 'mousedown':
  692. this._start(e);
  693. break;
  694. case 'touchmove':
  695. case 'pointermove':
  696. case 'MSPointerMove':
  697. case 'mousemove':
  698. this._move(e);
  699. break;
  700. case 'touchend':
  701. case 'pointerup':
  702. case 'MSPointerUp':
  703. case 'mouseup':
  704. case 'touchcancel':
  705. case 'pointercancel':
  706. case 'MSPointerCancel':
  707. case 'mousecancel':
  708. this._end(e);
  709. break;
  710. case 'orientationchange':
  711. case 'resize':
  712. this._resize();
  713. break;
  714. case 'transitionend':
  715. case 'webkitTransitionEnd':
  716. case 'oTransitionEnd':
  717. case 'MSTransitionEnd':
  718. this._transitionEnd(e);
  719. break;
  720. case 'wheel':
  721. case 'DOMMouseScroll':
  722. case 'mousewheel':
  723. this._wheel(e);
  724. break;
  725. case 'keydown':
  726. this._key(e);
  727. break;
  728. case 'click':
  729. if ( !e._constructed ) {
  730. e.preventDefault();
  731. e.stopPropagation();
  732. }
  733. break;
  734. }
  735. },
  736. _start: function (e) {
  737. if ( utils.eventType[e.type] != 1 ) { // 如果是鼠标点击,则只响应鼠标左键
  738. if ( e.button !== 0 ) {
  739. return;
  740. }
  741. }
  742. if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {
  743. return;
  744. }
  745. // 如果 preventDefault === true 且 不是落后的安卓版本 且 不是需要过滤的 target 就阻止默认的行为
  746. if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
  747. e.preventDefault();
  748. }
  749. var point = e.touches ? e.touches[0] : e, // 检验是触摸事件对象还是鼠标事件对象
  750. pos;
  751. this.initiated = utils.eventType[e.type]; // 初始化事件类型(1:触摸,2:鼠标,3:pointer)
  752. this.moved = false;
  753. this.distX = 0;
  754. this.distY = 0;
  755. this.directionX = 0;
  756. this.directionY = 0;
  757. this.directionLocked = 0;
  758. this._transitionTime();
  759. this.startTime = utils.getTime();
  760. // 定住正在滑动的 scroller,slider/tab 不这么做
  761. if ( this.options.useTransition && this.isInTransition && this.options.role !== 'slider' && this.options.role !== 'tab') {
  762. this.isInTransition = false;
  763. pos = this.getComputedPosition();
  764. this._translate(Math.round(pos.x), Math.round(pos.y));
  765. }
  766. // 场景:(没有使用 Transition 属性)
  767. else if ( !this.options.useTransition && this.isAnimating ) {
  768. this.isAnimating = false;
  769. }
  770. this.startX = this.x;
  771. this.startY = this.y;
  772. this.absStartX = this.x;
  773. this.absStartY = this.y;
  774. this.pointX = point.pageX;
  775. this.pointY = point.pageY;
  776. // throttle
  777. // ======================
  778. if (this.options.autoplay) {
  779. var context = this;
  780. clearTimeout(this.options.flag);
  781. this.options.flag = setTimeout(function() {
  782. context._autoplay.apply(context);
  783. }, context.options.interval);
  784. }
  785. event.stopPropagation();
  786. },
  787. _move: function (e) {
  788. if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { // 如果事件类型和 touchstart 初始化的事件类型不一致,退出
  789. return;
  790. }
  791. if ( this.options.preventDefault ) { // 这么做才能确保 Android 下 touchend 能被正常触发(需测试)
  792. e.preventDefault();
  793. }
  794. var point = e.touches ? e.touches[0] : e,
  795. deltaX = point.pageX - this.pointX,
  796. deltaY = point.pageY - this.pointY,
  797. timestamp = utils.getTime(),
  798. newX, newY,
  799. absDistX, absDistY;
  800. this.pointX = point.pageX;
  801. this.pointY = point.pageY;
  802. this.distX += deltaX;
  803. this.distY += deltaY;
  804. absDistX = Math.abs(this.distX);
  805. absDistY = Math.abs(this.distY);
  806. // 如果在很长的时间内只移动了少于 10 像素的距离,那么不会触发惯性滚动
  807. if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {
  808. return;
  809. }
  810. // 屏蔽滚动方向的另外一个方向(可配置)
  811. if ( !this.directionLocked && !this.options.freeScroll ) {
  812. if ( absDistX > absDistY + this.options.directionLockThreshold ) {
  813. this.directionLocked = 'h'; // lock horizontally
  814. } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {
  815. this.directionLocked = 'v'; // lock vertically
  816. } else {
  817. this.directionLocked = 'n'; // no lock
  818. }
  819. }
  820. if ( this.directionLocked == 'h' ) {
  821. // slider/tab 外层高度自适应
  822. if (this.options.role === 'tab') {
  823. $(this.scroller).children('li').height('auto');
  824. }
  825. if ( this.options.eventPassthrough == 'vertical' ) {
  826. e.preventDefault();
  827. } else if ( this.options.eventPassthrough == 'horizontal' ) {
  828. this.initiated = false;
  829. return;
  830. }
  831. deltaY = 0; // 不断重置垂直偏移量为 0
  832. }
  833. else if ( this.directionLocked == 'v' ) {
  834. if ( this.options.eventPassthrough == 'horizontal' ) {
  835. e.preventDefault();
  836. } else if ( this.options.eventPassthrough == 'vertical' ) {
  837. this.initiated = false;
  838. return;
  839. }
  840. deltaX = 0; // 不断重置水平偏移量为 0
  841. }
  842. deltaX = this.hasHorizontalScroll ? deltaX : 0;
  843. deltaY = this.hasVerticalScroll ? deltaY : 0;
  844. newX = this.x + deltaX;
  845. newY = this.y + deltaY;
  846. // Slow down if outside of the boundaries
  847. if ( newX > 0 || newX < this.maxScrollX ) {
  848. newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;
  849. }
  850. if ( newY > 0 || newY < this.maxScrollY ) {
  851. newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;
  852. }
  853. this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
  854. this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
  855. this.moved = true; // 滚动开始
  856. this._translate(newX, newY);
  857. if ( timestamp - this.startTime > 300 ) { // 每 300 毫秒重置一次初始值
  858. this.startTime = timestamp;
  859. this.startX = this.x;
  860. this.startY = this.y;
  861. }
  862. },
  863. _end: function (e) {
  864. if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {
  865. return;
  866. }
  867. if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {
  868. e.preventDefault();
  869. }
  870. var point = e.changedTouches ? e.changedTouches[0] : e, // 移开屏幕的那个触摸点,只会包含在 changedTouches 列表中,而不会包含在 touches 或 targetTouches 列表中
  871. momentumX,
  872. momentumY,
  873. duration = utils.getTime() - this.startTime,
  874. newX = Math.round(this.x),
  875. newY = Math.round(this.y),
  876. distanceX = Math.abs(newX - this.startX),
  877. distanceY = Math.abs(newY - this.startY),
  878. time = 0,
  879. easing = '';
  880. this.isInTransition = 0;
  881. this.initiated = 0;
  882. this.endTime = utils.getTime();
  883. if ( this.resetPosition(this.options.bounceTime) ) { // reset if we are outside of the boundaries
  884. if (this.options.role === 'tab') {
  885. $(this.scroller.children[this.currentPage]).siblings('li').height(0);
  886. }
  887. return;
  888. }
  889. this.scrollTo(newX, newY); // ensures that the last position is rounded
  890. if (!this.moved) { // we scrolled less than 10 pixels
  891. if (this.options.tap && utils.eventType[e.type] === 1) {
  892. utils.tap(e, this.options.tap);
  893. }
  894. if ( this.options.click) {
  895. utils.click(e);
  896. }
  897. }
  898. // 300ms 内的滑动要启动惯性滚动
  899. if ( this.options.momentum && duration < 300 ) {
  900. momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { destination: newX, duration: 0 };
  901. momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 };
  902. newX = momentumX.destination;
  903. newY = momentumY.destination;
  904. time = Math.max(momentumX.duration, momentumY.duration);
  905. this.isInTransition = 1;
  906. }
  907. if ( newX != this.x || newY != this.y ) {
  908. // change easing function when scroller goes out of the boundaries
  909. if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {
  910. easing = utils.ease.quadratic;
  911. }
  912. this.scrollTo(newX, newY, time, easing);
  913. return;
  914. }
  915. // tab
  916. // ==========================
  917. if (this.options.role === 'tab' && $(event.target).closest('ul').hasClass('ui-tab-nav')) {
  918. $(this.nav).children().removeClass('current');
  919. $(event.target).addClass('current');
  920. var tempCurrentPage = this.currentPage;
  921. this.currentPage = $(event.target).index();
  922. $(this.scroller).children().height('auto'); // tab 外层高度自适应
  923. this._execEvent('beforeScrollStart', tempCurrentPage, this.currentPage);
  924. }
  925. // slider & tab
  926. // ==============================
  927. if (this.options.role === 'slider' || this.options.role === 'tab') {
  928. if (distanceX < 30) {
  929. this.scrollTo(-this.itemWidth*this.currentPage, 0, this.options.bounceTime, this.options.bounceEasing);
  930. }
  931. else if (newX-this.startX<0) { // 向前
  932. this._execEvent('beforeScrollStart', this.currentPage, this.currentPage+1);
  933. this.scrollTo(-this.itemWidth*++this.currentPage, 0, this.options.bounceTime, this.options.bounceEasing);
  934. }
  935. else if (newX-this.startX>=0) { // 向后
  936. this._execEvent('beforeScrollStart', this.currentPage, this.currentPage-1);
  937. this.scrollTo(-this.itemWidth*--this.currentPage, 0, this.options.bounceTime, this.options.bounceEasing);
  938. }
  939. // tab 外层高度自适应
  940. if (this.options.role === 'tab') {
  941. $(this.scroller.children[this.currentPage]).siblings('li').height(0);
  942. }
  943. if (this.indicator && distanceX >= 30) {
  944. $(this.indicator).children().removeClass('current');
  945. $(this.indicator.children[this.currentPage]).addClass('current');
  946. }
  947. else if (this.nav && distanceX >= 30) {
  948. $(this.nav).children().removeClass('current');
  949. $(this.nav.children[this.currentPage]).addClass('current');
  950. }
  951. $(this.scroller).children().removeClass('current');
  952. $(this.scroller.children[this.currentPage]).addClass('current');
  953. }
  954. },
  955. _resize: function () {
  956. var that = this;
  957. clearTimeout(this.resizeTimeout);
  958. this.resizeTimeout = setTimeout(function () {
  959. that.refresh();
  960. }, this.options.resizePolling);
  961. },
  962. _transitionEnd: function (e) {
  963. if ( e.target != this.scroller || !this.isInTransition ) {
  964. return;
  965. }
  966. this._transitionTime();
  967. if ( !this.resetPosition(this.options.bounceTime) ) {
  968. this.isInTransition = false;
  969. this._execEvent('scrollEnd', this.currentPage);
  970. }
  971. },
  972. destroy: function () {
  973. this._initEvents(true); // 去除事件绑定
  974. },
  975. resetPosition: function (time) {
  976. var x = this.x,
  977. y = this.y;
  978. time = time || 0;
  979. if ( !this.hasHorizontalScroll || this.x > 0 ) {
  980. x = 0;
  981. } else if ( this.x < this.maxScrollX ) {
  982. x = this.maxScrollX;
  983. }
  984. if ( !this.hasVerticalScroll || this.y > 0 ) {
  985. y = 0;
  986. } else if ( this.y < this.maxScrollY ) {
  987. y = this.maxScrollY;
  988. }
  989. if ( x == this.x && y == this.y ) {
  990. return false;
  991. }
  992. this.scrollTo(x, y, time, this.options.bounceEasing);
  993. return true;
  994. },
  995. disable: function () {
  996. this.enabled = false;
  997. },
  998. enable: function () {
  999. this.enabled = true;
  1000. },
  1001. on: function (type, fn) {
  1002. if ( !this._events[type] ) {
  1003. this._events[type] = [];
  1004. }
  1005. this._events[type].push(fn);
  1006. },
  1007. off: function (type, fn) {
  1008. if ( !this._events[type] ) {
  1009. return;
  1010. }
  1011. var index = this._events[type].indexOf(fn);
  1012. if ( index > -1 ) {
  1013. this._events[type].splice(index, 1);
  1014. }
  1015. },
  1016. _execEvent: function (type) {
  1017. if ( !this._events[type] ) {
  1018. return;
  1019. }
  1020. var i = 0,
  1021. l = this._events[type].length;
  1022. if ( !l ) {
  1023. return;
  1024. }
  1025. for ( ; i < l; i++ ) {
  1026. this._events[type][i].apply(this, [].slice.call(arguments, 1));
  1027. }
  1028. },
  1029. scrollTo: function (x, y, time, easing) {
  1030. easing = easing || utils.ease.circular;
  1031. this.isInTransition = this.options.useTransition && time > 0;
  1032. if ( !time || (this.options.useTransition && easing.style) ) {
  1033. if (this.options.role === 'slider' || this.options.role === 'tab') { // 不添加判断会影响 left/top 的过渡
  1034. time = this.options.duration;
  1035. this.scrollerStyle[utils.style.transitionProperty] = utils.style.transform;
  1036. }
  1037. this.scrollerStyle[utils.style.transitionTimingFunction] = easing.style;
  1038. this._transitionTime(time);
  1039. this._translate(x, y);
  1040. } else {
  1041. this._animate(x, y, time, easing.fn);
  1042. }
  1043. },
  1044. scrollToElement: function (el, time, offsetX, offsetY, easing) {
  1045. el = el.nodeType ? el : this.scroller.querySelector(el);
  1046. if ( !el ) {
  1047. return;
  1048. }
  1049. var pos = utils.offset(el);
  1050. pos.left -= this.wrapperOffset.left;
  1051. pos.top -= this.wrapperOffset.top;
  1052. // if offsetX/Y are true we center the element to the screen
  1053. // 若 offsetX/Y 都是 true,则会滚动到元素在屏幕中间的位置
  1054. if ( offsetX === true ) {
  1055. offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);
  1056. }
  1057. if ( offsetY === true ) {
  1058. offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);
  1059. }
  1060. pos.left -= offsetX || 0;
  1061. pos.top -= offsetY || 0;
  1062. pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;
  1063. pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top;
  1064. time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;
  1065. this.scrollTo(pos.left, pos.top, time, easing);
  1066. },
  1067. _transitionTime: function (time) {
  1068. time = time || 0;
  1069. this.scrollerStyle[utils.style.transitionDuration] = time + 'ms';
  1070. if ( !time && utils.isBadAndroid ) {
  1071. this.scrollerStyle[utils.style.transitionDuration] = '0.001s';
  1072. }
  1073. },
  1074. _translate: function (x, y) {
  1075. if ( this.options.useTransform ) {
  1076. this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;
  1077. } else {
  1078. x = Math.round(x);
  1079. y = Math.round(y);
  1080. this.scrollerStyle.left = x + 'px';
  1081. this.scrollerStyle.top = y + 'px';
  1082. }
  1083. this.x = x;
  1084. this.y = y;
  1085. },
  1086. getComputedPosition: function () {
  1087. var matrix = window.getComputedStyle(this.scroller, null),
  1088. x, y;
  1089. if ( this.options.useTransform ) {
  1090. matrix = matrix[utils.style.transform].split(')')[0].split(', ');
  1091. x = +(matrix[12] || matrix[4]);
  1092. y = +(matrix[13] || matrix[5]);
  1093. } else {
  1094. x = +matrix.left.replace(/[^-\d.]/g, '');
  1095. y = +matrix.top.replace(/[^-\d.]/g, '');
  1096. }
  1097. return { x: x, y: y };
  1098. },
  1099. _animate: function (destX, destY, duration, easingFn) { // 当浏览器不支持 transition 时提供的退化方案 requestAnimationFrame
  1100. var that = this,
  1101. startX = this.x,
  1102. startY = this.y,
  1103. startTime = utils.getTime(),
  1104. destTime = startTime + duration;
  1105. function step () {
  1106. var now = utils.getTime(),
  1107. newX, newY,
  1108. easing;
  1109. if ( now >= destTime ) {
  1110. that.isAnimating = false;
  1111. that._translate(destX, destY);
  1112. if ( !that.resetPosition(that.options.bounceTime) ) {
  1113. that._execEvent('scrollEnd', this.currentPage);
  1114. }
  1115. return;
  1116. }
  1117. now = ( now - startTime ) / duration;
  1118. easing = easingFn(now);
  1119. newX = ( destX - startX ) * easing + startX;
  1120. newY = ( destY - startY ) * easing + startY;
  1121. that._translate(newX, newY);
  1122. if ( that.isAnimating ) {
  1123. rAF(step);
  1124. }
  1125. }
  1126. this.isAnimating = true;
  1127. step();
  1128. },
  1129. _autoplay: function() {
  1130. var self = this,
  1131. curPage = self.currentPage;
  1132. self.currentPage = self.currentPage >= self.count-1 ? 0 : ++self.currentPage;
  1133. self._execEvent('beforeScrollStart', curPage, self.currentPage); // 对于自动播放的 slider/tab,这个时机就是 beforeScrollStart
  1134. // tab 外层高度自适应
  1135. if (this.options.role === 'tab') {
  1136. $(this.scroller).children().height('auto');
  1137. document.body.scrollTop = 0;
  1138. }
  1139. self.scrollTo(-self.itemWidth*self.currentPage, 0, self.options.bounceTime, self.options.bounceEasing);
  1140. if (self.indicator) {
  1141. $(self.indicator).children().removeClass('current');
  1142. $(self.indicator.children[self.currentPage]).addClass('current');
  1143. $(self.scroller).children().removeClass('current');
  1144. $(self.scroller.children[self.currentPage]).addClass('current');
  1145. }
  1146. else if (self.nav) {
  1147. $(self.nav).children().removeClass('current');
  1148. $(self.nav.children[self.currentPage]).addClass('current');
  1149. $(self.scroller).children().removeClass('current');
  1150. $(self.scroller.children[self.currentPage]).addClass('current');
  1151. }
  1152. self.options.flag = setTimeout(function() {
  1153. self._autoplay.apply(self);
  1154. }, self.options.interval);
  1155. }
  1156. };
  1157. // Scroll.utils = utils;
  1158. window.fz = window.fz || {};
  1159. window.frozen = window.frozen || {};
  1160. window.fz.Scroll = window.frozen.Scroll = Scroll;
  1161. /*
  1162. * 兼容 RequireJS Sea.js
  1163. */
  1164. if (typeof define === "function") {
  1165. define(function(require, exports, module) {
  1166. module.exports = Scroll;
  1167. })
  1168. }
  1169. })(window.Zepto);
  1170. /**
  1171. * User: jeakeyliang
  1172. * Date: 14-11-07
  1173. * Time: 下午9:20
  1174. */
  1175. !function($){
  1176. // 默认模板
  1177. var _tipsTpl='<div class="ui-poptips ui-poptips-<%=type%>">'+
  1178. '<div class="ui-poptips-cnt">'+
  1179. '<i></i><%=content%>'+
  1180. '</div>'+
  1181. '</div>';
  1182. // 默认参数
  1183. var defaults={
  1184. content:'',
  1185. stayTime:1000,
  1186. type:'info',
  1187. callback:function(){}
  1188. }
  1189. // 构造函数
  1190. var Tips = function (el,option,isFromTpl) {
  1191. var self=this;
  1192. this.element=$(el);
  1193. this._isFromTpl=isFromTpl;
  1194. this.elementHeight=$(el).height();
  1195. this.option=$.extend(defaults,option);
  1196. $(el).css({
  1197. "-webkit-transform":"translateY(-"+this.elementHeight+"px)"
  1198. });
  1199. setTimeout(function(){
  1200. $(el).css({
  1201. "-webkit-transition":"all .5s"
  1202. });
  1203. self.show();
  1204. },20);
  1205. }
  1206. Tips.prototype={
  1207. show:function(){
  1208. var self=this;
  1209. // self.option.callback("show");
  1210. self.element.trigger($.Event("tips:show"));
  1211. this.element.css({
  1212. "-webkit-transform":"translateY(0px)"
  1213. });
  1214. if(self.option.stayTime>0){
  1215. setTimeout(function(){
  1216. self.hide();
  1217. },self.option.stayTime)
  1218. }
  1219. },
  1220. hide :function () {
  1221. var self=this;
  1222. self.element.trigger($.Event("tips:hide"));
  1223. this.element.css({
  1224. "-webkit-transform":"translateY(-"+this.elementHeight+"px)"
  1225. });
  1226. setTimeout(function(){
  1227. self._isFromTpl&&self.element.remove();
  1228. },500)
  1229. }
  1230. }
  1231. function Plugin(option) {
  1232. return $.adaptObject(this, defaults, option,_tipsTpl,Tips,"tips");
  1233. }
  1234. $.fn.tips=$.tips= Plugin;
  1235. }(window.Zepto)