uniapp 开发之仿抖音,上下滑动切换视频、点击小爱心效果

效果图:  

功能描述:

上下滑动视频,双击暂停,然后第一个视频再往上滑显示”已经滑到顶了“

开始代码:

首先视频接口使用的公开的视频测试接口

开放API-2.0  官网展示                      Swagger UI  接口文档

一开始编写如下: 

<template>
	<view>
		<!--swiper实现整屏划动播放视频-->
		<swiper circular vertical duration="200" @transition="transition" @change="changed"
			:style="{height: screenHeight-navBarHeight +'px'}">
			<block v-for="(item,index) in displaySwiperList" :key="index">
				<swiper-item>
					<!-- v-if="index==changeIndex" 只渲染当前页的视频,能够有效解决数组不断追加后引起黑屏的问题 -->
					<video v-if="index==changeIndex" :src="item.src" autoplay="true" controls="true"
						custom-cache="false" loop="false" enable-play-gesture="true" enable-progress-gesture="true"
						show-center-play-btn="true">
					</video>
					<!-- 文本标题 -->
					<view class="video-text">
						<view class="tips"> {{item.title}} </view>
					</view>
				</swiper-item>
			</block>
		</swiper>
 
	</view>
</template>
 
<script>
	export default {
		data() {
			return {
				screenHeight: 0,
				statusBarHeight: 0,
				navBarHeight: 0,
				originList: [], // 源数据
				displaySwiperList: [], // swiper需要的数据
				displayIndex: 0, // 用于显示swiper的真正的下标数值只有:0,1,2。
				originIndex: 0, // 记录源数据的下标
				changeIndex: 0, //控制video是否渲染
				page: 0, // 视频分页
				num: 0,
				flag: true
			}
		},
		onLoad() {
			/* 获取系统信息 */
			wx.getSystemInfo({
				success: (res) => {
					// 获取屏幕高度
					this.screenHeight = res.screenHeight
					// 获取状态栏高度
					this.statusBarHeight = res.statusBarHeight
					// 通过操作系统 确定自定义导航栏高度  
					if (res.system.substring(0, 3) == "iOS") {
						this.navBarHeight = 42
					} else {
						this.navBarHeight = 40
					}
				}
			})
 
			// 调用函数
			this.getPageID()
 
		},
 
		methods: {
			/* 生成随机的 pageID */
			getPageID() {
				let pageID = parseInt(Math.random() * (0 - 100 + 1) + 100) //生成 [min,max] 的随机数
				this.getVideoList(pageID)
			},
			/* 获取视频数据 */
			getVideoList(pageID) {
				uni.request({
					url: 'https://api.apiopen.top/api/getMiniVideo?page=' + pageID +
						'&size=10&pageSize=10', // 请求数据接口
					data: {},
					success: (res) => {
						if (res.data.code == 200) {
							res.data.result.list.forEach(item => {
								//取源数据的部分属性组合成新的数组
								let obj = {}
								obj.src = item.playurl
								obj.title = item.title
 
								this.originList.push(obj)
							})
						}
						//解决首次加载页面的时候没有画面的问题
						if (this.flag) {
							this.flag = false
							this.initSwiperData(0)
						}
 
					}
				})
			},
			changed(event) {
				let {
					current
				} = event.detail;
				let originListLength = this.originList.length;
				this.changeIndex = current;
				// console.log(this.displayIndex,current)
				// 如果两者的差为2或者-1则是向后滑动
				if (this.displayIndex - current == 2 || this.displayIndex - current == -1) {
					this.originIndex = this.originIndex + 1 == originListLength ? 0 : this.originIndex + 1;
					this.displayIndex = this.displayIndex + 1 == 3 ? 0 : this.displayIndex + 1;
 
					this.initSwiperData(this.originIndex);
					//如果滑到最后一条,请求新数据
					this.num++
					console.log('num',this.num,this.originList.length)
					if (this.num + 5 >= this.originList.length) {
						
						this.getPageID()
					}
				}
				// 如果两者的差为-2或者1则是向前滑动
				else if (this.displayIndex - current == -2 || this.displayIndex - current == 1) {
					this.originIndex = this.originIndex - 1 == -1 ? originListLength - 1 : this.originIndex - 1;
					this.displayIndex = this.displayIndex - 1 == -1 ? 2 : this.displayIndex - 1;
					this.initSwiperData(this.originIndex);
 
					if (this.num > 0) {
						this.num--
					}
				}
			},
 
			initSwiperData(originIndex = this.originIndex) {
				// console.log(this.displayIndex,originIndex)
				// 0 0
				// 1 1
				// 2 2
				// 0 3
				// 1 4
				//源数据长度
				let originListLength = this.originList.length;
				let displayList = [];
				displayList[this.displayIndex] = this.originList[originIndex];
				displayList[this.displayIndex - 1 == -1 ? 2 : this.displayIndex - 1] = this.originList[originIndex - 1 == -
					1 ? originListLength - 1 : originIndex - 1];
				displayList[this.displayIndex + 1 == 3 ? 0 : this.displayIndex + 1] = this.originList[originIndex + 1 ==
					originListLength ? 0 : originIndex + 1];
				// console.log(originIndex, (originIndex - 1 == -1 ? originListLength - 1 : originIndex - 1), (originIndex +
				// 	1 == originListLength ? 0 : originIndex + 1))
				// 0 9 1
				// 1 0 2
				// 2 1 3
				// 3 2 4
				// 4 3 5
				//刷新数据
				this.displaySwiperList = displayList;
				// console.log(this.displaySwiperList,this.originList)
			},
		}
	}
