这是一个没有套路的前端博主,热衷各种前端向的骚操作,经常想到哪就写到哪,如果有感兴趣的技术和前端效果可以留言~博主看到后会去代替大家踩坑的~
主页: oliver尹的主页 格言: 跌倒了爬起来就好~
《uni-app》uni-app实现疯狂点赞效果(一)实现
- 一. 前言
- 二. 阅读对象与难度
- 三. 项目地址与最终效果
- 四. 实现
- 4.1 简单布个局
- 4.2 实现上浮动画
- 4.3 加入点击事件
- 4.4 稍微优化一下
- 五. 小结
一. 前言
现在很多app尤其是直播类、视频类甚至是社交类的,基本都是带有 “点赞功能”,其中有一部分app的点赞功能甚至可以被称为是 “疯狂点赞”,大量的爱心漂浮功能感觉非常有意思,忍不住尝试一下其实现~当然本文的实现仅仅是demo级别的,下一篇我们再进一步做优化,本文先用CSS实现效果再说~
本文演示demo使用的UI组件库为:uView,它可以协助我们快速布局以及使用其一些组件,如对如何在uni-app中安装uView存在疑惑请浏览博文:《《uni-app》npm详解及在uni-app中对npm的支持》
耐心看完,或许所有收获~
二. 阅读对象与难度
本文难度属于:初级,适合有对uni-app有一定了解的小伙伴,通过本文你可以大致了解以下几个知识点:
- CSS中的动画animation属性及其用法;
- 利用Promise的特性实现对延迟时间的操作;
具体内容可以参考以下的思维导图:
三. 项目地址与最终效果
文本代码已上传上的gitCode,有兴趣的小伙伴可以直接clone,项目地址:https://gitcode.net/zy21131437/uni-app-study 本文最终实现的效果图如下:
四. 实现
4.1 简单布个局
由于我们只是为了探索实现点赞效果,因此template部分,也就是Html部分就简单布局一下了,大致布局的示意图如下:
具体代码如下:
<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 class="icon-style" color="#fc5531" name="heart-fill"></u-icon>
</view>
</view>
</view>
</template>
简单的盒模型,通过 view标签 的嵌套实现了简单布局,最终实现的布局效果大致如下:
其中这一段中最主要的是这一段代码:
<u-icon class="icon-style" color="#fc5531" name="heart-fill"></u-icon>
我们的目的是需要 实现点击后的大量带有上浮动画的爱心,那么这一段代码就是 必须包含点击事件,用于触发点击事件,绑定事件的语法遵循vue的语法
<u-icon class="icon-style" color="#fc5531" name="heart-fill" @click="createLikes"></u-icon>
<script>
export default {
methods: {
createLikes() {
console.log("触发点击")
}
}
};
</script>
4.2 实现上浮动画
上浮动画的核心利用的是CSS3的animate实现 的,先来个简单的上浮
.icon-animate-1 {
animation: animate-1 1.5s ease-in-out;
}
@keyframes animate-1 {
0% {
top: 20px;
opacity: 1;
}
100% {
top: -140px;
opacity: 0;
}
}
解释一下这段代码,有一个类名 icon-animate-1 ,这个类名中有一个 animation属性,它是隶属于CSS3中新增的一个属性,主要的作用是执行动画,这里它执行了一个名为 animate-1 的动画,动画持续时间为 1.5s,动画的运动速度为 ease-in-out(动画以低速开始和结束)
接着是 @keyframes animate-1,定义了一个动画,大致意思是开始的时候top的值为20px,当动画结束的时候top的值为-140px,当定义完,把类名加到Icon组件上,它就会实现一个动画,动画大致是这样的效果:
是不是有那么点意思了,既然单个动画实现了,那么接下来就是动态添加了,我们必须在 点击爱心的时候才触发这个动态效果,而不是一加载页面就立刻触发~
4.3 加入点击事件
接入上面的代码,我们在一开始的时候就为爱心的图标加入了 点击事件,如下:
<script>
export default {
methods: {
createLikes() {
console.log("触发点击")
}
}
};
</script>
为了配合这段代码,我们 需要加入icon组件以及循环生成icon组件的变量,加入组件后的代码如下:
<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>
<script>
import _ from 'lodash';
export default {
data() {
return {
likesData: []
};
},
methods: {
createLikes() {
console.log("触发点击")
}
}
};
</script>
通过触发点击事件,将生成的参数push进likesData,利用vue的v-for指令循环生成DOM,当DOM被渲染出来之后,立刻触发CSS样式中的 animation动画,大致流程如下:
第一步事件触发已经完成,就是绑定在DOM上的点击事件,接着是 第二步创建配置参数;
先说说配置参数的作用,主要作用其实就两个:
- ICON组件上附加的类名,这个是重要的,这个类名直接关系到这个icon组件执行的animation动画究竟是哪个;
- ICON组件的颜色,也就是漂浮爱心的颜色,因为按照那些app上的漂浮爱心显示,颜色明显是不一样的,具有一定的随机性,因此这里也要随机显示;
这两个参数都需要 随机显示,因此在写配置函数之前要有一个 生成随机数的函数:
<script>
export default {
methods: {
randomNum(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
},
getLikeParams(){}
}
};
</script>
这里简单的利用了原生的方法,实现了一个 随机数生成的函数,之后利用随机数生成函数可以获得 随机的类名 和 颜色:
<script>
export default {
methods: {
randomNum(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
},
getLikeParams(){
const classList = ['icon-animate-1'];
const colorList = ['#fc5531', '#fcd030', '#00ff7f'];
const className = classList[this.randomNum(0, classList.length)];
const colorName = colorList[this.randomNum(0, colorList.length)];
return {
animate: className,
color: colorName,
name: 'heart-fill',
id: `${new Date().getTime()}-likes`
};
}
}
};
</script>
这样,每一次点击的时候,我们都可以得到一个 相对随机的参数配置;
接着,我们需要 将参数配置push进likesData数组中,v-for执行就会立刻执行循环生成DOM渲染进页面了
<script>
export default {
methods: {
createLikes() {
const params = this.getLikeParams();
// push参数
this.likesData.push(params);
},
randomNum(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
},
getLikeParams(){
const classList = ['icon-animate-1'];
const colorList = ['#fc5531', '#fcd030', '#00ff7f'];
const className = classList[this.randomNum(0, classList.length)];
const colorName = colorList[this.randomNum(0, colorList.length)];
return {
animate: className,
color: colorName,
name: 'heart-fill',
id: `${new Date().getTime()}-likes`
};
}
}
};
</script>
试一下效果:
效果还算不错,确实有点开始与目标效果相近了~
4.4 稍微优化一下
略微想一下,立刻发现 可优化的点有三处:
- 第一处:创建的DOM没有销毁,也就是执行完动画的DOM并没有被销毁,这会导致页面上的DOM随着点击的次数变多而线性的增加,非常不好,影响性能;
- 第二处:动画太少,我们可以看到app上的点赞效果是非常丰富的,有向左,有向右,有直线,也有弧线,因此这里还得 增加动画的数量使其变得更加美观一点;
- 第三处:得加一个防抖,减少真的有人或者物理进行疯狂点击,一秒触发N次的那种;
第一点优化
第一处优化就是对于执行完的动画需要及时的销毁,怎么实现呢?其实很简单,我们是用push的方法将配置参数添加进数组的,然后v-for指令自动生成渲染了DOM,那么执行完了之后直接将这个配置删除就完了,由于配置删除,v-for指令自然而言就会将对应的DOM
new Promise(reslove => {
const params = this.getLikeParams();
this.likesData.push(params);
setTimeout(() => {
reslove(params);
}, 1200);
}).then(res => {
this.likesData.shift();
});
通过Promise确保代码是同步执行的,执行完动画后直接使用 shift() 函数删除第一个配置项即可,至于为什么要用Promise,那是因为其实有可能有一组动画类名,那么通过Promise我们可以精准的控制添加类名的时机,算是方便扩展吧;
第二处优化
动态太少,那就加动画嘛,多定义几个动画,然后在随机生成class类名的时候把类名带上:
getLikeParams() {
const classList = ['icon-animate-1', 'icon-animate-2', 'icon-animate-3', 'icon-animate-4', 'icon-animate-5'];
const colorList = ['#fc5531', '#fcd030', '#00ff7f'];
const className = classList[this.randomNum(0, classList.length)];
const colorName = colorList[this.randomNum(0, colorList.length)];
return {
animate: className,
color: colorName,
name: 'heart-fill',
id: `${new Date().getTime()}-likes`
};
},
具体类名对应的动画这里就不放了,直接去代码里看即可,增加了类名动画后,再来看一下效果
看上去还不错,但还不够多,表现力还可以更强,但这一篇这里就算了,有兴趣的小伙伴可以自己加一下~
第三处优化
第三处优化主要是没有做防抖处理,那么防抖我们可以直接借助于 lodash中的 throttle函数,用法也非常简单,只需要包裹我们的函数即可:
<script>
import _ from 'lodash';
export default {
methods: {
createLikes: _.throttle(function() {
new Promise(reslove => {
const params = this.getLikeParams();
this.likesData.push(params);
setTimeout(() => {
reslove(params);
}, 1200);
}).then(res => {
this.likesData.shift();
});
}, 50)
}
};
</script>
通过设置后,在50毫秒内只能触发一次函数,这样就防止了那种疯狂触发的情况
五. 小结
本文主要分享了一下 通过CSS3的animation属性,实现了一个疯狂点赞的效果,可能有小伙伴问这种用法会有性能上的问题么,我个人感觉吧,由于动画是CSS3实现的其实性能上没有多大影响,但要说这种做法是最合适嘛,那肯定不是,至少canvas实现的效果肯定比CSS3来的好~
下一篇,我们封装一下,毕竟真实项目中我们不可能不考虑复用以及实现的问题,然后动画也不够完美,下一步继续优化~