Commit 58d0048461f10dad45e5b9268b83ac191264334d
1 parent
911e0e61
feat(animation): run animations in edit mode
Showing
5 changed files
with
76 additions
and
7 deletions
front-end/h5/src/components/core/editor/edit-panel/animation.js
| ... | ... | @@ -3,29 +3,36 @@ import { animationOptions, animationValue2Name, firstLevelAnimationOptions } fro |
| 3 | 3 | |
| 4 | 4 | export default { |
| 5 | 5 | computed: { |
| 6 | - ...mapState('editor', ['editingElement']) | |
| 6 | + ...mapState('editor', ['editingElement']), | |
| 7 | + animationQueue () { | |
| 8 | + return (this.editingElement && this.editingElement.animations) || [] | |
| 9 | + } | |
| 7 | 10 | }, |
| 8 | 11 | data: () => ({ |
| 9 | - animationQueue: [], | |
| 12 | + // animationQueue: [], | |
| 10 | 13 | activeCollapsePanel: 0, |
| 11 | 14 | activePreviewAnimation: '', |
| 12 | 15 | drawerVisible: false |
| 13 | 16 | }), |
| 14 | 17 | methods: { |
| 15 | 18 | addAnimation () { |
| 19 | + // TODO move this to vuex | |
| 16 | 20 | this.animationQueue.push({ |
| 17 | 21 | type: '', |
| 18 | - duration: 0, | |
| 22 | + duration: 2, | |
| 19 | 23 | delay: 0, |
| 20 | - countNum: 1, | |
| 24 | + interationCount: 1, | |
| 21 | 25 | infinite: false |
| 22 | 26 | }) |
| 23 | 27 | this.activeCollapsePanel = this.animationQueue.length - 1 |
| 24 | 28 | }, |
| 25 | 29 | deleteAnimate (index) { |
| 30 | + // TODO move this to vuex | |
| 26 | 31 | this.animationQueue.splice(index, 1) |
| 27 | 32 | }, |
| 28 | 33 | runAnimate () { |
| 34 | + // front-end/h5/src/components/core/editor/index.js created() | |
| 35 | + window.getEditorApp.$emit('RUN_ANIMATIONS') | |
| 29 | 36 | }, |
| 30 | 37 | renderSecondAnimationTabs (animations) { |
| 31 | 38 | return ( |
| ... | ... | @@ -50,11 +57,11 @@ export default { |
| 50 | 57 | // https://www.quirksmode.org/js/events_mouse.html#mouseenter |
| 51 | 58 | <a-list-item> |
| 52 | 59 | <div |
| 53 | - class={[this.activePreviewAnimation === item.value && item.value + ' animated', 'shortcut-button']} | |
| 54 | 60 | onClick={(e) => { |
| 55 | 61 | // TODO move this to vuex mutation |
| 56 | 62 | this.editingElement.animations[this.activeCollapsePanel].type = item.value |
| 57 | 63 | }} |
| 64 | + class={[this.activePreviewAnimation === item.value && item.value + ' animated', 'shortcut-button']} | |
| 58 | 65 | onMouseenter={(e) => { |
| 59 | 66 | this.activePreviewAnimation = item.value |
| 60 | 67 | }} | ... | ... |
front-end/h5/src/components/core/editor/index.js
| ... | ... | @@ -3,6 +3,7 @@ import undoRedoHistory from '../../../store/plugins/undo-redo/History' |
| 3 | 3 | import { getEditorConfigForEditingElement } from '../../../utils/element' |
| 4 | 4 | |
| 5 | 5 | import '../styles/index.scss' |
| 6 | +import 'animate.css' | |
| 6 | 7 | |
| 7 | 8 | import RenderEditCanvas from './canvas/edit' |
| 8 | 9 | import RenderPreviewCanvas from './canvas/preview' |
| ... | ... | @@ -296,6 +297,8 @@ export default { |
| 296 | 297 | ) |
| 297 | 298 | }, |
| 298 | 299 | created () { |
| 300 | + // event bus for editor | |
| 301 | + window.getEditorApp = this | |
| 299 | 302 | let workId = this.$route.params.workId |
| 300 | 303 | console.log(workId) |
| 301 | 304 | if (workId) { | ... | ... |
front-end/h5/src/components/core/models/element.js
| ... | ... | @@ -34,6 +34,7 @@ class Element { |
| 34 | 34 | this.pluginProps = (typeof ele.pluginProps === 'object' && clone(ele.pluginProps)) || this.getDefaultPluginProps(ele.editorConfig || {}) |
| 35 | 35 | this.commonStyle = (typeof ele.commonStyle === 'object' && clone(ele.commonStyle)) || { ...defaultStyle } |
| 36 | 36 | this.events = [] |
| 37 | + this.animations = [] | |
| 37 | 38 | } |
| 38 | 39 | |
| 39 | 40 | getDefaultPluginProps (editorConfig) { |
| ... | ... | @@ -51,7 +52,7 @@ class Element { |
| 51 | 52 | return pluginProps |
| 52 | 53 | } |
| 53 | 54 | |
| 54 | - getStyle ({ position = 'static', isRem = false }) { | |
| 55 | + getStyle ({ position = 'static', isRem = false } = {}) { | |
| 55 | 56 | const pluginProps = this.pluginProps |
| 56 | 57 | const commonStyle = this.commonStyle |
| 57 | 58 | let style = { | ... | ... |
front-end/h5/src/components/core/support/shape.js
| 1 | +import animationMixin from '@/mixins/animation.js' | |
| 2 | + | |
| 1 | 3 | /** |
| 2 | 4 | * #!zh: 上下左右 对应的 东南西北 |
| 3 | 5 | * #!en: top(north)、bottom(south)、left(west)、right(east) |
| ... | ... | @@ -13,7 +15,8 @@ const directionKey = { |
| 13 | 15 | const points = ['lt', 'rt', 'lb', 'rb', 'l', 'r', 't', 'b'] |
| 14 | 16 | |
| 15 | 17 | export default { |
| 16 | - props: ['defaultPosition', 'active', 'handleMousedownProp', 'handleElementMoveProp', 'handlePointMoveProp', 'handleElementMouseUpProp', 'handlePointMouseUpProp'], | |
| 18 | + mixins: [animationMixin], | |
| 19 | + props: ['defaultPosition', 'active', 'handleMousedownProp', 'handleElementMoveProp', 'handlePointMoveProp', 'handleElementMouseUpProp', 'handlePointMouseUpProp', 'element'], | |
| 17 | 20 | computed: { |
| 18 | 21 | position () { |
| 19 | 22 | return { ...this.defaultPosition } | ... | ... |
front-end/h5/src/mixins/animation.js
0 → 100644
| 1 | +// https://stackoverflow.com/questions/26874769/getcomputedstyle-and-csstext-in-ie-and-firefox | |
| 2 | +function getComputedCSSText (style) { | |
| 3 | + let cssText = '' | |
| 4 | + for (let attr in style) { | |
| 5 | + // m <?> matched | |
| 6 | + // #!en: hump to line | |
| 7 | + // #!zh: 驼峰转下划线 | |
| 8 | + cssText += `${attr.replace(/[A-Z]+/g, m => `-${m.toLowerCase()}`)}:${style[attr]};` | |
| 9 | + } | |
| 10 | + return cssText | |
| 11 | +} | |
| 12 | + | |
| 13 | +export default { | |
| 14 | + methods: { | |
| 15 | + async runAnimations () { | |
| 16 | + const animationQueue = this.animations || this.element.animations || [] | |
| 17 | + let len = animationQueue.length | |
| 18 | + if (len === 0) return | |
| 19 | + | |
| 20 | + let that = this | |
| 21 | + let parentNode = this.$el | |
| 22 | + let animIdx = 0 | |
| 23 | + const oldStyle = that.element.getStyle({ position: 'absolute' }) | |
| 24 | + runAnimation() | |
| 25 | + | |
| 26 | + function runAnimation () { | |
| 27 | + if (animIdx < len) { | |
| 28 | + const animation = animationQueue[animIdx] | |
| 29 | + let animationStyle = { | |
| 30 | + animationName: animation.type, | |
| 31 | + animationDuration: `${animation.duration}s`, | |
| 32 | + animationIterationCount: animation.infinite ? 'infinite' : animation.interationCount, | |
| 33 | + animationDelay: `${animation.delay}s`, | |
| 34 | + animationFillMode: 'both' | |
| 35 | + } | |
| 36 | + parentNode.style.cssText = getComputedCSSText(animationStyle) + getComputedCSSText(oldStyle) | |
| 37 | + animIdx++ | |
| 38 | + } else { | |
| 39 | + // reset to the initial state after the animation ended | |
| 40 | + parentNode.style.cssText = getComputedCSSText(oldStyle) | |
| 41 | + } | |
| 42 | + } | |
| 43 | + parentNode.addEventListener('animationend', runAnimation, false) | |
| 44 | + } | |
| 45 | + }, | |
| 46 | + created () { | |
| 47 | + const that = this | |
| 48 | + window.getEditorApp.$on('RUN_ANIMATIONS', () => { | |
| 49 | + if (that.active) { | |
| 50 | + that.runAnimations() | |
| 51 | + } | |
| 52 | + }) | |
| 53 | + } | |
| 54 | + | |
| 55 | +} | ... | ... |