XiaoShang

  • 笔记
  • 日志
  • 阅读
所有文章

XiaoShang

  • 笔记
  • 日志
  • 阅读

使用密码代替密钥登录亚马逊免费云主机

2018-01-04 09:59:00

环境

Ubuntu 16.04.3 LTS

1 使用密钥登录系统

$ ssh -i ~/.ssh/awskey.pem ubuntu@54.186.40.*

2 设置root用户密码

$ sudo passwd root

3 切换至root身份

$ su root

4 修改ssh登录方式,找到 PasswordAuthentication no,把no改成yes

$ vim /etc/ssh/sshd_config

5 重启sshd

$ sudo service sshd restart

6 设置跟人用户ubuntu账号的登录密码

$ passwd ubuntu

7 完成,至此可以使用ssh ubuntu@54.186.40.*登录主机,但是好像不能使用root身份登录,不过可以使用ubuntu登录系统后切换到root用户

  • Linux
  • log

展开全文 >>

2018年flag

2018-01-03 10:22:31

HTML5

  • 语义化H5标签 特别注意article、header、footer、aside、nav等,注意HTML的标题结构
    • 完成方式:阅读《响应式Web设计 HTML5和CSS3实战(第2版)
  • 理解HTML标签在各个浏览器上的默认样式(代理样式),理解CSS中的重置样式表的概念
  • 理解Canvas、SVG 设计一个动画并使用Canvas实现
  • 阅读书籍 《HTML5秘籍》

CSS

  • Animate 使用animate实现3个酷炫动画
  • Flex布局 全面了解
  • Bootstrap 源码阅读学习
  • 通读《精通CSS高级Web标准解决方案(第2版)》

阅读书籍 《CSS SECRETS》

Javascript

  • 系统了解ES6语法
  • Array 熟练使用array的各种方法
  • 理解ES6新增的几种数据类型
  • 阅读Vue.js源码

阅读书籍 《Javascript 高级程序设计》、《Javascript 权威指南》《Javascript 语言精粹》

其他

  • 可以使用PS切图
  • 使用nginx在一台服务器上部署多个web程序
  • 熟练应用nginx的代理、rewrite配置解决跨域限制
  • 运行维护一个自有在线应用
  • 部署一个GitLab服务器

emm

  • 学会游泳
  • [x] 种棵友谊的小树苗-胡杨(不种了 2018.04.09)
  • note

展开全文 >>

Mac OS 更换Homebrew软件镜像源

2017-09-02 23:13:24

SOMETHING

  • Device

    • MacBook air
  • OS X version

    • 10.12.3 (16D30)
  • Brew –version

    • Homebrew 1.3.1
  • Dependencies

    • git

DO

1
2
3
4
# 替换brew.git:
$ cd "$(brew --repo)"
# 清华大学:
$ git remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/brew.git
1
2
3
4
# 替换homebrew-core.git:
$ cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core"
# 清华大学:
$ git remote set-url origin https://mirrors.tuna.tsinghua.edu.cn/git/homebrew/homebrew-core.git
1
2
3
4
# 替换homebrew-bottles:
# 清华大学:
$ echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.tuna.tsinghua.edu.cn/homebrew-bottles' >> ~/.bash_profile
$ source ~/.bash_profile
1
2
# 应用生效:
$ brew update

参考文献 http://blog.csdn.net/u010275932/article/details/76080833


Homebrew官方更新源是大陆访问一直是比较慢的,之前凑合着用,直到今儿,本来打算晚上搞事儿,结果一个mysql愣是耗了一个晚上才装上,可能也和郊区的渣网有关,不能忍,试了几次,最后成功替换为清华大学提供的软件源。


Tip

Mac系统下使用brew install mysql安装mysql后默认mysql是未启动的,直接运行mysql -uroot会出错:

ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)

解决办法,就是启动mysql:

1
$ mysql.server start

出现

Starting MySQL
. SUCCESS!

表示mysql启动成功,这时候就可以继续使用mysql -uroot登陆到mysql, (使用 brew install mysql 命令安装的mysql默认root用户密码为空)

可以为root用户设置个密码:

1
$ mysqladmin -uroot password root  #设置root的密码为 root

因为root用户一开始是没有密码的,所以省去了-p参数。

  • Mac
  • MySql
  • log

展开全文 >>

JS中float精度问题

2017-08-25 22:04:16

问题:

1
congsole.log(0.1 + 0.2); // 0.30000000000000004

看到没有,不是0.3 不是0.3 不是0.3 …

解决:

1
2
3
var n = 0.1 + 0.2;
var f = n.toFixed(1);
console.log(f); // 0.3

虽然得到了想要的结果,但这还会有较大的误差,因为numObj.toFixed([digits])使用的是四舍五入。

可以定义这么个函数:

1
2
3
4
5
6
function formatFloat(f, digit) {
var m = Math.pow(10, digit); // 求10 digit次方
var i = parseInt(f * m, 10); // f * m 后,按10进制返回数值,小数部分会被舍去

return i / m;
}

这个函数的巧妙之处在于,比如:

1
2
3
4
5
6
7
8
// 求 0.1 + 0.2,精确到2位小数
var f = 0.1 + 0.2;
formatFloat(f, 2);

=> m = Math.pow(10, 2); // 10的2次方等于100
=> i = parseInt(0.30000000000000004 * 100, 10); // 30.000000000000004按10进制返回,舍去小数部分就是 30

