Vue 弹幕功能使用方法及组件封装详细指南

代码教程

Vue实现弹幕功能的使用方法与组件封装指南

一、弹幕组件使用方法

(一)基础使用

  1. 引入组件
<template>
  <div class="container">
    <!-- 弹幕容器 -->
    <Danmaku :messages="danmakuList">
      <!-- 背景内容,如视频 -->
      <video src="your-video-url.mp4" controls></video>
    </Danmaku>
    
    <!-- 弹幕发送器 -->
    <DanmakuSender @send="handleSendDanmaku" />
  </div>
</template>

<script setup>
import Danmaku from '@/components/Danmaku.vue';
import DanmakuSender from '@/components/DanmakuSender.vue';
import { ref } from 'vue';

const danmakuList = ref([]);

const handleSendDanmaku = (message) => {
  // 添加弹幕到列表
  danmakuList.value.push({
    ...message,
    timestamp: Date.now()
  });
};
</script>
  1. 弹幕数据格式
interface DanmakuMessage {
  text: string;         // 弹幕文本
  color?: string;       // 弹幕颜色,默认白色
  fontSize?: number;    // 字体大小,默认18px
  speed?: number;       // 弹幕速度,默认10
  opacity?: number;     // 不透明度,默认1
  timestamp?: number;   // 时间戳
}

(二)高级用法

  1. 控制弹幕显示/隐藏
<Danmaku 
  :messages="danmakuList" 
  :paused="isDanmakuPaused"
/>

<button @click="toggleDanmaku">
  {{ isDanmakuPaused ? '显示弹幕' : '隐藏弹幕' }}
</button>

<script setup>
const isDanmakuPaused = ref(false);

const toggleDanmaku = () => {
  isDanmakuPaused.value = !isDanmakuPaused.value;
};
</script>
  1. 自定义弹幕样式
<DanmakuSender
  @send="handleSendDanmaku"
  :font-size="danmakuSize"
  :speed="danmakuSpeed"
/>

<div class="controls">
  <label>弹幕大小: {{ danmakuSize }}px</label>
  <input type="range" v-model.number="danmakuSize" min="12" max="36">
  
  <label>弹幕速度: {{ danmakuSpeed }}</label>
  <input type="range" v-model.number="danmakuSpeed" min="5" max="20">
</div>
  1. 响应弹幕事件
<Danmaku 
  :messages="danmakuList" 
  @send="handleSendDanmaku"
  @click="handleDanmakuClick"
/>

<script setup>
const handleDanmakuClick = (danmaku) => {
  console.log('点击了弹幕:', danmaku);
  // 可以实现点击弹幕高亮、回复等功能
};
</script>

二、组件封装方法

(一)基础组件封装

  1. 弹幕容器组件 (Danmaku.vue)
<template>
  <div class="danmaku-container" ref="container">
    <slot /> <!-- 背景内容 -->
    <div class="danmaku-area" ref="danmakuArea"></div>
  </div>
</template>

<script setup>
import { ref, onMounted, onBeforeUnmount, watch } from 'vue';

const props = defineProps({
  messages: {
    type: Array,
    default: () => []
  },
  trackCount: {
    type: Number,
    default: 10
  },
  paused: {
    type: Boolean,
    default: false
  }
});

const emits = defineEmits(['send']);

// 组件实现代码...
</script>
  1. 弹幕发送器组件 (DanmakuSender.vue)
<template>
  <div class="danmaku-sender">
    <div class="input-area">
      <input 
        v-model="message" 
        placeholder="发送弹幕..." 
        @keyup.enter="sendDanmaku"
      />
      <button @click="sendDanmaku">发送</button>
    </div>
    
    <div class="options">
      <div class="color-options">
        <label>颜色:</label>
        <input type="radio" id="white" value="white" v-model="color">
        <label for="white">白色</label>
        <input type="radio" id="red" value="red" v-model="color">
        <label for="red">红色</label>
        <input type="radio" id="yellow" value="yellow" v-model="color">
        <label for="yellow">黄色</label>
      </div>
      
      <div class="controls">
        <button @click="toggleDanmaku">
          {{ isDanmakuVisible ? '隐藏弹幕' : '显示弹幕' }}
        </button>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const props = defineProps({
  placeholder: {
    type: String,
    default: '发送弹幕...'
  }
});

