|
@@ -189,34 +189,33 @@ function themifyScript(
|
|
|
|
|
|
2、将图组放入指定脚本的工作区内生成可用的vue组件,脚本可见项目的README文档,然后自行新建文件、复制代码、安装依赖并运行
|
|
|
|
|
|
-3、将可用的vue组件引入到需要使用动画的页面中,并使用useSvgAnimation钩子进行动画控制,例如`<SVGAnimation :manager="animationManager" />`
|
|
|
+3、将可用的vue组件引入到需要使用动画的页面中,并使用useSvgAnimation钩子进行动画控制,例如`<SVGAnimation ref="svgRef" />`
|
|
|
|
|
|
-4、通过浏览器的元素检查功能,找到svg对应的group,复制group的id,并使用该id进行动画控制
|
|
|
+4、通过浏览器的元素检查功能,找到svg对应的group,复制group的id,并使用该id进行动画控制,详细可见步骤2中生成的组件的`animate`方法注释
|
|
|
|
|
|
使用示例:
|
|
|
|
|
|
```vue
|
|
|
<template>
|
|
|
- <SVGAni :manager="animationManager" />
|
|
|
+ <SVGAni ref="svgRef" />
|
|
|
</template>
|
|
|
<script setup>
|
|
|
import SVGAni from 'path/to/SVGAnimation.vue';
|
|
|
- import useSvgAnimation from 'path/to/useSvgAnimation.ts';
|
|
|
|
|
|
- const { animationManager,triggerAnimation } = useSvgAnimation();
|
|
|
+ const modelRef = ref();
|
|
|
|
|
|
onMounted(() => {
|
|
|
- // 根据情况触发动画
|
|
|
+ // 根据情况触发动画,每个组件有各自的animate实现,需要传入不同的参数
|
|
|
if (condition) {
|
|
|
- triggerAnimation('id', false);
|
|
|
- } else {
|
|
|
- triggerAnimation('id', true);
|
|
|
- }
|
|
|
- })
|
|
|
+ modelRef.value?.animate?.(specialArgs);
|
|
|
+ } else {
|
|
|
+ modelRef.value?.animate?.(specialArgs);
|
|
|
+ }
|
|
|
+ });
|
|
|
</script>
|
|
|
```
|
|
|
|
|
|
-上述的生成组件的脚本如下:
|
|
|
+上述的生成组件的脚本如下,注意脚本需要独立安装依赖运行:
|
|
|
|
|
|
```javascript
|
|
|
const fs = require('fs');
|
|
@@ -408,14 +407,9 @@ function generateVueComponent(svgContent, elementInfoMap, keys) {
|
|
|
return `
|
|
|
<template>\n${svgContent}\n</template>\n\n
|
|
|
<script setup lang="ts">
|
|
|
-import { watch, onMounted, defineExpose, defineProps } from "vue";
|
|
|
+import { onMounted, defineExpose } from "vue";
|
|
|
+import { useSvgAnimation } from '/@/hooks/vent/useSvgAnimation';
|
|
|
|
|
|
-const props = defineProps<{
|
|
|
- manager: Record<string, boolean>;
|
|
|
-}>();
|
|
|
-
|
|
|
-// 存储所有动画元素(不在模板中使用,不需要ref)
|
|
|
-const animElements = new Map<string, HTMLElement>();
|
|
|
|
|
|
// 元素信息(常量数据,使用Map)
|
|
|
const elementInfo = new Map([
|
|
@@ -424,55 +418,27 @@ ${Array.from(elementInfoMap.entries())
|
|
|
.join(',\n')}
|
|
|
]);
|
|
|
|
|
|
+const { animationElements, triggerAnimation } = useSvgAnimation(elementInfo);
|
|
|
+
|
|
|
// 初始化元素引用
|
|
|
onMounted(() => {
|
|
|
- elementInfo.forEach((info, elementId) => {
|
|
|
+ elementInfo.forEach((__, elementId) => {
|
|
|
const el = document.querySelector(\`[data-anim-id="\${elementId}"]\`);
|
|
|
if (el) {
|
|
|
- animElements.set(elementId, el as HTMLElement);
|
|
|
- // 设置初始transform
|
|
|
- const initialTransform = info.transforms[0] || '';
|
|
|
- el.setAttribute('transform', initialTransform);
|
|
|
+ animationElements.set(elementId, el as HTMLElement);
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
|
|
|
-// 监听manager变化并执行动画
|
|
|
-watch(() => props.manager, (newManager) => {
|
|
|
- Object.keys(newManager).forEach(key => {
|
|
|
- const isActive = newManager[key];
|
|
|
-
|
|
|
- // 找到所有属于这个key的元素
|
|
|
- animateByKey(key, isActive);
|
|
|
- });
|
|
|
-}, { deep: true });
|
|
|
-
|
|
|
-// 直接控制动画的方法
|
|
|
-const animateElement = (elementId: string, toEnd: boolean, duration: number = 3000) => {
|
|
|
- const el = animElements.get(elementId);
|
|
|
- const info = elementInfo.get(elementId);
|
|
|
-
|
|
|
- if (el && info && info.transforms.length > 1) {
|
|
|
- el.style.transition = \`transform \${duration}ms\`;
|
|
|
- el.setAttribute('transform', toEnd ? info.transforms[info.transforms.length - 1] : info.transforms[0]);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 批量控制同一key的所有元素
|
|
|
-const animateByKey = (key: string, toEnd: boolean, duration: number = 3000) => {
|
|
|
- animElements.forEach((el, elementId) => {
|
|
|
- const info = elementInfo.get(elementId);
|
|
|
- if (info && info.key === key) {
|
|
|
- animateElement(elementId, toEnd, duration);
|
|
|
- }
|
|
|
- });
|
|
|
-};
|
|
|
-
|
|
|
+/** 根据SVG的使用场景播放动画 */
|
|
|
+function animate() {
|
|
|
+ // 在SVG图片中,找到需要动起来的元素(类似<use xlink:href="#RE_L_0_Layer0_0_FILL"></use>),并填入id即可控制该元素的动画(如有)
|
|
|
+ // triggerAnimation(["${keys.join('","')}"], false);
|
|
|
+}
|
|
|
|
|
|
// 导出方法以便外部调用
|
|
|
defineExpose({
|
|
|
- animateElement,
|
|
|
- animateByKey
|
|
|
+ animate,
|
|
|
});
|
|
|
</script>
|
|
|
<style scoped>
|
|
@@ -507,13 +473,25 @@ async function main() {
|
|
|
const files = fs
|
|
|
.readdirSync(workspaceDir)
|
|
|
.filter((file) => file.endsWith('.svg'))
|
|
|
- .sort(); // 按字母顺序排序以确保正确的动画顺序
|
|
|
+ .sort((a, b) => {
|
|
|
+ const getNumber = (filename) => {
|
|
|
+ // 匹配文件名中的数字(在最后以后缀形式例如_1、_2)
|
|
|
+ const arr = filename.split('_');
|
|
|
+ return parseInt(arr[arr.length - 1]);
|
|
|
+ };
|
|
|
+
|
|
|
+ const numA = getNumber(a);
|
|
|
+ const numB = getNumber(b);
|
|
|
+
|
|
|
+ return numA - numB;
|
|
|
+ });
|
|
|
|
|
|
if (files.length === 0) {
|
|
|
throw new Error('workspace目录下没有找到SVG文件');
|
|
|
}
|
|
|
|
|
|
console.log(`找到 ${files.length} 个SVG文件`);
|
|
|
+ console.log(`序列为:\n${files.join('\n')}`);
|
|
|
|
|
|
// 读取第一个SVG文件
|
|
|
const firstSvgPath = path.join(workspaceDir, files[0]);
|