to my friend 小项目总结

写在最前面:
一直想找个云服务器玩一玩。一些日子前下定决心买一个试试。一顿折腾后发现了新大陆,架了VPN,突然想到,放个页面到云上也不错。

选择哪家云

国内阿里云很稳定,但是因为墙和价格,最终放弃。国外最先选中了AWS EC2,AWS一上来就让绑定信用卡,听说不少人被恶意消费掉了很多钱,因此又作废。DigitalOcean和LiNode最终选择了前者,送了10美刀,开了2个服务器,一个在SFC,一个在新加坡。新加坡连公司速度还行,服务器上访问主流网站简直是光速,之前每天大约会断4,5次,最近貌似好了。吐槽一句,家里用的是宽带通,访问服务器,说多了都是泪。未来很有可能尝试liNode.(后续添加),liNode不适合自己。

选择哪个操作系统

ubuntu16.0.4 我的地盘听我的。

架设VPN

1:官方开启PPTP
2:mac vpn
想抽自己2巴掌,刚写的重启服务器后自动启动PPTP教程遗失了。

写个前端页面

前端页面用到的技术栈

UI: React + ReactDOM
路由:React-router
数据管理 : Redux + Immutable
脚手架工具 : npm + webpack
其他通用工具:babel + eslint + ReduxDevTool + ReactDevTool
异步: fetch + promise

前端架构

写个简单页面可以用不到上面的技术,但是作为一个前端,接受组件化思想后,写出来的页面要可维护,好扩展。
页面架构图
page :每一个页面即为一个page
container:容器组件,Redux写在container里,管理多个component
component:展示组件

经过博文的提点,我们认为一个container就是一个container是错误的。项目中发现,页面比较复杂是,container变得巨大无比,缺乏维护性。不如按逻辑拆成多个container,每个container dispatch事件和数据,container之间通过redux通信。componet即为展示组件。个人认为,在不断细拆分组件和保持保持一定的组件杂糅之间折中,是一门艺术。

接口设计

按照RESTful设计规范,使用fetch和promise解决异步。目前用不到身份验证和异常处理,因此这一部分处理的很简单。

后台设计

重头戏来了,之前完全不了解后台,摸索了2个礼拜后,居然写出了个小后台。

后端用到的技术栈

服务器:koa koa-server
数据库:mongo
异步:generator + promise
爬虫:superagent + cheerio

数据库

1:数据库设计
想法很简单,爬百度贴吧数据,保留四个字段:

title :帖子名
star : 被跟帖数量
link : 帖子的url链接
date : 最后回帖时间

数据没什么价值,仅当练习。
2:mongo数据库的增删改查
自己写了个简单的驱动,先截断仅仅是满足了需求而已

var MongoClient = require('mongodb').MongoClient;
// Connection URL
var url = 'mongodb://localhost:27017/reptile';

var insertDocuments = function (db, connectionName, data, callback) {
  var collection = db.collection(connectionName);
  collection.insertMany(data, function (err, result) {
    callback(result);
  });
};

var findDocuments = function (db, callback) {
  var collection = db.collection('baidutieba');
  collection.find({}).toArray(function (err, docs) {
    callback(docs);
  });
};

var removeDocument = function (db, callback) {
  var collection = db.collection('video');
  collection.remove({}, function (err, result) {
    callback(result);
  });
};

var updateDocument = function (db, callback) {
  var collection = db.collection('video');
  collection.updateOne({a: 2}
    , {$set: {b: 1}}, function (err, result) {
      callback(result);
    });
};

var dropDocument = function (db, callback) {
  var collection = db.collection('video');
  collection.drop(null, function () {
    console.log('drop video');
  });
};

var mongoDriver = {
  koaConnection: function (callback) {
    return MongoClient.connect(url, function (err, db) {
      assert.equal(null, err);
      findDocuments(db, function (data) {
        callback(data);
        db.close();
      });
    });
  },

  writeToConnection: function (connectionName, data, callback) {
    return MongoClient.connect(url, function (err, db) {
      assert.equal(null, err);
      insertDocuments(db, connectionName, data, function () {
        callback();
        db.close();
      });
    });
  }
};

module.exports = mongoDriver;
爬虫

基本思路:用superagent爬取数据,用cheerio清洗数据,用上面main的驱动写到数据库里。

var superagent = require('superagent');
var charset = require('superagent-charset');
var cheerio = require('cheerio');
var async = require('async');