</script>
 
<style>
	swiper {
		width: 100%;
		background: #000
	}
 
	swiper-item {
		height: 100%;
		width: 100%
	}
 
	video {
		height: 96%;
		width: 100%
	}
 
	.video-text {
		position: absolute;
		margin-left: 32rpx;
		width: 580rpx;
		bottom: 200rpx;
		z-index: 9999;
	}
 
	.tips {
		width: 560rpx;
		font-size: 26rpx;
		color: #ffffff;
	}
</style>

注解:

  • autoplay="true":设置视频在加载完成后自动播放。
  • controls="true":显示视频的控制面板,包括播放/暂停按钮、音量控制、进度条和全屏按钮等。
  • custom-cache="false":禁用视频的自定义缓存,在每次播放时都重新加载视频。
  • loop="false":设置视频不循环播放,当播放完成后停止。
  • enable-play-gesture="true":启用手势控制,允许通过手势来播放/暂停视频。
  • enable-progress-gesture="true":启用手势控制,允许通过手势来调整视频播放的进度。
  • show-center-play-btn="true":显示一个居中的播放按钮,当视频处于暂停状态时,点击按钮可以播放视频。

进一步希望能够实现上滑到第一个视频之后,关闭循环 无法再上滑

<swiper :circular="!canCircular" >
</swiper>

computed: {
	canCircular() {
			console.log(Boolean((this.originIndex + 1 == this.originList.length ? 0 : this.originIndex + 1) == 1))
			return (this.originIndex + 1 == this.originList.length ? 0 : this.originIndex + 1) == 1; 
	}
}

第一个视频再上滑 弹出提示框

<swiper @transition="transition">
</swiper>


transition(e) {
	// console.log(e)
	let originListLength = this.originList.length;
	if ((this.originIndex + 1 == originListLength ? 0 : this.originIndex + 1) == 1 && e.detail.dy < -100) {
		uni.showToast({
			title: '已经到顶了',
			icon: 'none'
		})
	}
}

注解:

swiper-item 的位置发生改变时会触发 transition 事件,通过判断是否为第一个视频 && 进行了上滑行为 来控制弹出”已经到顶的提示“

完整代码:

<template>
	<view>
		<!--swiper实现整屏划动播放视频-->
		<swiper :circular="!canCircular" vertical duration="200" @transition="transition" @change="changed"
			:style="{height: screenHeight-navBarHeight +'px'}">
			<block v-for="(item,index) in displaySwiperList" :key="index">
				<swiper-item>
					<!-- v-if="index==changeIndex" 只渲染当前页的视频,能够有效解决数组不断追加后引起黑屏的问题 -->
					<video v-if="index==changeIndex" :src="item.src" autoplay="true" controls="true"
						custom-cache="false" loop="false" enable-play-gesture="true" enable-progress-gesture="true"
						show-center-play-btn="true">
					</video>
					<!-- 文本标题 -->
					<view class="video-text">
						<view class="tips"> {{item.title}} </view>
					</view>
				</swiper-item>
			</block>
		</swiper>

	</view>
