Skip to content
This repository has been archived by the owner on Aug 28, 2024. It is now read-only.

Commit

Permalink
feat: add transition demo (#280)
Browse files Browse the repository at this point in the history
  • Loading branch information
DesignHhuang committed Nov 23, 2023
1 parent 18fb3f4 commit e5a44e8
Show file tree
Hide file tree
Showing 23 changed files with 694 additions and 32 deletions.
47 changes: 47 additions & 0 deletions apps/admin/src/pages/demo/Transition.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<template>
<div class="p-2 h-100">
<div class="flex">
<VbenSelect
:options="options"
v-model:value="value"
placeholder="选择动画"
:style="{ width: '150px' }"
/>
<VbenButton type="primary" class="ml-4" @click="start">
start
</VbenButton>
</div>
<component :is="CustomTransition[value]">
<div class="box" v-show="show"></div>
</component>
</div>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { CustomTransition } from '@vben/components/index'
const options = Object.keys(CustomTransition).map((item) => {
const label = item.replace('Transition', '')
return {
label,
value: item,
}
})
const value = ref('FadeTransition')
const show = ref(true)
function start() {
show.value = false
setTimeout(() => {
show.value = true
}, 300)
}
</script>
<style lang="less" scoped>
.box {
width: 150px;
height: 150px;
margin-top: 20px;
background-color: rgb(126 170 236);
}
</style>
3 changes: 3 additions & 0 deletions packages/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,7 @@ export { default as CountDownInput } from './src/countdown-input/index.vue'
export { default as StrengthMeter } from './src/strength-meter/index.vue'
export { default as ClickOutside } from './src/click-outside/index.vue'

export { default as CollapseTransition } from './src/transition/collapse-transition.vue'
export { default as CustomTransition } from './src/transition/index'

export type { QrCodeActionType } from './src/qrcode/typing'
2 changes: 1 addition & 1 deletion packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"@vben/utils": "workspace:*",
"@zxcvbn-ts/core": "^3.0.4",
"qrcode": "^1.5.3",
"vue": "3.3.4",
"vue": "3.3.6",
"vue-router": "^4.2.4"
},
"devDependencies": {
Expand Down
72 changes: 72 additions & 0 deletions packages/components/src/transition/collapse-transition.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<template>
<transition mode="out-in" v-on="on">
<slot></slot>
</transition>
</template>
<script lang="ts" setup>
import { addClass, removeClass } from '@vben/utils'
defineOptions({ name: 'CollapseTransition' })
const on = {
beforeEnter(el) {
addClass(el, 'collapse-transition')
if (!el.dataset) el.dataset = {}
el.dataset.oldPaddingTop = el.style.paddingTop
el.dataset.oldPaddingBottom = el.style.paddingBottom
el.style.height = '0'
el.style.paddingTop = 0
el.style.paddingBottom = 0
},
enter(el) {
el.dataset.oldOverflow = el.style.overflow
if (el.scrollHeight !== 0) {
el.style.height = el.scrollHeight + 'px'
el.style.paddingTop = el.dataset.oldPaddingTop
el.style.paddingBottom = el.dataset.oldPaddingBottom
} else {
el.style.height = ''
el.style.paddingTop = el.dataset.oldPaddingTop
el.style.paddingBottom = el.dataset.oldPaddingBottom
}
el.style.overflow = 'hidden'
},
afterEnter(el) {
removeClass(el, 'collapse-transition')
el.style.height = ''
el.style.overflow = el.dataset.oldOverflow
},
beforeLeave(el) {
if (!el.dataset) el.dataset = {}
el.dataset.oldPaddingTop = el.style.paddingTop
el.dataset.oldPaddingBottom = el.style.paddingBottom
el.dataset.oldOverflow = el.style.overflow
el.style.height = el.scrollHeight + 'px'
el.style.overflow = 'hidden'
},
leave(el) {
if (el.scrollHeight !== 0) {
addClass(el, 'collapse-transition')
el.style.height = 0
el.style.paddingTop = 0
el.style.paddingBottom = 0
}
},
afterLeave(el) {
removeClass(el, 'collapse-transition')
el.style.height = ''
el.style.overflow = el.dataset.oldOverflow
el.style.paddingTop = el.dataset.oldPaddingTop
el.style.paddingBottom = el.dataset.oldPaddingBottom
},
}
</script>
82 changes: 82 additions & 0 deletions packages/components/src/transition/create-transition.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import type { PropType } from 'vue'

import { defineComponent, Transition, TransitionGroup } from 'vue'
import { getSlot } from '@vben/utils'

type Mode = 'in-out' | 'out-in' | 'default' | undefined

export function createSimpleTransition(
name: string,
origin = 'top center 0',
mode?: Mode,
) {
return defineComponent({
name,
props: {
group: {
type: Boolean as PropType<boolean>,
default: false,
},
mode: {
type: String as PropType<Mode>,
default: mode,
},
origin: {
type: String as PropType<string>,
default: origin,
},
},
setup(props, { slots, attrs }) {
const onBeforeEnter = (el: Element) => {
;(el as HTMLElement).style.transformOrigin = props.origin
}

return () => {
const Tag = !props.group ? Transition : TransitionGroup
return (
<Tag
name={name}
mode={props.mode}
{...attrs}
onBeforeEnter={onBeforeEnter}
>
{() => getSlot(slots)}
</Tag>
)
}
},
})
}
export function createJavascriptTransition(
name: string,
functions: Recordable,
mode: Mode = 'in-out',
) {
return defineComponent({
name,
props: {
mode: {
type: String as PropType<Mode>,
default: mode,
},
},
setup(props, { attrs, slots }) {
return () => {
return (
<Transition
name={name}
mode={props.mode}
{...attrs}
onBeforeEnter={functions.beforeEnter}
onEnter={functions.enter}
onLeave={functions.leave}
onAfterLeave={functions.afterLeave}
onLeaveCancelled={functions.afterLeave}
>
{() => getSlot(slots)}
</Transition>
)
}
},
})
}
91 changes: 91 additions & 0 deletions packages/components/src/transition/expand-transition.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* Makes the first character of a string uppercase
*/
export function upperFirst(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1)
}