=> 30 / 100; // 0.30(这里精确到了2位小数,但实际返回的是0.3,也就是最后的0被忽略)

总结: 之所以产生精度问题,并不是只有js中存在,应该是所有编程语言都会有这个问题,原因在于我们进行数学运算时习惯使用10进制,而计算机要把10进制转换成二进制进行运算,在这个转换过程中便产生了精度问题。

0.1 => 0.0001 1001 1001 1001…(无限循环)

0.2 => 0.0011 0011 0011 0011…(无限循环)

两个无限循环小数相加,我也不知道怎么算 233 …

在线转换

参考文章


关于js中float精度问题,曾在一次刁钻的笔试中遇到过,题目貌似就是让写出console.log(0.1 + 0.2)的结果,当时是不明所以(最后笔试也是通过了的233);这次是在项目中,碰到了这个问题,一番查找弄明白了怎么回事儿,记录下来避免二次踩坑!

  • JS
  • log

展开全文 >>

Angularjs src加载图片404

2017-08-24 22:46:44

Angularjs src与ng-src

问题: 在Angularjs(v1.x)项目中,img标签中使用src = { { url } }这种形式的数据绑定,在页面模版初次加载时,会有一个404的请求错误,原因在于,在Angularjs编译模版前,浏览器会把{ { url } }当作普通字符串,向{ { url } }发出请求,这个地址自然是不存在的,从而导致404.

解决: 使用ng-src = { { url } }代替src = { { url } }, 这样在模版初次加载时就不会发出错误的请求了!

Tip: 如果src的值时字符串常量,则无论使用src还是ng-src自然都不会有问题!

  • AngularJS
  • log

展开全文 >>

block元素垂直水平居中

2017-08-06 18:38:53

case 1 使用绝对定位

场景 1-1

  • 父元素宽高固定;
  • 子元素宽高固定;

HTML

1
2
3
<div class="wrap">
<div class="center"></div>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.wrap {
position: relative;
width: 700px;
height: 500px;
background-color: gray;
}
.center {
position: absolute;
width: 200px;
height: 200px;
left: 250px;
top: 150px;
background-color: black;
}

Tip

  • left:父元素宽度700px / 2 - 子元素宽度200px / 2 = 250px
  • top: 父元素高度500px / 2 - 子元素高度200px / 2 = 150px

Demo

场景 1-2 使用calc

  • 父元素或子元素的宽、高是相对值,无法确定具体大小;
  • 亦适用于场景 1-1

HTML

1
2
3
<div class="wrap">
<div class="center"></div>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.wrap {
position: relative;
width: 100vw;
height: 100vh;
background-color: gray;
}
.center {
position: absolute;
width: 20%;
height: 20%;
left: calc(100vw / 2 - 20% / 2);
top: calc(100vh / 2 - 20% / 2);
background-color: black;
}

Tip

  • vw/vh分别表示相对视口的宽度和高度, 100vw表示100%的视口宽度;
  • calc()是CSS的一个函数,可以通过计算决定一个属性的值;

Demo

场景 1-3 使用translate

  • 适用场景1-1、1-2;

HTML

1
2
3
<div class="wrap">
<div class="center"></div>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.wrap {
position: relative;
width: 100vw;
height: 100vh;
background-color: gray;
}
.center {
position: absolute;
width: 20%;
height: 20%;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background-color: black;
}

Tip

  • 设置left: 50%、top: 50%后,黑色方块的左上角在父元素中心位置;
  • transform: translate(-50%, -50%)使黑色方块分别向左、向上移动相对于自身宽、高50%的距离;

Demo

场景 1-4 绝对定位联合margin

  • 适用场景1-1、1-2;

HTML

1
2
3
<div class="wrap">
<div class="center"></div>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
.wrap {
position: relative;
width: 100vw;
height: 100vh;
background-color: gray;
}
.center {
position: absolute;
width: 20%;
height: 20%;
background-color: black;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
}

Tip

  • 不关心元素尺寸,不需要计算

Demo

case 2 flex布局

场景 2-1

  • 不关心元素尺寸

HTML

1
2
3
<div class="wrap">
<div class="center"></div>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
.wrap {
display: flex;
width: 100vw;
height: 100vh;
background-color: gray;
}
.center {
width: 20%;
height: 20%;
background-color: black;
margin: auto;
}

Tip

  • 父元素使用flex布局
  • 子元素设置margin: auto

Demo

场景 2-2

  • 不关心元素尺寸
  • 不需要设置子元素

HTML

1
2
3
<div class="wrap">
<div class="center"></div>
</div>

CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
.wrap {
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
background-color: gray;
}
.center {
width: 20%;
height: 20%;
background-color: black;
}

Tip

  • 父元素使用flex布局
  • justify-content: center:父元素内容水平居中
  • align-items: center:父元素内容垂直居中

Demo

  • HTML
  • CSS
  • note

展开全文 >>

用Canvas编织璀璨星空图

2017-07-16 10:42:10

前言

在网上看到的这个项目,觉着挺炫,拿到源码后参照作者的教程弄明白了实现原理,原作者的教程在这。在研究过程中感觉原教程缺了点儿东西,我觉得我可以写一篇更好的教程(傲娇脸.jpg), 也算是对研究结果做个总结!

完成效果

点击查看完成后的效果

