@morjs/runtime-web
Version:
mor runtime for web
363 lines (360 loc) • 14.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const lit_element_1 = require("lit-element");
const lodash_get_1 = tslib_1.__importDefault(require("lodash.get"));
const rpx_1 = require("../rpx");
const utils_1 = require("../utils");
const bool_converter_1 = tslib_1.__importDefault(require("../utils/bool-converter"));
const index_1 = require("../utils/index");
const IPage_1 = require("./IPage");
const defaultTitleBarHeight = (0, rpx_1.rpxToRem)(88);
const defaultStatusBarHeight = 0;
var PullRefreshState;
(function (PullRefreshState) {
PullRefreshState[PullRefreshState["Normal"] = 0] = "Normal";
PullRefreshState[PullRefreshState["Pulling"] = 1] = "Pulling";
PullRefreshState[PullRefreshState["WillRefresh"] = 2] = "WillRefresh";
PullRefreshState[PullRefreshState["Refreshing"] = 3] = "Refreshing"; // 正在刷新
})(PullRefreshState || (PullRefreshState = {}));
const PullRefreshRefreshingHeight = 44;
const MaxPullTop = 88;
const TransparentHeaderDefaultOpacity = 0;
class PageHost extends lit_element_1.LitElement {
constructor() {
super(...arguments);
this.config = IPage_1.DefualtPageConfig;
this.headerOpacity = TransparentHeaderDefaultOpacity;
this['show-header'] = true;
// header 上是否展示返回按钮
this['show-back'] = false;
this['title-bar-height'] = defaultTitleBarHeight;
this['status-bar-height'] = defaultStatusBarHeight;
this.canHandleReachBottom = true;
this.onScroll = () => {
const content = this.contentElement;
const scrollTop = content.scrollTop;
const clientHeight = content.clientHeight;
const scrollHeight = content.scrollHeight;
// 支持onPageScroll
this.dispatchEvent(new CustomEvent(IPage_1.ScrollEventName, { detail: { scrollTop, scrollHeight } }));
if (scrollHeight > clientHeight &&
scrollHeight - scrollTop - clientHeight <=
(this.config.onReachBottomDistance || 20)) {
if (this.canHandleReachBottom) {
this.canHandleReachBottom = false;
this.dispatchEvent(new CustomEvent(IPage_1.ReachBottomEventName));
}
}
else {
this.canHandleReachBottom = true;
}
if (this.isAutoTransparent) {
// 0.5:表示滚动条滚动的位置如果超过了 clientHeight 的 0.5倍,那么将header 的 opacity 设为1
this.headerOpacity =
TransparentHeaderDefaultOpacity +
(1 - TransparentHeaderDefaultOpacity) *
Math.min(1, scrollTop / (clientHeight * 0.5));
}
};
/**
* 是否启用下拉刷新功能
*/
this.enbalePullRefresh = false;
this._pullRefreshState = PullRefreshState.Normal;
this.onTouchMove = (e) => {
if (!this.enbalePullRefresh)
return;
const currentTouch = e.touches[0];
const content = this.contentElement;
if (this.pullRefreshState === PullRefreshState.Refreshing)
return;
if (this.lastTouchPoint) {
const diffY = currentTouch.clientY - this.lastTouchPoint.clientY;
if (content.scrollTop <= 0) {
const paddingTop = parseFloat(window.getComputedStyle(content).paddingTop) || 0;
const top = paddingTop + diffY;
content.style.setProperty('padding-top', Math.min(top, MaxPullTop *
(parseFloat(document.documentElement.style.fontSize) / 16)) + 'px');
if (this.pullRefreshState === PullRefreshState.Normal) {
this.pullRefreshState = PullRefreshState.Pulling;
}
if (top >= PullRefreshRefreshingHeight) {
this.pullRefreshState = PullRefreshState.WillRefresh;
}
}
}
this.lastTouchPoint = currentTouch;
};
this.onTouchEnd = () => {
if (this.pullRefreshState !== PullRefreshState.Normal) {
if (this.pullRefreshState === PullRefreshState.WillRefresh) {
this.pullRefreshState = PullRefreshState.Refreshing;
}
else if (this.pullRefreshState === PullRefreshState.Pulling) {
this.pullRefreshState = PullRefreshState.Normal;
}
}
};
this.headerLoading = false;
}
static get styles() {
return (0, lit_element_1.css) `
:host {
display: flex;
flex-direction: column;
height: 100%;
font-size: 16px;
}
.content {
position: relative;
flex: 1;
overflow-y: auto;
overflow-x: hidden;
}
.content::-webkit-scrollbar {
display: none; /* Chrome Safari */
}
.pull-header {
text-align: center;
color: #1890ff;
position: absolute;
left: 0;
width: 100%;
transform: translateY(-100%);
}
`;
}
static get properties() {
return {
pullRefreshState: { type: Number }
};
}
get isAutoTransparent() {
return this.config.transparentTitle === 'auto';
}
setConfig(config) {
this.config = Object.assign(Object.assign({}, this.config), config);
// 业务在页面打开时有覆盖页面配置的场景
const updatePageConfig = (0, lodash_get_1.default)(window.$MOR_APP_CONFIG, 'updatePageConfig');
if (updatePageConfig) {
const { path: pagePath, options: pageOptions } = (0, utils_1.getCurrentPageParams)([
'path',
'options'
]);
const resultConfig = (0, utils_1.getPageConfig)(updatePageConfig, pagePath, pageOptions);
if (typeof resultConfig === 'object')
this.config = Object.assign(this.config, resultConfig);
}
// 强制渲染
this.requestUpdate();
// NOTE: 页面背景色
if (config.backgroundColor &&
window.getComputedStyle(this).backgroundColor === 'rgba(0, 0, 0, 0)') {
if (!this.styleElement) {
this.styleElement = document.createElement('style');
this.classList.add(`page-${(0, index_1.uuid)()}`);
document.head.appendChild(this.styleElement);
}
this.styleElement.innerHTML = `
.${this.className}{
background-color:${config.backgroundColor};
}
`;
}
if (this.config.showTitleLoading) {
this.showNavigationBarLoading();
}
try {
const { defaultTitle } = this.config;
document.title = typeof defaultTitle === 'undefined' ? '' : defaultTitle;
}
catch (e) { }
}
getConfig() {
return this.config;
}
connectedCallback() {
super.connectedCallback();
setTimeout(() => {
this.contentElement.addEventListener('touchmove', this.onTouchMove, {
passive: true
});
this.contentElement.addEventListener('touchend', this.onTouchEnd, {
passive: true
});
this.contentElement.addEventListener('scroll', this.onScroll, {
passive: true
});
}, 0);
}
disconnectedCallback() {
super.disconnectedCallback();
if (this.styleElement) {
this.styleElement.remove();
}
this.contentElement.removeEventListener('touchmove', this.onTouchMove);
this.contentElement.removeEventListener('touchend', this.onTouchEnd);
this.contentElement.removeEventListener('scroll', this.onScroll);
}
get pullRefreshState() {
return this._pullRefreshState;
}
set pullRefreshState(value) {
if (value !== this._pullRefreshState) {
const oldVal = this._pullRefreshState;
this._pullRefreshState = value;
this.requestUpdate('pullRefreshState', oldVal);
if (value === PullRefreshState.Refreshing) {
this.animationPaddingTop(PullRefreshRefreshingHeight);
// 触发事件
this.dispatchEvent(new CustomEvent(IPage_1.PullDownRefreshEventName));
}
else if (this.pullRefreshState === PullRefreshState.Normal) {
this.animationPaddingTop(0);
}
}
}
startPullDownRefresh() {
this.pullRefreshState = PullRefreshState.Refreshing;
}
stopPullDownRefresh() {
this.pullRefreshState = PullRefreshState.Normal;
}
animationPaddingTop(top) {
const options = {
iterationStart: 0,
direction: 'alternate',
duration: 200,
fill: 'forwards',
easing: 'ease-in'
};
const keyframes = {
easing: 'ease-out',
paddingTop: (0, rpx_1.rpxToRem)(top * 2)
};
const a = this.contentElement.animate(keyframes, options);
a.addEventListener('finish', () => {
// 动画结束后,删除动画,并且将属性设为最终的值
a.cancel();
this.contentElement.style.setProperty('padding-top', (0, rpx_1.rpxToRem)(top * 2));
});
}
showNavigationBarLoading() {
this.headerLoading = true;
this.requestUpdate();
}
hideNavigationBarLoading() {
this.headerLoading = false;
this.requestUpdate();
}
getPullRefrehHeader() {
let content = undefined;
const buildHtml = (content) => (0, lit_element_1.html) `
<div
class="pull-header"
style="height:${this['title-bar-height']};line-height:${this['title-bar-height']};"
>
<span>${content}</span>
</div>
`;
switch (this.pullRefreshState) {
case PullRefreshState.Refreshing: {
content = '正在刷新...';
break;
}
case PullRefreshState.WillRefresh: {
content = '松开即可刷新';
break;
}
case PullRefreshState.Pulling: {
content = '下拉刷新';
break;
}
}
return buildHtml(content);
}
getRenderHeader() {
const { borderBottomColor, titleImage = '', defaultTitle, transparentTitle, titlePenetrate, titleBarColor } = this.config;
const pageHeaderConfig = (0, lodash_get_1.default)(window.$MOR_APP_CONFIG, 'pageHeaderConfig', {});
const { path: pagePath, options: pageOptions } = (0, utils_1.getCurrentPageParams)([
'path',
'options'
]);
const enableShowHeader = (0, utils_1.shouldEnableFor)(pageHeaderConfig.showHeader, pagePath, pageOptions);
// enableShowHeader 有可能为 undefined,代表用户未配置或者取数据异常
let showHeader = typeof enableShowHeader === 'boolean'
? enableShowHeader
: this['show-header'];
let showBack = this['show-back'];
try {
// 通过 url 上的字段隐藏 nav bar,实现动态切换展示/隐藏的功能
const { search } = location;
if (search && search.indexOf('hide-header=1') > -1)
showHeader = false;
const enableShowBack = (0, utils_1.shouldEnableFor)(pageHeaderConfig.showBack, pagePath, pageOptions);
if (typeof enableShowBack === 'boolean')
showBack = enableShowBack;
}
catch (e) { }
try {
// 处理业务自定义导航栏高度
const navConfig = (0, lodash_get_1.default)(window.$MOR_APP_CONFIG, 'nav', {});
const navResult = (0, utils_1.getNav)(navConfig, pagePath, pageOptions);
if (!(0, utils_1.isUndefined)(navResult.statusBarHeight))
this['status-bar-height'] = utils_1.converterForPx.fromAttribute(navResult.statusBarHeight);
if (!(0, utils_1.isUndefined)(navResult.titleBarHeight))
this['title-bar-height'] = utils_1.converterForPx.fromAttribute(navResult.titleBarHeight);
}
catch (e) { }
if (!showHeader)
return '';
return (0, lit_element_1.html) ` <tiga-header
default-title="${defaultTitle}"
title-image="${titleImage}"
border-bottom-color="${borderBottomColor}"
title-penetrate="${titlePenetrate}"
transparent-title="${transparentTitle}"
title-bar-color="${titleBarColor}"
show-back="${showBack}"
title-bar-height="${this['title-bar-height']}"
status-bar-height="${this['status-bar-height']}"
header-loading="${this.headerLoading}"
header-opacity="${this.headerOpacity}"
/>`;
}
render() {
return (0, lit_element_1.html) `
${this.getRenderHeader()}
<div class="content">
${this.getPullRefrehHeader()}
<slot></slot>
</div>
`;
}
}
tslib_1.__decorate([
(0, lit_element_1.internalProperty)()
], PageHost.prototype, "headerOpacity", void 0);
tslib_1.__decorate([
(0, lit_element_1.query)('.content')
], PageHost.prototype, "contentElement", void 0);
tslib_1.__decorate([
(0, lit_element_1.property)({ converter: bool_converter_1.default })
], PageHost.prototype, 'show-header', void 0);
tslib_1.__decorate([
(0, lit_element_1.property)({ converter: bool_converter_1.default })
], PageHost.prototype, 'show-back', void 0);
tslib_1.__decorate([
(0, lit_element_1.property)({
converter: utils_1.converterForPx
})
], PageHost.prototype, 'title-bar-height', void 0);
tslib_1.__decorate([
(0, lit_element_1.property)({
converter: utils_1.converterForPx
})
], PageHost.prototype, 'status-bar-height', void 0);
exports.default = PageHost;
(0, utils_1.defineElement)('tiga-page-host', PageHost);
//# sourceMappingURL=page-host.js.map