TODO
- 原型
- 异步
- flex
- throttle
- bind
- arguments
- []==false
- 动态规划
- 异步
- let =>
回答的不好的
- https
csrf- vue react diff
amd cmd
June 25, 2018
回答的不好的
June 24, 2018
June 23, 2018
June 23, 2018
缓存的种类有很多,大致归为两类:私有与共享缓存。共享缓存能够被多个用户使用。本文主要介绍浏览器与代理缓存,除此之外还有网关 缓存,CDN,反向代理缓存,负载均衡器等部署在服务器上,为站点和web应用提供更好的稳定性、性能和扩展性。
HTTP/1.1定义的Cache-Control投用来区分对缓存机制的支持情况,请求头和响应头都支持这个属性。 通过它来定义缓存策略。
禁止进行缓存
Cache-Control: no-store
强制确认缓存
Cache-Control: no-cache
私有和公共缓存
Cache-Control: private, public
缓存过期机制
max-age=<seconds>相比Expires而言,max-age是距离请求发起的时间的秒数。针对应用中那些不会改变的文件
通常可以手动设置一定的时长以保证缓存有效,如图片、css、js等静态资源
Cache-Control: max-age=387488400
缓存验证确认
这就意味着在考虑使用一个陈旧的资源时,必须先验证她的状态,已过期的缓存将不被使用。
Cache-Control: must-revalidate
Pragma是HTTP/1.0标准中定义的一个header属性,只能用在头中。作用和cache-control:no-cache相同
理论上来讲,当一个资源被缓存存储后,改资源可以被永久存储在缓存中。由于缓存只有有限空间,所以将定期删除 以下副本,这个过程叫做缓存驱逐。
由于HTTP是C/S模式的协议,服务器更新一个资源时,不可能直接通知客户端及其缓存,所以双方必须为该资源约定 一个过期时间,在此之前是,该资源是新鲜的,在此之后就是陈旧的。
一个陈旧的资源是不会被直接清楚或忽略的
更新旧资源的过程如下
- 客户端发起请求,缓存检测到一个对应的旧资源
- 缓存将此请求附加一个
If-None-Match头,发送给服务器
- 服务器返回304(该响应头不会带有实体信息),表示此资源副本是新鲜的
- 服务器判断已过期,则返回带有实体内容
对于含有特定头部信息的请求,会去计算缓存寿命。通常情况下
不频繁跟新的文件会使用特停的命名方式:在URL后面(通常是文件名后面)会加上版本号。加上版本号后的资源被视作一个完全新的 独立的资源,同时拥有一年伸着更长的缓存过期时长。同时更新的时候不会法伤部分缓存先更新而引起新旧文件内容不一致的问题。
用户点击刷新按钮时开始缓存验证。
作为缓存的一种强校验器,ETags响应头是一个队用户代理不透明的值。如果资源请求的响应头里含有ETag,客户端可以在后续的 请求的头中带上If-None-match头来验证缓存。
Last-Modified响应头可以作为一种弱校验器。因为只能精确到一秒。如果响应头里有这个信息,客户端可以在后续的请求的头部带上 If-Modified-Since来做校验
Vary: User-Agent
当缓存服务器收到一个请求,只有当前的请求和原始的请求头跟缓存的响应头里的Vary都匹配才能使用缓存。
使用Vary头有利于内容服务的动态多样性。如果需要区分移动端和桌面端的展示内容,就可以使用Vary: User-Agent,避免在不同终端展示 错误的布局。
GMT
响应头包含日期/时间,即在此时候之后,响应过期。
无效的日期,比如0,代表过去的日期,即该资源已过期。
如果在Cache-Control中设置了max-age或者s-max-age指令,Expires会被忽略。
GMT
Date是一个通用首部,其中包含了消息生成的日期和时间。
GMT
Last-Modified是一个响应首部,其中包含源头服务器认定的资源做出修改的日期及时间。由于精度比ETag要低, 所以这是一个备用机制。包含有If-Modified-Since或If-Unmodifed-Since首部的条件求情会使用这个字段。
ETag 响应头是资源的特定版本的标识符。这可以让缓存更高效,并节省贷款,因为如果内容没有变,web服务器 不需要发送完整的响应。如果变了,Etag能有防止资源的同时更新相互覆盖("空中碰撞")。
ETag与If-Match配合来检测到空中碰撞的编辑冲突
编辑内容是wiki被散列,放入Etag:
Etag: jdoiaj8383838392983ijaojdosdjiojsdij
将更改保存到wiki页面时,POST请求中包含有Etag值得If-Match头来检查是否为最新版本
原理上面已经讲到
专门为离线应用而设计的缓存
appcache是从浏览器缓存中分出来的一块缓存,要想使用该缓存,使用manifest文件
一个applicationCache对象API applicationCache属性
相对于http1.1有以下不同
客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤,如图所示。
(1)客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
(2)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
(3)客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
(4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给服务器。
(5)Web服务器利用自己的私钥解密出会话密钥。
(6)Web服务器利用会话密钥加密与客户端之间的通信。
Web Storage API 提供机制, 使浏览器能以一种比使用Cookie更直观的方式存储键/值对。
虽然 Web Storage 对于存储较少量的数据很有用,但对于存储更大量的结构化数据来说,这种方法不太有用。IndexedDB提供了一个解决方案。
IndexedDB 是一种在用户浏览器中持久存储数据的方法。它允许您不考虑网络可用性,创建具有丰富查询能力的可离线 Web 应用程序。
June 23, 2018
比较Angular,Ember,React,Backbone的角度有很多,但是也许比较他们是如何管理状态的角度是最有趣的。
我们可以理解为将我们的数据投影到屏幕上的。比如JS中的对象,数组,字符串是源头,HTML中的forms,links, buttons,images等是显示屏幕上的内容。
我们称之为渲染过程。我们可以认为是数据到可视化界面的投影。当我们根据数据渲染模板的时候,我们得到了代表了我们 数据的DOM(HTML)。
平常来说这是没有什么问题的。
假如数据随着时间的改变而改变的话,这就比较有挑战性了。比如用户的操作导致了数的变化,或者什么发生了什么改变了数据。 UI需要体现出这些变化。更重要的是,重新构建DOM是花费昂贵的。我们希望最小化的更新节点
这可比只渲染一次UI困难多了,因为牵涉到了状态的变化。我们就从这里探讨上面框架的解决方案与不同之处。
没有改变,全局不可变
在大JS的时代之前,每一个点击,没一个表单提交,都会将页面unload掉,从后端请求整个渲染的页面,回来之后,再次渲染。 这就是所谓的服务端渲染。
这种方法前端是不管理任何state的,都由后端处理,前端只是提供下html,css,或许有点点JS。
显而易见这种方法速度很慢
我不知道哪些应该重新渲染,你来搞明白
总的来说,数据改变,发出事件,重新渲染UI你来决定。
第一代框架如backbone, ext, dojo第一次在浏览器中引入了data model,同时也是第一次 我们需要改变state在浏览器端。data model的内容改变之后需要你来获取改变然后改变UI. 数据改变的时候回触发一些事件,但是重新渲染UI是你的责任。
到底是渲染一大部分还是渲染一小部分就由你来决定了。灵活性很大,但同时不要忘了性能。
我知道什么变化了,也知道哪里需要重新渲染,因为我控制了model和view
总的来说,通过我设计的API来控制Model
和backbone一样,Ember也会在数据改变的时候发出事件,不同的是,我们把UI绑定到data model上, 也就是说,有一个数据变化的监听器,在监听器里可以和UI做绑定。这个监听器知道在接收到数据变化的时候 如何更新UI。(我们可以通过watch来获得变化,并进行UI的绑定)
最大的不好的地方是,Ember必须永远知道数据的变化,这就要求我们使用Ember设计的一套API。
我不知道什么发生了改变,所以我就检查下所有地方好了
虽然AngularJS也在着手解决手动重新渲染的问题,但是它是从另一个角度解决问题的。
当我们通过angular模板渲染{{foo.x}}的时候,angular不仅渲染数据,还为这个特殊的值创建了的一个watcher,
从此以后,只要有变化,它就检查watcher中的值是否变了,如果变了就在UI中重新渲染这个值。整个过程就是脏检查。
不好的地方就是,当改变发生的时候,angular并没有深入的探测到具体是哪个数据发生了改变。所以,只要一有情况发生, 所有的watcher都要跑一遍。
听起来这是个性能的噩梦,但实际上还是挺快的,因为仅仅是纯JS的逻辑执行,没有牵涉到DOM的更新。但是当UI十分庞大的时候, 或者需要频繁渲染的时候,额外的优化技巧就是必须的了。
另外提一下,ES7中的Object.observe对Ember和Angular会十分有帮助,因为这给出了原生的watching在属性的改变上面。
我不知道发生了哪些改变,所以我就重新渲染下,看看与之前有什么不同
React和Angular类似,不需要data modal API的支持。那么React是如何根据数据的变化来解决UI的更新的呢?
React好像将我们带到了服务端渲染的方式。React的做法是从头到尾的渲染了整个UI。
这听起来是低效的,如果这就是故事的结尾,那确实是。然而,React 用了特殊的方法进行重新渲染。
当React UI进行渲染的时候,它首先渲染到Virtual DOM里面,并不是真正的DOM,而是一个轻量级的,纯粹的对象和数组的 JavaScript数据结构,这个数据结构代表了真实的DOM对象图。然后一个单独的进程采用该DOM结构在屏幕上渲染出真实的DOM结构。
当数据改变的时候,一个新的Virtual DOM被从头的创建。新的Virtual DOM中包含了变化的值。React从这两个Virtual DOM执行 diff算法。来获取变化的地方。而且只有那些被改变的地方才会被真实DOM重新渲染。
尽管React的Virtual DOM已经很快了,但是在UI很大或者需要频繁渲染的时候还是会出现瓶颈。
问题是真的没有方法能够渲染整个DOM,(UI太大渲染不过来,渲染太快,还没渲染完就需要渲染洗一次了)。除非想Ember一想引入 一套data model API。
一个有效的解决的方法就是使用immutable,这和React的Virtual DOM很般配。
immutable是这么一个原理。正如他的名字一样,你永远不能直接改变一个对象,当时我们可以基于这个对象产生一个新的版本。
使用immutable的意义就是,我们可以重复使用上次Virtual DOM的那些没有改变的Virtual DOM部分。
像Ember一样,我们不能使用原生JS对象,必须使用额外的API。但是不同点在于,这次并不是框架的需要,我们使用它因为这是一种 更好的管理state的方法。这不仅提高新性能,而且是一种文化的象征。
对改变的发现是UI渲染的核心问题,JS库通过各种各样的途径来解决这个问题。
EmberJS能够检测到变化,当他们发生的时候,因为EmberJS通过API控制了Model和View,当你调用他们的时候你可以触发事件。
AngularJS在变化之后去检测变化,通过re-running在UI中所有的绑定来看看值是否发生了改变。
纯React通过re-render whole UI到一个Virtual DOM然后和就得版本比较来获得改变。不管发生了什么,都补丁到真实DOM上。
有immutable的React加强了纯React,通过让component快速标记那些没有改变来提升速度,这是性能的选择,同时也是文化的选择。
June 22, 2018
2个取值(inherit不计算在内)
建议将所有元素的border-boxing都设置为border-box
.a {
flex: 1 1 100px;
}
这表示什么意思?
上面的样式等价于
.a {
flex-grow: 1; //扩展比率
flex-shrink: 1; //收缩比率
flex-basic: 100px; //伸缩基准值
}
wrapper的总长度是500,根据基准值算出的总长度是200+200+200=600,显然超出了,所以根据收缩比率进行压缩 (600-500) / (1+2+3) = 16.666,那么green块收缩16.666x1,black块收缩16.666x2,blue块收缩16.666x3 所以最后的宽度green = 200 - 16.666x1, 同理,black,blue类似
<style>
.ysy-f-wrapper {
display: flex;
width: 500px;
height: 50px;
}
.ysy-f-green{
flex: 1 1 200px;
background: green;
height: 50px;
}
.ysy-f-black{
flex: 2 2 200px;
background: black;
height: 50px;
}
.ysy-f-blue{
flex: 3 3 200px;
height: 50px;
background: blue;
}
</style>
<div class="ysy-f-wrapper">
<div class="ysy-f-green"></div>
<div class="ysy-f-black"></div>
<div class="ysy-f-blue"></div>
</div>
这个省略了,比flex-shrink好理解
要求如下
June 20, 2018
XML被设计用来传输和存储数据
HTML被设计用来显示数据
XMLHttpRequest是XML的衍生体,它不仅能从服务器取回数据,也能读取本地的xml文件
SVG的元素和属性必须按标准格式书写,因为XML是区分大小写的(这一点和html不同)
SVG里的属性值必须用引号引起来,就算是数值也必须这样做。
<?xml version="1.0" standalone="no"?>
<svg
version="1.1"
baseProfile="full"
width="300" height="200"
xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="red" />
<circle cx="150" cy="100" r="80" fill="green" />
<text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>
</svg>
HTML中如何引入SVG
服务器返回头部信息
基本上,在 SVG 文档中的1个像素对应输出设备(比如显示屏)上的1个像素。但是这种情况是可以改变的,否则 SVG 的名字里也不至于会有“Scalable”(可缩放)这个∫词
<?xml version="1.0" standalone="no"?>
<svg width="200" height="250" version="1.1" xmlns="http://www.w3.org/2000/svg">
<rect x="10" y="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
<rect x="60" y="10" rx="10" ry="10" width="30" height="30" stroke="black" fill="transparent" stroke-width="5"/>
<circle cx="25" cy="75" r="20" stroke="red" fill="transparent" stroke-width="5"/>
<ellipse cx="75" cy="75" rx="20" ry="5" stroke="red" fill="transparent" stroke-width="5"/>
<line x1="10" x2="50" y1="110" y2="150" stroke="orange" fill="transparent" stroke-width="5"/>
<polyline points="60 110 65 120 70 115 75 130 80 125 85 140 90 135 95 150 100 145"
stroke="orange" fill="transparent" stroke-width="5"/>
<polygon points="50 160 55 180 70 180 60 190 65 205 50 195 35 205 40 190 30 180 45 180"
stroke="green" fill="transparent" stroke-width="5"/>
<path d="M20,230 Q40,205 50,230 T90,230" fill="none" stroke="blue" stroke-width="5"/>
</svg>
直线命令
<?xml version="1.0" standalone="no"?>
<svg width="100" height="100" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M10 10 H 90 V 90 H 10 z" stroke-width="5" fill="transparent" stroke="blue"></path>
<circle cx="10" cy="10" r="2" fill="red"/>
<circle cx="90" cy="90" r="2" fill="red"/>
<circle cx="90" cy="10" r="2" fill="red"/>
<circle cx="10" cy="90" r="2" fill="red"/>
</svg>
绘制平滑曲线的命令有三个,其中两个用来绘制贝塞尔曲线,另外一个用来绘制弧形或者说是圆的一部分
贝塞尔曲线的类型有很多,但是在path元素里,只存在两种贝塞尔曲线:三次贝塞尔曲线C,和二次贝塞尔曲线Q。
4个命令
C x1 y1, x2 y2, x y (or c dx1 dy1, dx2 dy2, dx dy)
这里的最后一个坐标(x,y)表示的是曲线的终点,另外两个坐标是控制点,(x1,y1)是起点的控制点,(x2,y2)是终点的控制点
<?xml version="1.0" standalone="no"?>
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M10 10 C 20 20, 40 20, 50 10" stroke="black" fill="transparent"/>
<path d="M70 10 C 70 20, 120 20, 120 10" stroke="black" fill="transparent"/>
<path d="M130 10 C 120 20, 180 20, 170 10" stroke="black" fill="transparent"/>
<path d="M10 60 C 20 80, 40 80, 50 60" stroke="black" fill="transparent"/>
<path d="M70 60 C 70 80, 110 80, 110 60" stroke="black" fill="transparent"/>
<path d="M130 60 C 120 80, 180 80, 170 60" stroke="black" fill="transparent"/>
<path d="M10 110 C 20 140, 40 140, 50 110" stroke="black" fill="transparent"/>
<path d="M70 110 C 70 140, 110 140, 110 110" stroke="black" fill="transparent"/>
<path d="M130 110 C 120 140, 180 140, 170 110" stroke="black" fill="transparent"/>
</svg>
<?xml version="1.0" standalone="no"?>
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80" stroke="black" fill="transparent"/>
<circle cx="10" cy="80" r="2" fill="red"/>
<circle cx="40" cy="10" r="2" fill="red"/>
<path d="M 10 80 L 40 10" stroke="red"/>
<circle cx="65" cy="10" r="2" fill="red"/>
<circle cx="95" cy="80" r="2" fill="red"/>
<path d="M 65 10 L 95 80" stroke="red"/>
<circle cx="150" cy="150" r="2" fill="red"/>
<circle cx="125" cy="150" r="2" fill="red"/>
<path d="M 95 80 L 125 150" stroke="blue"/>
<path d="M 150 150 L 180 80" stroke="blue"/>
</svg>
<?xml version="1.0" standalone="no"?>
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M10 80 S 40 10, 95 80" stroke="black" fill="transparent"/>
<circle cx="10" cy="80" r="2" fill="red"/>
<circle cx="40" cy="10" r="2" fill="red"/>
<circle cx="95" cy="80" r="2" fill="red"/>
<path d="M10 80 L 40 10" stroke="red"/>
<path d="M95 80 L 40 10" stroke="red"/>
</svg>
相同的起始点和终点,相同的控制点,在三次和二次赛贝尔曲线中勾画出来的图形不一样
<?xml version="1.0" standalone="no"?>
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg"">
<path d="M10 80 Q 95 10 180 80" stroke="black" fill="transparent"/>
</svg>
<?xml version="1.0" standalone="no"?>
<svg width="190px" height="160px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M10 80 Q 52.5 10, 95 80 T 180 80" stroke="black" fill="transparent"/>
</svg>
已知椭圆形的长轴半径和短轴半径,并且已知两个点(在椭圆上),根据半径和两点,可以画出两个椭圆,在每个椭圆上根据两点都可以画出两种弧形。所以,仅仅根据半径和两点,可以画出四种弧形。为了保证创建的弧形唯一,A命令需要用到比较多的参数
A rx ry x-axis-rotation large-arc-flag sweep-flag x y
a rx ry x-axis-rotation large-arc-flag sweep-flag dx dy
参数解释
<?xml version="1.0" standalone="no"?>
<svg width="320px" height="320px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M10 315
L 110 215
A 30 50 0 0 1 162.55 162.45
L 172.55 152.45
A 30 50 -45 0 1 215.1 109.9
L 315 10" stroke="black" fill="green" stroke-width="2" fill-opacity="0.5"/>
</svg>
<?xml version="1.0" standalone="no"?>
<svg width="325px" height="325px" version="1.1" xmlns="http://www.w3.org/2000/svg">
<path d="M80 80
A 45 45, 0, 0, 0, 125 125
L 125 80 Z" fill="green"/>
<path d="M230 80
A 45 45, 0, 1, 0, 275 125
L 275 80 Z" fill="red"/>
<path d="M80 230
A 45 45, 0, 0, 1, 125 275
L 125 230 Z" fill="purple"/>
<path d="M230 230
A 45 45, 0, 1, 1, 275 275
L 275 230 Z" fill="blue"/>
</svg>
fill属性设置对象内部的颜色
stroke属性设置绘制对象的线条的颜色
<svg>
<rect x="10" y="10" width="100" height="100" stroke="blue" fill="purple"
fill-opacity="0.5" stroke-opacity="0.8"/>
</svg>
除了颜色属性,还有其他一些属性用来控制绘制描边的方式
<?xml version="1.0" standalone="no"?>
<svg width="160" height="140" xmlns="http://www.w3.org/2000/svg" version="1.1">
<line x1="40" x2="120" y1="20" y2="20" stroke="black" stroke-width="20" stroke-linecap="butt"/>
<line x1="40" x2="120" y1="60" y2="60" stroke="black" stroke-width="20" stroke-linecap="square"/>
<line x1="40" x2="120" y1="100" y2="100" stroke="black" stroke-width="20" stroke-linecap="round"/>
</svg>
<?xml version="1.0" standalone="no"?>
<svg width="160" height="280" xmlns="http://www.w3.org/2000/svg" version="1.1">
<polyline points="40 60 80 20 120 60" stroke="black" stroke-width="20"
stroke-linecap="butt" fill="none" stroke-linejoin="miter"/>
<polyline points="40 140 80 100 120 140" stroke="black" stroke-width="20"
stroke-linecap="round" fill="none" stroke-linejoin="round"/>
<polyline points="40 220 80 180 120 220" stroke="black" stroke-width="20"
stroke-linecap="square" fill="none" stroke-linejoin="bevel"/>
</svg>
<?xml version="1.0" standalone="no"?>
<svg width="200" height="120" xmlns="http://www.w3.org/2000/svg" version="1.1">
<path d="M 10 75 Q 50 10 100 75 T 190 75" stroke="black"
stroke-linecap="round" stroke-dasharray="5,15,5" fill="none"/>
<path d="M 10 75 L 190 75" stroke="red"
stroke-linecap="round" stroke-width="1" stroke-dasharray="1,2,3,4,5" fill="none"/>
</svg>
解释说明
除了定义对象的属性外,你也可以通过CSS来样式化填充和描边。语法和在html里使用CSS一样,只不过你要把background-color、border改成fill和stroke。
注意,不是所有的属性都能用CSS来设置。上色和填充的部分一般是可以用CSS来设置的,比如fill,stroke,stroke-dasharray等,但是不包括下面会提到的渐变和图案等功能。另外,width、height,以及路径的命令等等,都不能用css设置。判断它们能不能用CSS设置还是比较容易的。
SVG规范将属性区分成properties和其他attributes,前者是可以用CSS设置的,后者不能。
3种CSS用法
CSS可以利用style属性插入到元素的行间
<svg>
<rect x="10" height="180" y="10" width="180" style="stroke: black; fill: red;"/>
</svg>
利用<style>设置一段样式段落。就像在<html>里这样的<style>一般放在<head>里,在svg里<style>则放在<defs>标签里。<defs>表示定义,这里面可以定义一些不会在SVG图形中出现、但是可以被其他元素使用的元素。同样可以使用hover
<?xml version="1.0" standalone="no"?>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<style type="text/css"><![CDATA[
#MyRect {
stroke: black;
fill: red;
}
]]></style>
</defs>
<rect x="10" height="180" y="10" width="180" id="MyRect"/>
</svg>
你也可以定义一个外部的样式表
<?xml version="1.0" standalone="no"?>
<?xml-stylesheet type="text/css" href="style.css"?>
<svg width="200" height="50" xmlns="http://www.w3.org/2000/svg" version="1.1">
<rect height="10" width="10" id="MyRect2"/>
</svg>
并非只能简单填充颜色和描边,更令人兴奋的是,你还可以创建和并在填充和描边上应用渐变色。
有两种类型的渐变:线性渐变和径向渐变。你必须给渐变内容指定一个id属性,否则文档内的其他元素就不能引用它。为了让渐变能被重复使用,渐变内容需要定义在<defs>标签内部,而不是定义在形状上面
线性渐变沿着直线改变颜色,要插入一个线性渐变,你需要在SVG文件的<defs>元素内部,创建一个<linearGradient> 节点。
<?xml version="1.0" standalone="no"?>
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<linearGradient id="Gradient1">
<stop class="stop1" offset="0%"/>
<stop class="stop2" offset="50%"/>
<stop class="stop3" offset="100%"/>
</linearGradient>
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
<stop offset="0%" stop-color="red"/>
<stop offset="50%" stop-color="black" stop-opacity="0"/>
<stop offset="100%" stop-color="blue"/>
</linearGradient>
<style type="text/css"><![CDATA[
#rect1 { fill: url(#Gradient1); }
.stop1 { stop-color: red; }
.stop2 { stop-color: black; stop-opacity: 0; }
.stop3 { stop-color: blue; }
]]></style>
</defs>
<rect id="rect1" x="10" y="10" rx="15" ry="15" width="100" height="100"/>
<rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#Gradient2)"/>
</svg>
以上是一个应用了线性渐变的<rect>元素的示例。线性渐变内部有几个<stop> 结点,这些结点通过指定位置的offset(偏移)属性和stop-color(颜色中值)属性来说明在渐变的特定位置上应该是什么颜色;可以直接指定这两个属性值,也可以通过CSS来指定他们的值,该例子中混合使用了这两种方法.
使用渐变时,我们需要在一个对象的属性fill或属性stroke中引用它,这跟你在CSS中使用url引用元素的方法一样。在本例中,url只是一个渐变的引用,我们已经给这个渐变一个ID——“Gradient”。要想附加它,将属性fill设置为url(#Gradient)即可。现在对象就变成多色的了,也可以用同样的方式处理stroke。
<linearGradient>元素还需要一些其他的属性值,它们指定了渐变的大小和出现范围。渐变的方向可以通过两个点来控制,它们分别是属性x1、x2、y1和y2,这些属性定义了渐变路线走向。渐变色默认是水平方向的,但是通过修改这些属性,就可以旋转该方向。下例中的Gradient2创建了一个垂直渐变。
注意: 你也可以在渐变上使用xlink:href属性。如果使用了该属性时,一个渐变的属性和颜色中值(stop)可以被另一个渐变包含引用。在下例中,你就不需要再Grandient2中重新创建全部的颜色中值(stop)。
<linearGradient id="Gradient1">
<stop id="stop1" offset="0%"/>
<stop id="stop2" offset="50%"/>
<stop id="stop3" offset="100%"/>
</linearGradient>
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1"
xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#Gradient1"/>
径向渐变与线性渐变相似,只是它是从一个点开始发散绘制渐变。创建径向渐变需要在文档的defs中添加一个<radialGradient>元素.
stops的使用方法与之前一致,但是现在这个对象的颜色是中间是红色的,且向着边缘的方向渐渐的变成蓝色。跟线性渐变一样,<radialGradient> 节点可以有多个属性来描述其位置和方向,但是它更加复杂。
cx、cy、fx、fy和r的取值范围0-1,也就是宽度和高度的比率,参考gradientUnits
cx,cy表示渐变的中心点,r表示渐变的半径,这三者构成了渐变区域。fx,fy表示渐变区域的焦点。
<?xml version="1.0" standalone="no"?>
<svg width="120" height="240" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient id="RadialGradient1">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
<radialGradient id="RadialGradient2" cx="0.25" cy="0.25" r="0.25">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
</defs>
<rect x="10" y="10" rx="15" ry="15" width="100" height="100" fill="url(#RadialGradient1)"/>
<rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#RadialGradient2)"/>
</svg>
<?xml version="1.0" standalone="no"?>
<svg width="120" height="120" version="1.1"
xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient id="Gradient"
cx="0.5" cy="0.5" r="0.5" fx="0.25" fy="0.25">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
</defs>
<rect x="10" y="10" rx="15" ry="15" width="100" height="100"
fill="url(#Gradient)" stroke="black" stroke-width="2"/>
<circle cx="60" cy="60" r="50" fill="transparent" stroke="white" stroke-width="2"/>
<circle cx="35" cy="35" r="2" fill="white" stroke="white"/>
<circle cx="60" cy="60" r="2" fill="white" stroke="white"/>
<text x="38" y="40" fill="white" font-family="sans-serif" font-size="10pt">(fx,fy)</text>
<text x="63" y="63" fill="white" font-family="sans-serif" font-size="10pt">(cx,cy)</text>
</svg>
线性渐变和径向渐变都需要一些额外的属性用于描述渐变过程,这里我希望额外提及一个spreadMethod属性,该属性控制了当渐变到达终点的行为,但是此时该对象尚未被填充颜色.
<?xml version="1.0" standalone="no"?>
<svg width="220" height="220" version="1.1" xmlns="http://www.w3.org/2000/svg">
<defs>
<radialGradient id="GradientPad"
cx="0.5" cy="0.5" r="0.4" fx="0.75" fy="0.75"
spreadMethod="pad">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
<radialGradient id="GradientReflect"
cx="0.5" cy="0.5" r="0.4" fx="0.75" fy="0.75"
spreadMethod="reflect">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
<radialGradient id="GradientRepeat"
cx="0.5" cy="0.5" r="0.4" fx="0.75" fy="0.75"
spreadMethod="repeat">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
<radialGradient id="GradientReflect"
cx="0.5" cy="0.5" r="0.4" fx="0.75" fy="0.75"
spreadMethod="reflect">
<stop offset="0%" stop-color="red"/>
<stop offset="100%" stop-color="blue"/>
</radialGradient>
</defs>
<rect x="10" y="10" rx="15" ry="15" width="100" height="100" fill="url(#GradientPad)"/>
<rect x="10" y="120" rx="15" ry="15" width="100" height="100" fill="url(#GradientRepeat)"/>
<rect x="120" y="120" rx="15" ry="15" width="100" height="100" fill="url(#GradientReflect)"/>
<text x="15" y="30" fill="white" font-family="sans-serif" font-size="12pt">Pad</text>
<text x="15" y="140" fill="white" font-family="sans-serif" font-size="12pt">Repeat</text>
<text x="125" y="140" fill="white" font-family="sans-serif" font-size="12pt">Reflect</text>
</svg>
该属性有两个值,默认值为objectBoundingBox
在我看来patterns(图案)是SVG中用到的最让人混淆的填充类型之一。它的功能非常强大,所以我认为他们值得讨论一下并且我们应至少对他们有最基本的了解。跟渐变一样,<pattern>需要放在SVG文档的<defs>内部。
<?xml version="1.0" standalone="no"?>
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1">
<defs>
<linearGradient id="Gradient1">
<stop offset="5%" stop-color="white"/>
<stop offset="95%" stop-color="blue"/>
</linearGradient>
<linearGradient id="Gradient2" x1="0" x2="0" y1="0" y2="1">
<stop offset="5%" stop-color="red"/>
<stop offset="95%" stop-color="orange"/>
</linearGradient>
<pattern id="Pattern" x="0" y="0" width=".25" height=".25">
<rect x="0" y="0" width="50" height="50" fill="skyblue"/>
<rect x="0" y="0" width="25" height="25" fill="url(#Gradient2)"/>
<circle cx="25" cy="25" r="20" fill="url(#Gradient1)" fill-opacity="0.5"/>
</pattern>
</defs>
<rect fill="url(#Pattern)" stroke="black" x="0" y="0" width="200" height="200"/>
</svg>
<?xml version="1.0" standalone="no"?>
<svg width="300" height="300" xmlns="http://www.w5.org/2000/svg/" version="1.1">
<defs>
<linearGradient id="Gradient111">
<stop offset="5%" stop-color="white"/>
<stop offset="95%" stop-color="blue"/>
</linearGradient>
<linearGradient id="Gradient222" x1="0" x2="0" y1="0" y2="1">
<stop offset="5%" stop-color="red"/>
<stop offset="95%" stop-color="orange"/>
</linearGradient>
<pattern id="Pattern12" x="0" y="0" width=".25" height=".25">
<rect x="0" y="0" width="50" height="50" fill="skyblue"/>
<rect x="0" y="0" width="25" height="25" fill="url(#Gradient222)"/>
<circle cx="25" cy="25" r="20" fill="url(#Gradient111)" fill-opacity="0.5"/>
</pattern>
</defs>
<rect fill="url(#Pattern12)" stroke="black" x="0" y="0" width="300" height="300"/>
</svg>
改变对象大小,并不能自适应
patternUnits
patternContentUnits
这意味着除非你至少指定其中一个属性值(patternContentUnits或patternUnits),否则在pattern中绘制的形状将与pattern元素使用的坐标系不同.
如果对象改变了大小,pattern会自适应其大小,但是对象里面的内容不会自适应。如上图对象rect的大小增大了,内容并没有增大
<?xml version="1.0" standalone="no"?>
<svg width="300" height="300" xmlns="http://www.w6.org/2000/svg/" version="1.1">
<defs>
<linearGradient id="Gradient11">
<stop offset="5%" stop-color="white"/>
<stop offset="95%" stop-color="blue"/>
</linearGradient>
<linearGradient id="Gradient22" x1="0" x2="0" y1="0" y2="1">
<stop offset="5%" stop-color="red"/>
<stop offset="95%" stop-color="orange"/>
</linearGradient>
<pattern id="Pattern123" width=".25" height=".25" patternContentUnits="objectBoundingBox">
<rect x="0" y="0" width=".25" height=".25" fill="skyblue"/>
<rect x="0" y="0" width=".125" height=".125" fill="url(#Gradient22)"/>
<circle cx=".125" cy=".125" r=".1" fill="url(#Gradient11)" fill-opacity="0.5"/>
</pattern>
</defs>
<rect fill="url(#Pattern123)" stroke="black" x="0" y="0" width="300" height="300"/>
</svg>
设置了patternContentUnits="objectBoundingBox",并改变了取值单位后,就可以自适应了
在一个SVG文档中,
<?xml version="1.0" standalone="no"?>
<svg width="300" height="300" xmlns="http://www.w3.org/2000/svg" version="1.1">
<text x="10" y="10">Hello World!</text>
<text>
<tspan font-weight="bold" fill="red">This is bold and red</tspan>
</text>
</svg>
June 16, 2018
求职意向:前端工程师
去哪儿是中国领先的旅游搜索引擎,去哪儿是目前全球最大的中文在线旅行网站
业务上
技术上
去哪儿是中国领先的旅游搜索引擎,去哪儿是目前全球最大的中文在线旅行网站 业务上
参与5个web网站、1个公众号、1个H5和2个RN项目的开发
酒店业务华为对接,协调团结10多个小组近30人,推动项目的发展,按时交付
技术上
设计开发任务模板系统,提高运营效率100%,省50%成本,获年度优秀项目奖(10,000元)
设计开发npm包q-antd,提高项目开发效率30%,提高项目易维护性30%
优化去哪儿前端构建工具packing,新建页面错误率降为0,新建页面节省50%时间
设计开发grunt-i19n插件,准确率提高到100%,节省50%工作时间
爱折腾,知识面广,吸收了travis和jest等使得开发效率、正确率和规范化大大提高
喜欢逛github,研究优秀的项目,从中学习新知识和牛逼的地方
June 14, 2018
感觉vue-cli写得相当不错,想瞅瞅源码,于是就进入package.json中找找main字段吧,因为main 字段就是工程的入口文件嘛。
上下看了三遍,卧槽,没有!
好吧,main字段没有,bin总该有吧。
上下又看了三遍,卧槽,还是没有,唯一可疑的发现了个workspaces字段。
你牛B,那就去npm官网瞅瞅workspaces字段是什么意思吧。
卧槽,无此字段的介绍。瞬间一脸的懵逼。
后来各种搜索why package.json no main keyword,未找到答案
最后尝试了下package.json workspaces关键词的搜索,找到了yarn的一篇文章(原文传送门),柳暗花明又一村了。
大概意思是,随着时间的推移我们的项目会变得越来越大,模块越来越多。这时候有两种解决方案。
放在同一个repo中来管理的时候通常使用Monorepos的方式来管理此repo,使用这种方式的有很多我们经常使用 的js包,比如Babel, React, Vue, Angular, Jest等
然而,仅仅进行拆分并使用Monorepos管理远远是不够的,比如测试,管理依赖,发布多个包等变得复杂起来。 这是一些工具比如Lerna就派上了用场
Lerna是一个对多个子模块工程管理进行优化的工具。简而言之,Lerna会安装在工程中的每个package,并在 相互依赖的package之间创建软链接。
然而,作为一个包管理的装饰器,Lerna不能有效的控制node_module中的内容。 比如多个子模块都依赖同一个包。Lerna会安装多次而不是一次。
Workspaces能够让用户根据根package.json中的workspace字段从多个子文件中的package.json中安装以依赖。
例如Jest的例子
工程目录结构如下
| jest/
| ---- package.json //根package.json
| ---- packages/
| -------- jest-matcher-utils/
| ------------ package.json //子package.json
| -------- jest-diff/
| ------------ package.json
...
根package.json内容如下
{
"private": true,
"name": "jest",
"devDependencies": {
"chalk": "^2.0.1"
},
"workspaces": [
"packages/*"
]
}
两个字模块中的package.json如下
{
"name": "jest-matcher-utils",
"description": "...",
"version": "20.0.3",
"license": "...",
"main": "...",
"browser": "...",
"dependencies": {
"chalk": "^1.1.3",
"pretty-format": "^20.0.3"
}
}
{
"name": "jest-diff",
"version": "20.0.3",
"license": "...",
"main": "...",
"browser": "...",
"dependencies": {
"chalk": "^1.1.3",
"diff": "^3.2.0",
"jest-matcher-utils": "^20.0.3",
"pretty-format": "^20.0.3"
}
}
使用Lerno进行安装结果
| jest/
| ---- node_modules/
| -------- chalk/
| ---- package.json
| ---- packages/
| -------- jest-matcher-utils/
| ------------ node_modules/
| ---------------- chalk/
| ---------------- pretty-format/
| ------------ package.json
| -------- jest-diff/
| ------------ node_modules/
| ---------------- chalk/
| ---------------- diff/
| ---------------- jest-matcher-utils/ (symlink) -> ../jest-matcher-utils
| ---------------- pretty-format/
| ------------ package.json
...
我们可以看到jest-matcher-utils的冗余
使用workpaces进行安装
| jest/
| ---- node_modules/
| -------- chalk/
| -------- diff/
| -------- pretty-format/
| -------- jest-matcher-utils/ (symlink) -> ../packages/jest-matcher-utils
| ---- package.json
| ---- packages/
| -------- jest-matcher-utils/
| ------------ node_modules/
| ---------------- chalk/
| ------------ package.json
| -------- jest-diff/
| ------------ node_modules/
| ---------------- chalk/
| ------------ package.json
...
我们看到只有一个jest-matcher-utils
仅仅使用yarn add等命令在workspaces文件家中进行管理即可。
$ cd packages/jest-matcher-utils/
$ yarn add left-pad
✨ Done in 1.77s.
$ git status
modified: package.json
modified: ../../yarn.lock
但是注意,workspaces中无yarn.lock,只在root中含有一个yarn.lock
workspaces并没有使Lerna过时
Lerna有他的长处和优点,可以和workspaces共存
Jest使用yarn来启动工程,使用Lerna来发布。
June 12, 2018
以下操作是基于yarn的,npm同样有效
在之前介绍的三个方法中,虽然第三个方法看上去很完美。但是依然有一个问题。会出现multi package的问题,这是一个什么问题呢?比如我们的实际工程merchant_fe中引入了react,我们引入的q-antd(q-antd是被测试的包)中也引入了react。那么这时就需要在merchant_fe和q-antd都引入react,他们并没有引用同一个react包。
那么有没更好的方法来解决测试的问题?我们是不是可以换一种思路来解决问题,之前都是通过装包的方式来进行测试。 我们可否不装包就行测试,而是直接对包进行测试呢?
左思右想了下,之前了解过jest,不就是可以用在这种情况下。
于是,引入jest进行尝试。果不其然,完全可以。这才是真正的正解吧,只要我的包通过了各种姿势的测试,就不怕安装的包有问题。
开发一个npm包,偶尔或许经常需要优化下,每次都发包,然后安包,最后再测试,肯定太繁琐了。还有可能遇到愚蠢的错误,比如变量 未定义变量等。
所以,在发包前进行简单或者完整的测试是有必要的,这样也不至于导致我们的包的版本非常多。
比如要测试q-antd
import { Form } from 'absoulte_path|relative_path/to/q-antd'
这个方法最简单,适用于有个专门的测试工程来做测试这件事情.在实际工程中我们往往是这样引用的
import { Form } from 'q-antd'
每次测试完还需要改回来,太愚蠢了。
所以,不建议此方法。
具体步骤如下
#!/usr/local/env bash
cd path/to/q-antd
yarn pack
cd path/to/测试工程
yarn add absolute_path|realtive_path/to/q-antd/q-antd-version.tgz
yarn pack会将q-antd包生成一个tgz压缩包,然后就可以通过yarn来安装了
此方法其实和发布npm类似,没死修改之后都需要执行上面的至少两个步骤。而且每次pack的版本不能相同,否则,新增的内容不会 被引用到
总之,此方法也不行,太麻烦
具体步骤如下
#!/usr/local/env bash
cd path/to/q-antd
yarn link
cd path/to/测试工程
yarn link q-antd
yarn link会将q-antd放到node的全局变量里面,所以在目标工程里直接yarn link q-antd就可以了。
link一次,使用永久
此乃最佳方法