uni-halo/components/barrage/barrage.vue
小莫唐尼 9573b303e2 新增:文章详情页面添加弹幕功能;
修改:修复友链列表单分组显示问题;
优化;对恋爱日记清单列表进行优化
2022-12-12 23:03:48 +08:00

322 lines
6.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="barrage-wrap" :class="[type]">
<view class="danmu-li" v-for="(item, index) in listData" :class="[type, item.type]" :style="[item.style]" :key="index">
<view class="danmu-inner">
<view class="user-box">
<view class="user-img"><image class="avatar" :src="item.item.avatar"></image></view>
<view class="user-text cl1">{{ item.item.author }}</view>
<view class="user-status cl1">{{ item.item.content }}</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
//rightToLeft leftToRight leftBottom
type: {
type: String,
default: 'rightToLeft'
},
list: {
type: Array,
default() {
return [];
}
},
minTime: {
type: Number,
default: 4
},
maxTime: {
type: Number,
default: 9
},
minTop: {
type: Number,
default: 0
},
maxTop: {
type: Number,
default: 240
},
hrackH: {
//轨道高度
type: Number,
default: 40
}
},
data() {
return {
closeTimer: null,
listData: []
};
},
mounted() {
//leftBottom 使用参数
if (this.type === 'leftBottom') {
this.hrackNum = Math.floor(this.maxTop / this.hrackH);
}
},
methods: {
add(obj) {
console.log('加载弹幕中...');
this.isShow = true;
this.showFlag = true;
let data = {
...obj,
id: Date.parse(new Date()),
time: Math.ceil(Math.floor(Math.random() * (this.maxTime - this.minTime + 1) + this.minTime)),
type: this.type
};
if (this.type === 'leftBottom') {
console.log('leftBottom加载弹幕中...');
let objData = {
item: data,
type: 'leftBottomEnter',
style: {
transition: `all 0.5s`,
animationDuration: `0.5s`,
transform: `translateX(0%)`,
bottom: `${this.minTop}px`
}
};
let listLen = this.listData.length;
let hrackNum = this.hrackNum;
for (let i in this.listData) {
if (this.listData[i].status === 'reuse') {
//重用
this.$set(this.listData, i, objData);
} else if (this.listData[i].status === 'reset') {
//重置
this.listData[i].style.transition = 'none';
this.listData[i].style.bottom = '6px';
this.listData[i].status = 'reuse';
} else if (this.listData[i].status === 'recycle') {
//回收
this.listData[i].type = 'leftBottomExit';
this.listData[i].status = 'reset';
} else {
this.listData[i].style.bottom = parseInt(this.listData[i].style.bottom) + this.hrackH + 'px';
}
if (parseInt(this.listData[i].style.bottom) >= this.maxTop - this.hrackH && this.listData[i].status !== 'reset') {
//需要回收
this.listData[i].status = 'recycle';
}
}
if (listLen < hrackNum + 2) {
this.listData.push(objData);
}
} else if (this.type === 'rightToLeft') {
let objData = {
item: data.item,
type: 'rightToLeft',
style: {
animationDuration: `${data.time}s`,
top: `${Math.ceil(Math.random() * (this.maxTop - this.minTop + 1) + this.minTop)}px`
},
delTime: Date.parse(new Date()) + data.time * 1200
};
for (let i in this.listData) {
if (this.listData[i].delTime <= Date.parse(new Date())) {
this.repaint(i, objData.type);
objData.type = '';
this.$set(this.listData, i, objData);
return;
}
}
this.listData.push(objData);
}
},
async remove(options = {}) {
options = Object.assign(
{},
{
duration: 5000, // 延迟关闭的时间
speed: 1000 // 弹幕消失的速度
},
options
);
const _fnHandleRemove = item => {
return new Promise(resolve => {
setTimeout(() => {
item['type'] = 'leftBottomExitLeft';
// this.$forceUpdate();
resolve();
}, options.speed);
});
};
const _fnHandleLoop = item => {
return new Promise(resolve => {
setTimeout(async () => {
for (var i = 0; i < this.listData.length; i++) {
await _fnHandleRemove(this.listData[i]);
}
resolve();
}, options.duration);
});
};
await _fnHandleLoop();
setTimeout(() => {
this.listData = [];
}, 100);
},
repaint(index, type) {
setTimeout(() => {
this.listData[index].type = type;
}, 100);
}
}
};
</script>
<style lang="scss" scoped>
@keyframes leftBottomEnter {
0% {
transform: translateY(100%);
opacity: 0;
}
100% {
transform: translateY(0%);
opacity: 1;
}
}
@keyframes leftBottomExit {
0% {
transform: translateY(0%);
opacity: 1;
}
100% {
transform: translateY(-200%);
opacity: 0;
}
}
@keyframes leftBottomExitLeft {
0% {
transform: translateX(0%);
opacity: 1;
}
100% {
transform: translateX(-200%);
opacity: 0;
}
}
@keyframes leftToRight {
0% {
transform: translateX(-100%);
}
100% {
transform: translateX(100%);
}
}
@keyframes rightToLeft {
0% {
transform: translateX(100%);
}
100% {
transform: translateX(-100%);
}
}
.barrage-wrap {
position: fixed;
width: 100%;
height: 100%;
pointer-events: none;
top: 0;
z-index: 99;
transition: all 1s ease-in-out;
&.leftBottom {
top: initial;
bottom: 130rpx;
}
}
.danmu-li {
position: absolute;
width: 100%;
transform: translateX(100%);
animation-timing-function: linear;
transition: transform 0.5s ease-in-out;
&.is-hide {
transform: translateX(-100%) !important;
}
&.leftBottom {
left: 24rpx;
}
&.leftBottomEnter {
animation-name: leftBottomEnter;
}
&.leftBottomExit {
animation-name: leftBottomExit;
animation-fill-mode: forwards;
}
&.leftBottomExitLeft {
animation-name: leftBottomExitLeft;
animation-fill-mode: forwards;
}
&.rightToLeft {
animation-name: rightToLeft;
}
&.leftToRight {
animation-name: rightToLeft;
}
.danmu-inner {
display: inline-block;
font-size: 24rpx;
.user-box {
display: flex;
padding: 6rpx 40rpx 6rpx 10rpx;
background: rgba(0, 0, 0, 0.3);
border-radius: 32rpx;
align-items: center;
.user-img {
display: flex;
align-items: center;
justify-content: center;
.avatar {
width: 42rpx;
height: 42rpx;
background: rgba(55, 55, 55, 1);
border-radius: 50%;
}
}
.user-status {
margin-left: 10rpx;
white-space: nowrap;
font-weight: 400;
color: rgba(255, 255, 255, 1);
max-width: 320rpx;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.user-text {
max-width: 100rpx;
margin-left: 10rpx;
font-weight: 400;
color: rgba(255, 255, 255, 1);
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
}
}
}
</style>