</template>

<script>
	export default {
		data() {
			return {
				screenHeight: 0,
				statusBarHeight: 0,
				navBarHeight: 0,
				originList: [], // 源数据
				displaySwiperList: [], // swiper需要的数据
				displayIndex: 0, // 用于显示swiper的真正的下标数值只有:0,1,2。
				originIndex: 0, // 记录源数据的下标
				changeIndex: 0, //控制video是否渲染
				page: 0, // 视频分页
				num: 0,
				flag: true
			}
		},
		computed: {
			canCircular() {
				console.log(Boolean((this.originIndex + 1 == this.originList.length ? 0 : this.originIndex + 1) == 1))
				return (this.originIndex + 1 == this.originList.length ? 0 : this.originIndex + 1) == 1; 
			}
		},
		onLoad() {
			/* 获取系统信息 */
			wx.getSystemInfo({
				success: (res) => {
					// 获取屏幕高度
					this.screenHeight = res.screenHeight
					// 获取状态栏高度
					this.statusBarHeight = res.statusBarHeight
					// 通过操作系统 确定自定义导航栏高度  
					if (res.system.substring(0, 3) == "iOS") {
						this.navBarHeight = 42
					} else {
						this.navBarHeight = 40
					}
				}
			})

			// 调用函数
			this.getPageID()

		},

		methods: {
			transition(e) {
				// console.log(e)
				let originListLength = this.originList.length;
				if ((this.originIndex + 1 == originListLength ? 0 : this.originIndex + 1) == 1 && e.detail.dy < -100) {
					uni.showToast({
						title: '已经到顶了',
						icon: 'none'
					})
				}
			},
			/* 生成随机的 pageID */
			getPageID() {
				let pageID = parseInt(Math.random() * (0 - 100 + 1) + 100) //生成 [min,max] 的随机数
				this.getVideoList(pageID)
			},
			/* 获取视频数据 */
			getVideoList(pageID) {
				uni.request({
					url: 'https://api.apiopen.top/api/getMiniVideo?page=' + pageID +
						'&size=10&pageSize=10', // 请求数据接口
					data: {},
					success: (res) => {
						if (res.data.code == 200) {
							res.data.result.list.forEach(item => {
								//取源数据的部分属性组合成新的数组
								let obj = {}
								obj.src = item.playurl
								obj.title = item.title

								this.originList.push(obj)
							})
						}
						//解决首次加载页面的时候没有画面的问题
						if (this.flag) {
							this.flag = false
							this.initSwiperData(0)
						}

					}
				})
			},
			changed(event) {
				let {
					current
				} = event.detail;
				let originListLength = this.originList.length;
				this.changeIndex = current;
				// console.log(this.displayIndex,current)
				// 如果两者的差为2或者-1则是向后滑动
				if (this.displayIndex - current == 2 || this.displayIndex - current == -1) {
					this.originIndex = this.originIndex + 1 == originListLength ? 0 : this.originIndex + 1;
					this.displayIndex = this.displayIndex + 1 == 3 ? 0 : this.displayIndex + 1;

					this.initSwiperData(this.originIndex);
					//如果滑到最后一条,请求新数据
					this.num++
					console.log('num',this.num,this.originList.length)
					if (this.num + 5 >= this.originList.length) {
						
						this.getPageID()
					}
				}
				// 如果两者的差为-2或者1则是向前滑动
				else if (this.displayIndex - current == -2 || this.displayIndex - current == 1) {
					this.originIndex = this.originIndex - 1 == -1 ? originListLength - 1 : this.originIndex - 1;
					this.displayIndex = this.displayIndex - 1 == -1 ? 2 : this.displayIndex - 1;
					this.initSwiperData(this.originIndex);

					if (this.num > 0) {
						this.num--
					}
				}
			},

			initSwiperData(originIndex = this.originIndex) {
				// console.log(this.displayIndex,originIndex)
				// 0 0
				// 1 1
				// 2 2
				// 0 3
				// 1 4
				//源数据长度
				let originListLength = this.originList.length;
				let displayList = [];
				displayList[this.displayIndex] = this.originList[originIndex];
				displayList[this.displayIndex - 1 == -1 ? 2 : this.displayIndex - 1] = this.originList[originIndex - 1 == -
					1 ? originListLength - 1 : originIndex - 1];
				displayList[this.displayIndex + 1 == 3 ? 0 : this.displayIndex + 1] = this.originList[originIndex + 1 ==
					originListLength ? 0 : originIndex + 1];
				// console.log(originIndex, (originIndex - 1 == -1 ? originListLength - 1 : originIndex - 1), (originIndex +
				// 	1 == originListLength ? 0 : originIndex + 1))
				// 0 9 1
				// 1 0 2
				// 2 1 3
				// 3 2 4
				// 4 3 5
				//刷新数据
				this.displaySwiperList = displayList;
				// console.log(this.displaySwiperList,this.originList)
			},
		}
	}
