【视频墙】一款基于原生html+javascript+css的视屏墙网页(4分屏、9分屏、16分屏)

一直想找一款原生html+javascript+css的视屏墙,奈何搜遍了全网也没有找到合适的,既然没有合适的那就自力更生吧(过程中参考了boonya编写的一篇JavaScript之类操作:HTML5 canvas多分屏示例,在此表示感谢!)

这是一款基于原生html+javascript+css实现的视屏墙网页,没有使用任何第三方框架。使用方式如下:
1、引入videoWallUI.js,比如:<script src="videoWallUI.js"></script>
2、编写一个html文件,加入一个div,比如:<div id="videoWallContainer" style="width:1000px;height:600px;"></div>
3、在html内编写一个函数,在函数内添加代码:VideoWallUI.Init("videoWallContainer", 4, 0,IconClick,sliderChange)
详细参考videoWall.html
videoWallUI.js代码如下:

class VideoWallUI {
	static play = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA9UlEQVR4nLWSMXLCMBBF/zpj0qYOFG5JUiQ34CbxDTAngCNwBHESzA1cwNBSQE+LPbB8GcQs7sDDm9GMRvp+u5IlaMlrBL2yP1Tgj1NDNN91VjNO7hCOG4n+flTVYSry5rbxMoehV/0MVI9pHL9nGyn2XKq5E3TLvmsGLKHArrNOceUm4McZKxehMsMJgP2mIbt0ogmP40CswFnz5+FrAui/SDRheAaDzQpHjV301ALRMac+lPMSRxQVIDbLvQt20dMQLCjIHhdA0+sRHAw2awXtLtFDyfO/0RMC7OS5hxTolt8pcBpwW1GjzEV5aNvCjXa0FpwBe/yiESDXL9wAAAAASUVORK5CYII=";
	static pause = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAzElEQVR4nNWSPQ6CQBCFZzVgay0UtEQLPYEchRvIUTzCehLxBhQaWguxtnWJrm/RJQOxYmPhl2wymZl987MryJHfCIQq3miiFUzGaF/5px2MDgKnJdLLaV3ft0KM5cU75sQI60Wi9SP1vEl2FsUNroaOQKBi2U/g2AKVX6b0oRXA5QyVi37lPu9OdIRxJAEuILnyTMUawQNMwj7WV78UMBt47len4T8F3JZogMjwZzTYBHQy7CNZAjVPiZ4JwhjfYNYxym3bHATccBZ4ATiQlhHrE1baAAAAAElFTkSuQmCC";
	static stop = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABiUlEQVR4nK2RUU7CQBCGZyjUV3wVTHilatIbUE8gnIB6AuoJrCewnAA4gXgCyw2aqPBKIvgKrxba8V+ktaQSTPRLJt2d3fl2usv0R/YKqquLRkyRRaBAmj8rPY8wzMGIHaphvSPErpCUsThCioSowcRLJnFn+qSLVAojUiqh0cP2Fs505vprnzJUwjObKPZQ8jDXx9e0hREbKmHdwcdFsYXigH4AEhMSn7Bvrk88fLMCY4HpDYr7NTFr4TpsI52iF/XBlIMpJDa6vEcXxwQ2gurq3BKJhrCWMaWTD8MlllsMvxG+ez8auwTQ7ZJZa85KL/5GoAqYxYLAIqDmBwS+CPtq/j+C03W9GcfcS/7rsMBYMBda6S8oYF3iBRx1ibgoU0SaSKcw8xBrAdZsvISHbssEUoE6lZk6SF2qjUjlQLGJVp5EqJt0kwoU6KKP1BXCgWRAGVDcRrGHeMTpNm1hxA5fnYiDJcHmACnAJsaMi/OSkxNyggR1sVGkCok0TYK34mSIYY69gt/yCfDAxhFLwFnOAAAAAElFTkSuQmCC";

	//使用#前缀定义私有字段,这些字段只能在类的内部访问
	#Container = undefined;
	#ScreenNumber = -1;
	#SelectedScreen = undefined;
	#VideoWidth = 0;
	#VideoHeight = 0;
	#SelectVideoIndex = -1;
	#VideoType = 0; //0:preview	1:playback
	#IconCallBackFunc = undefined;
	#RangeCallBackFunc = undefined;

