UNPKG

@morjs/runtime-web

Version:
230 lines 8.94 kB
"use strict"; var _a, _b, _c, _d; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const lit_element_1 = require("lit-element"); 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"); const maskStyle = 'mask-style'; const maskClass = 'mask-class'; const indicatorStyle = 'indicator-style'; const indicatorClass = 'indicator-class'; class PickerViewColumn extends baseElement_1.BaseElement { constructor() { super(...arguments); // 起始位置,用于计算一次手指滑动距离 this.startY = 0; // 保存移动距离,用于在touchmove和touchend共享变量 this.movedY = 0; // 所有操作偏移之和 this.lastMovedY = 0; // 上次选中的下标,如果本次和上次相同,不触发change事件 this.lastIndex = -1; // 在PC端是否处于点击状态 this.isTouch = false; this[_a] = ''; this[_b] = ''; this[_c] = ''; this[_d] = ''; this.value = 0; // 通过切换transform属性实现滚动效果 this.styles = { transform: 'translate3d(0, 0, 0)' }; this.indicatorTop = constants_1.INDICATOR_TOP; } static get styles() { return index_style_1.Styles; } attributeChangedCallback(name, oldValue, newValue) { if (name === 'value') requestAnimationFrame(() => this.moveToSelectValue()); super.attributeChangedCallback(name, oldValue, newValue); } moveToSelectValue() { let value = this.value; const { length } = this.slotNodes; this.lastIndex = value; if (value > length) value = length; if (value >= 0) { this.lastMovedY = -(value * this.itemHeight); this.move(); } if (Math.abs(this.lastMovedY) > Math.abs((length - 1) * this.itemHeight)) { this.lastMovedY = -((length - 1) * this.itemHeight); this.move(); } } initStyles() { requestAnimationFrame(() => { const height = (this.itemHeight = this.$indicatorElement.offsetHeight); const nodes = this.slotNodes; this.indicatorTop = this.offsetHeight - height; this.$containerElement && (this.$containerElement.style.cssText = `padding-top: ${(0, rpx_1.rpxToRem)(this.indicatorTop)};`); this.$indicatorElement && (this.$indicatorElement.style.cssText = `${this[indicatorStyle]};top: ${(0, rpx_1.rpxToRem)(this.indicatorTop)};`); this.$maskElement && (this.$maskElement.style.cssText = `${this[maskStyle]};background-size: 100% ${(0, rpx_1.rpxToRem)(this.indicatorTop)};`); nodes.map((item) => { if (!item || !item.style) return; item.style.cssText = index_style_1.DEFAULT_ITEM_STYLES + `height:${(0, rpx_1.rpxToRem)(2 * height)};line-height:${(0, rpx_1.rpxToRem)(2 * height)};`; }); }); } onTouchStart(event) { if (this.isTouch) return; // 记录起始位置,方便后续计算滚动距离 const { y } = (0, utils_1.getPosition)(event); (0, utils_1.fixedBody)(document); this.startY = y; this.isTouch = true; } onTouchMove(event) { if (!this.isTouch) return; const { y } = (0, utils_1.getPosition)(event); this.movedY = y - this.startY; this.move(this.movedY); } onMouseLeave() { if (!this.isTouch) return; this.onTouchEnd(); } onTouchEnd() { // 计算最新的偏移距离 const lastMovedY = (this.lastMovedY = this.lastMovedY + this.movedY); // 消费完清空,否则会引起二次点击问题 this.movedY = 0; const height = this.itemHeight * (this.slotNodes.length - 1); (0, utils_1.looseBody)(document); this.startY = 0; // 如果滚动距离超出范围,做边界处理 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 * this.itemHeight); this.move(); } this.dispatch(); this.isTouch = false; } 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)(2 * this.itemHeight)); 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() { const index = this.getClosestIndex(this.lastMovedY); if (index === this.lastIndex) return; this.lastIndex = index; this.dispatchEvent(new CustomEvent('private-change', { detail: { value: index }, bubbles: true, composed: true })); } handleSlotChange() { this.initStyles(); } render() { return (0, lit_element_1.html) ` <section class="tiga-picker-column-container" @mousedown=${this.onTouchStart} @mousemove=${this.onTouchMove} @mouseup=${this.onTouchEnd} @mouseleave=${this.onMouseLeave} @touchstart=${this.onTouchStart} @touchmove=${this.onTouchMove} @touchend=${this.onTouchEnd} > <p class="tiga-picker-column-mask ${this[maskClass] || ''}" style=${this[maskStyle]} ></p> <div class="tiga-picker-column-indicator ${this[indicatorClass] || ''}" style="${this[indicatorStyle]}" ></div> <section class="tiga-picker-column-list" style="${(0, style_map_1.styleMap)(this.styles)}" > <slot @slotchange=${this.handleSlotChange}></slot> </section> </section> `; } } _a = maskStyle, _b = maskClass, _c = indicatorStyle, _d = indicatorClass; tslib_1.__decorate([ (0, lit_element_1.property)() ], PickerViewColumn.prototype, _a, void 0); tslib_1.__decorate([ (0, lit_element_1.property)() ], PickerViewColumn.prototype, _b, void 0); tslib_1.__decorate([ (0, lit_element_1.property)() ], PickerViewColumn.prototype, _c, void 0); tslib_1.__decorate([ (0, lit_element_1.property)() ], PickerViewColumn.prototype, _d, void 0); tslib_1.__decorate([ (0, lit_element_1.property)({ type: Number }) ], PickerViewColumn.prototype, "value", void 0); tslib_1.__decorate([ (0, lit_element_1.internalProperty)() ], PickerViewColumn.prototype, "styles", void 0); tslib_1.__decorate([ (0, lit_element_1.query)('.tiga-picker-column-indicator') ], PickerViewColumn.prototype, "$indicatorElement", void 0); tslib_1.__decorate([ (0, lit_element_1.query)('.tiga-picker-column-container') ], PickerViewColumn.prototype, "$containerElement", void 0); tslib_1.__decorate([ (0, lit_element_1.query)('.tiga-picker-column-mask') ], PickerViewColumn.prototype, "$maskElement", void 0); tslib_1.__decorate([ (0, lit_element_1.queryAssignedNodes)() ], PickerViewColumn.prototype, "slotNodes", void 0); tslib_1.__decorate([ (0, lit_element_1.eventOptions)({ passive: true }) ], PickerViewColumn.prototype, "onTouchStart", null); tslib_1.__decorate([ (0, lit_element_1.eventOptions)({ passive: true }) ], PickerViewColumn.prototype, "onTouchMove", null); tslib_1.__decorate([ (0, lit_element_1.eventOptions)({ passive: true }) ], PickerViewColumn.prototype, "onMouseLeave", null); tslib_1.__decorate([ (0, lit_element_1.eventOptions)({ passive: true }) ], PickerViewColumn.prototype, "onTouchEnd", null); exports.default = PickerViewColumn; //# sourceMappingURL=index.js.map