From 11b6aa9b0329ef3405f600b8794584657d20bdb2 Mon Sep 17 00:00:00 2001 From: rex Date: Mon, 25 Feb 2019 16:01:21 +0800 Subject: [PATCH] [new feature] Transition: refactor with css transition --- example/pages/transition/index.js | 11 +- example/pages/transition/index.wxml | 12 +++ example/pages/transition/index.wxss | 13 ++- packages/mixins/transition.ts | 89 ++++++++++------ packages/overlay/index.less | 2 +- packages/overlay/index.ts | 4 + packages/overlay/index.wxml | 1 + packages/popup/README.md | 11 +- packages/popup/index.less | 133 +++++++++--------------- packages/popup/index.ts | 26 ++++- packages/popup/index.wxml | 7 +- packages/transition/README.md | 43 ++++++-- packages/transition/index.less | 154 ++++++++++------------------ packages/transition/index.ts | 16 +-- packages/transition/index.wxml | 6 +- 15 files changed, 280 insertions(+), 248 deletions(-) diff --git a/example/pages/transition/index.js b/example/pages/transition/index.js index 15deb1d5..87221029 100644 --- a/example/pages/transition/index.js +++ b/example/pages/transition/index.js @@ -3,7 +3,8 @@ import Page from '../../common/page'; Page({ data: { show: false, - name: 'fade' + name: 'fade', + showCustom: false }, onClickFade() { @@ -47,5 +48,13 @@ Page({ setTimeout(() => { this.setData({ show: false }); }, 500); + }, + + onClickCustom() { + this.setData({ showCustom: true }); + + setTimeout(() => { + this.setData({ showCustom: false }); + }, 500); } }); diff --git a/example/pages/transition/index.wxml b/example/pages/transition/index.wxml index c3887365..fc8506d0 100644 --- a/example/pages/transition/index.wxml +++ b/example/pages/transition/index.wxml @@ -8,10 +8,22 @@ + + + diff --git a/example/pages/transition/index.wxss b/example/pages/transition/index.wxss index b8266086..9cc41872 100644 --- a/example/pages/transition/index.wxss +++ b/example/pages/transition/index.wxss @@ -1,9 +1,20 @@ .block { + position: fixed; top: 50%; left: 50%; width: 100px; height: 100px; - position: fixed; margin: -50px 0 0 -50px; background-color: #1989fa; } + +.van-enter-active-class, +.van-leave-active-class { + transition-property: background-color, transform; +} + +.van-enter-class, +.van-leave-to-class { + background-color: red; + transform: rotate(-360deg) translate3d(-100%, -100%, 0); +} diff --git a/packages/mixins/transition.ts b/packages/mixins/transition.ts index a3845734..9349def7 100644 --- a/packages/mixins/transition.ts +++ b/packages/mixins/transition.ts @@ -1,4 +1,15 @@ -export const transition = function(showDefaultValue) { +import { isObj } from '../common/utils'; + +const getClassNames = (name: string) => ({ + enter: `van-${name}-enter van-${name}-enter-active enter-class enter-active-class`, + 'enter-to': `van-${name}-enter-to van-${name}-enter-active enter-to-class enter-active-class`, + leave: `van-${name}-leave van-${name}-leave-active leave-class leave-active-class`, + 'leave-to': `van-${name}-leave-to van-${name}-leave-active leave-to-class leave-active-class` +}); + +const requestAnimationFrame = (cb: Function) => setTimeout(cb, 1000 / 60); + +export const transition = function(showDefaultValue: boolean) { return Behavior({ properties: { customStyle: String, @@ -8,8 +19,14 @@ export const transition = function(showDefaultValue) { observer: 'observeShow' }, duration: { - type: Number, - value: 300 + type: [Number, Object], + value: 300, + observer: 'observeDuration' + }, + name: { + type: String, + value: 'fade', + observer: 'updateClasses' } }, @@ -17,53 +34,65 @@ export const transition = function(showDefaultValue) { type: '', inited: false, display: false, - supportAnimation: true + classNames: getClassNames('fade') }, attached() { if (this.data.show) { this.show(); } - - this.detectSupport(); }, methods: { - detectSupport() { - wx.getSystemInfo({ - success: info => { - if (info && info.system && info.system.indexOf('iOS 8') === 0) { - this.set({ supportAnimation: false }); - } - } - }); - }, - - observeShow(value) { + observeShow(value: boolean) { if (value) { this.show(); } else { - if (this.data.supportAnimation) { - this.set({ type: 'leave' }); - } else { - this.set({ display: false }); - } + this.leave(); } }, - show() { + updateClasses(name: string) { this.set({ - inited: true, - display: true, - type: 'enter' + classNames: getClassNames(name) }); }, - onAnimationEnd() { - if (!this.data.show) { - this.set({ - display: false + show() { + const { classNames, duration } = this.data; + + this.set({ + inited: true, + display: true, + classes: classNames.enter, + currentDuration: isObj(duration) ? duration.enter : duration + }).then(() => { + requestAnimationFrame(() => { + this.set({ + classes: classNames['enter-to'] + }); }); + }); + }, + + leave() { + const { classNames, duration } = this.data; + + this.set({ + classes: classNames.leave, + currentDuration: isObj(duration) ? duration.leave : duration + }).then(() => { + requestAnimationFrame(() => { + this.set({ + classes: classNames['leave-to'] + }); + }); + }); + }, + + onTransitionEnd() { + if (!this.data.show) { + this.set({ display: false }); } } } diff --git a/packages/overlay/index.less b/packages/overlay/index.less index 1802ade9..9e6fe17c 100644 --- a/packages/overlay/index.less +++ b/packages/overlay/index.less @@ -1,7 +1,7 @@ .van-overlay { position: fixed; top: 0; - left: 0; right: 0; bottom: 0; + left: 0; } diff --git a/packages/overlay/index.ts b/packages/overlay/index.ts index 86126230..a996c78b 100644 --- a/packages/overlay/index.ts +++ b/packages/overlay/index.ts @@ -6,6 +6,10 @@ VantComponent({ show: Boolean, mask: Boolean, customStyle: String, + duration: { + type: [Number, Object], + value: 300 + }, zIndex: { type: Number, value: 1 diff --git a/packages/overlay/index.wxml b/packages/overlay/index.wxml index 630afac6..31d222e4 100644 --- a/packages/overlay/index.wxml +++ b/packages/overlay/index.wxml @@ -2,6 +2,7 @@ show="{{ show }}" custom-class="van-overlay" custom-style="z-index: {{ zIndex }}; {{ mask ? 'background-color: rgba(0, 0, 0, .7);' : '' }}; {{ customStyle }}" + duration="{{ duration }}" bind:tap="onClick" catch:touchmove="noop" /> diff --git a/packages/popup/README.md b/packages/popup/README.md index 53e02a20..9d8897a8 100644 --- a/packages/popup/README.md +++ b/packages/popup/README.md @@ -50,7 +50,7 @@ Page({ | z-index | z-index 层级 | `Number` | `100` | | overlay | 是否显示背景蒙层 | `Boolean` | `true` | | position | 可选值为 `top` `bottom` `right` `left` | `String` | - | -| duration | 动画时长,单位为毫秒 | `Number` | `300` | +| duration | 动画时长,单位为毫秒 | `Number | Object` | `300` | | custom-style | 自定义弹出层样式 | `String` | `` | | overlay-style | 自定义背景蒙层样式 | `String` | `` | | close-on-click-overlay | 点击蒙层是否关闭 Popup | `Boolean` | `true` | @@ -68,12 +68,3 @@ Page({ | 类名 | 说明 | |-----------|-----------| | custom-class | 根节点样式类 | - -### 更新日志 - -| 版本 | 类型 | 内容 | -|-----------|-----------|-----------| -| 0.0.1 | feature | 新增组件 | -| 0.3.2 | feature | 支持退场动画 | -| 0.3.2 | feature | 新增 z-index 属性 | -| 0.3.3 | feature | 新增 custom-style 属性 | diff --git a/packages/popup/index.less b/packages/popup/index.less index d57465b2..8eb1343e 100644 --- a/packages/popup/index.less +++ b/packages/popup/index.less @@ -1,26 +1,28 @@ @import '../common/style/var.less'; .van-popup { + position: fixed; top: 50%; left: 50%; - position: fixed; max-height: 100%; overflow-y: auto; - box-sizing: border-box; background-color: @white; - -webkit-overflow-scrolling: touch; + box-sizing: border-box; animation: ease both; + -webkit-overflow-scrolling: touch; + transition-timing-function: ease; &--center { transform: translate3d(-50%, -50%, 0); } &--top { - width: 100%; top: 0; right: auto; bottom: auto; left: 50%; + width: 100%; + transform: translate3d(-50%, 0, 0); } &--right { @@ -28,14 +30,16 @@ right: 0; bottom: auto; left: auto; + transform: translate3d(0, -50%, 0); } &--bottom { - width: 100%; top: auto; - bottom: 0; right: auto; + bottom: 0; left: 50%; + width: 100%; + transform: translate3d(-50%, 0, 0); } &--left { @@ -43,6 +47,7 @@ right: auto; bottom: auto; left: 0; + transform: translate3d(0, -50%, 0); } &--safe { @@ -50,100 +55,64 @@ } } -@keyframes van-center-enter { - from { - opacity: 0; - } +.van-scale-enter-active, +.van-scale-leave-active { + transition-property: opacity, transform; } -@keyframes van-center-leave { - to { - opacity: 0; - } +.van-scale-enter, +.van-scale-leave-to { + opacity: 0; + transform: translate3d(-50%, -50%, 0) scale(0.7); } -@keyframes van-scale-enter { - from { - opacity: 0; - transform: translate3d(-50%, -50%, 0) scale(0.7); - } +.van-fade-enter-active, +.van-fade-leave-active { + transition-property: opacity; } -@keyframes van-scale-leave { - to { - opacity: 0; - transform: translate3d(-50%, -50%, 0) scale(0.7); - } +.van-fade-enter, +.van-fade-leave-to { + opacity: 0; } -@keyframes van-bottom-enter { - from { - transform: translate3d(-50%, 100%, 0); - } - to { - transform: translate3d(-50%, 0, 0); - } +.van-center-enter-active, +.van-center-leave-active { + transition-property: opacity; } -@keyframes van-bottom-leave { - from { - transform: translate3d(-50%, 0, 0); - } - to { - transform: translate3d(-50%, 100%, 0); - } +.van-center-enter, +.van-center-leave-to { + opacity: 0; } -@keyframes van-top-enter { - from { - transform: translate3d(-50%, -100%, 0); - } - to { - transform: translate3d(-50%, 0, 0); - } +.van-bottom-enter-active, +.van-bottom-leave-active, +.van-top-enter-active, +.van-top-leave-active, +.van-left-enter-active, +.van-left-leave-active, +.van-right-enter-active, +.van-right-leave-active { + transition-property: transform; } -@keyframes van-top-leave { - from { - transform: translate3d(-50%, 0, 0); - } - to { - transform: translate3d(-50%, -100%, 0); - } +.van-bottom-enter, +.van-bottom-leave-to { + transform: translate3d(-50%, 100%, 0); } -@keyframes van-left-enter { - from { - transform: translate3d(-100%, -50%, 0); - } - to { - transform: translate3d(0, -50%, 0); - } +.van-top-enter, +.van-top-leave-to { + transform: translate3d(-50%, -100%, 0); } -@keyframes van-left-leave { - from { - transform: translate3d(0, -50%, 0); - } - to { - transform: translate3d(-100%, -50%, 0); - } +.van-left-enter, +.van-left-leave-to { + transform: translate3d(-100%, -50%, 0); } -@keyframes van-right-enter { - from { - transform: translate3d(100%, -50%, 0); - } - to { - transform: translate3d(0, -50%, 0); - } -} - -@keyframes van-right-leave { - from { - transform: translate3d(0, -50%, 0); - } - to { - transform: translate3d(100%, -50%, 0); - } +.van-right-enter, +.van-right-leave-to { + transform: translate3d(100%, -50%, 0); } diff --git a/packages/popup/index.ts b/packages/popup/index.ts index 8688a149..4d12fad2 100644 --- a/packages/popup/index.ts +++ b/packages/popup/index.ts @@ -3,10 +3,22 @@ import { transition } from '../mixins/transition'; import { iphonex } from '../mixins/iphonex'; VantComponent({ + classes: [ + 'enter-class', + 'enter-active-class', + 'enter-to-class', + 'leave-class', + 'leave-active-class', + 'leave-to-class' + ], + mixins: [transition(false), iphonex], props: { - transition: String, + transition: { + type: String, + observer: 'observeClass' + }, customStyle: String, overlayStyle: String, zIndex: { @@ -23,10 +35,15 @@ VantComponent({ }, position: { type: String, - value: 'center' + value: 'center', + observer: 'observeClass' } }, + created() { + this.observeClass(); + }, + methods: { onClickOverlay() { this.$emit('click-overlay'); @@ -34,6 +51,11 @@ VantComponent({ if (this.data.closeOnClickOverlay) { this.$emit('close'); } + }, + + observeClass() { + const { transition, position } = this.data; + this.updateClasses(transition || position); } } }); diff --git a/packages/popup/index.wxml b/packages/popup/index.wxml index bafbfecb..6d38e13b 100644 --- a/packages/popup/index.wxml +++ b/packages/popup/index.wxml @@ -6,13 +6,14 @@ show="{{ show }}" z-index="{{ zIndex }}" custom-style="{{ overlayStyle }}" + duration="{{ duration }}" bind:click="onClickOverlay" /> diff --git a/packages/transition/README.md b/packages/transition/README.md index 8b4dc0dc..81db405a 100644 --- a/packages/transition/README.md +++ b/packages/transition/README.md @@ -27,13 +27,42 @@ transition 组件内置了多种动画,可以通过`name`字段指定动画类 ``` +#### 高级用法 + +可以通过外部样式类自定义过渡效果,还可以定制进入和移出的持续时间: + +```html + +``` + +```css +.van-enter-active-class, +.van-leave-active-class { + transition-property: background-color, transform; +} + +.van-enter-class, +.van-leave-to-class { + background-color: red; + transform: rotate(-360deg) translate3d(-100%, -100%, 0); +} +``` + ### API | 参数 | 说明 | 类型 | 默认值 | |-----------|-----------|-----------|-------------| | name | 动画类型 | `String` | `fade`| | show | 是否展示组件 | `Boolean` | `true` | -| duration | 动画时长,单位为毫秒 | `Number` | `300` | +| duration | 动画时长,单位为毫秒 | `Number | Object` | `300` | | custom-style | 自定义样式 | `String` | - | ### 外部样式类 @@ -41,6 +70,12 @@ transition 组件内置了多种动画,可以通过`name`字段指定动画类 | 类名 | 说明 | |-----------|-----------| | custom-class | 根节点样式类 | +| enter-class | 定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。| +| enter-active-class | 定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。 | +| enter-to-class | 定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 enter-class 被移除),在过渡/动画完成之后移除。 | +| leave-class | 定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。| +| leave-active-class | 定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。 | +| leave-to-class | 定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 leave-class 被删除),在过渡/动画完成之后移除。 | ### 动画类型 @@ -55,9 +90,3 @@ transition 组件内置了多种动画,可以通过`name`字段指定动画类 | slide-down | 下滑进入 | | slide-left | 左滑进入 | | slide-right | 右滑进入 | - -### 更新日志 - -| 版本 | 类型 | 内容 | -|-----------|-----------|-----------| -| 0.1.1 | feature | 新增组件 | diff --git a/packages/transition/index.less b/packages/transition/index.less index 5ee8c129..7d649ef5 100644 --- a/packages/transition/index.less +++ b/packages/transition/index.less @@ -1,127 +1,79 @@ .van-transition { - animation: ease both; + transition-timing-function: ease; } -@keyframes van-fade-enter { - from { - opacity: 0; - } - - to { - opacity: 1; - } +.van-fade-enter-active, +.van-fade-leave-active { + transition-property: opacity; } -@keyframes van-fade-leave { - from { - opacity: 1; - } - - to { - opacity: 0; - } +.van-fade-enter, +.van-fade-leave-to { + opacity: 0; } -@keyframes van-fade-up-enter { - from { - opacity: 0; - transform: translate3d(0, 100%, 0); - } +.van-fade-up-enter-active, +.van-fade-up-leave-active, +.van-fade-down-enter-active, +.van-fade-down-leave-active, +.van-fade-left-enter-active, +.van-fade-left-leave-active, +.van-fade-right-enter-active, +.van-fade-right-leave-active { + transition-property: opacity, transform; } -@keyframes van-fade-up-leave { - to { - opacity: 0; - transform: translate3d(0, 100%, 0); - } +.van-fade-up-enter, +.van-fade-up-leave-to { + opacity: 0; + transform: translate3d(0, 100%, 0); } -@keyframes van-slide-up-enter { - from { - transform: translate3d(0, 100%, 0); - } +.van-fade-down-enter, +.van-fade-down-leave-to { + opacity: 0; + transform: translate3d(0, -100%, 0); } -@keyframes van-slide-up-leave { - to { - transform: translate3d(0, 100%, 0); - } +.van-fade-left-enter, +.van-fade-left-leave-to { + opacity: 0; + transform: translate3d(-100%, 0, 0); } -@keyframes van-fade-down-enter { - from { - opacity: 0; - transform: translate3d(0, -100%, 0); - } +.van-fade-right-enter, +.van-fade-right-leave-to { + opacity: 0; + transform: translate3d(100%, 0, 0); } -@keyframes van-fade-down-leave { - to { - opacity: 0; - transform: translate3d(0, -100%, 0); - } +.van-slide-up-enter-active, +.van-slide-up-leave-active, +.van-slide-down-enter-active, +.van-slide-down-leave-active, +.van-slide-left-enter-active, +.van-slide-left-leave-active, +.van-slide-right-enter-active, +.van-slide-right-leave-active { + transition-property: transform; } -@keyframes van-slide-down-enter { - from { - transform: translate3d(0, -100%, 0); - } +.van-slide-up-enter, +.van-slide-up-leave-to { + transform: translate3d(0, 100%, 0); } -@keyframes van-slide-down-leave { - to { - transform: translate3d(0, -100%, 0); - } +.van-slide-down-enter, +.van-slide-down-leave-to { + transform: translate3d(0, -100%, 0); } -@keyframes van-fade-left-enter { - from { - opacity: 0; - transform: translate3d(-100%, 0, 0); - } +.van-slide-left-enter, +.van-slide-left-leave-to { + transform: translate3d(-100%, 0, 0); } -@keyframes van-fade-left-leave { - to { - opacity: 0; - transform: translate3d(-100%, 0, 0); - } -} - -@keyframes van-slide-left-enter { - from { - transform: translate3d(-100%, 0, 0); - } -} - -@keyframes van-slide-left-leave { - to { - transform: translate3d(-100%, 0, 0); - } -} - -@keyframes van-fade-right-enter { - from { - opacity: 0; - transform: translate3d(100%, 0, 0); - } -} - -@keyframes van-fade-right-leave { - to { - opacity: 0; - transform: translate3d(100%, 0, 0); - } -} - -@keyframes van-slide-right-enter { - from { - transform: translate3d(100%, 0, 0); - } -} - -@keyframes van-slide-right-leave { - to { - transform: translate3d(100%, 0, 0); - } +.van-slide-right-enter, +.van-slide-right-leave-to { + transform: translate3d(100%, 0, 0); } diff --git a/packages/transition/index.ts b/packages/transition/index.ts index ca5a8288..23a371fc 100644 --- a/packages/transition/index.ts +++ b/packages/transition/index.ts @@ -2,12 +2,14 @@ import { VantComponent } from '../common/component'; import { transition } from '../mixins/transition'; VantComponent({ - mixins: [transition(true)], + classes: [ + 'enter-class', + 'enter-active-class', + 'enter-to-class', + 'leave-class', + 'leave-active-class', + 'leave-to-class' + ], - props: { - name: { - type: String, - value: 'fade' - } - } + mixins: [transition(true)] }); diff --git a/packages/transition/index.wxml b/packages/transition/index.wxml index f6deb0d3..412e8afc 100644 --- a/packages/transition/index.wxml +++ b/packages/transition/index.wxml @@ -1,8 +1,8 @@