| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- // @ts-nocheck
- import { raf } from '@/uni_modules/lime-shared/raf';
- // #ifndef UNI-APP-X
- import { watchEffect, ref, nextTick } from '@/uni_modules/lime-shared/vue'
- // #endif
- export type TransitionEmitStatus = "before-enter" | "enter" | "after-enter" | "before-leave" | "leave" | "after-leave"
- export type TransitionStatus = '' | 'enter' | 'leave';
- export type UseTransitionOptions = {
- element ?: Ref<UniElement | null>,
- enterClass ?: string,
- enterActiveClass ?: string,
- enterToClass ?: string,
- leaveClass ?: string,
- leaveActiveClass ?: string,
- leaveToClass ?: string,
- appear ?: boolean,
- defaultName ?: string,
- name ?: () => string,
- visible ?: () => boolean,
- emits ?: (name : TransitionEmitStatus) => void,
- onNextTick ?: (name : TransitionEmitStatus) => Promise<void>,
- duration ?: number
- removeClasses?: boolean;
- }
- type ClassNameMap = Map<string, string>;
- export type UseTransitionReturn = {
- state : Ref<boolean>,
- display : Ref<boolean>,
- inited : Ref<boolean>,
- classes : Ref<string>,
- name : Ref<string>,
- finished : () => void,
- toggle : (v : boolean) => void,
- }
- export function useTransition(options : UseTransitionOptions) : UseTransitionReturn {
- const state = ref(false);
- const display = ref(false);
- const inited = ref(false);
- const classes = ref('');
- const name = ref(options.defaultName ?? 'fade');
- const enterClass = options.enterClass ?? '';
- const enterActiveClass = options.enterActiveClass ?? '';
- const enterToClass = options.enterToClass ?? '';
- const leaveActiveClass = options.leaveActiveClass ?? '';
- const leaveToClass = options.leaveToClass ?? '';
- const leaveClass = options.leaveClass ?? '';
- const appear = options.appear ?? false
- const duration = options.duration ?? 300;
- let status : TransitionStatus = '';
- let isTransitionEnd = false;
- let isTransitioning = false;
- let timeoutId = -1
- const emitEvent = (event : TransitionEmitStatus) => {
- options.emits?.(event);
- };
- // 结束
- const finished = () => {
- if (isTransitionEnd) return;
- isTransitionEnd = true;
-
- if (options.removeClasses ?? false) {
- classes.value = '';
- }
- emitEvent(`after-${status}`)
-
- // classes.value = ''
- if (display.value && !state.value) {
- display.value = false
- }
- }
- const sleep = () : Promise<void> => {
- return new Promise((resolve) => {
- nextTick(() => {
- raf(() => {
- // #ifdef APP-ANDROID || APP-IOS || APP-HARMONY
- if (options.element?.value != null) {
- options.element?.value?.getBoundingClientRectAsync()?.then(res => {
- resolve()
- })
- } else {
- resolve()
- }
- // #endif
- // #ifndef APP-ANDROID || APP-IOS || APP-HARMONY
- resolve()
- // #endif
- })
- })
- })
- }
- const getClassNames = (name : string) : ClassNameMap => {
- return new Map<string, string>([
- ['enter', `l-${name}-enter l-${name}-enter-active ${enterClass} ${enterActiveClass}`],
- ['enter-to', `l-${name}-enter-to l-${name}-enter-active ${enterToClass} ${enterActiveClass}`],
- ['leave', `l-${name}-leave l-${name}-leave-active ${leaveClass} ${leaveActiveClass}`],
- ['leave-to', `l-${name}-leave-to l-${name}-leave-active ${leaveToClass} ${leaveActiveClass}`]
- ])
- };
- const transitionQueue = ref<TransitionStatus[]>([]);
- const performTransition = async (newStatus : TransitionStatus, eventName : TransitionStatus) => {
- if (status == newStatus) return
- transitionQueue.value.push(newStatus);
- if (isTransitioning) return;
- isTransitioning = true;
- // 防止因结束 又切换为开始导致闪烁
- isTransitionEnd = true;
- while (transitionQueue.value.length > 0) {
- const currentStatus = transitionQueue.value.shift()!;
- status = currentStatus;
- emitEvent(`before-${eventName}`);
-
- // IOS hbx4.76如果时间过短会卡住
- await sleep();
- await sleep();
- await sleep();
- await sleep();
- await sleep();
-
- if (status != currentStatus) continue;
- const classNames = getClassNames(name.value);
- inited.value = true;
- display.value = true;
- // const executeBeforeTick = options.onNextTick?.(`before-${eventName}`);
- // if (executeBeforeTick != null) {
- // await executeBeforeTick;
- // }
- classes.value = classNames.get(eventName)!;
- emitEvent(eventName);
- const executeAfterTick = options.onNextTick?.(eventName);
- if (executeAfterTick != null) {
- await executeAfterTick;
- }
- await sleep();
- // #ifdef MP
- await sleep();
- await sleep();
- // #endif
- if (status != currentStatus) continue;
- classes.value = classNames.get(`${eventName}-to`)!;
- // isTransitionEnd = false;
- // 防止最后无法关闭
- if (status == 'leave') {
- setTimeout(() => {
- finished()
- }, duration)
- }
- }
- // 不延迟 会导致快速切换时 因display none 闪烁
- clearTimeout(timeoutId)
- timeoutId = setTimeout(() => {
- if (transitionQueue.value.length == 0 && status == newStatus) {
- isTransitionEnd = false;
- }
- }, duration * 0.8)
- isTransitioning = false;
- }
- // 定义进入过渡的函数
- const enter = () => {
- performTransition('enter', 'enter');
- }
- const leave = () => {
- performTransition('leave', 'leave');
- }
- let init = false;
- watchEffect(() => {
- if (options.visible == null) return
- state.value = options.visible!();
- if (!appear && !init) {
- init = true
- return
- }
- if (state.value) {
- enter()
- } else {
- leave()
- }
- })
- watchEffect(() => {
- if (options.name == null) return
- name.value = options.name!()
- })
- const toggle = (v : boolean) => {
- state.value = v
- if (v) {
- enter()
- } else {
- leave()
- }
- }
- return {
- state,
- inited,
- display,
- classes,
- name,
- finished,
- toggle
- } as UseTransitionReturn
- }
|