const emits = defineEmits(['send', 'toggleVisibility']);

// 组件实现代码...
</script>

(二)高阶组件封装

  1. 视频弹幕组件 (VideoDanmaku.vue)
<template>
  <div class="video-danmaku">
    <div class="video-container">
      <video ref="videoRef" :src="videoSrc" controls></video>
      <Danmaku 
        :messages="danmakuList" 
        :paused="!isPlaying"
      />
    </div>
    
    <DanmakuSender @send="handleSendDanmaku" />
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import Danmaku from './Danmaku.vue';
import DanmakuSender from './DanmakuSender.vue';

const props = defineProps({
  videoSrc: {
    type: String,
    required: true
  }
});

// 组件实现代码...
</script>
  1. 直播弹幕组件 (LiveDanmaku.vue)
<template>
  <div class="live-danmaku">
    <div class="live-player">
      <!-- 直播播放器 -->
      <LivePlayer :stream-url="streamUrl" />
      
      <!-- 弹幕层 -->
      <Danmaku 
        :messages="danmakuList" 
        :paused="!isLivePlaying"
      />
    </div>
    
    <!-- 弹幕发送器 -->
    <DanmakuSender @send="handleSendDanmaku" />
    
    <!-- 观众列表 -->
    <div class="viewers">
      <h3>在线观众 ({{ viewerCount }})</h3>
      <ul>
        <li v-for="viewer in viewers" :key="viewer.id">{{ viewer.name }}</li>
      </ul>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import Danmaku from './Danmaku.vue';
import DanmakuSender from './DanmakuSender.vue';
import LivePlayer from './LivePlayer.vue';

const props = defineProps({
  streamUrl: {
    type: String,
    required: true
  }
});

// 组件实现代码...
</script>

(三)全局插件封装

// plugins/danmaku.ts
import { App } from 'vue';
import Danmaku from '@/components/Danmaku.vue';
import DanmakuSender from '@/components/DanmakuSender.vue';

export const DanmakuPlugin = {
  install(app: App) {
    // 注册组件
    app.component('Danmaku', Danmaku);
    app.component('DanmakuSender', DanmakuSender);
    
    // 添加全局方法
    app.config.globalProperties.$danmaku = {
      // 全局发送弹幕方法
      send(text: string, options = {}) {
        // 这里可以实现全局发送弹幕的逻辑
        console.log('全局发送弹幕:', text, options);
      }
    };
  }
};

在main.ts中使用插件:

import { createApp } from 'vue';
import App from './App.vue';
import { DanmakuPlugin } from './plugins/danmaku';

const app = createApp(App);

// 使用弹幕插件
app.use(DanmakuPlugin);

app.mount('#app');

三、性能优化与扩展

(一)性能优化

  1. 对象池技术
// 在Danmaku组件中实现对象池
const danmakuPool = ref([]);

const createDanmakuElement = () => {
  if (danmakuPool.value.length > 0) {
    return danmakuPool.value.pop();
  }
  
  const element = document.createElement('div');
  element.className = 'danmaku-item';
  return element;
};

const releaseDanmakuElement = (element) => {
  // 重置元素属性
  element.style.cssText = '';
  element.textContent = '';
  
  // 放入对象池
  danmakuPool.value.push(element);
};
  1. requestAnimationFrame优化
// 使用requestAnimationFrame更新弹幕位置
const updateDanmakuPositions = () => {
  if (isPaused.value) return;
  
  activeDanmakus.value.forEach(danmaku => {
    // 更新弹幕位置
    const progress = (Date.now() - danmaku.startTime) / danmaku.duration;
    if (progress < 1) {
      const x = containerWidth.value - progress * (containerWidth.value + danmaku.width);
      danmaku.element.style.transform = `translateX(${x}px)`;
    } else {
      // 弹幕播放完毕
      removeDanmaku(danmaku);
    }
  });
  
  requestAnimationFrame(updateDanmakuPositions);
};