var fs = require('fs');
var request = require("request");
var result = [];
var pageUrl = [];

charset(superagent);

var mongoDriver = require('./server/mongodbApp');

pageUrl.push('http://tieba.baidu.com/f?kw=%BA%A3%D4%F4%CD%F5&fr=ala0&tpl=5');

function start() {
  pageUrl.forEach((url, index) => {
    superagent.get(url).end((err, res) => {
      console.log(url);
      if (err) {
        console.log('error');
      } else if (res) {
        var $ = cheerio.load(res.text, {decodeEntities: false});
        var contentList = $('body .j_thread_list');

        console.log(contentList.length);
        for (var i = 0; i < contentList.length; i++) {
          let obj = {
            star: 0,
            title: '',
            url: '',
            date: ''
          };

          var $liContent = cheerio.load(contentList[i], {decodeEntities: false});

          obj.star = $liContent('.threadlist_rep_num').html();
          obj.title = $liContent('.threadlist_title>a').html();
          obj.url = 'tieba.baidu.com' + $liContent('.threadlist_title > a').attr('href');
          //百度里是最后的回复时间
          if (!$liContent('.threadlist_reply_date').html()) {
            obj.date = null;
          } else {
            obj.date = $liContent('.threadlist_reply_date').html().match(/\d\d:\d\d/)[0];
          }
          result.push(obj);
        }
        console.log(result);

        mongoDriver.writeToConnection('baidutieba', result, function () {
          console.log('write to baidutieba success');
        });
      }
    });
  });
}

start();

在爬另一个编码为gb2312网页时中文显示为乱码。
我的解决方法

服务器

逼着自己放弃express,投入koa怀抱。

var koa = require('koa');
var router = require('koa-router')();
var cors = require('koa-cors');
var mongoDriver = require('./mongodbApp');
var app = new koa();
//一键搞定跨域
app.use(cors());
router.get('/video', function*(next) {
    this.body = yield new Promise(function (resolve, reject) {
      mongoDriver.koaConnection(function (data) {
        resolve(data);
      });
    }).then(function (data) {
      return data;
    });
  });
app.use(router.routes()).use(router.allowedMethods());
app.listen(3000, () => {
    console.log('koa start!');
});

最终效果:

补充:服务器端部署

没想到部署到服务器上也够我喝上一壶。遇到问题有3个:
1:如何本地写好代码后,一键部署到服务器上。现在还不知道,靠手工scp
2:服务器上npm install 报killed错误。因为512M内存不够用。使用了swap。
3:npm run build后,我的电脑可以打开,其他电脑不能打开。经过分析,是redux-dev-tool问题。通过环境变量一顿折腾后解决问题。

再补充

仿照阿里的rc组件库,手写了个乞丐版本的分页组件,同时写好了分页接口。but,发现自己不会写数据库分页查询。网上找到的绝大多教程都是node-mongose,于是想了个蠢方法,让接口看起来支持分页查询。。。。

最终效果:

后记:

至此,前后端打通。自我膨胀一波。接下来需要改进的地方:
1:理解generator。服务器代码里的generator函数,是我试了一个晚上试出来的,到现在我还没搞懂为什么是这样的。为此,我显示回味了一遍generator函数语法逻辑,然后看了一眼《深入浅出NodeJS》里的异步章节,还是搞不懂,于是又看了一眼koa-router源码,koa源码,co源码,手动实现了一遍基础版co。虽然猪坚强,但是还是没搞懂。

2:改进driver,现在的driver只能说能用,回调嵌套回调,想改写成promise方式,或者未来熟悉了generator,用generator也说不定。

3:贴啊只是练手,接下来去扒一扒另一个网站,送给朋友们。

transform bug

#transform有毒
transform : translate(1px, 1px)有毒,translate会导致z-index混乱,stackoverflow上有大神解析了原因:z-index is canceled by setting transform(rotate),奈何等级不够无法理解,不知道怎么去处理这个问题。那就只能绕过这个问题:实际项目中的需求是鼠标hover上去x轴上平移-2个像素,完全可以用margin去替代transform:

1
2
3
4
5
6
7
element{
transition : margin 1s linear;
margin : 0 ;
}
element:hover{
margin : 0 0 0 -2px;
}

es6 promise && fetch