</script>

<style>
	swiper {
		width: 100%;
		background: #000
	}

	swiper-item {
		height: 100%;
		width: 100%
	}

	video {
		height: 96%;
		width: 100%
	}

	.video-text {
		position: absolute;
		margin-left: 32rpx;
		width: 580rpx;
		bottom: 200rpx;
		z-index: 9999;
	}

	.tips {
		width: 560rpx;
		font-size: 26rpx;
		color: #ffffff;
	}
</style>

小爱心效果 

<!DOCTYPE html>
<html>

<head>
  <title>点赞特效</title>
  <style>
    body {
      margin: 0;
      padding: 0;
      overflow: hidden;
    }

    #heart {
      position: absolute;
      top: 50%;
      left: 50%;
      width: 100px;
      height: 100px;
      border-radius: 50%;
      background: red;
      transform: translate(-50%, -50%);
      animation: heartBeat 1s linear infinite;
    }

    @keyframes heartBeat {
      0% {
        transform: scale(1);
      }

      50% {
        transform: scale(1.2);
      }

      100% {
        transform: scale(1);
      }
    }
  </style>
</head>

<body>
  <script src="https://cdn.jsdelivr.net/npm/jquery"></script>
  <script>
    $(document).ready(function () {
      var hearts = ["❤️", "💛", "💙", "💚", "💜", "🧡"];

      $(document).click(function (e) {
        var x = e.pageX;
        var y = e.pageY;

        var heartIcon = $("<div>").addClass("heart").text(hearts[Math.floor(Math.random() * hearts.length)]);

        $(heartIcon).css({
          position: "absolute",
          top: y - 10,
          left: x - 10,
          color: "red",
          userSelect: "none",
          pointerEvents: "none"
        });

        $("body").append($(heartIcon));

        // 1000 是动画的持续时间
        $(heartIcon).animate({
          top: y - 100,
          opacity: 0
        }, 1000, function () {
          $(heartIcon).remove();
        });
      });
    });
  </script>
</body>

</html>

效果图:

也可以将其换成爱心图片:

<!DOCTYPE html>
<html>

<head>
  <title>点赞特效</title>
  <style>
    body {
      margin: 0;
      padding: 0;
      overflow: hidden;
    }

    #heart {
      position: absolute;
      top: 50%;
      left: 50%;
      width: 100px;
      height: 100px;
      border-radius: 50%;
      background: red;
      transform: translate(-50%, -50%);
      animation: heartBeat 1s linear infinite;
    }

    @keyframes heartBeat {
      0% {
        transform: scale(1);
      }

      50% {
        transform: scale(1.2);
      }

      100% {
        transform: scale(1);
      }
    }
  </style>
</head>

