UNPKG

@morjs/runtime-web

Version:
183 lines 6.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const lit_element_1 = require("lit-element"); const baseElement_1 = require("../baseElement"); const bool_converter_1 = tslib_1.__importDefault(require("../utils/bool-converter")); const movable_area_1 = tslib_1.__importDefault(require("./movable-area")); /** * 可移动的视图容器,在页面中可以拖拽滑动。 * movable-view 必须在 movable-area 组件中,并且必须是直接子节点,否则不能移动。 */ class MovableView extends baseElement_1.BaseElement { constructor() { super(...arguments); /** * 定义 x 轴方向的偏移,会换算为 left 属性,如果 x 的值不在可移动范围内,会自动移动到可移动范围。 */ this.x = 0; /** * 定义 y 轴方向的偏移,会换算为 top 属性,如果 y 的值不在可移动范围内,会自动移动到可移动范围。 */ this.y = 0; /** * 超过可移动区域后,movable-view 是否还可以移动。 */ this['out-of-bounds'] = false; /** * movable-view 的移动方向,属性值有 all、vertical、horizontal、none。 */ this.direction = 'none'; this.onTouchStart = (e) => { this.preventDefault(e); this.canMove = true; }; this.canMove = false; this.onMouseMove = (e) => { this.preventDefault(e); if (e.buttons === 1) { // 只有鼠标左键处于按下状态才算 this.onMove({ clientX: e.clientX, clientY: e.clientY }); } else { if (this.canMove) { this.moveEnd(); } } }; this.onTouchMove = (e) => { this.preventDefault(e); const currentTouch = e.touches[0]; this.onMove({ clientX: currentTouch.clientX, clientY: currentTouch.clientY }); }; this.onTouchEnd = (e) => { // e.stopPropagation(); e.preventDefault(); this.moveEnd(); }; this.position = { x: 0, y: 0 }; } static get styles() { return (0, lit_element_1.css) ` :host { display: block; } `; } connectedCallback() { super.connectedCallback(); if (this.parentElement instanceof movable_area_1.default) { // 可以滑动 this.addEventListener('touchstart', this.onTouchStart, { passive: false }); this.addEventListener('touchmove', this.onTouchMove, { passive: false }); this.addEventListener('touchend', this.onTouchEnd, { passive: false }); } this.position.x = this.x; this.position.y = this.y; this.updatePosition(); } preventDefault(event) { if (this.direction !== 'horizontal') { event.preventDefault(); } } onMove(point) { if (this.lastPoint && this.canMove) { const diffX = point.clientX - this.lastPoint.clientX; const diffY = point.clientY - this.lastPoint.clientY; switch (this.direction) { case 'all': { this.position.x += diffX; this.position.y += diffY; break; } case 'vertical': { this.position.y += diffY; break; } case 'horizontal': { this.position.x += diffX; break; } } this.updatePosition('touch'); } this.lastPoint = point; } moveEnd() { this.lastPoint = null; this.canMove = false; this.dispatchEvent(new CustomEvent('changeend', { detail: { x: this.position.x, y: this.position.y } })); } attributeChangedCallback(name, oldVal, newVal) { super.attributeChangedCallback(name, oldVal, newVal); switch (name) { case 'x': { this.position.x = newVal; this.updatePosition(); break; } case 'y': { this.position.y = newVal; this.updatePosition(); break; } } } updatePosition(source = 'setData') { if (this.disabled) return; if (!this['out-of-bounds'] && this.parentElement) { if (this.parentElement.clientWidth >= this.clientWidth) { this.position.x = Math.min(Math.max(0, this.position.x), this.parentElement.clientWidth - this.clientWidth); } else { this.position.x = Math.max(Math.min(0, this.position.x), this.parentElement.clientWidth - this.clientWidth); } if (this.parentElement.clientHeight >= this.clientHeight) { this.position.y = Math.min(Math.max(0, this.position.y), this.parentElement.clientHeight - this.clientHeight); } else { this.position.y = Math.max(Math.min(0, this.position.y), this.parentElement.clientHeight - this.clientHeight); } } this.style.setProperty('margin-left', this.position.x + 'px'); this.style.setProperty('margin-top', this.position.y + 'px'); // NOTE: 事件 this.dispatchEvent(new CustomEvent('change', { detail: { x: this.position.x, y: this.position.y, source } })); } render() { return (0, lit_element_1.html) ` <slot></slot> `; } } tslib_1.__decorate([ (0, lit_element_1.property)({ type: Number }) ], MovableView.prototype, "x", void 0); tslib_1.__decorate([ (0, lit_element_1.property)({ type: Number }) ], MovableView.prototype, "y", void 0); tslib_1.__decorate([ (0, lit_element_1.property)({ converter: bool_converter_1.default }) ], MovableView.prototype, 'out-of-bounds', void 0); tslib_1.__decorate([ (0, lit_element_1.property)({ type: String }) ], MovableView.prototype, "direction", void 0); exports.default = MovableView; //# sourceMappingURL=movable-view.js.map