@morjs/runtime-web
Version:
mor runtime for web
183 lines • 6.49 kB
JavaScript
"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