mirror of
https://gitee.com/wot-design-uni/wot-design-uni.git
synced 2025-12-06 17:18:40 +08:00
feat: ✨ 使用Transition重构Popup为center类型的Popup添加zoom-in动画 (#699)
* feat: ✨ 使用Transition重构Popup为center类型的Popup添加zoom-in动画 ✅ Closes: #687 * fix: 🐛 修复 Transition 动画类名重复的问题
This commit is contained in:
parent
5e55da4839
commit
0dd34d0649
@ -8,7 +8,21 @@
|
||||
`v-model` 为绑定值,表示是否展示弹出层。
|
||||
|
||||
```html
|
||||
<wd-popup v-model="show" custom-style="padding: 30px 40px;" @close="handleClose">内容</wd-popup>
|
||||
<wd-popup v-model="show" custom-style="border-radius:32rpx;" @close="handleClose">
|
||||
<text class="custom-txt">弹弹弹</text>
|
||||
</wd-popup>
|
||||
```
|
||||
```css
|
||||
.custom-txt {
|
||||
color: black;
|
||||
width: 400rpx;
|
||||
height: 400rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 40rpx;
|
||||
border-radius: 32rpx;
|
||||
}
|
||||
```
|
||||
|
||||
## 弹出位置
|
||||
@ -89,6 +103,7 @@ h5 滚动穿透不需要处理,组件已默认开启 `lock-scroll`。
|
||||
| hide-when-close | 是否当关闭时将弹出层隐藏(display: none) | boolean | - | true | - |
|
||||
| lazy-render | 弹层内容懒渲染,触发展示时才渲染内容 | boolean | - | true | - |
|
||||
| safe-area-inset-bottom | 弹出面板是否设置底部安全距离(iphone X 类型的机型) | boolean | - | false | - |
|
||||
| transition | 动画类型,参见 wd-transition 组件的name | string | fade / fade-up / fade-down / fade-left / fade-right / slide-up / slide-down / slide-left / slide-right / zoom-in | - | - |
|
||||
| lockScroll | 是否锁定背景滚动 | boolean | - | true | 0.1.30 |
|
||||
|
||||
## Events
|
||||
|
||||
13
src/App.vue
13
src/App.vue
@ -1,3 +1,12 @@
|
||||
<!--
|
||||
* @Author: weisheng
|
||||
* @Date: 2024-10-12 13:07:08
|
||||
* @LastEditTime: 2024-11-08 13:14:48
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\App.vue
|
||||
* 记得注释
|
||||
-->
|
||||
<script setup lang="ts">
|
||||
import { onLaunch, onShow, onHide, onThemeChange } from '@dcloudio/uni-app'
|
||||
import { useDark } from './store'
|
||||
@ -7,7 +16,7 @@ onThemeChange((option) => {
|
||||
darkMode.setDark(option.theme === 'dark')
|
||||
})
|
||||
|
||||
onLaunch((ctx) => {
|
||||
onLaunch(() => {
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
darkMode.setDark(systemInfo.theme === 'dark')
|
||||
|
||||
@ -18,8 +27,6 @@ onLaunch((ctx) => {
|
||||
// 处理收到的消息
|
||||
if (typeof event.data === 'boolean') {
|
||||
darkMode.setDark(event.data)
|
||||
} else {
|
||||
darkMode.setDark(false)
|
||||
}
|
||||
})
|
||||
// #endif
|
||||
|
||||
@ -45,7 +45,9 @@
|
||||
</wd-cell-group>
|
||||
</demo-block>
|
||||
|
||||
<wd-popup v-model="show1" custom-style="padding: 30px 40px;" @close="handleClose1"><text class="custom-txt">内容</text></wd-popup>
|
||||
<wd-popup v-model="show1" @close="handleClose1" custom-style="border-radius:32rpx;">
|
||||
<text class="custom-txt">弹弹弹</text>
|
||||
</wd-popup>
|
||||
<wd-popup v-model="show2" position="top" custom-style="height: 200px;" @close="handleClose2"></wd-popup>
|
||||
<wd-popup v-model="show3" position="right" custom-style="width: 200px;" @close="handleClose3"></wd-popup>
|
||||
<wd-popup v-model="show4" position="bottom" custom-style="height: 200px;" @close="handleClose4"></wd-popup>
|
||||
@ -168,5 +170,12 @@ function handleClose10() {
|
||||
|
||||
.custom-txt {
|
||||
color: black;
|
||||
width: 400rpx;
|
||||
height: 400rpx;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 40rpx;
|
||||
border-radius: 32rpx;
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
</demo-block>
|
||||
<demo-block title="Zoom 动画">
|
||||
<wd-button @click="zoomIn">zoom-in</wd-button>
|
||||
<wd-button @click="zoomOut">zoom-out</wd-button>
|
||||
</demo-block>
|
||||
<demo-block title="自定义动画">
|
||||
<wd-button @click="custom">custom</wd-button>
|
||||
@ -25,7 +26,6 @@
|
||||
|
||||
<wd-transition
|
||||
:show="customShow"
|
||||
name=""
|
||||
:duration="{ enter: 700, leave: 1000 }"
|
||||
enter-class="custom-enter"
|
||||
enter-active-class="custom-enter-active"
|
||||
@ -39,10 +39,11 @@
|
||||
</view>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { TransitionName } from '@/uni_modules/wot-design-uni/components/wd-transition/types'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const show = ref<boolean>(false)
|
||||
const name = ref<any>('')
|
||||
const name = ref<TransitionName>()
|
||||
const customShow = ref<boolean>(false)
|
||||
function fade() {
|
||||
transition('fade')
|
||||
@ -74,13 +75,16 @@ function slideRight() {
|
||||
function zoomIn() {
|
||||
transition('zoom-in')
|
||||
}
|
||||
function zoomOut() {
|
||||
transition('zoom-out')
|
||||
}
|
||||
function custom() {
|
||||
customShow.value = true
|
||||
setTimeout(() => {
|
||||
customShow.value = false
|
||||
}, 1200)
|
||||
}
|
||||
function transition(transition: string) {
|
||||
function transition(transition: TransitionName) {
|
||||
name.value = transition
|
||||
show.value = true
|
||||
setTimeout(() => {
|
||||
|
||||
@ -103,6 +103,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* 定义状态(m) */
|
||||
@mixin mdeep($modifier...) {
|
||||
$selectors: "";
|
||||
|
||||
@each $item in $modifier {
|
||||
$selectors: #{$selectors + & + $modifierSeparator + $item + ","};
|
||||
}
|
||||
|
||||
@at-root {
|
||||
:deep() {
|
||||
#{$selectors} {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 对于需要需要嵌套在 m 底下的 e,调用这个混合宏,一般在切换整个组件的状态,如切换颜色的时候 */
|
||||
@mixin me($element...) {
|
||||
$selector: &;
|
||||
|
||||
@ -1,23 +1,33 @@
|
||||
@import './../common/abstracts/_mixin.scss';
|
||||
@import './../common/abstracts/variable.scss';
|
||||
@import '../wd-overlay/index.scss';
|
||||
|
||||
.wot-theme-dark {
|
||||
@include b(popup) {
|
||||
background: $-dark-background2;
|
||||
@include b(popup-wrapper) {
|
||||
:deep() {
|
||||
.wd-popup {
|
||||
background: $-dark-background2;
|
||||
}
|
||||
|
||||
@include e(close) {
|
||||
color: $-dark-color;
|
||||
.wd-popup__close {
|
||||
color: $-dark-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include b(popup) {
|
||||
position: fixed;
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
background: #fff;
|
||||
@include b(popup-wrapper) {
|
||||
:deep() {
|
||||
.wd-popup {
|
||||
position: fixed;
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
background: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@include b(popup) {
|
||||
@include edeep(close) {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
@ -27,86 +37,48 @@
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
@include m(center) {
|
||||
@include mdeep(center) {
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
transform-origin: 0% 0%;
|
||||
|
||||
&.wd-zoom-in-enter,
|
||||
&.wd-zoom-in-leave-to {
|
||||
transform: scale(0.8) translate3d(-50%, -50%, 0) !important;
|
||||
}
|
||||
|
||||
@include when(deep) {
|
||||
|
||||
&.wd-zoom-in-enter,
|
||||
&.wd-zoom-in-leave-to {
|
||||
transform: scale(0.1) translate3d(-50%, -50%, 0) !important;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@include m(left) {
|
||||
@include mdeep(left) {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
@include m(right) {
|
||||
@include mdeep(right) {
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
@include m(top) {
|
||||
@include mdeep(top) {
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
@include m(bottom) {
|
||||
@include mdeep(bottom) {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.wd-center-enter-active,
|
||||
.wd-center-leave-active {
|
||||
transition-property: opacity;
|
||||
}
|
||||
|
||||
.wd-center-enter,
|
||||
.wd-center-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.wd-top-enter-active,
|
||||
.wd-top-leave-active,
|
||||
.wd-bottom-enter-active,
|
||||
.wd-bottom-leave-active,
|
||||
.wd-left-enter-active,
|
||||
.wd-left-leave-active,
|
||||
.wd-right-enter-active,
|
||||
.wd-right-enter-active {
|
||||
transition-property: transform;
|
||||
}
|
||||
|
||||
.wd-top-enter,
|
||||
.wd-top-leave-to {
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
|
||||
.wd-bottom-enter,
|
||||
.wd-bottom-leave-to {
|
||||
transform: translate3d(0, 100%, 0);
|
||||
}
|
||||
|
||||
.wd-left-enter,
|
||||
.wd-left-leave-to {
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
}
|
||||
|
||||
.wd-right-enter,
|
||||
.wd-right-leave-to {
|
||||
transform: translate3d(100%, 0, 0);
|
||||
}
|
||||
|
||||
.wd-zoom-in-enter-active,
|
||||
.wd-zoom-in-leave-active {
|
||||
transition-property: opacity, transform;
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.wd-zoom-in-enter,
|
||||
.wd-zoom-in-leave-to {
|
||||
opacity: 0;
|
||||
transform: translate3d(-50%, -50%, 0) scale(0.7);
|
||||
}
|
||||
@ -1,33 +1,49 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2024-03-18 11:22:03
|
||||
* @LastEditTime: 2024-03-18 15:29:43
|
||||
* @LastEditTime: 2024-11-08 12:55:58
|
||||
* @LastEditors: weisheng
|
||||
* @Description:
|
||||
* @FilePath: \wot-design-uni\src\uni_modules\wot-design-uni\components\wd-popup\types.ts
|
||||
* 记得注释
|
||||
*/
|
||||
import type { PropType } from 'vue'
|
||||
import { baseProps, makeBooleanProp, makeNumberProp, makeStringProp } from '../common/props'
|
||||
import type { TransitionName } from '../wd-transition/types'
|
||||
|
||||
export type PopupType = 'center' | 'top' | 'right' | 'bottom' | 'left'
|
||||
|
||||
export const popupProps = {
|
||||
...baseProps,
|
||||
transition: String,
|
||||
/**
|
||||
* 动画类型,参见 wd-transition 组件的name
|
||||
* 类型:string
|
||||
* 可选值:fade / fade-up / fade-down / fade-left / fade-right / slide-up / slide-down / slide-left / slide-right / zoom-in
|
||||
*/
|
||||
transition: String as PropType<TransitionName>,
|
||||
/**
|
||||
* 关闭按钮
|
||||
* 类型:boolean
|
||||
* 默认值:false
|
||||
*/
|
||||
closable: makeBooleanProp(false),
|
||||
/**
|
||||
* 弹出框的位置
|
||||
* 类型:string
|
||||
* 默认值:center
|
||||
* 可选值:center / top / right / bottom / left
|
||||
*/
|
||||
position: makeStringProp<PopupType>('center'),
|
||||
/**
|
||||
* 点击遮罩是否关闭
|
||||
* 类型:boolean
|
||||
* 默认值:true
|
||||
*/
|
||||
closeOnClickModal: makeBooleanProp(true),
|
||||
/**
|
||||
* 动画持续时间
|
||||
* 类型:number | boolean
|
||||
* 默认值:300
|
||||
*/
|
||||
duration: {
|
||||
type: [Number, Boolean],
|
||||
@ -35,22 +51,32 @@ export const popupProps = {
|
||||
},
|
||||
/**
|
||||
* 是否显示遮罩
|
||||
* 类型:boolean
|
||||
* 默认值:true
|
||||
*/
|
||||
modal: makeBooleanProp(true),
|
||||
/**
|
||||
* 设置层级
|
||||
* 类型:number
|
||||
* 默认值:10
|
||||
*/
|
||||
zIndex: makeNumberProp(10),
|
||||
/**
|
||||
* 是否当关闭时将弹出层隐藏(display: none)
|
||||
* 类型:boolean
|
||||
* 默认值:true
|
||||
*/
|
||||
hideWhenClose: makeBooleanProp(true),
|
||||
/**
|
||||
* 遮罩样式
|
||||
* 类型:string
|
||||
* 默认值:''
|
||||
*/
|
||||
modalStyle: makeStringProp(''),
|
||||
/**
|
||||
* 弹出面板是否设置底部安全距离(iphone X 类型的机型)
|
||||
* 类型:boolean
|
||||
* 默认值:false
|
||||
*/
|
||||
safeAreaInsetBottom: makeBooleanProp(false),
|
||||
/**
|
||||
@ -59,10 +85,14 @@ export const popupProps = {
|
||||
modelValue: makeBooleanProp(false),
|
||||
/**
|
||||
* 弹层内容懒渲染,触发展示时才渲染内容
|
||||
* 类型:boolean
|
||||
* 默认值:true
|
||||
*/
|
||||
lazyRender: makeBooleanProp(true),
|
||||
/**
|
||||
* 是否锁定滚动
|
||||
* 类型:boolean
|
||||
* 默认值:true
|
||||
*/
|
||||
lockScroll: makeBooleanProp(true)
|
||||
}
|
||||
|
||||
@ -1,17 +1,33 @@
|
||||
<template>
|
||||
<wd-overlay
|
||||
v-if="modal"
|
||||
:show="modelValue"
|
||||
:z-index="zIndex"
|
||||
:lock-scroll="lockScroll"
|
||||
:duration="duration"
|
||||
:custom-style="modalStyle"
|
||||
@click="handleClickModal"
|
||||
@touchmove="noop"
|
||||
/>
|
||||
<view v-if="!lazyRender || inited" :class="rootClass" :style="style" @transitionend="onTransitionEnd">
|
||||
<slot />
|
||||
<wd-icon v-if="closable" custom-class="wd-popup__close" name="add" @click="close" />
|
||||
<view class="wd-popup-wrapper">
|
||||
<wd-overlay
|
||||
v-if="modal"
|
||||
:show="modelValue"
|
||||
:z-index="zIndex"
|
||||
:lock-scroll="lockScroll"
|
||||
:duration="duration"
|
||||
:custom-style="modalStyle"
|
||||
@click="handleClickModal"
|
||||
@touchmove="noop"
|
||||
/>
|
||||
<wd-transition
|
||||
:lazy-render="lazyRender"
|
||||
:custom-class="rootClass"
|
||||
:custom-style="style"
|
||||
:duration="duration"
|
||||
:show="modelValue"
|
||||
:name="transitionName"
|
||||
:destroy="hideWhenClose"
|
||||
@before-enter="emit('before-enter')"
|
||||
@enter="emit('enter')"
|
||||
@after-enter="emit('after-enter')"
|
||||
@before-leave="emit('before-leave')"
|
||||
@leave="emit('leave')"
|
||||
@after-leave="emit('after-leave')"
|
||||
>
|
||||
<slot />
|
||||
<wd-icon v-if="closable" custom-class="wd-popup__close" name="add" @click="close" />
|
||||
</wd-transition>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@ -29,9 +45,9 @@ export default {
|
||||
<script lang="ts" setup>
|
||||
import wdIcon from '../wd-icon/wd-icon.vue'
|
||||
import wdOverlay from '../wd-overlay/wd-overlay.vue'
|
||||
import { computed, onBeforeMount, ref, watch } from 'vue'
|
||||
import { isObj, requestAnimationFrame } from '../common/util'
|
||||
import { computed, onBeforeMount, ref } from 'vue'
|
||||
import { popupProps } from './types'
|
||||
import type { TransitionName } from '../wd-transition/types'
|
||||
|
||||
const props = defineProps(popupProps)
|
||||
const emit = defineEmits([
|
||||
@ -46,53 +62,42 @@ const emit = defineEmits([
|
||||
'close'
|
||||
])
|
||||
|
||||
const getClassNames = (name?: string) => {
|
||||
if (!name) {
|
||||
return {
|
||||
enter: 'enter-class enter-active-class',
|
||||
'enter-to': 'enter-to-class enter-active-class',
|
||||
leave: 'leave-class leave-active-class',
|
||||
'leave-to': 'leave-to-class leave-active-class'
|
||||
}
|
||||
/**
|
||||
* 弹出位置
|
||||
*/
|
||||
const transitionName = computed<TransitionName | TransitionName[]>(() => {
|
||||
if (props.transition) {
|
||||
return props.transition
|
||||
}
|
||||
|
||||
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`
|
||||
if (props.position === 'center') {
|
||||
return ['zoom-in', 'fade']
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化是否完成
|
||||
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>('')
|
||||
if (props.position === 'left') {
|
||||
return 'slide-left'
|
||||
}
|
||||
if (props.position === 'right') {
|
||||
return 'slide-right'
|
||||
}
|
||||
if (props.position === 'bottom') {
|
||||
return 'slide-up'
|
||||
}
|
||||
if (props.position === 'top') {
|
||||
return 'slide-down'
|
||||
}
|
||||
return 'slide-up'
|
||||
})
|
||||
|
||||
const safeBottom = ref<number>(0)
|
||||
|
||||
const name = ref<string>('') // 动画名
|
||||
|
||||
const style = computed(() => {
|
||||
return `z-index: ${props.zIndex}; padding-bottom: ${safeBottom.value}px; -webkit-transition-duration: ${
|
||||
currentDuration.value
|
||||
}ms; transition-duration: ${currentDuration.value}ms; ${display.value || !props.hideWhenClose ? '' : 'display: none;'} ${props.customStyle}`
|
||||
return `z-index:${props.zIndex}; padding-bottom: ${safeBottom.value}px;${props.customStyle}`
|
||||
})
|
||||
|
||||
const rootClass = computed(() => {
|
||||
return `wd-popup wd-popup--${props.position} ${props.customClass || ''} ${classes.value || ''}`
|
||||
return `wd-popup wd-popup--${props.position} ${!props.transition && props.position === 'center' ? 'is-deep' : ''} ${props.customClass || ''}`
|
||||
})
|
||||
|
||||
onBeforeMount(() => {
|
||||
observerTransition()
|
||||
if (props.safeAreaInsetBottom) {
|
||||
const { safeArea, screenHeight, safeAreaInsets } = uni.getSystemInfoSync()
|
||||
|
||||
@ -107,95 +112,8 @@ onBeforeMount(() => {
|
||||
safeBottom.value = 0
|
||||
}
|
||||
}
|
||||
if (props.modelValue) {
|
||||
enter()
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => props.modelValue,
|
||||
(newVal) => {
|
||||
observermodelValue(newVal)
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
|
||||
watch(
|
||||
[() => props.position, () => props.transition],
|
||||
() => {
|
||||
observerTransition()
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
|
||||
function observermodelValue(value: boolean) {
|
||||
value ? enter() : leave()
|
||||
}
|
||||
|
||||
function enter() {
|
||||
const classNames = getClassNames(props.transition || props.position)
|
||||
const duration = props.transition === 'none' ? 0 : 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.transition || props.position)
|
||||
const duration = props.transition === 'none' ? 0 : 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
|
||||
const timer = setTimeout(() => {
|
||||
onTransitionEnd()
|
||||
clearTimeout(timer)
|
||||
}, 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.modelValue && display.value) {
|
||||
display.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function observerTransition() {
|
||||
const { transition, position } = props
|
||||
name.value = transition || position
|
||||
}
|
||||
|
||||
function handleClickModal() {
|
||||
emit('click-modal')
|
||||
if (props.closeOnClickModal) {
|
||||
|
||||
@ -2,25 +2,14 @@
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
.wd-fade-enter-active,
|
||||
.wd-fade-leave-active {
|
||||
transition-property: opacity;
|
||||
}
|
||||
|
||||
.wd-fade-enter,
|
||||
.wd-fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.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-enter-active {
|
||||
transition-property: opacity, transform;
|
||||
.wd-fade-enter-active,
|
||||
.wd-fade-leave-active {
|
||||
transition-property: opacity;
|
||||
}
|
||||
|
||||
.wd-fade-up-enter,
|
||||
@ -47,17 +36,6 @@
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.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-enter-active {
|
||||
transition-property: transform;
|
||||
}
|
||||
|
||||
.wd-slide-up-enter,
|
||||
.wd-slide-up-leave-to {
|
||||
transform: translate3d(0, 100%, 0);
|
||||
@ -78,14 +56,40 @@
|
||||
transform: translate3d(100%, 0, 0);
|
||||
}
|
||||
|
||||
.wd-zoom-in-enter-active,
|
||||
.wd-zoom-in-leave-active {
|
||||
transition-property: opacity, transform;
|
||||
transform-origin: center center;
|
||||
}
|
||||
|
||||
.wd-zoom-in-enter,
|
||||
.wd-zoom-in-leave-to {
|
||||
opacity: 0;
|
||||
transform: scale(0.7);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1,5 +1,14 @@
|
||||
/*
|
||||
* @Author: weisheng
|
||||
* @Date: 2024-09-01 15:42:04
|
||||
* @LastEditTime: 2024-11-06 23:50:08
|
||||
* @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, makeNumberProp, makeStringProp } from '../common/props'
|
||||
import { baseProps, makeBooleanProp, makeStringProp } from '../common/props'
|
||||
|
||||
export type TransitionName =
|
||||
| 'fade'
|
||||
@ -33,22 +42,25 @@ export const transitionProps = {
|
||||
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: makeStringProp<TransitionName | ''>('fade'),
|
||||
|
||||
name: [String, Array] as PropType<TransitionName | TransitionName[]>,
|
||||
/**
|
||||
* 是否延迟渲染子组件
|
||||
* 是否在动画结束时销毁子节点(display: none)
|
||||
* 类型:boolean
|
||||
* 默认值:true
|
||||
* 默认值:false
|
||||
*/
|
||||
lazyRender: makeBooleanProp(true),
|
||||
|
||||
destroy: makeBooleanProp(true),
|
||||
/**
|
||||
* 进入过渡的开始状态
|
||||
* 类型:string
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<view v-if="inited" :class="rootClass" :style="style" @transitionend="onTransitionEnd" @click="handleClick">
|
||||
<view v-if="!lazyRender || inited" :class="rootClass" :style="style" @transitionend="onTransitionEnd" @click="handleClick">
|
||||
<slot />
|
||||
</view>
|
||||
</template>
|
||||
@ -18,24 +18,33 @@ export default {
|
||||
<script lang="ts" setup>
|
||||
import { computed, onBeforeMount, ref, watch } from 'vue'
|
||||
import { isObj, isPromise, requestAnimationFrame } from '../common/util'
|
||||
import { transitionProps } from './types'
|
||||
import { transitionProps, type TransitionName } from './types'
|
||||
import { AbortablePromise } from '../common/AbortablePromise'
|
||||
|
||||
const getClassNames = (name?: string) => {
|
||||
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}`
|
||||
}
|
||||
}
|
||||
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: `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`
|
||||
enter: enter,
|
||||
'enter-to': enterTo,
|
||||
leave: leave,
|
||||
'leave-to': leaveTo
|
||||
}
|
||||
}
|
||||
|
||||
@ -65,7 +74,7 @@ const leaveLifeCyclePromises = ref<AbortablePromise<unknown> | null>(null)
|
||||
|
||||
const style = computed(() => {
|
||||
return `-webkit-transition-duration:${currentDuration.value}ms;transition-duration:${currentDuration.value}ms;${
|
||||
display.value ? '' : 'display: none;'
|
||||
display.value || !props.destroy ? '' : 'display: none;'
|
||||
}${props.customStyle}`
|
||||
})
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user