pipipi-pikachu vor 5 Jahren
Ursprung
Commit
93785a9ebc

+ 197 - 151
package-lock.json

@@ -2258,122 +2258,6 @@
         "tslint": "^5.20.1",
         "webpack": "^4.0.0",
         "yorkie": "^2.0.0"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "4.3.0",
-          "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1606792369066&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz",
-          "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "color-convert": "^2.0.1"
-          }
-        },
-        "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz?cache=0&sync_timestamp=1591687000046&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-4.1.0.tgz",
-          "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
-        "color-convert": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz?cache=0&sync_timestamp=1566248870121&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcolor-convert%2Fdownload%2Fcolor-convert-2.0.1.tgz",
-          "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "color-name": "~1.1.4"
-          }
-        },
-        "color-name": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz",
-          "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=",
-          "dev": true,
-          "optional": true
-        },
-        "fork-ts-checker-webpack-plugin-v5": {
-          "version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
-          "resolved": "https://registry.npm.taobao.org/fork-ts-checker-webpack-plugin/download/fork-ts-checker-webpack-plugin-5.2.1.tgz?cache=0&sync_timestamp=1607084938170&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffork-ts-checker-webpack-plugin%2Fdownload%2Ffork-ts-checker-webpack-plugin-5.2.1.tgz",
-          "integrity": "sha1-eTJthpeXkG+osk4qvPlCH8gFRQ0=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "@babel/code-frame": "^7.8.3",
-            "@types/json-schema": "^7.0.5",
-            "chalk": "^4.1.0",
-            "cosmiconfig": "^6.0.0",
-            "deepmerge": "^4.2.2",
-            "fs-extra": "^9.0.0",
-            "memfs": "^3.1.2",
-            "minimatch": "^3.0.4",
-            "schema-utils": "2.7.0",
-            "semver": "^7.3.2",
-            "tapable": "^1.0.0"
-          }
-        },
-        "has-flag": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz",
-          "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=",
-          "dev": true,
-          "optional": true
-        },
-        "lru-cache": {
-          "version": "6.0.0",
-          "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz?cache=0&sync_timestamp=1594427484405&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Flru-cache%2Fdownload%2Flru-cache-6.0.0.tgz",
-          "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "yallist": "^4.0.0"
-          }
-        },
-        "schema-utils": {
-          "version": "2.7.0",
-          "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-2.7.0.tgz",
-          "integrity": "sha1-FxUfdtjq5n+793lgwzxnatn078c=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "@types/json-schema": "^7.0.4",
-            "ajv": "^6.12.2",
-            "ajv-keywords": "^3.4.1"
-          }
-        },
-        "semver": {
-          "version": "7.3.4",
-          "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.4.tgz?cache=0&sync_timestamp=1606852064928&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.4.tgz",
-          "integrity": "sha1-J6qn0uTKdkUvmNOt0JOnLJQ+3Jc=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "lru-cache": "^6.0.0"
-          }
-        },
-        "supports-color": {
-          "version": "7.2.0",
-          "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz?cache=0&sync_timestamp=1606205010380&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsupports-color%2Fdownload%2Fsupports-color-7.2.0.tgz",
-          "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "has-flag": "^4.0.0"
-          }
-        },
-        "yallist": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz",
-          "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=",
-          "dev": true,
-          "optional": true
-        }
       }
     },
     "@vue/cli-plugin-unit-jest": {
@@ -2537,17 +2421,6 @@
             "unique-filename": "^1.1.1"
           }
         },
-        "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz?cache=0&sync_timestamp=1591687000046&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fchalk%2Fdownload%2Fchalk-4.1.0.tgz",
-          "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ansi-styles": "^4.1.0",
-            "supports-color": "^7.1.0"
-          }
-        },
         "cliui": {
           "version": "6.0.0",
           "resolved": "https://registry.npm.taobao.org/cliui/download/cliui-6.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcliui%2Fdownload%2Fcliui-6.0.0.tgz",
@@ -2610,18 +2483,6 @@
             "graceful-fs": "^4.1.6"
           }
         },
-        "loader-utils": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-2.0.0.tgz",
-          "integrity": "sha1-5MrOW4FtQloWa18JfhDNErNgZLA=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^2.1.2"
-          }
-        },
         "source-map": {
           "version": "0.6.1",
           "resolved": "https://registry.npm.taobao.org/source-map/download/source-map-0.6.1.tgz",
@@ -2670,18 +2531,6 @@
           "integrity": "sha1-tkb2m+OULavOzJ1mOcgNwQXvqmY=",
           "dev": true
         },
