Coder Social home page Coder Social logo

blog's Introduction

  • 👋 Hi, I’m @zi.li
  • 👀 I’m interested in Front-end development
  • 目前正在找工作,有看上我的,上海、杭州、合肥地区请联系我。
  • 邮箱:[email protected]

blog's People

Contributors

shiwuqi avatar

Watchers

 avatar

blog's Issues

npm包发布流程

npm发包流程

  1. 注册npm账号(https://www.npmjs.com/)

  2. 登录账号

    • 第一次发包

      npm添加用户账号

      命令:npm adduser

    • 已添加用户账号

      命令:npm login

      查看当前用户:npm whoami

  3. 发布

    命令:npm publish

  4. 更新发布

    npm version <update_type>

    npm publish

问题:

  • code 403

    检查下当前的登录源是否是https://registry.npmjs.org/,命令:**npm config get registry**

    若不是则设为npmjs源,命令:npm config set registry=npm config get registry

  • code 401

    未登录

  • 如果发的包是某个packages下的包,发布是不成功的

    命令:npm publish --access public

性能优化

性能优化

浏览器渲染

构建DOM树、CSSOM树、渲染树

DOM、style加载解析是一起的不会阻塞,script会阻塞DOM渲染

选择器是从右到左的

浏览器遇到link、@import会开启一个新的线程,发送http请求,link是异步的,不会阻塞DOM渲染,@import是同步的,会阻塞DOM渲染,在真实的项目中应该减少@import的使用

优化方案:

  1. 标签语义化和避免深层次嵌套
  2. css选择器渲染是从右到左的,避免嵌套太深
  3. 尽早尽快地把css下载到客户端(充分利用http多请求并发机制)
  4. 避免阻塞的js加载(放到底部)
  5. 减少DOM的回流和重绘

网络交互层面上的优化

  1. DNS解析优化

    每一次的DNS解析时间预计在20~120秒

    • 减少DNS请求次数

    • DNS预获取(DNS Prefetch)

      <link rel='dns-prefetch' href='' />
  2. 减少http请求次数和请求资源大小

    • 资源合并压缩
    • 字体图标
    • Base64
    • gzip
    • 图片懒加载
    • 数据延迟分批加载
    • cdn资源

应用缓存

缓存位置

  • Service Worker: 浏览器独立线程进行缓存
  • Memeory Cache: 内存缓存
  • Disk Cache:硬盘缓存
  • Push Cache: 推送缓存(http2中的)

BFC

一、简介

BFC(Block Formatting Context)块级格式化上下文。它是一个独立的渲染区域,只有Block-level box参与,它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。通俗地讲,BFC是一个容器,用于管理块级元素。

二、触发方式

  • 根元素
  • 浮动元素:float为left、right
  • overflow:auto、scroll、hidden
  • display:inline-block、table-cell、table-cation、table、inline-table、flex、inline-flex、grid、inline-grid
  • position:absolute、fixed

三、布局规则

  • 内部的Box会在垂直方向一个接一个地放置(即块级元素独占一行)
  • BFC的区域不会与float box重叠(实现自适应两栏布局)
  • 内部的Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠(margin重叠三个条件:同属一个BFC、相邻、块级元素)
  • 计算BFC的高度时,浮动元素也参与计算(清除浮动haslayout)
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之亦如此

四、特性

  • BFC会阻止垂直外边距重叠

    按照BFC的定义,只有同属于一个BFC时,两个元素才有可能发生垂直margin的重叠,这个包括相邻元素或者嵌套元素,只要他们之间没有阻挡(比如边框、非空内容、padding等)就会发生margin重叠。

    1. 相邻兄弟元素margin重叠问题

      <style>
          .child {
              color: #fff;
              background-color: #888;
              width: 200px;
              line-height: 100px;
              text-align: center;
              margin: 100px;
          }
      </style>
      <body>
          <div class='child'>Child1</div>
          <div class='child'>Child2</div>
      </body>

      垂直重叠

      上面两个div上下之间的距离本该为200px,然而实际上只有100px,发生了重叠。解决办法是在div外面包裹一层容器,并触发该容器生成一个BFC,那么两个div便不属于同一个BFC,就不会发生margin重叠了。

      <style>
          .parent {
              overflow: hidden;
          }
          .child {
              color: #fff;
              background-color: #888;
              width: 200px;
              line-height: 100px;
              text-align: center;
              margin: 100px;
          }
      </style>
      <body>
          <div class='child'>Child1</div>
          <div class='parent'>
          	<div class='child'>Child2</div>
          </div>
      </body>

      清除垂直重叠

    2. 父子元素margin重叠问题

      <style>
          .child1 {
              width: 100px;
              height: 100px;
          }
          .parent {
              background-color: turquoise;
          }
          .child2 {
              background-color: yellowgreen;
              margin: 40px;
          }
      </style>
      <body>
          <div class='child1'>Child1</div>
          <div class='parent'>
          	<div class='child2'>Child2</div>
          </div>
      </body>

      父子元素margin重叠

      上图parent元素与child2元素之间理论上本该有个40px的上下margin值,然而实际上父子元素并没有存在margin值,与此同时,parent与child1之间的间距为40px。解决方法:给parent元素添加overflow: hidden;或者overflow:auto;使其形成一个BFC,也可以在parent元素中添加border: 1px solid ; 或是padding: 1px;

      清除父子元素重叠

  • BFC不会重叠浮动元素

    <style>
        .box1 {
            width: 100px;
            height: 100px;
            float: left;
            background-color: lightblue;
        }
        .box2 {
            width: 200px;
            height: 200px;
            background-color: #eee;
        }
    </style>
    <body>
        <div class='box1'>
            我是一个左浮动的元素
        </div>
        <div class='box2'>
            喂喂喂!大家不要生气嘛,生气会犯嗔戒的。悟空你也太调皮了,
    		我跟你说过叫你不要乱扔东西,你怎么又……你看,我还没说完你就把棍子给扔掉了!
    		月光宝盒是宝物,你把它扔掉会污染环境,要是砸到小朋友怎么办,就算砸不到小朋友,
    		砸到花花草草也是不对的。
        </div>
    </body>

    浮动元素chongdie

    上图中,文字围绕着浮动元素排列,不过在这里,这显然不是我们想要的。解决办法:给box2元素添加overflow: auto; 使其形成一个BFC。

    重叠浮动元素

  • BFC可以包含浮动(清除浮动)

    <style>
        .parent {
            background-color: turquoise;
        }
        .child {
            width: 100px;
            height: 100px;
            float: left;
            border: 1px solid #000;
        }
    </style>
    <body>
        <div class='parent'>
            <div class='child'></div>
            <div class='child'></div>
        </div>
    </body>

    浮动

    由于父div内的两个div元素浮动,脱离了文档流,父div内容宽度为0(高度塌陷),未能将子元素包裹住。解决办法:把父div变成一个BFC。

    清除浮动

React组件复用

React组件复用在版本16.8以前一般是通过高阶组件和render props实现,16.8以后则可以通过hooks实现。下面我们以一个计时器为例看看这三种方式是如何实现的。

高阶组件

const WrapTimer = (WrapComponent: React.ComponentType<any>) => {
    return class extends React.Component<WrapTimerPropsType, TimeType> {
        timer: NodeJS.Timer | null = null;
        constructor(props: any) {
            super(props);
            this.state = {
                hour: '00',
                minute: '00',
                second: '00',
            }
            this.timer = null
        }

        componentDidMount() {
            this.timer && clearInterval(this.timer);
            if (this.props.time) {

                this.setState({
                    ...this.props.time
                }, () => {
                    this.countDown();
                })
            } else {
                this.countDown();
            }
        }

        countDown = () => {
            this.timer = setInterval(() => {
                this.setState((state: TimeType) => {
                    let { hour, minute, second } = state;
                    if (second >= '59') {
                        second = '00';
                        const newMinute = Number(minute) + 1;
                        minute = newMinute > 9 ? newMinute.toString() : addZero(newMinute);
                    } else if (minute >= '59') {
                        minute = '00';
                        const newHour = Number(hour) + 1;
                        hour = newHour > 9 ? newHour.toString() : addZero(newHour);
                    } else {
                        const newSecond = Number(second) + 1;
                        second = newSecond > 9 ? newSecond.toString() : addZero(newSecond);
                    }
                    return {
                        hour,
                        minute,
                        second,
                    }
                })
            }, 1000)
        };

        componentWillUnmount() {
            this.timer && clearInterval(this.timer);
        }

        render() {
            return (
                <WrapComponent {...this.state} />
            )
        }
    }
}

源码地址

render props

export default class RenderTimer extends React.Component<{ render: (state: TimeType) => React.ReactNode; time?: TimeType; }, TimeType> {
    timer: NodeJS.Timer | null = null;
    constructor(props: any) {
        super(props);
        this.state = {
            hour: '00',
            minute: '00',
            second: '00',
        }
        this.timer = null
    }

    componentDidMount() {
        this.timer && clearInterval(this.timer);
        if (this.props.time) {
            this.setState({
                ...this.props.time
            }, () => {
                this.countDown();
            })
        } else {
            this.countDown();
        }
    }

    countDown = () => {
        this.timer = setInterval(() => {
            this.setState((state: TimeType) => {
                let { hour, minute, second } = state;
                if (second >= '59') {
                    second = '00';
                    const newMinute = Number(minute) + 1;
                    minute = newMinute > 9 ? newMinute.toString() : addZero(newMinute);
                } else if (minute >= '59') {
                    minute = '00';
                    const newHour = Number(hour) + 1;
                    hour = newHour > 9 ? newHour.toString() : addZero(newHour);
                } else {
                    const newSecond = Number(second) + 1;
                    second = newSecond > 9 ? newSecond.toString() : addZero(newSecond);
                }
                return {
                    hour,
                    minute,
                    second,
                }
            })
        }, 1000)
    };

    componentWillUnmount() {
        this.timer && clearInterval(this.timer);
    }

    render() {
        return (
            <div>{this.props.render(this.state)}</div>
        )
    }
}

源码地址

hooks

export default function useTimer(props: { time?: TimeType }) {
  const time = props.time || {
    hour: '00',
    minute: '00',
    second: '00',
  };
  const [date, setDate] = useState(time)

  useEffect(() => {
    timer && clearInterval(timer);
    countDown();
    return () => {
      timer && clearInterval(timer);
    }
  }, [props.time]);

  // 倒计时
  const countDown = () => {
    timer = setInterval(() => {
      setDate((date: TimeType) => {
        let { hour, minute, second } = date;
        if (second >= '59') {
          second = '00';
          const newMinute = Number(minute) + 1;
          minute = newMinute > 9 ? newMinute.toString() : addZero(newMinute);
        } else if (minute >= '59') {
          minute = '00';
          const newHour = Number(hour) + 1;
          hour = newHour > 9 ? newHour.toString() : addZero(newHour);
        } else {
          const newSecond = Number(second) + 1;
          second = newSecond > 9 ? newSecond.toString() : addZero(newSecond);
        }
        return {
          hour,
          minute,
          second,
        }
      })
    }, 1000)
  };

  return date;
}

源码地址

通过上面三种方式,我们可以单独把计时器的逻辑部分抽离出来,实现组件的复用。在React16.8版本以前,通过高阶组件和render props可以实现,但是这类方案需要重新组织你的组件结构,这可能会很麻烦,使你的代码难以理解,而使用 Hook 从组件中提取状态逻辑,使得这些逻辑可以单独测试并复用,Hook 使你在无需修改组件结构的情况下复用状态逻辑。 这使得在组件间或社区内共享 Hook 变得更便捷。

Linux命令

Linux命令

yum install nginx 安装插件

netstat -lntup 查看运行的端口

locate nginx.conf 查找nginx.conf文件

systemctl restart nginx 重启nginx

nginx -c /path/to/nginx.conf 以特定目录下的配置文件启动nginx

nginx -s stop 快速停止nginx

nginx -s quit 完整有序的停止nginx

nginx -s reload 修改配置后重新加载生效

nginx -s reopen 重新打开日志文件

rm -rf 删除文件夹

rm -f 删除文件

cp index.js demo.js 复制一个文件

cp -a dir1 dir2 复制一个目录

cp -r dir1 dir2 复制一个目录及子目录

find / -name file 从'/'开始进入根文件系统搜索文件和目录

find / -user user 搜索属于用户‘user’的文件和目录

find /home/user -name *.bin 在目录'/home/user'中搜索带有'.bin'结尾的文件

gzip file 压缩文件

编辑文件

​ vi nginx.conf 查看nginx.conf文件

​ 接着恩i键

​ 接着编辑文件

​ 编辑完成后 esc->: ->wq! enter

pwd 查看当前所在路径

Node节点

Node.nodeType

nodeType属性用来区分不同类型的节点。

语法:var type = node.nodeType

例:var bodyType = document.body.nodeType

节点类型常量

  • Node.ELEMENT_NODE 值:1 元素节点,例如div、p
  • Node.TEXT_NODE 值:3 Element或Attr中实际的文字
  • Node.CDATA_SECTION_NODE 值:4 CDAASection,例如<!CDATA[[...]]>
  • Node.PROCESSING_INSTRUCTION_NODE 值: **7 ** 用于XML文档的processingIntruction,例如声明
  • Node.COMMENT_NODE 值:8 Comment节点
  • Node.DOCUMENT_NODE 值: 9 Document节点
  • Node.DOCUMENT_TYPE_NODE 值: 10 描述文档类型的DocumentType节点,例如
  • Node.DOCUMENT_FRGMENT_NODE 值: 11 DocumentFragment节点

Node.nodeValue

返回或设置当前节点的值

Node.parentNode

返回当前节点的父节点,若没有,则返回null

Node.parentElement

返回当前节点的父节点Element,若没有,则返回null

Node.previousSibling(只读)

返回当前节点同辈的前一个节点,若没有,则返回null

Node.textContent

返回或设置一个元素内所有子节点及其后代的文本

Node.childNodes(只读)

返回一个包含了该节点所有子节点的实时的NodeList

Node.firstChild(只读)

返回该节点的第一个子节点,若没有,则返回null

Node.lastChild(只读)

返回该节点的最后一个子节点,若没有,则返回null

Node.nextSibling(只读)

返回与该节点同级的下一个节点,若没有,则返回null

Node.nodeName(只读)

返回一个包含该节点名字的DOMString

Node.isConnected(只读)

返回一个布尔值用来检测该节点是否已连接(直接或者间接)到一个上下文对象上,比如通常DOM情况下的Document对象,或者在shadow DOM情况下的ShadowRoot对象。

Node.baseURI(只读)

返回一个表示base URL的DOMString

下面是一个爬取页面信息的例子:

(function(document_root) {
    let __html = '', node = document_root.firstChild;
    while(node) {
        switch(node.nodeType) {
            case Node.ELEMENT_NODE:
                __html += node.outerHTML;
                break;
            case Node.TEXT_NODE:
                __html += node.nodeValue;
                break;
            case Node.CDATA_SETION_NODE:
                __html += '<![CDATA[' + node.nodeValue + ']]>';
                break;
            case Node.COMMENT_NODE:
                __html += '<!--' + node.nodeValue + '-->';
                break;
            case Node.DOCUMENT_TYPE_NODE:
                __html += "<!DOCTYPE " + node.name + (node.publicId ? ' PUBLIC "' + node.publicId + '"' : '') + (!node.publicId && node.systemId ? ' SYSTEM' : '') + (node.systemId ? ' "' + node.systemId + '"' : '') + '>\n';
                break;
        }
        node = node.nextSibling;
    }
    return __html;
})(document)

参考文章:MDN

深入探讨React Hooks是如何实现的?

Hooks是在用户界面中封装有状态行为和副作用的最简单的方法。它的设计需要对JavaScript中的闭包有一定得了解。

什么是闭包?

You Don’t Know JavaScript一书中是这样定义的:

“闭包是指一个函数能够记住并访问其词法作用域,即使该函数在其词法作用域之外执行”

function useState(initialValue) {
  var _val = initialValue;
  function state() {
    return _val;
  }
  function setState(newVal) {
    _val = newVal;
  }
  return [state, setState];
}

var [count, setCount] = useState(0);
console.log(count());
setCount(1);
console.log(count());

在这里,我们模仿React useState创建了一个函数。在我们的useState函数中,有2个内部函数,state和setState。state返回_val上面定义的局部变量,并将setState局部变量设置为传递给它的参数(即newVal)。

在函数组件中使用

function Counter() {
  const [count, setCount] = useState(0);
  return {
    click: () => setCount(count() + 1),
    render: () => console.log('render: ', { count: count() })
  }
}

const c = Counter();
c.render();
c.click();
c.render();

这里我们没有DOM渲染,用console.log打印出来。上面函数是模拟函数组件的渲染和用户的操作。

上面的函数中我们返回的state都是函数,如果我们想和React useState一样,返回的是一个变量,则有一个错误:

function useState(initialValue) {
  var _val = initialValue;
  function setState(newVal) {
    _val = newVal;
  }
  return [_val, setState]
}

var [count, setCount] = useState(0);
console.log(count); // 0
setCount(1);
console.log(count); // 0

这里我们可以看到,当我们从useState拿到count后,count始终是初始化时的值。

变量state

const MyReact = (function() {
  let _val;
  return {
    render(Component) {
      const Comp = Component()
      Comp.render()
      return Comp
    },
    useState(initialValue) {
      _val = _val || initialValue
      function setState(newVal) {
        _val = newVal
      }
      return [_val, setState]
    }
  }
})();

function Counter() {
  const [count, setCount] = MyReact.useState(0)
  return {
    click: () => setCount(count + 1),
    render: () => console.log('render:', { count })
  }
}

let App;
App = MyReact.render(Counter); // render: { count: 0 }
App.click();
App = MyReact.render(Counter); // render: { count: 1 }

js继承

js继承

  • 原型继承

    function Parent (name) {
        this.name = name;
    }
    
    Parent.prototype.getName = function () {
        return this.name;
    }
    
    function Child (name, age) {
        this.name = name;
        this.age = age;
    }
    
    Child.prototype = new Parent();

    缺点:

    1. 实例无法向父类构造函数传参
    2. 所有实例都会共享父类实例的属性
  • 构造函数式继承

    function Parent (name) {
        this.name = name;
    }
    
    Parent.prototype.getName = function () {
        return this.name;
    }
    
    function Child (name, age) {
        Parent.call(this, name);
        this.age = age;
    }

    缺点:

    1. 没有继承父类原型上的方法
  • 组合继承

    function Parent (name) {
        this.name = name;
    }
    
    Parent.prototype.getName = function () {
        return this.name;
    }
    
    function Child (name, age) {
        Parent.call(this, name);
    }
    
    Child.prototype = new Parent();
    Child.prototype.constructor = Child;

    缺点:

    1. 父类的构造函数被调用两次
  • 寄生组合继承

    function _inherits (subClass, superClass) {
        subClass.prototype = Object.create(superClass && superClass.prototype);
        subClass.prototype.constructor = subClass;
    }
    
    function Parent (name) {
        this.name = name;
    }
    
    Parent.prototype.getName = function () {
        return this.name;
    }
    
    function Child (name, age) {
        Parent.call(this, name);
        this.age = age;
    }
    
    _inherits(Child, Parent);
    
    Child.prototype.getAge = function () {
        return this.age;
    }
  • class继承

    class Parent {
        constructor(name) {
            this.name = name;
        }
        
        getName() {
            return this.name;
        }
    }
    
    class Child extends Parent {
        constructor(name, age) {
            super(name); // Parent.call(this)
            this.age = age;
        }
    }
    // class继承用babel转为es5
    "use strict";
    
    function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
    
    function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
    
    function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
    
    function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
    
    function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
    
    function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
    
    function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
    
    function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
    
    function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }
    
    function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
    
    function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
    
    function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
    
    var Parent = /*#__PURE__*/function () {
      function Parent(name) {
        _classCallCheck(this, Parent);
    
        this.name = name;
      }
    
      _createClass(Parent, [{
        key: "getName",
        value: function getName() {
          return this.name;
        }
      }]);
    
      return Parent;
    }();
    
    var Child = /*#__PURE__*/function (_Parent) {
      _inherits(Child, _Parent);
    
      var _super = _createSuper(Child);
    
      function Child(name, age) {
        var _this;
    
        _classCallCheck(this, Child);
    
        _this = _super.call(this, name); // Parent.call(this)
    
        _this.age = age;
        return _this;
      }
    
      return Child;
    }(Parent);

    所以,ES5的继承实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.call(this));ES6的继承机制完全不同,实质是先将父类实例对象的属性和方法加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this