	static SetScreenNumber(paNum) {
		this.ScreenNumber = paNum;
	}

	static GetScreenNumber() {
		return this.ScreenNumber;
	}

	static SetContainer(paId) {
		this.Container = document.getElementById(paId);
		this.Container.style.position = "relative";
		this.Container.style.background = "rgba(0,0,0,0.9)";
	}

	static GetContainer() {
		return this.Container;
	}

	static SetSelectedScreen(paScreen) {
		this.SelectedScreen = paScreen;
	}

	static GetSelectedScreen() {
		return this.SelectedScreen;
	}

	static SetVideoWith(paVideoWidth) {
		this.VideoWidth = paVideoWidth;
	}

	static GetVideoWith() {
		return this.VideoWidth;
	}

	static SetVideoHeight(paVideoHeight) {
		this.VideoHeight = paVideoHeight;
	}

	static GetVideoHeight() {
		return this.VideoHeight;
	}

	static SetSelectVideoIndex(paIndex) {
		this.SelectVideoIndex = paIndex;
	}

	static GetSelectVideoIndex() {
		return this.SelectVideoIndex;
	}

	static SetVideoType(paVideoType) {
		this.VideoType = parseInt(paVideoType);
	}

	static GetVideoType() {
		return this.VideoType;
	}

	static SetIconCallBackFunc(paFunc) {
		this.IconCallBackFunc = paFunc;
	}

	static EmitIconCallBackFunc(paDom) {
		eval(this.IconCallBackFunc(document.getElementById(paDom.getAttribute('video')), paDom.getAttribute('pts')));
		if (paDom.getAttribute('pts') == "play") {
			paDom.src = this.pause;
			paDom.setAttribute('pts', "pause");
			paDom.alt = "暂停";
			paDom.title = "暂停";
		} else if (paDom.getAttribute('pts') == "pause") {
			paDom.src = this.play;
			paDom.setAttribute('pts', "play");
			paDom.alt = "播放";
			paDom.title = "播放";
		} else if (paDom.getAttribute('pts') == "stop") {
			paDom.previousElementSibling.src = this.play;
			paDom.previousElementSibling.setAttribute('pts', "play");
			paDom.previousElementSibling.alt = "播放";
			paDom.previousElementSibling.title = "播放";
		}
	}

	static SetRangeCallBackFunc(paFunc) {
		this.RangeCallBackFunc = paFunc;
	}

	static EmitRangeCallBackFunc(paDom) {
		//console.dir(paDom)
		let rangeValue = paDom.value;
		if (this.RangeCallBackFunc) {
			eval(this.RangeCallBackFunc(document.getElementById(paDom.getAttribute('video')), rangeValue));
		} else {
			console.log("SetRangeCallBackFunc error:No function was setted");
		}
	}

	static SetPlaybackDuration(paVideo, paStartTime, paEndTime) { //"20240618T000000", "20240618T125959"
		//console.log(paVideo)
		if (!paVideo) {
			console.log("SetPlaybackDuration error:No Selected Screen");
			return;
		}

		let rangeDom = document.querySelectorAll('[video="' + paVideo.id + '"]');
		//console.log(rangeDom)

		// 定义匹配日期时间格式的正则表达式
		let regex = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
		// 使用正则表达式测试字符串是否匹配
		if (!regex.test(paStartTime) || !regex.test(paEndTime)) {
			console.log("date format error,must be: YYYY-MM-DD HH:MM:SS");
			return;
		}

		try {
			// 将时间字符串转换为Date对象
			let startTime = new Date(paStartTime);
			let endTime = new Date(paEndTime);
			//console.log(startTime, endTime)
			// 计算两个时间的毫秒差
			let timeDifference = endTime.getTime() - startTime.getTime();
			console.log(timeDifference)
			if (isNaN(timeDifference)) {
				console.log("SetPlaybackDuration error:TimeFormat was Wrong");
				return;
			}
			// 将毫秒差转换为小时、分钟和秒
			let hours = Math.floor(timeDifference / 1000 / 60 / 60);
			let minutes = Math.floor((timeDifference / 1000 / 60) % 60);
			let seconds = Math.floor((timeDifference / 1000) % 60);
			Array.from(rangeDom).filter(item => item.type == "range").forEach(function(range) {
				//console.log(range)
				range.min = "0";
				range.max = timeDifference / 1000;
				range.step = 1;
				document.getElementById("startTime" + range.id.replace("range", "")).innerText = "0:0:0";
				document.getElementById("endTime" + range.id.replace("range", "")).innerText = hours + ":" + minutes + ":" + seconds;
			});
		} catch (e) {
			console.log("SetPlaybackDuration error:" + e.message);
		}
	}

