| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 | 
							- <template>
 
- 	<view class="like-container">
 
- 		<image class="image" @click="handleLike" src="/static/images/like_live.png" ref="likeBtn"></image>
 
- 		<view v-for="(icon, index) in icons" :key="icon.id" class="animated-icon" :style="{
 
-         top: icon.top + 'rpx',
 
-         left: icon.left + 'rpx',  // 补充left属性的单位
 
-         fontSize: icon.size + 'rpx',
 
-         color: icon.color,
 
-         opacity: icon.opacity,
 
-         transform: 'translateY(' + icon.y + 'rpx) rotate(' + icon.rotate + 'deg)',
 
-         transition: 'all ' + icon.duration + 'ms ' + icon.delay + 'ms ease-out'
 
-       }">
 
- 			{{ icon.symbol }}
 
- 		</view>
 
- 	</view>
 
- </template>
 
- <script>
 
- 	export default {
 
- 		name: 'DouyinLike',
 
- 		props: {
 
- 			// 初始点赞数
 
- 			initialCount: {
 
- 				type: Number,
 
- 				default: 0
 
- 			},
 
- 			// 单次点击生成的图标数量
 
- 			iconAmount: {
 
- 				type: Number,
 
- 				default: 6
 
- 			},
 
- 			// 图标颜色集合
 
- 			iconColors: {
 
- 				type: Array,
 
- 				default: () => [
 
- 					'#ff6082', '#ffb92b', '#ffaefb',
 
- 					'#87f37f', '#6eb9ff', '#6d86d6',
 
- 					'#ab71de', '#ff4b84'
 
- 				]
 
- 			},
 
- 			// 图标大小范围
 
- 			sizeRange: {
 
- 				type: Array,
 
- 				default: () => [40, 78]
 
- 			},
 
- 			// 动画持续时间范围(ms)
 
- 			durationRange: {
 
- 				type: Array,
 
- 				default: () => [700, 1300]
 
- 			},
 
- 			// 上升距离范围(px)
 
- 			riseRange: {
 
- 				type: Array,
 
- 				default: () => [200, 420]
 
- 			},
 
- 			// 左右飘动范围(px)
 
- 			floatRange: {
 
- 				type: Array,
 
- 				default: () => [-50, 50]
 
- 			}
 
- 		},
 
- 		data() {
 
- 			return {
 
- 				// 当前点赞数
 
- 				count: this.initialCount,
 
- 				// 是否已点赞
 
- 				isLiked: false,
 
- 				// 动画图标数组
 
- 				icons: [],
 
- 				// 按钮位置信息
 
- 				btnRect: null,
 
- 				// 可使用的图标集合
 
- 				iconSymbols: ['❤', '★', '🎁', '🔥', '👍', '✨', '💖', '🌟'],
 
- 				// 用于生成唯一ID
 
- 				iconId: 0
 
- 			};
 
- 		},
 
- 		mounted() {
 
- 			// 获取按钮位置信息
 
- 			this.getBtnRect();
 
- 		},
 
- 		methods: {
 
- 			/**
 
- 			 * 获取按钮位置信息
 
- 			 */
 
- 			getBtnRect() {
 
- 				const query = uni.createSelectorQuery().in(this);
 
- 				query.select('.image').boundingClientRect(data => {
 
- 					this.btnRect = data;
 
- 				}).exec();
 
- 			},
 
- 			/**
 
- 			 * 处理点击事件
 
- 			 */
 
- 			handleLike(e) {
 
- 				// 更新点赞状态
 
- 				this.isLiked = !this.isLiked;
 
- 				this.count += this.isLiked ? 1 : -1;
 
- 				this.$emit('change', {
 
- 					isLiked: this.isLiked,
 
- 					count: this.count
 
- 				});
 
- 				// 生成图标动画
 
- 				this.createIcons(e);
 
- 			},
 
- 			/**
 
- 			 * 创建多个图标动画
 
- 			 */
 
- 			createIcons(e) {
 
- 				if (!this.btnRect) {
 
- 					this.getBtnRect();
 
- 					return;
 
- 				}
 
- 				// 获取点击位置(相对于按钮)
 
- 				const rect = this.btnRect;
 
- 				const x = e.detail.x - rect.left;
 
- 				const y = e.detail.y - rect.top;
 
- 				// 生成多个图标,带轻微延迟形成连续效果
 
- 				for (let i = 0; i < this.iconAmount; i++) {
 
- 					this.createIcon(x, y, i * 40);
 
- 				}
 
- 			},
 
- 			/**
 
- 			 * 创建单个图标动画
 
- 			 * @param {Number} x 初始X坐标
 
- 			 * @param {Number} y 初始Y坐标
 
- 			 * @param {Number} delay 延迟时间(ms)
 
- 			 */
 
- 			createIcon(x, y, delay) {
 
- 				// 随机属性
 
- 				const size = this.getRandom(...this.sizeRange);
 
- 				const color = this.iconColors[Math.floor(Math.random() * this.iconColors.length)];
 
- 				const duration = this.getRandom(...this.durationRange);
 
- 				const riseDistance = -this.getRandom(...this.riseRange);
 
- 				const floatOffset = this.getRandom(...this.floatRange);
 
- 				const rotate = this.getRandom(-30, 30);
 
- 				// 随机选择一个图标
 
- 				const symbol = this.iconSymbols[Math.floor(Math.random() * this.iconSymbols.length)];
 
- 				// 生成唯一ID
 
- 				const iconId = this.iconId++;
 
- 				// 创建图标对象
 
- 				const icon = {
 
- 					id: iconId,
 
- 					left: x,
 
- 					top: y,
 
- 					size,
 
- 					color,
 
- 					opacity: 1,
 
- 					y: 0,
 
- 					rotate,
 
- 					duration,
 
- 					delay,
 
- 					symbol
 
- 				};
 
- 				// 添加到数组
 
- 				this.icons.push(icon);
 
- 				// 触发动画
 
- 				setTimeout(() => {
 
- 					// 使用Vue的$set方法确保响应式更新
 
- 					this.$set(this.icons, this.icons.findIndex(item => item.id === iconId), {
 
- 						...this.icons.find(item => item.id === iconId),
 
- 						y: riseDistance,
 
- 						left: x + floatOffset,
 
- 						opacity: 0
 
- 					});
 
- 				}, delay);
 
- 				// 动画结束后移除
 
- 				setTimeout(() => {
 
- 					const index = this.icons.findIndex(item => item.id === iconId);
 
- 					if (index !== -1) {
 
- 						this.icons.splice(index, 1);
 
- 					}
 
- 				}, duration + delay);
 
- 			},
 
- 			/**
 
- 			 * 生成范围内的随机数
 
- 			 */
 
- 			getRandom(min, max) {
 
- 				return min + Math.random() * (max - min);
 
- 			}
 
- 		}
 
- 	};
 
