代码
<template>
<div class="ciallo" @click="addClickEffect">
<!-- 弹幕输入框 -->
<div class="message-container" >
<h1 class="message-title">轻井泽惠</h1>
<div class="message-input">
<input class="input" v-model="messageContent" @click="showSendButton = true" @keyup.enter="send" placeholder="说点什么吧🖋️" />
<button class="send" @click="send" v-show="showSendButton">🏹</button>
</div>
</div>
<!-- 弹幕列表 -->
<div :class="isMobile ? 'danmaku-container-move' : 'danmaku-container'" @click="playSound">
<vue-danmaku ref="danmaku" class="danmaku" use-slot v-model:danmus="messageList"
:is-suspend="true" :loop="true" :interval="1000" :random="true" :randomChannel="true" :speeds="isMobile ? 70 : 200">
<template v-slot:dm="{ danmu }">
<span class="danmaku-item" :style="{ top: danmu.top + 'px', left: danmu.left + 'px', animationDuration: danmu.animationDuration + 's' }">
<img :src="danmu.avatar" width="30" height="30" style="border-radius: 50%" alt="用户头像"/>
<span class="ml">{{ danmu.nickname }} :</span>
<span class="ml">{{ danmu.messageContent }}</span>
</span>
</template>
</vue-danmaku>
</div>
</div>
</template>
<script setup lang="ts">
import { addMessage, getMessageList } from "@/api/message";
import { Message } from "@/api/message/types";
import useStore from "@/store";
import vueDanmaku from "vue3-danmaku";
import { ref } from 'vue';
/*鼠标点击效果“Ciallo~(∠・ω< )⌒★”*/
function addClickEffect() {
function getRandomColor(): string {
const letters = '0123456789ABCDEF';
let color = '#';
for (let i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
function createFloatingText(text: string, x: number, y: number): void {
const span = document.createElement('span');
span.innerText = text;
span.style.position = 'fixed';
span.style.left = `${x + 10}px`; // 加上偏移量调整位置
span.style.top = `${y}px`; // 初始位置设置为点击位置
span.style.color = getRandomColor();
span.style.zIndex = '9999';
span.style.pointerEvents = 'none';
span.style.fontWeight = 'bold'; // 加粗字体样式
const cialloDiv = document.querySelector('.ciallo');
if (cialloDiv) {
cialloDiv.appendChild(span);
// 添加向上飘的动画效果
setTimeout(() => {
let distance = 0;
const intervalId = setInterval(() => {
distance += 1; // 控制向上移动的速度
span.style.top = `${y - distance}px`;
if (distance >= 80) { // 控制向上移动的距离
clearInterval(intervalId);
cialloDiv.removeChild(span);
}
}, 20); // 控制向上移动的频率
}, 20);
}
}
if (document.body) {
document.addEventListener('click', (event) => {
createFloatingText('Ciallo~(∠・ω< )⌒★', event.clientX, event.clientY);
});
}
}
// 播放声音
const playSound = () => {
const audio = new Audio('https://blogfile.houxiongxiong.icu/music/ciallo.aac');
// const audio = new Audio('https://blogfile.houxiongxiong.icu/music/ciallo.mp3');
audio.play();
};
// 判断是否为移动端
const isMobile = computed(() => {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
});
const showSendButton = ref(false);
const handleOutsideClick = (event: MouseEvent) => {
showSendButton.value = !!((event.target as HTMLElement).closest('.message-input') || (event.target as HTMLElement).closest('.send'));
};
onMounted(() => {
document.addEventListener('click', handleOutsideClick);
});
const { blog, user } = useStore();
const messageContent = ref("");
const show = ref(false);
const danmaku = ref();
const messageList = ref<Message[]>([]);
onMounted(async () => {
await getMessageList().then(({ data }) => {
messageList.value = data.data;
});
});
const send = () => {
if (messageContent.value.trim() == "") {
window.$message?.warning("留言内容不能为空");
return false;
}
const userAvatar = user.avatar ? user.avatar : blog.blogInfo.siteConfig.touristAvatar;
const userNickname = user.nickname ? user.nickname : "游客";
let message = {
avatar: userAvatar,
nickname: userNickname,
messageContent: messageContent.value,
};
addMessage(message).then(({ data }) => {
if (data.flag) {
if (blog.blogInfo.siteConfig.messageCheck) {
window.$message?.warning("留言成功,正在审核中");
} else {
danmaku.value.push(message);
window.$message?.success("留言成功");
}
messageContent.value = "";
}
});
};
</script>
栈库
这里使用了vue3+vue3-danmuku+ts进行实现
预览
服务器2+2,现在跑不起来了,只能给图片,不能在线体验,见谅。
评论区