前端进阶(五)

  前端进阶五,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>

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>

基础标签

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>

line标签代表直线

<svg width="300" height="300">
	<line x1="0" y1="0" x2="200" y2="0" />
</svg>

polyline标签用于绘制一根折线

<svg width="300" height="300">
	<polyline points="3,3 30,28 3, 53" fill="none" stroke="black"/>
</svg>

rect标签用于绘制矩形

<svg width="300" height="300">
  <rect x="0" y="0" height="100" width="200" style="stroke: #70d5dd; fill: #dd524b" />
</svg>

ellipse标签用于绘制椭圆

<svg width="300" height="180">  <ellipse cx="60" cy="60" ry="40" rx="20" stroke="black" stroke-width="5" fill="silver"/></svg>

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>

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>

marker-start属性

Marker-end属性

stroke-linecap属性:用于控制描边末端的样式

Stroke-dasharray属性:控制画笔的虚实,通过实线和虚线控制画

stroke-dashoffset属性:相对于绘制的起点偏移的量,正值是向右或者顺时针偏移,负值是向左或者逆时针偏移

text标签用于绘制文本

<svg width="300" height="300">	<text x="50" y="25">22</text></svg>

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>

g标签用于将多个形状组成一个组,方便复用

<svg width="300" height="300">  <g id="myCircle">    <text></text>    <circle cx="50" cy="50" r="20"/>  </g></svg>

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>

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>

image标签用于插入图片文件

<svg viewBox="0 0 100 100" width="100" height"100">	<image xlink:href="path/to/image.jpg"         width="50%" height="50%"/></svg>

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>

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>

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>

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>

圆形进度条

<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>

Iconfont的使用

iconfont有三种使用方式:

unicode

<span class="icon-font">&#59173</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>

前两种不支持彩色图标,第三种支持

业务场景代码

手写轮播图

轮播需要设置一个很长的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();

手写图片懒加载

手写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),所以你只能访问同域中存储的数据,而不能访问其他域的。

性能监控

关键指标

首屏时间:从浏览器输入地址并回车后到首屏内容渲染完毕的时间;首屏时间等于白屏时间+首屏渲染时间

