欢迎加入我们的前端技术学习交流群,关注“前端组件开发”公众号,私信申请入群哦!
摘要:
随着春节的临近,各种线上活动逐渐升温。其中,红包活动成为了许多用户关注的焦点。为了满足这一需求,我们开发了一款实用的春节过年活动红包弹框插件。该插件支持生成随机金额,并提供了丰富的自定义选项。本文将对这款插件进行详细介绍,并分享其使用方法和实现原理。
一、引言
春节,作为中国最重要的传统节日之一,不仅象征着团圆和喜庆,也孕育了丰富的文化内涵。近年来,随着互联网的快速发展,线上春节活动逐渐成为一种新趋势。其中,红包活动因其互动性和趣味性受到了广大用户的喜爱。
为了满足这一市场需求,许多前端开发者开始着手设计红包弹框插件。这些插件不仅能够提升用户体验,还能为商家带来更多的流量和转化。本文将介绍一款实用的春节红包弹框插件,希望能为前端开发者提供一些参考和启示。
二、插件介绍
我们的春节红包弹框插件采用了简洁明了的设计风格,支持生成随机金额,并支持自定义红包参数。该插件主要由以下几个部分组成:
-
红包弹框组件:用于显示红包金额和确认收款按钮。支持自定义样式和位置。
-
随机金额生成器:用于生成指定范围内的随机金额。支持自定义最小值和最大值,以及保留的小数位数。
-
事件回调:提供了打开红包和确认收款两个事件回调,方便开发者进行后续处理。
使用我们的春节红包弹框插件非常简单,只需按照以下步骤进行操作:
-
在HTML文件中引入插件的JS和CSS文件。
-
在需要显示红包弹框的地方,使用
<cc-red-bag>
标签创建一个红包弹框组件。 -
通过
:money
属性设置红包金额,通过:options
属性设置红包参数。 -
通过
@onOpen
和@onConfirm
事件回调处理打开红包和确认收款事件。
下面是一个简单的示例代码:
<template><view class="content">
<!-- money:金额 options:红包参数设置 @onOpen:打开红包事件 @onConfirm:确认收款事件 -->
<cc-red-bag :money="moneyStr" :options="redBagConfig" @onOpen="onOpen" @onConfirm="onConfirm"></cc-red-bag>
</view>
</template>
<script>
export default {
data() {
return {
moneyStr: '',
redBagConfig: {
btnText: "确认收款",
}
}
},
onLoad() {
},
methods: {
// 生成0-100随机金额 并保留两位小数
createRandom() {
// 生成0-100随机小数
var min = 0;
var max = 100;
return (min + Math.random() * (max - min)).toFixed(2) + '';
},
// 打开红包
onOpen() {
// 生成随机金额
this.moneyStr = this.createRandom();
},
// 点击确认收款按钮事件
onConfirm(e) {
console.log("点击确认收款按钮事件");
},
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
</style>
组件源码:
<!-- 活动红包 -->
<template>
<view class="red-bag">
<!-- 左侧红包 -->
<image class="bag-btn" :animation="bagAnimation" src="../../image/bag.png" mode="scaleToFill"
@click="rbagmodelshow = true"></image>
<!-- 红包封面 -->
<view v-if="rbagmodelshow" class="rbag-model" @touchmove.prevent.stop>
<view class="rbag-con">
<view class="rbag-box">
<view class="rbag_top">
<view class="rbag_top_info">
<image v-if="config.userImg" class="rbag_logo" :src="config.userImg" mode="scaleToFill">
</image>
<image v-else class="rbag_logo" src="../../image/logo.jpg" mode="scaleToFill"></image>
<view class="app_name">{{ config.userName }}</view>
<view class="rbag_tips">{{ config.coverTitle }}</view>
</view>
</view>
<view class="open_rbag_btn" :animation="openbrnanimation" @click="openBtn()">開</view>
</view>
<view class="hide_btn" @click.stop="onClose()">
<icon type="cancel" color="#fbd977" size="32" />
</view>
</view>
</view>
<!-- 打开红包 -->
<view v-if="openrbagmodelshow" class="open_rbag_model" @touchmove.prevent.stop>
<image class="rbag_conbg" src="../../image/open_bag_bgImg.png"></image>
<view class="rbag_conbg open_rbag_con">
<view class="open_title">— {{ config.openTitle }} —</view>
<view class="rbag_detail">
<view class="open_money">
<!-- 数字滚动 -->
<view class="digital-scroll" :style="`font-size: 34px;color:#c95948;justify-content: center`">
<view v-for="(item, index) in digitalData" :key="index"
:class="{ 'digital': true, 'digital-str': isNaN(item.num) }">
<!-- 符号显示 -->
<view v-if="isNaN(item.num)">{{ item.num }}</view>
<!-- 滚动的列表 -->
<view v-else class="scroll-num">
<view class="tra-num" :style="item.style">{{item.num}}</view>
</view>
</view>
</view>
<view class="danwei">元</view>
</view>
<view class="open_tips">{{ config.openTips }}</view>
</view>
<view class="lookbag_box">
<view class="lookbag_btn">
<view class="text" @click.stop="onConfirm()">{{ config.btnText }}</view>
</view>
</view>
<view class="hide_btn" @click.stop="onClose()">
<icon type="cancel" color="#fbd977" size="28" />
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
// 金额
money: {
type: [Number, String],
default: '8.88',
required: true
},
// 配置
options: {
type: Object,
default: () => {}
}
},
data() {
return {
defConfig: {
userImg: '',
userName: '前端组件开发',
coverTitle: '恭喜发财',
openTitle: '恭喜您获得',
openTips: '已存入钱包,可直接提现',
btnText: '查看我的钱包'
}, // 默认配置
bagAnimation: {}, // 固定小红包动画
rbagmodelshow: false, // 红包封面
openrbagmodelshow: false, // 拆封红包
openbrnanimation: {}, // 拆封动画
digitalData: [], // 滚动数字数据
}
},
// onShow() {
// this.setImageAnimation()
// },
computed: {
// 处理配置项
config() {
const result = Object.assign(this.defConfig, this.options)
return result
}
},
onLoad() {
setTimeout(() => {
this.setImageAnimation()
}, 2000);
},
methods: {
// 侧边红包 => 动画
setImageAnimation() {
let next = true
const animation = uni.createAnimation({
duration: 1000,
timingFunction: 'ease'
})
this.bagAnimation = animation
setInterval(() => {
const rotate = next ? 36 : 6
animation.rotate(rotate).step()
next = !next
this.bagAnimation = animation.export()
}, 1000)
},
// 红包封面 => 開红包按钮
openBtn() {
var animation = uni.createAnimation({
duration: 1000,
timingFunction: 'ease'
})
this.openbrnanimation = animation
animation.rotateY(360).step()
this.openbrnanimation = animation.export()
setTimeout(() => {
this.rbagmodelshow = false
this.openrbagmodelshow = true
this.openbrnanimation = {}
this.setMoney()
this.$emit('onCover') // 打开封面后回调
}, 1000)
this.$emit('onOpen') // 确认后回调
},
// 确认红包
onConfirm() {
this.openrbagmodelshow = false
this.$emit('onConfirm') // 确认后回调
},
// 隐藏红包
onClose() {
this.rbagmodelshow = false
this.openrbagmodelshow = false
this.$emit('onClose') // 关闭后回调
},
// 设置金额
setMoney() {
const digitalArr = String(this.money).split('')
const dataList = []
digitalArr.forEach((num) => {
const obj = {
num: isNaN(num) ? num : Number(num),
style: ''
}
dataList.push(obj)
})
this.digitalData = dataList
this.setScrollNum()
},
// 滚动数字动画(重点)
setScrollNum() {
const defData = JSON.parse(JSON.stringify(this.digitalData))
defData.forEach((item, index) => {
// 设置移动距离
// item.style = `transform: translateY(-${item.num}em);`
})
setTimeout(() => {
this.digitalData = defData
}, 20)
}
}
}
</script>
<style lang="scss" scoped>
@keyframes bagAni {
0% {
transform: rotate(6deg);
}
100% {
transform: rotate(36deg);
}
}
.red-bag {
.bag-btn {
position: fixed;
left: -46rpx;
top: 360rpx;
width: 150rpx;
height: 100rpx;
z-index: 999;
animation-name: bagAni;
animation-duration: 1.1s;
animation-iteration-count: infinite;
animation-direction: alternate;
}
// 红包封面
.rbag-model {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
.rbag-con {
position: relative;
width: 80%;
height: 840rpx;
background-color: #da4d44;
border-radius: 14rpx;
box-shadow: 0rpx 0rpx 10rpx rgba(0, 0, 0, 0.2);
.rbag-box {
position: relative;
width: 100%;
height: 100%;
border-radius: 14rpx;
overflow: hidden;
}
.rbag_top {
position: absolute;
left: -20%;
top: 0;
width: 140%;
height: 540rpx;
background-color: #e0534a;
border-radius: 0 0 50% 50%;
box-shadow: 0 0 14rpx rgba(0, 0, 0, 0.4);
z-index: 1001;
.rbag_top_info {
margin-top: 60rpx;
.rbag_logo {
width: 160rpx;
height: 160rpx;
border-radius: 50%;
display: block;
margin: 0 auto;
overflow: hidden;
}
.app_name {
font-size: 38rpx;
color: #f6ac96;
text-align: center;
margin-top: 18rpx;
letter-spacing: 1rpx;
}
.rbag_tips {
font-size: 50rpx;
color: #edddd3;
text-align: center;
margin-top: 34rpx;
letter-spacing: 1rpx;
}
}
}
.open_rbag_btn {
position: absolute;
top: 450rpx;
left: 0;
right: 0;
width: 180rpx;
height: 180rpx;
line-height: 180rpx;
border-radius: 50%;
margin: 0 auto;
text-align: center;
background-color: #ffd287;
font-size: 55rpx;
color: #fef5e8;
box-shadow: 2rpx 2rpx 6rpx rgba(0, 0, 0, 0.2);
z-index: 1002;
}
.hide_btn {
position: absolute;
bottom: -110rpx;
left: 0;
right: 0;
width: 90rpx;
height: 90rpx;
margin: 0 auto;
}
}
}
// 打开红包
.open_rbag_model {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: rgba(0, 0, 0, 0.3);
z-index: 1000;
.rbag_conbg {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 80%;
height: 840rpx;
margin: auto;
z-index: 1001;
}
.open_rbag_con {
z-index: 1002;
.open_title {
height: 120rpx;
line-height: 120rpx;
text-align: center;
font-size: 38rpx;
letter-spacing: 2rpx;
color: #e46965;
}
.rbag_detail {
margin-top: 90rpx;
.open_money {
text-align: center;
font-size: 80rpx;
color: #c95948;
font-weight: bold;
display: flex;
justify-content: center;
.danwei {
font-size: 30rpx;
margin-left: 16rpx;
margin-top: 24rpx;
}
}
.open_tips {
text-align: center;
font-size: 30rpx;
color: #d26762;
margin-top: 30rpx;
}
}
.lookbag_box {
margin-top: 200rpx;
display: flex;
justify-content: center;
.lookbag_btn {
width: 70%;
height: 90rpx;
line-height: 90rpx;
text-align: center;
font-size: 32rpx;
color: #c95948;
letter-spacing: 2rpx;
background-color: #ffd356;
border-radius: 50rpx;
box-shadow: 0rpx 0rpx 4rpx rgba(0, 0, 0, 0.2);
}
}
.hide_btn {
position: absolute;
bottom: -110rpx;
left: 0;
right: 0;
width: 80rpx;
height: 80rpx;
line-height: 80rpx;
text-align: center;
margin: 0 auto;
}
}
}
}
.digital-scroll {
font-size: 28rpx;
font-weight: bold;
display: flex;
align-items: center;
.digital {
display: flex;
justify-content: center;
width: 0.7em; // 0.7em 是为了让文本间隔没那么宽
height: 1em;
line-height: 1em;
overflow: hidden;
.scroll-num {
// 文本竖直排列
writing-mode: vertical-rl;
text-orientation: upright;
.tra-num {
transition: all 1s;
}
}
}
.digital-str {
width: auto;
line-height: 1em;
}
}
</style>
四、实现原理
我们的春节红包弹框插件采用了Vue.js框架进行开发。通过Vue.js的组件化思想,我们将红包弹框封装成一个独立的组件,方便在其他页面进行复用。
在插件的实现过程中,我们主要使用了JavaScript的Math.random()
函数生成随机数,并通过toFixed()
方法保留指定的小数位数。同时,我们还提供了自定义红包参数的功能,以满足不同场景的需求。
在事件处理方面,我们采用了Vue.js的事件监听机制。通过在组件上添加@onOpen
和@onConfirm
事件回调,我们可以在打开红包和点击确认收款按钮时执行相应的逻辑。
五、总结
本文介绍了一款实用的春节红包弹框插件,并详细阐述了其使用方法和实现原理。该插件具有简单易用、功能丰富、高度可定制等特点,能够满足不同场景下的需求。希望本文能为前端开发者提供一些参考和启示,共同推动线上春节活动的发展和创新。
欢迎关注我的前端技术微信公众号: 前端组件开发
欢迎加入“前端组件开发学习”交流群,一起学习成长!可关注 “前端组件开发” 公众号后,私信后申请入群。