初始版本提交
This commit is contained in:
27
src/components/Transition/index.ts
Normal file
27
src/components/Transition/index.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { createSimpleTransition, createJavascriptTransition } from './src/CreateTransition';
|
||||
|
||||
import ExpandTransitionGenerator from './src/ExpandTransition';
|
||||
|
||||
export { default as CollapseTransition } from './src/CollapseTransition.vue';
|
||||
|
||||
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(''),
|
||||
);
|
||||
78
src/components/Transition/src/CollapseTransition.vue
Normal file
78
src/components/Transition/src/CollapseTransition.vue
Normal file
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<transition mode="out-in" v-on="on">
|
||||
<slot></slot>
|
||||
</transition>
|
||||
</template>
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
import { addClass, removeClass } from '/@/utils/domUtils';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'CollapseTransition',
|
||||
setup() {
|
||||
return {
|
||||
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>
|
||||
73
src/components/Transition/src/CreateTransition.tsx
Normal file
73
src/components/Transition/src/CreateTransition.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
import type { PropType } from 'vue';
|
||||
|
||||
import { defineComponent, Transition, TransitionGroup } from 'vue';
|
||||
import { getSlot } from '/@/utils/helper/tsxHelper';
|
||||
|
||||
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: HTMLElement) => {
|
||||
el.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>
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
}
|
||||
89
src/components/Transition/src/ExpandTransition.ts
Normal file
89
src/components/Transition/src/ExpandTransition.ts
Normal file
@ -0,0 +1,89 @@
|
||||
/**
|
||||
* 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');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user