	static Init(paId, paScreenNums, paVideoType, paIconClickFunc, paSliderChangeFunc) {
		this.SetContainer(paId);
		this.SetScreenNumber(paScreenNums);
		this.SetVideoWith(352);
		this.SetVideoHeight(288);
		this.SetSelectVideoIndex(-1);
		this.SetVideoType(paVideoType);
		this.CreateVideo();
		this.CreateMainStatusBar();
		this.LayoutScreens(paScreenNums);
		this.SetIconCallBackFunc(paIconClickFunc)
		this.SetRangeCallBackFunc(paSliderChangeFunc)
	}

	static CreateVideo() {
		let arrowUp = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAOBJREFUOE+1k1EOgjAMhtuRLPEGii/6BlxCuQmcRDyJ3ARPIby5F9EbGEjYzIQlw21EQ+zTsvb/2q4rwkzDmXqYBCyfwYZ4WPBOxI9FxWzJnIBBfB1EzAWxAsZizAFEAgBWiAHQxQgivdEq95soAxQHG8QA+G0oZNlKrPrWITUtt+reBDRRhsiZzCyD1m2QqLOE6L4+0YSt2rBAgD0A5jW9pD9NQYkFwHkKYq1Az8w7fiSEJP0jmpUYAFvZ78k4ICOADEQPTwjIPntWEIFid6dl7JyCDHR9W5vvv8v0zaa+AI6lfRGiBl2wAAAAAElFTkSuQmCC";
		let zoomOut = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAANRJREFUOE/Nk0EOgkAMRX8xwXgDgxvcoafQk6gnAU6C3oRTKDtnA/EGRhKmppohjIIR2TgrkrZvaPuGMPCQqZ9eA/8yyVRf3gMgxc6IzmCKibRiUFK4pxouOV65YALv5JtBoa54LRfWSd5tGYE4ZCAlYNUGMDEB5W62F1gNmJXBVsgAfAm0AZ63I3XAhzeA/GKz/y6AyTFxq8++A7Ra+KX4zwCDhyhr1KCNOPBpjQAUgeMuD5JvRBJji/Exsob4omqnysyOL8bqiueWyn3W2Hx4g0W6A7QcdxHrSRpcAAAAAElFTkSuQmCC";
		let zoomIn = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAOVJREFUOE/FUlEOwVAQnCUqbkD5qL/WKbgJJ8FJuImegv7VB+UG4km7snSl9CFBYj/37c6bnRnCl0Vf7uMG4JqAFYzAo60TzYvg7rE3AfFYe4mzuuyWABgId85qYGPWMsGCgL68PQGgOcBDME2T+nJSBGkbf8igGXCdKQHIgNBWqlnK3X0jWgtI8+B7lSrFeprM6AdWEWVBl5WFrXenwadu/M7GIoPOye9valFY7L09QYXJ1R5nKQ8eRVR3XNObJc5yZMnB1aJXQZKcSBY+CpJrghiA9yJI+dWWIAntS8jyKjH4m41n3TWGEaYieaoAAAAASUVORK5CYII=";

		//创建css样式
		const styleElement = document.querySelector('head style');
		// 如果<style>标签存在
		if (styleElement) {
			// 插入新的CSS规则
			if (styleElement.sheet) {
				styleElement.sheet.insertRule("input.ne-range[type=range]::-webkit-slider-thumb {width: 6px; height: 6px; border-radius: 50%; border: 0; background-color: #FFF; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.21); -webkit-transition: border-color 0.15s, background-color 0.15s; transition: border-color 0.15s, background-color 0.15s; cursor: pointer; background-clip: padding-box; box-sizing: border-box; -webkit-appearance: none !important;}", styleElement.sheet.cssRules.length);
				styleElement.sheet.insertRule("input.ne-range[type=range]::-webkit-slider-thumb:active { border: 0; background-color: #FFF;}", styleElement.sheet.cssRules.length);
				styleElement.sheet.insertRule("input.ne-range[type=range] {left:0px;width: 99%; height: 2px; border-radius: 8px; margin: .8em 0; padding: 0; cursor: pointer; border: 0; background: -webkit-linear-gradient(#FFF, #FFF) no-repeat #999999; background-size: 0% 100%; position: relative; outline: 0; top: -9px; -webkit-appearance: none !important;}", styleElement.sheet.cssRules.length);
			}
		} else {
			// 如果<style>标签不存在,创建一个新的
			const newStyle = document.createElement('style');
			newStyle.innerHTML = "";
			newStyle.innerHTML += "input.ne-range[type=range]::-webkit-slider-thumb {width: 6px; height: 6px; border-radius: 50%; border: 0; background-color: #FFF; box-shadow: 0 1px 4px rgba(0, 0, 0, 0.21); -webkit-transition: border-color 0.15s, background-color 0.15s; transition: border-color 0.15s, background-color 0.15s; cursor: pointer; background-clip: padding-box; box-sizing: border-box; -webkit-appearance: none !important;}";
			newStyle.innerHTML += "input.ne-range[type=range]::-webkit-slider-thumb:active { border: 0; background-color: #FFF;}";
			newStyle.innerHTML += "input.ne-range[type=range] {left:0px;width: 99%; height: 2px; border-radius: 8px; margin: .8em 0; padding: 0; cursor: pointer; border: 0; background: -webkit-linear-gradient(#FFF, #FFF) no-repeat #999999; background-size: 0% 100%; position: relative; outline: 0; top: -9px; -webkit-appearance: none !important;}";
			document.head.appendChild(newStyle);
		}

		for (let i = 1; i <= 16; i++) {
			//创建videoContainer
			let videoContainer = document.createElement('div');
			videoContainer.id = "videoContainer" + i;
			videoContainer.width = this.VideoWith;
			videoContainer.height = this.VideoHeight;
			videoContainer.style.background = "#00000000";
			videoContainer.style.cssFloat = "left";
			videoContainer.style.position = "relative";
			//创建video
			let videoElement = document.createElement('video');
			videoElement.id = "video" + i;
			videoElement.src = "";
			videoElement.width = this.VideoWith;
			videoElement.height = this.VideoHeight;
			videoElement.style.width = "100%";
			videoElement.style.height = "100%";
			//创建video下方的状态栏
			let statusBar = document.createElement('div');
			statusBar.id = "statusBar" + i;
			statusBar.style.width = "100%";
			statusBar.style.height = "auto";
			statusBar.style.background = "rgba(255,255,255,0.2)";
			statusBar.style.position = "absolute";
			statusBar.style.bottom = "0px";
			statusBar.style.left = "0px";
			statusBar.style.padding = "1px";
			statusBar.style.position = "absolute";
			statusBar.style.alignItems = "center";
			statusBar.style.display = "none";
			//创建状态栏下的直播操作
			let statusBarPreview = document.createElement('div');
			statusBarPreview.id = "statusBarPreview" + i;
			statusBarPreview.style.width = "100%";
			statusBarPreview.style.height = "20px";
			statusBarPreview.style.display = this.VideoType == 0 ? "block" : "none";
			statusBarPreview.innerHTML = "&nbsp;<img src='" + arrowUp + "' video='video" + i + "' width=16 height=16 pts='left' alt='云台左转' title='云台左转' style='transform: rotate(-90deg);' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBarPreview.innerHTML += "&nbsp;<img src='" + arrowUp + "' video='video" + i + "' width=16 height=16 pts='left_up' alt='云台左上转' title='云台左上转' style='transform: rotate(-45deg);' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBarPreview.innerHTML += "&nbsp;<img src='" + arrowUp + "' video='video" + i + "' width=16 height=16 pts='up' alt='云台上转' title='云台上转' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBarPreview.innerHTML += "&nbsp;<img src='" + arrowUp + "' video='video" + i + "' width=16 height=16 pts='right_up' alt='云台右上转' title='云台右上转' style='transform: rotate(45deg);' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBarPreview.innerHTML += "&nbsp;<img src='" + arrowUp + "' video='video" + i + "' width=16 height=16 pts='right' alt='云台右转' title='云台右转' style='transform: rotate(90deg);' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBarPreview.innerHTML += "&nbsp;<img src='" + arrowUp + "' video='video" + i + "' width=16 height=16 pts='right_down' alt='云台右下转' title='云台右下转'  style='transform: rotate(135deg);' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBarPreview.innerHTML += "&nbsp;<img src='" + arrowUp + "' video='video" + i + "' width=16 height=16 pts='down' alt='云台下转' title='云台下转' style='transform: rotate(180deg);' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBarPreview.innerHTML += "&nbsp;<img src='" + arrowUp + "' video='video" + i + "' width=16 height=16 pts='left_down' alt='云台左下转' title='云台左下转' style='transform: rotate(-135deg);' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBarPreview.innerHTML += "&nbsp;<img src='" + zoomIn + "' video='video" + i + "' width=16 height=16 pts='zoom_in' alt='云台放大' title='云台放大' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBarPreview.innerHTML += "&nbsp;<img src='" + zoomOut + "' video='video" + i + "' width=16 height=16 pts='zoom_out' alt='云台缩小' title='云台缩小' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBar.append(statusBarPreview);
			//创建状态栏下的回放操作
			let statusBarPlayback = document.createElement('div');
			statusBarPlayback.id = "statusBarPlayback" + i;
			statusBarPlayback.style.width = "100%";
			statusBarPlayback.style.height = "40px";
			statusBarPlayback.style.display = this.VideoType == 1 ? "block" : "none";
			let statusBarPlaybackSlider = document.createElement('div');
			statusBarPlaybackSlider.style.display = "flex";
			statusBarPlaybackSlider.style.width = "100%";
			statusBarPlaybackSlider.style.height = "20px";
			statusBarPlaybackSlider.innerHTML += "<!-- 开始时间 --><div style='padding-left:2px; width: 25px; border:0px solid #FFFF00; color: #aaa; font-size:10px' id='startTime" + i + "'>0:0</div>";
			statusBarPlaybackSlider.innerHTML += "<!-- 滑块 --><div style='flex-grow: 1; border:0px solid #FFFF00;'><input type='range'  id='range" + i + "' video='video" + i + "'  class='ne-range' value='0' οnclick='VideoWallUI.EmitRangeCallBackFunc(this)' /></div>"
			statusBarPlaybackSlider.innerHTML += "<!-- 结束时间 --><div style='padding-right:2px; width: 45px; border:0px solid #FFFF00; color: #aaa;;font-size:10px' id='endTime" + i + "'>0:0</div>";
			statusBarPlayback.append(statusBarPlaybackSlider);
			let statusBarPlaybackControl = document.createElement('div');
			statusBarPlaybackControl.style.display = "flex";
			statusBarPlaybackControl.style.width = "100%";
			statusBarPlaybackControl.style.height = "20px";
			statusBarPlaybackControl.style.justifyContent = "center";
			statusBarPlaybackControl.innerHTML += "<img src='" + this.play + "' video='video" + i + "' width=16 height=16 pts='play' alt='播放' title='播放' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBarPlaybackControl.innerHTML += "&nbsp;<img src='" + this.stop + "' video='video" + i + "' width=16 height=16 pts='stop' alt='停止' title='停止' οnclick='VideoWallUI.EmitIconCallBackFunc(this)'>";
			statusBarPlayback.append(statusBarPlaybackControl);
			statusBar.append(statusBarPlayback);
			videoContainer.append(videoElement);
			videoContainer.append(statusBar);
			videoContainer.addEventListener('mouseover', () => statusBar.style.display = 'block');
			videoContainer.addEventListener('mouseout', () => statusBar.style.display = 'none');
			this.Container.append(videoContainer);
		}
	}