初次看阮一峰写的es6 promise和MDN文档里写的promise总有点云里雾里的感觉,一方面是自己心浮气躁,更多的是自己火候没到。自己看了个总结很好的es6 promise总结谈谈 ES6 的 Promise 对象
Talk is cheap, show me the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function testPromise(src) {
return new Promise((resolve, reject) => {
if (src === 'hello') {
resolve(src);
}
else {
reject(src);
}
});
}

testPromise('hello world').then((src)=> {
console.log(src);
}, (src)=> {
console.log(src);
});

promise对象有三种状态:pendding,fulfilled和rejected状态。初始化创建一个promise对象,其状态为pendding,promise对象的参数是一个函数,该函数有2个参数,第一个是resolve,第二个是reject。这2个参数都是函数。调用resolve函数,会将pendding状态变成fulfilled状态,调用rejected函数会变成rejected状态。如果是fulfilled,则调用then的第一个函数参数,rejected调用then的第二个函数参数。then方法返回一个新的promise对象(此时新的对象为pendding),一路链式调用then下去。
attention :

1
2
3
then(resolve).catch(reject);
等价于
then.(resolve).then(null, reject);

工程中,异步调用通常会在请求后台API接口。在想去,一招jQuery.ajax+回调函数吃遍所有接口。现在featch是个更好的选择。
BOM window提供了fetch接口,返回一个promise对象,nice,可以和promise组合使用了。

为什么要用fetch取代XMLHttpRequest
featch(url,option)
原始的featch写法:

1
2
3
4
5
6
7
8
9
10
11
12
//原始config
url = 'www.baidu.com';
options = {
method : 'post',
headers : {
'Content-Type' :'application/json',
'Authorization' : `JWT ${token}`,
'Acception' : 'application/json'
},
body:json.stringfy(payload)
}
fetch(url, options).then();

fetch还有request,header,response对象,但是我不喜欢这些对象,层层用类抽象,最终等价于url和options参数。不如后者来的简单直接。

现在fetch还不支持全系IE浏览器,chrome从42版本开始,safari从10开始。脊梁吓出了一身冷汗,现在mofa后端用的是fetch。还好用了pollyfill :whatwg-fetch.

Immutable总结

###immutable基本用法
immutable解决了JS没有不可变对象问题。不知道谁说过,可变对象是万恶之源。可见Immutable的伟大。虽然现在掩盖在React的光芒下,但是,看看吧,是金子总会发光的。从API文档里可以看出作者的努力,JS里常见的数据结构和方法都应有尽有。有种感觉,immutable可以替代js的Array和Object对象。
自己做了一些小测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
/**
* Created by pingfengafei on 16/8/29.
*/
import Immutable from 'immutable';
{
let map1 = Immutable.Map({a: 1, b: 2, c: 3});
let map5 = Immutable.Map({a: 1, b: 2, c: 3});

let map2 = map1.set('b', 2);
let map3 = map1;
let map4 = map1.set('b', 20);

console.log(map2 === map1); //true
console.log(map3 === map1); //true
console.log(map4 === map1); //false

console.log(map1 === map5); //false
console.log(Immutable.is(map1, map5)); //true
}

{
let map1 = Immutable.fromJS({a: 1, b: 2, c: 3});
let map5 = Immutable.fromJS({a: 1, b: 2, c: 3});

let map2 = map1.set('b', 2);
let map3 = map1;
let map4 = map1.set('b', 20);

console.log(map2 === map1); //true
console.log(map3 === map1); //true
console.log(map4 === map1); //false

console.log(map1 === map5); //false
console.log(Immutable.is(map1, map5)); //true
}

{
//用fromJS替换Map和List
let map1 = Immutable.fromJS([{a: 1, b: 2, c: 3}]);
let map2 = Immutable.List([{a: 1, b: 2, c: 3}]);
let map3 = Immutable.fromJS({a: 1, b: 2, c: 3});
let map4 = Immutable.Map({a: 1, b: 2, c: 3});

console.log(map1);
console.log(map2);
console.log(map3);
console.log(map4);
}

//修改Map(Object)对象
{
let map = Immutable.fromJS({a: 1, b: 2, c: 3});
let ma1 = Immutable.fromJS([{a: 1, b: 2, c: 3}]);

//查
console.log(map.get('a')); //1
console.log(map.get('d')); //undefined
//改
console.log(map.set('a', 4)); //new Map with a : 4
//增
console.log(map.set('d', 5)); //new Map with d :5
//删
console.log(map.delete('d', 5)); // new Map without d:5
}

