☰
从零开发微信小程序视频组件:Video 弹幕功能实战
2026/10/27 10:29:35 网站建设 项目流程

一、项目概览

这是一个名为「video组件」的微信小程序,核心功能是播放一段视频,并允许用户输入文字发送弹幕。项目结构如下:

text

├── app.js / app.json / app.wxss ├── project.config.json / project.private.config.json ├── sitemap.json ├── components/ │ └── navigation-bar/ # 自定义导航栏组件 └── pages/ └── index/ # 首页(视频 + 弹幕)

基础库版本为3.17.5,渲染器为webview,组件框架为glass-easel。

二、全局配置

app.json

json

{ "pages": ["pages/index/index"], "window": { "navigationBarTextStyle": "black", "navigationStyle": "custom" }, "style": "v2", "renderer": "webview", "componentFramework": "glass-easel", "sitemapLocation": "sitemap.json", "lazyCodeLoading": "requiredComponents" }

关键点:

  • navigationStyle: "custom":隐藏系统默认导航栏,这样才能使用自定义导航栏组件(注意处理安全区域适配)。

  • lazyCodeLoading: "requiredComponents":按需注入组件,减小包体积、提升启动速度。

  • componentFramework: "glass-easel":使用新版组件框架。

app.wxss

定义了两个通用样式类:.box(带橙色边框的容器)和.title(红色加粗居中标题),供页面复用。

三、自定义导航栏组件

由于全局关闭了系统导航栏,项目实现了一个navigation-bar组件,位于components/navigation-bar/。

组件定义(navigation-bar.js)

组件的核心设计:

  1. Properties 配置灵活:支持title、background、color、back、loading、homeButton、show、delta等属性,基本覆盖常见导航栏需求。

  2. 多 Slot 支持:通过multipleSlots: true启用多插槽,左侧、中间、右侧都可自定义内容。

  3. 状态栏安全区适配:这是自定义导航栏最关键的部分。

js

lifetimes: { attached() { const rect = wx.getMenuButtonBoundingClientRect() const platform = (wx.getDeviceInfo() || wx.getSystemInfoSync()).platform const isAndroid = platform === 'android' const isDevtools = platform === 'devtools' const { windowWidth, safeArea: { top = 0, bottom = 0 } = {} } = wx.getWindowInfo() || wx.getSystemInfoSync() this.setData({ ios: !isAndroid, innerPaddingRight: `padding-right: ${windowWidth - rect.left}px`, leftWidth: `width: ${windowWidth - rect.left}px`, safeAreaTop: isDevtools || isAndroid ? `height: calc(var(--height) + ${top}px); padding-top: ${top}px` : '' }) } }

这里做了几件重要的事:

  • 通过wx.getMenuButtonBoundingClientRect()获取胶囊按钮位置,保证导航栏内容与胶囊对齐;

  • 计算右侧留白padding-right,避免标题/内容被胶囊遮挡;

  • 计算左侧宽度,使左侧返回按钮区域与胶囊对称;

  • 针对 Android / 开发者工具额外处理safeArea.top,保证状态栏区域不被遮挡。

💡 注意:wx.getDeviceInfo()和wx.getWindowInfo()是新 API,代码里用|| wx.getSystemInfoSync()做了兼容降级,这是很实用的写法。

返回逻辑

js

back() { const data = this.data if (data.delta) { wx.navigateBack({ delta: data.delta }) } this.triggerEvent('back', { delta: data.delta }, {}) }

既执行了返回,又触发了back事件,方便父组件监听并做额外处理。

显示/隐藏动画

js

_showChange(show) { const animated = this.data.animated let displayStyle = '' if (animated) { displayStyle = `opacity: ${show ? '1' : '0'};transition:opacity 0.5s;` } else { displayStyle = `display: ${show ? '' : 'none'}` } this.setData({ displayStyle }) }

通过observer监听show属性变化,动态生成透明度过渡或display样式,实现平滑的显示/隐藏效果。

样式(navigation-bar.wxss)

样式部分使用了 CSS 变量控制高度:

css

.weui-navigation-bar { --height: 44px; --left: 16px; } .weui-navigation-bar .android { --height: 48px; }
  • iOS 导航栏高度 44px,Android 48px;

  • 使用env(safe-area-inset-top)适配刘海屏安全区;

  • 返回箭头、loading 图标都使用内联 SVG 作为mask/background,无需额外图片资源,非常轻量。

组件配置

json

{ "component": true, "styleIsolation": "apply-shared", "usingComponents": {} }

styleIsolation: "apply-shared"让组件可以使用外部(app.wxss)定义的样式,便于统一主题。

四、页面实现:视频 + 弹幕

页面结构(index.wxml)

xml

<navigation-bar title="video组件" back="{{false}}" color="black" background="#FFF"></navigation-bar> <scroll-view class="scrollarea" scroll-y type="list"> <view class="box"> <view class="title">华为开发者大会-2026</view> <view class="video-layout"> <video id="my-video" src="{{vieoPath}}" controls="true" danmu-list="{{danmuList}}" enable-danmu="true" danmu-btn="true" /> </view> <view> <view class="txt-style">弹幕内容</view> <input type="text" placeholder="在此处输入弹幕内容" bind:blur="inputBlur" /> <button type="primary" bind:tap="sendDanmu">发送弹幕</button> </view> </view> </scroll-view>