	static CreateMainStatusBar() {
		//创建下方的总状态栏
		let fullScreen = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAMZJREFUOE+9k0EOgjAURP+UiPEGBjewQy6BnkS9CZ6EeBLxEsgOF4Z4AwMJ/aZETCxGrBi77n+dmT8FDTwYOE8NwKmCmIgXRjDGrhinEaZX3xUW9rLmpQmgnXkACvvomQCcap6rR78HlEH0ZMFUQau2V8Gs8tfMwtXtCSGT8yhL3gKcMogYHIJx6OQDXvVmoABqUHnVAR+F+F+AXqTLJDs1AZIIZS23nRAtqB54r6t8r6lqKSzEIOpsgQhJYaeb33wmkwrrd29M84ZylD57vQAAAABJRU5ErkJggg==";
		let screen1 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAADpJREFUOE9jZKAQMIL0S//SXEyOOU/ZrsfCDfjPwBBDiiGMDAxLRg0YDYPhmA5IyQcwtfC8QI5mmB4AfeZQETbEiiwAAAAASUVORK5CYII=";
		let screen4 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAIJJREFUOE9jZKAQMIL0S3zXUGBmZnBAN+vvX4YDLzhvPJD+pZGASw5sAEjBfwbG+eiKmBj/O4LE/v1n3I8ux8jwP/Ep240FowZAwwAUCywsDAroAfWE9cYBXHJ//jA8AMUQPBqxGQBTJPNbAyOKUQwYjUYqJGVcmQmU1gllNHA0UgIAQUKgEaMrVmIAAAAASUVORK5CYII=";
		let screen9 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAOtJREFUOE/NU1sKgkAUPVfJaAe9oD7NTWQrqVZSrcRaSboJ89OgrB1Eht64IxMO+GdQ92s4MGfOYy6h5ZDc7z/cqW3D11xXJ9mPX67PjKlgREgvnSSsY0WB8N5LUkUwyt0VgwI5MxDenNNimHsBwKuKlPaZE68H+exIqB4i8Foe+g6BSCuYNoqZKcq68Xb49LZMPDew3AsYrGzZxDuxpRS0GUUgCkq2loqIcRYFVS5WpQBlJH7rmEXl4aPgP0LUFprkakyCBWEitgwLXwnxUyMolU/TWGOtWqPG34dYX6amxdGYKNV5GcvUJsQ3MorzEcNe+yUAAAAASUVORK5CYII=";
		let screen16 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAARVJREFUOE/NU0tOw0AMtT1SETeAwCLs0l6C5iSkJ2l7koSTUC4B3ZENnxsggsYP2WFEyCZUsCCbyZvM8/j5vXDWzUH902pEKUHWRKhsQxglQDmIa8Mg2j3P7sshhweANOKCA9dMtDQCE1aA5MRYpwKIWEngh89LabJAT+w7IOJGo26/FTh5LXL79HK8b21NOO2N8fCMcTjrFjUIXsT0nXVFpcRXhgNja2sEuwQG3z4d3W1Ou/nNjyX8egaTBazl1M7jbN+cvxdLs85bj7RzKaF3ZYxdVva22PgLa5sKqIoTVLXxPIj4JenMkDNp46SEPwjSl42eMpEKjMtko80j2SqEa5uDpbVPKrd8aHDGYTt4Bv/vZ/oAtpMSob5nDMgAAAAASUVORK5CYII=";
		let statusBar = document.createElement('div');
		statusBar.id = "mainStatusBar";
		statusBar.style.width = "100%";
		statusBar.style.height = "20px";
		statusBar.style.background = "rgba(255,255,255,0.2)";
		statusBar.style.position = "absolute";
		statusBar.style.bottom = "0px";
		statusBar.style.left = "0px";
		//statusBar.style.padding = "0px";
		statusBar.style.display = "flex";
		statusBar.style.justifyContent = "flex-end";
		statusBar.style.alignItems = "center";
		statusBar.innerHTML = "&nbsp;<img src='" + screen1 + "' width=16 height=16 alt='1x1' title='1x1' οnclick='VideoWallUI.LayoutScreens(1)'>";
		statusBar.innerHTML += "&nbsp;<img src='" + screen4 + "' width=16 height=16 alt='2x2' title='2x2' οnclick='VideoWallUI.LayoutScreens(4)'>";
		statusBar.innerHTML += "&nbsp;<img src='" + screen9 + "' width=16 height=16 alt='3x3' title='3x3' οnclick='VideoWallUI.LayoutScreens(9)'>";
		statusBar.innerHTML += "&nbsp;<img src='" + screen16 + "' width=14 height=14 alt='4x4' title='4x4' οnclick='VideoWallUI.LayoutScreens(16)'>";
		statusBar.innerHTML += "&nbsp;<img src='" + fullScreen + "' width=16 height=16 alt='全屏' title='全屏' οnclick='VideoWallUI.fullScreen()'>&nbsp;";
		this.Container.append(statusBar);
	}

