Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
D
DC-TOM
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
刘照晖
DC-TOM
Commits
d5e2c6c8
Commit
d5e2c6c8
authored
Aug 12, 2025
by
Cai Wei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat(*): 添加动画效果
parent
2efabdd5
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
567 additions
and
192 deletions
+567
-192
package-lock.json
package-lock.json
+11
-0
package.json
package.json
+1
-0
gsapNumber.vue
src/views/dustMonitoring/components/gsapNumber.vue
+343
-0
index.vue
src/views/dustMonitoring/index.vue
+212
-192
No files found.
package-lock.json
View file @
d5e2c6c8
...
...
@@ -13,6 +13,7 @@
"crypto-js"
:
"^4.2.0"
,
"echarts"
:
"^5.6.0"
,
"element-plus"
:
"^2.9.10"
,
"gsap"
:
"^3.13.0"
,
"js-cookie"
:
"^3.0.5"
,
"moment"
:
"^2.30.1"
,
"nprogress"
:
"^0.2.0"
,
...
...
@@ -1698,6 +1699,11 @@
"url"
:
"https://github.com/sponsors/ljharb"
}
},
"node_modules/gsap"
:
{
"version"
:
"3.13.0"
,
"resolved"
:
"https://registry.npmmirror.com/gsap/-/gsap-3.13.0.tgz"
,
"integrity"
:
"sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw=="
},
"node_modules/has-symbols"
:
{
"version"
:
"1.1.0"
,
"resolved"
:
"https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz"
,
...
...
@@ -3452,6 +3458,11 @@
"resolved"
:
"https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz"
,
"integrity"
:
"sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="
},
"gsap"
:
{
"version"
:
"3.13.0"
,
"resolved"
:
"https://registry.npmmirror.com/gsap/-/gsap-3.13.0.tgz"
,
"integrity"
:
"sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw=="
},
"has-symbols"
:
{
"version"
:
"1.1.0"
,
"resolved"
:
"https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz"
,
...
...
package.json
View file @
d5e2c6c8
...
...
@@ -14,6 +14,7 @@
"
crypto-js
"
:
"
^4.2.0
"
,
"
echarts
"
:
"
^5.6.0
"
,
"
element-plus
"
:
"
^2.9.10
"
,
"
gsap
"
:
"
^3.13.0
"
,
"
js-cookie
"
:
"
^3.0.5
"
,
"
moment
"
:
"
^2.30.1
"
,
"
nprogress
"
:
"
^0.2.0
"
,
...
...
src/views/dustMonitoring/components/gsapNumber.vue
0 → 100644
View file @
d5e2c6c8
<
template
>
<div
class=
"gsap-number-container"
>
<div
:class=
"['value', colorClass]"
ref=
"numberElement"
>
{{
isStringMode
?
stringValue
:
displayValue
}}
</div>
</div>
</
template
>
<
script
setup
>
import
{
ref
,
onMounted
,
watch
,
defineProps
,
defineEmits
,
onUnmounted
,
computed
}
from
'vue'
;
import
gsap
from
'gsap'
;
const
props
=
defineProps
({
// 要显示的目标数字或字符串
value
:
{
type
:
[
Number
,
String
],
required
:
true
,
default
:
0
},
// 数字的初始值
startValue
:
{
type
:
Number
,
default
:
0
},
// 动画持续时间(秒)
duration
:
{
type
:
Number
,
default
:
1
},
// 是否启用颜色变化
enableColorChange
:
{
type
:
Boolean
,
default
:
false
},
// 数字的小数位数
decimals
:
{
type
:
Number
,
default
:
0
},
// 数字的前缀
prefix
:
{
type
:
String
,
default
:
''
},
// 数字的后缀
suffix
:
{
type
:
String
,
default
:
''
},
// 是否在组件挂载时自动开始动画
autoStart
:
{
type
:
Boolean
,
default
:
true
},
// 动画类型
animationType
:
{
type
:
String
,
default
:
'count'
,
// 'count', 'bounce', 'color'
validator
:
(
value
)
=>
[
'count'
,
'bounce'
,
'color'
].
includes
(
value
)
},
// 颜色阈值(用于颜色变化)
colorThresholds
:
{
type
:
Object
,
default
:
()
=>
({
low
:
{
value
:
30
,
color
:
'#e74c3c'
},
// 红色
medium
:
{
value
:
70
,
color
:
'#f39c12'
},
// 橙色
high
:
{
value
:
100
,
color
:
'#36f1cd'
}
// 绿色
})
},
// 动画触发间隔(毫秒),默认为0表示不自动触发
animationInterval
:
{
type
:
Number
,
default
:
0
}
});
const
emit
=
defineEmits
([
'animation-complete'
]);
const
displayValue
=
ref
(
props
.
startValue
);
const
stringValue
=
ref
(
''
);
const
numberElement
=
ref
(
null
);
const
colorClass
=
ref
(
'blue'
);
// 默认颜色类
const
intervalTimer
=
ref
(
null
);
// 判断是否为字符串模式
const
isStringMode
=
computed
(()
=>
typeof
props
.
value
===
'string'
);
// 格式化数字显示
const
formatNumber
=
(
num
)
=>
{
// 判断传入的值有多少位小数
const
numStr
=
String
(
num
);
const
decimalParts
=
numStr
.
split
(
'.'
);
const
decimalPlaces
=
decimalParts
.
length
>
1
?
decimalParts
[
1
].
length
:
0
;
// 使用传入值的小数位数,而不是props.decimals
const
formattedNum
=
parseFloat
(
num
).
toFixed
(
decimalPlaces
);
return
`
${
props
.
prefix
}${
formattedNum
}${
props
.
suffix
}
`
;
};
// 根据值确定颜色
const
determineColor
=
(
value
)
=>
{
const
{
low
,
medium
,
high
}
=
props
.
colorThresholds
;
if
(
value
<=
low
.
value
)
return
'red'
;
if
(
value
<=
medium
.
value
)
return
'orange'
;
return
'green'
;
};
// 执行计数动画
const
animateCount
=
()
=>
{
// 如果是字符串模式,直接设置值并执行弹跳动画
if
(
isStringMode
.
value
)
{
stringValue
.
value
=
props
.
value
;
animateBounceForString
();
return
;
}
const
obj
=
{
value
:
props
.
startValue
};
// 保存目标值的小数位数
const
targetValueStr
=
String
(
props
.
value
);
const
decimalParts
=
targetValueStr
.
split
(
'.'
);
const
targetDecimalPlaces
=
decimalParts
.
length
>
1
?
decimalParts
[
1
].
length
:
0
;
gsap
.
to
(
obj
,
{
value
:
props
.
value
,
duration
:
props
.
duration
,
ease
:
"power2.inOut"
,
onUpdate
:
function
()
{
// 动画过程中使用整数递增
const
intValue
=
Math
.
floor
(
obj
.
value
);
displayValue
.
value
=
`
${
props
.
prefix
}${
intValue
}${
props
.
suffix
}
`
;
if
(
props
.
enableColorChange
)
{
colorClass
.
value
=
determineColor
(
obj
.
value
);
}
},
onComplete
:
()
=>
{
// 动画完成时显示原始值的完整格式(包含小数)
displayValue
.
value
=
formatNumber
(
props
.
value
);
emit
(
'animation-complete'
);
}
});
};
// 执行弹跳动画
const
animateBounce
=
()
=>
{
// 如果是字符串模式,使用字符串弹跳动画
if
(
isStringMode
.
value
)
{
stringValue
.
value
=
props
.
value
;
animateBounceForString
();
return
;
}
// 首先更新值
displayValue
.
value
=
formatNumber
(
props
.
value
);
// 然后添加弹跳动画
const
tl
=
gsap
.
timeline
();
tl
.
from
(
numberElement
.
value
,
{
scale
:
0.5
,
duration
:
0.5
,
ease
:
"back.out(1.7)"
});
tl
.
to
(
numberElement
.
value
,
{
scale
:
1.2
,
duration
:
0.3
,
ease
:
"power2.inOut"
});
tl
.
to
(
numberElement
.
value
,
{
scale
:
1
,
duration
:
0.3
,
ease
:
"power2.inOut"
,
onComplete
:
()
=>
{
emit
(
'animation-complete'
);
}
});
};
// 字符串的弹跳动画
const
animateBounceForString
=
()
=>
{
const
tl
=
gsap
.
timeline
();
tl
.
from
(
numberElement
.
value
,
{
scale
:
0.5
,
duration
:
0.5
,
ease
:
"back.out(1.7)"
});
tl
.
to
(
numberElement
.
value
,
{
scale
:
1.1
,
duration
:
0.3
,
ease
:
"power2.inOut"
});
tl
.
to
(
numberElement
.
value
,
{
scale
:
1
,
duration
:
0.3
,
ease
:
"power2.inOut"
,
onComplete
:
()
=>
{
emit
(
'animation-complete'
);
}
});
};
// 执行颜色变化动画
const
animateColor
=
()
=>
{
// 如果是字符串模式,使用字符串弹跳动画
if
(
isStringMode
.
value
)
{
stringValue
.
value
=
props
.
value
;
animateBounceForString
();
return
;
}
// 首先执行计数动画
const
obj
=
{
value
:
props
.
startValue
};
// 确定目标颜色
const
targetColor
=
props
.
enableColorChange
?
props
.
colorThresholds
[
determineColor
(
props
.
value
)].
color
:
'#36f1cd'
;
gsap
.
to
(
obj
,
{
value
:
props
.
value
,
duration
:
props
.
duration
,
ease
:
"power2.inOut"
,
onUpdate
:
function
()
{
// 动画过程中使用整数递增
const
intValue
=
Math
.
floor
(
obj
.
value
);
displayValue
.
value
=
`
${
props
.
prefix
}${
intValue
}${
props
.
suffix
}
`
;
},
onComplete
:
()
=>
{
// 动画完成时显示原始值的完整格式(包含小数)
displayValue
.
value
=
formatNumber
(
props
.
value
);
}
});
// 同时执行颜色变化
gsap
.
to
(
numberElement
.
value
,
{
color
:
targetColor
,
duration
:
props
.
duration
,
ease
:
"power2.inOut"
,
onComplete
:
()
=>
{
emit
(
'animation-complete'
);
}
});
};
// 开始动画
const
startAnimation
=
()
=>
{
switch
(
props
.
animationType
)
{
case
'bounce'
:
animateBounce
();
break
;
case
'color'
:
animateColor
();
break
;
case
'count'
:
default
:
animateCount
();
break
;
}
};
// 设置定时器
const
setupIntervalTimer
=
()
=>
{
// 清除之前的定时器
if
(
intervalTimer
.
value
)
{
clearInterval
(
intervalTimer
.
value
);
intervalTimer
.
value
=
null
;
}
// 如果设置了有效的间隔时间,则创建新的定时器
if
(
props
.
animationInterval
>
0
)
{
intervalTimer
.
value
=
setInterval
(()
=>
{
startAnimation
();
},
props
.
animationInterval
);
}
};
// 监听值变化
watch
(()
=>
props
.
value
,
(
newValue
)
=>
{
// 如果是字符串,直接设置值
if
(
typeof
newValue
===
'string'
)
{
stringValue
.
value
=
newValue
;
}
startAnimation
();
});
// 监听间隔时间变化
watch
(()
=>
props
.
animationInterval
,
()
=>
{
setupIntervalTimer
();
});
// 组件挂载时
onMounted
(()
=>
{
// 如果初始值是字符串,直接设置
if
(
typeof
props
.
value
===
'string'
)
{
stringValue
.
value
=
props
.
value
;
}
if
(
props
.
autoStart
)
{
startAnimation
();
}
// 设置定时器(如果有指定间隔)
setupIntervalTimer
();
});
// 组件卸载时清除定时器
onUnmounted
(()
=>
{
if
(
intervalTimer
.
value
)
{
clearInterval
(
intervalTimer
.
value
);
intervalTimer
.
value
=
null
;
}
});
</
script
>
<
style
scoped
>
.gsap-number-container
{
width
:
100%
;
}
.value
{
transition
:
color
0.3s
ease
;
}
.blue
{
color
:
#fff
;
}
.green
{
color
:
#fff
;
}
.orange
{
color
:
#fff
;
}
.red
{
color
:
#fff
;
}
</
style
>
\ No newline at end of file
src/views/dustMonitoring/index.vue
View file @
d5e2c6c8
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment