色字體,選擇“標星公眾號”
優質文章,第一時間送達
屏幕錄制?截屏?網頁生成圖片?幀圖?說到錄屏,我一開始想到的是前面這些詞。大致的想法是持續的生成當前頁面的截圖,然后把這些幀圖再合并成一個視頻文件。前端頁面生成圖片我們應該比較熟悉的是html2canvas。另外也有一些現成的庫可以使用來進行屏幕的錄制,RecordRTC上就有很多屏幕錄制的實現。有聲音(Audio)、視頻(Video)、屏幕(Screen)的錄制;有針對canvas的錄制等等,一共有三十多個示例。這里主要想簡單的講一講原生的 Screen Capture API。參見:Using the Screen Capture API
navigator.mediaDevices.getDisplayMedia
該方法會返回一個promise, 該promise會resolve當前屏幕內容的實時數據流。
使用 async / await 實現如下:
async function startCapture(displayMediaOptions) {
let captureStream = ;
try {
captureStream = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
} catch(err) {
console.error("Error: " + err);
}
return captureStream;
}
使用 promise 的方式實現如下:
function startCapture(displayMediaOptions) {
let captureStream = ;
return navigator.mediaDevices.getDisplayMedia(displayMediaOptions)
.catch(err => { console.error("Error:" + err); return ; });
}
我們在獲取屏幕數據的時候有可能會獲取到一些敏感信息,所有在使用getDisplayMedia的時候,為了安全考慮,會彈出一個選擇框,然用戶自己選擇需要共享那一部分的內容。可以共享當前屏幕,也可以共享其他的應用窗口和瀏覽器的其他標簽頁。
二、參數配置:
我們在上面的實現中可以看到, 傳遞給startCapture函數的參數為displayMediaOptions。這個參數是用于配置返回數據流的。數據形式如下:
const displayMediaOptions = {
video: {
cursor: "never"
},
audio: false,
logicalSurface: false,
};
開可以針對音視頻做詳細的配置:
const gdmOptions = {
video: {
cursor: "always" // 始終顯示鼠標信息
},
// audio 配置信息是可選的
audio: {
echoCancellation: true,
noiseSuppression: true,
sampleRate: 44100
}
}
三、示例
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Screen Record</title>
<link rel="stylesheet" href="./css/index.css">
</head>
<body>
<p>This example shows you the contents of the selected part of your display.
Click the Start Capture button to begin.</p>
<p><button id="start">Start Capture</button> <button id="stop">Stop Capture</button></p>
<video id="video" autoplay></video>
<br>
<strong>Log:</strong>
<br>
<pre id="log"></pre>
<script src="./js/index.js"></script>
</body>
</html>
CSS:
#video {
border: 1px solid #999;
width: 98%;
max-width: 860px;
}
.error {
color: red;
}
.warn {
color: orange;
}
.info {
color: darkgreen;
}
JS:
const videoElem = document.getElementById("video");
const logElem = document.getElementById("log");
const startElem = document.getElementById("start");
const stopElem = document.getElementById("stop");
const displayMediaOptions = {
video: {
cursor: "never"
},
audio: false
};
startElem.addEventListener("click", function(evt) {
startCapture;
}, false);
stopElem.addEventListener("click", function(evt) {
stopCapture;
}, false);
console.log = msg => logElem.innerHTML += `${msg}<br>`;
console.error = msg => logElem.innerHTML += `<span class="error">${msg}</span><br>`;
console.warn = msg => logElem.innerHTML += `<span class="warn">${msg}<span><br>`;
console.info = msg => logElem.innerHTML += `<span class="info">${msg}</span><br>`;
async function startCapture {
logElem.innerHTML = "";
try {
videoElem.srcObject = await navigator.mediaDevices.getDisplayMedia(displayMediaOptions);
dumpOptionsInfo;
} catch(err) {
console.error("Error: " + err);
}
}
function stopCapture(evt) {
let tracks = videoElem.srcObject.getTracks;
tracks.forEach(track => track.stop);
videoElem.srcObject = ;
}
function dumpOptionsInfo {
const videoTrack = videoElem.srcObject.getVideoTracks[0];
console.info("Track settings:");
console.info(JSON.stringify(videoTrack.getSettings, , 2));
console.info("Track constraints:");
console.info(JSON.stringify(videoTrack.getConstraints, , 2));
}
效果如下:
點擊Start Capture 之后選擇需要共享的部分就可以共享如下的內容:
點擊Stop Capture即可˙停止錄制共享。
這個例子只是調取接口獲取到當前分享屏幕的數據流,并通過video的形式顯示出來。我們在拿到數據流信息這個,可以把這些信息上傳到服務器,生成相應的視頻文件。也可以結合websocket之類的處理方式,實現實時的屏幕共享功能。
作者:飯等米
鏈接:segmentfault.com/a/1190000020267689
如果喜歡本篇文章,歡迎。關注訂閱號「Web項目聚集地」,回復「進群」即可進入無廣告技術交流。
1.2. 4. 5.6.
件傳遞有兩種方式,冒泡和捕獲。事件傳遞定義了元素事件觸發的順序,在冒泡中,內部元素的事件會先被觸發,然后在觸發外部元素,如先觸發p元素然后觸發div元素。在捕獲事件中,外部元素先被觸發,然后內部事件觸發。addEventListener() 方法可以指定 "useCapture" 參數來設置傳遞類型:addEventListener(event, function, useCapture);
創建新的HTML元素(節點)appendChild()
HTML Collection與NodeList的區別:NodeList 與 HTMLCollection 有很多類似的地方。NodeList 與 HTMLCollection 都與數組對象有點類似,可以使用索引 (0, 1, 2, 3, 4, ...) 來獲取元素。NodeList 與 HTMLCollection 都有 length 屬性。節點列表不是一個數組!節點列表無法使用數組的方法: valueOf(), pop(), push(), 或 join() 。
件流:
事件冒泡
取消冒泡:oEvent.cancelBubble=true
<html>
<head>
<meta charset="utf-8">
<title>無標題文檔</title>
<style>
#div1 {width:400px; height:300px; background:#CCC; display:none;}
</style>
<script>
window.onload=function ()
{
var oBtn=document.getElementById('btn1');
var oDiv=document.getElementById('div1');
oBtn.onclick=function (ev)
{
var oEvent=ev||event;
oDiv.style.display='block';
//alert('按鈕被點擊了');
oEvent.cancelBubble=true; //取消事件冒泡,是解決許多問題的方法和手段
};
document.onclick=function ()
{
oDiv.style.display='none';
//alert('document被點擊了');
};
};
</script>
</head>
<body>
<input id="btn1" type="button" value="顯示" />
<div id="div1">
</div>
</body>
</html>
冒泡型事件:
<html>
<head>
<title>冒泡型事件</title>
<script language="javascript">
function add(sText){
var oDiv = document.getElementById("display");
oDiv.innerHTML += sText; //輸出點擊順序
}
</script>
</head>
<body onclick="add('body<br>');">
<div onclick="add('div<br>');">
<p onclick="add('p<br>');">Click Me</p>
</div>
<div id="display"></div>
</body>
</html>
執行順序:p對象 -> div對象 -> body對象
冒泡型事件執行順序::由內到外(p -> div -> body -> document)
注意: DOM 0級只有冒泡, 沒有捕獲
捕獲型事件
相對于IE使用冒泡型事件, Netscape使用了另一種稱為捕獲型事件(eventcapturing)的解決方案;
addEventListener(事件名稱,函數, bCapture)
removeEventListener(事件名稱, 函數, bCapture)
事件監聽函數第三個參數bCapture確定是冒泡型還是捕獲型事件(true:捕獲 false:冒泡,默認值false)
<!DOCTYPE html>
<html>
<head>
<style>
div {
background-color: coral;
border: 1px solid;
padding: 50px;
}
</style>
</head>
<body>
<div id="myDiv2">
<p id="myP2">點擊該段落, 我是捕獲</p>
</div>
<script>
document.getElementById("myP2").addEventListener("click", function() {
alert("你點擊了 P 元素!");
}, true);
document.getElementById("myDiv2").addEventListener("click", function() {
alert("你點擊了 DIV 元素!");
}, true);
</script>
</body>
</html>
執行順序: div對象 -> p對象
捕獲型事件執行順序:由外到內(如:document -> body -> div -> p)
冒泡型:事件從內部往外部依次執行。
捕捉型:事件從外部往內部依次執行。
事件監聽
通用監聽方法:
1.直接在HTML標簽中分配事件處理函數:
<script language="javascript">
function add(sText){
var oDiv = document.getElementById("display");
oDiv.innerHTML += sText; //輸出點擊順序
}
</script>
</head>
<body onclick="add('body<br>');">
<div onclick="add('div<br>');">
<p onclick="add('p<br>');">Click Me</p>
</div>
<div id="display"></div>
</body>
2.結構與行為的分離:
<html>
<head>
<title>監聽函數</title>
<script language="javascript">
window.onload = function(){
var oP = document.getElementById("myP"); //找到對象
oP.onclick = function(){ //設置事件監聽函數
alert('我被點擊了');
}
}
</script>
</head>
<body>
<div>
<p id="myP">Click Me</p>
</div>
</body>
</html>
事件監聽的作用:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>無標題文檔</title>
<script>
window.onload=function ()
{
alert('a');
};
window.onload=function ()
{
alert('b');
};
</script>
</head>
<body>
</body>
</html>
以上程序只彈出alert('b');
理解:對同一對象執行兩次事件(同一事件類型)處理函數時,往往只能只執行后一個
因此如果要讓腳本在本瀏覽器中正常運行的話,就必須使用瀏覽器所支持的事件監聽器
IE中的監聽方法:
attachEvent(事件名稱, 函數), 綁定事件處理函數 attach: 貼上, 附著
detachEvent(事件名稱, 函數), 解除綁定 detach: 分離, 拆開
注意:IE只支持冒泡型事件監聽, 沒有第三個參數, 事件名稱前要加"on";
<html>
<head>
<title>多個監聽函數</title>
<script language="javascript">
function fnClick1(){
alert("我被fnClick1點擊了");
}
function fnClick2(){
alert("我被fnClick2點擊了");
//oP.detachEvent("onclick",fnClick1); //刪除監聽函數1
}
var oP;
window.onload = function(){
oP = document.getElementById("myP"); //找到對象
oP.attachEvent("onclick",fnClick1); //添加監聽函數1
oP.attachEvent("onclick",fnClick2); //添加監聽函數2
}
</script>
</head>
<body>
<div>
<p id="myP">Click Me</p>
</div>
</body>
</html>
標準DOM的事件監聽:
addEventListener(事件名稱,函數, 捕獲)
element.addEventListener(event, function, useCapture)
removeEventListener(事件名稱, 函數, 捕獲)
element.removeEventListener(event, function, useCapture)
bCapture 是用于冒泡階段還是捕獲階段(true:捕獲 false:冒泡,默認值false)
注意:IE9版本已支持
<html>
<head>
<title>標準DOM的事件監聽</title>
<script language="javascript">
function fnClick1(){
alert("我被fnClick1點擊了");
//oP.removeEventListener("click",fnClick2,false); //刪除監聽函數2
}
function fnClick2(){
alert("我被fnClick2點擊了");
}
var oP;
window.onload = function(){
oP = document.getElementById("myP"); //找到對象
oP.addEventListener("click",fnClick1,false); //添加監聽函數1
oP.addEventListener("click",fnClick2,false); //添加監聽函數2
}
</script>
</head>
<body>
<div>
<p id="myP">Click Me</p>
</div>
</body>
</html>
編寫兼容性事件監聽函數
function addEvent(obj, ev, fn){
if(obj.addEventListener){
obj.addEventListener(ev, fn, false);
}else{
obj.attachEvent('on'+ev, fn);
}
}
function removeEvent(obj, ev, fn){
if(obj.removeEventListener){
obj.addEventListener(ev, fn, false);
}else{
obj.attachEvent('on'+ev, fn);
}
}
實例:
*請認真填寫需求信息,我們會在24小時內與您取得聯系。