分析

  1. 整个页面只用了一个canvas元素,canvas画布大小为页面可视区域大小,整个canvas的背景为黑色,在画布上只有两种元素:星星和连线;
  2. 星星半径有大有小;
  3. 距离近的星星之间的连线较粗且透明度较低,距离较远的相反,星星之间的距离太远则没有连线;
  4. 星星是运动的,速度、方向不一;
  5. 有一个星星的位置是跟随鼠标移动的;

Coding

HTML部分

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html>
<head>
<title>用Canvas编织璀璨星空图</title>
</head>
<body>
<canvas id="canvas"></canvas>

<script type="text/javascript" src="index.js"></script>
</body>
</html>

以上就是全部html代码,只有一个canvas标签。

JavaScript部分

1.首先我们要得到那个 canvas 并得到绘制上下文:

1
2
var canvasEl = document.getElementById('canvas');
var ctx = canvasEl.getContext('2d');

2.声明两个数组,分别存放星星和连线

1
2
var nodes = [];     // 星星数组
var edges = []; // 连线数组

3.构建星星

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 构建星星
function constructorNodes() {
for (var i = 0; i < 100; i++) {
var node = {
drivenByMouse: i === 1,
x: Math.random() * canvasEl.width,
y: Math.random() * canvasEl.height,
vx: Math.random() - 0.5,
vy: Math.random() - 0.5,
radius: Math.random() > 0.9 ? Math.random() * 3 + 3 : Math.random() * 3 + 1
};

nodes.push(node);
}
}

for循环产生100个星星;

drivenByMouse: 在一开始的项目分析中知道,整个系统中要有一个星星是跟随鼠标移动的,跟随鼠标移动的星星是不用绘制出来的,这里用drivenByMouse属性做标记,标记 i === 0 即第一个星星,后面遍历绘制星星的时候就可以根据这个属性的值判断当前星星是否需要绘制;

x: 星星的x坐标;

y: 星星的y坐标;

vx: 星星在x轴方向的速度;

vy: 星星在y轴方向的速度;

radius: 星星的半径; 为了实现页面中小半径星星占多数,大半径星星占少数,用Math.random() > 0.9进行概率分配,使得10%的星星半径是Math.random() * 3 + 3即3~6, 90%的星星半径是Math.random() * 3 + 1即1~4;

在构建星星x,y坐标的时候用到了canvasEl.clientWidth和canvasEl.clientHeight, canvas画布的默认大小是宽300高150,需要设置一下画布大小,让画布充满屏幕,另外希望在改面浏览器窗口大小的时候,画布大小也随之改变,可以像下面这样做:

4.设置画布大小

1
2
3
4
5
6
7
8
9
10
11
12
13
window.onresize = function() {
canvasEl.width = document.body.scrollWidth;
canvasEl.height = document.body.scrollHeight;

if (nodes.length === 0) {
constructorNodes();
constructorEdge();
}

render();
};

window.onresize()

浏览器窗口大小改变会触发window.onresize;

document.body.scrollWidth和document.body.scrollHeight分别是浏览器可视工作区的宽高;

重置画布大小之后立即调用render函数绘制星空(render函数目前还没有定义,后面再具体实现函数内容);

在绘制星空之前需要检查nodes数组是否为空,如果为空则需要先调用构建函数constructorNodes和constructorEdge分别构建星星和连线;

因为不曾在canvas标签设置画布宽高,所以需要在程序中手动调用一次window.onresize,实现对画布的初始化设置;

星星构建好了,画布大小也设置完成,下面开始构建连线

5.构建连线

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 构建连线
function constructorEdge() {
nodes.forEach(function(e1) {
nodes.forEach(function(e2) {
if (e1 === e2) {
return;
}

var edge = {
from: e1,
to: e2
};

addEdge(edge);
})
})
}

双重遍历nodes;

如果两个节点是同一个,则跳过;

设置两个星星之间连线的起点是e1终点是e2

这里没有直接用edges.push(),为什么?

假设之前连接了 A、B两点,也就是外侧循环是A,内侧循环是B,那么在下一次循环中,外侧为B,内侧为A,是不是也会创建一条线呢?而实际上,这两条线除了方向不一样以外是完全一样的,这完全没有必要而且占用资源。因此在 addEdge 函数中进行一个判断:

1
2
3
4
5
6
7
8
9
10
11
12
13
function addEdge(edge) {
var ignore = false;

edges.forEach(function(e) {
if (e.from === edge.to && e.to === edge.from) {
ignore = true;
}
});

if (!ignore) {
edges.push(edge);
}
}

整个系统所需要的元素:星星和联系都构建好了,下面就可以实现前面提到的绘制函数render了

6.实现绘制函数

这个函数内容有点多,分两步来介绍,首先是背景和星星的绘制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function render() {
// 绘制背景
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvasEl.clientWidth, canvasEl.clientHeight);

// 绘制星星
nodes.forEach(function(node) {
if (node.drivenByMouse) {
return;
}

ctx.fillStyle = nodeColor;
ctx.beginPath();
ctx.arc(node.x, node.y, node.radius, 0, 2 * Math.PI);
ctx.fill();
})
}

背景颜色存储在backgroundColor变量中,将所有全局变量的声明统一放在js文件的开始位置是个好主意,方便日后查找修改。顺便将后面要用到的nodeColor和edgeColor一起声明了。代码看起来像这样:

1
2
3
var backgroundColor = '#000';
var nodeColor = '#fff';
var edgeColor = '#fff';

接着上面的代码,完成第二部分连线的绘制,整个函数完成后看起来像这样:

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
function render() {
// 绘制背景
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvasEl.clientWidth, canvasEl.clientHeight);