//修改List(Array)对象
{
let list = Immutable.fromJS([1, 2, {a: 'aaaaaaaa'}]);

console.log(list.size);
list.forEach((val, index)=> {
list[index] = 'aaa';
});
console.log(list);
}

个人的小总结:
1:通常只用到Map和List,对应Object和Array
2:用fromJS替换Map和List
3:用toJS方法将Map或者List对象转换成Object或Array对象
4:immutable.is()比较2个immutable对象数值相等效率特别特别高
5:利用4,在用react性能优化的大杀器:shouldComponentUpdate时候,通过(immutable.is(nextPrps, this.props))能极大的提高性能。
6:凡事都有双刃剑,使用5,会使得使用chrome react调试工具调试变得苦难,因为immutable对象不已阅读,从props和state里判断数据变得异常困难。

最后测试一下immutable的效率:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function testEfficiency() {
var a = [];
var b = [];
console.time('创建数组');
for (var i = 0; i <= 1000000; i++) {
a.push(i);
b.push(i);
}
console.timeEnd('创建数组');


console.time('List');
var $$b = Immutable.List(b);
console.timeEnd('List');

console.time('fromJS');
var $$a = Immutable.fromJS(a);
console.timeEnd('fromJS');

console.time('is比较');
Immutable.is($$a, $$b);
console.timeEnd('is比较');

console.time('lodash比较');
_.isEqual($$a, $$b);
console.timeEnd('lodash比较');

var $$c = $$b.shift();

console.time('immutable比较');
_.isEqual($$c, $$b);
console.timeEnd('immutable比较');

console.time('lodash比较');
_.isEqual(a, b);
console.timeEnd('lodash比较');

console.time('is比较');
Immutable.is(a, b);
console.timeEnd('is比较');

}
testEfficiency();

结论:
1:相同数据创建Immutable对象,多数测试下,fromJS要比List耗时长一点,偶尔List长一点,不排除是JS引擎问题。
2:在比较2各完全不同的Immutable对象时,用lodah的is_Equal会比is方法快一丢丢。
3:is方法不能比较非Immutable对象
4:比较有相同原的Immutable对象时is god damn fast!!!

debug之旅--解决jsonwebtoken缺少包问题

###debug之旅–解决jsonwebtoken缺少包问题。
最近倒腾一个带有实验性质的小程序用到jsonwebtoken。

npm install jsonwebtoken,引入包后出错:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
ERROR in ./~/dns/~/native-dns/lib/server.js
Module not found: Error: Cannot resolve module 'dgram' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/dns/node_modules/native-dns/lib
@ ./~/dns/~/native-dns/lib/server.js 23:12-28

ERROR in ./~/dns/~/native-dns/lib/platform.js
Module not found: Error: Cannot resolve module 'fs' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/dns/node_modules/native-dns/lib
@ ./~/dns/~/native-dns/lib/platform.js 23:9-22

ERROR in ./~/dns/~/native-dns/lib/utils.js
Module not found: Error: Cannot resolve module 'dgram' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/dns/node_modules/native-dns/lib
@ ./~/dns/~/native-dns/lib/utils.js 21:12-28

ERROR in ./~/native-dns-cache/lookup.js
Module not found: Error: Cannot resolve module 'dgram' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/native-dns-cache
@ ./~/native-dns-cache/lookup.js 21:12-28

ERROR in ./~/tap/lib/test.js
Module not found: Error: Cannot resolve module 'child_process' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/tap/lib
@ ./~/tap/lib/test.js 31:12-36

ERROR in ./~/tap/lib/test.js
Module not found: Error: Cannot resolve module 'fs' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/tap/lib
@ ./~/tap/lib/test.js 35:9-22

ERROR in ./~/graceful-fs/graceful-fs.js
Module not found: Error: Cannot resolve module 'fs' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/graceful-fs
@ ./~/graceful-fs/graceful-fs.js 1:9-22

ERROR in ./~/mkdirp/index.js
Module not found: Error: Cannot resolve module 'fs' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/mkdirp
@ ./~/mkdirp/index.js 2:9-22

ERROR in ./~/graceful-fs/fs.js
Module not found: Error: Cannot resolve module 'fs' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/graceful-fs
@ ./~/graceful-fs/fs.js 3:9-22

ERROR in ./~/convert-source-map/index.js
Module not found: Error: Cannot resolve module 'fs' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/convert-source-map
@ ./~/convert-source-map/index.js 2:9-22