-        "vue-loader-v16": {
-          "version": "npm:vue-loader@16.1.2",
-          "resolved": "https://registry.npm.taobao.org/vue-loader/download/vue-loader-16.1.2.tgz?cache=0&sync_timestamp=1608187974157&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-loader%2Fdownload%2Fvue-loader-16.1.2.tgz",
-          "integrity": "sha1-XAO2xQ0qX5g8fOuhXFDXjKKymPQ=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "chalk": "^4.1.0",
-            "hash-sum": "^2.0.0",
-            "loader-utils": "^2.0.0"
-          }
-        },
         "wrap-ansi": {
           "version": "6.2.0",
           "resolved": "https://registry.npm.taobao.org/wrap-ansi/download/wrap-ansi-6.2.0.tgz",
@@ -7478,6 +7327,122 @@
         "worker-rpc": "^0.1.0"
       }
     },
+    "fork-ts-checker-webpack-plugin-v5": {
+      "version": "npm:fork-ts-checker-webpack-plugin@5.2.1",
+      "resolved": "https://registry.npm.taobao.org/fork-ts-checker-webpack-plugin/download/fork-ts-checker-webpack-plugin-5.2.1.tgz",
+      "integrity": "sha1-eTJthpeXkG+osk4qvPlCH8gFRQ0=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "@babel/code-frame": "^7.8.3",
+        "@types/json-schema": "^7.0.5",
+        "chalk": "^4.1.0",
+        "cosmiconfig": "^6.0.0",
+        "deepmerge": "^4.2.2",
+        "fs-extra": "^9.0.0",
+        "memfs": "^3.1.2",
+        "minimatch": "^3.0.4",
+        "schema-utils": "2.7.0",
+        "semver": "^7.3.2",
+        "tapable": "^1.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1606792302448&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz",
+          "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz",
+          "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz",
+          "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz",
+          "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=",
+          "dev": true,
+          "optional": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1596294337050&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz",
+          "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=",
+          "dev": true,
+          "optional": true
+        },
+        "lru-cache": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npm.taobao.org/lru-cache/download/lru-cache-6.0.0.tgz",
+          "integrity": "sha1-bW/mVw69lqr5D8rR2vo7JWbbOpQ=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "yallist": "^4.0.0"
+          }
+        },
+        "schema-utils": {
+          "version": "2.7.0",
+          "resolved": "https://registry.npm.taobao.org/schema-utils/download/schema-utils-2.7.0.tgz",
+          "integrity": "sha1-FxUfdtjq5n+793lgwzxnatn078c=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "@types/json-schema": "^7.0.4",
+            "ajv": "^6.12.2",
+            "ajv-keywords": "^3.4.1"
+          }
+        },
+        "semver": {
+          "version": "7.3.4",
+          "resolved": "https://registry.npm.taobao.org/semver/download/semver-7.3.4.tgz?cache=0&sync_timestamp=1606852122426&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsemver%2Fdownload%2Fsemver-7.3.4.tgz",
+          "integrity": "sha1-J6qn0uTKdkUvmNOt0JOnLJQ+3Jc=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz",
+          "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "yallist": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npm.taobao.org/yallist/download/yallist-4.0.0.tgz",
+          "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=",
+          "dev": true,
+          "optional": true
+        }
+      }
+    },
     "form-data": {
       "version": "2.3.3",
       "resolved": "https://registry.npm.taobao.org/form-data/download/form-data-2.3.3.tgz",
@@ -15923,6 +15888,87 @@
         }
       }
     },
