更新:登录功能
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
.wd-transition {
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
.wd-fade-enter,
|
||||
.wd-fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.wd-fade-enter-active,
|
||||
.wd-fade-leave-active {
|
||||
transition-property: opacity;
|
||||
}
|
||||
|
||||
.wd-fade-up-enter,
|
||||
.wd-fade-up-leave-to {
|
||||
transform: translate3d(0, 100%, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.wd-fade-down-enter,
|
||||
.wd-fade-down-leave-to {
|
||||
transform: translate3d(0, -100%, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.wd-fade-left-enter,
|
||||
.wd-fade-left-leave-to {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.wd-fade-right-enter,
|
||||
.wd-fade-right-leave-to {
|
||||
transform: translate3d(100%, 0, 0);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.wd-slide-up-enter,
|
||||
.wd-slide-up-leave-to {
|
||||
transform: translate3d(0, 100%, 0);
|
||||
}
|
||||
|
||||
.wd-slide-down-enter,
|
||||
.wd-slide-down-leave-to {
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
|
||||
.wd-slide-left-enter,
|
||||
.wd-slide-left-leave-to {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
|
||||
.wd-slide-right-enter,
|
||||
.wd-slide-right-leave-to {
|
||||
transform: translate3d(100%, 0, 0);
|
||||
}
|
||||
|
||||
.wd-zoom-in-enter,
|
||||
.wd-zoom-in-leave-to {
|
||||
opacity: 0;
|
||||
transform: scale(0.8);
|
||||
}
|
||||
|
||||
.wd-zoom-out-enter,
|
||||
.wd-zoom-out-leave-to {
|
||||
transform: scale(1.2);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.wd-zoom-in-enter-active,
|
||||
.wd-zoom-in-leave-active,
|
||||
.wd-zoom-out-enter-active,
|
||||
.wd-zoom-out-leave-active,
|
||||
.wd-fade-up-enter-active,
|
||||
.wd-fade-up-leave-active,
|
||||
.wd-fade-down-enter-active,
|
||||
.wd-fade-down-leave-active,
|
||||
.wd-fade-left-enter-active,
|
||||
.wd-fade-left-leave-active,
|
||||
.wd-fade-right-enter-active,
|
||||
.wd-fade-right-leave-active {
|
||||
transition-property: opacity, transform;
|
||||
}
|
||||
|
||||
.wd-slide-up-enter-active,
|
||||
.wd-slide-up-leave-active,
|
||||
.wd-slide-down-enter-active,
|
||||
.wd-slide-down-leave-active,
|
||||
.wd-slide-left-enter-active,
|
||||
.wd-slide-left-leave-active,
|
||||
.wd-slide-right-enter-active,
|
||||
.wd-slide-right-leave-active {
|
||||
transition-property: transform;
|
||||
}
|
||||
107
uni_modules/wot-design-uni/components/wd-transition/types.ts
Normal file
107
uni_modules/wot-design-uni/components/wd-transition/types.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2024-09-01 15:42:04
|
||||
* @LastEditTime: 2025-07-04 18:33:43
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: /wot-design-uni/src/uni_modules/wot-design-uni/components/wd-transition/types.ts
|
||||
* 记得注释
|
||||
*/
|
||||
import type { ExtractPropTypes, PropType } from 'vue'
|
||||
import { baseProps, makeBooleanProp, makeStringProp } from '../common/props'
|
||||
|
||||
export type TransitionName =
|
||||
| 'fade'
|
||||
| 'fade-down'
|
||||
| 'fade-left'
|
||||
| 'fade-right'
|
||||
| 'fade-up'
|
||||
| 'slide-down'
|
||||
| 'slide-left'
|
||||
| 'slide-right'
|
||||
| 'slide-up'
|
||||
| 'zoom-in'
|
||||
| 'zoom-out'
|
||||
|
||||
export const transitionProps = {
|
||||
...baseProps,
|
||||
|
||||
/**
|
||||
* 是否展示组件
|
||||
* 类型:boolean
|
||||
* 默认值:false
|
||||
*/
|
||||
show: makeBooleanProp(false),
|
||||
|
||||
/**
|
||||
* 动画执行时间
|
||||
* 类型:number | boolean | Record<string, number>
|
||||
* 默认值:300 (毫秒)
|
||||
*/
|
||||
duration: {
|
||||
type: [Object, Number, Boolean] as PropType<Record<string, number> | number | boolean>,
|
||||
default: 300
|
||||
},
|
||||
/**
|
||||
* 弹层内容懒渲染,触发展示时才渲染内容
|
||||
* 类型:boolean
|
||||
* 默认值:false
|
||||
*/
|
||||
lazyRender: makeBooleanProp(false),
|
||||
/**
|
||||
* 动画类型
|
||||
* 类型:string
|
||||
* 可选值:fade / fade-up / fade-down / fade-left / fade-right / slide-up / slide-down / slide-left / slide-right / zoom-in
|
||||
* 默认值:'fade'
|
||||
*/
|
||||
name: [String, Array] as PropType<TransitionName | TransitionName[]>,
|
||||
/**
|
||||
* 是否在动画结束时销毁子节点(display: none)
|
||||
* 类型:boolean
|
||||
* 默认值:false
|
||||
*/
|
||||
destroy: makeBooleanProp(true),
|
||||
/**
|
||||
* 进入过渡的开始状态
|
||||
* 类型:string
|
||||
*/
|
||||
enterClass: makeStringProp(''),
|
||||
|
||||
/**
|
||||
* 进入过渡的激活状态
|
||||
* 类型:string
|
||||
*/
|
||||
enterActiveClass: makeStringProp(''),
|
||||
|
||||
/**
|
||||
* 进入过渡的结束状态
|
||||
* 类型:string
|
||||
*/
|
||||
enterToClass: makeStringProp(''),
|
||||
|
||||
/**
|
||||
* 离开过渡的开始状态
|
||||
* 类型:string
|
||||
*/
|
||||
leaveClass: makeStringProp(''),
|
||||
|
||||
/**
|
||||
* 离开过渡的激活状态
|
||||
* 类型:string
|
||||
*/
|
||||
leaveActiveClass: makeStringProp(''),
|
||||
|
||||
/**
|
||||
* 离开过渡的结束状态
|
||||
* 类型:string
|
||||
*/
|
||||
leaveToClass: makeStringProp(''),
|
||||
/**
|
||||
* 是否阻止触摸滚动
|
||||
* 类型:boolean
|
||||
* 默认值:false
|
||||
*/
|
||||
disableTouchMove: makeBooleanProp(false)
|
||||
}
|
||||
|
||||
export type TransitionProps = ExtractPropTypes<typeof transitionProps>
|
||||
@@ -0,0 +1,232 @@
|
||||
<template>
|
||||
<view
|
||||
:class="rootClass"
|
||||
:style="style"
|
||||
@transitionend="onTransitionEnd"
|
||||
@click="handleClick"
|
||||
@touchmove.stop.prevent="noop"
|
||||
v-if="isShow && disableTouchMove"
|
||||
>
|
||||
<slot />
|
||||
</view>
|
||||
<view :class="rootClass" :style="style" @transitionend="onTransitionEnd" @click="handleClick" v-else-if="isShow && !disableTouchMove">
|
||||
<slot />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'wd-transition',
|
||||
options: {
|
||||
addGlobalClass: true,
|
||||
virtualHost: true,
|
||||
styleIsolation: 'shared'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onBeforeMount, ref, watch } from 'vue'
|
||||
import { isObj, isPromise, pause } from '../common/util'
|
||||
import { transitionProps, type TransitionName } from './types'
|
||||
import { AbortablePromise } from '../common/AbortablePromise'
|
||||
|
||||
const getClassNames = (name?: TransitionName | TransitionName[]) => {
|
||||
let enter: string = `${props.enterClass} ${props.enterActiveClass}`
|
||||
let enterTo: string = `${props.enterToClass} ${props.enterActiveClass}`
|
||||
let leave: string = `${props.leaveClass} ${props.leaveActiveClass}`
|
||||
let leaveTo: string = `${props.leaveToClass} ${props.leaveActiveClass}`
|
||||
|
||||
if (Array.isArray(name)) {
|
||||
for (let index = 0; index < name.length; index++) {
|
||||
enter = `wd-${name[index]}-enter wd-${name[index]}-enter-active ${enter}`
|
||||
enterTo = `wd-${name[index]}-enter-to wd-${name[index]}-enter-active ${enterTo}`
|
||||
leave = `wd-${name[index]}-leave wd-${name[index]}-leave-active ${leave}`
|
||||
leaveTo = `wd-${name[index]}-leave-to wd-${name[index]}-leave-active ${leaveTo}`
|
||||
}
|
||||
} else if (name) {
|
||||
enter = `wd-${name}-enter wd-${name}-enter-active ${enter}`
|
||||
enterTo = `wd-${name}-enter-to wd-${name}-enter-active ${enterTo}`
|
||||
leave = `wd-${name}-leave wd-${name}-leave-active ${leave}`
|
||||
leaveTo = `wd-${name}-leave-to wd-${name}-leave-active ${leaveTo}`
|
||||
}
|
||||
return {
|
||||
enter: enter,
|
||||
'enter-to': enterTo,
|
||||
leave: leave,
|
||||
'leave-to': leaveTo
|
||||
}
|
||||
}
|
||||
|
||||
const props = defineProps(transitionProps)
|
||||
const emit = defineEmits(['click', 'before-enter', 'enter', 'before-leave', 'leave', 'after-leave', 'after-enter'])
|
||||
|
||||
// 初始化是否完成
|
||||
const inited = ref<boolean>(false)
|
||||
// 是否显示
|
||||
const display = ref<boolean>(false)
|
||||
// 当前动画状态
|
||||
const status = ref<string>('')
|
||||
// 动画是否结束
|
||||
const transitionEnded = ref<boolean>(false)
|
||||
// 动画持续时间
|
||||
const currentDuration = ref<number>(300)
|
||||
// 类名
|
||||
const classes = ref<string>('')
|
||||
// 用于控制enter和leave的顺序执行
|
||||
const enterPromise = ref<AbortablePromise<void> | null>(null)
|
||||
|
||||
// 动画进入的生命周期
|
||||
const enterLifeCyclePromises = ref<AbortablePromise<unknown> | null>(null)
|
||||
|
||||
// 动画离开的生命周期
|
||||
const leaveLifeCyclePromises = ref<AbortablePromise<unknown> | null>(null)
|
||||
|
||||
const style = computed(() => {
|
||||
return `-webkit-transition-duration:${currentDuration.value}ms;transition-duration:${currentDuration.value}ms;${
|
||||
display.value || !props.destroy ? '' : 'display: none;'
|
||||
}${props.customStyle}`
|
||||
})
|
||||
|
||||
const rootClass = computed(() => {
|
||||
return `wd-transition ${props.customClass} ${classes.value}`
|
||||
})
|
||||
|
||||
const isShow = computed(() => {
|
||||
return !props.lazyRender || inited.value
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
if (props.show) {
|
||||
enter()
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.show,
|
||||
(newVal) => {
|
||||
handleShow(newVal)
|
||||
},
|
||||
{ deep: true }
|
||||
)
|
||||
|
||||
function handleClick() {
|
||||
emit('click')
|
||||
}
|
||||
|
||||
function handleShow(value: boolean) {
|
||||
if (value) {
|
||||
handleAbortPromise()
|
||||
enter()
|
||||
} else {
|
||||
leave()
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 取消所有的promise
|
||||
*/
|
||||
function handleAbortPromise() {
|
||||
isPromise(enterPromise.value) && enterPromise.value.abort()
|
||||
isPromise(enterLifeCyclePromises.value) && enterLifeCyclePromises.value.abort()
|
||||
isPromise(leaveLifeCyclePromises.value) && leaveLifeCyclePromises.value.abort()
|
||||
enterPromise.value = null
|
||||
enterLifeCyclePromises.value = null
|
||||
leaveLifeCyclePromises.value = null
|
||||
}
|
||||
|
||||
function enter() {
|
||||
enterPromise.value = new AbortablePromise(async (resolve) => {
|
||||
try {
|
||||
const classNames = getClassNames(props.name)
|
||||
const duration = isObj(props.duration) ? (props.duration as any).enter : props.duration
|
||||
status.value = 'enter'
|
||||
emit('before-enter')
|
||||
enterLifeCyclePromises.value = pause()
|
||||
await enterLifeCyclePromises.value
|
||||
emit('enter')
|
||||
classes.value = classNames.enter
|
||||
currentDuration.value = duration
|
||||
enterLifeCyclePromises.value = pause()
|
||||
await enterLifeCyclePromises.value
|
||||
inited.value = true
|
||||
display.value = true
|
||||
enterLifeCyclePromises.value = pause()
|
||||
await enterLifeCyclePromises.value
|
||||
enterLifeCyclePromises.value = null
|
||||
transitionEnded.value = false
|
||||
classes.value = classNames['enter-to']
|
||||
resolve()
|
||||
} catch (error) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
}
|
||||
})
|
||||
}
|
||||
async function leave() {
|
||||
if (!enterPromise.value) {
|
||||
transitionEnded.value = false
|
||||
return onTransitionEnd()
|
||||
}
|
||||
try {
|
||||
await enterPromise.value
|
||||
if (!display.value) return
|
||||
const classNames = getClassNames(props.name)
|
||||
const duration = isObj(props.duration) ? (props.duration as any).leave : props.duration
|
||||
status.value = 'leave'
|
||||
emit('before-leave')
|
||||
currentDuration.value = duration
|
||||
leaveLifeCyclePromises.value = pause()
|
||||
await leaveLifeCyclePromises.value
|
||||
emit('leave')
|
||||
classes.value = classNames.leave
|
||||
leaveLifeCyclePromises.value = pause()
|
||||
await leaveLifeCyclePromises.value
|
||||
transitionEnded.value = false
|
||||
classes.value = classNames['leave-to']
|
||||
leaveLifeCyclePromises.value = setPromise(currentDuration.value)
|
||||
await leaveLifeCyclePromises.value
|
||||
leaveLifeCyclePromises.value = null
|
||||
onTransitionEnd()
|
||||
enterPromise.value = null
|
||||
} catch (error) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时器promise化
|
||||
* @param duration 持续时间ms
|
||||
*/
|
||||
function setPromise(duration: number) {
|
||||
return new AbortablePromise<void>((resolve) => {
|
||||
const timer = setTimeout(() => {
|
||||
clearTimeout(timer)
|
||||
resolve()
|
||||
}, duration)
|
||||
})
|
||||
}
|
||||
function onTransitionEnd() {
|
||||
if (transitionEnded.value) return
|
||||
|
||||
transitionEnded.value = true
|
||||
if (status.value === 'leave') {
|
||||
// 离开后触发
|
||||
emit('after-leave')
|
||||
} else if (status.value === 'enter') {
|
||||
// 进入后触发
|
||||
emit('after-enter')
|
||||
}
|
||||
|
||||
if (!props.show && display.value) {
|
||||
display.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function noop() {}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './index.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user