第一次在uniapp里处理富文本内容时,我遇到了个让人头疼的问题:从后台获取的富文本里明明有视频,但页面上死活显示不出来。折腾了半天才发现,uniapp内置的rich-text组件根本不支持video标签渲染。这就像你买了台号称能播放所有格式的视频播放器,结果发现它连最常见的MP4都不支持一样让人崩溃。
经过反复测试,我发现rich-text组件确实存在几个明显的局限性:
这种限制在实际开发中会造成很多麻烦。比如新闻类APP需要展示带视频的新闻详情页,或者教育类APP要显示课程内容中的教学视频,都会遇到视频无法渲染的问题。更糟的是,控制台不会报错,开发者只能看到一片空白区域,排查起来特别费劲。
在插件市场搜了一圈后,我最终选择了uParse这个富文本解析插件。选择它的原因很实在:
安装步骤其实很简单:
安装完成后,你的项目components目录下会出现u-parse文件夹。这里有个小技巧:建议把插件文件放在统一的组件目录下,比如我习惯放在/components/common/u-parse/,这样项目结构更清晰。
在页面中使用uParse只需要三步:
javascript复制// 1. 导入组件
import uParse from '@/components/u-parse/u-parse.vue'
export default {
// 2. 注册组件
components: { uParse },
data() {
return {
// 3. 绑定富文本数据
content: '<p>这里是富文本内容<video src="example.mp4"></video></p>'
}
}
}
模板部分更简单,直接把原来的rich-text替换掉:
html复制<!-- 替换前 -->
<rich-text :nodes="content"></rich-text>
<!-- 替换后 -->
<u-parse :content="content" />
不过要注意,uParse默认的视频样式可能不太美观。我遇到过视频宽度溢出容器、没有居中显示等问题,这就需要我们进一步优化样式了。
直接修改富文本字符串听起来有点原始,但确实是最有效的方案。下面这个工具函数是我经过多次调试后总结出来的:
javascript复制// richTextUtil.js
function formatRichText(html) {
if (!html) return ''
// 1. 统一处理img和video标签的基础属性
let content = html.replace(/<(img|video)[^>]*>/gi, (tag) => {
// 移除原有样式、宽度和高度属性
return tag
.replace(/(style|width|height)="[^"]*"/g, '')
.replace(/(style|width|height)='[^']*'/g, '')
})
// 2. 处理内联样式
content = content.replace(/style="[^"]*"/gi, (styleAttr) => {
return styleAttr
.replace(/(width|height):[^;]*;/g, '')
.replace(/;/g, '') + 'max-width:100%;'
})
// 3. 添加响应式样式
content = content.replace(/<(img|video)/gi, '<$1 style="max-width:100%;height:auto;display:block;margin:10px auto;"')
// 4. 处理换行符(可选)
content = content.replace(/<br[^>]*\/?>/gi, '')
return content
}
这个方案有四个关键点:
在真实项目中使用时,通常是这样的流程:
javascript复制import { formatRichText } from '@/utils/richTextUtil'
export default {
async onLoad() {
const res = await uni.request({
url: 'https://api.example.com/article/123'
})
this.content = formatRichText(res.data.content)
}
}
我遇到过几个常见问题及解决方案:
::-webkit-media-controls-play-button { margin-left: 50% }样式x5-playsinline属性(针对微信浏览器)当页面有多个视频时,全部加载会影响性能。这是我改进后的懒加载方案:
javascript复制function lazyLoadVideos(html) {
// 1. 替换video标签为占位图
let content = html.replace(/<video[^>]*poster="([^"]*)"[^>]*>/gi,
(match, poster) => {
return `<img src="${poster}" class="video-placeholder"
onclick="playVideo(this)" data-src="${match.match(/src="([^"]*)"/)[1]}">`
})
// 2. 添加播放逻辑
content += `
<script>
function playVideo(el) {
const video = document.createElement('video')
video.src = el.dataset.src
video.controls = true
video.style = "width:100%;height:auto;"
el.parentNode.replaceChild(video, el)
video.play()
}
</script>
`
return content
}
这个方案的核心优势是:
对于频繁访问的富文本内容,可以结合uniapp的storage做缓存:
javascript复制const CACHE_KEY = 'rich_text_cache'
async function getRichText(id) {
// 1. 尝试从缓存获取
const cache = uni.getStorageSync(CACHE_KEY) || {}
if (cache[id] && cache[id].expire > Date.now()) {
return cache[id].data
}
// 2. 请求网络数据
const res = await uni.request({ url: `/article/${id}` })
const processed = formatRichText(res.data)
// 3. 更新缓存
cache[id] = {
data: processed,
expire: Date.now() + 3600000 // 1小时缓存
}
uni.setStorageSync(CACHE_KEY, cache)
return processed
}
缓存策略可以根据实际需求调整:
uniapp的最大优势是一次开发多端运行,但各平台对video标签的实现差异很大。这是我总结的兼容性处理方案:
微信小程序需要额外注意:
javascript复制function handleWechatVideo(html) {
// 1. 添加微信专用属性
return html.replace(/<video/gi,
'<video x5-video-player-type="h5" x5-video-player-fullscreen="true"')
}
在H5环境下可以增强视频功能:
javascript复制function enhanceH5Video(html) {
// 1. 添加playsinline属性防止iOS全屏
// 2. 添加controlsList属性优化控制栏
return html.replace(/<video/gi,
'<video playsinline controlsList="nodownload"')
}
APP端可以调用原生能力:
javascript复制function handleAppVideo(html) {
// 1. 替换为原生video组件
if (uni.getSystemInfoSync().platform === 'ios') {
return html.replace(/<video/gi, '<video webkit-playsinline')
}
return html
}
实际项目中,我会根据编译环境动态选择处理方案:
javascript复制const processors = {
'mp-weixin': handleWechatVideo,
'h5': enhanceH5Video,
'app': handleAppVideo
}
function platformSpecificProcess(html) {
const current = process.env.VUE_APP_PLATFORM
return processors[current] ? processors[current](html) : html
}
这些经验都是我在实际项目中踩坑后总结出来的。比如微信小程序的x5内核视频播放器表现就很特别,iOS的自动全屏问题也让人头疼。关键是要多测试不同平台,及时发现并解决问题。