UNPKG

@morjs/runtime-web

Version:
222 lines (220 loc) 8.09 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const lit_element_1 = require("lit-element"); const class_map_1 = require("lit-html/directives//class-map"); const style_map_1 = require("lit-html/directives/style-map"); const baseElement_1 = require("../../baseElement"); const rpx_1 = require("../../rpx"); const constants_1 = require("./constants"); const index_style_1 = require("./index.style"); const utils_1 = require("./utils"); class Picker extends baseElement_1.BaseElement { constructor() { super(...arguments); this.startY = 0; this.movedY = 0; this.lastMovedY = 0; this.lastIndex = 0; this.showPicker = false; // 通过切换transform属性实现滚动效果 this.styles = { transform: 'translate3d(0, 0, 0)' }; this.title = ''; this.show = false; this.range = []; this['range-key'] = ''; this.value = 0; this.disabled = false; this.confirmText = '确定'; this.cancelText = '取消'; } connectedCallback() { super.connectedCallback(); // 默认打开逻辑 if (this.show) { this.togglePicker(true); } this.lastIndex = this.value; } static get styles() { return index_style_1.PickerStyles; } onPickerClick() { if (this.disabled) return; this.togglePicker(true); } togglePicker(isShow = false) { if (isShow) { // 解决滚动穿透 (0, utils_1.fixedBody)(document); // 计算传入的index所在位置,提前记录位置并滚动到该区域 this.lastMovedY = -((this.value * constants_1.ITEM_HEIGHT) / 2); this.move(); } else { // picker关闭时解除滚动传动限制 (0, utils_1.looseBody)(document); } this.showPicker = isShow; } onTouchStart(event) { // 记录起始位置,方便后续计算滚动距离 const { y } = (0, utils_1.getPosition)(event); this.startY = y; } onTouchMove(event) { const { y } = (0, utils_1.getPosition)(event); this.movedY = y - this.startY; this.move(this.movedY); } onTouchEnd() { this.startY = 0; // 计算最新的偏移距离 const lastMovedY = (this.lastMovedY = this.lastMovedY + this.movedY); const height = (constants_1.ITEM_HEIGHT / 2) * (this.range.length - 1); // 如果滚动距离超出范围,做边界处理 if (Math.abs(lastMovedY) > height || lastMovedY > 0) { this.lastMovedY = lastMovedY > 0 ? 0 : -height; this.move(); } else { // 计算当前滚动距离离哪个元素更近 const index = this.getClosestIndex(lastMovedY); // 计算出下标并滚动以确保滚动距离始终为 ITEM_HEIGHT 的倍数 this.lastMovedY = -((index * constants_1.ITEM_HEIGHT) / 2); this.move(); } } move(moveY = 0) { // 将当前计算的距离转换成rem保证各分辨率的适配 const value = (0, rpx_1.rpxToRem)(2 * (moveY + this.lastMovedY)); this.styles = { transform: `translate3d(0, ${value}, 0)` }; } // 根据当前滚动距离获取最近的节点 getClosestIndex(distance) { // 将 rpx 单位转换成rem做计算用于适配 const itemHeight = parseFloat((0, rpx_1.rpxToRem)(constants_1.ITEM_HEIGHT)); const currentHeight = Math.abs(parseFloat((0, rpx_1.rpxToRem)(2 * distance))); const num = parseInt(currentHeight / itemHeight + ''); const extra = (currentHeight - itemHeight * num) / itemHeight; // 判断多出的距离是否大于边界因子(0.4效果比较好),如果大于就滚动到下一个元素 if (extra >= constants_1.RATE) return num + 1; return num; } dispatch(eventName, data) { this.dispatchEvent(new CustomEvent(eventName, { detail: data, bubbles: true, composed: true })); } onConfirm() { const index = this.getClosestIndex(this.lastMovedY); if (index === this.lastIndex) { this.dispatch('no-change', { value: index }); return; } this.value = index; this.lastIndex = index; this.dispatch('change', { value: index }); this.togglePicker(); } onCancel() { this.dispatch('cancel', { value: this.value }); this.togglePicker(); } getName(item) { return typeof item === 'object' ? item[this['range-key']] : item; } render() { const classes = { 'picker-container--show': this.showPicker }; return (0, lit_element_1.html) ` <slot @click="${this.onPickerClick}"></slot> <slot name="picker"> </slot> <div class="picker-container ${(0, class_map_1.classMap)(classes)}"> <div class="picker-mask"></div> <div class="picker-main ${(0, utils_1.isIos)() ? 'picker-main--ios' : 'picker-main--android'}" > <div class="picker-main-header"> ${(0, utils_1.isIos)() ? (0, lit_element_1.html) `<p class="picker-btn" @click="${this.onCancel}"> ${this.cancelText} </p>` : null} ${this.title ? (0, lit_element_1.html) `<p class="picker-title">${this.title}</p>` : null} ${(0, utils_1.isIos)() ? (0, lit_element_1.html) `<p class="picker-btn" @click="${this.onConfirm}"> ${this.confirmText} </p>` : null} </div> <div class="picker-main-content" @touchstart="${this.onTouchStart}" @touchmove="${this.onTouchMove}" @touchend="${this.onTouchEnd}" > <div class="picker-content-mask"></div> <div class="picker-content-indicator"></div> <div class="picker-content-list" style="${(0, style_map_1.styleMap)(this.styles)}"> ${this.range.map((item) => (0, lit_element_1.html) ` <div class="picker-content-item">${this.getName(item)}</div> `)} </div> </div> ${!(0, utils_1.isIos)() ? (0, lit_element_1.html) ` <footer class="picker-footer-group"> <p class="picker-btn-android" @click="${this.onCancel}"> 取消 </p> <p class="picker-btn-android" @click="${this.onConfirm}"> 确定 </p> </footer> ` : null} </div> </div> `; } } tslib_1.__decorate([ (0, lit_element_1.internalProperty)() ], Picker.prototype, "showPicker", void 0); tslib_1.__decorate([ (0, lit_element_1.internalProperty)() ], Picker.prototype, "styles", void 0); tslib_1.__decorate([ (0, lit_element_1.property)({ type: String }) ], Picker.prototype, "title", void 0); tslib_1.__decorate([ (0, lit_element_1.property)({ type: Boolean }) ], Picker.prototype, "show", void 0); tslib_1.__decorate([ (0, lit_element_1.property)({ type: Array }) ], Picker.prototype, "range", void 0); tslib_1.__decorate([ (0, lit_element_1.property)({ type: String }) ], Picker.prototype, 'range-key', void 0); tslib_1.__decorate([ (0, lit_element_1.property)({ type: Number, reflect: true }) ], Picker.prototype, "value", void 0); tslib_1.__decorate([ (0, lit_element_1.property)({ type: Boolean }) ], Picker.prototype, "disabled", void 0); tslib_1.__decorate([ (0, lit_element_1.property)() ], Picker.prototype, "confirmText", void 0); tslib_1.__decorate([ (0, lit_element_1.property)() ], Picker.prototype, "cancelText", void 0); exports.default = Picker; //# sourceMappingURL=index.js.map