You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
188 lines
5.2 KiB
Vue
188 lines
5.2 KiB
Vue
<template>
|
|
<view v-if="inited" :class="rootClass" :style="style" @transitionend="onTransitionEnd" @click="handleClick">
|
|
<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, requestAnimationFrame } from '../common/util'
|
|
|
|
const getClassNames = (name) => {
|
|
if (!name) {
|
|
return {
|
|
enter: `${props.enterClass} ${props.enterActiveClass}`,
|
|
'enter-to': `${props.enterToClass} ${props.enterActiveClass}`,
|
|
leave: `${props.leaveClass} ${props.leaveActiveClass}`,
|
|
'leave-to': `${props.leaveToClass} ${props.leaveActiveClass}`
|
|
}
|
|
}
|
|
|
|
return {
|
|
enter: `wd-${name}-enter wd-${name}-enter-active`,
|
|
'enter-to': `wd-${name}-enter-to wd-${name}-enter-active`,
|
|
leave: `wd-${name}-leave wd-${name}-leave-active`,
|
|
'leave-to': `wd-${name}-leave-to wd-${name}-leave-active`
|
|
}
|
|
}
|
|
|
|
type TransitionName =
|
|
| 'fade'
|
|
| 'fade-down'
|
|
| 'fade-left'
|
|
| 'fade-right'
|
|
| 'fade-up'
|
|
| 'slide-down'
|
|
| 'slide-left'
|
|
| 'slide-right'
|
|
| 'slide-up'
|
|
| 'zoom-in'
|
|
| 'zoom-out'
|
|
|
|
interface Props {
|
|
show?: boolean
|
|
duration?: Record<string, number> | number | boolean
|
|
name?: TransitionName | ''
|
|
customStyle?: string
|
|
lazyRender?: boolean
|
|
customClass?: string
|
|
// 定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
|
|
enterClass?: string
|
|
// 定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
|
|
enterActiveClass?: string
|
|
// 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 enter-class 被移除),在过渡/动画完成之后移除。
|
|
enterToClass?: string
|
|
// 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
|
|
leaveClass?: string
|
|
// 定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
|
|
leaveActiveClass?: string
|
|
// 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 leave-class 被删除),在过渡/动画完成之后移除。
|
|
leaveToClass?: string
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
customClass: '',
|
|
customStyle: '',
|
|
show: false,
|
|
name: 'fade',
|
|
duration: 300,
|
|
lazyRender: true
|
|
})
|
|
|
|
// 初始化是否完成
|
|
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>('')
|
|
|
|
const emit = defineEmits(['click', 'before-enter', 'enter', 'before-leave', 'leave', 'after-leave', 'after-enter'])
|
|
|
|
const style = computed(() => {
|
|
return `-webkit-transition-duration:${currentDuration.value}ms;transition-duration:${currentDuration.value}ms;${
|
|
display.value ? '' : 'display: none;'
|
|
}${props.customStyle}`
|
|
})
|
|
|
|
const rootClass = computed(() => {
|
|
return `wd-transition ${props.customClass} ${classes.value}`
|
|
})
|
|
|
|
onBeforeMount(() => {
|
|
if (props.show) {
|
|
enter()
|
|
}
|
|
})
|
|
|
|
watch(
|
|
() => props.show,
|
|
(newVal) => {
|
|
observerShow(newVal)
|
|
},
|
|
{ deep: true, immediate: true }
|
|
)
|
|
|
|
function handleClick() {
|
|
emit('click')
|
|
}
|
|
|
|
function observerShow(value: boolean) {
|
|
value ? enter() : leave()
|
|
}
|
|
|
|
function enter() {
|
|
const classNames = getClassNames(props.name)
|
|
const duration = isObj(props.duration) ? (props.duration as any).enter : props.duration
|
|
status.value = 'enter'
|
|
emit('before-enter')
|
|
|
|
requestAnimationFrame(() => {
|
|
emit('enter')
|
|
classes.value = classNames.enter
|
|
currentDuration.value = duration
|
|
requestAnimationFrame(() => {
|
|
inited.value = true
|
|
display.value = true
|
|
requestAnimationFrame(() => {
|
|
transitionEnded.value = false
|
|
classes.value = classNames['enter-to']
|
|
})
|
|
})
|
|
})
|
|
}
|
|
function leave() {
|
|
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')
|
|
|
|
requestAnimationFrame(() => {
|
|
emit('leave')
|
|
classes.value = classNames.leave
|
|
currentDuration.value = duration
|
|
|
|
requestAnimationFrame(() => {
|
|
transitionEnded.value = false
|
|
setTimeout(() => onTransitionEnd(), currentDuration.value)
|
|
classes.value = classNames['leave-to']
|
|
})
|
|
})
|
|
}
|
|
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
|
|
}
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
@import './index.scss';
|
|
</style>
|