vue 3 + mo.js 实现点赞粒子特效【实战】
最终效果为方便大家下载,开源gitee地址如下点赞粒子效果 (gitee.com)文章较长,建议一步一步跟着走创建一个项目首先我们创建一个vue3.2项目详情请见Vue3+TypeScript 项目创建_qq_22841387的博客-CSDN博客,这里就不赘述了这里选择默认即可一、显示页面1.新建页面在components文件夹下新建页面ThumbsUp.vue单文件组件遵循 大驼峰原则2.写部分
最终效果
为方便大家下载,开源gitee地址如下
点赞粒子效果 (gitee.com)
文章较长,建议一步一步跟着走
创建一个项目
首先我们创建一个vue3.2项目
详情请见Vue3+TypeScript 项目创建_qq_22841387的博客-CSDN博客,这里就不赘述了
这里选择默认即可
一、显示页面
1.新建页面
在components
文件夹下新建页面ThumbsUp.vue
单文件组件遵循 大驼峰原则
2.写部分显示代码
<template>
<h1>点赞页面</h1>
</template>
<script>
export default {
}
</script>
<style>
</style>
3.导入文件
在App.vue
文件下导入文件
可直接写名字(Vue 3会自动导入)
4.将其他的注释掉
<template>
<!-- <img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/> -->
<thumbs-up></thumbs-up>
</template>
<script>
// import HelloWorld from './components/HelloWorld.vue'
import ThumbsUp from './components/ThumbsUp.vue'
export default {
name: 'App',
components: {
// HelloWorld,
ThumbsUp
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
二、下载点赞图片
1.打开阿里云矢量库
打开下方链接
选择一个你喜欢的图标下载,最好是空心的
2.复制SVG代码
选择完成后,将鼠标移动至所选图标
点击下载
在弹出的窗口中,选择复制SVG代码,直接粘贴到目标文件ThumbsUp.vue
3.调整样式
css建议书写顺序:
- 布局定位属性:display / position / float / clear / visibility / overflow
- 自身属性:width / height / margin / padding / border / background
- 文本属性:color / font / text-decoration / text-align / vertical-align / white- space / break-word
- 其他属性(CSS3):content / cursor / border-radius / box-shadow / text-shadow / background: linear-gradient …
示例代码:
.jdc { display: block; position: relative; float: left; width: 100px; height: 100px; margin: 0 10px; padding: 20px 0; font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; color: #333; background: rgba(0,0,0,.5); -webkit-border-radius: 10px; -moz-border-radius: 10px; -o-border-radius: 10px; -ms-border-radius: 10px; border-radius: 10px; }
①包裹整体、爱心和文字
这里我使用
thums-up
包裹整体,局部心形用heart
包裹
<template>
<h3>点赞页面</h3>
<div class="thums-up">
<div class="heart">
<svg
t="1644501913302"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1268"
width="25"
height="20"
>
<path
d="M171.712 571.648l0.352 0.32 287.904 252.8a64 64 0 0 0 82.912 1.344l296.832-244.544a215.584 215.584 0 1 0-301.824-300.576L512 316.672l-25.888-35.616a215.584 215.584 0 1 0-314.4 290.624zM32 407.584a279.584 279.584 0 0 1 480-194.944 279.584 279.584 0 0 1 480 194.944 278.144 278.144 0 0 1-113.024 224.512l-295.36 243.392a128 128 0 0 1-165.888-2.592L129.984 620.16A278.976 278.976 0 0 1 32 407.584z"
p-id="1269"
></path>
</svg>
</div>
<div class="thums-up-text"><span>点赞</span></div>
</div>
</template>
②修改总体样式
.thums-up {
display: flex;
align-items: center;
justify-content: center;
height: 24px;
cursor: pointer;
}
③修改心
样式
.thums-up .heart {
display: inline-flex;
position: relative;
height: 20px;
}
④修改svg
样式
.thums-up .heart svg {
stroke: #9A9DAA;
stroke-width: 30px;
transition: fill 0.3s , stroke 0.3s;
fill: transparent;
}
给一个延迟的动画效果,显得没有那么突兀
⑤修改文字样式
.thums-up-text {
margin-left: 1px;
font-size: 13px;
user-select: none; // 用户不可选择
}
⑥增加鼠标悬浮效果
.thums-up:hover .heart svg {
stroke: #e05b5b;
}
当前效果
三、制作粒子扩散效果
1.安装mo.js
这里使用的是一个轻量级的图形动画库
npm install @mojs/core
或者使用cnpm
安装也可以,会快一些
cnpm install @mojs/core
出现无法安装的问题可查看这篇文章
2.页面引用
<script>
import mojs from '@mojs/core'
export default {
setup(){
new mojs.Timeline()
}
};
</script>
3.构建特效
这里我们使用的是Burst(炸裂)
特效
①定义ref
(响应式数据)
<div class="heart" ref="heart">
……
const heart = ref(null);
②构建burst
let burst;
onMounted(() => {
burst = new mojs.Burst({
// 爆炸范围
radius: { 0: 50 },
// 动画挂载父元素,默认改在到body上
parent: heart.value,
// 动画延时函数
easing: mojs.easing.bezier(0.1, 1, 0.3, 1),
// 动画延时时间
duration: 1500,
// 动画等待时间
delay: 300,
// 扩散的粒子配置
children: {
duration: 750,
// 随机数范围爆炸
radius: { 0: "rand(5,25)" },
shape: ["circle", "rect", "polygon"],
// 粒子可选色
fill: [
"#1abc9c",
"#2ecc71",
"#00cec9",
"#3498db",
"#9b59b6",
"#fdcb6e",
"#f1c40f",
"#e67e22",
"#e74c3c",
"#e84393",
],
degreeShift: "rand(-90, 90)",
delay: "stagger(0, 40)",
},
// 透明度
opacity: 0.6,
// 生成粒子数量
count: 10,
});
});
③调用动画
<div class="thums-up" @click="thumbsUp">
……
function thumbsUp() {
new mojs.Timeline().add(burst).play();
}
<template>
<h3>点赞页面</h3>
<div class="thums-up" @click="thumbsUp">
<div class="heart" ref="heart">
<svg
t="1644501913302"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1268"
width="25"
height="20"
>
<path
d="M171.712 571.648l0.352 0.32 287.904 252.8a64 64 0 0 0 82.912 1.344l296.832-244.544a215.584 215.584 0 1 0-301.824-300.576L512 316.672l-25.888-35.616a215.584 215.584 0 1 0-314.4 290.624zM32 407.584a279.584 279.584 0 0 1 480-194.944 279.584 279.584 0 0 1 480 194.944 278.144 278.144 0 0 1-113.024 224.512l-295.36 243.392a128 128 0 0 1-165.888-2.592L129.984 620.16A278.976 278.976 0 0 1 32 407.584z"
p-id="1269"
></path>
</svg>
</div>
<div class="thums-up-text"><span>点赞</span></div>
</div>
</template>
<script>
import mojs from "@mojs/core";
import { ref, onMounted } from "vue";
export default {
setup() {
const heart = ref(null);
let burst;
onMounted(() => {
burst = new mojs.Burst({
// 爆炸范围
radius: { 0: 50 },
// 动画挂载父元素,默认改在到body上
parent: heart.value,
// 动画延时函数
easing: mojs.easing.bezier(0.1, 1, 0.3, 1),
// 动画延时时间
duration: 1500,
// 动画等待时间
delay: 300,
// 扩散的粒子配置
children: {
duration: 750,
// 随机数范围爆炸
radius: { 0: "rand(5,25)" },
shape: ["circle", "rect", "polygon"],
// 粒子可选色
fill: [
"#1abc9c",
"#2ecc71",
"#00cec9",
"#3498db",
"#9b59b6",
"#fdcb6e",
"#f1c40f",
"#e67e22",
"#e74c3c",
"#e84393",
],
degreeShift: "rand(-90, 90)",
delay: "stagger(0, 40)",
},
// 透明度
opacity: 0.6,
// 生成粒子数量
count: 10,
});
});
function thumbsUp() {
new mojs.Timeline().add(burst).play();
}
return {
heart,
burst,
thumbsUp,
};
},
};
</script>
<style>
.thums-up {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
height: 24px;
}
.thums-up .heart {
display: inline-flex;
position: relative;
height: 20px;
}
.thums-up .heart svg {
stroke: #9a9daa;
stroke-width: 30px;
transition: fill 0.3s, stroke 0.3s;
fill: transparent;
}
.thums-up:hover .heart svg {
stroke: #e05b5b;
}
.thums-up-text {
margin-left: 1px;
font-size: 13px;
user-select: none;
}
</style>
阶段演示效果
四、制作红晕
使用mo.js
中的Transit制作一个空心的圆形
1.定义ref
<svg
ref="heart_icon"
t="1644501913302"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1268"
width="25"
height="20"
>
……
const heart_icon = ref(null);
2.构建aperture
let burst , aperture;
aperture = new mojs.Transit({
parent: heart.value,
duration: 750,
type: 'circle',
radius: { 0 : 20 },
fill: 'transparent',
stroke: '#E05B5B',
strokeWidth: { 20 : 0 },
opacity: 0.6,
isRunless: true,
easing: mojs.easing.bezier(0, 1, 0.5, 1)
})
3.增加动画
function thumbsUp() {
new mojs.Timeline().add(burst , aperture).play();
}
<template>
<h3>点赞页面</h3>
<div class="thums-up" @click="thumbsUp">
<div class="heart" ref="heart">
<svg
ref="heart_icon"
t="1644501913302"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1268"
width="25"
height="20"
>
<path
d="M171.712 571.648l0.352 0.32 287.904 252.8a64 64 0 0 0 82.912 1.344l296.832-244.544a215.584 215.584 0 1 0-301.824-300.576L512 316.672l-25.888-35.616a215.584 215.584 0 1 0-314.4 290.624zM32 407.584a279.584 279.584 0 0 1 480-194.944 279.584 279.584 0 0 1 480 194.944 278.144 278.144 0 0 1-113.024 224.512l-295.36 243.392a128 128 0 0 1-165.888-2.592L129.984 620.16A278.976 278.976 0 0 1 32 407.584z"
p-id="1269"
></path>
</svg>
</div>
<div class="thums-up-text"><span>点赞</span></div>
</div>
</template>
<script>
import mojs from "@mojs/core";
import { ref, onMounted } from "vue";
export default {
setup() {
const heart = ref(null);
const heart_icon = ref(null);
let burst , aperture;
/**
* burst 扩散
* aperture 红色光圈(红晕)
*/
onMounted(() => {
burst = new mojs.Burst({
// 爆炸范围
radius: { 0: 50 },
// 动画挂载父元素,默认改在到body上
parent: heart.value,
// 动画延时函数
easing: mojs.easing.bezier(0.1, 1, 0.3, 1),
// 动画延时时间
duration: 1500,
// 动画等待时间
delay: 300,
// 扩散的粒子配置
children: {
duration: 750,
// 随机数范围爆炸
radius: { 0: "rand(5,25)" },
shape: ["circle", "rect", "polygon"],
// 粒子可选色
fill: [
"#1abc9c",
"#2ecc71",
"#00cec9",
"#3498db",
"#9b59b6",
"#fdcb6e",
"#f1c40f",
"#e67e22",
"#e74c3c",
"#e84393",
],
degreeShift: "rand(-90, 90)",
delay: "stagger(0, 40)",
},
// 透明度
opacity: 0.6,
// 生成粒子数量
count: 10,
});
aperture = new mojs.Transit({
parent: heart.value,
duration: 750,
type: 'circle',
radius: { 0 : 20 },
fill: 'transparent',
stroke: '#E05B5B',
strokeWidth: { 20 : 0 },
opacity: 0.6,
isRunless: true,
easing: mojs.easing.bezier(0, 1, 0.5, 1)
})
});
function thumbsUp() {
new mojs.Timeline().add(burst , aperture).play();
}
return {
heart,
heart_icon,
burst,
aperture,
thumbsUp,
};
},
};
</script>
<style>
.thums-up {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
height: 24px;
}
.thums-up .heart {
display: inline-flex;
position: relative;
height: 20px;
}
.thums-up .heart svg {
stroke: #9a9daa;
stroke-width: 30px;
transition: fill 0.3s, stroke 0.3s;
fill: transparent;
}
.thums-up:hover .heart svg {
stroke: #e05b5b;
}
.thums-up-text {
margin-left: 1px;
font-size: 13px;
user-select: none;
}
</style>
阶段演示效果
五、制作已点赞效果
1.心形样式绑定
<svg
ref="heart_icon"
:style="heartStyle"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
>
<path
d="M533.504 268.288q33.792-41.984 71.68-75.776 32.768-27.648 74.24-50.176t86.528-19.456q63.488 5.12 105.984 30.208t67.584 63.488 34.304 87.04 6.144 99.84-17.92 97.792-36.864 87.04-48.64 74.752-53.248 61.952q-40.96 41.984-85.504 78.336t-84.992 62.464-73.728 41.472-51.712 15.36q-20.48 1.024-52.224-14.336t-69.632-41.472-79.872-61.952-82.944-75.776q-26.624-25.6-57.344-59.392t-57.856-74.24-46.592-87.552-21.504-100.352 11.264-99.84 39.936-83.456 65.536-61.952 88.064-35.328q24.576-5.12 49.152-1.536t48.128 12.288 45.056 22.016 40.96 27.648q45.056 33.792 86.016 80.896z"
p-id="2432"
></path>
</svg>
……
// 是否已点赞
const hearted = ref(false)
const heartBounce = ref(1)
const heartStyle = computed(() => {
return {
fill: `${hearted.value ? '#E05B5B' : ''}`,
stroke: `${hearted.value ? 'E05B5B' : ''}`,
transform: `scale3d(${heartBounce.value},${heartBounce.value},1)`,
}
})
2.炸裂效果点赞
burst = new mojs.Burst({
// 爆炸范围
radius: { 0: 50 },
……
onStart(){
hearted.value = true
}
});
<template>
<h3>点赞页面</h3>
<div class="thums-up" @click="thumbsUp">
<div class="heart" ref="heart">
<!-- <svg
ref="heart_icon"
:style="heartStyle"
t="1644501913302"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1268"
width="25"
height="20"
>
<path
d="M171.712 571.648l0.352 0.32 287.904 252.8a64 64 0 0 0 82.912 1.344l296.832-244.544a215.584 215.584 0 1 0-301.824-300.576L512 316.672l-25.888-35.616a215.584 215.584 0 1 0-314.4 290.624zM32 407.584a279.584 279.584 0 0 1 480-194.944 279.584 279.584 0 0 1 480 194.944 278.144 278.144 0 0 1-113.024 224.512l-295.36 243.392a128 128 0 0 1-165.888-2.592L129.984 620.16A278.976 278.976 0 0 1 32 407.584z"
p-id="1269"
></path>
</svg> -->
<svg
ref="heart_icon"
:style="heartStyle"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
>
<path
d="M533.504 268.288q33.792-41.984 71.68-75.776 32.768-27.648 74.24-50.176t86.528-19.456q63.488 5.12 105.984 30.208t67.584 63.488 34.304 87.04 6.144 99.84-17.92 97.792-36.864 87.04-48.64 74.752-53.248 61.952q-40.96 41.984-85.504 78.336t-84.992 62.464-73.728 41.472-51.712 15.36q-20.48 1.024-52.224-14.336t-69.632-41.472-79.872-61.952-82.944-75.776q-26.624-25.6-57.344-59.392t-57.856-74.24-46.592-87.552-21.504-100.352 11.264-99.84 39.936-83.456 65.536-61.952 88.064-35.328q24.576-5.12 49.152-1.536t48.128 12.288 45.056 22.016 40.96 27.648q45.056 33.792 86.016 80.896z"
p-id="2432"
></path>
</svg>
</div>
<div class="thums-up-text"><span>点赞</span></div>
</div>
</template>
<script>
import mojs from "@mojs/core";
import { ref, onMounted, computed } from "vue";
export default {
setup() {
const heart = ref(null);
const heart_icon = ref(null);
// 是否已点赞
const hearted = ref(false);
const heartBounce = ref(1);
const heartStyle = computed(() => {
return {
fill: `${hearted.value ? "#E05B5B" : ""}`,
stroke: `${hearted.value ? "E05B5B" : ""}`,
transform: `scale3d(${heartBounce.value},${heartBounce.value},1)`,
};
});
let burst, aperture;
/**
* burst 扩散
* aperture 红色光圈(红晕)
*/
onMounted(() => {
burst = new mojs.Burst({
// 爆炸范围
radius: { 0: 50 },
// 动画挂载父元素,默认改在到body上
parent: heart.value,
// 动画延时函数
easing: mojs.easing.bezier(0.1, 1, 0.3, 1),
// 动画延时时间
duration: 1500,
// 动画等待时间
delay: 300,
// 扩散的粒子配置
children: {
duration: 750,
// 随机数范围爆炸
radius: { 0: "rand(5,25)" },
shape: ["circle", "rect", "polygon"],
// 粒子可选色
fill: [
"#1abc9c",
"#2ecc71",
"#00cec9",
"#3498db",
"#9b59b6",
"#fdcb6e",
"#f1c40f",
"#e67e22",
"#e74c3c",
"#e84393",
],
degreeShift: "rand(-90, 90)",
delay: "stagger(0, 40)",
},
// 透明度
opacity: 0.6,
// 生成粒子数量
count: 10,
onStart() {
hearted.value = true;
},
});
aperture = new mojs.Transit({
parent: heart.value,
duration: 750,
type: "circle",
radius: { 0: 20 },
fill: "transparent",
stroke: "#E05B5B",
strokeWidth: { 20: 0 },
opacity: 0.6,
isRunless: true,
easing: mojs.easing.bezier(0, 1, 0.5, 1),
});
});
function thumbsUp() {
new mojs.Timeline().add(burst, aperture).play();
}
return {
heart,
heart_icon,
hearted,
heartBounce,
heartStyle,
burst,
aperture,
thumbsUp,
};
},
};
</script>
<style>
.thums-up {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
height: 24px;
}
.thums-up .heart {
display: inline-flex;
position: relative;
height: 20px;
}
.thums-up .heart svg {
stroke: #9a9daa;
stroke-width: 60px;
transition: fill 0.3s, stroke 0.3s;
fill: transparent;
}
.thums-up:hover .heart svg {
stroke: #e05b5b;
}
.thums-up-text {
margin-left: 1px;
font-size: 13px;
user-select: none;
}
</style>
阶段演示效果
六、制作心跳效果
1.制作跳动函数
bounce = new mojs.Tween({
duration: 1200,
onUpdate:(progress) => {
if(progress > 0.3) {
// elastic 弹性的
heartBounce.value = mojs.easing.elastic.out(1.43 * progress - 0.43);
}else {
heartBounce.value = 0
}
}
})
2.添加进thumbsUp
函数中
function thumbsUp() {
new mojs.Timeline().add(burst, aperture, bounce).play();
}
<template>
<h3>点赞页面</h3>
<div class="thums-up" @click="thumbsUp">
<div class="heart" ref="heart">
<!-- <svg
ref="heart_icon"
:style="heartStyle"
t="1644501913302"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1268"
width="25"
height="20"
>
<path
d="M171.712 571.648l0.352 0.32 287.904 252.8a64 64 0 0 0 82.912 1.344l296.832-244.544a215.584 215.584 0 1 0-301.824-300.576L512 316.672l-25.888-35.616a215.584 215.584 0 1 0-314.4 290.624zM32 407.584a279.584 279.584 0 0 1 480-194.944 279.584 279.584 0 0 1 480 194.944 278.144 278.144 0 0 1-113.024 224.512l-295.36 243.392a128 128 0 0 1-165.888-2.592L129.984 620.16A278.976 278.976 0 0 1 32 407.584z"
p-id="1269"
></path>
</svg> -->
<svg
ref="heart_icon"
:style="heartStyle"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
>
<path
d="M533.504 268.288q33.792-41.984 71.68-75.776 32.768-27.648 74.24-50.176t86.528-19.456q63.488 5.12 105.984 30.208t67.584 63.488 34.304 87.04 6.144 99.84-17.92 97.792-36.864 87.04-48.64 74.752-53.248 61.952q-40.96 41.984-85.504 78.336t-84.992 62.464-73.728 41.472-51.712 15.36q-20.48 1.024-52.224-14.336t-69.632-41.472-79.872-61.952-82.944-75.776q-26.624-25.6-57.344-59.392t-57.856-74.24-46.592-87.552-21.504-100.352 11.264-99.84 39.936-83.456 65.536-61.952 88.064-35.328q24.576-5.12 49.152-1.536t48.128 12.288 45.056 22.016 40.96 27.648q45.056 33.792 86.016 80.896z"
p-id="2432"
></path>
</svg>
</div>
<div class="thums-up-text"><span>点赞</span></div>
</div>
</template>
<script>
import mojs from "@mojs/core";
import { ref, onMounted, computed } from "vue";
export default {
setup() {
const heart = ref(null);
const heart_icon = ref(null);
// 是否已点赞
const hearted = ref(false);
const heartBounce = ref(1);
const heartStyle = computed(() => {
return {
fill: `${hearted.value ? "#E05B5B" : ""}`,
stroke: `${hearted.value ? "E05B5B" : ""}`,
transform: `scale3d(${heartBounce.value},${heartBounce.value},1)`,
};
});
let burst, aperture, bounce;
/**
* burst 扩散
* aperture 红色光圈(红晕)
*/
onMounted(() => {
burst = new mojs.Burst({
// 爆炸范围
radius: { 0: 50 },
// 动画挂载父元素,默认改在到body上
parent: heart.value,
// 动画延时函数
easing: mojs.easing.bezier(0.1, 1, 0.3, 1),
// 动画延时时间
duration: 1500,
// 动画等待时间
delay: 300,
// 扩散的粒子配置
children: {
duration: 750,
// 随机数范围爆炸
radius: { 0: "rand(5,25)" },
shape: ["circle", "rect", "polygon"],
// 粒子可选色
fill: [
"#1abc9c",
"#2ecc71",
"#00cec9",
"#3498db",
"#9b59b6",
"#fdcb6e",
"#f1c40f",
"#e67e22",
"#e74c3c",
"#e84393",
],
degreeShift: "rand(-90, 90)",
delay: "stagger(0, 40)",
},
// 透明度
opacity: 0.6,
// 生成粒子数量
count: 10,
onStart() {
hearted.value = true;
},
});
aperture = new mojs.Transit({
parent: heart.value,
duration: 750,
type: "circle",
radius: { 0: 20 },
fill: "transparent",
stroke: "#E05B5B",
strokeWidth: { 20: 0 },
opacity: 0.6,
isRunless: true,
easing: mojs.easing.bezier(0, 1, 0.5, 1),
});
bounce = new mojs.Tween({
duration: 1200,
onUpdate:(progress) => {
if(progress > 0.3) {
// elastic 弹性的
heartBounce.value = mojs.easing.elastic.out(1.43 * progress - 0.43);
}else {
heartBounce.value = 0
}
}
})
});
function thumbsUp() {
new mojs.Timeline().add(burst, aperture, bounce).play();
}
return {
heart,
heart_icon,
hearted,
heartBounce,
heartStyle,
burst,
aperture,
bounce,
thumbsUp,
};
},
};
</script>
<style>
.thums-up {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
height: 24px;
}
.thums-up .heart {
display: inline-flex;
position: relative;
height: 20px;
}
.thums-up .heart svg {
stroke: #9a9daa;
stroke-width: 60px;
transition: fill 0.3s, stroke 0.3s;
fill: transparent;
}
.thums-up:hover .heart svg {
stroke: #e05b5b;
}
.thums-up-text {
margin-left: 1px;
font-size: 13px;
user-select: none;
}
</style>
阶段演示效果
七、制作点赞状态锁
增加一层判断,当处在已点赞
状态时,取消状态
function thumbsUp() {
if (!hearted.value) {
new mojs.Timeline().add(burst, aperture, bounce).play();
} else {
hearted.value = false
}
}
阶段演示效果
完整代码
<template>
<h3>点赞页面</h3>
<div class="thums-up" @click="thumbsUp">
<div class="heart" ref="heart">
<!-- <svg
ref="heart_icon"
:style="heartStyle"
t="1644501913302"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="1268"
width="25"
height="20"
>
<path
d="M171.712 571.648l0.352 0.32 287.904 252.8a64 64 0 0 0 82.912 1.344l296.832-244.544a215.584 215.584 0 1 0-301.824-300.576L512 316.672l-25.888-35.616a215.584 215.584 0 1 0-314.4 290.624zM32 407.584a279.584 279.584 0 0 1 480-194.944 279.584 279.584 0 0 1 480 194.944 278.144 278.144 0 0 1-113.024 224.512l-295.36 243.392a128 128 0 0 1-165.888-2.592L129.984 620.16A278.976 278.976 0 0 1 32 407.584z"
p-id="1269"
></path>
</svg> -->
<svg
:style="heartStyle"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
>
<path
d="M533.504 268.288q33.792-41.984 71.68-75.776 32.768-27.648 74.24-50.176t86.528-19.456q63.488 5.12 105.984 30.208t67.584 63.488 34.304 87.04 6.144 99.84-17.92 97.792-36.864 87.04-48.64 74.752-53.248 61.952q-40.96 41.984-85.504 78.336t-84.992 62.464-73.728 41.472-51.712 15.36q-20.48 1.024-52.224-14.336t-69.632-41.472-79.872-61.952-82.944-75.776q-26.624-25.6-57.344-59.392t-57.856-74.24-46.592-87.552-21.504-100.352 11.264-99.84 39.936-83.456 65.536-61.952 88.064-35.328q24.576-5.12 49.152-1.536t48.128 12.288 45.056 22.016 40.96 27.648q45.056 33.792 86.016 80.896z"
p-id="2432"
></path>
</svg>
</div>
<div class="thums-up-text"><span>点赞</span></div>
</div>
</template>
<script>
import mojs from "@mojs/core";
import { ref, onMounted, computed } from "vue";
export default {
setup() {
const heart = ref(null);
// 是否已点赞
const hearted = ref(false);
const heartBounce = ref(1);
const heartStyle = computed(() => {
return {
fill: `${hearted.value ? '#E05B5B' : ''}`,
stroke: `${hearted.value ? '#E05B5B' : ''}`,
transform: `scale3d(${heartBounce.value},${heartBounce.value},1)`,
};
});
let burst, aperture, bounce;
/**
* burst 扩散
* aperture 红色光圈(红晕)
* bounce 心跳
*/
onMounted(() => {
burst = new mojs.Burst({
// 爆炸范围
radius: { 0: 50 },
// 动画挂载父元素,默认改在到body上
parent: heart.value,
// 动画延时函数
easing: mojs.easing.bezier(0.1, 1, 0.3, 1),
// 动画延时时间
duration: 1500,
// 动画等待时间
delay: 300,
// 扩散的粒子配置
children: {
duration: 750,
// 随机数范围爆炸
radius: { 0: "rand(5,25)" },
shape: ["circle", "rect", "polygon"],
// 粒子可选色
fill: [
"#1abc9c",
"#2ecc71",
"#00cec9",
"#3498db",
"#9b59b6",
"#fdcb6e",
"#f1c40f",
"#e67e22",
"#e74c3c",
"#e84393",
],
degreeShift: "rand(-90, 90)",
delay: "stagger(0, 40)",
},
// 透明度
opacity: 0.6,
// 生成粒子数量
count: 10,
onStart() {
hearted.value = true;
},
});
aperture = new mojs.Transit({
parent: heart.value,
duration: 750,
type: "circle",
radius: { 0: 20 },
fill: "transparent",
stroke: "#E05B5B",
strokeWidth: { 20: 0 },
opacity: 0.6,
isRunless: true,
easing: mojs.easing.bezier(0, 1, 0.5, 1),
});
bounce = new mojs.Tween({
duration: 1200,
onUpdate: (progress) => {
if (progress > 0.3) {
// elastic 弹性的
heartBounce.value = mojs.easing.elastic.out(1.43 * progress - 0.43);
} else {
heartBounce.value = 0;
}
},
});
});
function thumbsUp() {
if (!hearted.value) {
new mojs.Timeline().add(burst, aperture, bounce).play();
} else {
hearted.value = false;
}
}
return {
heart,
hearted,
heartBounce,
heartStyle,
burst,
aperture,
bounce,
thumbsUp,
};
},
};
</script>
<style>
.thums-up {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
height: 24px;
}
.thums-up .heart {
display: inline-flex;
position: relative;
height: 20px;
}
.thums-up .heart svg {
stroke: #9a9daa;
stroke-width: 60px;
transition: fill 0.3s, stroke 0.3s;
fill: transparent;
}
.thums-up:hover .heart svg {
stroke: #e05b5b;
}
.thums-up-text {
margin-left: 1px;
font-size: 13px;
user-select: none;
}
</style>
最终效果
思考与总结
终于敲完了,内心也十分喜悦,终于独立完成了一个小小的项目。这个项目中用到了mo.js
和vue3
的一些钩子函数(例如,onMounted
,onComputed
等等),特别是ref
响应式数据,目前感觉这个点挺神奇(reactive
)
-
这个项目的所有属性和方法都是写在
setup
(即vue2中的created
和beforeCreated
)中的,按道理来说是不需要的,这个小项目也算是带我领略了一番vue3
的风采吧。 -
知道了css样式编写大致格式(最好统一,见名知意)
-
还有就是第一次尝试跟着博客做一个开源的项目,尽管很小,很简单,但是也给了我一些开源项目的方法
-
1、将代码复制到本地跑起来
-
2、另起炉灶,跟着博客大致搭建起来(在抄写代码的时候,改成自己的代码风格,比如在这个项目中,我用到了
css代码风格
) -
3、遇见效果不一致的先自己猜测可能出现问题的地方,对比差别,逐一排查(一个一个替换进去,再思考为什么)
其实,这个项目中有一些css样式,我就没有抄写
因为我发现效果是一样的,所以就没有添加,比如说
i
,margin-right
等
-
参考博客:
更多推荐
所有评论(0)