@morjs/runtime-web
Version:
mor runtime for web
230 lines • 8.94 kB
JavaScript
"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"
=${this.onTouchStart}
=${this.onTouchMove}
=${this.onTouchEnd}
=${this.onMouseLeave}
=${this.onTouchStart}
=${this.onTouchMove}
=${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 =${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