interface HTMLExpandElement extends HTMLElement {
_parent?: (Node & ParentNode & HTMLElement) | null
_initialStyle: {
transition: string
overflow: string | null
height?: string | null
width?: string | null
}
}

export default function (expandedParentClass = '', x = false) {
const sizeProperty = x ? 'width' : ('height' as 'width' | 'height')
const offsetProperty = `offset${upperFirst(sizeProperty)}` as
| 'offsetHeight'
| 'offsetWidth'

return {
beforeEnter(el: HTMLExpandElement) {
el._parent = el.parentNode as (Node & ParentNode & HTMLElement) | null
el._initialStyle = {
transition: el.style.transition,
overflow: el.style.overflow,
[sizeProperty]: el.style[sizeProperty],
}
},

enter(el: HTMLExpandElement) {
const initialStyle = el._initialStyle

el.style.setProperty('transition', 'none', 'important')
el.style.overflow = 'hidden'
// const offset = `${el[offsetProperty]}px`;

// el.style[sizeProperty] = '0';

void el.offsetHeight // force reflow

el.style.transition = initialStyle.transition

if (expandedParentClass && el._parent) {
el._parent.classList.add(expandedParentClass)
}

requestAnimationFrame(() => {
// el.style[sizeProperty] = offset;
})
},

afterEnter: resetStyles,
enterCancelled: resetStyles,

leave(el: HTMLExpandElement) {
el._initialStyle = {
transition: '',
overflow: el.style.overflow,
[sizeProperty]: el.style[sizeProperty],
}

el.style.overflow = 'hidden'
el.style[sizeProperty] = `${el[offsetProperty]}px`
/* eslint-disable-next-line */
void el.offsetHeight // force reflow

requestAnimationFrame(() => (el.style[sizeProperty] = '0'))
},

afterLeave,
leaveCancelled: afterLeave,
}

function afterLeave(el: HTMLExpandElement) {
if (expandedParentClass && el._parent) {
el._parent.classList.remove(expandedParentClass)
}
resetStyles(el)
}

function resetStyles(el: HTMLExpandElement) {
const size = el._initialStyle[sizeProperty]
el.style.overflow = el._initialStyle.overflow!
if (size != null) el.style[sizeProperty] = size
Reflect.deleteProperty(el, '_initialStyle')
}
}
51 changes: 51 additions & 0 deletions packages/components/src/transition/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {
createSimpleTransition,
createJavascriptTransition,
} from './create-transition'
import ExpandTransitionGenerator from './expand-transition'

export const FadeTransition = createSimpleTransition('fade-transition')
export const ScaleTransition = createSimpleTransition('scale-transition')
export const SlideYTransition = createSimpleTransition('slide-y-transition')
export const ScrollYTransition = createSimpleTransition('scroll-y-transition')
export const SlideYReverseTransition = createSimpleTransition(
'slide-y-reverse-transition',
)
export const ScrollYReverseTransition = createSimpleTransition(
'scroll-y-reverse-transition',
)
export const SlideXTransition = createSimpleTransition('slide-x-transition')
export const ScrollXTransition = createSimpleTransition('scroll-x-transition')
export const SlideXReverseTransition = createSimpleTransition(
'slide-x-reverse-transition',
)
export const ScrollXReverseTransition = createSimpleTransition(
'scroll-x-reverse-transition',
)
export const ScaleRotateTransition = createSimpleTransition(
'scale-rotate-transition',
)
export const ExpandXTransition = createJavascriptTransition(
'expand-x-transition',
ExpandTransitionGenerator('', true),
)
export const ExpandTransition = createJavascriptTransition(
'expand-transition',
ExpandTransitionGenerator(''),
)

export default {
FadeTransition,
ScaleTransition,
SlideYTransition,
ScrollYTransition,
SlideYReverseTransition,
ScrollYReverseTransition,
SlideXTransition,
ScrollXTransition,
SlideXReverseTransition,
ScrollXReverseTransition,
ScaleRotateTransition,
ExpandXTransition,
ExpandTransition,
}
2 changes: 1 addition & 1 deletion packages/directives/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
},
"dependencies": {
"@vben/utils": "workspace:*",
"vue": "3.3.4"
"vue": "3.3.6"
},
"devDependencies": {
"@vben/types": "workspace:*"
Expand Down
2 changes: 1 addition & 1 deletion packages/grid-layouts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"@vben/utils": "workspace:*",
"@vben/vbencomponents": "workspace:*",
"pinia": "^2.1.6",
"vue": "3.3.4",
"vue": "3.3.6",
"vue-router": "^4.2.4"
},
"devDependencies": {
Expand Down
1 change: 1 addition & 0 deletions packages/locale/src/lang/en/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,5 +70,6 @@ export default {
accountCenter: 'Center',
accountSetting: 'Setting',
},
transition: 'Transition',
},
}
1 change: 1 addition & 0 deletions packages/locale/src/lang/zh-CN/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,6 @@ export default {
accountCenter: '个人中心',
accountSetting: '个人设置',
},
transition: '过渡动画',
},
}
Loading

0 comments on commit e5a44e8

Please sign in to comment.