JavaScript获取音视频

JavaScript获取音视频

MediaDevidces.getUserMedia()

MediaDevices.getUserMedia()方法提示用户允许使用一个视频和/或一个音频输入设备,例如相机或屏幕共享和/或麦克风。它返回一个Promise对象,成功后会resolve回调一个MediaStream对象。若用户拒绝了使用权限,或者需要的媒体源不可用,promisereject回调一个 PermissionDeniedError 或者 NotFoundError

function getNavigatorUserMedia() {
    if (navigator.mediaDevices === undefined) {
        navigator.mediaDevices = {};
    }
    if (navigator.mediaDevices.getUserMedia === undefined) { // 兼容低版本浏览器
        navigator.mediaDevices.getUserMedia = function (constraints) {
            const getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
            if (!getUserMedia) {
                return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
            }
            return new Promise((resolve, reject) => {
                getUserMedia.call(navigator, constraints, resolve, reject);
            });
        }
    }
    return navigator;
}
getNavigatorUserMedia().mediaDevices.getUserMedia({ video: { width, height }, audio: true })
    .then((stream) => {
        setStatus('success');
        const video = document.querySelector('video');
        if ('srcObject' in video) {
            video.srcObject = stream;
        } else {
            video.src = window.URL.createObjectURL(stream);
        }
        video.onloadedmetadata = function () {
            video.play();
        };
    })
    .catch((error) => {
        console.log(error);
    });

