@tarojs/components
Version:
433 lines (432 loc) • 12.1 kB
JavaScript
import { Host, h } from '@stencil/core';
import { TOP, LINE_HEIGHT, MASK_HEIGHT } from './constant';
export class TaroPickerGroup {
constructor() {
this.mode = undefined;
this.range = [];
this.rangeKey = undefined;
this.height = undefined;
this.columnId = undefined;
this.updateHeight = undefined;
this.updateDay = undefined;
this.startY = undefined;
this.preY = undefined;
this.hadMove = undefined;
this.touchEnd = undefined;
this.isMove = undefined;
}
getPosition() {
const transition = this.touchEnd ? 0.3 : 0;
const transformValue = `translate3d(0, ${this.height}px, 0)`;
const transitionValue = `transform ${transition}s`;
return {
transform: transformValue,
'-webkit-transform': transformValue,
transition: transitionValue,
'-webkit-transition': transitionValue
};
}
formulaUnlimitedScroll(range, absoluteHeight, direction) {
const { height, updateHeight, columnId } = this;
const factor = direction === 'up' ? 1 : -1;
this.touchEnd = false;
// 点击超过范围,点击到补帧时,先跳到另一端的补帧
updateHeight(-range * factor * LINE_HEIGHT + height, columnId);
// 再做过渡动画
requestAnimationFrame(() => {
this.touchEnd = true;
const index = Math.round(absoluteHeight / -LINE_HEIGHT) + range * factor;
const relativeHeight = TOP - LINE_HEIGHT * index;
updateHeight(relativeHeight, columnId, true);
});
}
async handleMoveStart(clientY) {
// 记录第一次的点击位置
this.startY = clientY;
this.preY = clientY;
this.hadMove = false;
}
async handleMoving(clientY) {
const y = clientY;
const deltaY = y - this.preY;
this.preY = y;
this.touchEnd = false;
if (Math.abs(y - this.startY) > 10)
this.hadMove = true;
let newPos = this.height + deltaY;
// 处理时间选择器的无限滚动
if (this.mode === 'time') {
if (this.columnId === '0') {
// 数字 28 来自于 4 格补帧 + 0 ~ 23 的 24 格,共 28 格
if (newPos > TOP - LINE_HEIGHT * 3) {
newPos = TOP - LINE_HEIGHT * 27 + deltaY;
}
if (newPos < TOP - LINE_HEIGHT * 28) {
newPos = TOP - LINE_HEIGHT * 4 + deltaY;
}
}
else if (this.columnId === '1') {
if (newPos > TOP - LINE_HEIGHT * 3) {
newPos = TOP - LINE_HEIGHT * 63 + deltaY;
}
if (newPos < TOP - LINE_HEIGHT * 64) {
newPos = TOP - LINE_HEIGHT * 4 + deltaY;
}
}
}
this.updateHeight(newPos, this.columnId);
}
async handleMoveEnd(clientY) {
const { mode, range, height, updateHeight, columnId } = this;
const max = 0;
const min = -LINE_HEIGHT * (range.length - 1);
const endY = clientY;
this.touchEnd = true;
// touchEnd 时的高度,可能带小数点,需要再处理
let absoluteHeight;
if (!this.hadMove) {
/** 点击 */
// 屏幕高度
const windowHeight = window.innerHeight;
// picker__mask 垂直方向距离屏幕顶部的高度
const relativeY = windowHeight - MASK_HEIGHT / 2;
absoluteHeight = height - TOP - (endY - relativeY);
// 处理时间选择器的无限滚动
if (mode === 'time') {
if (columnId === '0') {
// 点击上溢出
// absoluteHeight 是相对模块中点来算的,所以会算多半行,这时要减去这半行,即2.5行
if (absoluteHeight > -LINE_HEIGHT * 2.5) {
return this.formulaUnlimitedScroll(24, absoluteHeight, 'up');
}
// 点击下溢出
if (absoluteHeight < -LINE_HEIGHT * 28.5) {
return this.formulaUnlimitedScroll(24, absoluteHeight, 'down');
}
}
else if (columnId === '1') {
// 点击上溢出
if (absoluteHeight > -LINE_HEIGHT * 2.5) {
return this.formulaUnlimitedScroll(60, absoluteHeight, 'up');
}
// 点击下溢出
if (absoluteHeight < -LINE_HEIGHT * 64.5) {
return this.formulaUnlimitedScroll(60, absoluteHeight, 'down');
}
}
}
}
else {
/** 滚动 */
absoluteHeight = height - TOP;
}
// 边界情况处理
if (absoluteHeight > max)
absoluteHeight = 0;
if (absoluteHeight < min)
absoluteHeight = min;
// 先按公式算出 index, 再用此 index 算出一个整数高度
const index = Math.round(absoluteHeight / -LINE_HEIGHT);
const relativeHeight = TOP - LINE_HEIGHT * index;
if (this.mode === 'date' && typeof this.updateDay === 'function') {
if (this.columnId === '0') {
this.updateDay(+this.range[index].replace(/[^0-9]/gi, ''), 0);
}
if (this.columnId === '1') {
this.updateDay(+this.range[index].replace(/[^0-9]/gi, ''), 1);
}
if (this.columnId === '2') {
this.updateDay(+this.range[index].replace(/[^0-9]/gi, ''), 2);
}
}
updateHeight(relativeHeight, columnId, mode === 'time');
this.onColumnChange.emit({
columnId,
height: relativeHeight,
});
}
onMouseDown(e) {
this.isMove = true;
this.handleMoveStart(e.clientY);
}
onMouseMove(e) {
if (!this.isMove)
return;
this.handleMoving(e.clientY);
}
onMouseMoveEnd(e) {
if (!this.isMove)
return;
this.isMove = false;
this.handleMoveEnd(e.clientY);
}
onTouchStart(e) {
this.handleMoveStart(e.changedTouches[0].clientY);
}
onTouchMove(e) {
this.handleMoving(e.changedTouches[0].clientY);
}
onTouchEnd(e) {
this.handleMoveEnd(e.changedTouches[0].clientY);
}
render() {
const { range, rangeKey } = this;
const pickerItem = range.map(item => {
const content = rangeKey ? item[rangeKey] : item;
return (h("div", { class: 'weui-picker__item' }, content));
});
return (h(Host, { class: 'weui-picker__group' }, h("div", { class: 'weui-picker__mask' }), h("div", { class: 'weui-picker__indicator' }), h("div", { class: 'weui-picker__content', style: this.getPosition() }, pickerItem)));
}
static get is() { return "taro-picker-group"; }
static get properties() {
return {
"mode": {
"type": "string",
"mutable": false,
"complexType": {
"original": "'time' | 'date'",
"resolved": "\"date\" | \"time\"",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "mode",
"reflect": false
},
"range": {
"type": "unknown",
"mutable": false,
"complexType": {
"original": "any[]",
"resolved": "any[]",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"defaultValue": "[]"
},
"rangeKey": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "range-key",
"reflect": false
},
"height": {
"type": "number",
"mutable": false,
"complexType": {
"original": "number",
"resolved": "number",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "height",
"reflect": false
},
"columnId": {
"type": "string",
"mutable": false,
"complexType": {
"original": "string",
"resolved": "string",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
},
"attribute": "column-id",
"reflect": false
},
"updateHeight": {
"type": "unknown",
"mutable": false,
"complexType": {
"original": "(height: number, columnId: string, needRevise?: boolean) => void",
"resolved": "(height: number, columnId: string, needRevise?: boolean | undefined) => void",
"references": {}
},
"required": false,
"optional": false,
"docs": {
"tags": [],
"text": ""
}
},
"updateDay": {
"type": "unknown",
"mutable": false,
"complexType": {
"original": "(value: number, fields: number) => void",
"resolved": "((value: number, fields: number) => void) | undefined",
"references": {}
},
"required": false,
"optional": true,
"docs": {
"tags": [],
"text": ""
}
}
};
}
static get states() {
return {
"startY": {},
"preY": {},
"hadMove": {},
"touchEnd": {},
"isMove": {}
};
}
static get events() {
return [{
"method": "onColumnChange",
"name": "columnChange",
"bubbles": true,
"cancelable": true,
"composed": true,
"docs": {
"tags": [],
"text": ""
},
"complexType": {
"original": "any",
"resolved": "any",
"references": {}
}
}];
}
static get methods() {
return {
"handleMoveStart": {
"complexType": {
"signature": "(clientY: number) => Promise<void>",
"parameters": [{
"tags": [],
"text": ""
}],
"references": {
"Promise": {
"location": "global"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "",
"tags": []
}
},
"handleMoving": {
"complexType": {
"signature": "(clientY: number) => Promise<void>",
"parameters": [{
"tags": [],
"text": ""
}],
"references": {
"Promise": {
"location": "global"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "",
"tags": []
}
},
"handleMoveEnd": {
"complexType": {
"signature": "(clientY: number) => Promise<void>",
"parameters": [{
"tags": [],
"text": ""
}],
"references": {
"Promise": {
"location": "global"
}
},
"return": "Promise<void>"
},
"docs": {
"text": "",
"tags": []
}
}
};
}
static get listeners() {
return [{
"name": "mousedown",
"method": "onMouseDown",
"target": undefined,
"capture": false,
"passive": true
}, {
"name": "mousemove",
"method": "onMouseMove",
"target": undefined,
"capture": true,
"passive": true
}, {
"name": "mouseup",
"method": "onMouseMoveEnd",
"target": undefined,
"capture": false,
"passive": true
}, {
"name": "mouseleave",
"method": "onMouseMoveEnd",
"target": undefined,
"capture": false,
"passive": true
}, {
"name": "touchstart",
"method": "onTouchStart",
"target": undefined,
"capture": false,
"passive": true
}, {
"name": "touchmove",
"method": "onTouchMove",
"target": undefined,
"capture": true,
"passive": true
}, {
"name": "touchend",
"method": "onTouchEnd",
"target": undefined,
"capture": false,
"passive": true
}];
}
}