	static ContainsScreen(num) {
		let screens = [1, 4, 9, 16];
		for (let i = 0; i < screens.length; i++) {
			if (screens[i] == num) {
				return true;
			}
		}
		return false;
	}

	static LayoutScreens(num) {
		if (num == undefined) {
			console.log("LayoutScreens num is undefined");
		} else if (!VideoWallUI.ContainsScreen(num)) {
			console.log("LayoutScreens num is not in  [1, 4, 9, 16]");
			return;
		} else {
			this.ScreenNumber = num;
		}

		//console.log(this.Container)
		for (let i = 1; i <= this.Container.childElementCount; i++) {
			let videoContainer = this.Container.childNodes.item(i - 1);
			//console.log("videoContainer"+i,videoContainer)
			if (videoContainer.id == "mainStatusBar") {
				continue;
			}
			videoContainer.index = i;
			videoContainer.style.margin = "1px";
			videoContainer.parentContainer = this.Container;
			videoContainer.onclick = function() {
				VideoWallUI.SelectVideoIndex = this.index;
				//alert(VideoWallUI.SelectVideoIndex);
				VideoWallUI.SetSelectedScreen(videoContainer.childNodes.item(0));
				for (let j = 1; j <= this.parentContainer.childElementCount; j++) {
					if (j === VideoWallUI.SelectVideoIndex) {
						this.style.border = "1px solid #00FF00";
					} else {
						this.parentContainer.childNodes.item(j - 1).style.border = "1px solid black";
					}
				}
			};
			if (this.ScreenNumber < i) {
				videoContainer.style.display = "none";
			} else {
				videoContainer.style.display = "block";
			}
		}
		this.LayoutResize();
	}