// 绘制星星
nodes.forEach(function(node) {
if (node.drivenByMouse) {
return;
}

ctx.fillStyle = nodeColor;
ctx.beginPath();
ctx.arc(node.x, node.y, node.radius, 0, 2 * Math.PI);
ctx.fill();
});

// 绘制连线
edges.forEach(function(edge) {
var length = lengthOfEdge(edge);
var maxLength = canvasEl.clientWidth / 8;

if (length > maxLength) {
return;
}

ctx.strokeStyle = edgeColor;
ctx.strokeWidth = (1 - length / maxLength) * 2.5;
ctx.globalAlpha = 1 - length / maxLength;
ctx.beginPath();
ctx.moveTo(edge.from.x, edge.from.y);
ctx.lineTo(edge.to.x, edge.to.y);
ctx.stroke();
});

ctx.globalAlpha = 1.0;
}

计算连线的长度,这里用了另一个函数lengthOfEdge,和之前一样,这个函数留着后面再具体实现;

maxLength设置连线的最大长度是画布的1/8,超出这个长度的连线就不进行绘制了;

ctx.strokeStyle设置画笔颜色,即连线的颜色,使用的edgeColor变量在前面声明过了;

ctx.strokeWidth连线的宽度,可以不断调整公式后面的系数达到想要的效果;

ctx.globalAlpha透明度设置,这是个全局变量,连线绘制完成后要重置为1.0,不然就出事儿了!

接着实现上面提到的用于计算连线长度的函数:

1
2
3
function lengthOfEdge(edge) {
return Math.sqrt(Math.pow(edge.from.x - edge.to.x, 2) + Math.pow(edge.from.y - edge.to.y, 2));
}

看着挺复杂,其实就是求两点间的距离:d2 = (x1-x2)2 + (y1 - y2)2

到这里星空绘制完成,打开页面就可以看到效果了,下面开始实现让星空动动动起来!

7.实现动画效果

这里使用window.requestAnimationFrame(step)实现动画效果,找到window.onresize()这句代码,在这句之后调用函数window.requestAnimationFrame(step), 就像这样:

1
window.requestAnimationFrame(step);

然后需要做的就是定义step函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function step() {
nodes.forEach(function(node) {
node.x += node.vx;
node.y += node.vy;

// 越界检查
if(node.x < 0 || node.x > canvasEl.clientWidth) {
node.vx *= -1;
node.x = clamp(0, canvasEl.clientWidth, node.x);
}
if (node.y < 0 || node.y > canvasEl.clientHeight) {
node.vy *= -1;
node.y = clamp(0, canvasEl.clientHeight, node.y)
}
});

render();
window.requestAnimationFrame(step);
}

遍历所有星星,更新每个星星的x,y坐标,公式:x = x + vx; y = y + vy;

星星坐标改变后要检查星星的坐标位置是否超出了画布边界,如果超出边界则设置速度为反方向,然后调用函数clamp,为星星坐标设置一个不超出边界的值;

星星坐标改变后,立即调用绘制函数,重新绘制星空;

绘制完成后再调用window.requestAnimationFrame(step),这样就形成了一个循环,星空不断重绘,形成动画;

现在实现上面的clamp函数,就像是这样:

1
2
3
4
5
6
7
8
9
function clamp(min, max, value) {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}

OK, 进行到这里,整个系统基本完成了,现在再打开页面已经可以看到酷炫的效果了,不过还可以再酷炫一点儿,就是一开始提到的要有一个星星是跟随鼠标移动的,现在就来实现它:

8.实现鼠标跟随

定义一个全局变量 mousePos存储鼠标x,y位置,初始位置就设置为[0,0], 和之前的全局变量放在一起,代码是这样的:

1
var mousePos = [0, 0];

需要获取鼠标位置,这样实现:

1
2
3
4
window.onmousemove = function(e) {
mousePos[0] = e.clientX;
mousePos[1] = e.clientY;
};

知道了鼠标位置就可以调整第一颗星星(即需要跟随鼠标移动的星星)的位置了:

1
2
3
4
function adjustNodeDrivenByMouse() {
nodes[0].x = mousePos[0];
nodes[0].y = mousePos[1];
}

第一颗星星和其它星星的区别在于,其它星星是根据自身的vx,vy的值改变位置的,第一颗星星是根据鼠标位置改变位置的;相同的是它们都需要不断更新自己的位置,所以要在step函数中调用adjustNodeDrivenByMouse函数来更新第一个星星的位置。找到step函数,在step函数里有一个绘制函数render, 把adjustNodeDrivenByMouse函数的调用写在绘制函数render调用前面,就是这句:

1
adjustNodeDrivenByMouse();

现在基本就完成了,已经可以看到不断变化的星空,鼠标跟随效果,但是上面的adjustNodeDrivenByMouse函数还可以优化一下,需要优化的原因是这样的:

刷新页面,此时第一颗星星的位置一开始设置的是[0,0],这时如果鼠标从浏览器外移动到星空的一个位置,会发现跟随星空移动的点(即第一颗星星)瞬间就到了鼠标位置,优化的目的就是让这个移动有个过渡的过程,而不是瞬移。现在来修改adjustNodeDrivenByMouse函数,修改后是这样:

