example.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. /**
  2. * Created by jf on 2015/9/11.
  3. * Modified by bear on 2016/9/7.
  4. */
  5. $(function () {
  6. var pageManager = {
  7. $container: $('#container'),
  8. _pageStack: [],
  9. _configs: [],
  10. _pageAppend: function(){},
  11. _defaultPage: null,
  12. _pageIndex: 1,
  13. setDefault: function (defaultPage) {
  14. this._defaultPage = this._find('name', defaultPage);
  15. return this;
  16. },
  17. setPageAppend: function (pageAppend) {
  18. this._pageAppend = pageAppend;
  19. return this;
  20. },
  21. init: function () {
  22. var self = this;
  23. $(window).on('hashchange', function () {
  24. var state = history.state || {};
  25. var url = location.hash.indexOf('#') === 0 ? location.hash : '#';
  26. var page = self._find('url', url) || self._defaultPage;
  27. if (state._pageIndex <= self._pageIndex || self._findInStack(url)) {
  28. self._back(page);
  29. } else {
  30. self._go(page);
  31. }
  32. });
  33. if (history.state && history.state._pageIndex) {
  34. this._pageIndex = history.state._pageIndex;
  35. }
  36. this._pageIndex--;
  37. var url = location.hash.indexOf('#') === 0 ? location.hash : '#';
  38. var page = self._find('url', url) || self._defaultPage;
  39. this._go(page);
  40. return this;
  41. },
  42. push: function (config) {
  43. this._configs.push(config);
  44. return this;
  45. },
  46. go: function (to) {
  47. var config = this._find('name', to);
  48. if (!config) {
  49. return;
  50. }
  51. location.hash = config.url;
  52. },
  53. _go: function (config) {
  54. this._pageIndex ++;
  55. history.replaceState && history.replaceState({_pageIndex: this._pageIndex}, '', location.href);
  56. var html = $(config.template).html();
  57. var $html = $(html).addClass('slideIn').addClass(config.name);
  58. $html.on('animationend webkitAnimationEnd', function(){
  59. $html.removeClass('slideIn').addClass('js_show');
  60. });
  61. this.$container.append($html);
  62. this._pageAppend.call(this, $html);
  63. this._pageStack.push({
  64. config: config,
  65. dom: $html
  66. });
  67. if (!config.isBind) {
  68. this._bind(config);
  69. }
  70. return this;
  71. },
  72. back: function () {
  73. history.back();
  74. },
  75. _back: function (config) {
  76. this._pageIndex --;
  77. var stack = this._pageStack.pop();
  78. if (!stack) {
  79. return;
  80. }
  81. var url = location.hash.indexOf('#') === 0 ? location.hash : '#';
  82. var found = this._findInStack(url);
  83. if (!found) {
  84. var html = $(config.template).html();
  85. var $html = $(html).addClass('js_show').addClass(config.name);
  86. $html.insertBefore(stack.dom);
  87. if (!config.isBind) {
  88. this._bind(config);
  89. }
  90. this._pageStack.push({
  91. config: config,
  92. dom: $html
  93. });
  94. }
  95. stack.dom.addClass('slideOut').on('animationend webkitAnimationEnd', function () {
  96. stack.dom.remove();
  97. });
  98. return this;
  99. },
  100. _findInStack: function (url) {
  101. var found = null;
  102. for(var i = 0, len = this._pageStack.length; i < len; i++){
  103. var stack = this._pageStack[i];
  104. if (stack.config.url === url) {
  105. found = stack;
  106. break;
  107. }
  108. }
  109. return found;
  110. },
  111. _find: function (key, value) {
  112. var page = null;
  113. for (var i = 0, len = this._configs.length; i < len; i++) {
  114. if (this._configs[i][key] === value) {
  115. page = this._configs[i];
  116. break;
  117. }
  118. }
  119. return page;
  120. },
  121. _bind: function (page) {
  122. var events = page.events || {};
  123. for (var t in events) {
  124. for (var type in events[t]) {
  125. this.$container.on(type, t, events[t][type]);
  126. }
  127. }
  128. page.isBind = true;
  129. }
  130. };
  131. function fastClick(){
  132. var supportTouch = function(){
  133. try {
  134. document.createEvent("TouchEvent");
  135. return true;
  136. } catch (e) {
  137. return false;
  138. }
  139. }();
  140. var _old$On = $.fn.on;
  141. $.fn.on = function(){
  142. if(/click/.test(arguments[0]) && typeof arguments[1] == 'function' && supportTouch){ // 只扩展支持touch的当前元素的click事件
  143. var touchStartY, callback = arguments[1];
  144. _old$On.apply(this, ['touchstart', function(e){
  145. touchStartY = e.changedTouches[0].clientY;
  146. }]);
  147. _old$On.apply(this, ['touchend', function(e){
  148. if (Math.abs(e.changedTouches[0].clientY - touchStartY) > 10) return;
  149. e.preventDefault();
  150. callback.apply(this, [e]);
  151. }]);
  152. }else{
  153. _old$On.apply(this, arguments);
  154. }
  155. return this;
  156. };
  157. }
  158. function preload(){
  159. $(window).on("load", function(){
  160. var imgList = [
  161. "./images/layers/content.png",
  162. "./images/layers/navigation.png",
  163. "./images/layers/popout.png",
  164. "./images/layers/transparent.gif"
  165. ];
  166. for (var i = 0, len = imgList.length; i < len; ++i) {
  167. new Image().src = imgList[i];
  168. }
  169. });
  170. }
  171. function androidInputBugFix(){
  172. // .container 设置了 overflow 属性, 导致 Android 手机下输入框获取焦点时, 输入法挡住输入框的 bug
  173. // 相关 issue: https://github.com/weui/weui/issues/15
  174. // 解决方法:
  175. // 0. .container 去掉 overflow 属性, 但此 demo 下会引发别的问题
  176. // 1. 参考 http://stackoverflow.com/questions/23757345/android-does-not-correctly-scroll-on-input-focus-if-not-body-element
  177. // Android 手机下, input 或 textarea 元素聚焦时, 主动滚一把
  178. if (/Android/gi.test(navigator.userAgent)) {
  179. window.addEventListener('resize', function () {
  180. if (document.activeElement.tagName == 'INPUT' || document.activeElement.tagName == 'TEXTAREA') {
  181. window.setTimeout(function () {
  182. document.activeElement.scrollIntoViewIfNeeded();
  183. }, 0);
  184. }
  185. })
  186. }
  187. }
  188. function setPageManager(){
  189. var pages = {}, tpls = $('script[type="text/html"]');
  190. var winH = $(window).height();
  191. for (var i = 0, len = tpls.length; i < len; ++i) {
  192. var tpl = tpls[i], name = tpl.id.replace(/tpl_/, '');
  193. pages[name] = {
  194. name: name,
  195. url: '#' + name,
  196. template: '#' + tpl.id
  197. };
  198. }
  199. pages.home.url = '#';
  200. for (var page in pages) {
  201. pageManager.push(pages[page]);
  202. }
  203. pageManager
  204. .setPageAppend(function($html){
  205. var $foot = $html.find('.page__ft');
  206. if($foot.length < 1) return;
  207. if($foot.position().top + $foot.height() < winH){
  208. $foot.addClass('j_bottom');
  209. }else{
  210. $foot.removeClass('j_bottom');
  211. }
  212. })
  213. .setDefault('home')
  214. .init();
  215. }
  216. function init(){
  217. preload();
  218. fastClick();
  219. androidInputBugFix();
  220. setPageManager();
  221. window.pageManager = pageManager;
  222. window.home = function(){
  223. location.hash = '';
  224. };
  225. }
  226. init();
  227. });