<body>
  <script src="https://cdn.jsdelivr.net/npm/jquery"></script>
  <script>
    $(document).ready(function () {
      var hearts = ["❤️", "💛", "💙", "💚", "💜", "🧡"];

      $(document).click(function (e) {
        var x = e.pageX;
        var y = e.pageY;

        // var heartIcon = $("<div>").addClass("heart").text(hearts[Math.floor(Math.random() * hearts.length)]);
        var heartIcon = $("<img>").addClass("heart").attr("src", "./hh.png")

        $(heartIcon).css({
          position: "absolute",
          top: y - 10,
          left: x - 10,
          color: "red",
          wight:"40px",
          height:"40px",
          userSelect: "none",
          pointerEvents: "none"
        });

        $("body").append($(heartIcon));

        // 1000 是动画的持续时间
        $(heartIcon).animate({
          top: y - 100,
          opacity: 0
        }, 1000, function () {
          $(heartIcon).remove();
        });
      });
    });
  </script>
</body>

</html>

效果图:

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/97744.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AMEYA360:ROHM开发出适用于条码标签打印应用、超快打印速度的热敏打印头

AMEYA360&#xff1a;ROHM开发出适用于条码标签打印应用、超快打印速度的热敏打印头 全球知名半导体制造商ROHM(总部位于日本京都市)新推出两款高可靠性高速热敏打印头 “TE2004-QP1W00A(203dpi)”和“TE3004-TP1W00A(300dpi)”&#xff0c;新产品非常适用于物流和库存管理等领…

【Python自学笔记】Python好用的模块收集(持续更新...)

文章目录 日志模块钉钉机器人命令助手持续更新中,如果您有其他实用好用的模块欢迎留言...日志模块 写代码离不开日志,自定义一个理想的日志对于小白来说可能是一件很反锁的事情,就像我刚学习Python的时候自己写的一个自定义日志,为了解决这个痛点,今天就和大家分享一个可以…

Python 接口测试之接口关键字封装

引言 我们使用RF做UI自动化测试的时候&#xff0c;使用的是关键字驱动。同样&#xff0c;Python做接口自动化测试的时候&#xff0c;也可以使用关键字驱动。但是这里并不是叫关键字驱动&#xff0c;而是叫数据驱动。而接口测试的关键字是什么呢&#xff1f; 我们数据驱动的载体…

多用户商城系统常见的安全性和数据保护措施有哪些?

电子商务的迅速发展&#xff0c;越来越多的企业选择搭建多用户商城系统来扩展业务。然而&#xff0c;随之而来的是对数据安全和保护的日益关注。在选择多用户商城系统时&#xff0c;我们需要考虑一系列的安全性和数据保护措施&#xff0c;以确保商城系统的稳定性和用户数据的完…

SpringBoot + layui 框架实现一周免登陆功能

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

抢跑预制菜,双汇发展转守为攻?

懒&#xff0c;懒出新风口&#xff0c;预制菜竟成了年轻人新时代的“田螺神话”&#xff1f; 《2022年中国预制菜产业发展白皮书》数据显示&#xff0c;2022年全国预制菜的市场规模是4196亿元人民币&#xff0c;到2026年可以突破万亿大关。 预制菜的火爆显而易见&#xff0c;…

Java的类加载顺序

加载、验证、准备、解析和初始化。 加载 “加载”(Loading)阶段是“类加载”(Class Loading)过程的第一个阶段&#xff0c;在此阶段&#xff0c;虚拟机需要完成以下三件事情&#xff1a; 通过一个类的全限定名来获取定义此类的二进制字节流。将这个字节流所代表的静态存储结构…

如果应对2023年国赛

国赛倒计时一周&#xff0c;大家多看看优秀论文&#xff0c;赛前多思考&#xff0c;使大脑在活跃状态&#xff0c;更好的应对题目。 需要历年游戏论文的小伙伴可私信我&#xff0c;或关注微信公众号私信我

Rabbitmq的Shovel

Federation 具备的数据转发功能类似&#xff0c; Shovel 够可靠、持续地从一个 Broker 中的队列 ( 作为源端&#xff0c;即source)拉取数据并转发至另一个 Broker 中的交换器 ( 作为目的端&#xff0c;即 destination) 。作为源端的队列和作为目的端的交换器可以同时位于…

Debian12 Gnome环境下的办公软件安装