1
2
3
4
5
6
function adjustNodeDrivenByMouse() {
// nodes[0].x = mousePos[0];
// nodes[0].y = mousePos[1];
nodes[0].x += (mousePos[0] - nodes[0].x) / easingFactor;
nodes[0].y += (mousePos[1] - nodes[0].y) / easingFactor;
}

这里将之前的代码注释了,便于对照。新增的两行用到了easingFactor变量,这是个过渡系数,这里设置的是5,和之前一样,也将这个变量和其他全局变量放在一起:

1
var easingFactor = 5;

修改adjustNodeDrivenByMouse函数后,刷新页面,将鼠标移出浏览器,然后再移入到浏览器时就会发现跟随鼠标移动的点从原始位置移动到鼠标位置时是有一个平滑的过渡过程的。

最后奉上完整的index.js代码:

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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
152
153
154
155
156
157
158
159
var canvasEl = document.getElementById('canvas');
var ctx = canvasEl.getContext('2d');

var backgroundColor = '#000';
var nodeColor = '#fff';
var edgeColor = '#fff';

var nodes = []; // 星星数组
var edges = []; // 连线数组
var mousePos = [0, 0];
var easingFactor = 5;

// 构建星星
function constructorNodes() {
for (var i = 0; i < 100; i++) {
var node = {
drivenByMouse: i === 1,
x: Math.random() * canvasEl.width,
y: Math.random() * canvasEl.height,
vx: Math.random() - 0.5,
vy: Math.random() - 0.5,
radius: Math.random() > 0.9 ? Math.random() * 3 + 3 : Math.random() * 3 + 1
};

nodes.push(node);
}
}

// 构建连线
function constructorEdge() {
nodes.forEach(function(e1) {
nodes.forEach(function(e2) {
if (e1 === e2) {
return;
}

var edge = {
from: e1,
to: e2
};

addEdge(edge);
})
})
}

function addEdge(edge) {
var ignore = false;

edges.forEach(function(e) {
if (e.from === edge.to && e.to === edge.from) {
ignore = true;
}
});

if (!ignore) {
edges.push(edge);
}
}

function render() {
// 绘制背景
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, canvasEl.clientWidth, canvasEl.clientHeight);

// 绘制星星
nodes.forEach(function(node) {
if (node.drivenByMouse) {
return;
}

ctx.fillStyle = nodeColor;
ctx.beginPath();
ctx.arc(node.x, node.y, node.radius, 0, 2 * Math.PI);
ctx.fill();
});

// 绘制连线
edges.forEach(function(edge) {
var length = lengthOfEdge(edge);
var maxLength = canvasEl.clientWidth / 8;

if (length > maxLength) {
return;
}

ctx.strokeStyle = edgeColor;
ctx.strokeWidth = (1 - length / maxLength) * 2.5;
ctx.globalAlpha = 1 - length / maxLength;
ctx.beginPath();
ctx.moveTo(edge.from.x, edge.from.y);
ctx.lineTo(edge.to.x, edge.to.y);
ctx.stroke();
});

ctx.globalAlpha = 1.0;
}

function lengthOfEdge(edge) {
return Math.sqrt(Math.pow(edge.from.x - edge.to.x, 2) + Math.pow(edge.from.y - edge.to.y, 2));
}

function step() {
nodes.forEach(function(node) {
node.x += node.vx;
node.y += node.vy;

// 越界检查
if(node.x < 0 || node.x > canvasEl.clientWidth) {
node.vx *= -1;
node.x = clamp(0, canvasEl.clientWidth, node.x);
}
if (node.y < 0 || node.y > canvasEl.clientHeight) {
node.vy *= -1;
node.y = clamp(0, canvasEl.clientHeight, node.y)
}
});

adjustNodeDrivenByMouse();
render();
window.requestAnimationFrame(step);
}

function clamp(min, max, value) {
if (value < min) {
return min;
}
if (value > max) {
return max;
}
return value;
}

function adjustNodeDrivenByMouse() {
// nodes[0].x = mousePos[0];
// nodes[0].y = mousePos[1];
nodes[0].x += (mousePos[0] - nodes[0].x) / easingFactor;
nodes[0].y += (mousePos[1] - nodes[0].y) / easingFactor;
}

window.onmousemove = function(e) {
mousePos[0] = e.clientX;
mousePos[1] = e.clientY;
};

window.onresize = function() {
canvasEl.width = document.body.scrollWidth;
canvasEl.height = document.body.scrollHeight;

if (nodes.length === 0) {
constructorNodes();
constructorEdge();
}

render();
};

window.onresize();
window.requestAnimationFrame(step);

好了,整个程序的介绍到此结束,Have Fun!

  • JS
  • HTML
  • Canvas
  • note

展开全文 >>

慕课网之《进击Node.js基础》学习笔记

2017-04-12 15:53:14

HTTP请求状态码

类型 指示信息 状态码 说明
1xx 请求已经接收,继续处理
2xx 请求处理完成 200 OK 请求成功
3xx 请求需要重定向
4xx 客户端错误 400 客户的请求有语法错误,服务端不能理解
401 请求可能没有经过授权
403 服务端收到请求但是拒绝提供服务,可能还是没有权限等等
404 找不到请求资源,可能是错误的请求地址
5xx 服务端错误 500 服务端发生不可预期的错误
503 服务端当前还不能处理这个请求,过段时间后可能会恢复正常

HTTP概念进阶

什么是回调?

回调是异步编程最基本的方法,对NodeJS来说,当需要按顺序执行异步逻辑的时候,一般采用后续传递的方式,也就是将后续逻辑封装在回调函数中作为起始函数的参数,逐层去嵌套,通过这种方式来让程序按照我们所期望的方式走完整个流程。

