[TOC] <br/><br/><br/> # <b style="color:#4F4F4F;">简介说明</b> 原文链接: - [硬件加速中的“层”和层叠上下文中的“层”](https://mp.weixin.qq.com/s/xuWgEMh9Y8Eq_Go2uBH24g) - [浏览器层合成与页面渲染优化](https://juejin.cn/post/6844903966573068301) - [浏览器跨页面通信方案](https://juejin.cn/post/6919334960818192391) - [Cookie的SameSite了解吧,那SameParty呢](https://cloud.tencent.com/developer/article/2062315) - [你不知道的前端高分屏图片加载方案](https://mp.weixin.qq.com/s/TaHLyibhciT2uk35T2367Q) - [通过几行 JS 就可以读取电脑上的所有数据](https://mp.weixin.qq.com/s/E4EA8SfgI_zBlVmVEBGQBA) - [浏览器及nodeJS中的EventLoop事件循环机制](https://zhuanlan.zhihu.com/p/389250124) - [Deco 编辑器开放性技术架构解析](https://jishuin.proginn.com/p/763bfbd7124e) - [基于自然流布局的可视化拖拽搭建平台设计方案](https://mp.weixin.qq.com/s/WFwGw4OkGOKopIgz4rrCTg) - [js判断客户端是PC端还是移动端访问](https://hotsuitor.blog.csdn.net/article/details/90905730) - [基于FFmpeg + nginx + flv.js 实现的网页 ▶(播放) 摄像头](https://mp.weixin.qq.com/s/oLfrrppukfflHwvMusugTg) - [自动化生成骨架屏的技术方案设计与落地](https://mp.weixin.qq.com/s/z6ovNVlfd0Nc3_FwqMxXow) - [在浏览器控制台安装 NPM 包](https://mp.weixin.qq.com/s/dDAC758fUu8Ia4gtfuwzYg) - [编写一个浏览器扩展](https://mp.weixin.qq.com/s/m-MYwM4CXZ1lR_zyvBLJiQ) - [一键支持暗色模式](https://mp.weixin.qq.com/s/AHHxUatITmwdRr-OyHQHQw) - [前端 “一键换肤“ 的几种方案](https://mp.weixin.qq.com/s/_wOihA75a5EFpk7Ltil9mQ) - [前端换肤的N种方案](https://mp.weixin.qq.com/s/4W24J-B6wkBaCzbWpK3ppg) - [Dooring可视化之从零实现动态表单设计器](https://mp.weixin.qq.com/s/9z8DPJ9tdQIav6sHYdE9XQ) - [划线高亮和插入笔记的技术实现](https://mp.weixin.qq.com/s/ejLJ4LNnxOXgIKQgBsX9vg) - [前端跨页面通信](https://blog.csdn.net/p3118601/article/details/88966864) - [复杂场景下唤起App实践](https://juejin.cn/post/7039974294926917640) - [如何在网页中使用响应式图像](https://mp.weixin.qq.com/s/RuejbQ92aSnvF_-KF4-dxQ) - [可视化大屏开发的一点思考](https://mp.weixin.qq.com/s/bM4sGZHEWmeNdCKmDLeQCw) - [虚拟 DOM 到底是什么](https://mp.weixin.qq.com/s/zcUXHEqtoz6pYlp1KUeUKw) - [手写一个虚拟DOM库,彻底让你理解diff算法](https://mp.weixin.qq.com/s/au2Z5qOh8451dSbQ1Wo-Pw) - [小程序的鼻祖在国内就这么消亡了](https://mp.weixin.qq.com/s/11jacUC53QOiR3rUR5pPLA) - [实现一个很牛逼的扫码功能](https://mp.weixin.qq.com/s/PTPdFxQFM9ysLTfFAPygCA) - [浅聊WebRTC视频通话](https://mp.weixin.qq.com/s/sGvfR9McNu-Reyi-3b0MTg) - [三种视频流浏览器播放解决方案](https://juejin.cn/post/6844903953126129671) - [前端网页如何打开一个PC本地应用](https://juejin.cn/post/6844903989155217421) - [Python 已可在浏览器端运行,来抢前端饭碗](https://mp.weixin.qq.com/s/gusjKuSzEyJPFhZLkL9mGA) - [Share Element动画实现案例](https://stackblitz.com/edit/nextjs-as4uje?file=README.md) - [前端应该知道的:开放图谱协议(The Open Graph protocol)](https://segmentfault.com/a/1190000040863000) - [RSS用于发布站点更新的数种 XML 文档格式](https://developer.mozilla.org/zh-CN/docs/Glossary/RSS) - [RSS 教程](https://www.runoob.com/rss/rss-tutorial.html) - [微前端-最容易看懂的微前端知识](https://zhuanlan.zhihu.com/p/141530392) - [架构设计:微前端架构](https://zhuanlan.zhihu.com/p/79388540) - [初探 MicroApp,一个极致简洁的微前端框架](https://mp.weixin.qq.com/s/gNS6FUhPWHD-IXdlUAop5A) - [Web App Manifest](https://developer.mozilla.org/zh-CN/docs/Web/Manifest) - [ARIA 状态及属性 - 无障碍](https://developer.mozilla.org/zh-CN/docs/Web/Accessibility/ARIA/Attributes) - [OGC标准WMTS服务概念与地图商的瓦片编号流派-web地图切片加载](https://zhuanlan.zhihu.com/p/393081170) - [只需要点击页面上的元素,就能够自动打开 vscode 定位到源代码,支持多框架!](https://mp.weixin.qq.com/s/lW_VWn9dPZyMNgTfHA4Nqw) ``` 版本:Browser常见问题 作用:Browser常见问题 ``` <br/> # <b style="color:#4F4F4F;">浏览器内核</b> <br/> # <span style="color:#619BE4">gecko</span> ***** gecko浏览器内核,开源内核 <br/> ### 示例内容 <span style="color:red;">1. 谁用过</span> ``` 网景公司开发的Netscape Netscape Mozilla FireFox ``` <br/> # <span style="color:#619BE4">gecko2</span> ***** 第二代的gecko内核 <br/> ### 示例内容 <span style="color:red;">1. 谁用过</span> ``` Netscape死掉后,由于IE垄断严重,标准和W3C脱节,导致不满微软的员工叛逃 一起创办了Mozilla公司,并且以Trident内核重新编写,而且开源 Mozilla FireFox ``` <br/> # <span style="color:#619BE4">trident</span> ***** trident浏览器内核 <br/> ### 示例内容 <span style="color:red;">1. 谁用过</span> ``` 网景公司膨胀了,想要做操作系统,威胁到了微软 微软收购了Mosaic公司,开发了Trident内核 IE浏览器 ``` <br/> # <span style="color:#619BE4">webkit</span> ***** webkit内核 <br/> ### 示例内容 <span style="color:red;">1. 谁用过</span> ``` gecko和trident贪大包全,把各种内容加入浏览器导致运行缓慢, 勤劳追求极致的苹果公司开发了webkit内核用于Safari浏览器 Google很喜欢这个内核,于是拿来用了 Firefox也很喜欢,也用了 Safari Chrome Mozilla FireFox ``` <span style="color:red;">2. 发展史</span> ![web发展史](https://img.kancloud.cn/b5/ec/b5ecf0cbc4c93400fa3ec828df8a12b0_720x341.jpg) <br/> # <span style="color:#619BE4">blink</span> ***** blink内核 <br/> ### 示例内容 <span style="color:red;">1. 谁用过</span> ``` 2013谷歌和苹果发生矛盾分道扬镳,谷歌自主开发了blink内核 blink其实是webkit的一个分支,为了切断与苹果的关系 Chrome ``` <br/> # <b style="color:#4F4F4F;">常见问题</b> <br/> # <span style="color:#619BE4">判断客户端是PC端还是移动端</span> ***** 判断客户端是PC端还是移动端 <br/> ### 示例内容 <span style="color:red">1. 解决代码</span> ``` function IsPC(){ var userAgentInfo = navigator.userAgent; var Agents = new Array("Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"); var flag = true; for (var v = 0; v < Agents.length; v++) { if (userAgentInfo.indexOf(Agents[v]) > 0) { flag = false; break; } } return flag; } if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) { //alert(navigator.userAgent); window.location.href ="iPhone.html"; } else if (/(Android)/i.test(navigator.userAgent)) { //alert(navigator.userAgent); window.location.href ="Android.html"; } else { window.location.href ="pc.html"; }; ``` <br/> # <span style="color:#619BE4">判断用户网络类型</span> ***** 判断用户网络类型 <br/> ### 示例内容 <span style="color:red">1. 解决代码</span> ``` getNetworkType() function getNetworkType() { var ua = navigator.userAgent; var networkStr = ua.match(/NetType\/\w+/) ? ua.match(/NetType\/\w+/)[0] : 'NetType/other'; networkStr = networkStr.toLowerCase().replace('nettype/', ''); var networkType; switch(networkStr) { case 'wifi': networkType = 'wifi'; break; case '4g': networkType = '4g'; break; case '3g': networkType = '3g'; break; case '3gnet': networkType = '3g'; break; case '2g': networkType = '2g'; break; default: networkType = 'other'; } alert(networkStr) } ``` <br/> # <span style="color:#619BE4">判断是否支持Passive</span> ***** 判断是否支持Passive <br/> ### 示例内容 <span style="color:red">1. 解决代码</span> ``` // ref https://github.com/WICG/EventListenerOptions/pull/30 function isPassive() { var supportsPassiveOption = false; try { addEventListener("test", null, Object.defineProperty({}, 'passive', { get: function () { supportsPassiveOption = true; } })); } catch (e) { } return supportsPassiveOption; } ``` <br/> # <span style="color:#619BE4">多图加载完毕回调函数</span> ***** 多图加载完毕回调函数 <br/> ### 示例内容 <span style="color:red">1. 解决代码</span> ``` var img = [], flag = 0, mulitImg = [ 'http://www.daqianduan.com/wp-content/uploads/2017/03/IMG_0119.jpg', 'http://www.daqianduan.com/wp-content/uploads/2017/01/1.jpg', 'http://www.daqianduan.com/wp-content/uploads/2015/11/jquery.jpg', 'http://www.daqianduan.com/wp-content/uploads/2015/10/maid.jpg' ]; var imgTotal = mulitImg.length; for(var i = 0 ; i < imgTotal ; i++){ img[i] = new Image() img[i].src = mulitImg[i] img[i].onload = function(){ //第i张图片加载完成 flag++ if( flag == imgTotal ){ //全部加载完成 } } } ``` <span style="color:red">2. 使用Promise</span> ``` let mulitImg = [ 'http://www.daqianduan.com/wp-content/uploads/2017/03/IMG_0119.jpg', 'http://www.daqianduan.com/wp-content/uploads/2017/01/1.jpg', 'http://www.daqianduan.com/wp-content/uploads/2015/11/jquery.jpg', 'http://www.daqianduan.com/wp-content/uploads/2015/10/maid.jpg' ]; let promiseAll = [], img = [], imgTotal = mulitImg.length; for(let i = 0 ; i < imgTotal ; i++){ promiseAll[i] = new Promise((resolve, reject)=>{ img[i] = new Image() img[i].src = mulitImg[i] img[i].onload = function(){ //第i张加载完成 resolve(img[i]) } }) } Promise.all(promiseAll).then((img)=>{ //全部加载完成 }) ``` <br/> # <span style="color:#619BE4">阻止双击放大和双指缩放</span> ***** 阻止双击放大和双指缩放 <br/> ### 示例内容 <span style="color:red">1. 解决代码</span> ``` <script> window.onload = function () { document.addEventListener('touchstart', function (event) { if (event.touches.length > 1) { event.preventDefault(); } }); let lastTouchEnd = 0; document.addEventListener('touchend', function (event) { let now = (new Date()).getTime(); if (now - lastTouchEnd <= 300) { event.preventDefault(); } lastTouchEnd = now; }, false); } </script> ``` <br/> # <span style="color:#619BE4">将屏幕宽度分为24个rem</span> ***** 将屏幕宽度分为24个rem <br/> ### 示例内容 <span style="color:red">1. 解决代码</span> ``` <script> let html = document.documentElement; let deviceWidth = html.clientWidth; let GridNumber=24; html.style.fontSize = `${deviceWidth / GridNumber}px`; </script> ``` <br/> # <span style="color:#619BE4">URL scheme跳转方案</span> ***** URL scheme跳转方案 <br/> ### 示例内容 <span style="color:red">1. 解决代码</span> ``` function clickMusic() { setTimeout(function() { alert('It seems that your device does not support our feature.'); }, 1000); document.write('<iframe style="border:none; width:1px; height:1px;" src="orpheus://song/1400256289"></iframe>'); } ``` <br/> # <span style="color:#619BE4">滚动穿透</span> ***** 解决移动端遮罩层滚动穿透问题 <br/> ### 示例内容 <span style="color:red">1. 解决代码</span> ``` function fixedBody() { var scrollTop = document.body.scrollTop || document.documentElement.scrollTop; document.body.style.cssText += 'position:fixed;top:-' + scrollTop + 'px;'; } function looseBody() { var body = document.body; body.style.position = ''; var top = body.style.top; document.body.scrollTop = document.documentElement.scrollTop = -parseInt(top); body.style.top = ''; } var mask = document.getElementById("modal"); function open() { fixedBody(); mask.style.display = 'block'; } function close() { mask.style.display = 'none'; looseBody(); } ``` <br/> # <span style="color:#619BE4">点击穿透</span> ***** 解决移动端click事件300ms延迟后再执行,导致弹出层消失底层元素被点击 <br/> ### 示例内容 <span style="color:red">1. 解决代码</span> ``` 1. 不使用带有click事件的标签,统一 touch 事件去管理 2. 加一个遮挡350ms延迟后再去除掉 touchend时禁用默认事件 mask.addEventListener("touchend", function (e) { e.preventDefault(); }) ``` <br/> # <span style="color:#619BE4">检查控制台被打开</span> ***** 检查控制台被打开 <br/> ### 示例内容 <span style="color:red">1. 解决代码</span> ``` 第一个是 sindresorhus 大神写的 devtools-detect,算是全平台兼容(除IE),但独立窗口打开的时候是检测不到的。 另一个是咱们国人 zswang 写的 jdetects,目测也是 Chrome only,当然我的灵感也来至于他。 第三种 利用正则 (function () { var re = /x/; var i = 0; console.log(re); re.toString = function () { return alert('第 ' + (++i) + ' 次打开控制台'); }; })(); ``` <br/> # <span style="color:#619BE4">监听全屏改变事件</span> ***** 监听全屏改变事件 <br/> ### 示例内容 <span style="color:red;">1. 解决代码</span> ``` function checkFull() { var isFull = document.fullscreenEnabled || window.fullScreen || document.webkitIsFullScreen || document.msFullscreenEnabled; if (isFull === undefined) isFull = false; return isFull; } $(window).resize(function () { if (!checkFull()) { console.log("退出全屏"); } }); ``` <br/> # <span style="color:#619BE4">取消默认事件</span> ***** 取消默认事件 <br/> ### 示例内容 <span style="color:red;">1. 解决代码</span> ``` window.addEventListener(‘touchmove’, func, { passive: false }) touch-action: none; 应用 CSS 属性 touch-action: none; 这样任何触摸事件都不会产生默认行为,但是 touch 事件照样触发 ``` <br/> # <span style="color:#619BE4">新页预览</span> ***** 打开新页面并且预览代码 <br/> ### 示例内容 <span style="color:red;">1. 解决代码</span> ``` if( $(".runCode").length == 0 ) { $(".cnblogs_code").before( $('<p><span class="runCode">运行下面代码</span></p>') ); }; var isIE = /MSIE|Trident/i.test(navigator.userAgent.toLowerCase()); $(".runCode").on("click", function(evt) { evt.stopPropagation(); var $this = $(this), $p = $this.parent("p").next(".cnblogs_code"), code = $p.text(), code = $p.hasClass('jscode') ? ( "log下面可能有测试的数据, 你可以按F12打开看看(笔记本按fn+F12)" + code + "") : code; if(code.indexOf("<script>")==-1&&code.indexOf("<html>")==-1&&code.indexOf("<body>")==-1){ code = "<script>"+code+"</script>" }; if (!isIE) { window.open(URL.createObjectURL(new Blob([code], { type: "text/html; charset=utf-8" }))); } else { var d = window.open("about:blank").document; d.write(code); d.close(); } }); ``` <br/> # <span style="color:#619BE4">innertHtml添加的script不执行?</span> ***** innertHtml添加的script不执行 <br/> ### 示例内容 <span style="color:red;">1. 重新构造</span> ``` 这并不是浏览器的bug,因为w3c文档就是这么规定的 var html = '<div>html</div><script>alert(1);<\/script>'; var cont = document.getElementById('cont'); cont.innerHTML = html; var oldScript = cont.getElementsByTagName('script')[0]; cont.removeChild(oldScript); var newScript = document.createElement('script'); newScript.type = 'text/javascript'; newScript.innerHTML = oldScript.innerHTML; cont.appendChild(newScript); ``` <span style="color:red;">2. eval大法</span> ``` var html = '<div>html</div><script>alert(1);<\/script>'; var cont = document.getElementById('cont'); cont.innerHTML = html; var oldScript = cont.getElementsByTagName('script')[0]; cont.removeChild(oldScript); var scriptText = oldScript.innerHTML; eval(scriptText); ``` <span style="color:red;">3. jQuery</span> ``` 使用jQuery的html() ``` <br/> # <span style="color:#619BE4">视频流浏览器播放解决方案?</span> ***** 视频流浏览器播放解决方案 <br/> ### 示例内容 <span style="color:red;">1. HLS</span> ``` HLS(Http Live Streaming) 是一个由苹果公司提出的基于HTTP的流媒体网络传输协议,直接把流媒 体切片成一段段,信息保存到m3u列表文件中, 可以将不同速率的版本切成相应的片;播放器可以直 接使用http协议请求流数据。 优势: * 可以在不同速率的版本间自由切换,实现无缝播放 * 省去使用其他协议的烦恼 劣势: * 延迟大小受切片大小影响,不适合直播,适合视频点播。 * 实时性差,延迟高。HLS 的延迟基本在 10s+ 以上 * 文件碎片。特性的双刃剑,ts 切片较小,会造成海量小文件,对存储和缓存都有一定的挑战 ``` <span style="color:red;">2. RTMP</span> [nginx-rtmp](https://blog.csdn.net/little__SuperMan/article/details/89071764) ``` RTMP(Real Time Message Protocol)由 Adobe 公司提出流媒体协议,并且是私有协议,未完全公 开,用来解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题,RTMP协 议一般传输的是 flv,f4v 格式流。一般在 TCP 1个通道上传输命令和数据。 优势: * 在于低延迟,稳定性高,支持所有摄像头格式 * 专为流媒体开发的协议,对底层的优化比其它协议更加优秀 劣势: * 浏览器需要加载 flash插件才能播放。 * RTMP 为 Adobe 私有协议,很多设备无法播放,特别是在 iOS 端,需要使用第三方解码器才能播放 * 基于 TCP 传输,非公共端口,可能会被防火墙阻拦 ``` <span style="color:red;">3. RTSP</span> ``` RTSP(Real-Time Stream Protocol)由Real Networks 和Netscape共同提出的流媒体协议,RTSP协 议是共有协议,并有专门机构做维护。是TCP/IP协议体系中的一个应用层协议. RTSP协议一般传输的 是 ts、mp4 格式的流,RTSP传输一般需要 2-3 个通道,命令和数据通道分离。基于文本的多媒体 放控制协议. RTSP定义流格式,流数据经由RTP传输; 优势: 1. RTSP实时效果非常好,适合视频聊天,视频监控等方向。 劣势: 1. 浏览器不能直接播放,只能通过插件或者转码 ``` <br/> # <span style="color:#619BE4">浏览器端解析XML格式文档?</span> ***** 浏览器端解析XML格式文档 <br/> ### 示例内容 <span style="color:red;">1. 举例说明</span> ``` function parseXml(xml, arrayTags) { let dom = null; if (window.DOMParser) dom = (new DOMParser()).parseFromString(xml, 'text/xml'); else if (window.ActiveXObject) { dom = new ActiveXObject('Microsoft.XMLDOM'); dom.async = false; if (!dom.loadXML(xml)) throw dom.parseError.reason + ' ' + dom.parseError.srcText; } else throw new Error('cannot parse xml string!'); function parseNode(xmlNode, result) { if (xmlNode.nodeName === '#text') { let v = xmlNode.nodeValue; if (v.trim()) result['#text'] = v; return; } let jsonNode = {}, existing = result[xmlNode.nodeName]; if (existing) { if (!Array.isArray(existing)) result[xmlNode.nodeName] = [existing, jsonNode]; else result[xmlNode.nodeName].push(jsonNode); } else { if (arrayTags && arrayTags.indexOf(xmlNode.nodeName) !== -1) result[xmlNode.nodeName] = [jsonNode]; else result[xmlNode.nodeName] = jsonNode; } if (xmlNode.attributes) for (let attribute of xmlNode.attributes) jsonNode[attribute.nodeName] = attribute.nodeValue; for (let node of xmlNode.childNodes) parseNode(node, jsonNode); } let result = {}; for (let node of dom.childNodes) parseNode(node, result); return result; } ``` <br/> # <span style="color:#619BE4">惯性运动?</span> ***** 惯性运动 <br/> ### 示例内容 <span style="color:red;">1. 举例说明</span> ``` <!DOCTYPE html> <html lang="zh-cn"> <head> <title>惯性运动</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <style> #box { background: pink; width: 100px; height: 100px; position: absolute; top: 100px; left: 100px; } </style> </head> <body> <div id="box"></div> <script> let boxDOM = document.getElementById('box'); let isDown = false; //是否按下鼠标 let timer = null; let inertance = 1.2; //惯性系数,越大,惯性越不明显,不能小于0 let fv = 0; //滑动的力度 let startX = 0; boxDOM.onmousedown = function (e) { clearTimeout(timer); //清除定时器 fv = 0; startX = e.clientX; //鼠标按下的位置 isDown = true;//鼠标是否有按下,主要防止用户是从容器外开始滑动的 } boxDOM.onmousemove = function (e) { if (isDown) { let moveFrame = e.clientX - startX; startX = e.clientX; fv = moveFrame; boxDOM.style.left = moveFrame + boxDOM.offsetLeft + 'px'; } } window.onmouseup = function (e) { if (isDown) { isDown = false; let friction = ((fv >> 31) * 2 + 1) * inertance; // 根据力度套用公式计算出惯性大小,公式要记住 let absFriction = Math.abs(friction); timer = setInterval(function () { fv -= friction; // 力度按 惯性的大小递减 boxDOM.style.left = fv + boxDOM.offsetLeft + 'px'; if (Math.abs(fv) < absFriction) { // 如果力度减小到小于1了,结束,或者边界弹回 clearInterval(timer); } }, 20); } } </script> </body> </html> ``` <br/> # <span style="color:#619BE4">浏览器渲染过程?</span> ***** 浏览器渲染过程 <br/> ### 示例内容 <span style="color:red;">1. 举例说明</span> ![浏览器解析过程](https://img.kancloud.cn/a9/52/a952ee0d5aa2090ce2ef3ff8bedffeb1_640x430.jpeg) ![浏览器网页渲染流程](https://img.kancloud.cn/63/91/6391573a276c47a9a50ae0cbd2c5844c_1440x810.jpg) <br/> # <span style="color:#619BE4">浏览器自动填充机制?</span> ***** 浏览器渲染过程 <br/> ### 示例内容 <span style="color:red;">1. 触发条件</span> ``` 当浏览器遇到type="text"与type="password"的input标签紧邻时,会触发浏览器自动填充行为 默认为黄色背景 firefox和360浏览器的处理方式是:只要检测到页面里有满足填充机制的, 不管是不是display:none 的,只要检测到就直接往里填充 ``` <br/>