├── .DS_Store
├── src
├── .DS_Store
├── this.md
├── CSS3--font-face使用.md
├── javascript数据结构3-栈.md
├── javascript数据结构5-链表2 存放点数据(x,y).md
├── File Input多次添加文件,用来实现上传等操作.md
├── javascript面向对象和面向委托.md
├── 2017阿里实习校招-前端技术视频面试体会.md
├── HTTP协议实践篇--浏览器缓存总结、利用Fiddler和apache模拟.md
├── javascript数据结构4-队列2-基数排序.md
├── webpack基础实践2.md
├── webpack基础实践1.md
├── javascript数据结构8-图(Graph).md
├── openlayers 3实践与原理探究4.3.md
├── 写给前端er的TCP-IP知识及《图解TCP-IP》读书笔记.md
├── openlayers 3实践与原理探究2.md
├── javascript数据结构6-字典-散列-集合.md
├── React Router的一个完整示例.md
├── 使用javascript原生实现一个模板引擎.md
├── openlayers 3实践与原理探究4.2.md
├── webpack项目实践.md
├── javascript数据结构1-数组.md
├── openlayers 3实践与原理探究4.1.md
├── rollup+es6最佳实践.md
├── javascript数据结构4-队列.md
├── 前端自动化测试工具--使用karma进行javascript单元测试.md
├── PHP爬虫最全总结2-phpQuery,PHPcrawer,snoopy框架中文介绍.md
├── javascript数据结构2-列表.md
├── 动手DIY一个underscorejs库及underscorejs源码分析3.md
├── 阿里巴巴校招2017前端笔试题目-原生js-html5-实现一个路由.md
├── 前端自动化测试工具PhantomJS+CasperJS结合使用教程.md
├── ECharts 3.0底层zrender 3.x源码分析3-Handler(C层).md
├── HTTP协议实践篇--使用fiddle与后台php交互.md
├── openlayers 3实践与原理探究4.4.md
├── 使用React+Three.js封装一个三维地球.md
├── 一步一步DIY jQuery库3-引入sizzle引擎.md
├── openlayers 3实践与原理探究1.md
├── javascript数据结构7-二叉搜索树(BST).md
├── domReady机制探究及DOMContentLoaded研究.md
├── EChart 2升级EChart 3注意事项.md
├── openlayers 3扩展,调用百度地图、高德地图、天地图服务.md
└── 动手DIY一个underscorejs库及underscorejs源码分析2.md
└── README.md
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/Blog/HEAD/.DS_Store
--------------------------------------------------------------------------------
/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zrysmt/Blog/HEAD/src/.DS_Store
--------------------------------------------------------------------------------
/src/this.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: this指针总结
3 | tags:
4 | - FE
5 | - javascript
6 | categories: 前端技术
7 | date: 2016-09-28 00:00:00
8 | ---
9 | 文章只是简单列举了方式和一些会改变this指针的情况
10 |
11 | # 1.探寻之,必昭然若揭
12 | 1. new绑定 this-->新创建的对象
13 | ``var bar = new foo()``
14 | 2. call/bind 硬绑定 this-->指定的对象
15 | ``var bar = foo.call(obj2)``
16 | 3. 隐式绑定 this-->上下文对象
17 | ``var bar = obj1.foo()``
18 | 4. 默认绑定 this-->全局对象window
19 |
20 | 四种情况也是按照优先级排列的
21 |
22 | # 2.实践之,定了然于胸
23 | ## 2.1 回掉函数会改变this指针
24 | 绑定
25 | ```javascript
26 | dbTools.queryUsrDB2Datas(function(){
27 | usrResDiv.fyDiv.apply(usrResDiv,arguments);
28 | });
29 | ```
30 | ## 2.2 setTimeout/setinterval函数会改变this指针(例子见第三部分)
31 | ## 2.3 绑定的例外
32 | - `foo.call(null)` 使用`null`或者`undefined`,忽略传入对象的`this`,实际运用的是默认绑定,这也是这样方法的弊端,this指向`window`。
33 | 修改`var DMZ = Object.create(null); foo.apply(DMZ,[2,3]);`
34 |
35 | - 间接引用
36 |
37 | ```javascript
38 | function foo(){
39 | console.log(this.a);
40 | }
41 | var a = 2;
42 | var o = {a:3,foo:foo};
43 | var p = {a:4};
44 |
45 | o.foo();//3
46 | (p.foo = o.foo)(); //2 this-->window
47 | p.foo(); //4
48 | ```
49 | `p.foo = o.foo`返回值是目标函数的引用,因此调用位置是foo(),而不是`p.foo()`,`o.foo()`;
50 | # 3.避免之,需谨小事微
51 | 除了第一部分的方法外,还有一些常用的方法。
52 | ## 3.1 ES5中我们经常会使用`self = this`,如:
53 |
54 | ```javascript
55 | function foo(){
56 | var self = this;
57 | setTimeout(function(){
58 | console.log(self.a);
59 | },100);
60 | }
61 |
62 | var obj = {
63 | a:2;
64 | }
65 | foo.call(obj);//2
66 | ```
67 | ## 3.2 ES6中的箭头函数(this词法)
68 |
69 | ```javascript
70 | function foo(){
71 | setTimeout => {
72 | console.log(this.a);//this继承来自foo()
73 | },100);
74 | }
75 |
76 | var obj = {
77 | a:2;
78 | }
79 | foo.call(obj);//2
80 | ```
--------------------------------------------------------------------------------
/src/CSS3--font-face使用.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: CSS3--font-face使用
3 | tags:
4 | - FE
5 | - CSS
6 | - CSS3
7 | categories: 前端技术
8 | date: 2016-09-27 19:27:49
9 | ---
10 | # 1.介绍
11 | - @font-face是CSS3中的一个模块,他主要是把自己定义的Web字体嵌入到你的网页中,不用担心兼容性,@font-face在IE4中都支持。
12 | - 如果是用字体做logo,英文的话字体和图片占用大小差不多,但是中文的字体包一般比较大,最好还是使用图片的形式。
13 |
14 | # 2.快速实践
15 | - [下载字体](http://www.dafont.com/)需要格式为.tff格式的字体文件
16 | - 搜索Webfont Generator,或者直接使用[该网站](https://www.web-font-generator.com/)提供的服务。这很简单,进入网站后选择.tff字体文件上传,勾选同意的复选框,点击`Generate web font`,点击`Download Package`下载,解压缩文件。
17 | - 使用
18 | 新建index.css
19 |
20 | ```css
21 | @font-face {
22 | font-family: 'Happy-Camper-Regular';
23 | src: url('../fonts2/Happy-Camper-Regular.eot');
24 | src: url('../fonts2/Happy-Camper-Regular.eot?#iefix') format('embedded-opentype'), url('../fonts2/Happy-Camper-Regular.woff') format('woff'), url('../fonts2/Happy-Camper-Regular.ttf') format('truetype'), url('../fonts2/Happy-Camper-Regular.svg#SingleMaltaRegular') format('svg');
25 | font-weight: normal;
26 | font-style: normal;
27 | }
28 |
29 | h2.demo {
30 | font-size: 100px;
31 | font-family: 'Happy-Camper-Regular'
32 | }
33 |
34 | ```
35 | ```html
36 |
37 |
38 |
39 |
40 | 字体
41 |
42 |
43 |
44 | hello world!You are my Destiny
45 |
46 |
47 | ```
48 |
49 | # 3.字体icon
50 | 使用某些字体,如:`WebSymbols-Regular`[百度云下载地址](http://pan.baidu.com/s/1jIO0Y2q),`Guifx`字体,包括现在开源的比较流行的`Font Awesome`,使用方法同上。在html文件中如下示例:
51 |
52 | ```html
53 | A
54 | B
55 | C
56 | D
57 | F
58 | ```
59 | 每一行显示的是其对应的图标
60 | 
61 | 参考文献:
62 | - [下载字体的地方](http://www.dafont.com/)
63 | - [CSS3 @font-face](http://www.w3cplus.com/content/css3-font-face)
64 | - [@font-face制作Web Icon](http://www.w3cplus.com/css3/web-icon-with-font-face)
65 |
--------------------------------------------------------------------------------
/src/javascript数据结构3-栈.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: javascript数据结构3-栈
3 | tags:
4 | - javascript
5 | - 数据结构
6 | categories: 数据结构
7 | date: 2016-10-09 00:00:00
8 | ---
9 |
10 | 后进先出(LIFO,last-in-first-out)的数据结构
11 | 类比:堆叠盘子,只能从上面拿走盘子
12 |
13 | ```html5
14 |
15 |
16 |
17 | 栈
18 |
19 |
20 |
55 |
56 |
57 | ```
58 | 例子:
59 | 十进制转化为二进制,使用栈实现:
60 |
61 | ```javascript
62 | /*数制间的相互转换*/
63 | function mulBase(num,base){
64 | var s=new Stack();
65 | do{
66 | s.push(num% base);
67 | num=Math.floor(num /=base);
68 | }while(num > 0);
69 | var cov="";
70 | console.log(s.length());
71 | while(s.length() >0){
72 | cov += s.pop();
73 |
74 | }
75 | return cov;
76 | }
77 | var num=32;
78 | var newNum=mulBase(32,2); //十进制转换为二进制
79 | console.log(newNum);
80 | document.write(newNum);
81 | ```
--------------------------------------------------------------------------------
/src/javascript数据结构5-链表2 存放点数据(x,y).md:
--------------------------------------------------------------------------------
1 | ---
2 | title: javascript数据结构5-链表2 存放点数据(x,y)
3 | tags:
4 | - javascript
5 | - 数据结构
6 | categories: 数据结构
7 | date: 2016-10-09 00:00:00
8 | ---
9 |
10 | ```html5
11 |
12 |
13 |
14 |
15 | Document
16 |
17 |
18 |
87 |
88 |
89 | ```
--------------------------------------------------------------------------------
/src/File Input多次添加文件,用来实现上传等操作.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: File Input多次添加文件,动态删除文件,用来实现上传等操作
3 | tags: FE
4 | categories: 前端技术
5 | date: 2016-09-27 00:00:00
6 | ---
7 | ### 1.需求图示
8 | 
9 |
10 | ### 2.按图索骥
11 | - 添加 实际上,添加附件就是``的控件,`var fileList = getElementById(myFile).files`就可以得到选择的文件的FileList对象,这个对象是类数组的对象(含义有点像函数参数arguments)。记住这一点很重要。
12 |
13 | - 显示 下面的显示文件名的面板根据上传的文件名`name`显示
14 |
15 | ### 3.刨根问底
16 | - FileList类数组对象
17 | `console.log(fileList)`打印出来的结果显示:
18 | ``` bash
19 | FileList
20 | 0:File
21 | lastModified:1446204650848
22 | lastModifiedDate:Fri Oct 30 2015 19:30:50 GMT+0800 (中国标准时间)
23 | name:"CCGIS.png"
24 | size:809542
25 | type:"image/png"
26 | webkitRelativePath:""
27 | __proto__:File
28 | length:1
29 | __proto__:FileList
30 | ```
31 | 思考:我们只需要能动态修改fileList即可,第一想法是将它转化为数组进行操作。
32 | `` files = Array.prototype.slice.call(files); ``
33 |
34 | ### 4.付诸行动
35 | 动手编程吧:
36 | html很简单,省略
37 | 逻辑代码
38 | ``` javascript
39 | var fileInput = document.getElementById('myFile');
40 | var files = fileInput.files; //filelist
41 |
42 | $('#myFile').on('change', function(event) {
43 |
44 | files = fileInput.files; //应该重新获取
45 | console.log(files);
46 |
47 | files = Array.prototype.slice.call(files); //全部转化为数组
48 | fileLists = fileLists.concat(files);
49 | //显示文件名面板
50 | if (files.length !== 0) {
51 | var html = '';
52 | for (var i = 0; i < files.length; i++) {
53 | html += "" + files[i].name + "  ![]()
";
54 | }
55 | $('.upfile-list-mes').append(html);
56 | }
57 | });
58 |
59 | /*点击叉号可以删除要上传的文件*/
60 | $('.upfile-list-mes').on('click', '.icon-remove', function(event) {
61 | var ind = $(this).parent().index();
62 | $(this).parent().css('display', 'none');
63 | fileLists.splice(ind, 1);//修改fileLists
64 | console.log(fileLists);
65 | });
66 | ```
67 |
68 |
--------------------------------------------------------------------------------
/src/javascript面向对象和面向委托.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: javascript面向对象和面向委托
3 | tags:
4 | - FE
5 | - javascript
6 | - 设计模式
7 | categories: 前端技术
8 | date: 2016-09-27 00:00:00
9 | ---
10 |
11 | 昨天看了一本书《你不知道的javascript(上)》关于这方面的内容,体会颇深,其中书中讲到的把javascript当作是面向委托的语言比面向对象的解释更加贴切,下面我就简单结合自己的理解,书写阐述一下,也可以作为一种笔记记录。
12 | ### 1. 提取精华——几个重要的方法
13 | #### 1.1 原型链关联
14 | - Bar.prototype = Foo.prototype;
15 | - Bar.prototype = new Foo();
16 | - Bar.prototype = Object.create(Foo.prototype);
17 | 第一种方式,没有创建Bar.prototype的新对象Bar.prototype直接引用了Foo.prototype,修改Bar.prototype会影响Foo.prototype
18 | 第二种方式,创建了一个关联Bar.prototype的新对象,new其实是调用Foo的“构造函数”,有些东西会影响到Bar()的后代。
19 | 第三种方式,Object.create() 方法创建一个拥有指定原型和若干个指定属性的对象。
20 | 语法:``Object.create(proto, [ propertiesObject ])``
21 | 参数:proto 一个对象,作为新创建对象的原型。
22 | propertiesObject 可选。该参数对象是一组属性与值,该对象的属性名称将是新创建的对象的属性名称,值是属性描述符(这些属性描述符的结构与Object.defineProperties()的第二个参数一样)
23 | > [MDN](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
24 |
25 | ES5之前Object.create Poyfill代码:
26 | ```javascript
27 | if(!Object.create){
28 | Object.create = function(o){
29 | function F(){};
30 | F.prototype = o;
31 | return new F(); //new的作用参见上述 第二种方式
32 | }
33 | }
34 | ```
35 | ES5:``Object.setPrototypeOf(Bar.prototype,Foo.prototype)``更加标准可靠
36 | #### 1.2 ES6 class
37 | 内部也是通过原型链实现的,只是一种语法糖。
38 |
39 | ### 2.针尖麦芒——面向对象(OO) VS 面向委托(对象关联 OLOO)
40 | - OO:类的继承是复制行为,简单说关系是父子关系
41 | OLOO: 只是对象的关联(基于原型/原型链),简单说关系是兄弟关系,互相关联。
42 |
43 | - 代码
44 | OO风格:
45 | ```javascript
46 | function Foo(who){
47 | this.name = who;
48 | }
49 | Foo.prototype.identity = function(){
50 | return "I am "+this.name;
51 | };
52 |
53 | function Bar(who){
54 | Foo.call(this,who);
55 | }
56 | Bar.prototype = Object.create(Foo.prototype);
57 |
58 | Bar.prototype.speak = function(){
59 | alert("hello,"+this.identity()+" .");
60 | };
61 |
62 | var b1 = new Bar('b1');
63 | var b2 = new Bar('b2');
64 | b1.speak();
65 | b2.speak();
66 | ```
67 |
68 | OLOO风格:
69 | ```javascript
70 | Foo = {
71 | init: function(who) {
72 | this.name = who;
73 | },
74 | identity: function() {
75 | return "I am " + this.name;
76 | }
77 | };
78 |
79 | Bar = Object.create(Foo);
80 | Bar.speak = function() {
81 | alert("hello," + this.identity() + " .");
82 | };
83 |
84 | var b1 = Object.create(Bar);
85 | b1.init('b1');
86 | var b2 = Object.create(Bar);
87 | b2.init('b2');
88 | b1.speak();
89 | b2.speak();
90 | ```
91 |
92 | ### 3.问题探究
93 | **内省:**我们想看Foo和Bar之间的关系
94 | OO:对比的是Bar.prototype与Foo的关系,并不是Bar和Foo的关系
95 | ```javascript
96 | console.log(Bar.prototype instanceof Foo); //true
97 | console.log(Object.getPrototypeOf(Bar.prototype) === Foo.prototype);//true
98 | console.log(Foo.prototype.isPrototypeOf(Bar.prototype));//true
99 | ```
100 |
101 | OLOO:是Bar和Foo的关系
102 | ```javascript
103 | console.log(Object.getPrototypeOf(Bar) === Foo);
104 | console.log(Foo.isPrototypeOf(Bar));
105 | ```
--------------------------------------------------------------------------------
/src/2017阿里实习校招-前端技术视频面试体会.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 2017阿里实习校招-前端技术视频面试体会
3 | tags:
4 | - FE
5 | - 面试
6 | categories: 前端技术
7 | date: 2017-05-22 16:14:00
8 | ---
9 | 快要秋招找工作了,预约的暑期实习面试,也是为了秋招攒点经验。约的时间是15:15 - 16:00,焦急又必须有耐心的等待后,终于在下午四点左右接通了视频,紧张ing。
10 |
11 | 首先面试官介绍了自己的花名,心里紧张没记下来,现在想想挺后悔的。但是谁让我紧张了呢?
12 | 然后是我的自我介绍,简单的介绍了一下我的基本情况,把技能和项目都介绍了介绍。
13 | 面试官态度挺好的,平易近人的感觉,慢慢的也就不紧张了,后面面试官一路45度仰天扣鼻子,也是让我乐了,心态更加轻松随意了。
14 |
15 | 面试的前端工程师,当然最重要的技术问题。上来就是让我共享屏幕,然后打开IDE写个排序,尼玛宝宝好怕,虽然简单,但是全部写下来运行太痛苦了。
16 |
17 | # 1.数组排序
18 | - 原生实现 sort函数,倒是很快就写出来了,然后随时就让我用不是原生的方法实现
19 | ```javascript
20 | var arr = [1,6,8,34,20,10];
21 | function main(arr,sortType){
22 | return arr.sort(function(num1,num2){
23 | if(sortType == "desc"){
24 | return num1 < num2;
25 | }else{
26 | return num1 > num2;
27 | }
28 | })
29 | }
30 | ```
31 | - 快排 我记得模棱两可,没写出来啊,心痛啊。现在把正确的贴在这里。
32 | ```javascript
33 | function quickSort(arr) {
34 | if(arr.length<=1) {
35 | return arr;
36 | }
37 |
38 | let leftArr = [];
39 | let rightArr = [];
40 | let q = arr[0];
41 | for(let i = 1,l=arr.length; iq) {
43 | rightArr.push(arr[i]);
44 | }else{
45 | leftArr.push(arr[i]);
46 | }
47 | }
48 |
49 | return [].concat(quickSort(leftArr),[q],quickSort(rightArr));
50 | }
51 | ```
52 | - 还好冒泡还记得,又用冒泡写的,马马虎虎能运行了。
53 | ```javascript
54 | function bubbleSort(arr) {
55 | for(let i = 0,l=arr.length;iarr[j]) {
58 | let tem = arr[i];
59 | arr[i] = arr[j];
60 | arr[j] = tem;
61 | }
62 | }
63 | }
64 | return arr;
65 | }
66 | ```
67 |
68 | # 2.ES6
69 | 提了下ES6,问了ES6的**let,const与var**的区别,特意说下let和const有块级作用域。var没有。然后又问了我都有什么作用域,我说ES5没有块级作用域,有全局作用域和函数作用域。然后面试官补充了一个对象作用域,这个我知道只是好像没经过总结过啊。
70 |
71 | 问我在项目中使用的ES6都有哪些?我说**Promoise**挺优雅的,然后让我写写,然后我就写了个XmlHttpServer,啊悲了个催了的,我的编辑器没有智能提示(论一个智能提醒的IDE有多重要),然后我手写的ajax请求,忘记了很多细节,怎么写啊,写了部分,面试官看不下去了吧(心伤),说他明白我的意思,你不用全部写下来,把过程大概写好就行了。然后我就写了怎么调用,我是理解了Promise,不知道这个问题面试官给打多少分,所以说坑都是自己挖的。
72 |
73 | 其实介绍了几次我使用了React+react router,估计阿里内部使用的是Weex,Kissy这样的自己的框架,面试官估计没有太接触React,所以一直没问我这方面的问题。
74 |
75 | # 3.项目
76 | 一直不提我使用React写的项目,提起来我之前做的一个项目,那个项目我也没啥说的吧,我只能说我比较早做的,使用的都是老技术。运用的是Bootstrap,查询渲染数据,巴拉巴拉,感觉我说完的意思是我的这个项目不咋样,自己不相信自己了啊,怀疑了人生。
77 |
78 | 然后问我做了其他的有什么最深的体会。
79 | 所以我立刻就说了使用 React的项目(终于可以介绍了),然后我就说主要分了两个模块,一个是基础的显示模块,一个是地图模块,使用Openlayers api的组件化,还和github上的有个OpenLayer封装的做了个对比,我说有一个开源的使用React封装的Openlayers不方便,而且源码不全,我就自己封装了,面试官再次表现出了不太了解React,所以就没有继续追问下去。
80 |
81 | # 4.对可视化的理解
82 | 估计看了我的博客,我的博客最近写的是WebGL,就问了我对WebGL的理解。
83 | 理解,这怎么说啊,好难过,我也不知道怎么描述啊。而且我也只是刚看了一个星期的书,还有一个周的Threejs罢了,我就说性能好,但是WebGL书写比较麻烦,所以大家都用Three.js,我也看了部分的Three.js。然后又顺嘴提了下我后面的研究方向, 目前还没有太深的理解(是不是这句话不应该说啊,应该忽悠忽悠的啊),然后就又随口说了下cesium.js,与我们的专业还有点关系--webgis,然后我们会在此基础上扩展。
84 |
85 | 总之问我理解,我又给出的印象是我的理解不深,痛心了。
86 | 然后给了个更大的题目,对可视化的理解,这题目呢,怎么说啊。我只能说大数据可视化和canvas,然后举了举例子,ECharts,datav,mapv等,然后说我对这方面挺有兴趣的,忘了面试官说什么了,好像的意思也只是你对这感兴趣,有个方向,没有深耕下去。
87 |
88 | # 5.总结
89 | 这可以说是我第一次真正意义上的面试,第一次视频面试,还是阿里的。总之感觉是这次我没戏了,哪怕是个实习面试。看来是要多刷刷面试经验的。
90 |
91 | 离远方还是有很多路要走啊,还有两三个月时间,继续加油吧,一定要告诫自己不要气馁,坚持就是胜利。
92 |
93 | 简单体会,写至此处,感怀万千。,坚持就是胜利。 简单体会,写至此处,感怀万千。
94 |
--------------------------------------------------------------------------------
/src/HTTP协议实践篇--浏览器缓存总结、利用Fiddler和apache模拟.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: HTTP协议实践篇--浏览器缓存总结、利用Fiddler和apache模拟
3 | tags:
4 | - HTTP协议
5 | - HTTP协议实践
6 | - 浏览器缓存
7 | date: 2016-09-27 00:00:00
8 | categories: HTTP/TCP/IP
9 | ---
10 | # 1.浏览器缓存
11 | 废话少说,我们先了解浏览器缓存的知识。
12 | 
13 | 其中优先级是:Cache-Control>Expires>协商缓存
14 | 浏览器访问缓存的顺序是:
15 | 
16 | # 2.浏览器刷新的几种状态
17 | - **普通模式** 我们下面的叙述在没有特殊说明的情况下就是这个模式
18 | - **普通页面跳转**(点击页面链接跳转,window.open,在地址栏敲回车,刷新页面)
19 | + 无缓存情况下,请求会返回所有资源结果
20 | + 设置Expires并且未过期时,浏览器将不会发出http请求
21 | + 如果Expires过期,则会发送相应请求,并附带上Last-Modifed等信息,供服务器校验
22 | - **页面刷新(F5)**
23 | 这种情况一下,一般会看到很多304的请求,就是说即便资源设置了Expires且未过期,浏览器也会发送相应请求,**命中协商缓存**。
24 | - **强制刷新(Ctrl+F5)**
25 | 效果和无缓存时候一致,返回200的结果
26 |
27 | # 3.强缓存
28 | 返回的http状态为**200**,在chrome的开发者工具的network里面size会显示为from cache
29 | ## 3.1 Cache-Control
30 | 请求指令
31 | 
32 | 响应指令
33 | 
34 | 这里需要注意`no-cache`对客户端和服务器含义是不同的,见下图
35 | 
36 |
37 | ## 3.2 Expires
38 | 资源失效的日期
39 | ```
40 | Expires: Wed, 21 Sep 2016 12:06:44 GMT
41 | ```
42 |
43 | ---
44 | **实践:**
45 | ## 实践3-1 html文件中
46 | 在html文件中
47 |
48 | ```html
49 |
50 |
51 | ```
52 | 这些方法不常用,而且测试不能通过
53 | ## 实践3-2 PHP中设置
54 |
55 | 可以使用php设置,当然也可以在apche服务器中进行设置
56 | ```php
57 | header("Cache-Control: public");
58 | header("Pragma: cache");
59 | $offset = 30*60*60*24; // cache 1 month
60 | $ExpStr = "Expires: ".gmdate("D, d M Y H:i:s", time() + $offset)." GMT";
61 | header($ExpStr);
62 | ```
63 | chrome network工具栏显示
64 | 
65 | **打开浏览器新窗口的方式测试,而不是F5刷新**
66 | chrome network工具栏显示
67 | 
68 |
69 | ## 实践3-3 不需要PHP
70 | 可以像[浅谈浏览器http的缓存机制](http://www.cnblogs.com/vajoy/p/5341664.html)文中所使用的方法
71 |
72 | - 在fildder右下角黑色区域--命令行,输入如:bpu localhost:8000 阻断来自localhost:8000的本地http请求
73 | - 点击被拦截的请求,可以在右栏直接修改报文内容(上半区域是请求报文,下半区域是响应报文),点击黄色的“Break on Response”按钮可以执行下一步(把请求发给服务器),点击绿色的按钮“Run to Completion”可以直接完成整个请求过程
74 |
75 | ---
76 |
77 | # 4.协商缓存
78 | 当浏览器对某个资源的请求没有命中强缓存,就会发一个请求到服务器,验证协商缓存是否命中,如果协商缓存命中,请求响应返回的http状态为**304**并且会显示一个Not Modified的字符串
79 | ## 4.1 Last-Modified,If-Modified-Since
80 | 这对名词通常是成对出现的
81 | `last-modified`:服务端设置的文档的最后的更新日期
82 | `if-modified-since`用于指定这个时间以后的服务器资源,GMT格式
83 |
84 | ## 4.2 ETag、If-None-Match/if-match
85 | 这对名词通常也是成对出现的
86 | `ETag`用于服务器向客户端传送的代表实体内容特征的标记信息
87 | `If-None-Match/if-match`服务器给客户机传送网页的时候,可以传递代表实体内容特征的头字段(ETag),这种头字段被叫做实体标签。当客户机再次向服务端发请求的时候,会使用if-match携带实体标签信息
88 |
89 | ---
90 |
91 | **实践:**
92 | **php**
93 | ```php
94 | header("Last-Modified:".gmdate("D, d M Y H:i:s") . " GMT" );
95 | ```
96 | **使用fiddler请求**
97 | ```
98 | 如:
99 | If-Modified-Since: Wed, 04 Oct 2016 13:32:30 GMT
100 | Last-Modified: Wed, 05 Oct 2016 13:32:30 GMT
101 | ```
102 | 
103 | 测试了几遍,并没有返回 304,原因不明
104 |
105 | ---
106 |
107 | **参考阅读:**
108 | - [php header()函数设置页面Cache缓存](http://www.111cn.net/phper/php/48528.htm)
109 | - [在php编程中使用header()函数发送文件头,设置浏览器缓存,加快站点的访问速度](http://www.lampweb.org/seo/4/11.html)
110 | - [浅谈浏览器http的缓存机制](http://www.cnblogs.com/vajoy/p/5341664.html)
111 | - [HTML meta标签总结与属性的使用介绍](http://www.imooc.com/article/4475)
--------------------------------------------------------------------------------
/src/javascript数据结构4-队列2-基数排序.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: javascript数据结构4-队列2-基数排序
3 | tags:
4 | - javascript
5 | - 数据结构
6 | categories: 数据结构
7 | date: 2016-10-09 00:00:00
8 | ---
9 |
10 | 第一次按个位上的数字进行排序,第二次按十位上的数字进行排序
11 |
12 | 排序:91, 46, 85, 15, 92, 35, 31, 22
13 | **经过基数排序第一次扫描**之后,数字被分配到如下盒子中:
14 |
15 | ```
16 | Bin 0:
17 | Bin 1: 91, 31
18 | Bin 2: 92, 22
19 | Bin 3:
20 | Bin 4:
21 | Bin 5: 85, 15, 35
22 | Bin 6: 46
23 | Bin 7:
24 | Bin 8:
25 | Bin 9:
26 | ```
27 |
28 | 根据盒子的顺序,对数字进行第一次排序的结果如下:
29 | 91, 31, 92, 22, 85, 15, 35, 46
30 | 然后根据**十位上的数值再将上次排序**的结果分配到不同的盒子中:
31 |
32 | ```
33 | Bin 0:
34 | Bin 1: 15
35 | Bin 2: 22
36 | Bin 3: 31, 35
37 | Bin 4: 46
38 | Bin 5:
39 | Bin 6:
40 | Bin 7:
41 | Bin 8: 85
42 | Bin 9: 91, 92
43 | ```
44 | Javascript实现代码:
45 |
46 | ```html5
47 |
48 |
49 |
50 |
51 | Queue Sample
52 |
53 |
54 |
55 |
151 |
152 |
153 |
154 | ```
155 |
156 |
157 |
--------------------------------------------------------------------------------
/src/webpack基础实践2.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: webpack基础实践2
3 | tags:
4 | - FE
5 | - javascript
6 | - webpack
7 | categories: 前端技术
8 | date: 2016-09-28 00:00:00
9 | ---
10 | 本文在webpack基础实践1的基础上,主要阐述的是模块化和ES6与webpack的结合使用。
11 | # 1.模块化
12 | **commonJS/CMD风格**
13 | module1.js
14 |
15 | ```javascript
16 | var obj = {
17 | val:"hello from m1",
18 | sayHi:function(){
19 | document.write('hi');
20 | },
21 | sum:function(a,b){
22 | return a+b;
23 | }
24 | };
25 | module.exports = obj;
26 | ```
27 | **AMD风格**
28 | module2.js
29 |
30 | ```javascript
31 | define(['./module1.js'],function(m1){
32 | return "1+2="+m1.sum(1,2);
33 | });
34 | ```
35 | 入口文件entry.js
36 |
37 | ```javascript
38 | var m1 = require("./module1.js");
39 | document.write("
");
40 | document.write(m1.val);
41 | document.write("
");
42 | var m2 = require("./module2.js");
43 | document.write(m2);
44 | ```
45 | 结果显示为
46 | ```
47 | hello from m1
48 | 1+2=3
49 | ```
50 | 当然实际项目中不建议两种风格的模块都使用,选择其中一种模块风格即可。
51 | # 2.ES6
52 | webpack是支持babel转化器的,所以可以将ES6代码转为ES5供现在的浏览器使用
53 | - 1) 安装babel依赖库
54 |
55 | ```bash
56 | npm install babel-loader --save-dev
57 | npm install babel-core --save-dev
58 | npm install babel-preset-es2015 --save-dev
59 | ```
60 | - 2) 新建一个`.babelrc`文件,内容是:
61 |
62 | ```javascript
63 | {
64 | "presets": [
65 | "es2015"
66 | ]
67 | }
68 | ```
69 | - 3) 配置`webpack.config.js`文件
70 | ```javascript
71 | module: {loaders: [
72 | { test: /\.js$/,exclude: /node_modules/,loader: 'babel-loader',}
73 | ]
74 | ```
75 | - 4) 入口文件`entry.js`中就可以使用了
76 |
77 | ```javascript
78 | /*es6*/
79 | require("./es6test2.js");
80 | ```
81 | `es6test2.js`
82 |
83 | ```javascript
84 | import Point from './es6test1';
85 |
86 | let p = new Point(1,2);
87 | document.write(p.toString());
88 | ```
89 | `es6test1.js`
90 |
91 | ```javascript
92 | //定义类
93 | class Point {
94 | constructor(x, y) {
95 | this.x = x;
96 | this.y = y;
97 | }
98 |
99 | toString() {
100 | return '(' + this.x + ', ' + this.y + ')';
101 | }
102 | }
103 | export default Point;
104 | ```
105 | 编译完成即可
106 | # 3.总结
107 |
108 | ## 3.1 配置文件`webpack.config.js`
109 |
110 | ```javascript
111 | module.exports = {
112 | entry: "./src/home/js/entry.js", //入口文件
113 | output: {
114 | path: __dirname,
115 | filename: "bundle.js"
116 | },
117 | module: {
118 | loaders: [
119 | { test: /\.css$/, loader: "style!css" }, //css加载器
120 | { test: /\.scss$/, loader: "style!css!sass" }, //sass加载器
121 | { test: /\.(jpg|png)$/, loader: "url?limit=8192" }, //图片加载器
122 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', }
123 | ]
124 | }
125 | };
126 | ```
127 | ## 3.2 加载的依赖库`package.json`
128 |
129 | ```javascript
130 | {
131 | "name": "webpackdemo",
132 | "version": "1.0.0",
133 | "description": "webpack demo",
134 | "main": "index.js",
135 | "scripts": {
136 | "test": "echo \"Error: no test specified\" && exit 1"
137 | },
138 | "author": "",
139 | "license": "ISC",
140 | "devDependencies": {
141 | "babel-core": "^6.14.0",
142 | "babel-loader": "^6.2.5",
143 | "babel-preset-es2015": "^6.14.0",
144 | "css-loader": "^0.24.0",
145 | "file-loader": "^0.9.0",
146 | "node-sass": "^3.8.0",
147 | "sass-loader": "^4.0.0",
148 | "style-loader": "^0.13.1",
149 | "url-loader": "^0.5.7",
150 | "webpack": "^1.13.2"
151 | }
152 | }
153 | ```
154 | ## 3.3 入口文件`entry.js`
155 | ```javascript
156 | require("./style.css");
157 | require("./index.scss");
158 |
159 | document.write(require("./content.js"));
160 | document.write("");
161 |
162 | var img = document.createElement("img");
163 | img.src = require("./img/webpack.png");
164 | document.body.appendChild(img);
165 | document.write("");
166 |
167 | /*模块化*/
168 | var m1 = require("./module1.js");
169 | document.write("");
170 | document.write(m1.val);
171 | document.write("
");
172 | var m2 = require("./module2.js");
173 | document.write(m2);
174 | document.write("
");
175 |
176 | /*es6*/
177 | require("./es6test2.js");
178 | ```
179 |
--------------------------------------------------------------------------------
/src/webpack基础实践1.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: webpack基础实践1
3 | tags:
4 | - FE
5 | - javascript
6 | - webpack
7 | categories: 前端技术
8 | date: 2016-09-28 00:00:00
9 | ---
10 |
11 | 这是个webpack的入门教程,看到网上blog大多是配置好了再解释,这样来的不太直观。本文从第一步开始慢慢做起,一步一步走下来,最后再总结,这样直观看到每个配置行代表什么含义。
12 | webpack的作用是什么?现在说太多可能对于入门的同学来说也不好理解,索性这里就记住一句话,一张图得了
13 | **一张图**
14 | 
15 | **一句话**
16 | webpack是能把各种资源,例如JS(JSX),coffee,样式(CSS/SASS/LESS),图片作为模块来进行打包和处理。
17 | # 1.安装
18 | ## 1.1 安装全局webpack
19 | 前提是在本地先安装了`node.js`.
20 |
21 | ```bash
22 | $ npm install webpack -g
23 | ```
24 | ## 1.2 将依赖写入package.json
25 | 新建的话:
26 |
27 | ```bash
28 | npm init
29 | ```
30 | 一路回车就可以,其实这些都是项目的描述信息和git地址等信息,这些信息我们可以后面再文件中直接修改
31 | 如果是clone的项目,已经有package.json文件了,就运行命令(忽略步骤`1.3`,`2.3`引入css加载器部分)
32 | ```bash
33 | npm install
34 | ```
35 | ## 1.3 安装局部webpack
36 | ```bash
37 | npm install webpack --save-dev
38 | ```
39 | # 2.开始使用
40 | ## 2.1 起步
41 | `entry.js`作为我们的入口文件,其中会包含其他模块(js)或者是CSS
42 |
43 | ```javascript
44 | document.write("入口entry.js");
45 | ```
46 | index.html
47 |
48 | ```html
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | ```
58 | 运行webpack命令
59 | ```bash
60 | $ webpack ./entry.js bundle.js
61 | ```
62 | 然后index.html就可以work了
63 | ```
64 | 入口entry.js
65 | ```
66 | ## 2.2 引入其他模块
67 | `content.js`
68 | ```javascript
69 | module.exports = "模块content.js";
70 | ```
71 | `entry.js`
72 | ```javascript
73 | document.write(require("./content.js"));
74 | ```
75 | 编译命令同上
76 | 运行index.html结果
77 | ```
78 | 模块content.js
79 | ```
80 | ## 2.3 引入CSS
81 | 引入css加载器
82 |
83 | ```bash
84 | npm install css-loader --save-dev
85 | npm install style-loader --save-dev
86 | ```
87 | style.css
88 |
89 | ```css
90 | body {
91 | background: yellow;
92 | }
93 | ```
94 | entry.js
95 |
96 | ```javascript
97 | require("!style!css!./style.css");
98 | document.write(require("./content.js"));
99 | ```
100 | 最后编译,就是这么简单随意完成了,如果我们想这样`require("./style.css");`引入css,岂不是更加完美
101 | 使用编译命令
102 |
103 | ```bash
104 | webpack ./entry.js bundle.js --module-bind 'css=style!css'
105 | ```
106 | ## 2.4 引入SASS文件
107 | 引入sass加载器
108 |
109 | ```bash
110 | npm install node-sass --save-dev
111 | npm install sass-loader --save-dev
112 | ```
113 | index.scss
114 | ```css
115 | body{
116 | color:white;
117 | }
118 | ```
119 | 同css一样
120 | entry.js
121 |
122 | ```javascript
123 | require("!style!css!sass!./index.scss");
124 | ```
125 | 当然我们还不是很满意。简单点,编译命令的方式简单点。所以我们来到了配置文件
126 | # 3.配置文件
127 | 新建文件`webpack.config.js`
128 |
129 | ```javascript
130 | module.exports = {
131 | entry: "./entry.js",
132 | output: {
133 | path: __dirname,
134 | filename: "bundle.js"
135 | },
136 | module: {
137 | loaders: [
138 | { test: /\.css$/, loader: "style!css" },//css加载器
139 | { test: /\.scss$/, loader: "style!css!sass" }//sass加载器
140 | ]
141 | }
142 | };
143 | ```
144 | 编译命令就剩下这样的
145 | ```bash
146 | webpack
147 | ```
148 | # 5.图片的打包
149 | 图片是用url-loader加载的。css中的url属性,其实就是一种封装过的require操作。
150 | ```bash
151 | npm install url-loader --save-dev
152 | npm install file-loader --save-dev
153 | ```
154 | webpack.config.js
155 |
156 | ```javascript
157 | {test: /\.(jpg|png)$/, loader: "url?limit=8192"}
158 | ```
159 | 在js中 entry.js
160 |
161 | ```javascript
162 | var img = document.createElement("img");
163 | img.src = require("./img/webpack.png");
164 | document.body.appendChild(img);
165 | ```
166 | 或者直接在css中写
167 | ```css
168 | div.img{
169 | width: 300px;
170 | height: 300px;
171 | background: url("./img/font-icon.png");//小于8kb的图片会打包处理成Base64的图片
172 | }
173 | ```
174 | # 6.常用webpack编译命令
175 | ```bash
176 | webpack //基本命令
177 | webpack --progress --colors //显示打包过程
178 | webpack -w //实时进行打包更新,文件改变时候,自动打包
179 | webpack -p // 对打包后的文件进行压缩,提供production
180 | webpack -d // 提供source map,方便调试。
181 | ```
182 |
183 | 关于对图片打包 AMD/CommonJS/ES6的使用在下一篇博客中`webpack基础实践2`
184 | 参考文章
185 | - [webpack官网-getting-start](http://webpack.github.io/docs/tutorials/getting-started/)
186 | - [webpack前端模块加载工具](http://www.cnblogs.com/YikaJ/p/4586703.html)
--------------------------------------------------------------------------------
/src/javascript数据结构8-图(Graph).md:
--------------------------------------------------------------------------------
1 | ---
2 | title: javascript数据结构8-图(Graph)
3 | tags:
4 | - javascript
5 | - 数据结构
6 | categories: 数据结构
7 | date: 2016-10-09 00:00:00
8 | ---
9 |
10 |
11 | **图(graph)**
12 | 图由边的集合及顶点的集合组成
13 | **有向图:**
14 | 
15 | **无向图:**
16 | 
17 | **代码:**
18 |
19 | ```html5
20 |
21 |
22 |
23 |
24 | Graph
25 |
26 |
27 |
136 |
137 |
138 | ```
139 | **运行结果:**
140 |
141 | >
142 | 0-->1 2
143 | 1-->0 3
144 | 2-->0 4
145 | 3-->1
146 | 4-->2
147 | ======深度度优先搜索=====
148 | 访问的节点:0
149 | 访问的节点:1
150 | 访问的节点:3
151 | 访问的节点:2
152 | 访问的节点:4
153 | ======广度优先搜索=====
154 | 访问的节点:0
155 | 访问的节点:1
156 | 访问的节点:2
157 | 访问的节点:3
158 | 访问的节点:4
159 |
160 | 深度搜索的含义:
161 | 
162 | 广度搜索的含义:
163 | 
--------------------------------------------------------------------------------
/src/openlayers 3实践与原理探究4.3.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: OpenLayers 3实践与原理探究4.3-ol3源码分析-Source,Layer
3 | tags:
4 | - OpenLayers 3
5 | - 地图
6 | - js库
7 | - WebGIS
8 | categories: WebGIS
9 | date: 2016-09-28 00:00:00
10 | ---
11 |
12 | # 3.Source
13 | `ol/ol/Source`文件夹下
14 |
15 | ## 3.1构造函数
16 | ### 3.1.1 `ol.source.Source` ol.source的基础类
17 | `ol/ol/Source/source.js`
18 |
19 | ```javascript
20 | ol.source.Source = function(options) {}
21 | ```
22 | ### 3.1.2 `ol.source.OSM`
23 | `ol/ol/Source/osmsource.js`
24 | `openStreetMap`:
25 |
26 | ```javascript
27 | ol.source.OSM = function(opt_options) {}
28 | ```
29 | 具体不进行展开描述。
30 | 运用实例:
31 |
32 | ```javascript
33 | var osmSource = new ol.source.OSM();
34 | ```
35 | ### 3.1.3 `ol.source.TileWMS`
36 | 先看个例子:
37 |
38 | ```javascript
39 | var map = new ol.Map({
40 | target: 'map', //document.getElementById("map")
41 | layers: [
42 | new ol.layer.Tile({
43 | title: "Global Imagery",
44 | source: new ol.source.TileWMS({
45 | url: 'http://demo.boundlessgeo.com/geoserver/wms',
46 | params: {
47 | 'LAYERS': 'ne:NE1_HR_LC_SR_W_DR'
48 | }
49 | })
50 | })
51 | ],
52 |
53 | });
54 | ```
55 | 我们可以一路找下源头:
56 | `tilewmssource.js`-->`tileimagessource.js`-->`uritilesource.js`-->`tilespurce.js`-->`source.js`
57 | 我们可以发现实例中的`source.url`是在`uritilesource.js`
58 | 处理的
59 | 我们先考虑单url的情况(当然存在url数组的情况)
60 |
61 | ```javascript
62 | if (options.url) {
63 | this.setUrl(options.url);
64 | }
65 | //... ...
66 | ol.source.UrlTile.prototype.setUrl = function(url) {
67 | var urls = this.urls = ol.TileUrlFunction.expandUrl(url);
68 | this.setTileUrlFunction(this.fixedTileUrlFunction ?
69 | this.fixedTileUrlFunction.bind(this) :
70 | ol.TileUrlFunction.createFromTemplates(urls, this.tileGrid), url);
71 | };
72 | ```
73 | 处理函数为`fixedTileUrlFunction`,在`tilewmssource.js`
74 | `fixedTileUrlFunction`-->`getRequestUrl_`-->`ol.uri.appendParams(url, params)`请求地图
75 | params包含请求地图的宽、高、分辨率、地图范围
76 | # 4.Layer
77 | `ol/ol/Layer`文件夹下
78 |
79 | ## 4.1构造函数
80 | ### 4.1.1 `ol/ol/Layer/layer.js`
81 |
82 | ```javascript
83 | ol.layer.Layer = function(options) {}
84 | ```
85 | ```javascript
86 | ol.inherits(ol.layer.Layer, ol.layer.Base);
87 | ```
88 | `ol.layer.Base`定义layer的基本属性和基本属性的setter,getter方法
89 |
90 | 实际在api接口上使用的是具体的图层
91 | ### 4.1.2 矢量地图`ol/ol/Layer/vectorlayer.js`
92 | ```javascript
93 | ol.layer.Vector = function(opt_options) {
94 | var baseOptions = ol.object.assign({}, options);
95 | ol.layer.Layer.call(this, /** @type {olx.layer.LayerOptions} */ (baseOptions));
96 | }
97 | ```
98 | 实际调用的方法,仍然在`ol/ol/Layer/layer.js`中
99 | ### 4.1.3 瓦块地图`ol/ol/Layer/titlelayer.js`
100 | ```javascript
101 | ol.layer.Tile = function(opt_options) {
102 | var baseOptions = ol.object.assign({}, options);
103 | ol.layer.Layer.call(this, /** @type {olx.layer.LayerOptions} */ (baseOptions));
104 | }
105 | ```
106 | 还有`heatmaplayer.js`,`imagelayer.js`,`vectortilelayer.js`对应热力图,图片地图,矢量瓦块地图
107 | 总结:
108 | `ol/ol/Layer/layer.js`是通用的方法部分
109 | 各个具体的地图*.js是各个地图的专有方法。
110 | 运用实例:
111 |
112 | ```javascript
113 | var map = new ol.Map({
114 | target: 'map', //document.getElementById("map")
115 | layers: [
116 | new ol.layer.Tile({
117 | title: "Global Imagery",
118 | source: new ol.source.TileWMS({
119 | url: 'http://demo.boundlessgeo.com/geoserver/wms',
120 | params: {
121 | 'LAYERS': 'ne:NE1_HR_LC_SR_W_DR'
122 | }
123 | })
124 | })
125 | ],
126 |
127 | });
128 | ```
129 | `source`在layer.js中处理
130 |
131 | ```javascript
132 | var source = options.source ? options.source : null;
133 | this.setSource(source);
134 |
135 | ol.layer.Layer.prototype.setSource = function(source) {
136 | this.set(ol.layer.LayerProperty.SOURCE, source);//添加到常量上,其实也是将source对象共享出去了
137 | };
138 | ```
139 | ## 4.2方法 事件
140 | ### 4.2.1 `ol/ol/Layer/layer.js`
141 | 主要是一下方法
142 | ```javascript
143 | ol.layer.Layer.visibleAtResolution
144 | getLayersArray
145 | getLayerStatesArray
146 | getSource
147 | getSourceState
148 | handleSourceChange_
149 | handleSourcePropertyChange_
150 | setMap
151 | setSource
152 | ```
--------------------------------------------------------------------------------
/src/写给前端er的TCP-IP知识及《图解TCP-IP》读书笔记.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 写给前端er的TCP/IP知识及《图解TCP/IP》读书笔记
3 | tags:
4 | - TCP/IP
5 | - 图解TCP/IP
6 | categories: HTTP/TCP/IP
7 | date: 2016-11-08 00:00:00
8 | ---
9 | # 1.分层
10 | OSI参考模型分为7层,TCP/IP分为四层。
11 | 
12 |
13 | # 2.物理设备介绍
14 | 
15 |
16 | # 3.传输过程
17 | 
18 |
19 | # 4.分层介绍
20 |
21 | ## 4.1 数据链路层
22 |
23 | 几个关键的相关技术
24 | - MAC地址:用于识别数据链路层中互连的节点,在使用网卡(NIC)的情况下,MAC地址会烧入在ROM中
25 | 
26 | - 以太网(Ethernet)
27 | 以太网帧式,前端是前导码部分,后面是帧的本体
28 | 
29 | 
30 | 帧尾叫做FCS,用来检测帧信息是否完整
31 |
32 | ## 4.2 网路层
33 |
34 | ### 4.2.1 IP协议--无连接型
35 |
36 | - **数据链路层和IP层的区别:**
37 | 
38 | #### 1. **IP地址的分类**
39 | 
40 | A类:0.0.0.0 ~ 127.0.0.0 【127为回环测试地址,如127.0.0.0为本机地址】
41 | B类:128.0.0.1 ~ 191.255.0.0
42 | C类:192.0.0.0 ~ 233.255.255.0
43 | D类:224.0.0.0 ~ 239.255.255.0 【用于多播】
44 | #### 2. **单播、广播、多播**
45 | 单播:一对一
46 | 广播:会被路由器屏蔽
47 | 【例如:192.168.0.0/24广播地址为192.168.0.255/24】
48 | 多播:能通过路由器,D类IP地址,从224.0.0.0 ~ 239.255.255.255
49 | 其中224.0.0.0到224.0.0.255不需要路由控制,在同一个链路中能实现多播。
50 | #### 3. **解决IP地址有限:**
51 | 
52 | 标识方法:
53 | **方法1:**
54 | 
55 | **方法2:**
56 | 
57 | #### 4. **IP分片:**
58 | 数据链路不同,最大的传输单元(MTU)不同,所以需要对IP分片进行处理。分片只能在目标主机中进行重组。
59 | - **ICMP通知MTU大小**
60 | 路径MTU发现机制(UDP情况下)
61 | 
62 | 路径MTU发现机制(TCP情况下)不同于上
63 | #### 5. **IPv6**
64 | IP地址长度为128位,以每18比特为一组进行标记,如果出现连续的0,用“::”代替
65 | - **IPv6地址结构:**
66 | 
67 | 全局单播地址是世界上唯一的地址
68 | 
69 | #### 6. **IPv4首部**
70 | IP首部+IP载荷(数据)组成:
71 | 
72 | #### 7. **IPv6首部**
73 | 
74 |
75 | ### 4.2.2 IP协议相关技术
76 |
77 | #### 1. DNS
78 | 管理主机名和IP地址之间对应关系的系统,叫做DNS系统。
79 | - **DNS查询:**
80 | 
81 | 第三步 会将IP地址信息暂时保存到缓存中,减少每次查询时的性能消耗。
82 | DNS的主要记录包括很多类型的数据,比如类型A值主机名的IP地址,PTR指IP地址的反向解析,即IP地址检索的主机名。
83 | #### 2. ARP
84 | IP地址到Mac地址解析
85 | #### 3.ICMP
86 | 主要功能是确认IP包是否成功送达目的地址,通知在发送过程当中IP包被废弃的原因,改善网络的设置等。
87 | #### 4.DHCP
88 | 动态设置ip地址
89 |
90 | ## 4.3 TCP/UDP
91 |
92 | - TCP首部格式
93 | 
94 | - 三次握手
95 | 
96 | - 识别多个请求
97 | 
98 | - 套接口
99 | 
100 |
101 | ## 4.4 应用层
102 | 应用层有SSH,FTP,HTTP,TLS/SSL等
103 | - ftp使用两条TCP连接
104 | 
105 | - javascript,CGI
106 | 
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/src/openlayers 3实践与原理探究2.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: OpenLayers 3实践与原理探究2-ol3基础入门案例
3 | tags:
4 | - OpenLayers 3
5 | - 地图
6 | - js库
7 | - WebGIS
8 | categories: WebGIS
9 | date: 2016-09-28 00:00:00
10 | ---
11 | 【注】所有代码挂在我的[github](https://github.com/zrysmt/openlayers-3)上
12 |
13 | # 0.实例
14 | 在OpenLayers3官网的[下载页面](http://openlayers.org/download/)下载我们在开发工程中需要的文件(如:v3.17.1-dist.zip),实际工程中包含两个文件`ol.js`,`ol.css`
15 | 先看一个实例代码如下:
16 |
17 | ```html
18 |
19 |
20 |
21 |
22 |
23 | 1-TileWMS
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
56 |
57 |
58 |
59 | ```
60 | 效果图:
61 | 
62 |
63 | 通过api的overview我们可以看到ol3的核心部件
64 | 
65 | # 1.基本概念
66 | 
67 | ## 1.1 Map
68 | Map(ol.Map)是OL3的核心部件,它被呈现在target容器上(div)。也可以使用setTarget方法。
69 | 位置:`ol/ol/map.js`
70 |
71 | ```javascript
72 | var map = new ol.Map({target: 'map'});
73 | ```
74 | ## 1.2 View
75 | `ol.View`负责地图的中心点,放大,投影之类的设置。
76 | 一个ol.View实例包含投影projection,该投影决定中心center 的坐标系以及分辨率的单位,如果没有指定(如下面的代码段),默认的投影是球墨卡托(EPSG:3857),以米为地图单位。
77 |
78 | 放大zoom 选项是一种方便的方式来指定地图的分辨率,可用的缩放级别由maxZoom (默认值为28)、zoomFactor (默认值为2)、maxResolution (默认由投影在256×256像素瓦片的有效成都来计算) 决定。起始于缩放级别0,以每像素maxResolution 的单位为分辨率,后续的缩放级别是通过zoomFactor区分之前的缩放级别的分辨率来计算的,直到缩放级别达到maxZoom 。
79 | ```javascript
80 | var map = new ol.Map({
81 | target: 'map',
82 | view: new ol.View({
83 | projection: 'EPSG:4326', //WGS 84
84 | center: [0, 0],
85 | zoom: 2,
86 | maxResolution: 0.703125
87 | }),
88 |
89 | });
90 | ```
91 | ## 1.3 Source
92 | OpenLayers 3使用ol.source.Source子类获取远程数据图层,包含免费的和商业的地图瓦片服务,如OpenStreetMap、Bing、OGC资源(WMS或WMTS)、矢量数据(GeoJSON格式、KML格式…)等。
93 |
94 | ```javascript
95 | var osmSource = new ol.source.OSM();
96 | ```
97 | ## 1.4 Layer
98 | 一个图层是资源中数据的可视化显示,OpenLayers 3包含三种基本图层类型:`ol.layer.Tile(瓦片)`、`ol.layer.Image(图片样式的图层`)和 `ol.layer.Vector(矢量图层)`。
99 |
100 | - `ol.layer.Tile` 用于显示瓦片资源,这些瓦片提供了预渲染,并且由特定分别率的缩放级别组织的瓦片图片网格组成。
101 | - `ol.layer.Image`用于显示支持渲染服务的图片,这些图片可用于任意范围和分辨率。
102 | - `ol.layer.Vector`用于显示在客户端渲染的矢量数据。
103 |
104 | ```javascript
105 | var osmLayer = new ol.layer.Tile({source: osmSource}); map.addLayer(osmLayer);
106 | ```
107 | ## 1.5 控件与交互
108 | ### 1.5.1 控件
109 |
110 | ```javascript
111 | var map = new ol.Map({
112 | controls: ol.control.defaults().extend([
113 | new ol.control.FullScreen(), //全屏控件
114 | new ol.control.ScaleLine(), //比例尺
115 | new ol.control.OverviewMap(), //鹰眼控件
116 | new ol.control.Zoom(),
117 | ]),
118 | layers: [bglayer, vector], //添加两个图层
119 | target: 'map', //div#id='map'
120 | });
121 | ```
122 | ### 1.5.2 交互
123 |
124 | ```javascript
125 | var select = new ol.interaction.Select({
126 | wrapX: false
127 | });
128 |
129 | var modify = new ol.interaction.Modify({
130 | features: select.getFeatures()
131 | });
132 | var map = new ol.Map({
133 | layers: [bglayer, vector], //添加两个图层
134 | target: 'map', //div#id='map'
135 | interaction:ol.interaction.defaults().extend([select, modify])
136 | });
137 | ```
138 | 或者用方法的方式添加:
139 |
140 | ```javascript
141 | draw = new ol.interaction.Draw({
142 | source: source,
143 | type: /** @type {ol.geom.GeometryType} */ (shapeName),
144 | geometryFunction: geometryFunction,
145 | maxPoints: maxPoints
146 | });
147 | map.addInteraction(draw); //增加的交互
148 | ```
149 |
--------------------------------------------------------------------------------
/src/javascript数据结构6-字典-散列-集合.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: javascript数据结构6-字典 散列 集合
3 | tags:
4 | - javascript
5 | - 数据结构
6 | categories: 数据结构
7 | date: 2016-10-09 00:00:00
8 | ---
9 |
10 | ## 6.1 字典
11 | 字典是一种以键- 值对形式存储数据的数据结构,就像电话号码簿里的名字和电话号码一
12 |
13 | ```html5
14 |
15 |
16 |
17 |
18 | 字典sample
19 |
20 |
21 |
89 |
90 |
91 | ```
92 |
93 | ## 6.2 散列(HashTable)
94 |
95 | 它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度
96 | 使用:MD5 和 SHA-1 可以说是目前应用最广泛的Hash算法
97 | java中已经实现
98 | 
99 |
100 | ```html5
101 |
102 |
103 |
104 |
105 | HashTable散列表
106 |
107 |
108 |
160 |
161 |
162 | ```
163 | 
164 | 这就是碰撞,为避免碰撞,使用betterHash
165 | 修改:
166 | ```javascript
167 | function put(data) {
168 | // var pos = this.simpleHash(data);
169 | var pos = this.betterHash(data);
170 | this.table[pos] = data;
171 | }
172 | ```
173 |
174 |
--------------------------------------------------------------------------------
/src/React Router的一个完整示例.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: React Router的一个完整示例
3 | tags:
4 | - React
5 | - React Router
6 | categories: 前端技术
7 | date: 2016-11-04 00:00:00
8 | ---
9 | 本博文提供一个单网页结构网页(SPA)使用React Router路由控制跳转的完整例子。
10 | > 可以在我的[github](https://github.com/zrysmt/react-demo/tree/master/demo03) 中clone或者fork
11 | https://github.com/zrysmt/react-demo/tree/master/demo03
12 |
13 | 关于配置可以查看我之前的一篇博客:[一步一步进入React的世界(React+Webpack+ES6组合配置)](https://zrysmt.github.io/2016/10/31/%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E8%BF%9B%E5%85%A5React%E7%9A%84%E4%B8%96%E7%95%8C%EF%BC%88React+Webpack+ES6%E7%BB%84%E5%90%88%EF%BC%89/)。
14 | # 1.整个目录结构
15 | 
16 | - build是编译后的文件夹
17 | - src 放入源码
18 | + components组件
19 | + global 通用组件和SCSS
20 | + ... 分模块
21 | + app.js入口
22 | - index.html
23 |
24 | # 2.源码
25 | 关于源码可以在开头给出的github中找到详细的完整例子,这里就介绍重要的几个文件源码
26 | 记住要安装react-router
27 |
28 | ```bash
29 | npm i react-router -S
30 | ```
31 | ## 2.1 index.html
32 |
33 | ```html
34 |
35 |
36 |
37 |
38 |
39 | Our Home,Our Heart
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | ```
50 | ## 2.2 入口文件app.js
51 | 关于react router的基础知识我们可以参考阮一峰老师的博客作为入门指导。
52 |
53 | ```javascript
54 | import React from 'react';
55 | import ReactDOM from 'react-dom';
56 | import {Router,Route,IndexRoute,hashHistory} from 'react-router';
57 |
58 | import './components/global/global.scss';
59 |
60 | import Nav from './components/global/menu';
61 | import Home from './components/home/home';
62 | import Story from './components/story/story';
63 |
64 |
65 | class App extends React.Component{
66 | render(){
67 | return(
68 |
69 |
70 | {this.props.children}
71 |
72 | )
73 | }
74 | }
75 |
76 | ReactDOM.render((
77 |
78 |
79 |
80 |
81 |
82 |
83 | ),document.body
84 | );
85 | ```
86 | **简单解释下:**
87 | 组件App除了包含Nav组件,还应该包括主体内容
88 | 当使用index.html访问的时候,是在项目根目录下,这样会先加载APP组件,APP组件包含`{this.props.children}`,便会加载``里面定义的组件Home。用户访问'/'相当于:
89 |
90 | ```
91 |
92 |
93 |
94 |
95 | ```
96 |
97 | ## 2.3 Nav组件
98 | /components/global/menuLi.jsx
99 | /components/global/menu.jsx
100 |
101 | - 最小一块组件menuLi.jsx
102 |
103 | ```javascript
104 | import React from 'react';
105 | import {Link} from 'react-router';
106 | class MenuLi extends React.Component{
107 | render(){
108 | let linkTo = this.props.name =="Home"?"/":"/"+this.props.name;
109 | return (
110 |
111 |
112 | {this.props.name}
113 |
114 |
115 | );
116 | }
117 | }
118 | export default MenuLi;
119 | ```
120 | `Link`组件用于取代``元素,生成一个链接,允许用户点击后跳转到另一个路由
121 | - Nav组件 menu.jsx
122 |
123 | ```javascript
124 | import React from 'react';
125 | import ReactDOM from 'react-dom';
126 | import MenuLi from './menuLi';
127 | import './menu.scss';
128 |
129 | let menuLis = ["Home","Story","Travel","TimeLine","Future"];
130 | class MenuUl extends React.Component{
131 | render(){
132 | return(
133 |
134 | {
135 | menuLis.map(function(menuLi) {
136 | return
137 | })
138 | }
139 |
140 | );
141 | }
142 | }
143 | class Nav extends React.Component{
144 | render(){
145 | return(
146 |
151 | )
152 | }
153 | }
154 | export default Nav;
155 | ```
156 | ## 2.4 Home组件
157 | /components/home/home.jsx,示例比较简单
158 |
159 | ```javascript
160 | import React from 'react';
161 | import ReactDOM from 'react-dom';
162 | import "./home.scss";
163 | class Home extends React.Component{
164 | render(){
165 | return (
166 | 这是home
167 | );
168 | }
169 | }
170 | export default Home;
171 | ```
172 | ## 2.5 Story组件
173 |
174 | ```javascript
175 | import React from 'react';
176 | import ReactDOM from 'react-dom';
177 | import "./story.scss";
178 |
179 | class Story extends React.Component{
180 | render(){
181 | return (
182 | 这是story
183 | );
184 | }
185 | }
186 | export default Story;
187 | ```
188 | 其余几个组件不一一列出了
189 |
190 | > 可以在我的[github](https://github.com/zrysmt/react-demo/tree/master/demo03) 中clone或者fork,查看完整的例子代码
191 |
192 | 参考阅读:
193 |
194 | - [React Router 使用教程--阮一峰](http://www.ruanyifeng.com/blog/2016/05/react_router.html?utm_source=tool.lu)
--------------------------------------------------------------------------------
/src/使用javascript原生实现一个模板引擎.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 使用javascript原生实现一个模板引擎
3 | tags:
4 | - FE
5 | - javascript
6 | - 模板引擎
7 | - js原生实现库
8 | categories: 前端技术
9 | date: 2016-12-05 00:00:00
10 | ---
11 | 模板引擎分为**前端**和**后端**的,前端常用的模板引擎如artTemplate,[juicer](http://www.juicer.name/docs/docs_zh_cn.html)渲染是在客户端完成的;后端的模板引擎如基于PHP的[smarty](http://www.smarty.net/docs/zh_CN/),渲染是服务器完成的。
12 |
13 | 前两天看到一篇博客挺好的是用了不到20行代码实现一个前端的模板引擎,感觉挺有趣的,今天就来实现下
14 |
15 | # 1.简单的例子
16 | **逻辑**
17 |
18 | ```javascript
19 | var tplEngine = function(tpl, data) {
20 | var re = /<%([^%>]+)?%>/g;
21 | while (match = re.exec(tpl)) {
22 | tpl = tpl.replace(match[0], data[match[1]]);
23 | }
24 | return tpl;
25 | };
26 | ```
27 | 就是把`<%name%>`替换成`data.name`即可
28 | **测试**
29 | ```javascript
30 | var template1 = 'Hello, my name is <%name%>. I\'m <%age%> years old.
';
31 | console.log(tplEngine(template1, {
32 | name: "Tom",
33 | age: 29
34 | }));
35 | ```
36 | # 2. data属性复杂点
37 |
38 | ```javascript
39 | var tplEngine = function(tpl, data) {
40 | var re = /<%([^%>]+)?%>/g;
41 | var code = 'var r=[];\n',
42 | cursor = 0;//辅助变量
43 | var add = function(line, js) {//针对变量还是普通的片段分别处理
44 | js ? code += 'r.push(' + line + ');\n' :
45 | code += 'r.push("' + line.replace(/"/g, '\\"') + '");\n';
46 | };
47 | while (match = re.exec(tpl)) {
48 | add(tpl.slice(cursor, match.index));
49 | add("this."+match[1],true);//要替换的变量
50 | cursor = match.index + match[0].length;
51 | }
52 | add(tpl.substr(cursor, tpl.length - cursor));
53 | code += 'return r.join("");'; // <-- return the result
54 | console.info(code);
55 |
56 | return new Function(code.replace(/[\r\t\n]/g,'')).apply(data);
57 | };
58 | ```
59 | 我们研究下`new Function`
60 | **构造函数**
61 | ```
62 | new Function ([arg1[, arg2[, ...argN]],] functionBody)
63 | ```
64 | argN是传入的参数,当然可以省略
65 | 函数体是`code.replace(/[\r\t\n]/g,'')`,apply将函数体的上下文环境(this)指向了data
66 | 测试
67 |
68 | ```javascript
69 | var template2 = 'Hello, my name is <%name%>. I\'m <%profile.age%> years old.
';
70 | console.log(tplEngine(template2, {
71 | name: "Kim",
72 | profile: {
73 | age: 29
74 | }
75 | }));
76 | ```
77 |
78 | # 3.加入for if循环和判断语句
79 | 按照上面的测试
80 |
81 | ```javascript
82 | var template3 =
83 | 'My skills:' +
84 | '<%for(var index in this.skills) {%>' +
85 | '<%skills[index]%>' +
86 | '<%}%>';
87 | console.log(tplEngine(template3, {
88 | skills: ["js", "html", "css"]
89 | }));
90 | ```
91 | 报错:
92 | ```
93 | Uncaught SyntaxError: Unexpected token for
94 | ```
95 | 打印结果`r.push(for(var index in this.skills) {);`是有问题的。
96 | ```
97 | var r=[];
98 | r.push("My skills:");
99 | r.push(for(var index in this.skills) {);
100 | r.push("");
101 | r.push(this.skills[index]);
102 | r.push("");
103 | r.push(this.});
104 | r.push("");
105 | return r.join("");
106 | ```
107 | 修改
108 |
109 | ```javascript
110 | var tplEngine = function(tpl, data) {
111 | var re = /<%([^%>]+)?%>/g,
112 | re2 = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g;
113 | var code = 'var r=[];\n',
114 | cursor = 0;
115 | var add = function(line, js) {
116 | js ? code += line.match(re2) ? line + '\n' : 'r.push(' + line + ');\n' :
117 | code += 'r.push("' + line.replace(/"/g, '\\"') + '");\n';
118 | };
119 | while (match = re.exec(tpl)) {
120 | add(tpl.slice(cursor, match.index));
121 | re2.test(match[1]) ? add(match[1], true) : add("this." + match[1], true);
122 | cursor = match.index + match[0].length;
123 | }
124 | add(tpl.substr(cursor, tpl.length - cursor));
125 | code += 'return r.join("");';
126 | console.info(code);
127 |
128 | return new Function(code.replace(/[\r\t\n]/g, '')).apply(data);
129 | };
130 | ```
131 |
132 | 我们可以打印`code`看看
133 | ```
134 | code+='console.log(r);\n';
135 | ```
136 | ```
137 | ["My skills:", "", "js", "", "", "html", "", "", "css", "", ""]
138 | ```
139 | 最终的结果
140 | ```
141 | var r=[];
142 | r.push("My skills:");
143 | for(var index in this.skills) {
144 | r.push("");
145 | r.push(this.skills[index]);
146 | r.push("");
147 | }
148 | r.push("");
149 | console.log(r);
150 | return r.join("");
151 | ```
152 | 解析结果
153 | ```
154 | My skills:jshtmlcss
155 | ```
156 |
157 | 参考阅读:
158 | - [只有20行Javascript代码!手把手教你写一个页面模板引擎](http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651551309&idx=1&sn=93bf90d6f2c63fea0e5f3ec488a1431f&chksm=8025a18cb752289af6ad341cdd20daa4b0d0dc6fd5e1f8cd6d8910afa8ee1b6400b0503ad382&mpshare=1&scene=1&srcid=0926c4H6Se5FCKfQBRO2uDjd#rd)
159 |
--------------------------------------------------------------------------------
/src/openlayers 3实践与原理探究4.2.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: OpenLayers 3实践与原理探究4.2-ol3源码分析-Map,View
3 | tags:
4 | - OpenLayers 3
5 | - 地图
6 | - js库
7 | - WebGIS
8 | categories: WebGIS
9 | date: 2016-09-28 00:00:00
10 | ---
11 | # 1.Map
12 | `ol/ol/map.js`
13 |
14 | ## 1.1构造函数
15 | ```javascript
16 | ol.Map = function(options) {
17 | ol.Object.call(this);//@extends {ol.Object}
18 | var optionsInternal = ol.Map.createOptionsInternal(options);
19 | }
20 | ```
21 | **常量对象共享地图设置,并且将常量对象共享出去,作为公用变量**
22 |
23 | ```javascript
24 | goog.provide('ol.MapProperty');
25 | ol.MapProperty = {
26 | LAYERGROUP: 'layergroup',
27 | SIZE: 'size',
28 | TARGET: 'target',
29 | VIEW: 'view'
30 | };
31 | ```
32 | `createOptionsInternal`函数对map中的配置对象进行处理。
33 |
34 | ```javascript
35 | //分别处理layer、layerGroup、target、view、renderer、controls、interactions、overlays
36 | var layerGroup = (options.layers instanceof ol.layer.Group) ?
37 | options.layers : new ol.layer.Group({layers: options.layers});
38 | values[ol.MapProperty.LAYERGROUP] = layerGroup;
39 |
40 | values[ol.MapProperty.TARGET] = options.target;
41 |
42 | values[ol.MapProperty.VIEW] = options.view !== undefined ?
43 | options.view : new ol.View();
44 |
45 | //......
46 | return {
47 | controls: controls,
48 | interactions: interactions,
49 | keyboardEventTarget: keyboardEventTarget,
50 | logos: logos,
51 | overlays: overlays,
52 | rendererConstructor: rendererConstructor,
53 | values: values
54 | };
55 | ```
56 | 运用实例-初始化:
57 |
58 | ```javascript
59 | var map = new ol.Map({
60 | controls: ol.control.defaults().extend([
61 | new ol.control.ScaleLine(), //比例尺
62 | ]),
63 | layers: [bglayer, vector], //添加两个图层
64 | target: 'map', //div#id='map'
65 | view: view,
66 | interaction:interaction
67 | });
68 | ```
69 |
70 |
71 |
72 | ## 1.2 方法 事件
73 | 方法 事件列表:
74 | ```
75 | addControl
76 | addInteraction
77 | addLayer
78 | addOverlay
79 | beforeRender
80 | changed
81 | dispatchEvent
82 | forEachFeatureAtPixel
83 | forEachLayerAtPixel
84 | get
85 | getControls
86 | getCoordinateFromPixel
87 | getEventCoordinate
88 | getEventPixel
89 | getInteractions
90 | getKeys
91 | getLayerGroup
92 | getLayers
93 | getOverlayById
94 | getOverlays
95 | getPixelFromCoordinate
96 | getProperties
97 | getRevision
98 | getSize
99 | getTarget
100 | getTargetElement
101 | getView
102 | getViewport
103 | hasFeatureAtPixel
104 | on
105 | once
106 | removeControl
107 | removeInteraction
108 | removeLayer
109 | removeOverlay
110 | render
111 | renderSync
112 | set
113 | setLayerGroup
114 | setProperties
115 | setSize
116 | setTarget
117 | setView
118 | un
119 | unByKey
120 | unset
121 | updateSize
122 | ```
123 | 实现方式举几个例子:
124 |
125 | ```javascript
126 | ol.Map.prototype.addControl = function(control) {
127 | var controls = this.getControls();
128 | goog.asserts.assert(controls !== undefined, 'controls should be defined');
129 | controls.push(control);
130 | };
131 |
132 | ol.Map.prototype.addInteraction = function(interaction) {
133 | var interactions = this.getInteractions();
134 | goog.asserts.assert(interactions !== undefined,
135 | 'interactions should be defined');
136 | interactions.push(interaction);
137 | };
138 | ```
139 | `controls`控件,控件添加到`map`上,对控件设置两个监听事件,增加、删除。
140 |
141 | ```javascript
142 | this.controls_ = optionsInternal.controls;
143 | this.controls_.forEach( function(control) {
144 | control.setMap(this);
145 | }, this);
146 |
147 | ol.events.listen(this.controls_, ol.CollectionEventType.ADD, function(event) {
148 | event.element.setMap(this);
149 | }, this);
150 |
151 | ol.events.listen(this.controls_, ol.CollectionEventType.REMOVE, function(event) {
152 | event.element.setMap(null);
153 | }, this);
154 | ```
155 |
156 | # 2.View
157 | `ol/ol/view.js`
158 |
159 | ## 2.1构造函数
160 |
161 | ```javascript
162 | ol.View = function(opt_options) {
163 | ol.Object.call(this);
164 | var options = opt_options || {};
165 | this.projection_ = ol.proj.createProjection(options.projection, 'EPSG:3857');
166 | //... ...
167 | }
168 | ```
169 | 运用实例:
170 |
171 | ```javascript
172 | var map = new ol.Map({
173 | target: 'map',
174 | view: new ol.View({
175 | projection: 'EPSG:4326', //WGS 84
176 | center: [0, 0],
177 | zoom: 2,
178 | maxResolution: 0.703125
179 | }),
180 |
181 | });
182 | ```
183 | ```javascript
184 | goog.provide('ol.View');
185 | goog.provide('ol.ViewHint');
186 | goog.provide('ol.ViewProperty');
187 | ```
188 | 提供不只是一个构造函数,还有两个常量对象,其中一个常量对象包含三个常量如下所示:
189 |
190 | ```javascript
191 | ol.ViewProperty = {
192 | CENTER: 'center',
193 | RESOLUTION: 'resolution',
194 | ROTATION: 'rotation'
195 | };
196 | ```
197 | 其实,我们在对象属性中写出来的,如`center`,作用等同于用下面介绍的方法`setCenter`,其本质是写入常量中,共享出去作为公用。
198 | ## 2.2方法 事件
199 | 举例;
200 |
201 | ```javascript
202 | ol.View.prototype.setCenter = function(center) {
203 | this.set(ol.ViewProperty.CENTER, center);
204 | };
205 | ```
--------------------------------------------------------------------------------
/src/webpack项目实践.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: webpack项目实践
3 | tags:
4 | - FE
5 | - javascript
6 | - webpack
7 | categories: 前端技术
8 | date: 2016-09-28 00:00:00
9 | ---
10 | # 1.目录结构初步构想
11 | 上面的例子只是介绍了webpack的基本用法,并没有按照一个实际的项目进行构建目录结构,对于一个多页面的项目我们定义的目录结构如下
12 | ```
13 | - web/ # web根目录
14 | - src/ # 开发目录
15 | - home/ # 主页目录
16 | + css/ # css/sass资源目录
17 | + img/ # 图片资源目录
18 | + js/ # js&jsx资源目录
19 | entry.js # webpack入口文件
20 | home.html # 页面文件
21 | - about/ # about页目录
22 | + css/ # css/sass资源目录
23 | + img/ # 图片资源目录
24 | + js/ # js&jsx资源目录
25 | entry.js # webpack入口文件
26 | about.html # about页面文件
27 | - dist/ # 编译输出目录,即发布目录
28 | - home/ # 编译输出的home目录
29 | - about/ # 编译输出的about目录
30 | - common/ # 编译输出的公共资源目录
31 | + js/ # 编译输出的公共js目录
32 | + css/ # 编译输出的公共css目录
33 | + img/ # 编译输出的公共图片目录
34 | - index.html # 系统html入口
35 | webpack.config.js # webpack配置文件
36 | package.json # 项目配置
37 | .babelrc # 配置es-2015
38 | README.md # 项目说明
39 | ```
40 | 将上两篇博客`webpack基础实践1-2`中的例子配置文件改成如下
41 |
42 | ```javascript
43 | var path = require("path");
44 |
45 | module.exports = {
46 | entry: "./src/home/entry.js", //入口文件
47 | output: {
48 | path: path.join(__dirname, 'dist','home'),
49 | filename: "bundle.js",
50 | publicPath:'./images/'//可以限定图片生成位置的路径
51 | },
52 | module: {
53 | loaders: [
54 | { test: /\.css$/, loader: "style!css" }, //css加载器
55 | { test: /\.scss$/, loader: "style!css!sass" }, //sass加载器
56 | { test: /\.(jpg|png)$/, loader: "url?limit=8192&name=../images/[hash].[ext]" }, //图片加载器[name].[ext] limit 是限制大小,大于这个尺寸会是单独的图片,小于这个尺寸是base64的形式
57 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', }//babel加载器
58 | ]
59 | }
60 | };
61 | ```
62 | 入口文件等只需要改换成相对路径即可
63 | # 2.独立css文件
64 | 需要配合插件一起使用
65 | ```bash
66 | npm install extract-text-webpack-plugin --save-dev
67 | ```
68 | 比1中配置文件增加/修改的内容
69 |
70 | ```javascript
71 | var ExtractTextPlugin = require("extract-text-webpack-plugin");
72 | module.exports = {
73 | //... ...
74 | module: {
75 | loaders: [
76 | { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader")}, //css加载器
77 | { test: /\.scss$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader")}, //sass加载器
78 | ]
79 | },
80 | plugins: [
81 | new ExtractTextPlugin("[name].css")
82 | ]
83 | };
84 | ```
85 | 此时在html文件中引入就可以了
86 |
87 | ```html
88 |
89 | ```
90 | # 3.多入口
91 | 为了模拟数据,我们在`home`文件夹下新建了一个`entry2.js`入口
92 |
93 | ```javascript
94 | var m2 = require("./module2.js");
95 | document.write(m2);
96 | /*es6*/
97 | require("./es6test2.js");
98 | ```
99 | 配置文件如下
100 |
101 | ```javascript
102 | var path = require("path");
103 | var ExtractTextPlugin = require("extract-text-webpack-plugin");
104 |
105 | module.exports = {
106 | entry: {
107 | page1:"./src/home/entry.js",
108 | page2:"./src/home/entry2.js"
109 |
110 | }, //入口文件
111 | output: {
112 | path: path.join(__dirname, 'dist','home'),
113 | filename: "[name].js",
114 | },
115 | module: {
116 | loaders: [
117 | { test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader")}, //css加载器
118 | { test: /\.scss$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader")}, //sass加载器
119 | { test: /\.(jpg|png)$/, loader: "url?limit=8192&name=../images/[hash].[ext]" },
120 | { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', }
121 | ]
122 | },
123 | plugins: [
124 | new ExtractTextPlugin("[name].css")
125 | ]
126 | };
127 |
128 | ```
129 | 这个时候需要在`index.html`中分别引入
130 |
131 | ```html
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 | ```
148 | # 4.提取公共部分
149 | 第3部分中给出的`entry2.js`和`entry.js`是有相同的部分的,我们想要实现的是可以提取出两者的公共部分。
150 | 配置文件中增加
151 |
152 | ```javascript
153 | var webpack = require('webpack');
154 | //... ...
155 | plugins: [
156 | new webpack.optimize.CommonsChunkPlugin('common.js')
157 | ]
158 | ```
159 | 如果公共部分想单列一个文件夹下,可以
160 | ```
161 | new webpack.optimize.CommonsChunkPlugin('../common/js/common.js')
162 | ```
163 | 在html文件中引入`common.js`文件即可
164 | # 5.实践后的项目目录
165 | 
166 |
--------------------------------------------------------------------------------
/src/javascript数据结构1-数组.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: javascript数据结构1-数组
3 | tags:
4 | - javascript
5 | - 数据结构
6 | categories: 数据结构
7 | date: 2016-10-09 00:00:00
8 | ---
9 |
10 | 书籍:
11 |
12 | > 数据结构与算法javascript描述
13 |
14 | 数组比较简单,这里只是简单介绍:
15 | ## 1.使用数组
16 | ### 1.1 创建数组
17 | ```javascript
18 | //第一种形式
19 | var numbers = new Array(3);
20 | //第二种形式
21 | var numbers = [7,4,1776];
22 |
23 | ```
24 |
25 | 大多数JavaScript 专家推荐使用[]操作符,和使用Array 的构造函数相比,这种方式被认为效率更高(new创建的对象,会一直存在于内存中)
26 |
27 | ### 1.2 读写数组
28 |
29 | ```javascript
30 | var numbers = [1,2,3,5,8,13,21];
31 | var sum = 0;
32 | for (var i = 0; i < numbers.length; ++i) {
33 | sum += numbers[i];
34 | }
35 | ```
36 | ### 1.3 字符串生成数组
37 |
38 | ```javascript
39 | //下面的这一小段程序演示了split() 方法的工作原理:
40 | var sentence = "the quick brown fox jumped over the lazy dog";
41 | var words = sentence.split(" ");
42 | for (var i = 0; i < words.length; ++i) {
43 | console.log("word " + i + ": " + words[i]);
44 | }
45 | ```
46 | ### 1.4 对数组的整体性操作
47 |
48 | ```javascript
49 | var nums = [];
50 | for (var i = 0; i < 100; ++i) {
51 | nums[i] = i+1;
52 | }
53 | var samenums = nums;
54 | nums[0] = 400;
55 | console.log(samenums[0]); // 显示400
56 | ```
57 | 这种行为被称为**浅复制**,新数组依然指向原来的数组。一个更好的方案是使用**深复制**,将
58 | 原数组中的每一个元素都复制一份到新数组中。可以写一个深复制函数来做这件事:
59 |
60 | ```javascript
61 | function copy(arr1, arr2) {
62 | for (var i = 0; i < arr1.length; ++i) {
63 | arr2[i] = arr1[i];
64 | }
65 | }
66 | //这样,下述代码片段的输出就和我们希望的一样了:
67 | var nums = [];
68 | for (var i = 0; i < 100; ++i) {
69 | nums[i] = i+1;
70 | }
71 | var samenums = [];
72 | copy(nums, samenums);
73 | nums[0] = 400;
74 | console.log(samenums[0]); // 显示 1
75 | ```
76 | ## 2. 存取函数
77 | ### 2.1 查找元素
78 |
79 | ```javascript
80 | var names = ["David", "Cynthia", "Raymond", "Clayton", "Jennifer"];
81 | putstr("Enter a name to search for: ");
82 | var name = readline();
83 | var position = names.indexOf(name);
84 | if (position >= 0) {
85 | console.log("Found " + name + " at position " + position);
86 | }
87 | else {
88 | console.log(name + " not found in array.");
89 | }
90 | ```
91 | ### 2.2 两个函数使用
92 | concat 连接
93 | splice 截取
94 | join() 和toString() 将数组转化为字符串
95 |
96 | ```javascript
97 | var cisDept = ["Mike", "Clayton", "Terrill", "Danny", "Jennifer"];
98 | var dmpDept = ["Raymond", "Cynthia", "Bryan"];
99 | var itDiv = cis.concat(dmp);
100 | console.log(itDiv);
101 | itDiv = dmp.concat(cisDept);
102 | console.log(itDiv);
103 | //输出为:
104 | Mike,Clayton,Terrill,Danny,Jennifer,Raymond,Cynthia,Bryan
105 | Raymond,Cynthia,Bryan,Mike,Clayton,Terrill,Danny,Jennifer
106 | ```
107 | ## 3. 可变函数
108 | **简单函数:**
109 | ```
110 | push() 末尾增加元素
111 | unshift() 在开头添加元素
112 | pop() 在末尾删除元素
113 | shift() 在开头删除元素
114 | ```
115 | **从数组中间删除元素:**
116 |
117 | ```javascript
118 | var nums = [1,2,3,7,8,9];
119 | var newElements = [4,5,6];
120 | nums.splice(3,0,newElements);
121 | console.log(nums); // 1,2,3,4,5,6,7,8,9
122 | ```
123 | **排序函数:**
124 |
125 | ```javascript
126 | var nums = [1,2,3,4,5];
127 | nums.reverse();
128 | console.log(nums); // 5,4,3,2,1
129 | ```
130 |
131 | ```javascript
132 | var names = ["David","Mike","Cynthia","Clayton","Bryan","Raymond"];
133 | names.sort();
134 | console.log(names); // Bryan,Clayton,Cynthia,David,Mike,Raymond
135 | ```
136 | 自定义:
137 |
138 | ```javascript
139 | function compare(num1, num2) {
140 | return num1 - num2;
141 | }
142 | var nums = [3,1,2,100,4,200];
143 | nums.sort(compare);
144 | console.log(nums); // 1,2,3,4,100,200
145 | //sort() 函数使用了compare() 函数对数组按照数字大小进行排序,而不是按照字典顺序。
146 | ```
147 | ## 4.迭代器
148 | ```
149 | 函数 说明 是否生成新数组
150 | foreach() 全部遍历 否
151 | every() 全部返回true,才返回true 否
152 | some() 只要一个返回true,就返回true 否
153 | reduce() 不断调用累加值 否
154 | map() 符合条件的,类比foreach() 是
155 | filter() 返回结果为true的函数 是
156 | ```
157 | ## 5.二维数组和多维数组
158 |
159 | ```javascript
160 | Array.matrix = function(numrows, numcols, initial) {
161 | var arr = [];
162 | for (var i = 0; i < numrows; ++i) {
163 | var columns = [];
164 | for (var j = 0; j < numcols; ++j) {
165 | columns[j] = initial;
166 | }
167 | arr[i] = columns;
168 | }
169 | return
170 | ```
171 |
172 | ## 6.两种特殊的数组
173 | 数组的函数同样适用
174 |
175 | **对象数组**
176 | ```javascript
177 | function Point(x,y) {
178 | this.x = x;
179 | this.y = y;
180 | }
181 | ```
182 | **对象中的数组**
183 |
184 | ```javascript
185 | function weekTemps() {
186 | this.dataStore = [];
187 | this.add = add;
188 | this.average = average;
189 | }
190 | function add(temp) {
191 | this.dataStore.push(temp);
192 | }
193 | function average() {
194 | var total = 0;
195 | for (var i = 0; i < this.dataStore.length; ++i) {
196 | total += this.dataStore[i];
197 | }
198 | return total / this.dataStore.length;
199 | }
200 | var thisWeek = new weekTemps();
201 | thisWeek.add(52);
202 | thisWeek.add(55);
203 | thisWeek.add(61);
204 | thisWeek.add(65);
205 | thisWeek.add(55);
206 | thisWeek.add(50);
207 | thisWeek.add(52);
208 | thisWeek.add(49);
209 | console.log(thisWeek.average()); // 显示54.875
210 |
211 | ```
--------------------------------------------------------------------------------
/src/openlayers 3实践与原理探究4.1.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: OpenLayers 3实践与原理探究4.1-ol3源码分析-底层基础
3 | tags:
4 | - OpenLayers 3
5 | - 地图
6 | - js库
7 | - WebGIS
8 | categories: WebGIS
9 | date: 2016-09-28 00:00:00
10 | ---
11 | 因为下面的内容会分模块介绍源码,所以这里为了方便,首先介绍源码的目录结构
12 | 在OpenLayers 3官网的[下载页面](http://openlayers.org/download/)下载我们在开发工程中需要的文件(如:v3.17.1.zip),注意如果需要编译源代码,需要下载包含编译功能的文件包:https://github.com/openlayers/ol3/releases 下载指定release版本的源码,注意是Source code (zip)或者Source code (tar.gz)。
13 | 
14 | - `apidoc`是ol3的api文档,打开`ol.html`就可以在浏览器中离线使用,当然也可以在官网中查看api;
15 | - `build`是ol3编译过的文件,工程开发中可以直接使用,下部分的案例是基于离线的源码的;
16 | - `closure-library`是google的closure库文件夹;
17 | - `css`里面只有`ol.css`一个文件,是定义ol3的全局样式,项目开发中需要引入;
18 | - `doc`提供给我们一些的案例,打开`quickstart.html`即可看到快速开始的案例;
19 | - `examples`是比较丰富的例子,和官网中的examples一样;
20 | - `ol`就是我们要分析的源码文件夹;
21 | - `ol.ext`是ol3所要使用的js库。
22 |
23 | `ol/ol`文件夹下是我们分析的源码,分析基本思路:文件夹下的文件是公用的部分(A部分),文件夹是分部分写的(B部分)。
24 | # 0.底层基础
25 | ## 0.1 `ol.js`
26 | 第一行就可以看出,`ol.js`提供全局的第一命名空间`ol`
27 |
28 | ```javascript
29 | goog.provide('ol');
30 | ```
31 | 唯一的一个方法是:继承
32 |
33 | ```javascript
34 | ol.inherits = function(childCtor, parentCtor) {
35 | childCtor.prototype = Object.create(parentCtor.prototype);
36 | childCtor.prototype.constructor = childCtor;
37 | };
38 | ```
39 | ## 0.2 `object.js`
40 |
41 | ```javascript
42 | goog.provide('ol.Object');
43 | goog.provide('ol.ObjectEvent');
44 | goog.provide('ol.ObjectEventType');
45 |
46 | goog.require('ol.Observable');
47 | goog.require('ol.events');
48 | goog.require('ol.events.Event');
49 | goog.require('ol.object');
50 | ```
51 | ol命名空间下所有的基本对象,比如`map`对象,`feature`矢量地图对象,都应该建立在`ol.Object`基础上。如:
52 | ***
53 | `map.js`
54 |
55 | ```javascript
56 | ol.Object.call(this);
57 | ol.inherits(ol.Map, ol.Object);
58 | ```
59 | `feature.js`
60 |
61 | ```javascript
62 | ol.Object.call(this);
63 | ol.inherits(ol.Feature, ol.Object);
64 | ```
65 | ***
66 | 通过这行代码:
67 | ```javascript
68 | ol.inherits(ol.Object, ol.Observable);
69 | ```
70 | 我们发现`ol.Object`继承`ol.Observable`
71 | `Observable.js`
72 |
73 | ```javascript
74 | ol.inherits(ol.Observable, ol.events.EventTarget);
75 | ```
76 | 我们发现`ol.Observable`继承`ol.EventTarget`;
77 | 这样,我们可以知道继承`ol.Object`后也就继承了基础事件`ol.events`。
78 | ## 0.3 `events.js`
79 | ol3的基础事件
80 |
81 | ```javascript
82 | goog.provide('ol.events');
83 | goog.provide('ol.events.EventType');
84 | goog.provide('ol.events.KeyCode');
85 |
86 | goog.require('ol.object');
87 | ```
88 | 提供的所有基础事件
89 |
90 | ```javascript
91 | ol.events.EventType = {
92 | CHANGE: 'change',
93 | CLICK: 'click',
94 | DBLCLICK: 'dblclick',
95 | DRAGENTER: 'dragenter',
96 | DRAGOVER: 'dragover',
97 | DROP: 'drop',
98 | ERROR: 'error',
99 | KEYDOWN: 'keydown',
100 | KEYPRESS: 'keypress',
101 | LOAD: 'load',
102 | MOUSEDOWN: 'mousedown',
103 | MOUSEMOVE: 'mousemove',
104 | MOUSEOUT: 'mouseout',
105 | MOUSEUP: 'mouseup',
106 | MOUSEWHEEL: 'mousewheel',
107 | MSPOINTERDOWN: 'mspointerdown',
108 | RESIZE: 'resize',
109 | TOUCHSTART: 'touchstart',
110 | TOUCHMOVE: 'touchmove',
111 | TOUCHEND: 'touchend',
112 | WHEEL: 'wheel'
113 | };
114 | ```
115 | 我们分析一下提供的几个方法
116 |
117 | ```javascript
118 | ol.events.bindListener_ = function(listenerObj) {};
119 | ol.events.listen = function(target, type, listener, opt_this, opt_once) {};
120 | ol.events.unlisten = function(target, type, listener, opt_this) {};
121 | ol.events.unlistenAll = function(target) {};
122 | ```
123 | 其中方法名末尾带有"_"为私有方法,不带的为提供出去的共有方法。
124 | ## 0.4 `math.js`
125 | 提供基础的数学运算方法,角度转化弧度函数如:
126 |
127 | ```javascript
128 | ol.math.toRadians = function(angleInDegrees) {
129 | return angleInDegrees * Math.PI / 180;
130 | };
131 | ```
132 | ## 0.5 `animation.js`
133 | 提供bounce、pan、rotate、zoom四种方法
134 | ## 0.6 `collection.js`
135 | 对ol命名空间下的对象集合的操作。
136 |
137 | ```javascript
138 | goog.provide('ol.Collection');
139 | goog.provide('ol.CollectionEvent');
140 | goog.provide('ol.CollectionEventType');
141 |
142 | goog.require('ol.events.Event');
143 | goog.require('ol.Object');
144 | ```
145 | ```javascript
146 | ol.CollectionEventType = {
147 | ADD: 'add'
148 | REMOVE: 'remove'
149 | };
150 | ```
151 | 继承
152 |
153 | ```javascript
154 | ol.inherits(ol.CollectionEvent, ol.events.Event);
155 | ol.inherits(ol.Collection, ol.Object);
156 | ```
157 | 方法举例:
158 |
159 | ```javascript
160 | ol.Collection.prototype.remove = function(elem) {
161 | var arr = this.array_;
162 | var i, ii;
163 | for (i = 0, ii = arr.length; i < ii; ++i) {
164 | if (arr[i] === elem) {
165 | return this.removeAt(i);
166 | }
167 | }
168 | return undefined;
169 | };
170 | ```
171 | ## 0.7 `uri.js`
172 | 通过url加载地图,其中`params`包含请求地图的宽、高、分辨率、地图范围
173 |
174 | ```javascript
175 | ol.uri.appendParams = function(uri, params) {
176 | var qs = Object.keys(params).map(function(k) {
177 | return k + '=' + encodeURIComponent(params[k]);
178 | }).join('&');
179 | // remove any trailing ? or &
180 | uri = uri.replace(/[?&]$/, '');
181 | // append ? or & depending on whether uri has existing parameters
182 | uri = uri.indexOf('?') === -1 ? uri + '?' : uri + '&';
183 | return uri + qs;
184 | };
185 | ```
--------------------------------------------------------------------------------
/src/rollup+es6最佳实践.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: rollup + es6最佳实践
3 | tags:
4 | - FE
5 | - javascript
6 | - es6
7 | - rollup
8 | categories: 前端技术
9 | date: 2016-10-02 00:00:00
10 | ---
11 | 简单说下rollup就是只将调用过的模块打包,做到尽量精简的打包。
12 |
13 | 使用webpack 1.X 版本是无法利用该特性来避免引入冗余模块代码的
14 |
15 | webpack2 已经出来好几款 beta 版本了,同样也加上了对 Tree-shaking 的支持
16 |
17 | # 1.src中的文件
18 | jquery.js
19 |
20 | ```javascript
21 | // 出口
22 | import init from './init';
23 | init(jQuery);
24 |
25 | export default jQuery;
26 | ```
27 | init.js
28 |
29 | ```javascript
30 | var init = function(jQuery){
31 | jQuery.fn.init = function (selector, context, root) {
32 | if (!selector) {
33 | return this;
34 | } else {
35 | var elem = document.querySelector(selector);
36 | if (elem) {
37 | this[0] = elem;
38 | this.length = 1;
39 | }
40 | return this;
41 | }
42 | };
43 | jQuery.fn.init.prototype = jQuery.fn;
44 | };
45 |
46 | export default init;
47 | ```
48 | # 2.安装包
49 | pakage.json 包管理
50 | ```
51 | npm init
52 | ```
53 | 开始安装
54 | ```
55 | npm i rollup rollup-plugin-babel babel-preset-es2015-rollup --save-dev
56 | ```
57 | # 3.编译
58 | ## 3.1 命令行编译
59 |
60 | ```
61 | rollup src/jquery.js --output bundle.js -f cjs
62 | ```
63 | ### 3.1.1 编译成commonjs格式的文件
64 |
65 | ```javascript
66 | 'use strict';
67 |
68 | var init = function(jQuery){
69 | jQuery.fn.init = function (selector, context, root) {
70 | if (!selector) {
71 | return this;
72 | } else {
73 | var elem = document.querySelector(selector);
74 | if (elem) {
75 | this[0] = elem;
76 | this.length = 1;
77 | }
78 | return this;
79 | }
80 | };
81 | jQuery.fn.init.prototype = jQuery.fn;
82 | };
83 |
84 | init(jQuery);
85 |
86 | module.exports = jQuery;
87 | ```
88 | 另外还有几种格式
89 | ```
90 | amd / es6 / iife / umd
91 | ```
92 | ### 3.1.2 **umd**
93 | ```
94 | rollup src/jquery.js --output bundle.js -f umd
95 | ```
96 | 会报错
97 | ```
98 | You must supply options.moduleName for UMD bundles
99 | ```
100 | 这是因为我们在`jquery.js`中
101 | ```
102 | export default jQuery;
103 | ```
104 | 我们使用配置方式进行编译,就能指定导出的模块名`moduleName: 'jQuery'`
105 | ## 3.2 配置编译--rollup -c rollup.config.dev.js
106 | `rollup.config.dev.js`
107 |
108 | ```javascript
109 | import babel from 'rollup-plugin-babel';
110 |
111 | export default {
112 | entry: 'src/jquery.js',
113 | format: 'iife',
114 | moduleName: 'jQuery',
115 | plugins: [babel() ],
116 | dest: 'bundle.js',
117 | };
118 | ```
119 | src中`.babelrc`
120 | ```
121 | {
122 | presets: [
123 | ["es2015", { "modules": false }]
124 | ]
125 | }
126 | ```
127 | 注意` { "modules": false }`一定要有,否则一直报错,错误如下所示
128 | ```bash
129 | Error transforming E:\javascript\rollup-demo\src\jquery.js with 'babel' plugin: It looks like your Babel configuration specifies a module transformer. Please disable it. If you're using the "es2015" preset, consider using "es2015-rollup" instead. See https://github.com/rollup/rollup-plugin-babel#configuring-babel f or more information
130 | Error: Error transforming E:\javascript\rollup-demo\src\jquery.js with 'babel' plugin: It looks like your Babel configuration specifies a module transformer. Please disable it. If you're using the "es2015" preset, consider using "es2015- rollup" instead. See https://github.com/rollup/rollup-plugin-babel#configuring- babel for more information
131 | at preflightCheck (E:\javascript\rollup-demo\node_modules\rollup-plugin-bab el\dist\rollup-plugin-babel.cjs.js:43:102)
132 | at Object.transform$1 [as transform] (E:\javascript\rollup-demo\node_module s\rollup-plugin-babel\dist\rollup-plugin-babel.cjs.js:104:18)
133 | at C:\Users\Ruyi\AppData\Roaming\npm\node_modules\rollup\src\utils\transfor m.js:19:35
134 | at process._tickCallback (node.js:379:9)
135 | at Function.Module.runMain (module.js:459:11)
136 | at startup (node.js:138:18)
137 | at node.js:974:3
138 | ```
139 | 命令
140 | ```
141 | rollup -c rollup.config.dev.js
142 | ```
143 | ## 3.3 配置编译--node rollup.config.dev.js
144 | `rollup.config.dev.js`
145 |
146 | ```javascript
147 | var rollup = require( 'rollup' );
148 | var babel = require('rollup-plugin-babel');
149 |
150 | rollup.rollup({
151 | entry: 'src/jquery.js',
152 | plugins: [ babel() ]
153 | }).then( function ( bundle ) {
154 | bundle.write({
155 | format: 'umd',
156 | moduleName: 'jQuery', //umd或iife模式下,若入口文件含 export,必须加上该属性
157 | dest: 'bundle.js',
158 | sourceMap: true
159 | });
160 | });
161 | ```
162 |
163 |
164 |
165 | 参考阅读:
166 | - [Issue rollup -c](https://github.com/rollup/rollup-plugin-babel/issues/72)
167 | - [rollup.js官网 http://rollupjs.org/guide/](http://rollupjs.org/guide/)
168 | - [## 冗余代码都走开——前端模块打包利器 Rollup.js 入门](http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651550907&idx=2&sn=4acac6d96a0ce4fc61e37b798dd90fd8&scene=21#wechat_redirect)
169 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 前端学习之路
2 | > https://zrysmt.github.io
3 |
4 | - [使用React+Three.js封装一个三维地球](./src/使用React+Three.js封装一个三维地球.md)
5 | - [基于WebGL的大数据二三维可视化-uber的deck-gl介绍](./src/基于WebGL的大数据二三维可视化-uber的deck-gl介绍.md)
6 | - [leaflet可视化平台搭建](./src/leaflet可视化平台搭建.md)
7 | - [2017阿里实习校招-前端技术视频面试体会](./src/2017阿里实习校招-前端技术视频面试体会.md)
8 | - [阿里巴巴校招2017前端笔试题目-原生js-html5-实现一个路由](./src/阿里巴巴校招2017前端笔试题目-原生js-html5-实现一个路由.md)
9 | - [WebGL基础简明教程1-简介](./src/WebGL基础简明教程1-简介.md)
10 | - [WebGL基础简明教程2-基础知识](./src/WebGL基础简明教程2-基础知识.md)
11 | - [CSS3--font-face使用](./src/CSS3--font-face使用.md)
12 | - [EChart 2升级EChart 3注意事项](./src/EChart%202升级EChart%203注意事项.md)
13 | - [ECharts 3.0底层zrender 3.x源码分析1-总体架构](./src/ECharts%203.0底层zrender%203.x源码分析1-总体架构.md)
14 | - [ECharts 3.0底层zrender 3.x源码分析2-Painter(V层)](./src/ECharts%203.0底层zrender%203.x源码分析2-Painter(V层).md)
15 | - [ECharts 3.0底层zrender 3.x源码分析3-Handler(C层)](./src/ECharts%203.0底层zrender%203.x源码分析3-Handler(C层).md)
16 | - [ECharts 3.0源码简要分析1-总体架构](./src/ECharts%203.0源码简要分析1-总体架构.md)
17 | - [File Input多次添加文件,用来实现上传等操作](./src/File%20Input多次添加文件,用来实现上传等操作.md)
18 | - [HTTP协议实践篇--使用fiddle与后台php交互](./src/HTTP协议实践篇--使用fiddle与后台php交互.md)
19 | - [HTTP协议实践篇--浏览器缓存总结、利用Fiddler和apache模拟](./src/HTTP协议实践篇--浏览器缓存总结、利用Fiddler和apache模拟.md)
20 | - [PHP爬虫最全总结1](./src/PHP爬虫最全总结1.md)
21 | - [PHP爬虫最全总结2-phpQuery,PHPcrawer,snoopy框架中文介绍](./src/PHP爬虫最全总结2-phpQuery,PHPcrawer,snoopy框架中文介绍.md)
22 | - [React Router的一个完整示例](./src/React%20Router的一个完整示例.md)
23 | - [WebRTC1-原理探究](./src/WebRTC1-原理探究.md)
24 | - [domReady机制探究及DOMContentLoaded研究](./src/domReady机制探究及DOMContentLoaded研究.md)
25 | - [javascript数据结构1-数组](./src/javascript数据结构1-数组.md)
26 | - [javascript数据结构2-列表](./src/javascript数据结构2-列表.md)
27 | - [javascript数据结构3-栈](./src/javascript数据结构3-栈.md)
28 | - [javascript数据结构4-队列](./src/javascript数据结构4-队列.md)
29 | - [javascript数据结构4-队列2-基数排序](./src/javascript数据结构4-队列2-基数排序.md)
30 | - [javascript数据结构5-链表2 存放点数据(x,y)](./src/javascript数据结构5-链表2%20存放点数据(x,y).md)
31 | - [javascript数据结构5-链表(包括循环链表 双向链表)](./src/javascript数据结构5-链表(包括循环链表%20双向链表).md)
32 | - [javascript数据结构6-字典-散列-集合](./src/javascript数据结构6-字典-散列-集合.md)
33 | - [javascript数据结构7-二叉搜索树(BST)](./src/javascript数据结构7-二叉搜索树(BST).md)
34 | - [javascript数据结构8-图(Graph)](./src/javascript数据结构8-图(Graph).md)
35 | - [javascript数据结构9-排序](./src/javascript数据结构9-排序.md)
36 | - [javascript的setter getter方法总结](./src/javascript的setter%20getter方法总结.md)
37 | - [javascript设计模式 使用ES6语法](./src/javascript设计模式%20使用ES6语法.md)
38 | - [javascript设计模式【上】](./src/javascript设计模式【上】.md)
39 | - [javascript设计模式【下】](./src/javascript设计模式【下】.md)
40 | - [javascript面向对象和面向委托](./src/javascript面向对象和面向委托.md)
41 | - [jqprint插件使用教程与源码实现分析](./src/jqprint插件使用教程与源码实现分析.md)
42 | - [openlayers 3 使用React 组件化+wepack+ES6实践记录](./src/openlayers%203%20使用React%20组件化+wepack+ES6实践记录.md)
43 | - [openlayers 3实践与原理探究1](./src/openlayers%203实践与原理探究1.md)
44 | - [openlayers 3实践与原理探究2](./src/openlayers%203实践与原理探究2.md)
45 | - [openlayers 3实践与原理探究3](./src/openlayers%203实践与原理探究3.md)
46 | - [openlayers 3实践与原理探究4.1](./src/openlayers%203实践与原理探究4.1.md)
47 | - [openlayers 3实践与原理探究4.2](./src/openlayers%203实践与原理探究4.2.md)
48 | - [openlayers 3实践与原理探究4.3](./src/openlayers%203实践与原理探究4.3.md)
49 | - [openlayers 3实践与原理探究4.4](./src/openlayers%203实践与原理探究4.4.md)
50 | - [openlayers 3扩展,调用百度地图、高德地图、天地图服务](./src/openlayers%20-%203扩展,调用百度地图、高德地图、天地图服务.md)
51 | - [rollup+es6最佳实践](./src/rollup+es6最佳实践.md)
52 | - [this](./src/this.md)
53 | - [webpack基础实践1](./src/webpack基础实践1.md)
54 | - [webpack基础实践2](./src/webpack基础实践2.md)
55 | - [webpack项目实践](./src/webpack项目实践.md)
56 | - [一步一步DIY jQuery库1](./src/一步一步DIY%20jQuery库1.md)
57 | - [一步一步DIY jQuery库2-使用es6模块化](./src/一步一步DIY%20jQuery库2-使用es6模块化.md)
58 | - [一步一步DIY jQuery库3-引入sizzle引擎](./src/一步一步DIY%20jQuery库3-引入sizzle引擎.md)
59 | - [一步一步DIY zepto库,研究zepto源码1](./src/一步一步DIY%20zepto库,研究zepto源码1.md)
60 | - [一步一步DIY zepto库,研究zepto源码2](./src/一步一步DIY%20zepto库,研究zepto源码2.md)
61 | - [一步一步DIY zepto库,研究zepto源码3 -- 事件模块](./src/一步一步DIY%20zepto库,研究zepto源码3%20--%20事件模块.md)
62 | - [一步一步DIY zepto库,研究zepto源码4 -- ajax模块](./src/一步一步DIY%20zepto库,研究zepto源码4%20--%20ajax模块.md)
63 | - [一步一步DIY zepto库,研究zepto源码5--callbacks](./src/一步一步DIY%20zepto库,研究zepto源码5--callbacks.md)
64 | - [一步一步DIY zepto库,研究zepto源码6--deferred](./src/一步一步DIY%20zepto库,研究zepto源码6--deferred.md)
65 | - [一步一步DIY zepto库,研究zepto源码7--动画模块(fx,fx_method)](./src/一步一步DIY%20zepto库,研究zepto源码7--动画模块(- fx,fx_method).md)
66 | - [一步一步DIY zepto库,研究zepto源码8--touch模块](./src/一步一步DIY%20zepto库,研究zepto源码8--touch模块.md)
67 | - [一步一步进入React的世界(React+Webpack+ES6组合)](./src/一步一步进入React的世界(React+Webpack+ES6组合).md)
68 | - [使用javascript原生实现一个模板引擎](./src/使用javascript原生实现一个模板引擎.md)
69 | - [使用leaflet或者openlayers-3-调用MapServer服务最佳实践完整说明](./src/使用leaflet或者openlayers-3-调用MapServer服务最佳实践完整说明.md)
70 | - [写给前端er的TCP-IP知识及《图解TCP-IP》读书笔记](./src/写给前端er的TCP-IP知识及《图解TCP-IP》读书笔记.md)
71 | - [利用File Input控件修改name属性](./src/利用File%20Input控件修改name属性.md)
72 | - [利用dataTabels可视化后台数据库,可编辑](./src/利用dataTabels可视化后台数据库,可编辑.md)
73 | - [利用php和ajax实现局部更新数据](./src/利用php和ajax实现局部更新数据.md)
74 | - [前端CSS&JS动画总结](./src/前端CSS&JS动画总结.md)
75 | - [前端模块化](./src/前端模块化.md)
76 | - [前端自动化测试工具--使用karma进行javascript单元测试](./src/前端自动化测试工具--使用karma进行javascript单元测试.md)
77 | - [前端自动化测试工具PhantomJS+CasperJS结合使用教程](./src/前端自动化测试工具PhantomJS+CasperJS结合使用教程.md)
78 | - [前端视频播放初探总结,元素video标签-视频插件](./src/前端视频播放初探总结,元素video标签-视频插件.md)
79 | - [动手DIY一个underscorejs库及underscorejs源码分析1](./src/动手DIY一个underscorejs库及underscorejs源码分析1.md)
80 | - [动手DIY一个underscorejs库及underscorejs源码分析2](./src/动手DIY一个underscorejs库及underscorejs源码分析2.md)
81 | - [动手DIY一个underscorejs库及underscorejs源码分析3](./src/动手DIY一个underscorejs库及underscorejs源码分析3.md)
82 | - [在线浏览online officepdf探究](./src/在线浏览online%20officepdf探究.md)
83 | - [富文本编辑器实践](./src/富文本编辑器实践.md)
84 | - [对象数组比较](./src/对象数组比较.md)
85 | - [时间控件插件[js jquery]总结和简单实践-前端](./src/时间控件插件[js%20jquery]总结和简单实践-前端.md)
86 | - [现代web前端开发工具和流程](./src/现代web前端开发工具和流程.md)
87 |
--------------------------------------------------------------------------------
/src/javascript数据结构4-队列.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: javascript数据结构4-队列
3 | tags:
4 | - javascript
5 | - 数据结构
6 | categories: 数据结构
7 | date: 2016-10-09 00:00:00
8 | ---
9 | 队列是一种先进先出(FIFO,first-in-first-out)的数据结构
10 |
11 | **javascript代码实现队列:**
12 |
13 | ```html5
14 |
15 |
16 |
17 |
18 | Queue Sample
19 |
20 |
21 |
22 |
77 |
78 |
79 | ```
80 | **举个案例:**
81 | 常用队列模拟排队的人。下面我们使用队列来模拟跳方块舞的人。
82 | 当男男女女来到舞池,他们按照自己的性别排成两队。当舞池中有地方空出来时,选两个队列中的第一个人组成舞伴。他们身后的人各自向前移动一位,变成新的队首。当一对舞伴迈入舞池时,主持人会大声喊出他们的名字。当一对舞伴走出舞池,且两排队伍中有任意一队没人时,主持人也会把这个情况告诉大家。
83 |
84 | ```html5
85 |
86 |
87 |
88 |
89 | Queue Sample
90 |
91 |
92 |
93 |
193 |
194 |
195 | ```
--------------------------------------------------------------------------------
/src/前端自动化测试工具--使用karma进行javascript单元测试.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 前端自动化测试工具--使用karma进行javascript单元测试
3 | tags:
4 | - FE
5 | - PhantomJS
6 | - Jasmine
7 | - Karma
8 | - 自动化测试
9 | categories: 前端技术
10 | date: 2016-10-11 00:00:00
11 | ---
12 | 前面我写了一篇博客是《前端自动化测试工具PhantomJS+CasperJS结合使用教程》其中使用CasperJS不仅可以进行单元测试,还可以进行浏览器测试,是个很不错的工具,今天介绍的工具是Karma+Jasmine+PhantomJS组合的前端javascript单元测试工具。
13 | # 1.介绍
14 | Karma是由Google团队开发的一套前端测试运行框架,karma会启动一个web服务器,将js源代码和测试脚本放到PhantomJS或者Chrome上执行。
15 | # 2.安装
16 | - 包管理package.json
17 |
18 | ```
19 | npm init
20 | ```
21 | 一路回车下去即可
22 | - 在项目中安装karma包
23 |
24 | ```
25 | npm i karma --save-dev
26 | ```
27 | - karma初始化
28 |
29 | ```
30 | karma init
31 | ```
32 | 按照下面的选择好
33 |
34 | ```bash
35 | E:\javascript\auto-test\karma-demo>karma init
36 |
37 | Which testing framework do you want to use ?
38 | Press tab to list possible options. Enter to move to the next question.
39 | > jasmine
40 |
41 | Do you want to use Require.js ?
42 | This will add Require.js plugin.
43 | Press tab to list possible options. Enter to move to the next question.
44 | > no
45 |
46 | Do you want to capture any browsers automatically ?
47 | Press tab to list possible options. Enter empty string to move to the next question.
48 | > PhantomJS
49 | >
50 |
51 | What is the location of your source and test files ?
52 | You can use glob patterns, eg. "js/*.js" or "test/**/*Spec.js".
53 | Enter empty string to move to the next question.
54 | > src/**/*.js
55 | > test/**/*.js
56 | 14 10 2016 10:49:43.958:WARN [init]: There is no file matching this pattern.
57 |
58 | >
59 |
60 | Should any of the files included by the previous patterns be excluded ?
61 | You can use glob patterns, eg. "**/*.swp".
62 | Enter empty string to move to the next question.
63 | >
64 |
65 | Do you want Karma to watch all the files and run the tests on change ?
66 | Press tab to list possible options.
67 | > yes
68 |
69 |
70 | Config file generated at "E:\javascript\auto-test\karma-demo\karma.conf.js".
71 |
72 | ```
73 | 上图是选项的示例,这里使用jasmine测试框架,PhantomJS作为代码运行的环境(也可以选择其他浏览器作为运行环境,比如Chrome,IE等)。最后在项目中生成karma.conf.js文件
74 | - 安装jasmine-core
75 |
76 | ```bash
77 | npm i jasmine-core --save-dev
78 | ```
79 | # 3.demo1--ES5
80 | 目录结构
81 | ```
82 | karma-example
83 | ├── src
84 | ├── index.js
85 | ├── test
86 | ├── package.json
87 | ```
88 | 源码:src--index.js
89 | ```javascript
90 | function isNum(num) {
91 | if (typeof num === 'number') {
92 | return true;
93 | } else {
94 | return false;
95 | }
96 | }
97 | ```
98 | 测试:test--index.js
99 | ```javascript
100 | describe('index.js: ', function() {
101 | it('isNum() should work fine.', function() {
102 | expect(isNum(1)).toBe(true)
103 | expect(isNum('1')).toBe(false)
104 | })
105 | })
106 | ```
107 | 运行,执行命令
108 | ```
109 | karma start
110 | ```
111 | 命令行结果
112 |
113 | ```bash
114 | 14 10 2016 10:56:13.038:WARN [karma]: No captured browser, open http://localhost:9876/
115 | 14 10 2016 10:56:13.067:INFO [karma]: Karma v1.3.0 server started at http://localhost:9876/
116 | 14 10 2016 10:56:13.101:INFO [launcher]: Launching browser PhantomJS with unlimited concurrency
117 | 14 10 2016 10:56:13.119:INFO [launcher]: Starting browser PhantomJS
118 | 14 10 2016 10:56:16.207:INFO [PhantomJS 2.1.1 (Windows 8 0.0.0)]: Connected on socket /#JoOdYxAeCS4xvhHHAAAA with id 87859111
119 | PhantomJS 2.1.1 (Windows 8 0.0.0): Executed 1 of 1 SUCCESS (0.009 secs / 0.004 secs)
120 | ```
121 | # 4.demo2-ES6
122 | 安装**使用Webpack+Babel**
123 | ```
124 | npm i karma-webpack --save-dev
125 | npm i babel-loader babel-core babel-preset-es2015 --save-dev
126 | ```
127 | 源码src--index2.js
128 | ```javascript
129 | function isNum(num) {
130 | if (typeof num === 'number') {
131 | return true;
132 | } else {
133 | return false;
134 | }
135 | }
136 |
137 | export {isNum};
138 | // export default isNum;
139 | ```
140 | 测试test--index2.js
141 |
142 | ```javascript
143 | import {isNum} from '../src/index2';
144 | // import isNum from '../src/index2';
145 |
146 | describe('index2.js:', () => {
147 | it('isNum() should work fine.', () => {
148 | expect(isNum(1)).toBe(true);
149 | expect(isNum('1')).toBe(false);
150 | });
151 | });
152 | ```
153 | 修改配置文件`karma.conf.js`
154 |
155 | ```javascript
156 | config.set({
157 | basePath: '',
158 | frameworks: ['jasmine'],
159 | //修改
160 | files: [
161 | // 'src/**/*.js',
162 | 'test/**/*.js'
163 | ],
164 | exclude: [],
165 | preprocessors: {
166 | 'test/**/*.js': ['webpack', 'coverage'] //新增
167 | //coverage为覆盖率测试,这里不再介绍
168 | },
169 | reporters: ['progress', 'coverage'],
170 | // 新增--覆盖率测试
171 | coverageReporter: {
172 | type: 'html',
173 | dir: 'coverage/'
174 | },
175 | port: 9876,
176 | colors: true,
177 | logLevel: config.LOG_INFO,
178 | autoWatch: true,
179 | browsers: ['PhantomJS'],
180 | singleRun: false,
181 | concurrency: Infinity,
182 | //新增
183 | webpack: {
184 | module: {
185 | loaders: [{
186 | test: /\.js$/,
187 | loader: 'babel',
188 | exclude: /node_modules/,
189 | query: {
190 | presets: ['es2015']
191 | }
192 | }]
193 | }
194 | }
195 | })
196 | ```
197 | **参考阅读:**
198 | - [http://karma-runner.github.io/](http://karma-runner.github.io/)
199 | - [https://github.com/karma-runner/karma](https://github.com/karma-runner/karma)
200 | - [前端单元测试之Karma环境搭建](http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651551281&idx=2&sn=a2c7e0c5ce40d3c76a77878bb059b247&chksm=8025a1f0b75228e69ba643cba44872120d8a54c5ec240c36fd37f2d8b5a24d2e980464df651e&scene=1&srcid=0921IND89Hz7S81VX0ZCtsGf#rd)
--------------------------------------------------------------------------------
/src/PHP爬虫最全总结2-phpQuery,PHPcrawer,snoopy框架中文介绍.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: PHP爬虫最全总结2-phpQuery,PHPcrawer,snoopy框架中文介绍
3 | tags:
4 | - 爬虫
5 | - PHP
6 | categories: PHP
7 | date: 2016-10-13 00:00:00
8 | ---
9 |
10 | 第一篇文章介绍了使用原生的PHP和PHP的扩展库实现了爬虫技术。本文尝试使用PHP爬虫框架来写,首先对三种爬虫技术[phpQuery](https://github.com/punkave/phpQuery),[PHPcrawer](http://phpcrawl.cuab.de/), snoopy进行对比,然后分析模拟浏览器行为的方式,重点介绍下snoopy
11 |
12 | > 所有代码挂在我的[github](https://github.com/zrysmt/PHPSpider)上
13 |
14 | # 1.几种常用的PHP爬虫框架对比
15 | ## 1.1 [phpQuery](https://github.com/punkave/phpQuery)
16 | **优势:**类似jquery的强大搜索DOM的能力。
17 | pq()是一个功能强大的搜索DOM的方法,跟jQuery的$()如出一辙,jQuery的选择器基本上都能使用在phpQuery上,只要把“.”变成“->”,Demo如下(对应我的github的Demo5)
18 |
19 | ```php
20 | html()."
";
26 | }
27 | foreach($menu_a as $a){
28 | echo pq($a)->attr("href")."
";
29 | }
30 | ?>
31 | ```
32 | ## 1.2 [PHPcrawer](http://phpcrawl.cuab.de/)
33 | **优势:**过滤能力比较强。
34 | 官方给的Demo如下(我的github中对应demo4):
35 |
36 | ```php
37 | url."
";
44 | }
45 | }
46 | $crawler = new MyCrawler();
47 | $crawler->setURL("www.baidu.com");
48 | $crawler->addURLFilterRule("#\.(jpg|gif)$# i");
49 | //过滤到含有这些图片格式的URL
50 | $crawler->go();
51 | ?>
52 | ```
53 | ## 1.3 snoopy
54 | **优势:**提交表单,设置代理等
55 | Snoopy是一个php类,用来模拟浏览器的功能,可以获取网页内容,发送表单,
56 | demo如下(对应github中的demo3):
57 |
58 | ```php
59 | include 'Snoopy/Snoopy.class.php';
60 | $snoopy = new Snoopy();
61 | $url = "http://www.baidu.com";
62 | // $snoopy->fetch($url);
63 | // $snoopy->fetchtext($url);//去除HTML标签和其他的无关数据
64 | $snoopy->fetchform($url);//只获取表单
65 | //只返回网页中链接 默认情况下,相对链接将自动补全,转换成完整的URL。
66 | // $snoopy->fetchlinks($url);
67 | var_dump($snoopy->results);
68 | ```
69 | ## 1.4 [phpspider](http://www.sphider.eu/)
70 | **优势:**安装配置到数据库
71 | 提供了安装配置,能够直接连接mysql数据库,使用也是比较广泛,这里我们暂时不单独介绍。
72 | # 2.模拟用户行为
73 | ## 2.1 file_get_contents
74 |
75 | ```php
76 | array(
79 | 'method'=>"GET",
80 | 'header'=>"Accept-language: en\r\n" .
81 | "Cookie: foo=bar\r\n"
82 | )
83 | );
84 |
85 | $context = stream_context_create($opts);
86 |
87 | /* Sends an http request to www.example.com
88 | with additional headers shown above */
89 | $fp = fopen('http://www.example.com', 'r', false, $context);
90 | fpassthru($fp);
91 | fclose($fp);
92 | ?>
93 | ```
94 | ## 2.2 curl
95 |
96 | ```php
97 | $ch=curl_init(); //初始化一个cURL会话
98 | curl_setopt($ch,CURLOPT_URL,$url);//设置需要获取的 URL 地址
99 | // 设置浏览器的特定header
100 | curl_setopt($ch, CURLOPT_HTTPHEADER, array(
101 | "Host: www.baidu.com",
102 | "Connection: keep-alive",
103 | "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
104 | "Upgrade-Insecure-Requests: 1",
105 | "DNT:1",
106 | "Accept-Language: zh-CN,zh;q=0.8,en-GB;q=0.6,en;q=0.4,en-US;q=0.2",
107 | "Cookie:_za=4540d427-eee1-435a-a533-66ecd8676d7d;"
108 | ));
109 | $result=curl_exec($ch);//执行一个cURL会话
110 | ```
111 | ## 2.3 snoopy
112 | - 表单提交
113 |
114 | 我们的一个例子
115 | form-demo.html
116 |
117 | ```html
118 |
119 |
120 |
121 |
122 | form-demo
123 |
124 |
125 |
130 |
131 |
132 | ```
133 | form-demo.php
134 |
135 | ```php
136 |
145 | ```
146 | 提交表单
147 | ```php
148 | submit($action,$formvars);
156 | echo $snoopy->results;
157 | ?>
158 | ```
159 | > 问题1:openssl extension required for HTTPS 增加对https的支持
160 |
161 | ```
162 | php.in ==> ;extension=php_openssl.dll 去除注释
163 | ```
164 |
165 | > 问题2:405 Not Allowed增加
166 |
167 | ```php
168 | $snoopy->agent = "(compatible; MSIE 4.01; MSN 2.5; AOL 4.0; Windows 98)"; //伪装浏览器
169 | $snoopy->referer = "http://www.icultivator.com"; //伪装来源页地址 http_referer
170 | $snoopy->rawheaders["Pragma"] = "no-cache"; //cache 的http头信息
171 | $snoopy->rawheaders["X_FORWARDED_FOR"] = "122.0.74.166"; //伪装ip
172 | ```
173 | > 问题3 : snoopy使用代理
174 |
175 | ```php
176 | $snoopy->proxy_host = "http://www.icultivator.com";
177 | // HTTPS connections over proxy are currently not supported
178 | $snoopy->proxy_port = "8080"; //使用代理
179 | $snoopy->maxredirs = 2; //重定向次数
180 | $snoopy->expandlinks = true; //是否补全链接 在采集的时候经常用到
181 | $snoopy->maxframes = 5; //允许的最大框架数
182 | ```
183 |
184 | **问题:**
185 | 其实尝试了网站进行提交表单是有问题的。这样简单的处理是不能提交表单的,使用代理也是有问题
186 | 的。snoopy框架确实会有很多问题,后面有解决思路了再说。
187 |
188 | **参考阅读:**
189 | - [cURL、file_get_contents、snoopy.class.php 优缺点](https://my.oschina.net/junn/blog/147936)
190 | - [开源中国-PHP爬虫框架列表](http://www.oschina.net/project/lang/22?tag=64&show=news)
191 | - [phpQuery](http://blog.johnsonlu.org/phpphpquery/)
192 | - [Snoopy下载地址](https://sourceforge.net/projects/snoopy/)
193 | - [Snoopy —— 强大的PHP采集类使用详解及示例:采集、模拟登录及伪装浏览器](http://www.thinksaas.cn/topics/0/558/558466.html)
194 | - [开源中国-snoopy博客列表](https://www.oschina.net/search?scope=blog&q=Snoopy)
195 |
196 |
--------------------------------------------------------------------------------
/src/javascript数据结构2-列表.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: javascript数据结构2-列表
3 | tags:
4 | - javascript
5 | - 数据结构
6 | categories: 数据结构
7 | date: 2016-10-09 00:00:00
8 | ---
9 |
10 | ## 1. 类型定义
11 | ```
12 | listSize(属性) 列表的元素个数
13 | pos( 属性) 列表的当前位置
14 | length( 属性) 返回列表中元素的个数
15 | clear( 方法) 清空列表中的所有元素
16 | toString( 方法) 返回列表的字符串形式
17 | getElement( 方法) 返回当前位置的元素
18 | insert( 方法) 在现有元素后插入新元素
19 | append( 方法) 在列表的末尾添加新元素
20 | remove( 方法) 从列表中删除元素
21 | front( 方法) 将列表的当前位置设移动到第一个元素
22 | end( 方法) 将列表的当前位置移动到最后一个元素
23 | prev(方法) 将当前位置后移一位
24 | next( 方法) 将当前位置前移一位
25 | currPos( 方法) 返回列表的当前位置
26 | moveTo(方法) 将当前位置移动到指定位置
27 | ```
28 | ## 2.实现列表类
29 |
30 | ```html5
31 |
32 |
33 |
34 | 实现列表类
35 |
36 |
37 |
38 |
106 |
107 |
108 | ```
109 | ## 3.实际例子
110 | 从txt文件中读取数据(注意:这种方法只是适合在IE浏览器)
111 | 文档内容:
112 |
113 | > 1.sam
114 | 2.tim
115 | 3.jom
116 | 4.dim
117 | 5.pop
118 | 6.hello
119 | 7.ming
120 |
121 | ```html5
122 |
123 |
124 |
125 | 无标题
126 |
127 |
128 |
241 |
242 |
243 | ```
244 |
--------------------------------------------------------------------------------
/src/动手DIY一个underscorejs库及underscorejs源码分析3.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 动手DIY一个underscorejs库及underscorejs源码分析3
3 | tags:
4 | - FE
5 | - underscorejs
6 | - 源码
7 | - js原生实现库
8 | categories: 前端技术
9 | date: 2016-10-26 00:00:00
10 | ---
11 | > 所有代码挂在我的[github](https://github.com/zrysmt/DIY-underscorejs)上,例子是demo6.html,DIY/4/_underscore.js.欢迎fork,star。
12 | > https://github.com/zrysmt/DIY-underscorejs
13 |
14 | 这一部分来DIY两个经常被使用的函数(或者说分析其源码),分别是throttle(节流函数)和debounce(防反跳函数)。
15 |
16 | 这两个函数特别适合一些场景:事件频繁被触发,会导致频繁执行DOM的操作,如下:
17 | - window对象的resize、scroll事件
18 | - 拖拽时候的mousemove事件
19 | - mousedown、keydown事件
20 | - 文字输入、自动完成的keyup事件
21 |
22 | # 1.throttle节流函数
23 |
24 | 创建并返回一个像节流阀一样的函数,当重复调用函数的时候,最多每隔 **wait**毫秒调用一次该函数。对于想控制一些触发频率较高的事件有帮助。
25 |
26 | 默认情况下,**throttle**将在你调用的第一时间尽快执行这个**function**,并且,如果你在**wait**周期内调用任意次数的函数,都将尽快的被覆盖。如果你想禁用第一次首先执行的话,传递{leading: false},还有如果你想禁用最后一次执行的话,传递{trailing: false}。
27 |
28 | 也许你还没完全看懂,我们来做个demo测试下。
29 | ```html
30 |
31 | 创建并返回一个像节流阀一样的函数,当重复调用函数的时候,最多每隔 wait毫秒调用一次该函数。对于想控制一些触发频率较高的事件有帮助。(注:详见:javascript函数的throttle和debounce) 默认情况下,throttle将在你调用的第一时间尽快执行这个function,并且,如果你在wait周期内调用任意次数的函数,都将尽快的被覆盖。如果你想禁用第一次首先执行的话,传递{leading: false},还有如果你想禁用最后一次执行的话,传递{trailing: false}
32 |
33 |
48 | ```
49 | 我们先看结果,后看下部分的源码实现。
50 | - 1.只拉动一次窗口,会响应两次`updatePosition`,分别对应状态A、B,示例Demo中有详细说明解释第三个参数。
51 |
52 | 
53 | - 2.多次拉动窗口,第一次会立即响应,拖动比较快的时候,只会隔大概1000ms(自己设置的时间,默认100ms)响应一次。
54 |
55 | 
56 | 源码实现:
57 | ```javascript
58 | _.throttle = function(func, wait, options) {
59 | var timeout, context, args, result;
60 | var previous = 0;
61 | if (!options) options = {};
62 |
63 | var later = function() {
64 | previous = options.leading === false ? 0 : _.now();
65 | timeout = null;
66 | result = func.apply(context, args);
67 |
68 | if (!timeout) context = args = null;
69 | };
70 |
71 | var throttled = function() {
72 | var now = _.now();//加入_.now(),这里不在单说,相见开头处提供的github地址。
73 | if (!previous && options.leading === false) previous = now; //禁止第一次执行(A) remaining = wait - 0 = wait > 0 的话不会执行A
74 | //不禁止第一次执行A的时候,previous = 0,现在时间now >= wait,就是过了wait等待时间
75 | var remaining = wait - (now - previous); //remaining 第一次为< 0
76 | console.warn(wait, now, remaining);
77 | context = this;
78 | args = arguments;
79 | //按理来说remaining <= 0已经足够证明已经到达wait的时间间隔,但这里还考虑到假如客户端修改了系统时间则马上执行func函数(remaining > wait)
80 | if (remaining <= 0 || remaining > wait) {
81 | if (timeout) {
82 | clearTimeout(timeout);
83 | timeout = null;
84 | }
85 | previous = now;
86 | result = func.apply(context, args); //第一次执行A
87 | if (!timeout) context = args = null;
88 | } else if (!timeout && options.trailing !== false) { //不会禁用第二次执行(B)
89 | console.log("============第二次===============");
90 | timeout = setTimeout(later, remaining); //第二次执行(B)
91 | }
92 | return result;
93 | };
94 |
95 | throttled.cancel = function() {
96 | clearTimeout(timeout);
97 | previous = 0;
98 | timeout = context = args = null;
99 | };
100 |
101 | return throttled;
102 | };
103 |
104 | ```
105 | # 2.debounce 防反跳函数
106 |
107 | 返回 **function** 函数的防反跳版本, 将延迟函数的执行(真正的执行)在函数最后一次调用时刻的 **wait** 毫秒之后. 对于必须在一些输入(多是一些用户操作)停止到达_之后_执行的行为有帮助。 例如: 渲染一个Markdown格式的评论预览, 当窗口停止改变大小之后重新计算布局, 等等.
108 |
109 | 传参 **immediate** 为 true, **debounce**会在 **wait** 时间间隔的开始调用这个函数 。
110 | 示例Demo
111 | ```javascript
112 | var debounce = _.debounce(updatePosition, 1000);
113 | $(window).resize(debounce);
114 | ```
115 | - 只会在停止操作后1000ms(自己设置的)执行
116 |
117 | 
118 | - 加入第三个参数,会在操作的同时执行
119 |
120 | `var debounce = _.debounce(updatePosition, 1000,true);`
121 | 
122 | 首先一个使用的工具函数,不在这里详细说明了。
123 | ```javascript
124 | _.delay = restArgs(function(func, wait, args) {
125 | return setTimeout(function() {
126 | return func.apply(null, args);
127 | }, wait);
128 | var restArgs = function(func, startIndex) {
129 | };
130 | _.restArgs = restArgs;
131 | ```
132 | 源码实现:
133 | ```javascript
134 | //immediate默认为false
135 | //只在最后一次关闭的时候,延迟后执行一次
136 | _.debounce = function(func, wait, immediate) {
137 | var timeout, result;
138 |
139 | var later = function(context, args) {
140 | timeout = null;
141 | if (args) result = func.apply(context, args);
142 | };
143 | restArgs = _.restArgs; //增加
144 | var debounced = restArgs(function(args) {
145 | if (timeout) clearTimeout(timeout);
146 | //控制timeout,一直拖动的时候会清除timeout,这样中间就不会执行了
147 | if (immediate) {//immediate为true立刻执行
148 | var callNow = !timeout;
149 | timeout = setTimeout(later, wait);
150 | if (callNow) result = func.apply(this, args);
151 | } else {
152 | timeout = _.delay(later, wait, this, args);
153 | }
154 |
155 | return result;
156 | });
157 |
158 | debounced.cancel = function() {
159 | clearTimeout(timeout);
160 | timeout = null;
161 | };
162 |
163 | return debounced;
164 | };
165 | ```
166 | 好了就简单介绍到这里
167 | > 所有代码挂在我的[github](https://github.com/zrysmt/DIY-underscorejs)上,例子是demo6.html,DIY/4/_underscore.js.欢迎fork,star。
168 | > https://github.com/zrysmt/DIY-underscorejs
--------------------------------------------------------------------------------
/src/阿里巴巴校招2017前端笔试题目-原生js-html5-实现一个路由.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 阿里巴巴校招2017前端笔试题目 -- 原生js/html5 实现一个路由
3 | date: 2017-04-28 12:44:52
4 | tags:
5 | - FE
6 | - 路由
7 | - 笔试
8 | categories: 前端技术
9 | ---
10 |
11 | 阿里巴巴校招2017前端笔试题目:
12 | 1)路由有什么缺点?
13 | 2)原生js/html5 实现一个路由
14 |
15 | 缺点:
16 | * 使用浏览器的前进,后退键的时候会重新发送请求,没有合理地利用缓存
17 | * 单页面无法记住之前滚动的位置,无法在前进,后退的时候记住滚动的位置
18 |
19 | 路由的概念:
20 | * 路由是根据不同的 url 地址展示不同的内容或页面
21 | * 前端路由就是把不同路由对应不同的内容或页面的任务交给前端来做,之前是通过服务端根据 url 的不同返回不同的页面实现的。
22 |
23 | 我们直接来看两个例子,一个是hash结构的,这是在Html5 的history api出现之前的解决方案;一个是基于history api实现的。
24 | - hash
25 |
26 | ```
27 | http://10.0.0.1/
28 | http://10.0.0.1/#/about
29 | http://10.0.0.1/#/concat
30 | ```
31 | - history
32 |
33 | ```
34 | http://10.0.0.1/
35 | http://10.0.0.1/about
36 | http://10.0.0.1/concat
37 | ```
38 | 前端的路由和后端的路由在实现技术上不一样,但是原理都是一样的。
39 | # 1.hash
40 | 关键是监控两个事件,一个是页面加载进来的时候触发`load`,一个是hash改变的时候触发`hashchange`。
41 | ```javascript
42 |
43 |
44 |
45 |
46 |
47 | Document
48 |
49 |
50 |
55 |
91 |
92 |
93 |
94 |
95 | ```
96 |
97 | # 2.history api
98 | html5 增加了两个方法,分别是`pushState`,`replaceState`.
99 |
100 | 两个方法均有三个参数:一个状态对象、一个标题(现在会被忽略),一个可选的URL地址
101 | **状态对象(state object)** — 一个JavaScript对象,与用pushState()方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,popstate事件都会被触发,并且事件对象的state属性都包含历史记录条目的状态对象的拷贝。
102 |
103 | 任何可序列化的对象都可以被当做状态对象。因为FireFox浏览器会把状态对象保存到用户的硬盘,这样它们就能在用户重启浏览器之后被还原,我们强行限制状态对象的大小为640k。如果你向pushState()方法传递了一个超过该限额的状态对象,该方法会抛出异常。如果你需要存储很大的数据,建议使用sessionStorage或localStorage。
104 |
105 | pushState 用于向 history 添加当前页面的记录,而 replaceState 和 pushState 的用法完全一样,唯一的区别就是它用于修改当前页面在 history 中的记录。
106 |
107 | **两者的一个表现的区别是**:在浏览器上点击后退键的时候,使用pushState的会正常按照点击的顺序依次返回,而使用replaceState的只是替换,不会返回,会直接返回到pushState的记录。
108 |
109 | **index.html**
110 | ```html
111 |
112 |
113 |
114 |
115 | Simple History
116 |
117 |
118 | Push One
119 | Push Two
120 | Push Three
121 | Replace One
122 | Replace Two
123 | Replace Three
124 |
125 |
126 |
127 |
151 |
152 |
153 |
154 | ```
155 | **simple-history.js**
156 | ```javascript
157 | (function(window, undefined) {
158 |
159 | var initial = location.href;
160 |
161 | window.SimpleHistory = {
162 | supported: !!(window.history && window.history.pushState),
163 | pushState: function(fragment, state) {
164 | state = state || {};
165 | history.pushState(state, null, fragment);
166 | this.notify(state);
167 | },
168 | replaceState: function(fragment, state) {
169 | state = state || {};
170 | history.replaceState(state, null, fragment);
171 | },
172 | notify: function(state) {
173 | console.log(location.pathname,location.search);
174 | this.matcher(location.pathname + location.search, state);
175 | },
176 | start: function(matcher) {
177 | this.matcher = matcher;
178 | window.addEventListener("popstate", function(event) {
179 | // workaround to always ignore first popstate event (Chrome)
180 | // a timeout isn't reliable enough
181 | if (initial && initial === location.href) {
182 | initial = null;
183 | return;
184 | }
185 | SimpleHistory.notify(event.state || {});
186 | }, false);
187 | }
188 | };
189 |
190 | }(window));
191 | ```
192 |
193 |
194 | **参考阅读:**
195 | - [ 原生JS实现一个简单的前端路由(路由实现的原理)](http://blog.csdn.net/sunxinty/article/details/52586556)
196 | - [从 React Router 谈谈路由的那些事](http://blog.csdn.net/u013063153/article/details/52513872)
--------------------------------------------------------------------------------
/src/前端自动化测试工具PhantomJS+CasperJS结合使用教程.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 前端自动化测试工具PhantomJS+CasperJS结合使用教程
3 | tags:
4 | - FE
5 | - PhantomJS
6 | - CasperJS
7 | - 自动化测试
8 | categories: 前端技术
9 | date: 2016-10-11 00:00:00
10 | ---
11 | > 下面的安装测试基于window系统(win10)
12 |
13 | # 1.PhantomJS
14 | [**PhantomJS** ](http://phantomjs.org/ " phantomjs ")是一个基于 **WebKit** 的服务器端JavaScript API,它全面支持web而不需浏览器支持,其快速,原生支持各种Web标准: DOM 处理, CSS 选择器, JSON, Canvas, 和 SVG。 PhantomJS 可以用于 页面自动化, 网络监测 , 网页截屏 ,以及 无界面测试 等
15 | ## 1.1 安装
16 | 下载地址为:http://phantomjs.org/download.html 解压之后,可以加到环境变量中
17 | ## 1.2 使用
18 | - 示例demo1.js--截图:
19 |
20 | ```javascript
21 | var page = require('webpage').create();
22 | page.viewportSize = {
23 | width: 1366,
24 | height: 800
25 | };
26 | var urls = ["https://www.baidu.com/", "https://zrysmt.github.io/"];
27 | page.open(urls[0], function() {
28 | console.log('welcome!');
29 | page.render('screen.png');
30 | phantom.exit();
31 | });
32 | ```
33 | 命令行输入:
34 | ```
35 | phantomjs demo1.js
36 | ```
37 |
38 | - 示例demo2.js--DOM操作
39 |
40 | ```javascript
41 | var page = require('webpage').create();
42 | phantom.outputEncoding = "gbk"; //解决中文乱码
43 | page.open("https://www.baidu.com/", function(status) {
44 | console.log(status);
45 | page.render('screen.png');
46 | var title = page.evaluate(function() {
47 | return document.title;
48 | });
49 | console.log('Page title: ' + title);
50 | phantom.exit();
51 | });
52 | ```
53 | 执行命令同上,得到结果是:
54 | ```
55 | success
56 | Page title: 百度一下,你就知道
57 | ```
58 | 所执行的DOM操作要在`page.evaluate`中,
59 |
60 | - 示例demo3.js--读取文件
61 |
62 | ```javascript
63 | var system = require('system');
64 | var fs = require('fs');
65 |
66 | phantom.outputEncoding = "gbk"; //解决中文乱码
67 | var filePath = "url-02.txt";
68 | var content = fs.read(filePath);
69 | console.log(content);
70 | ```
71 |
72 | url-02.txt中如果是很多url,一个一个访问url的话,可能会这样实现
73 | ```javascript
74 | page.open(urlArr[0], function(status) {
75 | page.open(urlArr[1], function(status) {
76 | page.open(urlArr[2], function(status) {
77 | //... ...
78 | });
79 | });
80 | });
81 | ```
82 | 这样写法就有很大的不方便,于是我们就引入了CasperJS
83 | # 2.CasperJS
84 | ## 2.1 安装
85 | ```
86 | npm i casperjs --save-dev
87 | ```
88 | 为方便使用也可以加入到环境变量中
89 | ## 2.2 使用
90 | - 示例demo:casper-test.js--打开网页截图
91 |
92 | ```javascript
93 | var casper = require('casper').create();
94 | casper.start();
95 | casper.thenOpen('http://www.baidu.com/', function () {
96 | casper.captureSelector('baidu.png', 'html');
97 | });
98 | casper.run();
99 | ```
100 | 执行命令如下
101 | ```
102 | casperjs casper-test.js
103 | ```
104 |
105 | - 示例demo:casper-test2.js--操作DOM,访问网页
106 |
107 | ```javascript
108 | var casper = require('casper').create();
109 | var links;
110 |
111 | function getLinks() {
112 | // Scrape the links from top-right nav of the website
113 | var links = document.querySelectorAll('ul.navigation li a');
114 | return Array.prototype.map.call(links, function (e) {
115 | return e.getAttribute('href')
116 | });
117 | }
118 | // Opens casperjs homepage
119 | casper.start('http://casperjs.org/');
120 |
121 | casper.then(function () {
122 | links = this.evaluate(getLinks);
123 | });
124 |
125 | casper.run(function () {
126 | for(var i in links) {
127 | console.log(links[i]);
128 | }
129 | casper.done();
130 | });
131 | ```
132 | 执行命令类比同上
133 |
134 | - 示例demo:casper-test3.js--单元测试
135 |
136 | ```javascript
137 | function Cow() {
138 | this.mowed = false;
139 | this.moo = function moo() {
140 | this.mowed = true; // mootable state: don't do that at home
141 | return 'moo!';
142 | };
143 | }
144 |
145 | casper.test.begin('Cow can moo', 2, function suite(test) {
146 | var cow = new Cow();
147 | test.assertEquals(cow.moo(), 'moo!');
148 | test.assert(cow.mowed);
149 | test.done();
150 | });
151 | ```
152 |
153 | 执行命令
154 | ```
155 | casperjs test casper-test3.js
156 | ```
157 | 结果是:
158 | ```
159 | Test file: casper-test3.js
160 | # Cow can moo
161 | PASS Subject equals the expected value
162 | PASS Subject is strictly true
163 | PASS Cow can moo (2 tests)
164 | PASS 2 tests executed in 0.031s, 2 passed, 0 failed, 0 dubious, 0 skipped.
165 | ```
166 | - 示例demo:casper-test4.js--浏览器测试
167 |
168 | ```javascript
169 | casper.test.begin('Google search retrieves 10 or more results', 5, function suite(test) {
170 | casper.start("http://www.google.fr/", function() {
171 | test.assertTitle("Google", "google homepage title is the one expected");
172 | test.assertExists('form[action="/search"]', "main form is found");
173 | this.fill('form[action="/search"]', {
174 | q: "casperjs"
175 | }, true);
176 | });
177 |
178 | casper.then(function() {
179 | test.assertTitle("casperjs - Recherche Google", "google title is ok");
180 | test.assertUrlMatch(/q=casperjs/, "search term has been submitted");
181 | test.assertEval(function() {
182 | return __utils__.findAll("h3.r").length >= 10;
183 | }, "google search for \"casperjs\" retrieves 10 or more results");
184 | });
185 |
186 | casper.run(function() {
187 | test.done();
188 | });
189 | });
190 | ```
191 | 执行命令如demo3类比
192 |
193 | # 3.PhantomJs+CasperJs
194 | 实现异步操作
195 |
196 | ```javascript
197 | var casper = require('casper').create(); //新建一个页面
198 |
199 | casper.start(url1); //添加第一个URL
200 | casper.thenOpen(url2); //添加第二个URL,依次类推
201 | casper.thenOpen(url3);
202 | casper.thenOpen(url4);
203 |
204 | casper.run(); //开始导航
205 | ```
206 | demo(casper-phantomjs.js)如下--一次访问三十几个url:
207 | ```javascript
208 | var fs = require('fs');
209 | var casper = require('casper').create();
210 | phantom.outputEncoding = "gbk"; //解决中文乱码
211 |
212 | var filePath = "url-02.txt";
213 | var content = fs.read(filePath);
214 | var urlArr = content.split('\n');
215 | casper.start();
216 | for (var i = 0; i < urlArr.length; i++) {
217 | casper.thenOpen(urlArr[i], function() {
218 | this.echo('Page title: ' + this.getTitle());
219 | });
220 | }
221 | casper.run();
222 | // phantom.exit();
223 | ```
224 | 执行命令
225 | ```
226 | casperjs casper-phantomjs.js
227 | ```
228 |
229 | **参考阅读:**
230 | - [http://phantomjs.org/](http://phantomjs.org/)
231 | - [PhantomJS快速入门教程](http://www.tuicool.com/articles/beeMNj/)
232 | - [http://casperjs.org/](http://casperjs.org/)
233 | - [浏览器自动化测试初探 - 使用phantomjs与casperjs](http://imweb.io/topic/55e46d8d771670e207a16bdc)
234 | - [CasperJS,基于PhantomJS的工具包](http://www.cnblogs.com/ziyunfei/archive/2012/09/27/2706254.html)
235 |
236 |
--------------------------------------------------------------------------------
/src/ECharts 3.0底层zrender 3.x源码分析3-Handler(C层).md:
--------------------------------------------------------------------------------
1 | ---
2 | title: ECharts 3.0底层zrender 3.x源码分析3-Handler(C层)
3 | tags:
4 | - FE
5 | - ECharts
6 | - zrender
7 | - 源码
8 | categories: 前端技术
9 | date: 2017-01-11 00:00:00
10 | ---
11 | 这一篇,介绍下Handler处理机制。
12 |
13 | Handler负责事件处理,包括'click', 'dblclick', 'mousewheel', 'mouseout', 'mouseup', 'mousedown', 'mousemove', 'contextmenu'等。我们知道canvas API没有提供监听每个元素的机制,这就需要一些处理。处理的思路是:监听事件的作用坐标(如点击时候的坐标),判断在哪个绘制元素的范围中,如果在某个元素中,这个元素就监听该事件。
14 |
15 | 一些demo和没有在博客中介绍的源码请进我的[github仓库](https://github.com/zrysmt/echarts3/tree/master/zrender)。
16 | >https://github.com/zrysmt/echarts3/tree/master/zrender
17 |
18 | # 1.Handle.js整体
19 | 同样Handle.js文件的结构是一个构造函数,一个prototype扩展原型,一些混入模式。
20 |
21 | 我们首先看在入口(zrender.js)中的调用
22 | ```javascript
23 | var handerProxy = !env.node ? new HandlerProxy(painter.getViewportRoot()) : null;//env.node默认为false
24 | //HandlerProxy 是移动端的一些处理事件
25 | this.handler = new Handler(storage, painter, handerProxy, painter.root);
26 | ```
27 | **构造函数:**
28 | ```javascript
29 | var Handler = function(storage, painter, proxy, painterRoot) {
30 | Eventful.call(this);
31 | this.storage = storage;
32 | this.painter = painter;
33 | this.painterRoot = painterRoot;
34 | proxy = proxy || new EmptyProxy();
35 | /**
36 | * Proxy of event. can be Dom, WebGLSurface, etc.
37 | */
38 | this.proxy = proxy;
39 | // Attach handler
40 | proxy.handler = this;
41 | this._hovered;
42 | /**
43 | * @private
44 | * @type {Date}
45 | */
46 | this._lastTouchMoment;
47 | this._lastX;//坐标位置x
48 | this._lastY;//坐标位置y
49 |
50 | Draggable.call(this);
51 | util.each(handlerNames, function (name) {
52 | proxy.on && proxy.on(name, this[name], this);
53 | }, this);
54 | };
55 | ```
56 | 构造函数中保留的有坐标信息。
57 |
58 | prototype中的一个重要的方法`dispatchToElement`,针对目标图形元素触发事件。
59 | ```javascript
60 | /**
61 | * 事件分发代理
62 | *
63 | * @private
64 | * @param {Object} targetEl 目标图形元素
65 | * @param {string} eventName 事件名称
66 | * @param {Object} event 事件对象
67 | */
68 | dispatchToElement: function(targetEl, eventName, event) {
69 | var eventHandler = 'on' + eventName;
70 | var eventPacket = makeEventPacket(eventName, targetEl, event);
71 | var el = targetEl;
72 | while (el) {
73 | el[eventHandler] && (eventPacket.cancelBubble = el[eventHandler].call(el, eventPacket));
74 | el.trigger(eventName, eventPacket);//触发
75 | el = el.parent;
76 | if (eventPacket.cancelBubble) {
77 | break;
78 | }
79 | }
80 | if (!eventPacket.cancelBubble) {
81 | // 冒泡到顶级 zrender 对象
82 | this.trigger(eventName, eventPacket);
83 | // 分发事件到用户自定义层
84 | // 用户有可能在全局 click 事件中 dispose,所以需要判断下 painter 是否存在
85 | this.painter && this.painter.eachOtherLayer(function(layer) {
86 | if (typeof(layer[eventHandler]) == 'function') {
87 | layer[eventHandler].call(layer, eventPacket);
88 | }
89 | if (layer.trigger) {
90 | layer.trigger(eventName, eventPacket);//触发
91 | }
92 | });
93 | }
94 | }
95 | ```
96 |
97 | 混入Eventful(发布订阅模式事件)、Draggable(拖动事件)
98 | ```javascript
99 | util.mixin(Handler, Eventful);
100 | util.mixin(Handler, Draggable);
101 | ```
102 | # 2.canvas上元素的监听事件
103 |
104 | 对于一些事件的处理(Handler.js)
105 | ```javascript
106 | util.each(['click', 'mousedown', 'mouseup', 'mousewheel', 'dblclick', 'contextmenu'], function (name) {
107 | Handler.prototype[name] = function (event) {
108 | // Find hover again to avoid click event is dispatched manually. Or click is triggered without mouseover
109 | var hovered = this.findHover(event.zrX, event.zrY, null);
110 | if (name === 'mousedown') {
111 | this._downel = hovered;
112 | // In case click triggered before mouseup
113 | this._upel = hovered;
114 | }
115 | else if (name === 'mosueup') {
116 | this._upel = hovered;
117 | }
118 | else if (name === 'click') {
119 | if (this._downel !== this._upel) {
120 | return;
121 | }
122 | }
123 |
124 | console.info("hovered:",hovered);
125 | console.info(this);
126 | this.dispatchToElement(hovered, name, event);
127 | };
128 | });
129 | ```
130 | 我们在其中打印了this,通过demo/demo1/demo3-chartHasHover.html的例子我们可以发现,点击的时候都会打印this,而且打印3次。
131 |
132 | 通过打印的hovered,我们可以看出来hovered就是我们点击的对象。
133 | 
134 |
135 | `findHover`调用的是`isHover`函数,在`isHover`函数中通过`displayable`(Displayable.js)的`contain`或者`rectContain`判断点在哪个元素中。
136 |
137 | ```javascript
138 | function isHover(displayable, x, y) {
139 | if (displayable[displayable.rectHover ? 'rectContain' : 'contain'](x, y)) {
140 | var el = displayable;
141 | while (el) {
142 | // If ancestor is silent or clipped by ancestor
143 | if (el.silent || (el.clipPath && !el.clipPath.contain(x, y))) {
144 | return false;
145 | }
146 | el = el.parent;
147 | }
148 | return true;
149 | }
150 | return false;
151 | }
152 | ```
153 | Displayable.js的`contain`或者`rectContain`方法都是调用`rectContain`方法,判断x,y是否在图形的包围盒上。
154 | ```javascript
155 | rectContain: function(x, y) {
156 | var coord = this.transformCoordToLocal(x, y);
157 | var rect = this.getBoundingRect();//@module zrender/core/BoundingRect
158 | return rect.contain(coord[0], coord[1]);
159 | }
160 | ```
161 | zrender/core/BoundingRect的`contain`方法
162 | ```javascript
163 | contain: function(x, y) {
164 | var rect = this;
165 | return x >= rect.x && x <= (rect.x + rect.width) &&
166 | y >= rect.y && y <= (rect.y + rect.height);
167 | }
168 | ```
169 | 我们再来看看,在painter.js中,其实已经为每个元素生成了它的包围盒上。
170 | ```javascript
171 | var tmpRect = new BoundingRect(0, 0, 0, 0);
172 | var viewRect = new BoundingRect(0, 0, 0, 0);
173 |
174 | function isDisplayableCulled(el, width, height) {
175 | tmpRect.copy(el.getBoundingRect());
176 | if (el.transform) {
177 | tmpRect.applyTransform(el.transform);
178 | }
179 | viewRect.width = width;
180 | viewRect.height = height;
181 | return !tmpRect.intersect(viewRect);
182 | }
183 | ```
184 | 在绘制每个元素的时候,在`_doPaintEl`方法中调用了`isDisplayableCulled`。
185 |
186 |
187 |
188 | **参考阅读:**
189 | - [canvas-mdn教程](https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial)
190 | - [canvas基本的动画-mdn](https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial/Basic_animations)
191 |
192 |
--------------------------------------------------------------------------------
/src/HTTP协议实践篇--使用fiddle与后台php交互.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: HTTP协议实践篇--使用Fiddler与后台php交互
3 | tags:
4 | - HTTP协议
5 | - HTTP协议实践
6 | - Fiddler
7 | categories: HTTP/TCP/IP
8 | date: 2016-09-27 00:00:00
9 | ---
10 |
11 | 工具:
12 | - PHP、Apache服务器,端口号这里设置为8000,如果本机没有安装php环境,可以选择wamp或者xampp集成的php环境开发器
13 | - [fiddler](http://www.telerik.com/fiddler)是比较好用的抓包工具,它是免费的,具体使用我们不单独介绍。
14 |
15 | # 1.模拟form表单提交数据
16 |
17 | **html表单写法**
18 |
19 | ```html
20 |
24 | ```
25 | method改为`post`,`get`去体会它们的区别
26 | - 最大的区别是`get`方式,提交的话会将提交的数据放在url中,如`http://127.0.0.1:8000/test.php?name=hello`
27 | `post`请求提交的name=hello会放在header请求体内,具体位置在【**报文主体**】
28 | 
29 | - get传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB
30 | - 其实,两种方式都可以向服务器传送数据,向服务器上获取数据。
31 | **test.php**
32 |
33 | ```php
34 |
40 | ```
41 | 完整的请求头是
42 |
43 | ```
44 | POST http://127.0.0.1:8000/test.php HTTP/1.1
45 | Host: 127.0.0.1:8000
46 | Connection: keep-alive
47 | Content-Length: 10
48 | Cache-Control: max-age=0
49 | Origin: null
50 | Upgrade-Insecure-Requests: 1
51 | User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36
52 | Content-Type: application/x-www-form-urlencoded
53 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
54 | Accept-Encoding: gzip, deflate
55 | Accept-Language: zh-CN,zh;q=0.8
56 |
57 | name=hello
58 | ```
59 | 最后的结果,分别两种方式提交,总会有一个会显示没有定义,一个显示出请求的数据
60 |
61 | 下面就用Fiddler模拟
62 | - 使用`post`方式
63 | 
64 | `Content-Type`不能忽略
65 | ```
66 | Content-Type: application/x-www-form-urlencoded
67 | Content-Length: 10
68 | Host: 127.0.0.1:8000
69 | ```
70 | 点击右上角【Execute】,就能模拟一个form表单提交数据了。
71 | 右边会显示一条我们刚刚的HTTP请求。
72 | - 使用`get`方式
73 | 
74 | 【Execute】执行
75 |
76 | # 2.模拟文件操作
77 | ## 2.1 上传文件
78 | post方式提交请求,很少会用get方式去请求文件
79 | **html**
80 |
81 | ```html
82 |
87 | ```
88 | **php**
89 | ```php
90 | ";
95 | echo $_FILES["file"]["name"];//$_FILES["file"]通过 HTTP POST 方式上传到当前脚本的项目的数组。
96 | echo "
";
97 |
98 | if (file_exists("upload/" . $_FILES["file"]["name"])) {
99 | echo $_FILES["file"]["name"] . " already exists. ";
100 | }else{
101 | move_uploaded_file($_FILES["file"]["tmp_name"],
102 | "upload/" . $_FILES["file"]["name"]);
103 | echo "Stored in: " . "upload/" . $_FILES["file"]["name"];
104 | }
105 | ?>
106 | ```
107 | **请求头文件**
108 | - 在chrome中
109 |
110 | ```
111 | POST http://127.0.0.1:8000/test/upload_file.php HTTP/1.1
112 | Host: 127.0.0.1:8000
113 | Connection: keep-alive
114 | Content-Length: 291
115 | Cache-Control: max-age=0
116 | Origin: null
117 | Upgrade-Insecure-Requests: 1
118 | User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36
119 | Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryC1Pk1uMWXzAMqRMF
120 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
121 | Accept-Encoding: gzip, deflate
122 | Accept-Language: zh-CN,zh;q=0.8
123 |
124 | ------WebKitFormBoundaryC1Pk1uMWXzAMqRMF
125 | Content-Disposition: form-data; name="name"
126 |
127 | wenjian
128 | ------WebKitFormBoundaryC1Pk1uMWXzAMqRMF
129 | Content-Disposition: form-data; name="file"; filename="1.txt"
130 | Content-Type: text/plain
131 |
132 | This is a txt.
133 | ------WebKitFormBoundaryC1Pk1uMWXzAMqRMF--
134 |
135 | ```
136 | - 在Firfox中
137 |
138 | ```
139 | POST http://127.0.0.1:8000/test/upload_file.php HTTP/1.1
140 | Host: 127.0.0.1:8000
141 | User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
142 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
143 | Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
144 | Accept-Encoding: gzip, deflate
145 | Connection: keep-alive
146 | Content-Type: multipart/form-data; boundary=---------------------------31340552315478
147 | Content-Length: 302
148 |
149 | -----------------------------31340552315478
150 | Content-Disposition: form-data; name="name"
151 |
152 | txt文件
153 | -----------------------------31340552315478
154 | Content-Disposition: form-data; name="file"; filename="1.txt"
155 | Content-Type: text/plain
156 |
157 | This is a txt.
158 | -----------------------------31340552315478--
159 |
160 | ```
161 | 其中最大的差异也就是`boundary`分界线
162 | 分界线里的是上传文件的信息,如果是个图片,我们会看到
163 | ```
164 | Content-Disposition: form-data; name="file"; filename="CCGIS2.png"
165 | Content-Type: image/png
166 |
167 | //下面这些是图片的信息
168 |
169 | ```
170 | **响应头信息**差别并不大
171 | ```
172 | HTTP/1.1 200 OK
173 | Date: Tue, 20 Sep 2016 06:48:58 GMT
174 | Server: Apache/2.4.16 (Win64) PHP/5.6.13
175 | X-Powered-By: PHP/5.6.13
176 | Content-Length: 43
177 | Keep-Alive: timeout=5, max=100
178 | Connection: Keep-Alive
179 | Content-Type: text/html; charset=UTF-8
180 |
181 | wenjian
1.txt
Stored in: upload/1.txt
182 | ```
183 | **用Fiddler模拟**
184 | 
185 | 这里的头信息完全是照抄在chrome请求的头信息,其中最重要的是`Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryC1Pk1uMWXzAMqRMF`,我们用这一行就可以去执行,当然Fiddler会自动加入
186 | ```
187 | Host: 127.0.0.1:8000
188 | Content-Length: 295
189 | ```
190 | 有意思的是我们在`Request Body`中可以修改`filename`就可以修改上传后的文件名,我们也可以添加些内容,上传到服务器端。
191 | ```
192 | ------WebKitFormBoundaryC1Pk1uMWXzAMqRMF
193 | Content-Disposition: form-data; name="name"
194 |
195 | wenjian
196 | ------WebKitFormBoundaryC1Pk1uMWXzAMqRMF
197 | Content-Disposition: form-data; name="file"; filename="3.txt"
198 | Content-Type: text/plain
199 |
200 | This is a txt. 这里是加入的内容 hahahha 哈哈哈
201 | ------WebKitFormBoundaryC1Pk1uMWXzAMqRMF--
202 | ```
203 | 我们甚至可以修改boundary:`Content-Type: multipart/form-data; boundary=----123456`
204 | 那么`Request Body`中
205 | ```
206 | ------123456
207 | Content-Disposition: form-data; name="name"
208 |
209 | wenjian
210 | ------123456
211 | Content-Disposition: form-data; name="file"; filename="4.txt"
212 | Content-Type: text/plain
213 |
214 | This is a txt.hahahha 哈哈哈
215 | ------123456
216 | ```
217 | 值得一提的是,`Ruqest Body`右边的`Upload File`可以将选择的文件放在请求体中。注意修改`name`属性,与php文件的获取字段相同。
218 | ## 2.2 请求文件
219 | 请求文件其实很简单
220 | POST/GET http://127.0.0.1:8000/test/upload/1.txt
221 | 【Excute】执行即可
222 |
223 | 既然我们是来实践HTTP协议的,那么很重要的文件缓存这方面的我们也可以实践,这些内容我打算单独写一篇博客
224 |
225 | -----------------------华丽的分界线----------------------------
226 | 感觉这些技术很基础,但是也很黑客,我们完全可以使用这些技术去“黑”些网站,哈哈,当然要遵纪守法,当然有这些技术还是不够的。
227 |
228 |
229 |
230 |
231 |
232 |
233 |
--------------------------------------------------------------------------------
/src/openlayers 3实践与原理探究4.4.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: OpenLayers 3实践与原理探究4.4-ol3源码分析-render
3 | tags:
4 | - OpenLayers 3
5 | - 地图
6 | - js库
7 | - WebGIS
8 | categories: WebGIS
9 | date: 2016-09-28 00:00:00
10 | ---
11 | 前面几节的内容介绍了`Map`,`View`,`Source`,`Layer`,这些其实我们都是要么在对象属性中设置 ,要么是通过方法设置,实质上是通过共享的全局变量设置地图包含的图层,地图的显示效果,但是如果真正上绘制在浏览器上,需要渲染在canvas(ol3常用的渲染方式).
12 |
13 | 由于源码代码量比较大,这里只是从大部分介绍流程。
14 | 网上有人(OpenLayers 3源码那些事)总结一张图的不错,这里拿来用一下
15 | 
16 | # 0.从`map.js`开始
17 | - **1) render/renderSync**
18 | 具体流程用注释的形式标出
19 |
20 | ```javascript
21 | //renderSync是异步的,同样道理
22 | ol.Map.prototype.render = function() {
23 | if (this.animationDelayKey_ === undefined) {
24 | this.animationDelayKey_ = ol.global.requestAnimationFrame(
25 | this.animationDelay_);
26 | }
27 | };
28 | ```
29 | - **2) animationDelay_**
30 |
31 | ```javascript
32 | this.animationDelay_ = function() {
33 | this.animationDelayKey_ = undefined;
34 | this.renderFrame_.call(this, Date.now());
35 | }.bind(this);
36 | ```
37 | - **3) renderFrame_**
38 |
39 | ```javascript
40 | ol.Map.prototype.renderFrame_ = function(time) {
41 |
42 | var i, ii, viewState;
43 |
44 | var size = this.getSize();
45 | var view = this.getView();
46 | var extent = ol.extent.createEmpty();
47 | /** @type {?olx.FrameState} */
48 | var frameState = null;
49 | if (size !== undefined && ol.size.hasArea(size) && view && view.isDef()) {
50 | var viewHints = view.getHints(this.frameState_ ? this.frameState_.viewHints : undefined);
51 | var layerStatesArray = this.getLayerGroup().getLayerStatesArray();
52 | var layerStates = {};
53 | for (i = 0, ii = layerStatesArray.length; i < ii; ++i) {
54 | layerStates[goog.getUid(layerStatesArray[i].layer)] = layerStatesArray[i];
55 | }
56 | viewState = view.getState();
57 | frameState = /** @type {olx.FrameState} */ ({ //1.准备frameState
58 | animate: false,
59 | attributions: {},
60 | coordinateToPixelMatrix: this.coordinateToPixelMatrix_,
61 | extent: extent,
62 | focus: !this.focus_ ? viewState.center : this.focus_,
63 | index: this.frameIndex_++,
64 | layerStates: layerStates,//layer的常量属性,通过共享作为全局变量
65 | layerStatesArray: layerStatesArray,
66 | logos: ol.object.assign({}, this.logos_),
67 | pixelRatio: this.pixelRatio_,
68 | pixelToCoordinateMatrix: this.pixelToCoordinateMatrix_,
69 | postRenderFunctions: [],
70 | size: size,
71 | skippedFeatureUids: this.skippedFeatureUids_,
72 | tileQueue: this.tileQueue_,
73 | time: time,
74 | usedTiles: {},
75 | viewState: viewState,//view的常量属性,通过共享作为全局变量
76 | viewHints: viewHints,
77 | wantedTiles: {}
78 | });
79 | }
80 |
81 | if (frameState) {
82 | var preRenderFunctions = this.preRenderFunctions_;//2.渲染前
83 | var n = 0, preRenderFunction;
84 | for (i = 0, ii = preRenderFunctions.length; i < ii; ++i) {
85 | preRenderFunction = preRenderFunctions[i];
86 | if (preRenderFunction(this, frameState)) {
87 | preRenderFunctions[n++] = preRenderFunction;
88 | }
89 | }
90 | preRenderFunctions.length = n;
91 |
92 | frameState.extent = ol.extent.getForViewAndSize(viewState.center,
93 | viewState.resolution, viewState.rotation, frameState.size, extent);
94 | }
95 |
96 | this.frameState_ = frameState;
97 | this.renderer_.renderFrame(frameState); //3.渲染
98 |
99 | if (frameState) {
100 | if (frameState.animate) {
101 | this.render();
102 | }
103 | Array.prototype.push.apply(
104 | this.postRenderFunctions_, frameState.postRenderFunctions);//4.渲染后
105 |
106 | var idle = this.preRenderFunctions_.length === 0 &&
107 | !frameState.viewHints[ol.ViewHint.ANIMATING] &&
108 | !frameState.viewHints[ol.ViewHint.INTERACTING] &&
109 | !ol.extent.equals(frameState.extent, this.previousExtent_);
110 |
111 | if (idle) {
112 | this.dispatchEvent(
113 | new ol.MapEvent(ol.MapEventType.MOVEEND, this, frameState));
114 | ol.extent.clone(frameState.extent, this.previousExtent_);
115 | }
116 | }
117 |
118 | this.dispatchEvent(
119 | new ol.MapEvent(ol.MapEventType.POSTRENDER, this, frameState));
120 |
121 | goog.async.nextTick(this.handlePostRender, this);
122 |
123 | };
124 | ```
125 |
126 | **下面讲诉的渲染的第3步 `renderFrame(frameState)`**
127 | 有关渲染的源代码在`ol/ol/render`,`ol/ol/renderer`下。
128 | `ol/ol/render`文件夹下是渲染的基本属性和方法,利用设计模式中的工厂模式,用来构造`ol/ol/renderer`。
129 | # 1.渲染Map
130 | `ol/ol/renderer/maprenderer.js`
131 |
132 | ```javascript
133 | ol.renderer.Map = function(container, map) {}
134 | ```
135 | 这只是个父类,具体实现类位置在:
136 | `ol/ol/renderer/canvas/canvasmaprenderer.js`--ol.render.canvas.Map(默认)
137 | `ol/ol/renderer/canvas/webglmaprenderer.js`--ol.render.webgl.Map
138 | `ol/ol/renderer/canvas/dommaprenderer.js`--ol.render.dom.Map
139 |
140 | 主要介绍第一种`ol/ol/renderer/canvas/canvasmaprenderer.js`
141 |
142 | ```javascript
143 | ol.renderer.canvas.Map = function(container, map) {
144 | ol.renderer.Map.call(this, container, map);
145 | this.context_ = ol.dom.createCanvasContext2D();
146 |
147 | this.canvas_ = this.context_.canvas;
148 |
149 | this.canvas_.style.width = '100%';
150 | this.canvas_.style.height = '100%';
151 | this.canvas_.className = ol.css.CLASS_UNSELECTABLE;
152 | container.insertBefore(this.canvas_, container.childNodes[0] || null);
153 | }
154 | ```
155 | 渲染逻辑
156 | ```javascript
157 | ol.renderer.canvas.Map.prototype.renderFrame = function(frameState) {}
158 | ```
159 | # 2.渲染Layer
160 | `ol/ol/renderer/layerrenderer.js`
161 |
162 | ```javascript
163 | ol.renderer.Layer = function(layer) {
164 |
165 | ol.Observable.call(this);
166 |
167 | this.layer_ = layer;
168 | };
169 | ```
170 | 这只是个父类,具体实现类位置在:
171 | `ol/ol/renderer/canvas/canvaslayerrenderer.js`--ol.render.canvas.Layer(默认)
172 | `ol/ol/renderer/canvas/webgllayerrenderer.js`--ol.render.webgl.Layer
173 | `ol/ol/renderer/canvas/domlayerrenderer.js`--ol.render.dom.Layer
174 |
175 | 主要介绍第一种ol.render.canvas.Layer(默认):
176 | 这个类又分为三种类型:
177 | - ol.render.canvas.TileLayer
178 | - ol.render.canvas.VectorLayer
179 | - ol.render.canvas.VectorTileLayer
180 |
181 |
182 | `ol.render.canvas.TileLayer`渲染逻辑
183 |
184 | ```javascript
185 | ol.renderer.canvas.TileLayer.prototype.prepareFrame = function(
186 | frameState, layerState) {} //第一步
187 | ol.renderer.canvas.TileLayer.prototype.composeFrame = function(//第二步
188 | frameState, layerState, context) {
189 | var transform = this.getTransform(frameState, 0);
190 | this.dispatchPreComposeEvent(context, frameState, transform);
191 | this.renderTileImages(context, frameState, layerState);
192 | this.dispatchPostComposeEvent(context, frameState, transform);
193 | };
194 |
195 | ol.renderer.canvas.TileLayer.prototype.renderTileImages = function(context, frameState, layerState) {}
196 | ```
197 |
198 |
199 | 参考文献:
200 | - [OpenLayers 3源码解析视频](http://www.jianshu.com/p/573cde18575a)
201 | - [OpenLayers 3源码那些事(上)](https://www.google.com.hk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=4&ved=0ahUKEwjV852YrvDNAhVEQo8KHbbAAzwQFgg0MAM&url=%68%74%74%70%3a%2f%2f%77%65%69%6c%69%6e%2e%6d%65%2f%64%6f%63%2f%4f%70%65%6e%4c%61%79%65%72%73%25%32%30%33%25%45%36%25%42%41%25%39%30%25%45%37%25%41%30%25%38%31%25%45%39%25%38%32%25%41%33%25%45%34%25%42%41%25%39%42%25%45%34%25%42%41%25%38%42%28%25%45%34%25%42%38%25%38%41%29%2e%64%6f%63%78&usg=AFQjCNHRsX5ZW6MBpwJUCSEZgOuR7NL4Rw)
202 | - [OpenLayers 3源码那些事(下)](http://weilin.me/ol3-shares/source-explain-2/)
--------------------------------------------------------------------------------
/src/使用React+Three.js封装一个三维地球.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 使用React+Three.js 封装一个三维地球
3 | tags:
4 | - FE
5 | - Three.js
6 | categories: 前端技术
7 | date: 2017-09-23 17:43:15
8 | ---
9 | 良久没有写过博客了,最近忙的焦头烂额,忽略了博客,罪过罪过。今天补充一篇,前一段时间研究过的技术,使用React+Three.js 封装一个三维地球,支持鼠标的交互行为。其实也实现了对有坐标的json数据展示在地球上的功能,以后会有补充。
10 |
11 | [github仓库地址](https://github.com/zrysmt/react-threejs-app):
12 | > https://github.com/zrysmt/react-threejs-app
13 |
14 | 整体做完之后的效果图:
15 | 
16 | 废话少说,直接上环境
17 | ## 1.环境
18 | 使用facebook给出的脚手架工具[create-react-app](https://github.com/facebookincubator/create-react-app).
19 |
20 | ```bash
21 | npm install -g create-react-app
22 |
23 | create-react-app react-threejs-app
24 | cd react-threejs-app/
25 | ```
26 | 执行
27 | ```bash
28 | npm start
29 | ```
30 | 浏览器会自动打开`localhost:3000`。
31 |
32 | ## 2.背景知识
33 | Three.js简单来说就是封装了WebGL一些易用的API接口,我们知道只使用WebGL比较低效。具体的关于WebGL的技术给出两篇博客的入口,关于Three.js可以参考文章最后给出的参考阅读部分。
34 | - [WebGL基础简明教程1-简介](https://zrysmt.github.io/2017/05/17/WebGL%E5%9F%BA%E7%A1%80%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B1-%E7%AE%80%E4%BB%8B/)
35 | - [WebGL基础简明教程2-基础知识](https://zrysmt.github.io/2017/05/17/WebGL%E5%9F%BA%E7%A1%80%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B2-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/)
36 |
37 | 如果不是很了解WebGL技术也没有关系,不妨现在先看看Three.js创建模型的整体过程。
38 | 
39 |
40 | 安装需要的库,`three`是Three.js的库,` three-orbitcontrols`用来支持鼠标的交互行为的库。
41 | ```bash
42 | npm i three three-orbitcontrols --save
43 | ```
44 |
45 | ## 3.一步一个脚印
46 | ### 3.1 准备一张高清的世界地图
47 | 这里在github仓库中已经给出。
48 | ### 3.2 定义一个组件`ThreeMap`
49 | 在`ThreeMap.js`定义组件`ThreeMap`,并且创建改组件的样式`ThreeMap.css`。css定义三维地球的容器的宽度和高度。
50 | ```css
51 | #WebGL-output{
52 | width: 100%;
53 | height: 700px;
54 | }
55 | ```
56 | 并且该组件在`App.js`引用。
57 | ### 3.3 引入库和样式
58 | ```js
59 | import './ThreeMap.css';
60 | import React, { Component } from 'react';
61 | import * as THREE from 'three';
62 | import Orbitcontrols from 'three-orbitcontrols';
63 | import Stats from './common/threejslibs/stats.min.js';
64 | ```
65 | ### 3.4 初始化方法入口和要渲染的虚拟DOM
66 | ```js
67 | componentDidMount(){
68 | this.initThree();
69 | }
70 | ```
71 | 要渲染的虚拟DOM设定好
72 | ```js
73 | render(){
74 | return(
75 |
76 | )
77 | }
78 | ```
79 | ### 3.4 initThree方法
80 | - 创建场景
81 |
82 | ```js
83 | let scene;
84 | scene = new THREE.Scene();
85 | ```
86 | - 创建Group
87 |
88 | ```js
89 | let group;
90 | group = new THREE.Group();
91 | scene.add( group );
92 | ```
93 | - 创建相机
94 |
95 | ```js
96 | camera = new THREE.PerspectiveCamera( 60, width / height, 1, 2000 );
97 | camera.position.x = -10;
98 | camera.position.y = 15;
99 | camera.position.z = 500;
100 | camera.lookAt( scene.position );
101 | ```
102 | - 相机作为`Orbitcontrols`的参数,支持鼠标交互
103 |
104 | ```js
105 | let orbitControls = new Orbitcontrols(camera);
106 | orbitControls.autoRotate = false;
107 | ```
108 | - 添加光源:环境光和点光源
109 |
110 | ```js
111 | let ambi = new THREE.AmbientLight(0x686868); //环境光
112 | scene.add(ambi);
113 | let spotLight = new THREE.DirectionalLight(0xffffff); //点光源
114 | spotLight.position.set(550, 100, 550);
115 | spotLight.intensity = 0.6;
116 | scene.add(spotLight);
117 | ```
118 | - 创建模型和材质
119 |
120 | ```js
121 | let loader = new THREE.TextureLoader();
122 | let planetTexture = require("./assets/imgs/planets/Earth.png");
123 |
124 | loader.load( planetTexture, function ( texture ) {
125 | let geometry = new THREE.SphereGeometry( 200, 20, 20 );
126 | let material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
127 | let mesh = new THREE.Mesh( geometry, material );
128 | group.add( mesh );
129 | } );
130 | ```
131 | - 渲染
132 |
133 | ```js
134 | let renderer;
135 | renderer = new THREE.WebGLRenderer();
136 | renderer.setClearColor( 0xffffff );
137 | renderer.setPixelRatio( window.devicePixelRatio );
138 | renderer.setSize( width, height );
139 | container.appendChild( renderer.domElement );
140 | ```
141 | - 增加监控的信息状态
142 |
143 | ```js
144 | stats = new Stats();
145 | container.appendChild( stats.dom );
146 | ```
147 | **将以上封装到`init`函数中**
148 | - 动态渲染,地球自转
149 |
150 | ```js
151 | function animate() {
152 | requestAnimationFrame( animate );
153 | render();
154 | stats.update();
155 | }
156 | function render() {
157 | group.rotation.y -= 0.005; //这行可以控制地球自转
158 | renderer.render( scene, camera );
159 | }
160 | ```
161 | 调用的顺序是:
162 | ```js
163 | init();
164 | animate();
165 | ```
166 | 大功告成,一个可交互的三维地球就可以使用了。
167 |
168 | ## 4.`ThreeMap.js`整体代码
169 | ```js
170 | import './ThreeMap.css';
171 | import React, { Component } from 'react';
172 | import * as THREE from 'three';
173 | import Orbitcontrols from 'three-orbitcontrols';
174 | import Stats from './common/threejslibs/stats.min.js';
175 |
176 | class ThreeMap extends Component{
177 | componentDidMount(){
178 | this.initThree();
179 | }
180 | initThree(){
181 | let stats;
182 | let camera, scene, renderer;
183 | let group;
184 | let container = document.getElementById('WebGL-output');
185 | let width = container.clientWidth,height = container.clientHeight;
186 |
187 | init();
188 | animate();
189 |
190 | function init() {
191 | scene = new THREE.Scene();
192 | group = new THREE.Group();
193 | scene.add( group );
194 |
195 | camera = new THREE.PerspectiveCamera( 60, width / height, 1, 2000 );
196 | camera.position.x = -10;
197 | camera.position.y = 15;
198 | camera.position.z = 500;
199 | camera.lookAt( scene.position );
200 |
201 | //控制地球
202 | let orbitControls = new /*THREE.OrbitControls*/Orbitcontrols(camera);
203 | orbitControls.autoRotate = false;
204 | // let clock = new THREE.Clock();
205 | //光源
206 | let ambi = new THREE.AmbientLight(0x686868);
207 | scene.add(ambi);
208 |
209 | let spotLight = new THREE.DirectionalLight(0xffffff);
210 | spotLight.position.set(550, 100, 550);
211 | spotLight.intensity = 0.6;
212 |
213 | scene.add(spotLight);
214 | // Texture
215 | let loader = new THREE.TextureLoader();
216 | let planetTexture = require("./assets/imgs/planets/Earth.png");
217 |
218 | loader.load( planetTexture, function ( texture ) {
219 | let geometry = new THREE.SphereGeometry( 200, 20, 20 );
220 | let material = new THREE.MeshBasicMaterial( { map: texture, overdraw: 0.5 } );
221 | let mesh = new THREE.Mesh( geometry, material );
222 | group.add( mesh );
223 | } );
224 |
225 | renderer = new THREE.WebGLRenderer();
226 | renderer.setClearColor( 0xffffff );
227 | renderer.setPixelRatio( window.devicePixelRatio );
228 | renderer.setSize( width, height );
229 | container.appendChild( renderer.domElement );
230 | stats = new Stats();
231 | container.appendChild( stats.dom ); //增加状态信息
232 |
233 | }
234 |
235 | function animate() {
236 | requestAnimationFrame( animate );
237 | render();
238 | stats.update();
239 | }
240 | function render() {
241 | group.rotation.y -= 0.005; //这行可以控制地球自转
242 | renderer.render( scene, camera );
243 | }
244 | }
245 | render(){
246 | return(
247 |
248 | )
249 | }
250 | }
251 |
252 | export default ThreeMap;
253 | ```
254 | **参考阅读:**
255 | - [WebGL基础简明教程1-简介](https://zrysmt.github.io/2017/05/17/WebGL%E5%9F%BA%E7%A1%80%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B1-%E7%AE%80%E4%BB%8B/)
256 | - [WebGL基础简明教程2-基础知识](https://zrysmt.github.io/2017/05/17/WebGL%E5%9F%BA%E7%A1%80%E7%AE%80%E6%98%8E%E6%95%99%E7%A8%8B2-%E5%9F%BA%E7%A1%80%E7%9F%A5%E8%AF%86/)
257 | - [图解WebGL&Three.js工作原理](http://www.cnblogs.com/wanbo/p/6754066.html)
258 |
--------------------------------------------------------------------------------
/src/一步一步DIY jQuery库3-引入sizzle引擎.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 一步一步DIY jQuery库3-引入sizzle引擎
3 | tags:
4 | - FE
5 | - jQuery
6 | - js原生实现库
7 | categories: 前端技术
8 | date: 2016-10-05 00:00:00
9 | ---
10 |
11 | 【注】所有代码挂在我的[github](https://github.com/zrysmt/DIY-jQuery)上
12 |
13 | 在前两篇的基础上,正式引入sizzle引擎,这里不详细介绍sizzle引擎。
14 |
15 | 我们在前两篇的`jQuery.fn.init`的方法是
16 |
17 | ```javascript
18 | var init = function(jQuery){
19 | jQuery.fn.init = function (selector, context) {
20 | if (!selector) {
21 | return this;
22 | } else {
23 | var elem = document.querySelector(selector);
24 | if (elem) {
25 | this[0] = elem;
26 | this.length = 1;
27 | }
28 | return this;
29 | }
30 | };
31 |
32 | jQuery.fn.init.prototype = jQuery.fn;
33 | };
34 | ```
35 | 这里得到的结果是个数组,而不是我们需要的类数组结构的DOM集合**HTMLCollection**
36 |
37 | # 1.引入Sizzle引擎
38 | 下载Sizzle,将`sizzle.js`文件复制在`src/sizzle`中,并且改造Sizzle成模块化的
39 |
40 | ```javascript
41 | //1-头部注释
42 | //(function( window ) {
43 |
44 | //2-最后尾部注释
45 | /*if ( typeof define === "function" && define.amd ) {
46 | define(function() { return Sizzle; });
47 | // Sizzle requires that there be a global window in Common-JS like environments
48 | } else if ( typeof module !== "undefined" && module.exports ) {
49 | module.exports = Sizzle;
50 | } else {
51 | window.Sizzle = Sizzle;
52 | }
53 | // EXPOSE
54 |
55 | })( window );*///修改点2
56 |
57 | //3-增加
58 | export default Sizzle;
59 | ```
60 | 同时增加一个初始化文件`src/sizzle/init.js`
61 |
62 | ```javascript
63 | import Sizzle from './sizzle.js';
64 |
65 | var selectorInit = function(jQuery){
66 | jQuery.find = Sizzle; // Sizzle 赋予静态接口 jQuery.find
67 | }
68 |
69 | export default selectorInit;
70 | ```
71 | 我们可以在jquery源码中找到全部将sizzle赋值的语句,这些我们暂时先不管
72 |
73 | ```javascript
74 | jQuery.find = Sizzle;
75 | jQuery.expr = Sizzle.selectors;
76 | jQuery.expr[":"] = jQuery.expr.pseudos;
77 | jQuery.unique = Sizzle.uniqueSort;
78 | jQuery.text = Sizzle.getText;
79 | jQuery.isXMLDoc = Sizzle.isXML;
80 | jQuery.contains = Sizzle.contains;
81 | ```
82 | 修改`jquery.js`
83 |
84 | ```javascript
85 | import jQuery from './core';
86 | import global from './global';
87 | import init from './init';
88 | import sizzleInit from './sizzle/init'; //新增
89 |
90 | global(jQuery);
91 | init(jQuery);
92 | sizzleInit(jQuery); //新增
93 |
94 | export default jQuery;
95 | ```
96 | 测试:
97 | ```html
98 | 1
99 | 2
100 | 3
101 | ```
102 | ```javascript
103 | var div = $('div');
104 | console.log(div);
105 | ```
106 | 最后的结果仍然是个DOM集合数组
107 |
108 | # 2.`$.merger`方法
109 |
110 | ```javascript
111 | jQuery.fn = jQuery.prototype = {
112 | length: 0, // 修改点1,jQuery实例.length 默认为0,这句一定要有,否则length会NAN
113 | ```
114 | ```javascript
115 | jQuery.extend({
116 | merge: function(first, second) {//新增
117 | var len = +second.length,
118 | j = 0,
119 | i = first.length;
120 | for (; j < len; j++) {
121 | first[i++] = second[j];
122 | }
123 | first.length = i;
124 |
125 | return first;
126 | }
127 | });
128 | ```
129 | 测试
130 | ```javascript
131 | var divs = $.find('div'); //纯数组
132 | var $div1 = $.merge(['hi'], divs); //右边的数组合并到左边的数组,形成一个新数组
133 | var $div2 = $.merge({
134 | 0: 'hi',
135 | length: 1
136 | }, divs); //右边的数组合并到左边的对象,形成一个新的类数组对象
137 |
138 | console.log($div1);
139 | console.log($div2);
140 | ```
141 | 我们发现,只需要将`$.merger`的第一个参数first设置为this(jQuery的示例对象,length已经默认设置为0),第二个参数second设置为搜索到的DOM集合就可以得到DOM集合类数组对象。
142 | 修改`src/init.js`
143 | ```javascript
144 | var init = function(jQuery){
145 | jQuery.fn.init = function (selector, context) {
146 | if (!selector) {
147 | return this;
148 | } else {
149 | var elemList = jQuery.find(selector);
150 | if (elemList.length) {
151 | jQuery.merge( this, elemList ); //this是jQuery实例,默认实例属性 .length 为0
152 | }
153 | return this;
154 | }
155 | };
156 |
157 | jQuery.fn.init.prototype = jQuery.fn;
158 | };
159 | export default init;
160 | ```
161 | # 3.扩展 `$.fn.find`
162 |
163 | 我们虽然能使用$.find方法,但是它并不支持链式,所以我们需要扩展之。
164 |
165 | ```javascript
166 | jQuery.fn.extend({
167 | find: function(selector) {
168 | var i, ret,
169 | len = this.length,
170 | self = this;
171 | ret = [];
172 |
173 | for (i = 0; i < len; i++) {
174 | jQuery.find(selector, self[i], ret); // //直接利用 Sizzle 接口,把结果注入到 ret 数组中去
175 | }
176 | return jQuery.merger(this,ret);
177 | }
178 | }
179 | ```
180 | # 4.记录栈-pushStack方法
181 |
182 | 参考浏览器的历史记录栈,将检索到的jQuery实例放入到栈中,方便存取数据,其中jquery中有一个方法`$.end`放回上次检索的jQuery对象,使用记录栈能够很方便的实现。
183 |
184 | ```javascript
185 | jQuery.fn = jQuery.prototype = {
186 | /**新增:
187 | * [pushStack 入栈操作]
188 | * @param {[Array]} elems
189 | * @return {[*]}
190 | */
191 | pushStack: function(elems) {
192 | var ret = jQuery.merge(this.constructor(), elems); //this.constructor() 返回了一个 length 为0的jQuery对象
193 | ret.prevObject = this;
194 | return ret;
195 | }
196 | };
197 | ```
198 | 重新修改第3部分的代码
199 |
200 | ```javascript
201 | jQuery.fn.extend({
202 | find: function(selector) {
203 | var i, ret,
204 | len = this.length,
205 | self = this;
206 | ret =[];
207 | for (i = 0; i < len; i++) {
208 | jQuery.find(selector, self[i], ret); // //直接利用 Sizzle 接口,把结果注入到 ret 数组中去
209 | }
210 | return this.pushStack(ret);
211 | },
212 | });
213 | ```
214 | 从性能上考虑,改为这样,建设merge里面的遍历
215 |
216 | ```javascript
217 | jQuery.fn.extend({
218 | find: function(selector) {
219 | var i, ret,
220 | len = this.length,
221 | self = this;
222 | ret = this.pushStack([]);
223 | for (i = 0; i < len; i++) {
224 | jQuery.find(selector, self[i], ret);
225 | }
226 | return ret;
227 | }
228 | });
229 | ```
230 | # 5.`$.fn.end`、`$.fn.eq` 和 `$.fn.get`
231 |
232 | ```javascript
233 | jQuery.fn.extend({
234 | end: function() {
235 | return this.prevObject || this.constructor();//this.prevObject记录栈中存在
236 | },
237 | eq: function(i) {
238 | var len = this.length;
239 | var j = +i + (i < 0 ? len : 0);
240 | return this.pushStack(j >= 0 && j < len ? [this[j]] : []);
241 | },
242 | get: function(num) {
243 | return num != null ?
244 | // 支持倒序搜索,num可以是负数
245 | (num < 0 ? this[num + this.length] : this[num]) :
246 | // 克隆一个新数组,避免指向相同
247 | [].slice.call(this);
248 | },
249 | first: function() {
250 | return this.eq(0);
251 | },
252 | last: function() {
253 | return this.eq(-1);
254 | }
255 | });
256 | ```
257 |
258 | # 6.todolist
259 |
260 | 我们花了三篇博客写到这里,其实还是有很多没有完全实现,后面的部分也是参照jquery的源码,DIY一个自己的jquery,还有一些没有实现的点
261 | - `$.fn.init`第二个参数context上下文还没实现
262 | - `$.fn.find`返回结果中可能带着重复的DOM
263 | 例如:
264 |
265 | ```html
266 |
267 |
271 | ```
272 | 下面的部分留作再写几篇博客
273 |
274 | 参考阅读:
275 | - [从零开始,DIY一个jQuery(1)](http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651551118&idx=1&sn=be4df567418db97c9b3d8a7ab5314e01&scene=1&srcid=0810SD0bcpyNFVUcmgsy5kh7#rd)
276 | - [从零开始,DIY一个jQuery(2)](http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651551123&idx=2&sn=26ddfeb73928eded3a63f05ca5273d66&scene=1&srcid=0811ZOMbQiHHtIIHRBceFbp7#rd)
277 | - [从零开始,DIY一个jQuery(3)](http://mp.weixin.qq.com/s?__biz=MzAxODE2MjM1MA==&mid=2651551144&idx=2&sn=78d8eec17bcdfa5bf51b5ec14c15c474&scene=1&srcid=0817O7pEiReCTSKGByB8SSIq#rd)
278 |
--------------------------------------------------------------------------------
/src/openlayers 3实践与原理探究1.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: OpenLayers 3实践与原理探究1-ol2 VS ol3
3 | tags:
4 | - OpenLayers 3
5 | - 地图
6 | - js库
7 | - WebGIS
8 | categories: WebGIS
9 | date: 2016-09-28 00:00:00
10 | ---
11 | 本文的重点在OpenLayers 3,对于OpenLayers 2简单比较说明。
12 | 下文中OpenLayers 2简称OL2,OpenLayers 3简称OL3
13 | # 1.OL 2 VS OL 3简单源码和实例
14 | ## 1.1 OpenLayers 2
15 | OpenLayers 是一个专为Web GIS 客户端开发提供的JavaScript 类库包,用于实现标准格式发布的地图数据访问。从OpenLayers2.2版本以后,OpenLayers已经将所用到的Prototype.js组件整合到了自身当中,并不断在Prototype.js的基础上完善面向对象的开发,Rico用到地方不多,只是在OpenLayers.Popup.AnchoredBubble类中圆角化DIV
16 | ## 1.1.1 OpenLayers 2源码简要分析
17 | 源码分析,下载版本为`2.13.1`,源码位置在`lib/OpenLayers`
18 | 
19 | 由于OL2不是本文的重点,所以下面会简诉关于OL2源码。
20 | `lib/OpenLayers/Layer/Image.js`
21 |
22 | ```javascript
23 | OpenLayers.Layer.Image = OpenLayers.Class(OpenLayers.Layer, {
24 | isBaseLayer: true,
25 | url: null,
26 | extent: null,
27 | size: null,
28 | tile: null,
29 | aspectRatio: null,
30 | initialize: function(name, url, extent, size, options) {
31 | //...
32 | },
33 | destroy: function() {
34 | //...
35 | },
36 | clone: function(obj) {
37 | //...
38 | },
39 | setMap: function(map) {
40 | //...
41 | },
42 | moveTo:function(bounds, zoomChanged, dragging) {
43 | //...
44 | },
45 | setTileSize: function() {
46 | //...
47 | },
48 | addTileMonitoringHooks: function(tile) {
49 | //...
50 | },
51 | //...
52 | CLASS_NAME: "OpenLayers.Layer.Image"
53 | });
54 | ```
55 | OpenLayers.Layer.Image 继承了OpenLayers.Layer类
56 | OpenLayers.Layer在上级目录下`lib/OpenLayers/Layer.js`
57 |
58 | ```javascript
59 | OpenLayers.Layer = OpenLayers.Class({
60 | id: null,
61 | name: null,
62 | //...
63 | initialize: function(name, options) {
64 | //...
65 | },
66 | destroy: function(setNewBaseLayer) {
67 | //...
68 | },
69 | clone: function (obj) {
70 | //...
71 | },
72 | getOptions: function() {
73 | //...
74 | },
75 | CLASS_NAME: "OpenLayers.Layer"
76 | });
77 | ```
78 | 通过分析我们可以知道,`OpenLayers.Class`的第一个参数是等号前面类(A类)继承的类;第二个参数是个对象,前面的部分作为A类的属性,后面的作为A类的方法。通过观察前三个方法我们可以看出,前三个方法依次为`initialize`,`destroy`,`clone`,分别为A类的初始化构造函数,销毁函数,克隆函数。
79 |
80 | ## 1.1.2 OpenLayers 2简单实例
81 |
82 | ```html
83 |
84 |
85 |
86 |
87 |
88 |
89 | 创建一个简单的电子地图
90 |
91 |
92 |
94 |
103 |
104 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | ```
126 | 
127 | ## 1.2 OpenLayers 3
128 | ## 1.2.1 OpenLayers 3源码简要分析
129 | OpenLayers 3对OpenLayers网络地图库进行了根本的重新设计。版本2虽然被广泛使用,但从JavaScript开发的早期发展阶段开始,已日益现实出它的落后。 OL3已运用现代的设计模式从底层重写。
130 |
131 | 最初的版本旨在支持第2版提供的功能,提供大量商业或免费的瓦片资源以及最流行的开源矢量数据格式。与版本2一样,数据可以被任意投影。最初的版本还增加了一些额外的功能,如能够方便地旋转地图以及显示地图动画。
132 | OpenLayers3同时设计了一些主要的新功能,如显示三维地图,或使用WebGL快速显示大型矢量数据集,这些功能将在以后的版本中加入。
133 |
134 | 源码分析,下载版本为`3.17.1`,源码位置在`ol/ol`文件夹下
135 | 
136 | `ol/ol/layer/layer.js`
137 |
138 | ```javascript
139 | goog.provide('ol.layer.Layer');
140 |
141 | goog.require('ol.events');
142 | goog.require('ol.events.EventType');
143 | goog.require('ol');
144 | goog.require('ol.Object');
145 | goog.require('ol.layer.Base');
146 | goog.require('ol.layer.LayerProperty');
147 | goog.require('ol.object');
148 | goog.require('ol.render.EventType');
149 | goog.require('ol.source.State');
150 |
151 | ol.layer.Layer = function(options) {
152 | var baseOptions = ol.object.assign({}, options);
153 | delete baseOptions.source;
154 |
155 | ol.layer.Base.call(this, /** @type {olx.layer.BaseOptions} */ (baseOptions));//继承extends {ol.layer.Base}
156 | this.mapPrecomposeKey_ = null;
157 | this.mapRenderKey_ = null;
158 | this.sourceChangeKey_ = null;
159 |
160 | if (options.map) {
161 | this.setMap(options.map);
162 | }
163 |
164 | ol.events.listen(this,
165 | ol.Object.getChangeEventType(ol.layer.LayerProperty.SOURCE),
166 | this.handleSourcePropertyChange_, this);
167 |
168 | var source = options.source ? options.source : null;
169 | this.setSource(source);
170 | };
171 | ol.inherits(ol.layer.Layer, ol.layer.Base);
172 |
173 | ol.layer.Layer.visibleAtResolution = function(layerState, resolution) {
174 | //...
175 | };
176 |
177 | ol.layer.Layer.prototype.getLayersArray = function(opt_array) {
178 | //...
179 | };
180 | ol.layer.Layer.prototype.getLayerStatesArray = function(opt_states) {
181 | //...
182 | };
183 | //...
184 | ```
185 | OL3利用[google的closure库](https://developers.google.com/closure/)组织代码的,库文件在源码的`closure-library`文件夹下。
186 | 在源码中用到的常用的功能是:
187 | - 类声明:使用goog.provide方法声明和注册一个类(表示自己能提供什么功能)。
188 | - 依赖声明:使用goog.require方法声明具体依赖的其它类(表示提供这些功能需要额外的哪功能的支持)
189 | 这一点也是OL2和OL3源代码重写的最重要的变化。
190 |
191 | ## 1.2.1 OpenLayers 3实例
192 |
193 | ```html
194 |
195 |
196 |
197 |
198 |
199 |
205 |
206 | OpenLayers 3 example
207 |
208 |
209 |
210 | My Map
211 |
212 |
226 |
227 |
228 |
229 | ```
230 | 
231 | # 2.OL 2 VS OL 3变化简要总结
232 | |比较部分|OL2|OL3|
233 | |------|:------------:|------:|
234 | |源码|使用Prototype和Rico|使用Clourse|
235 | |实现| var map = new OpenLayers.Map("rcp1_map");var osm = new OpenLayers.Layer.OSM();map.addLayer(osm);|var map = new ol.Map({});|
236 | |渲染方式|dom|canvas/webgl/dom|
237 |
238 | 补充说明:
239 | 三种渲染方式可以在`ol/ol/map.js`看到
240 |
241 | ```javascript
242 | ol.DEFAULT_RENDERER_TYPES = [
243 | ol.RendererType.CANVAS,
244 | ol.RendererType.WEBGL,
245 | ol.RendererType.DOM
246 | ];
247 | ```
248 | - dom是OL2常用的方式,显示地图时候(如openstreetmap)会采用img集合的方式。
249 | - OL3常用的渲染方式是基于canvas绘图技术。
250 | - WebGL快速显示大型矢量数据集
251 | OL2和OL3的差别比较大,目前看从OL2升级OL3的比较麻烦。
252 | 最后分享一个ol2和ol3的[资料](http://pan.baidu.com/s/1dFt3tIx),包含源码,教程和书籍
253 |
254 |
255 | 参考阅读:
256 | - 1.2-2015_OpenLayers_3_入门教程详细版.pdf
257 | - [OpenLayers](http://www.openlayers.cn/portal.php)
258 | - [OpenLayers 3官网](http://openlayers.org/)
259 | - [OpenLayers 2官网](http://openlayers.org/two/)
260 | - [google closure库](https://developers.google.com/closure/)
261 | - [JS 库浅析之 Google Closure](http://www.kuqin.com/webpagedesign/20100309/81059.html)
--------------------------------------------------------------------------------
/src/javascript数据结构7-二叉搜索树(BST).md:
--------------------------------------------------------------------------------
1 | ---
2 | title: javascript数据结构7-二叉搜索树(BST)
3 | tags:
4 | - javascript
5 | - 数据结构
6 | categories: 数据结构
7 | date: 2016-10-09 00:00:00
8 | ---
9 | ## 二叉树 :
10 | 
11 |
12 | 闲话少说,直接上代码:
13 |
14 | ```html5
15 |
16 |
17 |
18 |
19 | BST
20 |
21 |
22 |
219 |
220 |
221 | ```
222 | 结果:
223 | 
224 | ## 遍历
225 | 中序遍历:
226 | 
227 | 理解双层递归
228 |
229 | ```javascript
230 | function inOrder(node) {
231 | if (!(node == null)) {
232 | inOrder(node.left); //@1
233 | document.document(node.show() + " "); //@2
234 | inOrder(node.right); //@3
235 | }
236 | }
237 |
238 |
239 | inOrder(nums.root); //开始执行
240 | ```
241 | 从根节点开始:
242 | 
243 |
244 | 
245 | 
246 |
247 | ## 删除节点:
248 |
249 | ```javascript
250 | function remove(data) {
251 | root = removeNode(this.root, data);
252 | }
253 | ```
254 | 简单接受待删除的数据,具体执行是removeNode函数;
255 |
256 | ```javascript
257 | function removeNode(node, data) {
258 | }
259 | ```
260 | **待删除的节点是:**
261 | **1.叶子结点**,只需要将从父节点只想它的链接指向null;
262 |
263 | ```javascript
264 | if (node.left == null && node.right == null) {
265 | return null;
266 | }
267 | ```
268 |
269 | ```javascript
270 | if (node.left == null && node.right == null) {
271 | return null; //递归,找到节点置为空即可
272 | }
273 | //其他情况
274 | }
275 | else if (data < node.data) {
276 | node.left = removeNode(node.left, data); //#1
277 | return node; //#2
278 | }
279 | else {
280 | node.right = removeNode(node.right, data);//#3
281 | return node; //#4
282 | }
283 | ```
284 |
285 | 通过if else逻辑找到node节点
286 |
287 |
288 | ----------
289 | //#1 node.left=null(后面的函数递归后返回的值)
290 | //#3 node.right=null(后面的函数递归后返回的值)
291 |
292 | ----------
293 | **2.只包含一个子节点**,原本指向它的节点指向它的子节点。
294 | **3.左右子树都有的时候**。两种做法:找到左子树的最大值或者右子树的最小值。这里我们用第二种。
295 |
296 | - 查找右子树的最小值,创建一个临时的节点tempNode。
297 | - 将临时节点的值赋值给待删除节点
298 | - 删除临时节点
299 |
300 | 注意:
301 |
302 | ----------
303 | //#2 //#4必须有,如果没有,则删除节点下面的所有子树都将被删除。
304 | 真个过程举个形象的说明,遍历的时候把节点之间的链条解开进行查询,return node;递归查询到最后一级后,由下向上对链条进行缝合。
305 |
306 | ----------
307 |
--------------------------------------------------------------------------------
/src/domReady机制探究及DOMContentLoaded研究.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: domReady机制探究及DOMContentLoaded研究
3 | tags:
4 | - FE
5 | - DOMContentLoaded
6 | - domReady
7 | categories: 前端技术
8 | date: 2016-11-10 20:16:20
9 | ---
10 | domReady机制是很多框架和库都具有的种子模块,使用了在DOM树解析完成后就立即响应,不用等待图片等资源下载完成(onload执行时候表示这些资源完全下载完成)的一种机制,那怎么实现呢。
11 |
12 |
13 | 1)支持DOMContentLoaded事件的,就使用DOMContentLoaded事件;
14 | 2)不支持的,就用来自Diego Perini发现的著名Hack兼容。兼容原理大概就是,通过IE中的document.documentElement.doScroll(‘left’)来判断DOM树是否创建完毕或者使用监控script标签的onreadystatechange得到它的readyState属性判断【遗憾的是经过我们的实验,在IE下domReady机制总会在onload后执行】
15 | # 1. domReady机制在IE7-8下
16 | ## 1.1 domReady机制源码(包括IE/非IE)
17 | demo1.html
18 | ```html
19 |
20 |
21 |
22 |
23 | DOMContentLoaded Demo
24 |
25 |
26 |
27 |
28 |
29 |
30 |
35 |
36 |
37 |
38 |
39 | ```
40 | deferjs.js
41 | ```javascript
42 | console.log("defer script");
43 | ```
44 | demo1.js
45 | ```javascript
46 | dom = [];
47 | dom.isReady = false;
48 | dom.isFunction = function(obj) {
49 | return Object.prototype.toString.call(obj) === "[object Function]";
50 | };
51 | dom.Ready = function(fn) {
52 | dom.initReady(); //如果没有建成DOM树,则走第二步,存储起来一起杀
53 | if (dom.isFunction(fn)) {
54 | if (dom.isReady) {
55 | fn(); //如果已经建成DOM,则来一个杀一个
56 | } else {
57 | dom.push(fn); //存储加载事件
58 | }
59 | }
60 | };
61 | dom.fireReady = function() {
62 | if (dom.isReady) return;
63 | dom.isReady = true;
64 | for (var i = 0, n = dom.length; i < n; i++) {
65 | var fn = dom[i];
66 | fn();
67 | }
68 | dom.length = 0; //清空事件
69 | };
70 | dom.initReady = function() {
71 | if (document.addEventListener) {//非IE
72 | document.addEventListener("DOMContentLoaded", function() {
73 | console.log("DOMContentLoaded");
74 | document.removeEventListener("DOMContentLoaded", arguments.callee, false); //清除加载函数
75 | dom.fireReady();
76 | }, false);
77 | } else {//IE走这条线
78 | if (document.getElementById) {
79 | document.write("
153 | ```
154 |
155 |
156 |
157 |
158 | > defer 属性仅适用于外部脚本(只有在使用 src 属性时)
159 | > * 如果 async="async":脚本相对于页面的其余部分异步地执行(当页面继续进行解析时,脚本将被执行)
160 | > * 如果不使用 async 且 defer="defer":脚本将在页面完成解析时执行
161 | > * 如果既不使用 async 也不使用 defer:在浏览器继续解析页面之前,立即读取并执行脚本
162 |
163 |
164 | ## 1.3 结果分析
165 | 在IE7/8打印的结果是:
166 | 
167 | dom.fireReady函数在onload函数之后执行
168 |
169 |
170 | ## 1.4 IE下监控DOM树是否解析完成的其他做法
171 | 除了使用`document.write("
39 |
89 |
90 | ```
91 | ## 2.2 EChart 2非模块化引入
92 | ```html
93 |
94 |
95 |
96 | ECharts
97 |
98 |
99 |
100 |
101 |
102 |
103 |
137 |
138 | ```
139 |
140 | ## 2.3 EChart 3模块化引入
141 | **通过npm命令安装**
142 |
143 | ```bash
144 | npm install echarts --save
145 | ```
146 | **按需引入 ECharts 图表和组件**
147 |
148 | ```javascript
149 | // 引入 ECharts 主模块
150 | var echarts = require('echarts/lib/echarts');
151 | // 引入柱状图
152 | require('echarts/lib/chart/bar');
153 | // 引入提示框和标题组件
154 | require('echarts/lib/component/tooltip');
155 | require('echarts/lib/component/title');
156 |
157 | // 基于准备好的dom,初始化echarts实例
158 | var myChart = echarts.init(document.getElementById('main'));
159 | // 绘制图表
160 | myChart.setOption({
161 | title: { text: 'ECharts 入门示例' },
162 | tooltip: {},
163 | xAxis: {
164 | data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
165 | },
166 | yAxis: {},
167 | series: [{
168 | name: '销量',
169 | type: 'bar',
170 | data: [5, 20, 36, 10, 10, 20]
171 | }]
172 | });
173 | ```
174 | ## 2.4 EChart 3非模块化引入
175 | 同2.2类似
176 |
177 | ```html
178 |
179 | ```
180 |
181 | # 3.异步数据加载与更新
182 | 由于地图模块分辨率变高,为了不增大源码的体积,地图模块采用按照需要下载引入
183 | 在[地图下载页面](http://echarts.baidu.com/download-map.html),下载需要的世界地图/中国地图/中国分省地图,下载后的格式有js和json两种。
184 | 对应js格式的,引入的方式是通过script标签
185 |
186 | ```html
187 |
188 |
189 |
198 | ```
199 | 通过JSON格式引入就可以实现异步数据加载与更新
200 |
201 | ```javascript
202 | $.get('map/json/china.json', function (chinaJson) {
203 | echarts.registerMap('china', chinaJson);
204 | var chart = echarts.init(document.getElementById('main'));
205 | chart.setOption({
206 | series: [{
207 | type: 'map',
208 | map: 'china'
209 | }]
210 | });
211 | });
212 | ```
213 |
214 | # 4.升级总结
215 | ## 4.1 配置变化举例
216 |
217 | | EChart 2 | EChart 3 |
218 | | ------------- |:-------------:|
219 | | option.series.mapLocation | 删去,使用left,top,bottom,right定义位置|
220 | | option.series.textFixed | 删去地区的名称文本位置修正 |
221 | |dataRange颜色标识属性(示例4.1-1)|visualMap|
222 | |单个echarts 实例中最多只能存在一个 grid 组件|ECharts 3 中可以存在任意个 grid 组件
223 | 一个网格中(示例4.1-2)|
224 | | addData , setSeries 方法设置配置项|统一使用setOption(示例4.1-3)|
225 | |级联this.myChart = ec.init(dom).showLoading({effect:'bubble'}).hideLoading();|不支持|
226 | | myChart.component.tooltip.showTip 这种形式调用相应的接口触发图表行为|dispatchAction(示例4.1-4)|
227 | 示例4.1-1
228 |
229 | ```javascript
230 | dataRange: {
231 | realtime: false,
232 | itemHeight: 80,
233 | splitNumber:6,
234 | borderWidth:1,
235 | textStyle: { color: '#333333' },
236 | text: ['高', '低'],
237 | calculable: true
238 | },
239 | //=======================================================
240 | visualMap: {
241 | min: 0,
242 | max: 1000000,
243 | text: ['High', 'Low'],
244 | realtime: false,
245 | calculable: true,
246 | inRange: {
247 | color: ['lightskyblue', 'yellow', 'orangered']
248 | }
249 | },
250 | ```
251 | 示例4.1-2
252 | 图略,官网例子:http://echarts.baidu.com/gallery/editor.html?c=scatter-anscombe-quartet
253 | 部分配置属性变化,需要修改
254 |
255 | 示例4.1-3
256 |
257 | ```javascript
258 | myChart.setOption({
259 | visualMap: {
260 | inRange: {
261 | color: ...
262 | }
263 | }
264 | })//注意最后一定要再次setOption(option);option是配置对象
265 | ```
266 | 示例4.1-4
267 |
268 | ```javascript
269 | myChart.on('brushselected', renderBrushed);
270 | setTimeout(function() {
271 | self.myChart.dispatchAction({
272 | type: 'brush',
273 | areas: [{
274 | geoIndex: 0,
275 | brushType: 'polygon',
276 | coordRange: [
277 | [119.72, 34.85],
278 | [117.05, 34.06],
279 | [117.49, 33.75],
280 | [123.16, 29.92],
281 | [121.64, 34.08]
282 | ]
283 | }]
284 | });
285 | }, 0);
286 |
287 |
288 | function renderBrushed(params) { //... ...
289 | }
290 | ```
291 |
292 | ## 4.2 第2部分的模块与非模块更改时候需要注意
293 | ## 4.3 地图模块
294 | EChart 2:
295 |
296 | ```javascript
297 | chart.setOption({
298 | series: [{
299 | type: 'map',
300 | map: 'china'//'world'
301 | }]
302 | });
303 | ```
304 | EChart 3,需要下载地图,使用方式见第3部分。
305 |
--------------------------------------------------------------------------------
/src/openlayers 3扩展,调用百度地图、高德地图、天地图服务.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: openlayers 3扩展,调用百度地图、高德地图、天地图服务
3 | tags:
4 | - OpenLayers 3
5 | - 地图
6 | - WebGIS
7 | categories: WebGIS
8 | date: 2017-03-28 00:00:00
9 | ---
10 | 调用这三个商业地图服务,我们使用的都是切片(Tile)地图服务,关于切片地图的含义这里做简单的介绍:
11 | 切片地图就是指将显示的地图切成一块一块的(256 * 256)分别显示加载。openlayers 3中有这样图层加载类,`ol.layer.Tile`,对应的source类有`ol.source.TileImage`,`ol.source.XYZ`,这两者的关系通过源码可以看到
12 | `ol.inherits(ol.source.XYZ, ol.source.TileImage);`,`ol.source.TileImage`是父类。
13 |
14 |
15 | 对于天地图,我们访问[天地图](http://map.tianditu.com/map/index.html)地图主页服务,打开控制台->`Network`,我们可以看到请求的一些地址如下:
16 |
17 | ```
18 | http://t2.tianditu.com/DataServer?T=vec_w&x=53&y=24&l=6'
19 | ```
20 | 其中重要的信息是x,y,z分别表示x坐标,y坐标和zoomLevel,
21 |
22 | 其实在openlayers 3源码中有Bing地图和OSM地图的扩展了,我们可以仿照它们进行一些扩展。
23 |
24 | ## 1.扩展天地图
25 |
26 | 源码使用模块化打包
27 |
28 | ```javascript
29 | var ol = require('openlayers');
30 |
31 | ol.source.TianMap = function(options){
32 | var options = options ? options : {};
33 | var attributions;
34 | if(options.attributions !== undefined){
35 | attributions = option.attributions;
36 | }else{
37 | attributions = [ol.source.BaiduMap.ATTRIBUTION];
38 | }
39 |
40 | var url;
41 | if(options.mapType == "sat"){
42 | url = "http://t{0-4}.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}";
43 | }else if(options.mapType == "satLabel"){
44 | url = "http://t{0-4}.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}";
45 | }else if(options.mapType == "label"){
46 | url = "http://t{0-4}.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}";
47 | }else{
48 | url = "http://t{0-4}.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}";
49 | }
50 |
51 | ol.source.XYZ.call(this, {
52 | attributions: attributions,
53 | projection: ol.proj.get('EPSG:3857'),
54 | cacheSize: options.cacheSize,
55 | crossOrigin: 'anonymous',
56 | opaque: options.opaque !== undefined ? options.opaque : true,
57 | maxZoom: options.maxZoom !== undefined ? options.maxZoom : 19,
58 | reprojectionErrorThreshold: options.reprojectionErrorThreshold,
59 | tileLoadFunction: options.tileLoadFunction,
60 | url: url,
61 | wrapX: options.wrapX
62 | });
63 | }
64 | ol.inherits(ol.source.TianMap, ol.source.XYZ);
65 |
66 | ol.source.TianMap.ATTRIBUTION = new ol.Attribution({
67 | html: '© ' +
69 | '天地图'
70 | });
71 | module.exports = ol.source.TianMap;
72 | ```
73 | 使用方法
74 |
75 | ```javascript
76 | var tianMapSat = new ol.layer.Tile({
77 | title: "天地图卫星",
78 | source: new ol.source.TianMap({mapType:"sat"})
79 | });
80 | map.addLayer(tianMapSat);
81 | ```
82 | ## 2. 扩展百度地图
83 | 百度地图坐标进行了加偏,所以需要使用`projzh`转化
84 | 百度地图使用的是定制化的墨卡托投影和BD-09 datum,所以将WGS-84坐标转化为百度坐标需要两步
85 | first transform from WGS-84 to BD-09 (which itself uses the GCJ-09 transform), and then do the forward transform to Baidu Mercator
86 | 第一步是将WGS-84 转化为 BD-09,然后转化为百度墨卡托
87 | ```
88 | baiduMercator.forward(bd09.fromWGS84(point))
89 | ```
90 | 反过来的转化为
91 | ```
92 | bd09.toWGS84(baiduMercator.inverse(point))
93 | ```
94 |
95 | > https://github.com/tschaub/projzh
96 |
97 | ```javascript
98 | var ol = require('openlayers');
99 | var projzh = require('projzh');
100 | /* projzh处理百度坐标的问题,算法基于proj4m project
101 | * https://www.versioneye.com/nodejs/projzh/0.5.0
102 | * https://github.com/tschaub/projzh
103 | */
104 | ol.source.BaiduMap = function(options){
105 | var options = options ? options : {};
106 |
107 | var attributions;
108 | if(options.attributions !== undefined){
109 | attributions = option.attributions;
110 | }else{
111 | attributions = [ol.source.BaiduMap.ATTRIBUTION];
112 | }
113 |
114 | var extent = [72.004, 0.8293, 137.8347, 55.8271];
115 |
116 | //定义百度坐标
117 | //地址:https://github.com/openlayers/openlayers/issues/3522
118 | var baiduMercator = new ol.proj.Projection({
119 | code: 'baidu',
120 | extent: ol.extent.applyTransform(extent, projzh.ll2bmerc),
121 | units: 'm'
122 | });
123 |
124 | ol.proj.addProjection(baiduMercator);
125 | ol.proj.addCoordinateTransforms('EPSG:4326', baiduMercator, projzh.ll2bmerc, projzh.bmerc2ll);
126 | ol.proj.addCoordinateTransforms('EPSG:3857', baiduMercator, projzh.smerc2bmerc, projzh.bmerc2smerc);
127 |
128 |
129 | var resolutions = [];
130 | for(var i=0; i<19; i++){
131 | resolutions[i] = Math.pow(2, 18-i);
132 | }
133 | var tilegrid = new ol.tilegrid.TileGrid({
134 | origin: [0,0],
135 | resolutions: resolutions,
136 | extent: ol.extent.applyTransform(extent, projzh.ll2bmerc),
137 | tileSize: [256, 256]
138 | });
139 | var satUrls = [0, 1, 2, 3, 4].map(function(sub) {
140 | return 'http://shangetu' + sub +
141 | '.map.bdimg.com/it/u=x={x};y={y};z={z};v=009;type=sate&fm=46&udt=20150601';
142 | });
143 | var urls = [0, 1, 2, 3, 4].map(function(sub) {
144 | return 'http://online' + sub +
145 | '.map.bdimg.com/onlinelabel/qt=tile&x={x}&y={y}&z={z}&v=009&styles=pl&udt=20170301&scaler=1&p=1';
146 | });
147 | ol.source.TileImage.call(this, {
148 | crossOrigin: 'anonymous', //跨域
149 | cacheSize: options.cacheSize,
150 | // projection: ol.proj.get('EPSG:3857'),
151 | projection:'baidu',
152 | tileGrid: tilegrid,
153 | tileUrlFunction: function(tileCoord, pixelRatio, proj){
154 | if(!tileCoord) return "";
155 |
156 | var z = tileCoord[0];
157 | var x = tileCoord[1];
158 | var y = tileCoord[2];
159 | var hash = (x << z) + y;
160 | var index = hash % urls.length;
161 | index = index < 0 ? index + urls.length : index;
162 | if(options.mapType == "sat"){
163 | return satUrls[index].replace('{x}', x).replace('{y}', y).replace('{z}', z);
164 | }
165 | return urls[index].replace('{x}', x).replace('{y}', y).replace('{z}', z);
166 |
167 | },
168 | wrapX: options.wrapX !== undefined ? options.wrapX : true
169 |
170 | });
171 | }
172 |
173 | ol.inherits(ol.source.BaiduMap,ol.source.TileImage);
174 |
175 | ol.source.BaiduMap.ATTRIBUTION = new ol.Attribution({
176 | html: '© ' +
178 | '百度地图'
179 | });
180 |
181 | module.exports = ol.source.BaiduMap;
182 | ```
183 | 调用
184 | ```javascript
185 | var baiduMapSat = new ol.layer.Tile({
186 | title: "百度地图卫星",
187 | source: new ol.source.BaiduMap({mapType:"sat"})
188 | });
189 | map.addLayer(baiduMapSat);
190 | ```
191 | ## 3. 扩展高德地图
192 |
193 | ```javascript
194 | var ol = require('openlayers');
195 |
196 | ol.source.AMap = function(options){
197 | var options = options ? options : {};
198 |
199 | var attributions;
200 | if(options.attributions !== undefined){
201 | attributions = option.attributions;
202 | }else{
203 | attributions = [ol.source.AMap.ATTRIBUTION];
204 | }
205 |
206 | var url;
207 | if(options.mapType == "sat"){
208 | url ="http://webst0{1-4}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}";
209 | }else{
210 | url = "http://webrd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}";
211 | }
212 |
213 | ol.source.XYZ.call(this, {
214 | crossOrigin: 'anonymous', //跨域
215 | cacheSize: options.cacheSize,
216 | projection: ol.proj.get('EPSG:3857'),
217 | // urls:urls,
218 | url:url,
219 | wrapX: options.wrapX !== undefined ? options.wrapX : true
220 |
221 | });
222 |
223 | }
224 |
225 | ol.inherits(ol.source.AMap,ol.source.XYZ);
226 |
227 |
228 | ol.source.AMap.ATTRIBUTION = new ol.Attribution({
229 | html: '© ' +
231 | '高德地图'
232 | });
233 |
234 | module.exports = ol.source.AMap;
235 | ```
236 | 调用
237 | ```javascript
238 | var aMapSat = new ol.layer.Tile({
239 | title: "高德地图卫星",
240 | source: new ol.source.AMap({mapType:"sat"})
241 | });
242 | map.addLayer(aMapSat);
243 | ```
244 |
245 | 最后推荐一个[github仓库](https://github.com/zrysmt/openlayers3-react),Openlayers 3 使用React 组件化+wepack+ES6实践,
246 | 包括扩展在其中的具体使用方法
247 | > https://github.com/zrysmt/openlayers3-react
248 |
249 | # 参考阅读
250 | - [openlayers github](https://github.com/openlayers/openlayers)
251 | - [openlayers github Issues](https://github.com/openlayers/openlayers/issues)
252 | - [openlayers 官方地址](https://openlayers.org/en/latest/apidoc/)
253 | - [Openlayers 3 使用React 组件化+wepack+ES6实践记录笔记](http://blog.csdn.net/future_todo/article/details/61206783)
254 | - [OpenLayers 3 之 加载百度地图](http://blog.csdn.net/qingyafan/article/details/49403989)
255 | - [OpenLayers 3 之 加载天地图](http://blog.csdn.net/qingyafan/article/details/49565245)
--------------------------------------------------------------------------------
/src/动手DIY一个underscorejs库及underscorejs源码分析2.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: 动手DIY一个underscorejs库及underscorejs源码分析2
3 | tags:
4 | - FE
5 | - underscorejs
6 | - 源码
7 | - js原生实现库
8 | categories: 前端技术
9 | date: 2016-10-26 00:00:00
10 | ---
11 |
12 | 接着第一篇《动手DIY一个underscorejs库及underscorejs源码分析1》
13 |
14 | > 所有代码挂在我的[github](https://github.com/zrysmt/DIY-underscorejs)上。
15 |
16 | # 1.兼容requirejs和seajs模块化
17 | - requirejs
18 | 在代码的尾部加上
19 |
20 | ```javascript
21 | if (typeof define == 'function' && define.amd) {
22 | //定义一个模块并且起个名字
23 | define('_underscore', [], function() {
24 | return _;
25 | });
26 | }
27 | ```
28 | 使用测试:[代码请点我](https://github.com/zrysmt/DIY-underscorejs/tree/master/demo)
29 | demo3.html
30 |
31 | ```html
32 |
33 |
34 |
35 | ```
36 | demo3.js
37 | ```javascript
38 | define(function(require) {
39 | require(['../DIY/2/_underscore'], function() {
40 | console.log(_);
41 | });
42 | });
43 | ```
44 | - 加上支持seajs的代码
45 |
46 | ```javascript
47 | if (typeof define == 'function' && define.amd) {
48 | define('_underscore', [], function() {
49 | return _;
50 | });
51 | } else if (typeof define == 'function' && define.cmd) { //seajs
52 | define(function(require, exports, module) {
53 | module.exports = _;
54 | });
55 | }
56 | ```
57 | 使用:
58 | demo2.html
59 |
60 | ```javascript
61 |
62 |
65 | ```
66 | demo2.js
67 |
68 | ```javascript
69 | define(function(require, exports, module) {
70 | var _ = require('../DIY/2/_underscore');
71 | console.info(_);
72 | });
73 | ```
74 | # 2.支持nodejs
75 |
76 | ```javascript
77 | root._ = _;
78 | ```
79 | 修改为:
80 |
81 | ```javascript
82 | if (typeof exports != 'undefined' && !exports.nodeType) {
83 | if (typeof module != 'undefined' && !module.nodeType && module.exports) {
84 | exports = module.exports = _;
85 | }
86 | exports._ = _;
87 | } else {
88 | root._ = _;
89 | }
90 | ```
91 | # 3.`_.extend`
92 |
93 | 使用:
94 |
95 | ```javascript
96 | console.log(_.extend({name: 'moe'}, {age: 50}));
97 | //结果Object {name: "moe", age: 50}
98 | ```
99 |
100 | ```javascript
101 | //类似与_.keys
102 | _.allKeys = function(obj) {
103 | if (!_.isObject(obj)) return [];
104 | var keys = [];
105 | for (var key in obj) keys.push(key);
106 | // Ahem, IE < 9.
107 | // if (hasEnumBug) collectNonEnumProps(obj, keys);
108 | return keys;
109 | };
110 | ```
111 | 主函数:
112 |
113 | ```javascript
114 | var createAssigner = function(keysFunc, defaults) {
115 | return function(obj) {
116 | var length = arguments.length;
117 | if (defaults) obj = Object(obj);
118 | if (length < 2 || obj == null) return obj;
119 | for (var index = 1; index < length; index++) {
120 | var source = arguments[index],
121 | keys = keysFunc(source),
122 | l = keys.length;
123 | for (var i = 0; i < l; i++) {
124 | var key = keys[i];
125 | if (!defaults || obj[key] === void 0) obj[key] = source[key];
126 | //将参数(对象)放入到obj组合到一起
127 | }
128 | }
129 | return obj;
130 | };
131 | };
132 | _.extend = createAssigner(_.allKeys);
133 | _.extendOwn = _.assign = createAssigner(_.keys);
134 | ```
135 | # 4.重要内部函数`cb`
136 |
137 | ```javascript
138 | var builtinIteratee;
139 | //如果是函数则返回上面说到的回调函数;
140 | //如果是对象则返回一个能判断对象是否相等的函数;
141 | //默认返回一个获取对象属性的函数
142 | var cb = function(value, context, argCount) {
143 | if (_.iteratee !== builtinIteratee) return _.iteratee(value, context);
144 | if (value == null) return _.identity; //默认的迭代器
145 | if (_.isFunction(value)) return optimizeCb(value, context, argCount);
146 | if (_.isObject(value)) return _.matcher(value);
147 | return _.property(value);
148 | };
149 | _.iteratee = builtinIteratee = function(value, context) {
150 | return cb(value, context, Infinity);
151 | };
152 | ```
153 | ## 4.1 `_.identity`
154 | 很简单但是是默认的迭代器
155 | ```javascript
156 | _.identity = function(value) {
157 | return value;
158 | };
159 | ```
160 | 测试很简单
161 | ```javascript
162 | var obj1 = {name:'zry'};
163 | console.log(obj1 === _.identity(obj1));//true
164 | ```
165 | ## 4.2 `_.matcher`
166 | ```javascript
167 | _.matcher = _.matches = function(attrs) {
168 | attrs = _.extendOwn({}, attrs);
169 | return function(obj) {
170 | return _.isMatch(obj, attrs);
171 | };
172 | };
173 | //两个对象是不是全等于。给定的对象是否匹配attrs指定键/值属性
174 | _.isMatch = function(object, attrs) {
175 | var keys = _.keys(attrs),
176 | length = keys.length;
177 | if (object == null) return !length;
178 | var obj = Object(object);
179 | for (var i = 0; i < length; i++) {
180 | var key = keys[i];
181 | if (attrs[key] !== obj[key] || !(key in obj)) return false;
182 | }
183 | return true;
184 |
185 | };
186 | ```
187 | 测试:
188 |
189 | ```javascript
190 | var obj2 = {selected: true, visible: true};
191 | var ready = _.isMatch(obj2,{selected: true, visible: true});
192 | //返回一个断言函数,这个函数会给你一个断言 可以用来辨别
193 | //给定的对象是否匹配attrs指定键/值属性
194 | console.log(ready);//true
195 | ```
196 | ## 4.3 `_.property`
197 | property函数在第一篇博客中已经实现
198 | ```javascript
199 | _.property = property;
200 | ```
201 | # 5.`_.map`
202 | ```javascript
203 | _.map = _.collect = function(obj, iteratee, context) {
204 | iteratee = cb(iteratee, context);
205 | var keys = !isArrayLike(obj) && _.keys(obj),
206 | length = (keys || obj).length,
207 | results = Array(length);
208 | for (var index = 0; index < length; index++) {
209 | var currentKey = keys ? keys[index] : index;
210 | results[index] = iteratee(obj[currentKey], currentKey, obj);
211 | //返回的是(value,key,obj)
212 | }
213 | return results;
214 | };
215 | ```
216 | # 6.`_.filter`
217 |
218 | ```javascript
219 | _.filter = _.select = function(obj, predicate, context) {
220 | var results = [];
221 | predicate = cb(predicate, context);
222 | _.each(obj, function(value, index, list) {
223 | if (predicate(value, index, list)) results.push(value);
224 | });
225 | return results;
226 | };
227 | ```
228 | 测试:
229 | ```javascript
230 | var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });//[2,4,6]
231 | ```
232 | # 7.两个常用的工具函数`_.escape`,_.unescape`
233 | ## 7.1 `_.escape`
234 | 要过滤的字符串
235 | ```javascript
236 | var escapeMap = {
237 | '&': '&',
238 | '<': '<',
239 | '>': '>',
240 | '"': '"',
241 | "'": ''',
242 | '`': '`'
243 | };
244 | ```
245 | 主函数
246 | ```javascript
247 | var createEscaper = function(map) {
248 | var escaper = function(match) {//match 匹配的子串
249 | return map[match];
250 | };
251 | var source = '(?:' + _.keys(map).join('|') + ')';
252 | var testRegexp = RegExp(source);
253 | var replaceRegexp = RegExp(source, 'g');
254 | return function(string) {
255 | string = string == null ? '' : '' + string;
256 | return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
257 | };
258 | };
259 | ```
260 | 注意值了的`string.replace`函数第二个参数是个函数,那么返回的数据第一个是match(匹配的子串)
261 |
262 | | 变量名 | 代表的值 |
263 | |---------|:------------:|
264 | | match | 匹配的子串。(对应于上述的$&。) |
265 | |p1,p2, ...| 假如replace()方法的第一个参数是一个`RegExp`对象,则代表第n个括号匹配的字符串。(对应于上述的$1,$2等。) |
266 | | offset| 匹配到的子字符串在原字符串中的偏移量。(比如,如果原字符串是“abcd”,匹配到的子字符串时“bc”,那么这个参数将是1) |
267 | | string | 被匹配的原字符串。 |
268 | ```javascript
269 | _.escape = createEscaper(escapeMap);
270 | ```
271 | 测试:
272 | ```javascript
273 | console.log(_.escape('Curly, Larry & Moe')//Curly, Larry & Moe
274 | ```
275 | ## 7.2 `_.unescape`
276 | 反转要过滤的字符串
277 | ```javascript
278 | _.invert = function(obj) {
279 | var result = {};
280 | var keys = _.keys(obj);
281 | for (var i = 0, length = keys.length; i < length; i++) {
282 | result[obj[keys[i]]] = keys[i];
283 | }
284 | return result;
285 | };
286 | var unescapeMap = _.invert(escapeMap);
287 | _.unescape = createEscaper(unescapeMap);
288 | ```
289 | 测试:
290 | ```javascript
291 | console.log(_.unescape('Curly, Larry & Moe'));//Curly, Larry & Moe
292 | ```
293 |
294 |
295 | **参考阅读:**
296 | - [http://underscorejs.org/](http://underscorejs.org/)
297 | - [underscorejs中文:http://www.bootcss.com/p/underscore/](http://www.bootcss.com/p/underscore/)
298 | - [UnderscoreJS精巧而强大工具包](http://blog.fens.me/nodejs-underscore/)
299 | - [JS高手进阶之路:underscore源码经典](http://www.imooc.com/article/1566)
--------------------------------------------------------------------------------