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>标签的src
						videoUrls.push(match[1]);
					} else if (match[2]) { // <video>标签的src
						videoUrls.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 = 5
						video.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() {
							// 创建画布的宽高属性节点,就是图片的大小,单位PX
							var 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.params
		
			this.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-WEIXIN
						this.richContent = res.busNews.content;
						//#endif
					
						this.XWtitle = res.busNews.title;
						this.createTime = res.busNews.createTime;
						this.videoLists = res.busNews.content;
					}
				})
			},
	
			//视频封面
			reciveMessage(val) {
				let that = this
				this.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.params
		
			this.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-WEIXIN
						this.richContent = res.busNews.content;
						//#endif
					
						this.XWtitle = res.busNews.title;
						this.createTime = res.busNews.createTime;
						this.videoLists = res.busNews.content;
					}
				})
			},
	
			//视频封面
			reciveMessage(val) {
				let that = this
				this.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>标签的src
						videoUrls.push(match[1]);
					} else if (match[2]) { // <video>标签的src
						videoUrls.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 = 5
						video.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() {
							// 创建画布的宽高属性节点,就是图片的大小,单位PX
							var 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

相关推荐
星光一影4 小时前
原生社交app/工会/家族/语音房/直播社交/付费解锁聊天/广场好友圈子/一对一聊天交友
mysql·uni-app·php·html5·交友
anyup4 小时前
🔥牛逼!3分钟生成 5 套主题,还能一键切换暗黑模式!
前端·前端框架·uni-app
2501_915918416 小时前
iOS 手机抓包软件怎么选?HTTPS 调试、TCP 数据流分析与多工具组合的完整实践
android·ios·智能手机·小程序·https·uni-app·iphone
游戏开发爱好者87 小时前
iOS 应用上架的工程实践复盘,从构建交付到审核通过的全流程拆解
android·ios·小程序·https·uni-app·iphone·webview
00后程序员张7 小时前
iOS App 如何上架,从准备到发布的完整流程方法论
android·macos·ios·小程序·uni-app·cocoa·iphone
Json____7 小时前
uni-app-数码购物商城h5手机端-前端静态网页
前端·uni-app·商城
wx_xsooop7 小时前
iOS 上架4.3a 被拒【uniapp专讲】
flutter·ios·uni-app·uniapp
脾气有点小暴1 天前
uniapp滚动容器冲突
uni-app
鱼樱前端1 天前
uni-app开发app之前提须知(IOS/安卓)
前端·uni-app
二狗mao2 天前
Uniapp使用websocket进行ai回答的流式输出
websocket·网络协议·uni-app