要点说明:

  • back="{{false}}":首页不需要返回按钮;

  • <video>组件通过danmu-list预置弹幕、enable-danmu开启弹幕、danmu-btn显示内置弹幕按钮;

  • 使用scroll-view包裹内容,页面整体采用flex布局让滚动区域占满剩余空间。

⚠️ 代码注释里也提到:danmu-btn在较高基础库版本中可能不再起作用(由enable-danmu控制),在低版本中才需要显式开启。建议以真机 + 当前基础库版本为准进行验证。

弹幕数据

js

data: { vieoPath: 'https://.../华为开发者大会2026.mp4?sign=...', danmuList: [ { text: '鸿蒙世界,奔腾不息', color: '#ff0000', time: 1 }, { text: 'HarmonyOS 7', color: '#ff00ff', time: 5 }, { text: '华为开发者大会2026', color: '#00ff00', time: 10 }, { text: '携手助力,筑牢金融安全', color: '#00ffff', time: 20 } ] }

每条弹幕包含text、color、time(单位:秒),time表示弹幕出现在视频第几秒。

获取 VideoContext 并发送弹幕

这是整个功能的核心。发送弹幕需要通过VideoContext.sendDanmu()完成,而获取VideoContext有两种方式:

js

onLoad() { const query = wx.createSelectorQuery() query.select('#my-video').context() query.exec((res) => { if (res[0]) { this.videoCtx = res[0].context } }) }

这里使用了SelectorQuery.context()获取节点对应的 context(在webview渲染下可取到 VideoContext)。

发送逻辑:

js

inputBlur(e) { this.inputValue = e.detail.value }, sendDanmu() { this.videoCtx.sendDanmu({ text: this.inputValue, color: getRandomColor() }) }
  • 输入框失焦时记录inputValue;

  • 点击按钮时调用sendDanmu,文字取输入值,颜色随机生成。

随机颜色生成

js

function getRandomColor() { let rgb = [] for (let index = 0; index < 3; index++) { let color = Math.floor(Math.random() * 256).toString(16) color = color.length == 1 ? '0' + color : color rgb.push(color) } return '#' + rgb.join('') }

对每个通道生成 0–255 的随机数并转十六进制,单位数补 0,最终拼接成#RRGGBB。

💡 一个小优化点:如果用bind:input实时同步输入值,会比bind:blur更即时,避免用户输入后直接点按钮(未触发 blur)导致取到旧值。当然实际点击按钮前通常会触发 blur,但显式同步更稳妥。

页面样式

css

page { height: 100vh; display: flex; flex-direction: column; } .scrollarea { flex: 1; overflow-y: hidden; }

page撑满视口并纵向 flex 布局,导航栏固定高度,滚动区域flex: 1占满剩余空间,保证页面不出现整体滚动。

五、开发配置

project.config.json 要点

json

{ "setting": { "es6": true, "postcss": true, "minified": true, "enhance": true, "minifyWXML": true, "minifyWXSS": true, "uploadWithSourceMap": true }, "compileType": "miniprogram", "appid": "wx1b90c2c80eb4d7c0" }

开启了 ES6 转 ES5、PostCSS、代码压缩、增强编译等常用选项,适合生产环境。

project.private.config.json

私有配置中指定了libVersion: "3.17.5",并开启了compileHotReLoad(热重载)、urlCheck等开发期选项。注意这个文件通常不纳入版本管理或按团队约定处理。

ESLint 配置

.eslintrc.js中声明了小程序特有的全局变量:

js

globals: { wx: true, App: true, Page: true, getCurrentPages: true, getApp: true, Component: true, requirePlugin: true, requireMiniProgram: true }

否则 ESLint 会报wx is not defined之类的错误。

六、踩坑与优化建议

  1. danmu-btn的版本差异:正如注释所说,高版本基础库中danmu-btn可能失效,建议通过enable-danmu控制,并在真机上验证不同基础库版本的表现。

  2. VideoContext 获取方式:SelectorQuery.context()在webview渲染下可用;若切换 Skyline 渲染,需确认 API 兼容性。也可以用wx.createVideoContext('my-video', this)作为替代方案(更简单,推荐)。

  3. 自定义导航栏的安全区:务必在真机(尤其刘海屏 iPhone 和 Android 挖孔屏)上验证,getMenuButtonBoundingClientRect的返回值与胶囊对齐是核心。

  4. 输入值同步:建议用bind:input实时保存输入内容,避免依赖 blur 时机。

  5. 视频地址带签名:示例中的云存储 URL 带sign和t参数,会过期,正式项目应使用长期有效的地址或动态获取。

  6. 弹幕颜色可读性:随机颜色可能生成接近白色/浅色的颜色,在浅色视频画面上看不清,可考虑限制亮度范围。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询