navigator 拓宽前端视野

964 阅读8分钟

前言💐

写本文的起因是最近做了一个共享屏幕在线演示ppt的需求,发现了navigator的新大陆。原来web端开启屏幕共享是如此的简单,在接触之前还以为是多么高大上的功能,需求评审时内心还有些慌张。

人总是对自己不了解的东西心生恐惧😱

因为在此之前,虽说我知道navigator记录了一些用户代理的信息,常用的也就是利用Navigator.userAgent判断下当前浏览器所处的环境 (好多前端仔都是这样吧~哈哈哈,如果你也是,评论区扣1,如果你深入了解过,评论区扣眼珠子) 。而对它的其他API的了解少之又少。因为在我认知里,它只是用来记录信息的,殊不知它还有很多强大的API,比如开启摄像头,保持屏幕常亮等。

于是我通读了mdn上关于navigator的文档,并将一些以后可能用到的API记录下来,看看你都知道哪些,如有错误,请在评论区指正!

本文只记录一些了navigator的属性,下一篇更文再记录下它的方法,欢迎关注!

1. clipboard(剪切板)

clipboard属性返回一个可以读写剪切板内容的Clipboard对象。
该对象实例有四个方法:read,readText,write,writeText

用途:实现web端剪切、复制、粘贴的功能。
兼容性:还不错,大胆用!

    //剪切板实例
    const theClipboard = navigator.clipboard;
  • read() 从剪贴板读取数据(比如图片),返回一个Promise对象。在检索到数据后,promise返回ClipboardItem对象的数组来提供剪切板数据,可以是文本数据,也可以是二进制数据(比如图片),该方法需要用户明确给予许可
  • readText() 从操作系统读取文本;返回一个 Promise,在从剪切板中检索到文本后,promise返回剪贴板里面的文本数据;
  • write() 用于将任意数据写入剪贴板,可以是文本数据,也可以是二进制数据,这是一个异步操作;
  • writeText() 用于将文本内容写入剪贴板。
//read
async function getClipboardContents() {
  try {
    const clipboardItems = await navigator.clipboard.read();

    for (const clipboardItem of clipboardItems) {

      for (const type of clipboardItem.types) {
        const blob = await clipboardItem.getType(type);
        // we can now use blob here
      }
    }

  } catch (err) {
    console.error(err.name, err.message);
  }
}

//readText
async function getClipboardText(){
    const text = await navigator.clipboard.readText();
    console.log(text);
}

//write
async function copyImage() {
    const input = document.getElementById("file");
    const blob = new Blob(["sample 2"], { type: "text/plain" });
    const clipboardItem = new ClipboardItem({
        "text/rt": blob,
        "image/png": input.files[0],
    });
    const response = await navigator.clipboard.write([clipboardItem]);
    console.log(response);
}

//writeText
async function writeDataToClipboard() {
    const result = await navigator.clipboard.writeText("Hello");
    console.log(result);
}

2. connection(网络连接状态)

Navigator.connection 用来获取设备的网络连接信息。
可以获取到的信息有:downlink(网络下行速度)、 effectiveType(网络类型)、onchange(有值代表网络状态变更)rtt(估算的往返时间)saveData(打开/请求数据保护模式)

用途:基于用户的网络状态来切换内容清晰度。
兼容性:慎用!实验中的功能,例如safari,Firefox,IE完全不支持,chrome目前也只支持downlink,effectiveType,rtt三个属性

//网络状态实例
const connectionInfo = navigator.connection

image.png

3. geolocation(地理位置)

Navigator.geolocation 只读属性返回一个Geolocation对象,利用该对象的方法可以获取到设备的地理定位。

注意:1.必须授予打开网页的客户端位置权限; 2. 必须使用https协议
兼容性:主流浏览器都支持,包括ie

navigator.geolocation.getCurrentPosition(
    function(position) {
        console.log(position.coords.latitude, position.coords.longitude);
    },
    function(error){
      console.error(error.message);
    }, {
        enableHighAccuracy: true
        ,timeout : 5000
    }
);

示例:

image.png

4. mediaDevices(媒体捕获和流媒体)