白屏时间:是指从用户进入网站(输入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查询耗时 :domainLookupStartdomainLookupEnd分别代表DNS查询的开始和结束时间节点。如果浏览器没有进行DNS查询(比如使用了cache),则两者的值都等于fetchStart;

TCP链接耗时:connectStartconnectEnd分别代表TCP建立连接和连接成功的时间节点。如果浏览器没有进行TCP连接(比如使用持久化连接webscoket),则两者都等于domainLookupEnd;

request请求耗时:responseStartresponseEnd分别代表浏览器收到从服务器端(或缓存、本地资源)响应回的第一个字节和最后一个字节数据的时刻;

解析dom树耗时:domCompletehtml文档完全解析完毕的时间节点减去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

通常计算首屏的方法有

  • 首屏模块标签标记法
  • 统计首屏内加载最慢的图片的时间
  • 自定义首屏内容计算法

标签标记法

由于浏览器解析HTML是按照顺序解析的,当解析到某个元素的时候,觉得首屏完成了,就在此元素后面加入计算首屏完成时间

<!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=""></head><body>    <div>123</div>    <div>456</div>    // 首屏可见内容    <script>        // 首屏结束时间        window.firstPaint = Date.now();    </script>    // 首屏不可见内容    <div class=" "></div></body></html>首屏时间 = firstPaint - pageStartTime

统计首屏内加载最慢的图片/iframe(更常用)

<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <title>首屏时间</title>    <script>        window.pageStartTime = Date.now()    </script></head><body>    <img src="https://lz5z.com/assets/img/google_atf.png" alt="img" onload="load()">    <img src="https://lz5z.com/assets/img/css3_gpu_speedup.png" alt="img" onload="load()">    <script>        function load () {            window.firstScreen = Date.now()        }        window.onload = function () {            // 首屏时间            console.log(window.firstScreen - window.pageStartTime)        }    </script></body></html>

缺点:使用场景受限

同样无法获取解析html文档之前的时间信息

这种方案比较适合首屏元素数量固定的页面,比如移动端首屏不论屏幕大小都展示相同数量的内容,响应式得改变内容的字体、尺寸等。

但是对于首屏元素不固定的页面,这种方案并不适用,最典型的就是PC端页面,不同屏幕尺寸下展示的首屏内容不同。上述方案便不适用于此场景。

可操作时间

用户可操作的时间节点即dom ready触发的时间,使用jquery可以通过$(document).ready()获取此数据。

// 原生JS实现dom readywindow.addEventListener('DOMContentLoaded', (event) => {    console.log('DOM fully loaded and parsed');});

总下载时间

总下载时间即window.onload触发的时间节点。

自动化部署与负载均衡

pm2

pm2是node进程管理工具,利用它进行node应用管理的性能监控、自动重启、负载均衡等。

全局安装

npm install -g pm2

使用pm2控制进程

pm2 start app.js  //启动进程pm2 restart app.js   //重启进程pm2 list   //获取当前应用等名字/进程idpm2 stop app_name|app_id  //停止进程应用pm2 delete app_name|app_id  //删除特定进程应用pm2 stop all //停止所有应用

其他命令行参数

pm2 start app.js -i max //根据有效CPU数启动最大进程数目pm2 start app.js -i 3 //启动3个进程pm2 start app.js -n name //启动进程时指定进程名字namepm2 start app.js --watch //监听应用目录的变化,一旦发生变化就自动重启pm2 monit  //查看当前pm2的运行进程的状态pm2 start big-array.js --max-memory-restart 20M  //超过内存上限后自动重启

配置启动环境

在node中指定启动环境(开发环境、生产环境等)

"env":{  "NODE_ENV":"production",  "REMOTE_ADDR":"http://www.example.com/"},"env_dev":{  "NODE_ENV":"development",   "REMOTE_ADDR":"http://wdev.example.com/"}"env_test":{  "NODE_ENV":"test",  "REMOTE_ADDR":"http://wtest.example.com/"}

启动时设置环境

pm2 start app.js --env dev

pm2支持线上系统和第三方扩展,如常用的log、rotate,

jenkins

jenkins是基于java和docker的自动化部署和管理工具

安装之前确保电脑安装java(java 1.8)和docker

mac安装

使用brew工具安装和启动

Circle CI

circle CI可以与github action串接

参考rocksdb ci流程

Sentry

sentry是一个开源的错误追踪工具,可以帮助开发人员实时监控和修复系统中的错误。其专注于错误监控以及提取一切事后处理所需的信息,支持几乎所有主流开发语言(JS/Java/Python/php)和平台,并提供了web来展示错误。

sentry.io docs.sentry.io/platforms

官方推荐使用docker或者python安装

在前端项目中使用

npm install @sentry/browser @sentry/integrations
import * as Sentry from '@sentry/browser'import * as Intergrations from '@sentry/integrations'process.env.NODE_ENV === "production" && Sentry.init ({  dsn: 'https://e028cb7b8dd645978cf5d84a@sentry.io/18726',  integrations: [new Integrations.Vue{}],})

前端测试

现如今大部分互联网团队都是走 敏捷开发 的节奏。实际上,自动化测试才是实现“敏捷”的基本保障。业务端的快速上线和快速验证对技术侧的响应力提出了更高的要求:更快上线,持续上线。再考虑到人员流动和应用逐步变大的事实,日后迭代的成本只会变得越来越高。当然这个项目迭代的成本也跟项目的复杂度有关,比如笔者所在的点餐业务,项目有足够的复杂性,有些细微的改动点其实会牵扯到很多内容,而对刚加入团队的新人就会显得不太友好。因此,项目拥有前端测试是必不可少的,它能够有效保障业务迭代的质量和稳定性。

我们经常说的单元测试其实只是前端测试的一种。前端测试分为单元测试,UI 测试,集成测试和端到端测试。

  • 单元测试:是指对软件中的最小可测试单元进行检查和验证,通常指的是独立测试单个函数。
  • UI 测试:是对图形交互界面的测试。
  • 集成测试:就是测试应用中不同模块如何集成,如何一起工作,这和它的名字一致。
  • 端到端测试(e2e):是站在用户角度的测试,把我们的程序看成是一个黑盒子,我不懂你内部是怎么实现的,我只负责打开浏览器,把测试内容在页面上输入一遍,看是不是我想要得到的结果。

前端测试的框架可谓是百花齐放。

  • 单元测试有 Mocha, Ava, Karma, Jest, Jasmine 等。
  • UI 测试有 ReactTestUtils, Test Render, Enzyme, React-Testing-Library, Vue-Test-Utils 等。
  • e2e 测试有 Nightwatch, Cypress, Phantomjs, Puppeteer 等。

单元测试

https://kerminate.me/2019/12/22/%E5%89%8D%E7%AB%AF%E6%B5%8B%E8%AF%95%E7%9A%84%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/#more

highchart

bulma

bulma是纯css,没有js,bootstrap有JS。当用vuejs,reactjs时,带有js的css框架并不适合,需要纯的css框架。在好几个项目中用了vue + bulma/buefy,感觉不错

Bulma 是一个手机优先的框架,提供五个宽度断点,分别是 mobile(手机)、tablet(平板)、desktop(桌面)、widescreen(宽屏)、fullHD(高清),具有良好的自适应特性,可以随心所欲为不同设备设置不同样式。

mobile:小于等于768pxtablet:大于等于769pxdesktop:大于等于1024pxwidescreen:大于等于1216pxfullhd:大于等于1408px

class样式

网格

偏移用is-offset-修饰类

  • is-offset-one-quarter
  • is-offset-one-fifth
  • is-offset-8
  • is-offset-1

columns布局默认是在手机上垂直堆叠,其他宽度都是平铺。如果希望手机也保持平铺,可以加上is-mobile修饰类。

如果希望手机和平板是垂直堆叠,其他宽度平铺,可以使用is-desktop修饰类。

如果希望在不同设备,网格占据不同的宽度,可以像下面这样写。

// 网格在手机占据二分之一宽度,平板三分之一宽度,桌面四分之一宽度,宽屏和高清则是平铺。<div class="  column  is-half-mobile  is-one-third-tablet  is-one-quarter-desktop"></div>

隐藏某个项目

  • is-hidden-mobile:只在手机隐藏
  • is-hidden-tablet-only:只在平板隐藏
  • is-hidden-desktop-only :只在桌面隐藏
  • is-hidden-touch:手机和平板隐藏,其他宽度显示

字体

Bulma 提供7个修饰指定文字大小

//设置不同字体is-size-1: 3remis-size-2: 2.5remis-size-3: 2remis-size-4: 1.5remis-size-5: 1.25remis-size-6: 1remis-size-7: 0.75rem//为不同设备指定字体is-size-1-mobile:手机是 size-1is-size-1-tablet:平板是 size-1is-size-1-touch:手机和平板是 size-1is-size-1-desktop:桌面、宽屏和高清是 size-1is-size-1-widescreen:宽屏和高清是 size-1is-size-1-fullhd:高清是 size-1

定制

克隆仓库

git clone https://github.com/jgthms/bulma.gitcd bulmanpm run build

Tailwind

chrome插件开发

Chrome插件是一个用Web技术开发、用来增强浏览器功能的软件,它其实就是一个由HTML、CSS、JS、图片等资源组成的一个.crx后缀的压缩包.

个人猜测crx可能是Chrome Extension如下3个字母的简写

另外,其实不只是前端技术,Chrome插件还可以配合C++编写的dll动态链接库实现一些更底层的功能(NPAPI),比如全屏幕截图。

chrome插件能够增强浏览器功能,轻松实现属于自己的“定制版”浏览器,等等。

Chrome插件提供了很多实用API供我们使用,包括但不限于:书签控制;下载控制;窗口控制;标签控制;网络请求控制,各类事件监听;自定义原生菜单;完善的通信机制等等;

为什么是Chrome插件而不是Firefox插件?

Chrome占有率更高,更多人用;开发更简单,应用场景更广泛,Firefox插件只能运行在Firefox上,而Chrome除了Chrome浏览器之外,还可以运行在所有webkit内核的国产浏览器,比如360极速浏览器、360安全浏览器、搜狗浏览器、QQ浏览器等等;

开发与调试

Chrome插件没有严格的项目结构要求,只要保证本目录有一个manifest.json即可,也不需要专门的IDE,普通的web开发工具即可。

插件配置

"browser_action":{	"default_icon": "img/icon.png",	"default_title": "这是一个示例Chrome插件",	"default_popup": "popup.html"}

browser_action图标推荐使用宽高都为19像素的图片,更大的图标会被缩小,格式随意,一般推荐png,可以通过manifest中default_icon字段配置,也可以调用setIcon()方法。

修改browser_action的manifest中default_title字段,或者调用setTitle()方法。

所谓content-scripts,其实就是Chrome插件中向页面注入脚本的一种形式(虽然名为script,其实还可以包括css的),借助content-scripts我们可以实现通过配置的方式轻松向指定页面注入JS和CSS(如果需要动态注入,可以参考下文),最常见的比如:广告屏蔽、页面CSS定制,等等。

{	// 需要直接注入页面的JS	"content_scripts": 	[		{			//"matches": ["http://*/*", "https://*/*"],			// "<all_urls>" 表示匹配所有地址			"matches": ["<all_urls>"],			// 多个JS按顺序注入			"js": ["js/jquery-1.8.3.js", "js/content-script.js"],			// JS的注入可以随便一点,但是CSS的注意就要千万小心了,因为一不小心就可能影响全局样式			"css": ["css/custom.css"],			// 代码注入的时间,可选值: "document_start", "document_end", or "document_idle",最后一个表示页面空闲时,默认document_idle			"run_at": "document_start"		}	],}

Background是一个常驻的页面,它的生命周期是插件中所有类型页面中最长的,它随着浏览器的打开而打开,随着浏览器的关闭而关闭,所以通常把需要一直运行的、启动就运行的、全局的代码放在background里面。

background的权限非常高,几乎可以调用所有的Chrome扩展API(除了devtools),而且它可以无限制跨域,也就是可以跨域访问任何网站而无需要求对方设置CORS

鉴于background生命周期太长,长时间挂载后台可能会影响性能,所以Google又弄一个event-pages,在配置文件上,它与background的唯一区别就是多了一个persistent参数:

它的生命周期是:在被需要时加载,在空闲时被关闭,什么叫被需要时呢?比如第一次安装、插件更新、有content-script向它发送消息,等等。

因为content-script有一个很大的“缺陷”,也就是无法访问页面中的JS,虽然它可以操作DOM,但是DOM却不能调用它,也就是无法在DOM中通过绑定事件的方式调用content-script中的代码(包括直接写onclickaddEventListener2种方式都不行),但是,“在页面上添加一个按钮并调用插件的扩展API”是一个很常见的需求,

交互API

右键菜单

通过开发Chrome插件可以自定义浏览器的右键菜单,主要是通过chrome.contextMenusAPI实现,右键菜单可以出现在不同的上下文,比如普通页面、选中的文字、图片、链接,等等,如果有同一个插件里面定义了多个菜单,Chrome会自动组合放到以插件名字命名的二级菜单里,如下:

// manifest.json{"permissions": ["contextMenus"]}// background.jschrome.contextMenus.create({	title: "测试右键菜单",	onclick: function(){alert('您点击了右键菜单!');}});

常用chrome插件api

获取某个网站的所有cookie:

const url = 'https://www.baidu.com';chrome.cookies.getAll({url}, cookies => {	console.log(cookies);});

清除某个网站的某个cookie

const url = 'https://www.baidu.com';const cookieName = 'userName';chrome.cookies.remove({url, name: cookieName}, details => {});
chrome.runtime.id:获取插件idchrome.runtime.getURL('xxx.html'):获取xxx.html在插件中的地址

http://blog.haoji.me/chrome-plugin-develop.html

vscode插件开发

VSCode是微软出的一款轻量级代码编辑器,免费而且功能强大,以功能强大、提示友好、不错的性能和颜值俘获了大量开发者的青睐,对JavaScript和NodeJS的支持非常好,自带很多功能,例如代码格式化,代码智能提示补全、Emmet插件等。

再强大的IDE那也不可能面面俱到什么功能都塞进去,那样只会导致IDE本身太臃肿。功能嘛,按需索取,所以,vscode的很多强大功能都是基于插件实现的,IDE只提供一个最基本的框子和最基本功能,由插件来丰富和扩展它的功能。

因为vscode本身都是用浏览器实现的,所以其插件不用说肯定也是基于HTML+JS等前端技术实现,从形式上看就是一个类似于npm包的vsix文件,只不过按照一些特殊规范来实现一些特殊功能,所以vscode插件开发难度不大,甚至可以说熟悉了相关API之后很容易。

vscode插件能做的事情:

1.不受限地访问磁盘:

2.编写自定义命令、快捷键、菜单:

3.自定义跳转、自动补全、悬浮提示

4.自定义设置、自定义欢迎页

5.自定义网页显示

6.自定义左侧功能面板

7.自定义颜色、图标主题

8.新增语言支持

9.Markdown增强

10.其它还有比如状态栏修改、通知提示、编辑器控制、git源代码控制、任务定义、Language Server、Debug Adapter等等。

官方脚手架

使用官方脚手架生成插件项目

npm install -g yo generator-code

cd到工作目录,运行yo code命令

安装提示安装完成,按f5运行

设置插件激活方式

插件在VS Code中默认是没有被激活的,哪什么时候才被激活呢?就是通过activationEvents来配置,目前支持一下8种配置:

onLanguage:${language}onCommand:${command}onDebugworkspaceContains:${toplevelfilename}onFileSystem:${scheme}onView:${viewId}onUri*

如果配置了onLanguage:javascript,那么只要打开了JS类型的文件,插件就会被激活。

重点说一下*,如果配置了*,只要一启动vscode,插件就会被激活,为了出色的用户体验,官方不推荐这么做。看到这里相信大家知道了我们前面HelloWord里面为啥要配置onCommand了吧。

https://www.cnblogs.com/liuxianan/p/vscode-plugin-overview.html