来接私活吧?小程序私活必备功能分享之婚恋交友(附完整源码)

484 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

一、应用介绍

这次要分享的小程序功能为好友匹配动画界面,这是一款以交友相亲为背景的恋爱主题样式组件。

css样式JS原生语法打造,支持多端的开发,小程序、H5、APP均能丝滑享受。


二、效果展示

在这里插入图片描述


三、技术与难点

3.1 基本开发环境

  • 开发框架:uniapp
  • 代码语法:vue 2htmlcss3

3.2 开发要点

  • (1)头像图片的生成
    • 先引入<image>标签,配置好相应的图片路径
	 <image class="dot" src="randomImg"  style="width: 92px;height: 92px;border-radius: 50px;"></image>`
	- 	再通过CSS样式将其变成圆形
	
   -webkit-border-radius: 50%;
   -moz-border-radius: 50%;
   border-radius: 50%;
  • (2)CSS动画的引入 对于网页元素的动画效果我们使用CSS 3 动画,不太熟悉的小伙伴可以直接查看文档进行学习:CSS动画教程

    • 先声明一个放缩动画变量
@keyframes 动画变量名(taoren) {
	0% {
		-webkit-transform:scale(0) translateX(0);
		transform:scale(0) translateX(0);
		opacity:.6
	}
	5% {
		-webkit-transform:scale(1) translateX(0) translateY(-80%);
		transform:scale(1) translateX(0) translateY(-80%);
		opacity:.8
	}
	20% {
		opacity:1
	}
	30% {
		opacity:.2
	}
	32% {
		opacity:0;
		visibility:hidden
	}
	50% {
		-webkit-transform:scale(1.9) translateX(-40px) translateY(-340%);
		transform:scale(1.9) translateX(-40px) translateY(-340%)
	}
	100% {
		-webkit-transform:translateX(-100px);
		transform:translateX(-100px)
	}
}
  • 将动画变量绑定到相应的元素样式中
.相应原始的Class名称 {
	animation:taoren
}
  • (3)JS循环逻辑的控制 在元素和动画都具备的基础之上,接下来进行更重要的操作:将元素所设置的动画按照特定的规则进行重复播放。
    • JS中要实现重复播放的逻辑,通常的做法是使用setInterval方法。
			this.interval = setInterval((function() {
				// 动画逻辑
				}
			), this.intervalTime)

四、完整源码

代码基于vue 2语法编写,拷贝出来需保存为.vue文件。该示例代码中,包括三大模块:<script>,<template>,<style>,三大模块的作用分别是:控制元素逻辑和数据绑定,编写组织页面元素的渲染,控制和渲染元素的样式

<template>
	<view class="center">
		<view class="container">
			<image class="dot" src="randomImg"  style="width: 92px;height: 92px;border-radius: 50px;"></image>
			<view class="pulse"></view>
			<view class="pulse1"></view>
			<view class="prize-flying" >
				<view v-for="(item,index) in flyLeftList" class="fly-prize fly-left" 
				:style="{ 'background': 'url('+ item.img +')', '-webkit-animation-duration': flySpeed + 's','animation-duration': flySpeed + 's' }"></view>
				<view v-for="(item,index) in flyCenterList" class="fly-prize fly-center"
				:style="{ 'background': 'url('+ item.img +')', '-webkit-animation-duration': flySpeed + 's','animation-duration': flySpeed + 's' }"></view>
				<view v-for="(item,index) in flyRightList" class="fly-prize fly-right"
				:style="{ 'background': 'url('+ item.img +')', '-webkit-animation-duration': flySpeed + 's','animation-duration': flySpeed + 's' }"></view>
			</view>
		</view>
		<view class="flex justify-center items-center match-button" @click="showMan">
			<view class="match-btn">
				心动匹配
			</view>
		</view>
    </view>
</template>

<script>
	import utils from '@/utils/utils'
	export default {
		components: {utils},
		data() {
			return {
				show:false,
				randomImg:'/static/imgs/mm1.jpg',
				flyLeftList: [],
				flyCenterList: [],
				flyRightList: [],
				userList:[{img:'/static/imgs/mm1.jpg'},{img:'/static/imgs/mm2.jpg'},{img:'/static/imgs/mm3.jpg'}],
				flySpeed: 25,
				indexRecord: 0,
				intervalTime: 2.5,
				interval: null,
			};
		},
		// 从后台进入前台显示
		onShow() {
			this.flyLeftList=[];
			this.flyCenterList=[];
			this.flyRightList=[];
			this.refreshUser();
		},
		// 从前台进入后台
		onHide() {
			this.flyLeftList=[];
			this.flyCenterList=[];
			this.flyRightList=[];
			clearInterval(this.interval);
		},
		methods:{
			showMan(){
				console.log('========')
				this.show =true
			},
			refreshUser(){
				this.flyInterval();
			},
			flyInterval() {
				if(this.interval != null){
					clearInterval(this.interval);
				}
				var t = this;
				this.pushFlyList(),
				this.interval = setInterval((function() {
					t.pushFlyList()
				}
				), 1e3 * this.intervalTime)
			},
			pushFlyList() {
				var t = 0;
				while (t < 3) {
					this.indexRecord == this.userList.length - 1 ? this.indexRecord = 0 : this.indexRecord++;
					var a = this.userList[this.indexRecord];
						switch (t) {
							case 0:
								this.flyLeftList.push(a);
								break;
							case 1:
								this.flyCenterList.push(a);
								break;
							case 2:
								this.flyRightList.push(a);
								break
						}
					t++	
				}
			},
		}
	}
</script>

<style lang="scss">
page{
	height: 100%;
	background: url('~@/static/imgs/home/bg.png');
}
.match-button{
	background-image: linear-gradient(to top, #c471f5 0%, #fa71cd 100%);
	color: #ffff;
	border-radius: 100rpx;
	padding: 20rpx;
}
.center {
	height: 100%;
	flex: auto;
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	//background-color: red;
	
}
@keyframes warn {
	0% {
		transform: scale(0.3);
		-webkit-transform: scale(0.3);
		opacity: 0.0;
	}

	25% {
		transform: scale(0.3);
		-webkit-transform: scale(0.3);
		opacity: 0.1;
	}

	50% {
		transform: scale(0.5);
		-webkit-transform: scale(0.5);
		opacity: 0.3;
	}

	75% {
		transform: scale(0.8);
		-webkit-transform: scale(0.8);
		opacity: 0.5;
	}

	100% {
		transform: scale(1);
		-webkit-transform: scale(1);
		opacity: 0.0;
	}
}

@keyframes warn1 {
	0% {
		transform: scale(0.3);
		-webkit-transform: scale(0.3);
		opacity: 0.0;
	}

	25% {
		transform: scale(0.3);
		-webkit-transform: scale(0.3);
		opacity: 0.1;
	}

	50% {
		transform: scale(0.3);
		-webkit-transform: scale(0.3);
		opacity: 0.3;
	}

	75% {
		transform: scale(0.5);
		-webkit-transform: scale(0.5);
		opacity: 0.5;
	}

	100% {
		transform: scale(0.8);
		-webkit-transform: scale(0.8);
		opacity: 0.0;
	}
}
.container {
	position: relative;
	width: 96px;
	height: 96px;
	/*border: 1px solid #000; hovertree.com */
}
/* 保持大小不变的小圆圈 何问起 */
.dot {
	position: absolute;
	width: 92px;
	height: 92px;
	//left: -2.5px;
    //top: -2.5px;
	-webkit-border-radius: 50%;
	-moz-border-radius: 50%;
	//border: 2px solid red;
	border-radius: 50%;
	z-index: 2;
	animation: msClock 1.8s linear infinite; 
}
@keyframes msClock{ 
	0%,90%,100%{ transform: rotate(0) scale(1);}
	20%,40%{ transform: rotate(-15deg) scale(1.1);}
	30%,50%{ transform: rotate(15deg) scale(1.1);}
}
/* 产生动画(向外扩散变大)的圆圈  */
.pulse {
	position: absolute;
	width: 320px;
	height: 320px;
    left: -120px;
    top: -120px;
	border: 6px solid $dating-color-primary;
	-webkit-border-radius: 50%;
	-moz-border-radius: 50%;
	border-radius: 50%;
	z-index: 1;
	opacity: 0;
	-webkit-animation: warn 2s ease-out;
	-moz-animation: warn 2s ease-out;
	animation: warn 2s ease-out;
	-webkit-animation-iteration-count: infinite;
	-moz-animation-iteration-count: infinite;
	animation-iteration-count: infinite;
	box-shadow: 1px 1px 30px $dating-color-primary;
}

.pulse1 {
	position: absolute;
	width: 320px;
	height: 320px;
    left: -120px;
    top: -120px;
	border: 6px solid $dating-color-primary;
	-webkit-border-radius: 50%;
	-moz-border-radius: 50%;
	border-radius: 50%;
	z-index: 1;
	opacity: 0;
	-webkit-animation: warn1 2s ease-out;
	-moz-animation: warn1 2s ease-out;
	animation: warn1 2s ease-out;
	-webkit-animation-iteration-count: infinite;
	-moz-animation-iteration-count: infinite;
	animation-iteration-count: infinite;
	box-shadow: 1px 1px 30px $dating-color-primary;
}
a{color:blue;text-decoration:none;}
.match-button{
	position: fixed;
	bottom: calc(var(--status-bar-height) + 120rpx);
}
.prize-flying{
	z-index:99;
	width:100px;
	position:absolute;
	bottom:50%;
	left:50%;
	-webkit-transform:translateX(-50%);
	transform:translateX(-50%)
}
.prize-flying .fly-prize {
	text-align:center;
	position:absolute;
	top:100%;
	opacity:0;
	width:39px;
	height:39px;
	background-repeat:no-repeat!important;
	background-size:100% 100%!important;
	border-radius:50%;
	background:#fff;
	padding:7px
}
.showCard {
	z-index:10;
	animation:warn
}

.prize-flying .fly-left {
	left:0;
	z-index:5;
	animation:flyleft-data-v-1a236634
}
.prize-flying .fly-center {
	left:30px;
	z-index:3;
	animation:flycenter-data-v-1a236634
}
.prize-flying .fly-right {
	right:0;
	z-index:5;
	animation:flyright-data-v-1a236634
}

@keyframes flyleft-data-v-1a236634 {
	0% {
		-webkit-transform:scale(0) translateX(0);
		transform:scale(0) translateX(0);
		opacity:.6
	}
	5% {
		-webkit-transform:scale(1) translateX(0) translateY(-80%);
		transform:scale(1) translateX(0) translateY(-80%);
		opacity:.8
	}
	20% {
		opacity:1
	}
	30% {
		opacity:.2
	}
	32% {
		opacity:0;
		visibility:hidden
	}
	50% {
		-webkit-transform:scale(1.9) translateX(-40px) translateY(-340%);
		transform:scale(1.9) translateX(-40px) translateY(-340%)
	}
	100% {
		-webkit-transform:translateX(-100px);
		transform:translateX(-100px)
	}
}

@keyframes flycenter-data-v-1a236634 {
	0% {
		-webkit-transform:scale(0) translateX(0);
		transform:scale(0) translateX(0);
		opacity:.6
	}
	5% {
		-webkit-transform:scale(1) translateX(0) translateY(-80%);
		transform:scale(1) translateX(0) translateY(-80%);
		opacity:.8
	}
	20% {
		opacity:1
	}
	30% {
		opacity:.2
	}
	32% {
		opacity:0;
		visibility:hidden
	}
	34% {
		opacity:0
	}
	50% {
		-webkit-transform:scale(1.9) translateX(0) translateY(-340%);
		transform:scale(1.9) translateX(0) translateY(-340%)
	}
	100% {
		-webkit-transform:translateX(0);
		transform:translateX(0)
	}
}

@keyframes flyright-data-v-1a236634 {
	0% {
		-webkit-transform:scale(0) translateX(0);
		transform:scale(0) translateX(0);
		opacity:.6
	}
	5% {
		-webkit-transform:scale(1) translateX(0) translateY(-80%);
		transform:scale(1) translateX(0) translateY(-80%);
		opacity:.8
	}
	20% {
		opacity:1
	}
	30% {
		opacity:.2
	}
	32% {
		opacity:0;
		visibility:hidden
	}
	34% {
		opacity:0
	}
	50% {
		-webkit-transform:scale(1.9) translateX(40px) translateY(-340%);
		transform:scale(1.9) translateX(40px) translateY(-340%)
	}
	100% {
		-webkit-transform:translateX(100px);
		transform:translateX(100px)
	}
}
</style>