一、禁用Wayland&#xff0c;启用xorg 当前Debian12 默认采用Wayland来支持gnome环境&#xff0c;但是许多软件无法在该系统下显示&#xff0c;例如&#xff1a;openoffice&#xff0c;yozo-office&#xff0c;weixin&#xff0c;fcitx。所以要在gdm3的配置文件中&#xff0c;…

二叉树的构建及遍历

目录 题目题目要求示例 解答方法一、实现思路时间复杂度和空间复杂度代码 方法二、实现思路时间复杂度和空间复杂度代码 题目 二叉树的构建及遍历 题目要求 题目链接 示例 解答 方法一、 先构建二叉树&#xff0c;再中序遍历。 实现思路 按照给出的字符串创建二叉树&am…

微信8.0.41更新来了,看看有哪些变化吧

微信给我们带来了极大的方便&#xff0c;无论是日常聊天还是工作沟通&#xff0c;几乎离不开它。 时不时会给我一种熟悉的陌生感。 这个功能&#xff0c;好像我之前是没见过的。 就比如公众号信息流&#xff0c;刷着刷着就会发现&#xff0c;怎么会有看一看的信息推流会突然出现…

浅谈Lua协程和函数的尾调用

前言 虽然不经常用到协程&#xff0c;但是也不能谈虎色变。同时&#xff0c;在有些场景&#xff0c;协程会起到一种不可比拟的作用。所以&#xff0c;了解它&#xff0c;对于一些功能&#xff0c;也会有独特的思路和想法。 协程 概念 关于进程和线程的概念就不多说。 那么…

HRS--人力资源系统(Springboot+vue)--打基础升级--(六)分页查询 + 重置按钮

一&#xff1a;先弄个简单的重置按钮 1.界面设计就放在搜索框同一列的位置 2. 在点击重置按钮时&#xff0c;清空搜索框内的内容&#xff0c;同时触发一次无条件查询(这个写法有bug&#xff0c;下面会有说明) 二&#xff1a;做分页 在MyBatis中&#xff0c;有多种方法可以实现分…

Python编程

Lesson I 解rar压缩包的密码 1 下载Python并安装 网址: 注意选对是32 bit还是64 bit Python Releases for Windows | Python.orgThe official home of the Python Programming Languagehttps://www.python.org/downloads/windows/ 2 安装unrar pip install unrar 3 下载u…

十八、责任链模式

一、什么是责任链模式 责任链&#xff08;Chain of Responsibility&#xff09;模式的定义&#xff1a;为了避免请求发送者与多个请求处理者耦合在一起&#xff0c;于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链&#xff1b;当有请求发生时&#xff0…

开发卡牌gamefi游戏需要多少钱?

卡牌游戏作为一种受欢迎的游戏形式&#xff0c;吸引了众多开发者的关注。然而&#xff0c;开发一款成功的卡牌游戏需要全面考虑多个方面的因素&#xff0c;其中之一就是资金投入。本文将从专业性和投入回报的角度&#xff0c;探讨开发一款卡牌游戏所需的资金投入。 一、专业性的…

KubeFlow组件介绍

kubeflow是一个胶水项目&#xff0c;它把诸多对机器学习的支持&#xff0c;比如模型训练&#xff0c;超参数训练&#xff0c;模型部署等进行组合并已容器化的方式进行部署&#xff0c;提供整个流程各个系统的高可用及方便的进行扩展部署了 kubeflow的用户就可以利用它进行不同的…

四层负载均衡的NAT模型与DR模型推导 | 京东物流技术团队

导读 本文首先讲述四层负载均衡技术的特点&#xff0c;然后通过提问的方式推导出四层负载均衡器的NAT模型和DR模型的工作原理。通过本文可以了解到四层负载均衡的技术特点、NAT模型和DR模型的工作原理、以及NAT模型和DR模型的优缺点。读者可以重点关注NAT模型到DR模型演进的原…

Visual Studio 2022的MFC框架——theApp全局对象

我是荔园微风&#xff0c;作为一名在IT界整整25年的老兵&#xff0c;今天我们来重新审视一下Visual Studio 2022下开发工具的MFC框架知识。 MFC中的WinMain函数是如何与MFC程序中的各个类组织在一起的呢&#xff1f;MFC程序中的类是如何与WinMain函数关联起来的呢&#xff1f…