// 启动动画循环
onMounted(() => {
  updateDanmakuPositions();
});

(二)功能扩展

  1. 弹幕类型扩展
// 支持顶部固定弹幕
enum DanmakuType {
  Scroll = 'scroll',  // 滚动弹幕
  Top = 'top',        // 顶部固定弹幕
  Bottom = 'bottom'   // 底部固定弹幕
}

// 在Danmaku组件中处理不同类型弹幕
const createDanmaku = (message) => {
  const type = message.type || DanmakuType.Scroll;
  
  if (type === DanmakuType.Scroll) {
    // 创建滚动弹幕
    createScrollDanmaku(message);
  } else if (type === DanmakuType.Top) {
    // 创建顶部固定弹幕
    createFixedDanmaku(message, 'top');
  } else if (type === DanmakuType.Bottom) {
    // 创建底部固定弹幕
    createFixedDanmaku(message, 'bottom');
  }
};
  1. 弹幕过滤与屏蔽
// 在Danmaku组件中添加过滤功能
const isDanmakuAllowed = (message) => {
  // 检查是否包含敏感词
  if (containsSensitiveWords(message.text)) {
    return false;
  }
  
  // 检查是否被用户屏蔽
  if (isUserBlocked(message.userId)) {
    return false;
  }
  
  // 其他过滤条件...
  
  return true;
};

// 在添加弹幕前进行过滤
const addDanmaku = (message) => {
  if (!isDanmakuAllowed(message)) return;
  
  // 正常添加弹幕逻辑
};

四、完整示例

下面是一个完整的弹幕应用示例:

<template>
  <div class="app-container">
    <header class="bg-primary text-white p-4">
      <h1 class="text-2xl font-bold">弹幕演示应用</h1>
    </header>
    
    <main class="container mx-auto p-6">
      <div class="flex flex-col lg:flex-row gap-6">
        <!-- 视频区域 -->
        <div class="lg:w-2/3">
          <div class="bg-black rounded-lg overflow-hidden aspect-video relative">
            <video 
              ref="videoRef" 
              class="w-full h-full object-cover" 
              controls 
              poster="https://picsum.photos/1200/675?random=3"
            >
              <source src="https://example.com/sample-video.mp4" type="video/mp4">
              您的浏览器不支持视频播放
            </source>
            </video>
            
            <!-- 弹幕层 -->
            <Danmaku 
              ref="danmakuRef" 
              :messages="danmakuList" 
              :paused="!isPlaying"
            />
          </div>
          
          <!-- 弹幕发送器 -->
          <DanmakuSender 
            @send="handleSendDanmaku"
            :danmaku-count="danmakuList.length"
          />
        </div>
        
        <!-- 弹幕列表 -->
        <div class="lg:w-1/3">
          <div class="bg-white rounded-lg shadow-md p-4 h-full">
            <h2 class="text-xl font-bold mb-4">弹幕列表</h2>
            
            <div class="mb-4">
              <div class="flex justify-between items-center mb-2">
                <h3 class="font-medium">弹幕设置</h3>
              </div>
              
              <div class="space-y-3">
                <div>
                  <label class="block text-sm font-medium text-gray-700 mb-1">字体大小</label>
                  <input 
                    type="range" 
                    min="12" 
                    max="36" 
                    v-model.number="fontSize" 
                    class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary"
                  >
                  <div class="flex justify-between text-xs text-gray-500 mt-1">
                    <span></span>
                    <span>{{ fontSize }}px</span>
                    <span></span>
                  </div>
                </div>
                
                <div>
                  <label class="block text-sm font-medium text-gray-700 mb-1">弹幕速度</label>
                  <input 
                    type="range" 
                    min="5" 
                    max="20" 
                    v-model.number="speed" 
                    class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-primary"
                  >
                  <div class="flex justify-between text-xs text-gray-500 mt-1">
                    <span></span>
                    <span>{{ speed }}</span>
                    <span></span>
                  </div>
                </div>
                
                <div class="flex items-center">
                  <input type="checkbox" id="show-danmaku" v-model="showDanmaku" class="h-4 w-4 text-primary focus:ring-primary border-gray-300 rounded">
                  <label for="show-danmaku" class="ml-2 text-sm text-gray-700">显示弹幕</label>
                </div>
              </div>
            </div>
            
            <div class="border-t border-gray-100 pt-4">
              <div class="flex justify-between items-center mb-2">
                <h3 class="font-medium">最近弹幕</h3>
                <span class="text-sm text-gray-500">{{ danmakuList.length }}</span>
              </div>
              
              <div class="space-y-2 max-h-[400px] overflow-y-auto">
                <div 
                  v-for="(danmaku, index) in danmakuList.slice(-20).reverse()" 
                  :key="index" 
                  class="p-2 rounded bg-gray-50"
                >
                  <div class="flex justify-between">
                    <span :style="{ color: danmaku.color || '#FFFFFF' }">{{ danmaku.text }}</span>
                    <span class="text-xs text-gray-400">{{ formatTime(danmaku.timestamp) }}</span>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </main>
    
    <footer class="bg-gray-800 text-white p-6 mt-12">
      <div class="container mx-auto">
        <div class="text-center">
          <p>© 2025 弹幕演示应用</p>
        </div>
      </div>
    </footer>
  </div>
