当前位置: 首页 > news >正文

uni-app从后端返回的富文本中的视频截取一帧为封面

如下图,下面的封面图从视频中截取而来

<template><view class="detail"><view class="detail-content" :style="{paddingTop: height + 'px'}"><view class="xwbiaoti">{{XWtitle}}</view><view class="fabutime">{{createTime}}</view><view class="fuwenbjx" ref="htmlContent"><mp-html :content="richContent" show-img-menu="true" /></view><view class='healthPromotion' :videoLists="videoLists" :change:videoLists="renderScript.createPoster"></view><view class="lineView"></view></view></view>
</template>

使用使用renderjs 提取视频截图

<script module="renderScript" lang="renderjs">export default {methods: {extractVideoUrls(htmlContent) {// 假设视频通常在<iframe>或<video>标签中const videoRegex = /<iframe.*?src="([^"]+)".*?>|<video.*?src="([^"]+)".*?>/g;let match;const videoUrls = [];while ((match = videoRegex.exec(htmlContent)) !== null) {if (match[1]) { // <iframe>标签的srcvideoUrls.push(match[1]);} else if (match[2]) { // <video>标签的srcvideoUrls.push(match[2]);}}return videoUrls;},createPoster(val) {const htmlContent ='<video src="https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4"></video><video src="https://www.w3schools.com/html/mov_bbb.mp4"></video>';const videoUrls = this.extractVideoUrls(val); //假设视频通常在<iframe>或<video>标签中  提取视频地址var videoCanList = [],curDateList = []videoUrls.forEach((item, index) => {var promise = new Promise((reslove, reject) => {// 在缓存中创建video标签var video = document.createElement("VIDEO")// 通过setAttribute给video dom元素添加自动播放的属性,因为视频播放才能获取封面图video.currentTime = 5video.setAttribute('crossOrigin', 'anonymous');video.setAttribute('autoplay', 'autoplay')// 再添加一个静音的属性,否则自动播放会有声音video.setAttribute('muted', 'muted')// 上面我们只是创建了video标签,视频播放需要内部的source的标签,scr为播放源video.innerHTML = '<source src=' + item + ' type="audio/mp4">'// 再创建canvas画布标签var canvas = document.createElement('canvas');var ctx = canvas.getContext('2d');// video注册canplay自动播放事件video.addEventListener('canplay', function() {// 创建画布的宽高属性节点,就是图片的大小,单位PXvar anw = document.createAttribute("width");anw.nodeValue = 500;var anh = document.createAttribute("height");anh.nodeValue = 300;canvas.setAttributeNode(anw);canvas.setAttributeNode(anh);// 画布渲染ctx.drawImage(video, 0, 0, 500, 300);// 生成图片var base64 = canvas.toDataURL('image/png') // 这就是封面图片的base64编码// 视频结束播放的事件video.pause()curDateList.unshift({ // 这里是我自己的数据处理模块type: 'video',videoUrl: item.url,img: base64})reslove(base64) // promise函数成功的回调}, false)})videoCanList.push(promise)})Promise.all(videoCanList).then(res => {this.$ownerInstance.callMethod('reciveMessage', res)})},}}
</script>
<script>import url from '@/utils/URL.js'export default {data() {return {content: null,XWtitle: '', //新闻标题createTime: '', //发布时间link: '',xqid: '',height: 0,videoLists: [], // 获取到的视频列表数组posterList: [], // 视频封面图数组richContent: '', //带封面的富文本viedeourlArry: [], //视频地址数组}},components: {},created() {},onLoad(query) {this.xqid = query.paramsthis.getNewsContent();},onShow() {},methods: {getNewsContent() {//新闻列表this.$request({url: url.news.newsinfo + this.xqid,method: 'get',}).then(res => {if (res.code == 0) {this.content = res.busNews.content;// #ifdef MP-WEIXINthis.richContent = res.busNews.content;//#endifthis.XWtitle = res.busNews.title;this.createTime = res.busNews.createTime;this.videoLists = res.busNews.content;}})},//视频封面reciveMessage(val) {let that = thisthis.posterList = val		that.richContent = that.processRichText(this.content)},processRichText(html) {let that = this// 匹配视频标签的正则表达式let videoCount = 0;const videoRegex = /<video[^>]*>/g;return html.replace(videoRegex, (match) => {// 检查是否已经有 poster 属性if (!match.includes('poster=')) {videoCount++;// // 添加封面图,这里可以使用默认封面或根据视频生成var posterUrl = this.posterList[videoCount - 1]; return match.replace('>', ` poster="${posterUrl}">`);}							return match;});},}}
</script>

完整代码如下:

<template><view class="detail"><view class="detail-content" :style="{paddingTop: height + 'px'}"><view class="xwbiaoti">{{XWtitle}}</view><view class="fabutime">{{createTime}}</view>	<view class="fuwenbjx" ref="htmlContent"><mp-html :content="richContent" show-img-menu="true" /></view><view class='healthPromotion' :videoLists="videoLists" :change:videoLists="renderScript.createPoster"></view><view class="lineView"></view></view></view>
</template><script>import url from '@/utils/URL.js'export default {data() {return {content: null,XWtitle: '', //新闻标题createTime: '', //发布时间link: '',xqid: '',height: 0,videoLists: [], // 获取到的视频列表数组posterList: [], // 视频封面图数组richContent: '', //带封面的富文本viedeourlArry: [], //视频地址数组}},components: {},created() {},onLoad(query) {this.xqid = query.paramsthis.getNewsContent();},onShow() {},methods: {getNewsContent() {//新闻列表this.$request({url: url.news.newsinfo + this.xqid,method: 'get',}).then(res => {if (res.code == 0) {this.content = res.busNews.content;// #ifdef MP-WEIXINthis.richContent = res.busNews.content;//#endifthis.XWtitle = res.busNews.title;this.createTime = res.busNews.createTime;this.videoLists = res.busNews.content;}})},//视频封面reciveMessage(val) {let that = thisthis.posterList = val		that.richContent = that.processRichText(this.content)},processRichText(html) {let that = this// 匹配视频标签的正则表达式let videoCount = 0;const videoRegex = /<video[^>]*>/g;return html.replace(videoRegex, (match) => {// 检查是否已经有 poster 属性if (!match.includes('poster=')) {videoCount++;// // 添加封面图,这里可以使用默认封面或根据视频生成var posterUrl = this.posterList[videoCount - 1]; return match.replace('>', ` poster="${posterUrl}">`);}							return match;});},}}
</script><script module="renderScript" lang="renderjs">export default {methods: {extractVideoUrls(htmlContent) {// 假设视频通常在<iframe>或<video>标签中const videoRegex = /<iframe.*?src="([^"]+)".*?>|<video.*?src="([^"]+)".*?>/g;let match;const videoUrls = [];while ((match = videoRegex.exec(htmlContent)) !== null) {if (match[1]) { // <iframe>标签的srcvideoUrls.push(match[1]);} else if (match[2]) { // <video>标签的srcvideoUrls.push(match[2]);}}return videoUrls;},createPoster(val) {const htmlContent ='<video src="https://qiniu-web-assets.dcloud.net.cn/unidoc/zh/2minute-demo.mp4"></video><video src="https://www.w3schools.com/html/mov_bbb.mp4"></video>';const videoUrls = this.extractVideoUrls(val); //假设视频通常在<iframe>或<video>标签中  提取视频地址var videoCanList = [],curDateList = []videoUrls.forEach((item, index) => {var promise = new Promise((reslove, reject) => {// 在缓存中创建video标签var video = document.createElement("VIDEO")// 通过setAttribute给video dom元素添加自动播放的属性,因为视频播放才能获取封面图video.currentTime = 5video.setAttribute('crossOrigin', 'anonymous');video.setAttribute('autoplay', 'autoplay')// 再添加一个静音的属性,否则自动播放会有声音video.setAttribute('muted', 'muted')// 上面我们只是创建了video标签,视频播放需要内部的source的标签,scr为播放源video.innerHTML = '<source src=' + item + ' type="audio/mp4">'// 再创建canvas画布标签var canvas = document.createElement('canvas');var ctx = canvas.getContext('2d');// video注册canplay自动播放事件video.addEventListener('canplay', function() {// 创建画布的宽高属性节点,就是图片的大小,单位PXvar anw = document.createAttribute("width");anw.nodeValue = 500;var anh = document.createAttribute("height");anh.nodeValue = 300;canvas.setAttributeNode(anw);canvas.setAttributeNode(anh);// 画布渲染ctx.drawImage(video, 0, 0, 500, 300);// 生成图片var base64 = canvas.toDataURL('image/png') // 这就是封面图片的base64编码// 视频结束播放的事件video.pause()curDateList.unshift({ // 这里是我自己的数据处理模块type: 'video',videoUrl: item.url,img: base64})reslove(base64) // promise函数成功的回调}, false)})videoCanList.push(promise)})Promise.all(videoCanList).then(res => {this.$ownerInstance.callMethod('reciveMessage', res)})},}}
</script><style>/*/ 富文本*/.fuwenbjx {line-height: 24px;font-size: 29rpx;}.fuwenbjx img {border-radius: 20rpx;margin: 20rpx 0;}
</style>
<style lang="scss" scoped>.detail {padding: 0;padding-bottom: 54px;line-height: 52rpx;background: #fff;.detail-content {display: flex;flex-direction: column;margin-left: 10px;margin-right: 10px;height: 1000px;img {width: 80%;margin: 0 auto;}.article-share {display: none;}.detailText {display: flex;flex-direction: column;margin-top: 20px;margin-bottom: 10px;.textContentTitle {font-size: 14px;color: rgba(85, 85, 85, 1);text-decoration: underline;}.textContent {font-size: 12px;color: rgba(85, 85, 85, 1);text-decoration: underline;}}}}.xwbiaoti {font-weight: bold;color: #000;font-size: 32rpx;}.fabutime {color: #999;font-size: 28rpx;text-align: left;margin-bottom: 10px;}
</style>

参考文章:https://blog.csdn.net/yuanqi3131/article/details/128199069

http://www.dtcms.com/a/507167.html

相关文章:

  • 若依前后端分离版学习笔记(二十)——实现滑块验证码(vue3)
  • Linux 服务器安全巡检与加固:从命令到实操(CentOS/Ubuntu 通用)
  • 网站如何让百度收录官网seo是什么意思
  • STM32U5G9J-DK2开发板获取RAM占用
  • 从架构到运营:AIOps与O-AA™ 如何实现智能化企业运营
  • 徐州手机网站定制公司哪家好西安大型网站制作
  • 【Day 80】Linux-NAS 和 SAN 存储
  • C++可变参数模板
  • Python下载实战技巧的技术文章大纲
  • PostgreSQL高级特性解析:窗口函数与CTE
  • OpenBMC: BmcWeb处理WebScoket2 产生WebSocket对象
  • 构建AI智能体:六十九、Bootstrap采样在大模型评估中的应用:从置信区间到模型稳定性
  • 图论基础:探索节点与关系的复杂网络
  • 免费建网站 建站之星百度指数免费添加
  • python如何写数据到excel示例
  • Spring Cloud - Spring Cloud 注册中心与服务提供者(Spring Cloud Eureka 概述、微服务快速入门、微服务应用实例)
  • 测试经验分享,登录功能+购物车+限时秒杀(测试点)汇总
  • 腾讯云TVP走进美的,共探智能制造新范式
  • OpenAI 的 Sora 2来了:一场创意革命与失控的狂欢
  • 直播预告 | 时序数据赋能核电数字化转型,TDengine 引领创新新范式
  • 动漫网站建设规划书模板广州网站建设策划
  • 使用imapsync增量同步邮件到新邮局服务器
  • iOS 混淆与 IPA 加固全流程,多工具组合实现无源码混淆、源码防护与可审计流水线(iOS 混淆|IPA 加固|无源码加固|App 防反编译)
  • java数据结构--ArrayList与顺序表
  • 【IEEE/EI/Scopus检索】2026年IEEE第七届计算,网络与物联网国际会议(CNIOT 2026)
  • 大数据计算引擎-Hudi对Spark Catalyst 优化器的RBO、CBO做了什么
  • 设计模式之:建造者模式
  • 阿里云 RDS MySQL 可观测性最佳实践
  • 【含文档+PPT+源码】基于spring boot的固定资产管理系统
  • 企业门户网站建设新闻柳州seo培训