ERROR in ./~/glob-stream/~/glob/glob.js
Module not found: Error: Cannot resolve module 'fs' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/glob-stream/node_modules/glob
@ ./~/glob-stream/~/glob/glob.js 43:9-22

ERROR in ./~/clone-stats/index.js
Module not found: Error: Cannot resolve module 'fs' in /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/clone-stats
@ ./~/clone-stats/index.js 1:11-24

ERROR in ./~/constants-browserify/constants.json
Module parse failed: /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/constants-browserify/constants.json Unexpected token (2:12)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected token (2:12)
at Parser.pp.raise (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:923:13)
at Parser.pp.unexpected (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1490:8)
at Parser.pp.semicolon (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1469:73)
at Parser.pp.parseExpressionStatement (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1994:8)
at Parser.pp.parseStatement (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1772:188)
at Parser.pp.parseBlock (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:2009:21)
at Parser.pp.parseStatement (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1753:19)
at Parser.pp.parseTopLevel (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1666:21)
at Parser.parse (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1632:17)
at Object.parse (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:885:44)
@ ./~/graceful-fs/polyfills.js 2:16-36

一堆错误,说的是缺少必要包。stackoverflow上仅有的几个回答,意思是说在webpack中添加node字段:

1
2
3
4
5
6
7
8
9
node: {
tap: 'empty',
net: 'empty',
tls: 'empty',
dns: 'empty',
fs: 'empty',
dgram: 'empty',
child_process :'empty'
},

上面添加了所有能忽略的字段,结果还是出现了问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ERROR in ./~/constants-browserify/constants.json
Module parse failed: /Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/constants-browserify/constants.json Unexpected token (2:12)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected token (2:12)
at Parser.pp.raise (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:923:13)
at Parser.pp.unexpected (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1490:8)
at Parser.pp.semicolon (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1469:73)
at Parser.pp.parseExpressionStatement (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1994:8)
at Parser.pp.parseStatement (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1772:188)
at Parser.pp.parseBlock (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:2009:21)
at Parser.pp.parseStatement (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1753:19)
at Parser.pp.parseTopLevel (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1666:21)
at Parser.parse (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:1632:17)
at Object.parse (/Users/pingfengafei/Desktop/learn_luo/redux-learn/node_modules/acorn/dist/acorn.js:885:44)
@ ./~/graceful-fs/polyfills.js 2:16-36

到这里我已经不想再追究下去了,fs,net等都是node自带的核心包,一般不可能找不到,事出反常必有妖。对比了工友的和老项目的package.json文件,发现了思路:

1
2
3
npm install jsonwebtoken --save
//安装的版本:
"jsonwebtoken": "^7.1.6",

老项目用到的版本:

1
"jsonwebtoken": "^5.4.1",

果断删除掉7.1.6版本,手动安装5.4.1版本。it works!

ps:配置node项最初是工友告诉我的,他配置后能够运行,但是到我这儿就不行了。初步怀疑是我用的package.json的安装包比较老,不兼容7.1.6版本。 magic!

小随笔

完美世界毁约事件直接导致了我在今年四月走社招找工作。四月是个尴尬的时间点,春季补招和社招都临近末尾,最后幸运的来到了现在的公司。清明节搬到了漕河泾附近的平南一村。兼顾文文和自己上班。她三站地铁,我距离完美13站且需要换乘(毁约是租房子四五天以后的事情)。祸兮,福之所倚,运气好来到了新公司,在徐家汇。虽然也要换乘,但从13站变成了6站。一号线很挤,很多天早上都像照片一样被贴到门的玻璃上。上班不久后公司说要搬去新办公地点,地点在漕河泾,地图上显示距离住处只有2公司,以后每天可以走路上班了,不堵,20min。
今天是去新办公室的第一天,阵阵凉风袭来,太阳躲到了云朵里,走在路上非常惬意。自己被分配到了一个不尴不尬的位子上。第一天嘈杂的很,乘着暂时无法办公的空隙,写下这篇日记。

#test
原始md出现了格式不兼容,文章被当做类似代码块一样处理–黑色背景,有左右滚动条。因为文章每行都出现了空格符。

删除空格符后本地格式正确,hexo d部署说没有变化,这和删除了空格符矛盾。怀疑是部署模块有问题,然后,写到这里我才发现,忘记hexo generate!!!

锚点和事件响应

html锚点
为什么练葵花宝典的一定要自宫呢?
因为,纸上得来终觉浅,绝知此事要宫刑