+    "vue-loader-v16": {
+      "version": "npm:vue-loader@16.1.2",
+      "resolved": "https://registry.npm.taobao.org/vue-loader/download/vue-loader-16.1.2.tgz?cache=0&sync_timestamp=1608187974157&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-loader%2Fdownload%2Fvue-loader-16.1.2.tgz",
+      "integrity": "sha1-XAO2xQ0qX5g8fOuhXFDXjKKymPQ=",
+      "dev": true,
+      "optional": true,
+      "requires": {
+        "chalk": "^4.1.0",
+        "hash-sum": "^2.0.0",
+        "loader-utils": "^2.0.0"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npm.taobao.org/ansi-styles/download/ansi-styles-4.3.0.tgz?cache=0&sync_timestamp=1606792302448&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fansi-styles%2Fdownload%2Fansi-styles-4.3.0.tgz",
+          "integrity": "sha1-7dgDYornHATIWuegkG7a00tkiTc=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npm.taobao.org/chalk/download/chalk-4.1.0.tgz",
+          "integrity": "sha1-ThSHCmGNni7dl92DRf2dncMVZGo=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npm.taobao.org/color-convert/download/color-convert-2.0.1.tgz",
+          "integrity": "sha1-ctOmjVmMm9s68q0ehPIdiWq9TeM=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npm.taobao.org/color-name/download/color-name-1.1.4.tgz",
+          "integrity": "sha1-wqCah6y95pVD3m9j+jmVyCbFNqI=",
+          "dev": true,
+          "optional": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npm.taobao.org/has-flag/download/has-flag-4.0.0.tgz?cache=0&sync_timestamp=1596294337050&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhas-flag%2Fdownload%2Fhas-flag-4.0.0.tgz",
+          "integrity": "sha1-lEdx/ZyByBJlxNaUGGDaBrtZR5s=",
+          "dev": true,
+          "optional": true
+        },
+        "loader-utils": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npm.taobao.org/loader-utils/download/loader-utils-2.0.0.tgz",
+          "integrity": "sha1-5MrOW4FtQloWa18JfhDNErNgZLA=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^2.1.2"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npm.taobao.org/supports-color/download/supports-color-7.2.0.tgz",
+          "integrity": "sha1-G33NyzK4E4gBs+R4umpRyqiWSNo=",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
     "vue-style-loader": {
       "version": "4.1.2",
       "resolved": "https://registry.npm.taobao.org/vue-style-loader/download/vue-style-loader-4.1.2.tgz",

+ 88 - 36
src/configs/animation.ts

@@ -1,38 +1,90 @@
 export const ANIMATIONS = [
-  { name: '渐显', value: 'fadeIn' },
-  { name: '向右进入', value: 'fadeInLeft' },
-  { name: '向左进入', value: 'fadeInRight' },
-  { name: '向上进入', value: 'fadeInUp' },
-  { name: '向下进入', value: 'fadeInDown' },
-  { name: '向右长距进入', value: 'fadeInLeftBig' },
-  { name: '向左长距进入', value: 'fadeInRightBig' },
-  { name: '向上长距进入', value: 'fadeInUpBig' },
-  { name: '向下长距进入', value: 'fadeInDownBig' },
-  { name: '旋转进入', value: 'rotateIn' },
-  { name: '左顺时针旋转', value: 'rotateInDownLeft' },
-  { name: '右逆时针旋转', value: 'rotateInDownRight' },
-  { name: '左逆时针旋转', value: 'rotateInUpLeft' },
-  { name: '右逆时针旋转', value: 'rotateInUpRight' },
-  { name: '弹入', value: 'bounceIn' },
-  { name: '向右弹入', value: 'bounceInLeft' },
-  { name: '向左弹入', value: 'bounceInRight' },
-  { name: '向上弹入', value: 'bounceInUp' },
-  { name: '向下弹入', value: 'bounceInDown' },
-  { name: '光速从右进入', value: 'lightSpeedInRight' },
-  { name: '光速从左进入', value: 'lightSpeedInLeft' },
-  { name: '光速从右退出', value: 'lightSpeedOutRight' },
-  { name: '光速从左退出', value: 'lightSpeedOutLeft' },
-  { name: 'Y轴旋转', value: 'flip' },
-  { name: '中心X轴旋转', value: 'flipInX' },
-  { name: '中心Y轴旋转', value: 'flipInY' },
-  { name: '左长半径旋转', value: 'rollIn' },
-  { name: '由小变大进入', value: 'zoomIn' },
-  { name: '左变大进入', value: 'zoomInLeft' },
-  { name: '右变大进入', value: 'zoomInRight' },
-  { name: '向上变大进入', value: 'zoomInUp' },
-  { name: '向下变大进入', value: 'zoomInDown' },
-  { name: '向右滑动展开', value: 'slideInLeft' },
-  { name: '向左滑动展开', value: 'slideInRight' },
-  { name: '向上滑动展开', value: 'slideInUp' },
-  { name: '向下滑动展开', value: 'slideInDown' },
+  {
+    type: 'bounce',
+    name: '弹跳',
+    children: [
+      { name: '弹入', value: 'bounceIn' },
+      { name: '向右弹入', value: 'bounceInLeft' },
+      { name: '向左弹入', value: 'bounceInRight' },
+      { name: '向上弹入', value: 'bounceInUp' },
+      { name: '向下弹入', value: 'bounceInDown' },
+    ],
+  },
+  {
+    type: 'fade',
+    name: '浮现',
+    children: [
+      { name: '浮入', value: 'fadeIn' },
+      { name: '向下浮入', value: 'fadeInDown' },
+      { name: '向下长距浮入', value: 'fadeInDownBig' },
+      { name: '向右浮入', value: 'fadeInLeft' },
+      { name: '向右长距浮入', value: 'fadeInLeftBig' },
+      { name: '向左浮入', value: 'fadeInRight' },
+      { name: '向左长距浮入', value: 'fadeInRightBig' },
+      { name: '向上浮入', value: 'fadeInUp' },
+      { name: '向上长距浮入', value: 'fadeInUpBig' },
+      { name: '从左上浮入', value: 'fadeInTopLeft' },
+      { name: '从右上浮入', value: 'fadeInTopRight' },
+      { name: '从左下浮入', value: 'fadeInBottomLeft' },
+      { name: '从右下浮入', value: 'fadeInBottomRight' },
+    ],
+  },
+  {
+    type: 'rotate',
+    name: '旋转',
+    children: [
+      { name: '旋转进入', value: 'rotateIn' },
+      { name: '基于左下旋转进入', value: 'rotateInDownLeft' },
+      { name: '基于右下旋转进入', value: 'rotateInDownRight' },
+      { name: '基于左上旋转进入', value: 'rotateInUpLeft' },
+      { name: '基于右上旋转进入', value: 'rotateInUpRight' },
+    ],
+  },
+  {
+    type: 'zoom',
+    name: '缩放',
+    children: [
+      { name: '放大进入', value: 'zoomIn' },
+      { name: '向下放大进入', value: 'zoomInDown' },
+      { name: '从左放大进入', value: 'zoomInLeft' },
+      { name: '从右放大进入', value: 'zoomInRight' },
+      { name: '向上放大进入', value: 'zoomInUp' },
+    ],
+  },
+  {
+    type: 'slide',
+    name: '滑入',
+    children: [
+      { name: '向下滑入', value: 'slideInDown' },
+      { name: '从右滑入', value: 'slideInLeft' },
+      { name: '从左滑入', value: 'slideInRight' },
+      { name: '向上滑入', value: 'slideInUp' },
+    ],
+  },
+  {
+    type: 'flip',
+    name: '翻转',
+    children: [
+      { name: 'X轴翻转进入', value: 'flipInX' },
+      { name: 'Y轴翻转进入', value: 'flipInY' },
+    ],
+  },
+  {
+    type: 'back',
+    name: '放大滑入',
+    children: [
+      { name: '向下放大滑入', value: 'backInDown' },
+      { name: '从左放大滑入', value: 'backInLeft' },
+      { name: '从右放大滑入', value: 'backInRight' },
+      { name: '向上放大滑入', value: 'backInUp' },
+    ],
+  },
+  {
+    type: 'lightSpeed',
+    name: '飞入',
+    children: [
+      { name: '从右飞入', value: 'lightSpeedInRight' },
+      { name: '从左飞入', value: 'lightSpeedInLeft' },
+    ],
+  },
 ]

+ 0 - 56
src/hooks/useAnimation.ts

@@ -1,56 +0,0 @@
-import { computed, Ref, ref } from 'vue'
-import { useStore } from 'vuex'
-import { State } from '@/store'
-import { Slide } from '@/types/slides'
-
-const prefix = 'animate__'
-
-export default (elId: string) => {
-  const animationIndex = ref(-1)
-  const needWaitAnimation = ref(false)
-
-  const store = useStore<State>()
-  const currentSlide: Ref<Slide> = computed(() => store.getters.currentSlide)
-  const animations = computed(() => currentSlide.value.animations || [])
-
-  const elementIndexInAnimation = animations.value.findIndex(animation => animation.elId === elId)
-  if(elementIndexInAnimation !== -1 && elementIndexInAnimation < animationIndex.value) {
-    needWaitAnimation.value = true
-  }
-
-  const runAnimation = () => {
-    const animations = currentSlide.value.animations || []
-    if(!animations.length) return
-    if(animationIndex.value >= animations.length - 1) return
-
-    animationIndex.value += 1
-    const animation = animations[animationIndex.value]
-
-    const elRef = document.querySelector(`#screen-el-${animation.elId}`)
-    if(elRef) {
-      const animationName = `${prefix}${animation.type}`
-      elRef.classList.add(`${prefix}animated`, animationName)
-    }
-  }
-
-  const revokeAnimation = () => {
-    const animations = currentSlide.value.animations || []
-    if(!animations.length) return
-    if(animationIndex.value <= 0) return
-
-    animationIndex.value -= 1
-    const animation = animations[animationIndex.value]
-
-    const elRef = document.querySelector(`#screen-el-${animation.elId}`)
-    if(elRef) {
-      const animationName = `${prefix}${animation.type}`
-      elRef.classList.remove(`${prefix}animated`, animationName)
-    }
-  }
-
-  return {
-    needWaitAnimation,
-    runAnimation,
-    revokeAnimation,
-  }
-}

+ 8 - 1
src/mocks/index.ts

@@ -68,7 +68,7 @@ export const slides: Slide[] = [
       },
       {
         elId: 'xxx2',
-        type: 'zoomInDown',
+        type: 'zoomIn',
         duration: 1000,
       },
     ],
@@ -89,5 +89,12 @@ export const slides: Slide[] = [
         content: '<div>😀 😐 😶 😜 🔔 ⭐ ⚡ 🔥 👍 💡 🔰 🎀 🎁 🥇 🏅 🏆 🎈 🎉 💎 🚧 ⛔ 📢 ⌛ ⏰ 🕒 🧩 🎵 📎 🔒 🔑 ⛳ 📌 📍 💬 📅 📈 📋 📜 📁 📱 💻 💾 🌏 🚚 🚡 🚢💧 🌐 🧭 💰 💳 🛒</div>',
       },
     ],
