这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言~博主看到后会去代替大家踩坑的~
主页: oliver尹的主页
格言: 跌倒了爬起来就好~
《uni-app》uni-app实现疯狂点赞效果(二) 封装与优化
一. 前言
在上一篇中,我们简单的实现了一个疯狂点赞,或者说是漂浮爱心的效果,但代码也好效果也好,略微有一些些粗糙,有很多地方是可以改进的,这一篇我们主要的目的是为了改进上一篇中的最终成果,使之更符合真实使用~当然,要说这个优化版就是真的项目可使用版么,那也不见得,具体还得根据需求看,毕竟功能做的再好,不符合需求那也是白搭~
本文演示demo使用的UI组件库为:uView,如对如何在uni-app中安装uView存在疑惑请浏览博文:《《uni-app》npm详解及在uni-app中对npm的支持》
耐心看完,或许所有收获~
二. 阅读对象与难度
本文难度属于:初中级,适合有对uni-app有一定了解的小伙伴,通过本文你可以大致了解以下几个知识点:
- 组件的封装及使用;
- 利用Promise的特性实现对延迟时间的操作;
- CSS3的animation动画;
具体内容可以参考以下的思维导图:
三. 项目地址与最终效果
文本代码 已上传CSDN上的gitCode,有兴趣的小伙伴可以直接clone,项目地址:https://gitcode.net/zy21131437/uni-app-study
本文最终实现的效果图如下:
四. 具体实现
开始之前先想一想,如果我们要使这个功能更加贴切于实际项目,那么这个效果该怎么优化~
首先,有一点可以确认,这个点赞效果肯定是会被复用的,既然会被复用,那么就必须 组件化,这样的好处是对于组件的BUG我们只需要修改一次,减少代码量等等~
第二个改进,上一篇中虽然我们增加了一定的动画量,但很明显还是达不到那些app的效果,因此我们还需要 增加更多的动画种类来使得漂浮爱心的动画更具有表现力;
4.1 组件化修改
组件化修改其实没有那么复杂,说到底,就是把跟点赞漂浮爱心的功能相关的代码完全独立出去,使用的时候我们只需要在对应的位置引入即可,大致示例图如下:
用代码表示的话,大致就是原来是这种用法:
<!-- 原来的用法 -->
<template>
<view class="study-container">
<!-- 输入 -->
<view class="study-bottom">
<view class="input-container"><u--input class="input-style" placeholder="请输入内容" border="surround"></u--input></view>
<view class="likes-container" ref="likeContainer">
<u-icon v-for="(item, index) in likesData" :class="['icon-default', `${item.animate}`]" :name="item.name" :color="item.color" :key="item.id"></u-icon>
<u-icon class="icon-style" color="#fc5531" name="heart-fill" @click="createLikes"></u-icon>
</view>
</view>
</view>
</template>
<!-- 还有逻辑代码 -->
<!-- ...... -->
组件化之后,那么使用就改成了组件的方式的引入,而非代码
<!-- 组件化后的用法 -->
<template>
<view class="study-container">
<!-- 输入 -->
<view class="study-bottom">
<view class="input-container"><u--input class="input-style" placeholder="请输入内容" border="surround"></u--input></view>
<view class="likes-container" >
<!-- 引入点赞效果的组件 -->
<t-likes></t-likes>
</view>
</view>
</view>
</template>
<script>
import TLikes from './likesCom.vue';
export default {
components: {
TLikes
}
};
</script>
至于逻辑代码完全被内置在了 t-likes
这个组件里,与外界不再直接互通~因此,首先我们 新建了一个likesCom.vue
的文件,将之前关于点赞功能的代码全部移入该文件中,功能其实不需要怎么改动,全部移植即可
<template>
<view class="likes-container">
<u-icon v-for="(item, index) in likesData" :class="['icon-default', `${item.animate}`]" :name="item.name" :color="item.color" :key="item.id"></u-icon>
<u-icon class="icon-style" color="#fc5531" name="heart-fill" @click="createLikes"></u-icon>
</view>
</template>
<script>
import _ from 'lodash';
export default {
data() {
return {
likesData: []
};
},
methods: {
randomNum(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
},
getLikeParams() {
// ...原来的获取参数事件
},
createLikes: _.throttle(function() {
// ...原来的点击事件
}, 10)
}
};
</script>
<style lang="scss" scoped>
// 原来的样式代码
</style>
这样简单的代码剥离算是完成了,按照预期的期望进行测试,确认效果可以正常触发
接着,可以在这个上面 再加一些小功能,比如统计一共点击了多少下,那么只需要每一次点击记录一下,再取得总数传递给父组件即可:
export default {
data() {
return {
likesData: [],
total: 0
};
},
methods: {
randomNum(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
},
getLikeParams() {},
createLikes: _.throttle(function() {
new Promise(reslove => {
const params = this.getLikeParams();
this.likesData.push(params);
this.total += 1;
// 传递给父组件
this.$emit('getTotal', this.total);
setTimeout(() => {
reslove(params);
}, 1200);
}).then(res => {
this.likesData.shift();
});
}, 10)
}
};
</script>
在父组件中做一个接收,并打印接收值:
<view class="likes-container" >
<t-likes @getTotal="getTotal"></t-likes>
</view>
<script>
import TLikes from './likesCom.vue';
export default {
components: {
TLikes
},
methods: {
getTotal(total) {
console.log(total);
}
}
};
</script>
其表现的效果图如下:
4.2 实现更多动画
在上一篇中可以知道,上浮动画的核心利用的是CSS3的animation实现 的,大致的动画aanimation值如下:
.icon-animate-1 {
animation: animate-1 1.5s ease-in-out;
}
@keyframes animate-1 {
0% {
top: 20px;
opacity: 1;
}
100% {
top: -140px;
opacity: 0;
}
}
原理我们依旧采用CSS3的animation实现,但这个动画略微有点简单需要稍加改造,改造点主要有三个:
- 增加动画的种类,有原来的 5种 增加到 9种;
- 增加动画的复杂度,原来的 5种 动画实际上 有两种类型,一种是直线往上漂浮,一种是向左/向右+向上漂浮,改造过后 再加入一种贝塞尔曲线速率的动画种类;
- 增加爱心颜色,原来的 3种 颜色,增加到 7种 颜色,并且色调也稍微改动一下,显得爱心颜色更加柔和;
对于CSS3的animation这里就不全部粘贴了,这里分别对3类动画各选一种分享:
第一种:直线运行
这种最为简单,就是一个简单的上浮动画,CSS代码如下:
.icon-animate-2 {
animation: animate-2 2.4s ease-in-out;
animation-fill-mode: forwards;
}
@keyframes animate-2 {
0% {
top: 20px;
opacity: 1;
}
100% {
top: -180px;
opacity: 0;
}
}
执行了一个名为 animate-2 的动画,这个 动画持续2.4秒,并且速度是 先加速后减速的效果,动画则是开始距离顶部20像素,透明度为1,动画结束时距离顶部为-180像素,透明度为0,也就是此时已经处于透明状态;
其表现形态的 效果图 如下:
第二种:直线运行+向左/向右运动
这种动画和第一种 其实是相同原理,区别在于第一种只有改变了 top属性
和 opacity属性
,第二种会在第一种的基础上再增加一个 margin-left
或者 margin-right
,示例代码如下:
.icon-animate-4 {
animation: animate-4 2.4s ease-in-out;
animation-fill-mode: forwards;
}
@keyframes animate-4 {
0% {
top: 20px;
margin-left: 0;
opacity: 1;
}
100% {
top: -160px;
margin-left: -68px;
opacity: 0;
}
}
执行了一个名为 animate-4 的动画,这个 动画持续2.4秒,并且速度是 先加速后减速的效果,动画则是开始距离顶部20像素,透明度为1并且距离左侧的距离为0,动画结束时距离顶部为-160像素,透明度为0,距离左侧的距离为-68像素;
其表现形态的 效果图 如下:
第三种:贝塞尔曲线
这种略微有点复杂,主要复杂在原理,其实放到CSS3种实现就没有那么复杂,简单的说就是 运动的速度遵循贝塞尔曲线的速率公式,CSS3中有现成的公式计算器,如下:
cubic-bezier(0.66, 0.1, 1, 0.41)
类似于这种,这个解释还是有点复杂的,有兴趣的小伙伴可以自行查证,大致如下:
cubic-bezier(x1,y1,x2,y2)
cubic-bezier它接收4个参数,分别是两组平面坐标,起始点(x1,y1),终止点(x2,y2),在这两个点内的速率会按照cubic-bezier这个公式进行实时计算,有时候快,有时候慢~其实有一种animation种类也是遵循这个公式的,就是 ease-in-out
,它对应的贝塞尔曲线是
cubic-bezier(0.42,0,0.58,1)
本文中的动画代码如下:
.icon-animate-1 {
animation: animate-1-left 2.4s ease-in-out, animate-1-top 2.4s cubic-bezier(0.66, 0.1, 1, 0.41);
animation-fill-mode: forwards;
}
@keyframes animate-1-top {
0% {
top: 20px;
opacity: 1;
}
100% {
top: -200px;
opacity: 0;
}
}
@keyframes animate-1-left {
0% {
margin-left: 0;
}
100% {
margin-left: -100px;
}
}
animation执行了两组动画,第一组是向上的一个动画,第二组是一个自定义贝塞尔曲线速率的向左位移变化,动画持续时间都是2.4秒,其表现形态的效果图如下:
这三种动画各多写几种,最后得到 完整动画效果如下:
五. 小结
本文主要分享了一下 通过CSS3的animation属性,实现了一个疯狂点赞的效果,相比上一篇的效果这一篇完善了很多,并且我们将实现的代码独立成单独的一个 .vue文件,形成了一个组件这样就解决了复用代码的问题,当然还是那句话,CSS3的实现并非最优解,还有很多其他方式也可以实现,至少canvas实现的效果肯定比CSS3来的好~