什么是同步/异步?什么是阻塞/非阻塞?

这个两个概念有些像,且有些可意会不可言传的感觉,个人理解:同步、异步关注的是调用过程,而阻塞、非阻塞关注的是调用的状态,具体可以参考这个知乎回答。

什么是I/O

数据/文件的写入/输出;

什么是单线程/多线程

单线程:你谈对象,一次只能谈一个,和这个女朋友分手了再谈下一个,不断地谈不断地分,然后再接着谈,这个过程对应到程序层面就是单线程,因为你每次只能做一件事儿,这个对象分手之前不能谈下一个;优点:由于每次只做一件事,效律高,速度快。缺点:不能像别人一样同时有好几个女朋友==

多线程:你不老实,同时谈了好几个女朋友,这就是多线程。优点:资源充分利用;缺点:容易分身乏术,比如情人节和哪个女朋友一起过,这个稍有不慎就会出问题,导致系统崩溃;

小结

以上概念理清之后,就可以理解:对于单线程的NodeJs来说,我们可以通过回调的方式实现异步编程,达到非阻塞的效果;

什么是事件?

这个嘛,简单一句话:事件就是事件!

什么是事件驱动?

上代码

1
2
3
4
5
6
7
/* 点击按钮后弹出信息 */
function clickedButton() {
window.alert('Button is clicked');
}

