小程序手持弹幕的原理及实现(uni-app)

  • Post author:
  • Post category:小程序





手持弹幕前言

通过本篇的文章,可以使用HBuilder写一个手持弹幕,一步一步编写出来。(https://download.csdn.net/download/long19981231/85505893?spm=1001.2014.3001.5503)

先来效果展示(小程序)

在这里插入图片描述




一、思路

思考手持弹幕的实现:让文字横屏,然后匀速运动,当文字尾部到达屏幕的一半的时候,手机屏幕的底部再出来和之前一样的文字实现循环,最后用户可以控制文字大小,速度的快慢,文字的颜色等。



二、代码实现



1.文字横向展示

首先需要有个盒子,将盒子设置为和手机屏幕一样的宽高,通过

transform

属性旋转90度旋转中心点为屏幕的中心

——旋转盒子内容会变吗?

盒子旋转后里面的内容也会跟着改变

旋转后发现文字实现了横向,但是文字位于右上角,需要文字水平居中。给文字的外盒子一个

高度百分之百

垂直居中。

——这里有个小坑,为啥是高度不是宽度?

原因是盒子旋转了

┐( ̄ー ̄)┌

为了看着比较好看点给文字加上

filter

属性

// template标签
	<view class="barrage-box">
		<view class="bulletB">
			<text>文字横向</text>
		</view>
	</view>

// style标签
	page {
		background: #010101;
	}
	.barrage-box{
		width: 100vh;
		height: 100vw;
		transform-origin: 50vw 50vw;
		transform: rotate(90deg);
		background-color: #010101;
		overflow: hidden;
	}
	.bulletB{
		display: flex;
		align-items: center;
		height: 100%;
		color: #fff;
		font-size: 200rpx;
	}
	.bulletB text {
		filter: drop-shadow(4px 2px 2px #cd2068);
	}

效果图:

手持弹幕



2.让文字滚动起来

这一步就有点复杂,不仅要考虑到那种方式滚动起来更加合理,还要考虑到如何实现连续滚动。

滚动方式采用

css动画属性

来实现滚动,连续滚动肯定要有两个一样的元素,首先第一个动画文字从屏幕底部滚动到顶部,第二个动画接上第一个动画的结尾,第二个text文字滚动到和顶部一致的时候循环。

——为啥滚动的动画不放到类为bulletB的标签上?

效果不理想,可以试试**(~ ̄▽ ̄)~**

——为啥要用两个动画?

我只能想到用两个动画去实现,如果有更好的方法,指点我一下**(✪ω✪)**

之前没有修改的代码就不显示,新增代码如下:

// template标签
	<view class="bulletB">
		<text :class="rollClass">文字横向~</text>
		<text :class="rollClass">文字横向~</text>
	</view>

// script标签
		data() {
			return {
				rollClass:'',
			}
		},
		onShow() {
			this.roll()
			this.rollClass = 'roll'
		},
		methods: {
			roll(){
			// 这里的2000时间是由于动画执行2s,如果动画时间改变,这个也应该改变
				setTimeout(() => {
					this.roll()
					this.rollClass = 'rollCycle'
				},2000)
			}
		}

// style标签
	.bulletB text {
		padding-right: 300px;
		white-space: nowrap;
		filter: drop-shadow(4px 2px 2px #cd2068);
		animation-duration:2s;
	}
	
	.roll {
		animation-name: rollScreen;
		animation-timing-function: linear
	}
	
	.rollCycle {
		animation-name: roll;
		animation-timing-function: linear;
		animation-iteration-count: infinite;
	}
	
	@keyframes rollScreen {
		0% {
			transform: translateX(100vh);
		}
	
		100% {
			transform: translateX(0px);
		}
	}
	
	@keyframes roll {
		0% {
			transform: translateX(0px);
		}
	
		100% {
			transform: translateX(-100%);
		}
	}

运行界面:

手持弹幕



3.用户可以控制文字

一个输入框用于用户输入,当用户输入完成后,要根据文字的长度去计算出动画所需的时间,重新执行动画。

思路有了开始实现。

之前没有修改的代码就不显示,新增代码如下:

// template标签
		<view v-show="isShow && !isSetup" class="foot">
			<view class="footUp">
				<view class="footUpLeft">
					<input v-model="newRollTxt" type="text" placeholder="请输入内容"/>
					<text @click="setTxt()" class="btn">发送</text>
				</view>
				<!-- <view @click="Setup()" class="footIcon">
					<uni-icons type="settings-filled" size="30" color="#FFFFFF"></uni-icons>
				</view> -->
			</view>
		</view>
		
		<view @click="setShow"  class="barrage-box">
			<view class="bulletB">
				<text :class="rollClass" class="text" :style="{'animation-duration': rollTime}">{{rollTxt}}</text>
				<text :class="rollClass" :style="{'animation-duration': rollTime}">{{rollTxt}}</text>
			</view>
		</view>


// script标签
		data() {
			return {
				rollClass:'',
				rollTxt:'手持弹幕~',
				rollTime:'',
				newRollTxt:'',
				isShow: true, // 底部是否显示
				screenHeight: '', // 屏幕高度
				speed: 300, // 动画速度的比值
				timerName:'' // 定时器
			}
		},
		onReady() {
			uni.getSystemInfo({
				success: (res) => {
					this.screenHeight = res.screenHeight
					this.setTime()
				}
			})
		},
		methods: {
			setShow(){
				this.isShow = !this.isShow
			},
			// 发送弹幕
			setTxt() {
				this.rollTxt = this.newRollTxt
				this.newRollTxt = ''
				// 清除定时器,防止第一次东湖没有执行完,又重新输入了。
				clearTimeout(this.timerName);
				this.setTime()
			},
			// 计算出时间
			setTime() {
				this.$nextTick(() => {
					let txtView = uni.createSelectorQuery().in(this).select(".text");
					txtView.boundingClientRect(
						data => {
							this.rollClass = this.rollClass == 'rollTwo' ? 'roll' : 'rollTwo'
							// 屏幕高度除以动画比值得出第一个动画需要的时间
							let rollSpeed = (this.screenHeight / this.speed).toFixed(1)
							this.rollTime = rollSpeed + 's'
							// 滚动文字长度除以动画比值得出第二循环动画需要的时间
							let rollSpeedTxt = (rollSpeed * (data.height / this.screenHeight)).toFixed(1)
							// 设置一个计时器,当第一个动画结束的时候执行第二个动画
							this.timerName = setTimeout(() => {
								this.rollClass = 'rollCycle'
								this.rollTime = rollSpeedTxt + 's'
							}, rollSpeed * 1000)
						}).exec();
				})
			}
		}


// style标签

	.foot {
		position: fixed;
		bottom: 0rpx;
		z-index: 10;
	}
	
	.footUp {
		padding-left: 30rpx;
		display: flex;
		align-items: center;
		margin-bottom: 20rpx;
	}
	
	.footUpLeft {
		width: 640rpx;
		display: flex;
		align-items: center;
		justify-content: center;
		height: 80rpx;
		padding: 0 30rpx;
		background: #212427;
		color: #FFFFFF;
		border-radius: 10rpx;
	}
	
	.footUpLeft input {
		flex: 1;
	}
	
	.footUpLeft .btn {
		margin-left: 20rpx;
	}

	.rollTwo {
		animation-name: rollAgain;
		animation-timing-function: linear;
	}
	
	@keyframes rollAgain {
		0% {
			transform: translateX(100vh);
		}
	
		100% {
			transform: translateX(0px);
		}
	}




总结

别的小朋友有的我也要有

ᕦ(・ㅂ・)ᕤ

过程中遇到不少问题,幸运的是都不算是太难。

可能该手持弹幕还有一些问题存在比如文字过短的时候会导致第二个字不是从屏幕最底下出现的,加个文本长度和屏幕长度的对比就好了。

原本还想吧那个修改颜色,速度,大小写上去。明天放假**(~ ̄▽ ̄)~** 就这吧。



版权声明:本文为long19981231原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。