+    animations: [
+      {
+        elId: 'yyx1',
+        type: 'flipInX',
+        duration: 1000,
+      },
+    ],
   },
 ]

+ 2 - 1
src/store/constants.ts

@@ -10,6 +10,7 @@ export enum MutationTypes {
   SET_DISABLE_HOTKEYS_STATE = 'setDisableHotkeysState',
   SET_GRID_LINES_STATE = 'setGridLinesState',
   SET_AVAILABLE_FONTS = 'setAvailableFonts',
+  SET_TOOLBAR_STATE = 'setToolbarState',
 
   // slides
   SET_SLIDES = 'setSlides',
@@ -29,7 +30,7 @@ export enum MutationTypes {
   SET_SHIFT_KEY_STATE = 'setShiftKeyState',
 
   // screen
-  SET_SCREENING = 'SET_SCREENING'
+  SET_SCREENING = 'setScreening',
 }
 
 export enum ActionTypes {

+ 2 - 0
src/store/index.ts

@@ -20,6 +20,7 @@ export interface State {
   disableHotkeys: boolean;
   showGridLines: boolean;
   availableFonts: FontName[];
+  toolbarState: string;
   slides: Slide[];
   slideIndex: number;
   snapshotCursor: number;
@@ -39,6 +40,7 @@ const state: State = {
   disableHotkeys: false,
   showGridLines: false,
   availableFonts: [],
+  toolbarState: '',
   slides: slides,
   slideIndex: 0,
   snapshotCursor: -1,

+ 4 - 0
src/store/mutations.ts

@@ -53,6 +53,10 @@ export const mutations: MutationTree<State> = {
     state.availableFonts = FONT_NAMES.filter(font => isSupportFontFamily(font.en))
   },
 
+  [MutationTypes.SET_TOOLBAR_STATE](state, type) {
+    state.toolbarState = type
+  },
+
   // slides
 
   [MutationTypes.SET_SLIDES](state, slides: Slide[]) {

+ 0 - 35
src/views/Editor/Canvas/Operate/AnimationIndex.vue

@@ -1,35 +0,0 @@
-<template>
-  <div class="animation-index">
-    {{animationIndex}}
-  </div>
-</template>
-
-<script lang="ts">
-export default {
-  name: 'animation-index',
-  props: {
-    animationIndex: {
-      type: Number,
-      required: true,
-    },
-  },
-}
-</script>
-
-<style lang="scss" scoped>
-.animation-index {
-  position: absolute;
-  top: 0;
-  left: -22px;
-  font-size: 12px;
-  width: 20px;
-  height: 20px;
-  background-color: #fff;
-  color: #333;
-  border: 1px solid #666;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  margin-bottom: 3px;
-}
-</style>

+ 0 - 8
src/views/Editor/Canvas/Operate/ImageElementOperate.vue

@@ -42,8 +42,6 @@
         @mousedown.stop="rotateElement(elementInfo)"
       />
     </template>
-
-    <AnimationIndex v-if="animationIndex !== -1" :animationIndex="animationIndex" />
   </div>
 </template>
 
@@ -59,7 +57,6 @@ import useCommonOperate from '../hooks/useCommonOperate'
 import RotateHandler from './RotateHandler.vue'
 import ResizeHandler from './ResizeHandler.vue'
 import BorderLine from './BorderLine.vue'
-import AnimationIndex from './AnimationIndex.vue'
 import ImageClipHandler from './ImageClipHandler.vue'
 
 export default defineComponent({
@@ -68,7 +65,6 @@ export default defineComponent({
     RotateHandler,
     ResizeHandler,
     BorderLine,
-    AnimationIndex,
     ImageClipHandler,
   },
   props: {
@@ -92,10 +88,6 @@ export default defineComponent({
       type: Boolean,
       required: true,
     },
-    animationIndex: {
-      type: Number,
-      required: true,
-    },
     rotateElement: {
       type: Function as PropType<(element: PPTImageElement) => void>,
       required: true,

+ 0 - 8
src/views/Editor/Canvas/Operate/TextElementOperate.vue

@@ -29,8 +29,6 @@
         @mousedown.stop="rotateElement(elementInfo)"
       />
     </template>
-
-    <AnimationIndex v-if="animationIndex !== -1" :animationIndex="animationIndex" />
   </div>
 </template>
 
@@ -46,7 +44,6 @@ import useCommonOperate from '../hooks/useCommonOperate'
 import RotateHandler from './RotateHandler.vue'
 import ResizeHandler from './ResizeHandler.vue'
 import BorderLine from './BorderLine.vue'
-import AnimationIndex from './AnimationIndex.vue'
 
 export default defineComponent({
   name: 'text-element-operate',
@@ -54,7 +51,6 @@ export default defineComponent({
     RotateHandler,
     ResizeHandler,
     BorderLine,
-    AnimationIndex,
   },
   props: {
     elementInfo: {
@@ -77,10 +73,6 @@ export default defineComponent({
       type: Boolean,
       required: true,
     },
-    animationIndex: {
-      type: Number,
-      required: true,
-    },
     rotateElement: {
       type: Function as PropType<(element: PPTTextElement) => void>,
       required: true,

+ 36 - 9
src/views/Editor/Canvas/Operate/index.vue

@@ -15,22 +15,29 @@
       :isActive="isActive"
       :isActiveGroupElement="isActiveGroupElement"
       :isMultiSelect="isMultiSelect"
-      :animationIndex="animationIndex"
+      :animationIndex="elementIndexInAnimation"
       :rotateElement="rotateElement"
       :scaleElement="scaleElement"
     ></component>
+
+    <div 
+      class="animation-index"
+      v-if="toolbarState === 'animation' && elementIndexInAnimation !== -1"
+    >
+      {{elementIndexInAnimation + 1}}
+    </div>
   </div>
 </template>
 
 <script lang="ts">
-import { defineComponent, PropType, computed } from 'vue'
-import { PPTElement } from '@/types/slides'
+import { defineComponent, PropType, computed, Ref } from 'vue'
+import { useStore } from 'vuex'
+import { State } from '@/store'
+import { PPTElement, Slide } from '@/types/slides'
 import { OperateResizeHandler } from '@/types/edit'
 
 import ImageElementOperate from './ImageElementOperate.vue'
 import TextElementOperate from './TextElementOperate.vue'
-import { useStore } from 'vuex'
-import { State } from '@/store'
 
 export default defineComponent({
   name: 'operate',
@@ -55,10 +62,6 @@ export default defineComponent({
       type: Boolean,
       required: true,
     },
-    animationIndex: {
-      type: Number,
-      default: -1,
-    },
     rotateElement: {
       type: Function as PropType<(element: PPTElement) => void>,
       required: true,
@@ -71,6 +74,8 @@ export default defineComponent({
   setup(props) {
     const store = useStore<State>()
     const canvasScale = computed(() => store.state.canvasScale)
+    const toolbarState = computed(() => store.state.toolbarState)
+    const currentSlide: Ref<Slide> = computed(() => store.getters.currentSlide)
 
     const currentOperateComponent = computed(() => {
       const elementTypeMap = {
@@ -80,9 +85,16 @@ export default defineComponent({
       return elementTypeMap[props.elementInfo.type] || null
     })
 
+    const elementIndexInAnimation = computed(() => {
+      const animations = currentSlide.value.animations || []
+      return animations.findIndex(animation => animation.elId === props.elementInfo.id)
+    })
+
     return {
       currentOperateComponent,
       canvasScale,
+      toolbarState,
+      elementIndexInAnimation,
     }
   },
 })
@@ -94,4 +106,19 @@ export default defineComponent({
   z-index: 100;
   user-select: none;
 }
+.animation-index {
+  position: absolute;
+  top: 0;
+  left: -24px;
+  font-size: 12px;
+  width: 18px;
+  height: 18px;
+  background-color: #fff;
+  color: $themeColor;
+  border: 1px solid $themeColor;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  margin-bottom: 3px;
+}
 </style>

+ 2 - 0
src/views/Editor/Canvas/index.vue

@@ -58,7 +58,9 @@
         :height="mouseSelectionState.height" 
         :quadrant="mouseSelectionState.quadrant"
       />
+
       <SlideBackground />
+      
       <EditableElement 
         v-for="(element, index) in elementList" 
         :key="element.id"

+ 9 - 3
src/views/Screen/ScreenSlide.vue

@@ -8,11 +8,13 @@
     }"
   >
     <div class="background" :style="{ ...backgroundStyle }"></div>
-    <BaseElement
+    <ScreenElement
+      :id="`screen-element-${element.id}`"
       v-for="(element, index) in slide.elements"
       :key="element.id"
       :elementInfo="element"
       :elementIndex="index + 1"
+      :animationIndex="animationIndex"
     />
   </div>
 </template>
@@ -23,12 +25,12 @@ import { Slide } from '@/types/slides'
 import { VIEWPORT_SIZE, VIEWPORT_ASPECT_RATIO } from '@/configs/canvas'
 import useSlideBackgroundStyle from '@/hooks/useSlideBackgroundStyle'
 
-import BaseElement from '@/views/_element/BaseElement.vue'
+import ScreenElement from '@/views/_element/ScreenElement.vue'
 
 export default defineComponent({
   name: 'screen-slide',
   components: {
-    BaseElement,
+    ScreenElement,
   },
   props: {
     slide: {
@@ -39,6 +41,10 @@ export default defineComponent({
       type: Number,
       required: true,
     },
+    animationIndex: {
+      type: Number,
+      default: -1,
+    },
   },
   setup(props) {
     const background = computed(() => props.slide.background)

+ 59 - 12
src/views/Screen/index.vue

@@ -24,7 +24,11 @@
             height: slideHeight + 'px',
           }"
         >
-          <ScreenSlide :scale="scale" :slide="slide" />
+          <ScreenSlide 
+            :scale="scale" 
+            :slide="slide" 
+            :animationIndex="animationIndex"
+          />
         </div>
       </div>
     </div>
@@ -32,7 +36,7 @@
 </template>
 
 <script lang="ts">
-import { computed, defineComponent, onMounted, onUnmounted, ref } from 'vue'
+import { computed, defineComponent, onMounted, onUnmounted, Ref, ref } from 'vue'
 import { useStore } from 'vuex'
 import throttle from 'lodash/throttle'
 import { MutationTypes, State } from '@/store'
@@ -42,6 +46,7 @@ import { KEYS } from '@/configs/hotkey'
 import { ContextmenuItem } from '@/components/Contextmenu/types'
 
 import ScreenSlide from './ScreenSlide.vue'
+import { Slide } from '@/types/slides'
 
 export default defineComponent({
   name: 'screen',
@@ -52,6 +57,7 @@ export default defineComponent({
     const store = useStore<State>()
     const slides = computed(() => store.state.slides)
     const slideIndex = computed(() => store.state.slideIndex)
+    const currentSlide: Ref<Slide> = computed(() => store.getters.currentSlide)
 
     const slideWidth = ref(0)
     const slideHeight = ref(0)
@@ -83,24 +89,55 @@ export default defineComponent({
       if(!isFullscreen()) store.commit(MutationTypes.SET_SCREENING, false)
     }
 
-    const turnPrevSlide = () => {
-      if(slideIndex.value <= 0) return
-      store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value - 1)
+    const prefix = 'animate__'
+    const animationIndex = ref(0)
+    const animations = computed(() => currentSlide.value.animations || [])
+
+    const runAnimation = () => {
+      const animation = animations.value[animationIndex.value]
+      animationIndex.value += 1
+
+      const elRef = document.querySelector(`#screen-element-${animation.elId} [class^=base-element-]`)
+      if(elRef) {
+        const animationName = `${prefix}${animation.type}`
+        elRef.classList.add(`${prefix}animated`, animationName)
+
+        const handleAnimationEnd = () => {
+          elRef.classList.remove(`${prefix}animated`, animationName)
+        }
+        elRef.addEventListener('animationend', handleAnimationEnd, { once: true })
+      }
     }
-    const turnNextSlide = () => {
-      if(slideIndex.value >= slides.value.length - 1) return
-      store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value + 1)
+
+    const execPrev = () => {
+      if(animations.value.length && animationIndex.value > 0) {
+        animationIndex.value -= 1
+      }
+      else if(slideIndex.value > 0) {
+        store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value - 1)
+        const lastIndex = animations.value ? animations.value.length : 0
+        animationIndex.value = lastIndex
+      }
+    }
+    const execNext = () => {
+      if(animations.value.length && animationIndex.value < animations.value.length) {
+        runAnimation()
+      }
+      else if(slideIndex.value < slides.value.length - 1) {
+        store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value + 1)
+        animationIndex.value = 0
+      }
     }
 
     const keydownListener = (e: KeyboardEvent) => {
       const key = e.key.toUpperCase()
-      if(key === KEYS.UP || key === KEYS.LEFT) turnPrevSlide()
-      else if(key === KEYS.DOWN || key === KEYS.RIGHT) turnNextSlide()
+      if(key === KEYS.UP || key === KEYS.LEFT) execPrev()
+      else if(key === KEYS.DOWN || key === KEYS.RIGHT) execNext()
     }
 
     const mousewheelListener = throttle(function(e: WheelEvent) {
-      if(e.deltaY > 0) turnNextSlide()
-      else if(e.deltaY < 0) turnPrevSlide()
+      if(e.deltaY < 0) execPrev()
+      else if(e.deltaY > 0) execNext()
     }, 500, { leading: true, trailing: false })
 
     onMounted(() => {
@@ -112,6 +149,15 @@ export default defineComponent({
       document.removeEventListener('keydown', keydownListener)
     })
 
+    const turnPrevSlide = () => {
+      store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value - 1)
+      animationIndex.value = 0
+    }
+    const turnNextSlide = () => {
+      store.commit(MutationTypes.UPDATE_SLIDE_INDEX, slideIndex.value + 1)
+      animationIndex.value = 0
+    }
+
     const contextmenus = (): ContextmenuItem[] => {
       return [
         {
@@ -140,6 +186,7 @@ export default defineComponent({
       slideHeight,
       scale,
       mousewheelListener,
+      animationIndex,
       contextmenus,
     }
   },

+ 1 - 1
src/views/_element/BaseElement.vue

@@ -18,7 +18,7 @@ import BaseImageElement from './ImageElement/BaseImageElement.vue'
 import BaseTextElement from './TextElement/BaseTextElement.vue'
 
 export default defineComponent({
-  name: 'editable-element',
+  name: 'base-element',
   props: {
     elementInfo: {
       type: Object as PropType<PPTElement>,

+ 66 - 0
src/views/_element/ScreenElement.vue

@@ -0,0 +1,66 @@
+<template>
+  <div 
+    class="screen-element"
+    :style="{
+      zIndex: elementIndex,
+      visibility: needWaitAnimation ? 'hidden' : 'visible',
+    }"
+  >
+    <component
+      :is="currentElementComponent"
+      :elementInfo="elementInfo"
+    ></component>
+  </div>
+</template>
+
+<script lang="ts">
+import { computed, defineComponent, PropType, Ref } from 'vue'
+import { useStore } from 'vuex'
+import { State } from '@/store'
+import { PPTElement, Slide } from '@/types/slides'
+
+import BaseImageElement from './ImageElement/BaseImageElement.vue'
+import BaseTextElement from './TextElement/BaseTextElement.vue'
+
+export default defineComponent({
+  name: 'screen-element',
+  props: {
+    elementInfo: {
+      type: Object as PropType<PPTElement>,
+      required: true,
+    },
+    elementIndex: {
+      type: Number,
+      required: true,
+    },
+    animationIndex: {
+      type: Number,
+      default: -1,
+    },
+  },
+  setup(props) {
+    const currentElementComponent = computed(() => {
+      const elementTypeMap = {
+        'image': BaseImageElement,
+        'text': BaseTextElement,
+      }
+      return elementTypeMap[props.elementInfo.type] || null
+    })
+
+    const store = useStore<State>()
+    const currentSlide: Ref<Slide> = computed(() => store.getters.currentSlide)
+
+    const needWaitAnimation = computed(() => {
+      const animations = currentSlide.value.animations || []
+      const elementIndexInAnimation = animations.findIndex(animation => animation.elId === props.elementInfo.id)
+      if(elementIndexInAnimation !== -1 && elementIndexInAnimation >= props.animationIndex) return true
+      return false      
+    })
+
+    return {
+      currentElementComponent,
+      needWaitAnimation,
+    }
+  },
+})
+</script>