	static LayoutResize() {
		let width = this.Container.clientWidth;
		let height = this.Container.clientHeight - 20; //扣除mainStatusBar的高度
		let count = 0;
		let videoContainerArray = Array.from(this.Container.childNodes).filter(item => item.id !== "mainStatusBar"); // 过滤掉mainStatusBar
		videoContainerArray.forEach(function(videoContainer) {
			if (VideoWallUI.ScreenNumber == 1 && videoContainer.index == 1) {
				videoContainer.style.width = (width - 4) + "px";
				videoContainer.style.height = (height - 4) + "px";
				count++;
			} else if (VideoWallUI.ScreenNumber == 4 && videoContainer.index <= 4) {
				videoContainer.style.width = (width / 2 - 4) + "px";
				videoContainer.style.height = (height / 2 - 4) + "px";
				count++;
			} else if (VideoWallUI.ScreenNumber == 9 && videoContainer.index <= 9) {
				videoContainer.style.width = (width / 3 - 4) + "px";
				videoContainer.style.height = (height / 3 - 4) + "px";
				count++;
			} else if (VideoWallUI.ScreenNumber == 16 && videoContainer.index <= 16) {
				videoContainer.style.width = (width / 4 - 4) + "px";
				videoContainer.style.height = (height / 4 - 4) + "px";
				videoContainer.style.cssFloat = "left";
				videoContainer.style.margin = "1px";
				count++;
			}
			if (count == VideoWallUI.ScreenNumber) {
				//break;
			}
		});
	}

	static fullScreen() {
		if (!document.webkitIsFullScreen) {
			this.Container.webkitRequestFullScreen(); //全屏
			//player.style.width = "100%"
		} else {
			document.webkitCancelFullScreen();
		}
	}
}

videoWall.html代码如下:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>VideoWall</title>
    <script src="videoWallUI.js"></script>
    <script type="text/javascript">
        window.onload = function() {
            //参数:存放视频墙的容器ID,初始化分屏数量,初始化显示的状态栏(0:直播 1:回放),点击操作图标后的回调函数,拉动滑杆的回调函数
            VideoWallUI.Init("videoWallContainer", 4, 0,IconClick,sliderChange);
        }

        window.onresize = function() {
            VideoWallUI.LayoutResize();
        }

        function IconClick(paSelectedScreen, paPTS) {
            console.log(paSelectedScreen, paPTS)
        }

        function sliderChange(paSelectedScreen, paValue) {
            console.log(paSelectedScreen, paValue);
        }
    </script>
</head>

<body>
    <div id="videoWallContainer" style="width:1000px;height:600px;"></div>
</body>

</html>

效果图:
4分屏直播模式
4分屏直播模式
9分屏回放模式
9分屏回放模式
最新代码可访问:videoWallUI

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值