前端进阶3,web api
# 内网穿透
内网穿透,即NAT穿透,网络连接时术语,计算机是局域网内时,外网与内网的计算机节点需要连接通信,有时就会出现不支持内网穿透。就是说映射端口,能让外网的电脑找到处于内网的电脑,提高下载速度。不管是内网穿透还是其他类型的网络穿透,都是网络穿透的统一方法来研究和解决。
内网穿透的应用场景:
- 内网穿透,可代替vpn
- 将无外网IP的desktop映射到公网
- 临时搭建网络并分配二级域名
- 微信二次开发的本地调试
方法1:localtunnel (使用国外网,非常慢,经常超时,不建议使用)
首先安装包
npm install -g localtunnel
在本地开启服务后,如服务在8080端口,运行命令开启服务
lt --subdomain mitu --port 8080
lt为localtunnel的缩写,mitu是指定域名前缀为mitu,8080为配置端口
常见错误:
(1)运行脚本命令错误:以管理员模式开启脚本权限
(2)invalid host header:在webpack的配置devServer下添加配置:disableHostCheck: true
方法二:natapp (国内网站)
方法三:ngrok
ngrok需要在服务端和客户端配置,客户端叫ngrokd,服务端叫ngrok
https://juejin.cn/post/6844903623659356168
https://aotu.io/notes/2016/02/19/ngrok/index.html
https://xicheng412.github.io/2016/09/27/ngrok-config/
# canvas api
<canvas>
元素用于生成图像。它本身就像一个画布,JavaScript 通过操作它的 API,在上面生成图像。它的底层是一个个像素,基本上<canvas>
是一个可以用 JavaScript 操作的位图(bitmap)
它与 SVG 图像的区别在于,<canvas>
是脚本调用各种方法生成图像,SVG 则是一个 XML 文件,通过各种子元素生成图像。
每个<canvas>
元素都有一个对应的CanvasRenderingContext2D
对象(上下文对象)。Canvas API 就定义在这个对象上面。
<canvas id="myCanvas" width="400" height="250">
您的浏览器不支持 Canvas
</canvas>
<script>
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
</script>
2
3
4
5
6
7
Canvas API 需要getContext
方法指定参数2d
,表示该<canvas>
节点生成 2D 的平面图像。如果参数是webgl
,就表示用于生成 3D 的立体图案,这部分属于 WebGL API。
方法:
绘制路径:
ctx.beginPath()
:
ctx.closePath()
:
ctx.moveTo()
:
ctx.lineTo()
:
ctx.fill()
:
ctx.stroke()
:
ctx.fillStyle()
:
ctx.strokeStyle
:
ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight);
:
ctx.restore()
方法将画布的样式恢复到上一个保存的快照,如果没有已保存的快照,则不产生任何效果。
图像变换:
ctx.rotate
:图像旋转
ctx.scale
:图像缩放
ctx.translate
:图像平移
ctx.transform
:设置图像变换
ctx.settransform
:取消前面的图像变换
# svg
SVG是一种基于XML语法的图象格式,全称是可缩放矢量图,其他图像格式都是基于像素处理的,SVG则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。
SVG元素可以直接插入网页,成为DOM的一部分,然后用JavaScript和css进行操作
<!DOCTYPE html>
<html>
<head></head>
<body>
<svg
id="mysvg"
xmlns="https:/www.w3.org/2000/svg"
viewBox="0 0 800 600"
preserveAspectRatio="xMidYMid meet"
>
<circle id="mycircle" cx="400" cy="300" r="50"/>
</svg>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
# 基础标签
api
circle标签
circle标签代表圆形,cx、cy、r属性分别为横坐标、纵坐标、和半径单位为像素。
<svg width="300" height="300">
<circle cx="30" cy="50" r="25" />
<circle cx="30" cy="50" r="25" class="red"/>
<circle cx="30" cy="50" r="25" class="fancy"/>
</svg>
2
3
4
5
line标签代表直线
<svg width="300" height="300">
<line x1="0" y1="0" x2="200" y2="0" />
</svg>
2
3
polyline标签用于绘制一根折线
<svg width="300" height="300">
<polyline points="3,3 30,28 3, 53" fill="none" stroke="black"/>
</svg>
2
3
rect标签用于绘制矩形
<svg width="300" height="300">
<rect x="0" y="0" height="100" width="200" style="stroke: #70d5dd; fill: #dd524b" />
</svg>
2
3
ellipse标签用于绘制椭圆
<svg width="300" height="180">
<ellipse cx="60" cy="60" ry="40" rx="20" stroke="black" stroke-width="5" fill="silver"/>
</svg>
2
3
polygon标签用于绘制多边形
<svg width="300" height="180">
<polygon fill="green" stroke="orange" stroke-width="1" points="0,0 100,0 100, 100 0,100 0, 0"/>
</svg>
2
3
path标签用于绘制路径
<svg width="300" height="300">
<path
d="
M 18,3
L 46,3
L 46,40
L 62,40
L 32,68
L 3,40
L 18,40
Z
"
>
</path>
</svg>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
marker-start属性
Marker-end属性
stroke-linecap属性:用于控制描边末端的样式
Stroke-dasharray属性:控制画笔的虚实,通过实线和虚线控制画
stroke-dashoffset属性:相对于绘制的起点偏移的量,正值是向右或者顺时针偏移,负值是向左或者逆时针偏移
text标签用于绘制文本
<svg width="300" height="300">
<text x="50" y="25">22</text>
</svg>
2
3
use标签用于复制一个形状
<svg viewBox="0 0 30 10" xmlns="https://www.w3.org/2000/svg">
<circle id="myCircle" cx="5" cy="5" r="4" />
<use href="#myCircle" x="10" y="0" fill="blue"/>
<use href="#myCircle" x="20" y="0" fill="white" stroke="blue" />
</svg>
2
3
4
5
g标签用于将多个形状组成一个组,方便复用
<svg width="300" height="300">
<g id="myCircle">
<text></text>
<circle cx="50" cy="50" r="20"/>
</g>
</svg>
2
3
4
5
6
defs标签用于自定义形状,它内部的代码不会显示,仅供饮用
<svg width="300" height="100">
<defs>
<g id="myCircle">
<text x="25" y="20"></text>
<circle cx="50" cy="50" r="20"/>
</g>
</defs>
<usr href="#myCircle" x="0" y="0"/>
<usr href="#myCircle" x="100" y="0" fill="blue"/>
<usr href="#myCircle" x="200" y="0" fill="white" stroke="blue"/>
</svg>
2
3
4
5
6
7
8
9
10
11
pattern标签用于自定义一个形状,该形状可以被引用来平铺一个区域
<svg width="500" height="500">
<defs>
<pattern id="dots" x="0" y="0" width="100" height="100" patternUnits="userSpaceOnUse">
<circle fill="#bee9e8" cx="50" r="35"/>
</pattern>
</defs>
<rect x="0" y="0" width="100%" height="100%" fill="url(#dots)" />
</svg>
2
3
4
5
6
7
8
image标签用于插入图片文件
<svg viewBox="0 0 100 100" width="100" height"100">
<image xlink:href="path/to/image.jpg"
width="50%" height="50%"/>
</svg>
2
3
4
animate标签用于产生动画效果
<svg width="500px" height="500px">
<rect x="0" y="0" width="100" height="100" fill="#feac5e">
<animate attributeName="x" from="0" to="500" dur="2s" repeatCount="indefinite" />
</rect>
</svg>
2
3
4
5
animateTransform
<svg width="500px" height="500px">
<rect x="250" y="250" width="50" height="50" fill="#4bc0c8">
<animateTransform attributeName="transform" type="rotate" begin="0s" dur="10s" from="0 200 200" to="360 400 400" repeat="indefinite" />
</rect>
</svg>
2
3
4
5
# webapi
SVGGElement对应g标签
SVGDefsElement对应defs标签
SVGEllipseElement对应ellipse标签
https://developer.mozilla.org/en-US/docs/Web/API/SVGGElement
# js操作svg
<html>
<body>
<svg
id="mysvg"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 800 600"
preserveAspectRatio="xMidYMid meet"
>
<circle id="myCircle" cx="400" cy="300" r="50" />
</svg>
</body>
<css type="text/css">
circle {
stroke-width: 5;
stroke: #f00;
fill: #ff0;
}
circle:hover {
stroke: #090;
fill: #fff;
}
<css>
<script type="text/javascript">
var mycircle = document.getElementById('mycircle');
mycircle.addEventListener('click',function(e) {
console.log('circle clicked - enlarging');
mycircle.setAttribute('r',60);
},false)
</script>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# svg常见用法
作为css背景图
描边动画
<svg width="100%" height="100">
<text text-anchor="middle" x="50%" y="50%" class="text text-1">
segmentfault.com
</text>
<text text-anchor="middle" x="50%" y="50%" class="text text-2">
segmentfault.com
</text>
<text text-anchor="middle" x="50%" y="50%" class="text text-3">
segmentfault.com
</text>
<text text-anchor="middle" x="50%" y="50%" class="text text-4">
segmentfault.com
</text>
</svg>
<css>
.text {
font-size: 64px;
font-weight: bold;
text-transform: uppercase;
fill: none;
stroke-width: 2px;
stroke-dasharray: 90 310;
animation: stroke 6s infinite linear;
}
.text-1 {
stroke: #3498db;
text-shadow: 0 0 5px #3498db;
animation-delay: -1.5s;
}
.text-2 {
stroke: #f39c12;
text-shadow: 0 0 5px #f39c12;
animation-delay: -3s;
}
.text-3 {
stroke: #e74c3c;
text-shadow: 0 0 5px #e74c3c;
animation-delay: -4.5s;
}
.text-4 {
stroke: #9b59b6;
text-shadow: 0 0 5px #9b59b6;
animation-delay: -6s;
}
@keyframes stroke {
100% {
stroke-dashoffset: -400;
}
}
</css>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
圆形进度条
<svg>
<circle
cx="150"
cy="73"
r="60"
stroke="grey"
stroke-width="12"
fill="none"
stroke-dasharray="190"
stroke-dashoffset="-190"
stroke-linecap="round"
/>
<circle
cx="150"
cy="73"
r="60"
stroke="gold"
stroke-width="12"
fill="none"
stroke-dasharray="95 190" #修改此数字即为进度条进度
stroke-dashoffset="-190"
stroke-linecap="round"
/>
</svg>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Iconfont的使用
iconfont有三种使用方式:
unicode
<span class="icon-font"></span>
font class
<span class="iconfont icon-2018-pc"></span>
Symbol
<svg class="icon" aria-hidden="true">
<use xlink:href="#icon-2018-tu"></use>
</svg>
2
3
前两种不支持彩色图标,第三种支持
# 业务场景代码
# 手写轮播图
轮播需要设置一个很长的DOM,设置超出容器隐藏,使用setInterval进行轮播,计算便宜位置。
DOM左端与右端交换的时候会有快速滑动,为了体验好一点,我会设置两层DOM,在容器之外的DOM进行DOM的左右交换。
const position = [-8,-388,-768,-1148,-1528,-1908,-2208,-2668,-3048,-3428]
var certificate = document.getElementById("certificate-inner");
var i = 3;
function pre_pic(){
if(i >= 1){
if(isNaN(parseInt(certificate.style.marginLeft)) || parseInt(certificate.style.marginLeft) < -400)
i--;
var newLeft = position[i] + "px";
$("#certificate-inner").animate({marginLeft:newLeft},500);
else if (parseInt(certificate.style.marginLeft)> -400 || i >= 1){
i++;
var newLeft = position[i] + "px";
$("#certificate-inner").animate({marginLeft:newLeft},500);
setTimeout(function(){
i = 6;
certificate.style.marginLeft = "-2283px"
},3985)
}
}else{
i = 5;
certificate.style.marginLeft = "-2283px";
var newLeft = position[i] + "px"
$("#certificate-inner").animate({marginLeft:newLeft},500);
}
}
function next_pic(){
if(i < 9){
if(isNaN(parseInt(certificate.style.marginLeft))|| parseInt(certificate.style.marginLeft) > 374*8 || i > 0) {
i++;
var newLeft = position[i] + "px"
$("#certificate-inner").animate({marginLeft:newLeft},500)
}
else{
i++;
var newLeft = position[i] + "px"
$("#certificate-inner").animate({marginLeft:newLeft},500)
setTimeout(function(){
i = 3;
certificate.style.marginLeft = "-1143px"
},3985)
}
newLeft = newLeft + "px"
time = 0;
}else{
i = 4;
certificate.style.marginLeft = "1143px";
var newLeft = position[i] + "px"
$("#certificate-inner").animate({marginLeft:newLeft},500)
}
}
$(".left-coursol-icon").on("click",function(e){
e.preventDefault();
pre_pic();
})
$(".right-coursol-icon").on("click",function(e){
e.preventDefault();
next_pic();
})
var time = null;
function autoplay(){
time = setInterval(function(){
next_pic();
},4000);
}
autoplay();
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# 手写图片懒加载
# 手写Google搜索
# 前端添加水印
# 富文本编辑器
# 前端大容量缓存方案indexedDB
对于做3D WebGL 的开发者来说,加载大量的 hdr、glb、gltf 等文件往往是很令人头疼的,因为这些文件体积不小,在网络侧加载会消耗大量时间,从而影响用户体验。对于这些大文件,localstorage 和 sessionstorage 的缓存容量肯定是不够塞牙缝的。所以这时候我们要请出 IndexedDB。
IndexedDB 是一种可以让你在用户的浏览器内持久化存储数据的方法, 允许储存大量数据,提供查找接口,还能建立索引。 IndexedDB 的兼容性也还不错,基本上不兼容太老的浏览器,都还是可用的。
容量
chrome67设置了should remain available,这个值表示为浏览器本身需要留出来的空间,硬盘容量除去这个值以后的空间就是浏览器临时存储可用空间
大文件存储
IndexedDB 不仅可以储存字符串,还可以储存二进制数据(ArrayBuffer 对象和 Blob 对象),所以我们可以把图片或者 3D 模型文件转化成 Blob 格式的文件,存在 IndexedDB 中,就可以解决免去二次加载时网络请求的时间。
IndexedDB 完全可以满足存储大体积文件的需求,并且 IndexedDB 可以 worker 中使用,包括 Web Worker 和 Service Worker,当 3D 需要进行复杂计算时,就可以利用 Service Worker 把一些数据存储在 IndexedDB 中或者通过 Web Worker 读取 IndexedDB 中的数据进行多线程计算。
需要注意的是 IndexedDB 也遵从同源协议(same-origin policy (opens new window)),所以你只能访问同域中存储的数据,而不能访问其他域的。
#
# 性能监控
# 关键指标
首屏时间:从浏览器输入地址并回车后到首屏内容渲染完毕的时间;首屏时间等于白屏时间+首屏渲染时间
白屏时间:是指从用户进入网站(输入url、刷新、跳转等方式)的时刻开始计算,一直到页面有内容展示出来的时间节点。这个过程包括dns查询、建立tcp连接、发送首个http请求(如果使用https还要介入TLS的验证时间)、返回html文档、html文档head解析完毕。
用户可操作时间节点:domready触发节点,点击事件有反应;
总下载时间:window.onload的触发节点。
# window.performance
Window.performance是用来测量网页和Web应用程序的性能api,performance中有以下字段用来衡量性能:
memory字段
代表JavaScript对内存的占用。
navigation字段
统计的是一些网页导航相关的数据:redirectCount:重定向的数量(只读),但是这个接口有同源策略限制,即仅能检测同源的重定向;type 返回值应该是0,1,2 中的一个。分别对应三个枚举值: 0 : TYPE_NAVIGATE (用户通过常规导航方式访问页面,比如点一个链接,或者一般的get方式) 1 : TYPE_RELOAD (用户通过刷新,包括JS调用刷新接口等方式访问页面) 2 : TYPE_BACK_FORWARD (用户通过后退按钮访问本页面)
timing字段
的统计数据,它包含了网络、解析等一系列的时间数据。具体包括:
DNS查询耗时 :domainLookupStart
和domainLookupEnd
分别代表DNS查询的开始和结束时间节点。如果浏览器没有进行DNS查询(比如使用了cache),则两者的值都等于fetchStart;
TCP链接耗时:connectStart
和connectEnd
分别代表TCP建立连接和连接成功的时间节点。如果浏览器没有进行TCP连接(比如使用持久化连接webscoket),则两者都等于domainLookupEnd;
request请求耗时:responseStart
和responseEnd
分别代表浏览器收到从服务器端(或缓存、本地资源)响应回的第一个字节和最后一个字节数据的时刻;
解析dom树耗时:domComplete
html文档完全解析完毕的时间节点减去domInteractive
,代表浏览器解析html文档的状态为interactive时的时间节点。domInteractive并非DOMReady,它早于DOMReady触发,代表html文档解析完毕(即dom tree创建完成)但是内嵌资源(比如外链css、js等)还未加载的时间点;
白屏时间:domLoading
代表浏览器开始解析html文档的时间节点减去fetchStart
是指在浏览器发起任何请求之前的时间值。
domready可操作时间 :domContentLoadedEventEnd 代表DOMContentLoaded事件完成的时间节点,此刻用户可以对页面进行操作,也就是jQuery中的domready时间;- fetchStart
onload总下载时间 = loadEventEnd代表onload事件结束的时间节点-fetchStart;
# 实例方法
白屏时间
在html文档的head中所有的静态资源以及内嵌脚本/样式之前记录一个时间点,在head最底部记录另一个时间点,两者的差值作为白屏时间
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>白屏时间</title>
<script>
// 开始时间
window.pageStartTime = Date.now();
</script>
<link rel="stylesheet" href="">
<link rel="stylesheet" href="">
<script>
// 白屏结束时间
window.firstPaint = Date.now()
</script>
</head>
<body>
<div>123</div>
</body>
</html>
白屏时间 = firstPaint - pageStartTime
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
通常计算首屏的方法有
- 首屏模块标签标记法
- 统计首屏内加载最慢的图片的时间
- 自定义首屏内容计算法
标签标记法
由于浏览器解析HTML是按照顺序解析的,当解析到某个元素的时候,觉得首屏完成了,就在此元素后面加入