UNPKG

taro-ui-vue3

Version:

Taro UI Rewritten in Vue 3.0

208 lines (207 loc) 6.09 kB
import { h, defineComponent, ref, reactive, watch, computed, mergeProps } from "vue"; import _inRange from "lodash-es/inRange"; import _isEmpty from "lodash-es/isEmpty"; import {Text, View} from "@tarojs/components"; import { delayGetClientRect, delayGetScrollOffset, uuid } from "../utils/common"; import AtSwipeActionOptions from "./options/index"; const AtSwipeAction = defineComponent({ name: "AtSwipeAction", props: { isOpened: Boolean, disabled: Boolean, autoClose: Boolean, options: { type: Array, default: () => [] }, onClick: Function, onOpened: Function, onClosed: Function }, setup(props, {attrs, slots}) { const endValue = ref(0); const startX = ref(0); const startY = ref(0); const maxOffsetSize = ref(0); const isMoving = ref(false); const isTouching = ref(false); const domInfo = ref({ top: 0, bottom: 0, left: 0, right: 0 }); const state = reactive({ componentId: uuid(), offsetSize: 0, _isOpened: !!props.isOpened }); const transformStyle = computed(() => { const transform = computeTransform(state.offsetSize); return transform ? {transform} : {}; }); const actionContentClass = computed(() => ({ "at-swipe-action__content": true, animation: !isTouching.value })); const genActionItemClass = computed(() => (item) => ({ "at-swipe-action__option": true, [`${item.className}`]: Boolean(item.className) })); watch(() => props.isOpened, (isOpened) => { if (isOpened !== state._isOpened) { _reset(!!isOpened); } }); function getDomInfo() { return Promise.all([ delayGetClientRect({ delayTime: 0, selectorStr: `#swipeAction-${state.componentId}` }), delayGetScrollOffset({delayTime: 0}) ]).then(([rect, scrollOffset]) => { if (rect[0]) { rect[0].top += scrollOffset[0].scrollTop; rect[0].bottom += scrollOffset[0].scrollTop; domInfo.value = rect[0]; } }); } function _reset(isOpened) { isMoving.value = false; isTouching.value = false; if (isOpened) { endValue.value = -maxOffsetSize.value; state._isOpened = true; state.offsetSize = -maxOffsetSize.value; } else { endValue.value = 0; state.offsetSize = 0; state._isOpened = false; } } function computeTransform(value) { return value ? `translate3d(${value}px,0,0)` : null; } function handleOpened(event) { if (typeof props.onOpened === "function" && state._isOpened) { props.onOpened(event); } } function handleClosed(event) { if (typeof props.onClosed === "function" && !state._isOpened) { props.onClosed(event); } } function handleTouchStart(e) { const {clientX, clientY} = e.touches[0]; if (props.disabled) return; getDomInfo(); startX.value = clientX; startY.value = clientY; isTouching.value = true; } function handleTouchMove(e) { if (_isEmpty(domInfo.value)) { return; } const {top, bottom, left, right} = domInfo.value; const {clientX, clientY, pageX, pageY} = e.touches[0]; const x = Math.abs(clientX - startX.value); const y = Math.abs(clientY - startY.value); const inDom = _inRange(pageX, left, right) && _inRange(pageY, top, bottom); if (!isMoving.value && inDom) { isMoving.value = y === 0 || x / y >= Number.parseFloat(Math.tan(45 * Math.PI / 180).toFixed(2)); } if (isTouching.value && isMoving.value) { e.preventDefault(); const offsetSize = clientX - startX.value; const isRight = offsetSize > 0; if (state.offsetSize === 0 && isRight) return; const value = endValue.value + offsetSize; state.offsetSize = value >= 0 ? 0 : value; } } function handleTouchEnd(event) { isTouching.value = false; const {offsetSize} = state; endValue.value = offsetSize; const breakpoint = maxOffsetSize.value / 2; const absOffsetSize = Math.abs(offsetSize); if (absOffsetSize > breakpoint) { _reset(true); handleOpened(event); return; } _reset(false); handleClosed(event); } function handleDomInfo({width}) { const {_isOpened} = state; maxOffsetSize.value = width; _reset(_isOpened); } function handleClick(item, index, event) { if (typeof props.onClick === "function") { props.onClick(item, index, event); } if (props.autoClose) { _reset(false); handleClosed(event); } } return () => { return h(View, mergeProps(attrs, { id: `swipeAction-${state.componentId}`, class: "at-swipe-action", onTouchmove: handleTouchMove, onTouchend: handleTouchEnd, onTouchstart: handleTouchStart }), { default: () => [ h(View, { class: actionContentClass.value, style: transformStyle.value }, {default: () => slots.default && slots.default()}), Array.isArray(props.options) && props.options.length > 0 && h(AtSwipeActionOptions, { options: props.options, componentId: state.componentId, onQueryedDom: handleDomInfo }, { default: () => props.options.map((item, key) => h(View, { key: `${item.text}-${key}`, class: genActionItemClass.value(item), style: item.style, onTap: (e) => handleClick(item, key, e) }, { default: () => [ h(Text, { class: "option__text" }, {default: () => item.text}) ] })) }) ] }); }; } }); var swipe_action_default = AtSwipeAction; export { swipe_action_default as default };