Navigator.mediaDevices 属性返回一个MediaDevices对象,MediaDevices 界面提供对连接的媒体输入设备(如相机和麦克风)以及屏幕共享的访问。从本质上讲,它可以让您访问媒体数据的任何硬件源。
该对象提供对连接的媒体输入设备(如相机和麦克风)以及屏幕共享的访问。该对象提供了5个api: enumerateDevices()、getDisplayMedia()、getSupportedConstraints()、getUserMedia()、selectAudioOutput()

用途:web端屏幕共享,用于webRTC进行实时音视频,例如远程协作、在线会议演示文件、在线课堂等。
兼容性 :也就辣鸡ie不支持

  • enumerateDevices() 列举可用的媒体输入和输出设备,例如麦克风、相机、耳机等。返回结果未可用设备信息的数组;

  • getDisplayMedia(opitons) 调用后会提示用户选择并授予权限,以将显示内容或其一部分(例如窗口)捕获为MediaStream(媒体内容流),即共享屏幕内容
    参数options举例:getDisplayMedia({ video:true, audio:false })
    说明:video:true指内容流包含视频轨道;audio:false指内容流不包含音频轨道,查看全部参数

  • getSupportedConstraints() 方法返回用户代理(即浏览器)支持的约束列表,数据格式为对象字典,键为约束的属性,值都为true(因为返回的都是支持的约束,所有都为true)。查看约束如何工作的更多信息

  • getUserMedia(options) 方法询问用户是否允许使用媒体输入,即调用录制视频或者录音等功能,该媒体输入会产生包含所请求媒体类型的轨道,包括视频轨道(由硬件或虚拟视频源产生,例如相机、视频录制设备、屏幕共享服务等)、音频轨道(类似地,由物理或虚拟音频源,如麦克风、A/D 转换器等),可能还有其他音轨类型。
    参数options:getUserMedia({ video:true, audio:false })
    说明:该参数只有video和audio两个属性,即授予录制视频和录音权限。

  • selectAudioOutput() 方法提示用户选择特定的音频输出设备,例如扬声器或耳机。

//enumerateDevices() 列举可用媒体
async function getMediaDevices() {
    if (!navigator.mediaDevices?.enumerateDevices) {
      console.log("enumerateDevices() not supported.");
    } else {
      // List cameras and microphones.
      let mediaDevicesList;
      
      try {
         mediaDevicesList = await navigator.mediaDevices.enumerateDevices();
      } catch (err) {
        console.error(`Error: ${err}`);
      }
      return mediaDevicesList;
    }
}


//getDisplayMedia() 屏幕共享
async function startCapture(displayMediaOptions) {
  let captureStream;
  
  try {
    captureStream = await navigator.mediaDevices.getDisplayMedia(
      displayMediaOptions
    );
  } catch (err) {
    console.error(`Error: ${err}`);
  }
  return captureStream;
}

//getUserMedia() 开启录制视频/录音
async function startMediaInput(displayMediaOptions) {
  let stream = null;

  try {
    stream = await navigator.mediaDevices.getUserMedia(constraints);
    /* use the stream */
  } catch (err) {
    /* handle the error */
  }
}

