weui
Version:
A UI library by WeChat official design team, includes the most useful widgets/modules in mobile web applications.
320 lines (293 loc) • 9.15 kB
JavaScript
/**
* Created by jf on 2015/9/11.
* Modified by bear on 2016/9/7.
*/
const footerTmpl = $('#footerTmpl').html();
$(() => {
const pageManager = {
$container: $('#container'),
_pageStack: [],
_configs: [],
_pageAppend() {},
_defaultPage: null,
_pageIndex: 1,
setDefault(defaultPage) {
this._defaultPage = this._find('name', defaultPage);
return this;
},
setPageAppend(pageAppend) {
this._pageAppend = pageAppend;
return this;
},
init() {
const self = this;
$(window).on('hashchange', () => {
const state = history.state || {};
const url = location.hash.indexOf('#') === 0 ? location.hash : '#';
const page = self._find('url', url) || self._defaultPage;
if (state._pageIndex <= self._pageIndex || self._findInStack(url)) {
self._back(page);
} else {
self._go(page);
}
});
if (history.state && history.state._pageIndex) {
this._pageIndex = history.state._pageIndex;
}
this._pageIndex -= 1;
const url = location.hash.indexOf('#') === 0 ? location.hash : '#';
const page = self._find('url', url) || self._defaultPage;
this._go(page);
return this;
},
push(config) {
this._configs.push(config);
return this;
},
go(to) {
const config = this._find('name', to);
if (!config) {
return;
}
location.hash = config.url;
},
_go(config) {
this._pageIndex += 1;
history.replaceState && history.replaceState({ _pageIndex: this._pageIndex }, '', location.href);
const html = $(config.template).html();
const $html = $(html).addClass('slideIn')
.addClass(config.name);
$html.on('animationend webkitAnimationEnd', () => {
$html.removeClass('slideIn').addClass('js_show');
setPageA11y();
const event = new Event('switched');
window.dispatchEvent(event);
});
this.$container.append($html);
this._pageAppend.call(this, $html);
this._pageStack.push({
config,
dom: $html,
});
if (!config.isBind) {
this._bind(config);
}
return this;
},
back() {
history.back();
},
_back(config) {
this._pageIndex -= 1;
const stack = this._pageStack.pop();
if (!stack) {
return;
}
const url = location.hash.indexOf('#') === 0 ? location.hash : '#';
const found = this._findInStack(url);
if (!found) {
const html = $(config.template).html();
const $html = $(html).addClass('js_show')
.addClass(config.name);
$html.insertBefore(stack.dom);
if (!config.isBind) {
this._bind(config);
}
this._pageStack.push({
config,
dom: $html,
});
}
stack.dom.addClass('slideOut').on('animationend webkitAnimationEnd', () => {
stack.dom.remove();
setPageA11y();
});
return this;
},
_findInStack(url) {
let found = null;
for (let i = 0, len = this._pageStack.length; i < len; i++) {
const stack = this._pageStack[i];
if (stack.config.url === url) {
found = stack;
break;
}
}
return found;
},
_find(key, value) {
let page = null;
for (let i = 0, len = this._configs.length; i < len; i++) {
if (this._configs[i][key] === value) {
page = this._configs[i];
break;
}
}
return page;
},
_bind(page) {
const events = page.events || {};
for (const t in events) {
for (const type in events[t]) {
this.$container.on(type, t, events[t][type]);
}
}
page.isBind = true;
},
};
function fastClick() {
const supportTouch = (function () {
try {
document.createEvent('TouchEvent');
return true;
} catch (e) {
return false;
}
}());
const _old$On = $.fn.on;
$.fn.on = function () {
if (/click/.test(arguments[0]) && typeof arguments[1] === 'function' && supportTouch) { // 只扩展支持touch的当前元素的click事件
let touchStartY; const callback = arguments[1];
_old$On.apply(this, ['touchstart', function (e) {
touchStartY = e.changedTouches[0].clientY;
}]);
_old$On.apply(this, ['touchend', function (e) {
if (Math.abs(e.changedTouches[0].clientY - touchStartY) > 10) return;
e.preventDefault();
callback.apply(this, [e]);
}]);
} else {
_old$On.apply(this, arguments);
}
return this;
};
}
function preload() {
$(window).on('load', () => {
const imgList = [
'./images/layers/content.png',
'./images/layers/navigation.png',
'./images/layers/popout.png',
'./images/layers/transparent.gif',
];
for (let i = 0, len = imgList.length; i < len; ++i) {
new Image().src = imgList[i];
}
});
}
function androidInputBugFix() {
// .container 设置了 overflow 属性, 导致 Android 手机下输入框获取焦点时, 输入法挡住输入框的 bug
// 相关 issue: https://github.com/weui/weui/issues/15
// 解决方法:
// 0. .container 去掉 overflow 属性, 但此 demo 下会引发别的问题
// 1. 参考 http://stackoverflow.com/questions/23757345/android-does-not-correctly-scroll-on-input-focus-if-not-body-element
// Android 手机下, input 或 textarea 元素聚焦时, 主动滚一把
if (/Android/gi.test(navigator.userAgent)) {
window.addEventListener('resize', () => {
if (document.activeElement.tagName == 'INPUT' || document.activeElement.tagName == 'TEXTAREA') {
window.setTimeout(() => {
document.activeElement.scrollIntoViewIfNeeded();
}, 0);
}
});
}
}
function setJSAPI() {
const option = {
title: 'WeUI, 为微信 Web 服务量身设计',
desc: 'WeUI, 为微信 Web 服务量身设计',
link: 'https://weui.io',
imgUrl: 'https://mmbiz.qpic.cn/mmemoticon/ajNVdqHZLLA16apETUPXh9Q5GLpSic7lGuiaic0jqMt4UY8P4KHSBpEWgM7uMlbxxnVR7596b3NPjUfwg7cFbfCtA/0',
};
$.getJSON(`https://weui.io/api/sign?url=${encodeURIComponent(location.href.split('#')[0])}`, (res) => {
wx.config({
beta: true,
debug: false,
appId: res.appid,
timestamp: res.timestamp,
nonceStr: res.nonceStr,
signature: res.signature,
jsApiList: [
'onMenuShareTimeline',
'onMenuShareAppMessage',
'onMenuShareQQ',
'onMenuShareWeibo',
'onMenuShareQZone',
// 'setNavigationBarColor',
'setBounceBackground',
],
});
wx.ready(() => {
/*
wx.invoke('setNavigationBarColor', {
color: '#F8F8F8'
});
*/
wx.invoke('setBounceBackground', {
backgroundColor: '#F8F8F8',
footerBounceColor: '#F8F8F8',
});
wx.onMenuShareTimeline(option);
wx.onMenuShareQQ(option);
wx.onMenuShareAppMessage({
title: 'WeUI',
desc: '为微信 Web 服务量身设计',
link: location.href,
imgUrl: 'https://mmbiz.qpic.cn/mmemoticon/ajNVdqHZLLA16apETUPXh9Q5GLpSic7lGuiaic0jqMt4UY8P4KHSBpEWgM7uMlbxxnVR7596b3NPjUfwg7cFbfCtA/0',
});
});
});
}
function setPageManager() {
const pages = {}; const tpls = $('script[type="text/html"]');
for (let i = 0, len = tpls.length; i < len; ++i) {
const tpl = tpls[i]; const name = tpl.id.replace(/tpl_/, '');
pages[name] = {
name,
url: `#${name}`,
template: `#${tpl.id}`,
};
}
pages.home.url = '#';
for (const page in pages) {
pageManager.push(pages[page]);
}
pageManager
.setPageAppend(($html) => {
$html.eq(0).append(footerTmpl);
setTimeout(() => {
const $foot = $html.find('.page__ft');
if ($foot.length < 1) return;
const winH = $(window).height();
if ($foot.position().top + $foot.height() < winH) {
$foot.addClass('j_bottom');
} else {
$foot.removeClass('j_bottom');
}
});
})
.setDefault('home')
.init();
}
function setPageA11y() {
const $pages = $('.page');
const $lastPage = $pages.eq($pages.length - 1);
$pages.attr('aria-hidden', 'true'); // 所有page都加
$lastPage.removeAttr('aria-hidden').attr('tabindex', '-1')
.trigger('focus'); // 最后一个page不用加
}
function init() {
preload();
fastClick();
androidInputBugFix();
// setJSAPI();
setPageManager();
window.pageManager = pageManager;
window.home = function () {
location.hash = '';
};
var year = new Date().getFullYear();
document.getElementById('js_copyright_year').innerHTML = year;
}
init();
});