var button = document.getElementById('#button');
button.addEventListener('click', clickedButton');

按钮被点击后触发clickedButton方法, 点击事件发生的时候调用方法,类似这种就是事件驱动。

什么是基于事件驱动的回调?

上面这种注册回调就是基于事件驱动的回调

什么是事件循环(Eventloop)?

如果有大量的异步操作,或者是比较耗时的I/O操作,甚至定时器控制的延时操作,它们完成的时候都要调用相应的回调函数,从而完成一些密集的任务,而又不会阻塞整个程序执行的流程,这么多事件就需要一个机制进行管理,这个机制就是事件循环(Eventloop)。

Eventloop是一个回调函数队列,当异步函数执行的时候,回调函数就会被压入到这个队列。对于NodeJs来说,靠一个单线程不断的查询这个队列中是否有事件,当它读取到一个事件的时候,将调用与这个事件关联的JavaScript函数,事件的循环是一个先进先出的任务队列,回调就按照它们加入队列的顺序来执行。整个队列可以理解成是普通的函数和回调函数构成的一个完整的队列。

NodeJS核心思想

理解了上面一大坨以后,我们才能够去了解NodeJs的核心思想

1. 非阻塞
2. 单线程
3. 事件驱动

NodeJS实现继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Pet(words) {
this.words = words;
this.speak = function() {
console.log(this.words);
}
}

function Dog(words) {
Pet.call(this, words)
}

var dog = new Dog('Wang');

console.log(dog); // {words: 'Wang', speak: [function]}
dog.speak(); // 'Wang'

阅读NodeJS中HTTP模块源码

不以阅读源码为目的阅读源码,要带着问题阅读源码,现在的问题是我没有问题 ^_^
没有问题就要想办法制造问题 [/调皮]

1
2
3
4
5
6
7
8
9
var http = require('http')

http
.createServer(function(req, res){
res.writeHead(200, {'Content-Type': 'text/plain'})
res.write('Hello NodeJS')
res.end()
})
.listen(8080)

OK 上面代码创建了一个简单的服务,监听在8080端口;那么现在问题来了:

  1. createServer做了什么事情
  2. 回调函数是什么被调用的?
  3. req、res又是什么东西?
  4. listen又做了什么事情?

问题有了,带着问题也跟着把源码看了,然后发现,带着问题也看不懂源码,所以这些问题就留着吧留着吧. . .

  • Node
  • note

展开全文 >>

JavaScript正则表达式

2017-04-11 09:37:12

1-1 JS正则表达式简介及工具介绍

课程目标

  • 了解正则表达式语法
  • 在IDE中使用正则表达式处理规则复杂的字符串查找、替换需求
  • 在JavaScript程序设计中使用正则表达式处理字符串

什么是正字表达式?

  • Regular Expression 使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。

  • 说简单了就是按照某种规则去匹配符合条件的字符串。

举个例子

我们在linux系统中,想要查找当前目录中以txt为后缀的文件时,可以使用命令:find ./ -name *.txt 这里 * ;代表任意字符,这就使用了正则表达式。

然而,并不是所有的正则表达式都这么简单,有的正则表达式会非常复杂,比如这个

^([a-zA-Z0-9\_-])+@([a-zA-Z0-9\_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2}$ 

就不太容易看出所匹配的内容,这时候我们可以借助图形化工具帮助理解正则表达式意图,这里推荐一款在线的可以图形化正则表达式的工具,Regexper 正则表达式图形化工具
我们将刚才的正则表达式借助图形化工具转化后就是这种样式:
regexper
很容易可以看出这是一个匹配邮箱地址的正则表达式!

再比如:

/d 表示匹配数字

digit

/d? 表示匹配0或1个数字,?表示0或1个

digit0or1times

/d+ 表示匹配至少一个数字,+表示至少1个

digitmore1times

/d{3} 表示匹配3个数字,{3}是量词,表示3个

digit3times

/d{3,5} 表示匹配3~5个数字,{3,5}表示范围,3~5个

digit3to5

/d* 表示匹配任意个数字,*表示任意个,也可以是0个

digitany

正则表达式的简单应用场景

比如我们有一个文本文件,内容下图:

testtext

我们想要把文本中的is全部替换成IS,我们可以使用编辑器的查找/替换功能进行全部替换,替换完成后将得到如图所示文本数据:

textResult

我们发现,不仅单词is被替换了,this、display、isn’t中的is也被替换了,这并不是我们期待的结果,如何做到只替换单词is而忽视其他非单独单词的is部分?这时就可以使用正则表达式来达到期待的结果(其实,这个不使用正则也是可以实现的,不过我们还是说说正则的实现方式):

wholeworld

这里使用\b表示单词边界,这样只有当is为单个单词的时候才会匹配!

第二个例子,日期转换

我们想要把日期2017/01/26转换成26/01/2017这种格式,即,将年月日转换成日月年格式

转换前:
date

表达式(\d{4})-(\d{2})-(\d{2})将匹配2017-01-26,并将每个小括号的内容分为一组,如图

dategroup

然后我们使用分组进行替换,第一组匹配到的内容用$1表示,第二组用$2表示…

转换后:
date

通过这几个小例子,对正则表达式进行了简单的介绍,后面会对正则表达式进行详细的语法讲解。

2-1 RegExp对象

JavaScript通过内置对象RegExp支持正则表达式;

有两种方法实例化RegExp对象

  • 字面量
  • 构造函数

先来看一下使用字面量的方式,还是之前匹配is的例子

1
var reg = /\bis\b/;

同样的,使用构造函数方式如下

1
var reg = new RegExp('\\bis\\b');

这里反斜线使用了两次,是因为在js中反斜线本身就是特殊字符,使用的时候需要转义。

修饰符

  • g: global 全文搜索,不添加,搜索到第一个匹配值后就会停止向下继续匹配
  • i: ignore case 忽略大小写,默认大小写敏感
  • m: multiple lines 多行搜索

举个例子

1
2
'He is a boy. Is he?'.replace(/\bis\b/g, 'xx');  // g 表示进行全局匹配
// 输出结果: He xx a boy. Is he?

这是因为在js中,正则表达式默认大小写敏感,如果想忽略大小写则

1
2
He is a boy. Is he?'.replace(/\bis\b/gi, 'xx');	// i 表示忽略大小写
// 输出结果:He xx a boy. xx he?

2-2 元字符

正则表达式由两种基本的字符类型组成

  • 原义文本字符
  • 元字符

原义文本字符就是代表它本来含义的字符,比如:a,b,c,1,2,3等等;

元字符是指在正则表达式中有特殊含义的非字母字符,比如我们之前用到的\b表示单词边界,\d表示数字

在正则表达式中有几个字符是需要我们注意的,它们都有着特殊含义

* + ? $ ^ . | \ (){}[]

另外还有一些

\t    水平制表符
\v    垂直制表符
\n    换行符
\r    回车符
\0    空字符(这个是数字零)
\f    换页符
\cX    Ctrl+X

2-3 字符类

  • 一般情况下正则表达式的一个字符对应字符串一个字符,如’a’就表示字符’a’;
  • 我们可以使用元字符[]来构建一类字符,比如[abc]就可以匹配a或b或c;
  • [^abc]表示除a、b、c以外的字符;

2-4 范围类

  • [a-z] 表示从a到z的任意字符,这是一个闭区间,包含a和z本身;
  • [a-zA-Z] 表示任意大小写字母;

2-5 JS预定义类及边界

预定义类

字符 等价类 含义
. [^\r\n] 除回车符、换行符之外的所有字符
\d [0-9] 数字字符
\D [^0-9] 非数字字符
\s [\t\n\x0B\f\r] 空白符
\S [^\t\n\x0B\f\r] 非空白符
\w [a-zA-Z_0-9] 单词字符(字母、数字、下划线)
\W [^a-zA-Z_0-9] 非单词字符

单词边界

字符 含义
^ 以xxx开始
$ 以xxx结束
\b 单词边界
\B 非单词边界
1
2
3
4
5
6
'@123@abc@'.replace(/@/g, 'Q')        // Q123QabcQ
'@123@abc@'.replace(/^@/g, 'Q') // Q123@abc@
'@123@abc@'.replace(/@$/g, 'Q') // @123@abcQ
'This is a boy'.replace(/is/g, 'x'); // Thx x a boy
'This is a boy'.replace(/\bis\b/g, 'x') // This x a boy
'This is a boy'.replace(/\Bis/b/g, 'x') // Thx is a boy

多行匹配

1
2
3
4
// 注释中的 \n 表示换行
var mulStr = "@123\n@456\n@789"; // 使用"\n"转义符添加两个换行
mulStr.replace(/^@/g, 'at'); // at123\n@456\n@789
mulStr.replace(/^@/gm, 'at'); // at123\nat456\nat789

2-6 量词

假如我们希望匹配一个连续出现20次数字的字符串,我们可能会写成这样的正则表达式:

\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d\d

类似这种情况,使用量词表示便可简化很多,比如:

\d{20}

量词的表示规则如下:

字符 含义
? 出现零次或一次(最多出现一次)
+ 出现一次或多次(至少出现一次)
* 出现零次或多次(任意次)
{n} 出现n次
{n,m} 出现n至m次
{n,} 至少出现n次

2-7 JS正则贪婪模式

'12345678'.match(/\d{3,6}/); // ["123456", index: 0, input: "12345678"]

\d{3,6}表示匹配连续出现3至6次数字的字符串,从结果可以知道最终匹配的是连续出现6次数字的字符串,这是因为在js中默认是贪婪匹配,就是尽可能多的匹配;如果想让正则表达式尽可能少的匹配,也即是说一旦成功匹配不再继续尝试就是非贪婪模式,比如:

'12345678'.match(/\d{3,6}?/); // ["123", index: 0, input: "12345678"]

2-8 分组

2-9 前瞻

2-10 JS对象属性

2-11 test和exec方法

2-12 字符串对象方法

  • JS
  • note

展开全文 >>

UI-Bootstrap文档翻译

2017-03-19 20:44:52

UI Bootstrap

AngularUI 团队使用纯AngularJS写的Bootstrap 组件

Angular 2

为Angular 2 提供支持,检验ng-bootstrap, 由 UI Bootstrap 团队创建。

依赖

这个指令库包含了符合Bootstrap标准和样式的一组原生的AngularJS指令。而且不依赖于JQuery或者Bootstrap的javascript文件。它只依赖这些:

  • AngularJS(要求AngularJS 1.4.x或者更高版本,已在1.6.1版本测试). 0.14.3版本的库是支持AngularJS 1.3.x 的最新版本, 0.12.0版,是支持AngularJS 1.2.x的最新版本
  • Angular-animate (这个版本需要和你的angular匹配,1.6.1版本已测试),如果你打算使用动画,你需要加载angular-animate
  • angular-touch (这个版本需要和你的angular匹配,1.6.1版本已测试), 如果你打算使用swipe actions, 你需要加载angular-touch.
  • Bootstrap CSS (3.3.7版本已测试). 这个版本的库(2.5.0)只能与Bootstrap CSS 3.x版本使用。0.8.0版本的库是支持Bootstrap CSS 2.3.x的最新版本

文件下载

所有指令的构建文件分布几个不同的种类:为产品使用的压缩文件,为开发使用的非压缩文件,有或没有模板。所有的配置和描述说明可以从这里下载, 有-tpls标识的文件包含捆绑了JavaScript的模板,正常的版本不包含被捆绑的模板,如果你只对这些指令中的一部分感兴趣,你可以在这里创建你需要的文件然后下载(需要在原文创建)。

无论你选择用哪种方式,好消息是,所有这些文件的大小相当小:包含模板的压缩文件只有122k, 没有模板的是98k(如果使用gzip压缩,有模板的是 ~31kb , 没有模板是28k)。

安装

当你下载了所有的文件,并在你的页面中引用它们,你只需要在模块中声明依赖ui.bootstrap:

angular.module('myModule', ['ui.bootstrap']);

如果你在CSP模块中使用UI Bootstrap, 例如:在扩展中,确保手动在HTML文件中链接ui-bootstrap-csp.css

你可以从这个页面去plunkers查看对应描述的demo的运行示例。

前缀迁移

自从0.14.0版本,我们开始给所有的组件增加前缀。如果你是从ui-bootstrap 0.13.4或更早的版本升级,请查看我们的迁移指南。

CSS

由于最初的Bootstrap的CSS不依赖href属性,一些组件(pagination, tabs)的游标风格取决于空的href属性。
但是在AngularJS中添加空的href属性在link标签中将会导致有害的路由改变。这就是为什么样式不能正确应用,我们要在指令模板中移除空的href属性。这个纠正很简单,只需要在你的应用中增加下面的样式。

.nav, .pagination, .carousel, .panel-title a {cursor: pointer;}

FAQ

普通的问题/解决方法请查看我们的FAQ

文档阅读

ui-bootstrap提供的每一个组件都有说明文档和可交互的Plunker示例。

对于指令,我们列出不同属性的默认值。除了这个,一些设置还有增加了标记:

  • $watch-这个设置会被angular $watch 监听。
  • B-这个设置是布尔值,它不需要参数。
  • C-这个设置是可以在constant service中被配置成全局的形式。
  • $-这个设置期待一个angular表达式替代文字字符串。如果这个表达式支持布尔值/整数,你可以直接跳过。
  • readonly-这个设置是只读。

对于服务(你可以通过$前缀认出它们),我们会列出所有可能的参数,你可以跳过它们,和它们默认的值。

  • 有些指令会有一个配置服务,就像这种模式:uibDirectiveConfig. 这个服务设置使用驼峰式命名。服务可以在实例的.config方法中配置。

Accordion

Alert

Buttons

Carousel

Collapse

Dateparser

Datepicker

Datepicker Popup

Dropdown

Modal

Pager

Pagination

Popover

Position

Progressbar

Rating

Tabs

Timepicker

Tooltip

Typeahead

  • AngularJS
  • note

展开全文 >>

« Prev123Next »
© 2019 XiaoShang
  • 所有文章

tag:

  • JS
  • Mac
  • Npm
  • Redis
  • MySql
  • AngularJS
  • HTML
  • CSS
  • Hexo
  • Git
  • Vue
  • Linux
  • Node
  • Nginx
  • Canvas

    缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    3、在根目录_config.yml里添加配置:

      jsonContent:
        meta: false
        pages: false
        posts:
          title: true
          date: true
          path: true
          text: false
          raw: false
          content: false
          slug: false
          updated: false
          comments: false
          link: false
          permalink: false
          excerpt: false
          categories: false
          tags: true