- </script>
 
- <style scoped lang="scss">
 
- 	.like-container {
 
- 		position: relative;
 
- 	}
 
- 	.image {
 
- 		width: 72rpx;
 
- 		height: 72rpx;
 
- 	}
 
- 	.like-icon {
 
- 		font-size: 28rpx;
 
- 		color: #999;
 
- 		transition: all 0.3s ease;
 
- 	}
 
- 	/* 动画容器 */
 
- 	.like-container {
 
- 		/* position: absolute;
 
-   top: 0;
 
-   left: 0;
 
-   width: 100%;
 
-   height: 100%;
 
-   pointer-events: none;
 
-   overflow: visible; */
 
- 		position: relative;
 
- 		.image {
 
- 			width: 72rpx;
 
- 			height: 72rpx;
 
- 		}
 
- 		/* 动画图标样式 */
 
- 		.animated-icon {
 
- 			position: absolute;
 
- 			will-change: transform, opacity, left;
 
- 			text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.2);
 
- 			z-index: 10;
 
- 			animation-timing-function: cubic-bezier(0.2, 0.8, 0.2, 1);
 
- 		}
 
- 	/* 点赞按钮动画 */
 
- 	@keyframes pulse {
 
- 		0% {
 
- 			transform: scale(1);
 
- 		}
 
- 		50% {
 
- 			transform: scale(1.4);
 
- 		}
 
- 		100% {
 
- 			transform: scale(1);
 
- 		}
 
- 	}
 
- 	}
 
- </style>
 
 
  |