在TypeScript兼容低版本浏览器写法

function getNavigatorUserMedia() {
    let navigatorCopy = navigator as any;
    if (navigatorCopy.mediaDevices === undefined) {
        navigatorCopy.mediaDevices = {};
    }
    if (navigatorCopy.mediaDevices.getUserMedia === undefined) { // 兼容低版本浏览器
        navigatorCopy.mediaDevices.getUserMedia = function (constraints: MediaStreamConstraints | undefined) {
            const getUserMedia = navigatorCopy.webkitGetUserMedia || navigatorCopy.mozGetUserMedia;
            if (!getUserMedia) {
                return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
            }
            return new Promise((resolve, reject) => {
                getUserMedia.call(navigatorCopy, constraints, resolve, reject);
            });
        }
    }
}
getNavigatorUserMedia().mediaDevices.getUserMedia({ video: { width, height }, audio: true })
    .then((stream: MediaStream) => {
        setStatus('success');
        const video = document.querySelector('video') as HTMLMediaElement & { src: string };
        if ('srcObject' in video) {
            video.srcObject = stream;
        } else {
            video.src = window.URL.createObjectURL(stream);
        }
        video.onloadedmetadata = function () {
            video.play();
        };
    })
    .catch((error: any) => {
        console.log(error);
    });

参考连接:MDN web docs

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.