//selectAudioOutput() 选择音频输出设备
function selectAudioOutput(displayMediaOptions) {
  if (!navigator.mediaDevices.selectAudioOutput) {
    alert("selectAudioOutput() not supported.");
    return;
  }
  // Display prompt and log selected device or error
  navigator.mediaDevices
    .selectAudioOutput()
    .then((device) => {
      list3.innerText = JSON.stringify(device)
      console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`);
    })
    .catch((err) => {
      console.error(`${err.name}: ${err.message}`);
    });
}

5. permissions(权限管理)

Navigator.permissions 属性返回一个对象Permissions,该对象可用于查询和更新Permissions API涵盖的 API 的权限状态。
Permissions对象有三个实例方法:query()、request()、requestAll()、revoke()
注意:request()、requestAll()、revoke()方法都不可用!
兼容性:又是ie!

  • query() 用于查询指定权限的权限状态,例如 navigator.permissions.query({ name: " camera" })
    可查询的权限有:camera相机,clipboard-read剪切板读取,clipboard-write剪切板写入、geolocation地理位置、microphone麦克风、notifications通知、persistent-storage持久化存储、gyroscope陀螺仪,push推送通知

image.png

6. WakeLock(屏幕唤醒)

WakeLock在开启屏幕自动息屏时,浏览器会尝试阻止设备屏幕变暗、完全关闭或显示屏幕保护程序
兼容性:兼容性一般,慎用! navigator.wakeLock 保持屏幕唤醒状态:

let lock;
document.addEventListener("click", async () => {
  try {
    if (lock) {
      lock.release();
      return;
    }
 
    lock = await navigator.wakeLock.request("screen");
 
    lock.addEventListener("release", () => {
      lock = null;
    });
  } catch (err) {
    console.log(`${err.name}, ${err.message}`);
  }
});

7. userActivation(用户是否交互检查)

userActivation 返回一个UserActivation对象,该对象包含有关当前窗口的用户激活状态的信息。该对象有两个属性:isActive,hasBeenActive

用途:常用来检查最近是否执行了用户手势或检查是否曾经执行过用户手势
兼容性:IE不支持,safari 16.4版本以上才支持

  • isActive 用来判断短暂激活状态,即检查用户最近是否与页面交互,用户与页面的每次交互,都会让页面处于这个状态。但这个状态是有“有效期”的,如果在交互后的一段时间内,用户没有再与页面进行交互,这个状态就会过期。具体的有效期时长由浏览器决定,比如chrome是5秒。
  • hasBeenActive 用来判断粘性激活状态,即检查用户是否与页面交互过,只要交互过一次,就会一直处于这个状态。
if (navigator.userActivation.isActive) {
  // 例如继续请求播放媒体
}

if (navigator.userActivation.hasBeenActive) {
  // 例如继续自动播放动画
}

8. serial(串口通信,连接计算机的外围设备)

serial 提供了从网页查找和连接串口的属性和方法。
用途:可以实现在web端通过串口与硬件通信
兼容性:safari,Firefox,IE不支持

方法:

  • requestPort() 方法获取授权串口,提示用户选择设备,如果未选择任何设备则拒绝(必须在用户激活时调用此方法)。
  • getPorts() 表示连接到源有权访问的主机的串行端口。

事件:

  • connect() 事件:当端口连接到设备时触发的事件。
  • disconnect() 事件: 当端口与设备断开连接时触发的事件。
navigator.serial.addEventListener("connect", (e) => {
  // Connect to `e.target` or add it to a list of available ports.
});

navigator.serial.addEventListener("disconnect", (e) => {
  // Remove `e.target` from the list of available ports.
});

navigator.serial.getPorts().then((ports) => {
  // Initialize the list of available ports with `ports` on page load.
});

button.addEventListener("click", () => {
  const usbVendorId = 0xabcd;
  navigator.serial
    .requestPort({ filters: [{ usbVendorId }] })
    .then((port) => {
      // Connect to `port` or add it to the list of available ports.
    })
    .catch((e) => {
      // The user didn't select a port.
    });
});

9. 其他属性

属性/方法说明
userAgent返回当前浏览器的用户代理字符串,userAgent是可配置的
appName浏览器全名
cookieEnabled返回一个布尔值,来表示当前页面是否启用了 cookie
deviceMemory返回单位为GB的大概的设备内存容量
maxTouchPoints返回当前设备支持的最大同时触摸接触点数。
online返回布尔值,表示浏览器是否联网
userAgent返回浏览器的用户代理字符串
pdfViewerEnabled浏览器是否支持加载PDF文件,如果不支持在线查看,则下载PDF

10. 结语 🍺🍺🍺

再重申一下:本文只记录一些了navigator的属性,下一篇更文再记录下它的方法~
下一篇已更新 传送门

感悟:在了解navigator的过程中,发现了好多新大陆,原来web已经可以实现好多先进性的功能,比如连接VR设备等,虽然好多都是实验中的功能,但是了解他们以后,能够大大拓宽我们的前端视野。不至于在提出需求时,都不知道前端能否能实现😂

这里提供下所有Web API的列表---多的头皮发麻

奉劝各位,别整天琢磨前端已死的事了,前端死不是人💀,大不了找个饭馆去前面端菜(🐶)