</template>

<script setup>
import { ref, onMounted, computed } from 'vue';
import Danmaku from '@/components/Danmaku.vue';
import DanmakuSender from '@/components/DanmakuSender.vue';

const videoRef = ref(null);
const danmakuRef = ref(null);
const danmakuList = ref([]);
const isPlaying = ref(false);
const fontSize = ref(18);
const speed = ref(10);
const showDanmaku = ref(true);

onMounted(() => {
  if (videoRef.value) {
    videoRef.value.addEventListener('play', () => {
      isPlaying.value = true;
    });
    
    videoRef.value.addEventListener('pause', () => {
      isPlaying.value = false;
    });
  }
  
  // 添加示例弹幕
  addSampleDanmakus();
});

const addSampleDanmakus = () => {
  const sampleMessages = [
    { text: '欢迎来到直播间!', color: 'white' },
    { text: '666666', color: 'yellow' },
    { text: '主播好厉害!', color: 'white' },
    { text: '前方高能', color: 'red' },
    { text: '这个场景太赞了', color: 'white' },
    { text: '第一次看这个视频', color: 'white' },
    { text: '打卡打卡', color: 'yellow' },
    { text: '哈哈哈', color: 'white' }
  ];
  
  // 定时添加示例弹幕
  sampleMessages.forEach((message, index) => {
    setTimeout(() => {
      handleSendDanmaku(message);
    }, index * 2000);
  });
};

const handleSendDanmaku = (message) => {
  const newMessage = {
    ...message,
    timestamp: Date.now(),
    fontSize: fontSize.value,
    speed: speed.value
  };
  
  danmakuList.value.push(newMessage);
  
  // 实际项目中可以发送到服务器
  console.log('发送弹幕:', newMessage);
};

const formatTime = (timestamp) => {
  const date = new Date(timestamp);
  return `${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}:${date.getSeconds().toString().padStart(2, '0')}`;
};
</script>

通过以上使用方法和组件封装,您可以在Vue项目中实现一个功能完整、性能优良的弹幕系统,支持视频、直播等多种场景,并且可以根据需求进行灵活扩展和定制。


代码获取方式

【夸克网盘】点击查看


关注我获取更多内容

你可能感兴趣的:(软件安装,vue.js,前端,javascript,Vue,弹幕功能,使用方法,组件封装)