UNPKG

@morjs/runtime-web

Version:
363 lines (360 loc) 14.3 kB
"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