百度搜html锚点,搜到的都是半吊子答案,读起来不但费解,还误人子弟。读书就要彻底才行。

w3cschool说得很清楚w3cschool

1:同一页锚点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.partA{
width:500px;
height:1000px;
background-color: red;
}
.partB{
width:500px;
height:1000px;
background-color: yellow;
}
</style>
</head>
<body>
<a href="#point">锚点</a>
<div class="partA">
</div>
<div>
<a name="point"></a>
<div class="partB">
</div>
</body>
</html>

href url有3个类型:
a:绝对url
b:相对url
c:#name 锚点语法

2:跳转到新页面的锚点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
.partA{
width:500px;
height:1000px;
background-color: red;
}
.partB{
width:500px;
height:1000px;
background-color: yellow;
}
</style>
</head>
<body>
<a href="pointB.html#pointB">锚点</a>
<div class="partA">
</div>
<div>
<a name="point"></a>
<div class="partB">
</div>
</body>
</html>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>pointB.html</title>
<style>
.partA{
width:500px;
height:1000px;
background-color: red;
}
.partB{
width:500px;
height:1000px;
background-color: yellow;
}
</style>
</head>
<body>
<div class="partA">
</div>
<div>
<a name="pointB"></a>
<div class="partB">
</div>
</body>
</html>

href = url + # name

今天遇到的一个超级大bug
在给Revit-three.js做lod性能优化的时候我遇到一个问题:用什么条件来判断需要调用lod函数?
最早期的想法是查找three.js有没有api提供标记前后2帧发生了变化,用标记做判断条件。遗憾读了几天
object3Dscenecamerarender类几天,没发现自带api提供此功能,自己一时又不知道怎么造轮子,惨!
换个角度看问题,帧发生变化的原因是什么?是用户操作了平移(pan)旋转(rotate)缩放(sacle),而操作又是由事件响应完成的,包括鼠标事件和键盘事件。
细分事件,鼠标事件最常用:左键旋转,滚轮缩放,右键平移。
只要以事件响应作为判断标准即可。
写了个事件响应demo如下,chrome ok,不考虑兼容性问题:

1
2
3
4
5
6
7
8
9
10
11
12
var mousewheel = document.all ? "mousewheel" : "DOMMouseScroll"; 
$(window).bind('mousewheel', function(){
console.log('mousewheel1');
});

window.addEventListener( 'mousewheel', mouseWHeelHandler, false);

function mouseWHeelHandler(){
console.log('mousewheel2');
}

window.mousewheel = mouseWHeelHandler;

3种方法随意用!

但是迁移到Revit-three.js中失败了。
想了n中可能,走了n个玩路子,最终锁定在:自己写的事件响应被覆盖了。
找到一条引用的js文件:
<script type="text/javascript" src="source-file/OrbitControls.js"></script>
查找源代码发现:

学C++和java的时候经常听到函数覆盖,重载。今天在js里遇到竟然要想了半天,逻辑思维有待提高。
OrbitControls.js没有提供标记的api,于是自己增加了一条api:

1
2
3
4
5
6
7
8
9
this.flag = false;
每个eventHander函数里增加一句:
this.flag = true;
判断逻辑如下:
if(flag)
{
flag = false
do lod;
}

至此,毕业设计lod算法已经完成了。至于老陈说用四叉树优化性能,不想去尝试了。现在搞three.js和十几二十年前老前辈们学vb,c一样,没有现成的资料,只有源码,segmentfault,stackoverflow,技术群问问题基本上都没有人回答。

ps,canvas事件响应:
不能通过addEventListener给canvas内部对象绑定事件,因为无论内部多么复杂,canvas都是作为一个整体以帧为时间单位渲染的。

不过想想还挺有趣的。

那些年写过的脑残bug

dota有毒啊,忙里抽空改Cannot read property ‘appendChild’ of null三天,一直找不到原因。盯着chrome console一个字符一个字符比对,那个痛苦啊,然后,发现,傻比的html代码里把dom对象注释了。

append与after的去呗

JQuery点滴
append vs after
Talk is cheap,show me the code!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="http://libs.baidu.com/jquery/1.9.0/jquery.js"></script>
</head>
<body>
<div class="append">append</div>
<div class="after">after</div>
<script>
$('.append').append('<p>this is test append</p>');
$('.after').after('<p>this is test after</p>');
</script>
</body>
</html>

append vs after
查看DOM结构可知,append是附加到内容里面,after是附加到内容后面