diff --git "a/2015/09/30/AngularJS-ng-app\347\232\204\350\207\252\345\212\250\345\212\240\350\275\275/index.html" "b/2015/09/30/AngularJS-ng-app\347\232\204\350\207\252\345\212\250\345\212\240\350\275\275/index.html" index e69de29b..99c2ff28 100644 --- "a/2015/09/30/AngularJS-ng-app\347\232\204\350\207\252\345\212\250\345\212\240\350\275\275/index.html" +++ "b/2015/09/30/AngularJS-ng-app\347\232\204\350\207\252\345\212\250\345\212\240\350\275\275/index.html" @@ -0,0 +1,719 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AngularJS ng-app的自动加载 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

AngularJS ng-app的自动加载

+ + + +
+ + + + + +
+ + + + + +

今天练习AngularJS遇到了这个问题,ng-app=“值”,便无法实现,遂百度找到了答案,共享之。。

+

ng-app是angular的一个指令,代表一个angular应用(也叫模块)。使用ng-app或ng-app=””来标记一个DOM结点,让框架会自动加载。也就是说,ng-app是可以带属性值的。如果想要实现自动加载,那么就不能让ng-app带有属性值。

1
2
3
4
5
6
<html>
<body ng-app>
<div>div1:{{1+3*2}}</div>
<script src="angular.js"></script>
</body>
</html>

+

1、不含ng-app,无法自动加载,这个比较好理解。

1
2
3
4
5
6
<html>
<body>
<div>div1:{{1+3*2}}</div>
<script src="angular.js"></script>
</body>
</html>

+

2、含有2个ng-app,那么只会自动加载第一个,这个也好理解。

1
2
3
4
5
6
7
<html>
<body>
<div ng-app>div1:{{1+3*2}}</div>
<div ng-app>div2:{{1+3*2}}</div>
<script src="angular.js"></script>
</body>
</html>

+

3、ng-app带有属性,不能自动加载

1
2
3
4
5
6
<html>
<body>
<div ng-app="app1">div1:{{1+3*2}}</div>
<script src="angular.js"></script>
</body>
</html>

+

4、不带属性的在前,带属性的在后。ng-app标记的模块可以自动加载

1
2
3
4
5
6
7
<html>
<body>
<div ng-app>div1:{{1+3*2}}</div>
<div ng-app="app1">div1:{{1+3*2}}</div>
<script src="angular.js"></script>
</body>
</html>

+

5、带属性的在前,不带属性的在后。ng-app标记的模块不能自动加载

1
2
3
4
5
6
7
<html>
<body>
<div ng-app="app1">div1:{{1+3*2}}</div>
<div ng-app>div1:{{1+3*2}}</div>
<script src="angular.js"></script>
</body>
</html>

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2015/12/02/\344\273\212\345\244\251\351\201\207\345\210\260\347\232\204i-\351\227\256\351\242\230\344\271\213\350\256\260\345\275\225/index.html" "b/2015/12/02/\344\273\212\345\244\251\351\201\207\345\210\260\347\232\204i-\351\227\256\351\242\230\344\271\213\350\256\260\345\275\225/index.html" index e69de29b..7a7629b4 100644 --- "a/2015/12/02/\344\273\212\345\244\251\351\201\207\345\210\260\347\232\204i-\351\227\256\351\242\230\344\271\213\350\256\260\345\275\225/index.html" +++ "b/2015/12/02/\344\273\212\345\244\251\351\201\207\345\210\260\347\232\204i-\351\227\256\351\242\230\344\271\213\350\256\260\345\275\225/index.html" @@ -0,0 +1,720 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 今天遇到的i++问题之记录 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

今天遇到的i++问题之记录

+ + + +
+ + + + + +
+ + + + + +

今天逛贴吧看到的,与自己预想的不同,于是在群里求解后方得知答案,遂记录之。代码来袭。

1
2
3
4
5
6
7
function a(){
var i=1;
i++;
alert(i); //2
}
var c = a();
c();

+
1
2
3
4
5
6
function a(){
var i=1;
alert(i++); //1
}
var c = a();
c();
+

之所以是1是因为alert(i++)这句的过程是先取后加,取得是加之前的值。

1
2
3
4
5
6
7
function a(){
var i=1;
alert(i++); //1
alert(i); //2 加了之后就是2了
}
var c = a();
c();

+

所以alert(i++)这句话的过程是这样的 第一步:继承自上一句i=1 。 第二步:弹! 这时弹得值为1 第三步:i=i+1 这时的i就是2了。 所以下面那一句的alert(i)也就是2了

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2015/12/03/Enter\351\224\256\346\217\220\344\272\244\350\241\250\345\215\225/index.html" "b/2015/12/03/Enter\351\224\256\346\217\220\344\272\244\350\241\250\345\215\225/index.html" index e69de29b..b05ca874 100644 --- "a/2015/12/03/Enter\351\224\256\346\217\220\344\272\244\350\241\250\345\215\225/index.html" +++ "b/2015/12/03/Enter\351\224\256\346\217\220\344\272\244\350\241\250\345\215\225/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Enter键提交表单 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

Enter键提交表单

+ + + +
+ + + + + +
+ + + + + +

input type=”submit”在360浏览器上不能提交 用了这个

1
<input type="button" class="btn btn_green btn_active btn_block btn_lg reg" value="注 册">

+
1
2
3
4
5
6
7
8
$(".input").keydown(function(e){	//class为input的最后一个
var e = e || event, //event是兼容IE浏览器
keycode = e.which || e.keyCode; //e.keyCode是兼容IE浏览器,e.which是获取按键编码
if (keycode==13) {
$(".reg").trigger("click"); 如果input上设置了点击事件,就要注释掉这句,不然会重复提交两次

}
});
+ +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2015/12/03/\347\256\200\346\230\223\350\241\250\345\215\225\351\252\214\350\257\201/index.html" "b/2015/12/03/\347\256\200\346\230\223\350\241\250\345\215\225\351\252\214\350\257\201/index.html" index e69de29b..d7d93602 100644 --- "a/2015/12/03/\347\256\200\346\230\223\350\241\250\345\215\225\351\252\214\350\257\201/index.html" +++ "b/2015/12/03/\347\256\200\346\230\223\350\241\250\345\215\225\351\252\214\350\257\201/index.html" @@ -0,0 +1,719 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 简易表单验证 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

简易表单验证

+ + + +
+ + + + + +
+ + + + + +

本来是用的其他网站扒下来的验证,结果因为JS压缩问题无法实现,于是就在他的基础上,自己做了简易验证,代码来一波:

1
2
<input type="text" id="login_merchant_id" class="input input_white" name="key_uni" placeholder="请输入商户ID"  autocomplete="off"  onkeypress="return handleEnter(this, event)">
<span id="login_merchant_id_span" class="input_tips">请输入6位的商户ID</span>

+

span是提示信息,html里就给他写好,然后给个.input_tips{display: none;}
然后下面blur触发验证

1
2
3
4
5
6
7
8
9
$("#login_merchant_id").blur(function(e){
var val = $("#login_merchant_id").val();
if(val.length !=6){
$("#login_merchant_id").next().css("display","block");
}
else{
$("#login_merchant_id").next().css("display","none");
}
});

+

搞定

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2015/12/07/background-attachment-fixed\345\272\224\347\224\250/index.html" "b/2015/12/07/background-attachment-fixed\345\272\224\347\224\250/index.html" index e69de29b..4b395774 100644 --- "a/2015/12/07/background-attachment-fixed\345\272\224\347\224\250/index.html" +++ "b/2015/12/07/background-attachment-fixed\345\272\224\347\224\250/index.html" @@ -0,0 +1,719 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + background-attachment:fixed应用 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

background-attachment:fixed应用

+ + + +
+ + + + + +
+ + + + + +

设置为fixed属性,背景相对于屏幕窗口固定,然后如果有一张全屏的图片,再来一张全屏的图片,就可以看到与平时滚动屏幕不同的切换图片。代码
CSS部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
html, body,.content{
height: 100%;
}
h2, body { margin: 0;}
.fixed-bg {
position: relative;
background-size: cover;
background-attachment: fixed;
height: 100%;
background-position: center center;
}
.bg-1 {
background-image: url("images/cd-background-1.jpg");
}
.container {
padding: 23% 1%;
background-color: #C7ABAB;
height: 100%;
}
.bg-2 {
background-image: url("images/cd-background-2.jpg");
}

+

HTML部分:

1
2
3
4
5
6
7
8
<div class="main content">
<div class="fixed-bg bg-1">
<h2>此处是图片</h2>
</div>
<div class="fixed-bg bg-2">
<h2>又一张图片</h2>
</div>
</div>

+

由此可以想到:如果图片之间加上内容 ,就会是比较新鲜的滚动方式:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
html, body,.content{
height: 100%;
}
h2, body { margin: 0;}
.fixed-bg {
position: relative;
background-size: cover;
background-attachment: fixed;
height: 100%;
background-position: center center;
}
.bg-1 {
background-image: url("images/cd-background-1.jpg");
}
.container { padding: 23% 1%;
background-color: #C7ABAB;
height: 100%;}
.bg-2 {
background-image: url("images/cd-background-2.jpg");
}

</style>
</head>
<body>
<div class="main content">
<div class="fixed-bg bg-1">
<h2>此处是图片</h2>
</div>
<div class="scrolling-bg">
<div class="container">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore incidunt suscipit similique, dolor corrupti cumque qui consectetur autem laborum fuga quas ipsam doloribus sequi, mollitia, repellendus sapiente repudiandae labore rerum amet culpa inventore, modi non. Illo quod repellendus alias? Cum rem doloremque adipisci accusantium? Saepe, necessitatibus!</p>
</div>
</div>
<div class="fixed-bg bg-2">
<h2>又一张图片</h2>
</div>
<div class="scrolling-bg">
<div class="container">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolore incidunt suscipit similique, dolor corrupti cumque qui consectetur autem laborum fuga quas ipsam doloribus sequi, mollitia, repellendus sapiente repudiandae labore rerum amet culpa inventore, modi non. Illo quod repellendus alias? Cum rem doloremque adipisci accusantium? Saepe, necessitatibus!</p>
</div>
</div>
</div>
</body>
</html>

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2015/12/11/jQuery\350\216\267\345\217\226\345\222\214\350\256\276\347\275\256disabled\345\261\236\346\200\247\343\200\201\350\203\214\346\231\257\345\233\276\347\211\207\350\267\257\345\276\204/index.html" "b/2015/12/11/jQuery\350\216\267\345\217\226\345\222\214\350\256\276\347\275\256disabled\345\261\236\346\200\247\343\200\201\350\203\214\346\231\257\345\233\276\347\211\207\350\267\257\345\276\204/index.html" index e69de29b..f2b70b37 100644 --- "a/2015/12/11/jQuery\350\216\267\345\217\226\345\222\214\350\256\276\347\275\256disabled\345\261\236\346\200\247\343\200\201\350\203\214\346\231\257\345\233\276\347\211\207\350\267\257\345\276\204/index.html" +++ "b/2015/12/11/jQuery\350\216\267\345\217\226\345\222\214\350\256\276\347\275\256disabled\345\261\236\346\200\247\343\200\201\350\203\214\346\231\257\345\233\276\347\211\207\350\267\257\345\276\204/index.html" @@ -0,0 +1,721 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + jQuery获取和设置disabled属性、背景图片路径 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

jQuery获取和设置disabled属性、背景图片路径

+ + + +
+ + + + + +
+ + + + + +

之前对于这个独特的disabled属性获取和设置很混乱,今天项目中用到了,用attr不能实现,于是多次试验得出:
获取disabled属性用prop

1
$("#basic_key").prop("disabled")

+

以上会返回true或false.

+

然后设置disabled是attr,重点是后面的一个参数不加引号:

1
2
$("#basic_key").attr("disabled",'false')		//false加引号是错误的~!
$("#basic_key").attr("disabled",false) //不加引号才正确

+

另外,背景图片路径的获取是:

1
$(".mcht_tdcode").css("background-image")

+

设置图片路径是:

1
$(".mcht_tdcode").css("background-image","url(template/images/p9.jpg)");

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2015/12/18/function-\351\207\214\351\235\242\344\270\215\350\203\275\345\243\260\346\230\216\345\256\232\344\271\211\345\207\275\346\225\260/index.html" "b/2015/12/18/function-\351\207\214\351\235\242\344\270\215\350\203\275\345\243\260\346\230\216\345\256\232\344\271\211\345\207\275\346\225\260/index.html" index e69de29b..303cbb7d 100644 --- "a/2015/12/18/function-\351\207\214\351\235\242\344\270\215\350\203\275\345\243\260\346\230\216\345\256\232\344\271\211\345\207\275\346\225\260/index.html" +++ "b/2015/12/18/function-\351\207\214\351\235\242\344\270\215\350\203\275\345\243\260\346\230\216\345\256\232\344\271\211\345\207\275\346\225\260/index.html" @@ -0,0 +1,722 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(function(){})里面不能声明定义函数 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

$(function(){})里面不能声明定义函数

+ + + +
+ + + + + +
+ + + + + +

关于JS变量作用域的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
</head>
<body>
<div onclick="abc()">测试测试</div>
<script>

$(function(){
function abc(){
alert(123)
}
})

</script>
</body>
</html>

+

在ready函数里这样写会弹出函数未找到,如果写成这样:

1
2
3
4
5
(function(){
$("div").on("click", function(){
alert(123)
})
})

+

这样会执行成功,或者去掉ready这一层也能执行成功。

+

百度上搜为什么第一种不能执行,得到的答案差不多就是因为ready是局部函数。点击事件是在全局里调用,但是我的疑问就是我触发点击事件也是在ready加载完之后执行的,也应该是在ready作用域中啊。希望有想法的朋友可以回复我

+

先记录下来,目前的结论是:ready里不能声明函数。

+

2015.12.18 13点16分编辑:
中午趁吃饭时间问了问搞前端的同学,终于明白了其中含义:
div绑定的onclick = abc() 在页面加载 DOM渲染的时候 就会去绑定abc函数,就要去找abc()的函数声明,但是函数声明是在ready里面的,所以并没有找到,也就是没有给abc绑定上函数,所以就算等页面加载完了再去点击,这时候abc已经定型了,就是没找到这个函数声明。
解决办法:
方法一:把ready那一层去掉。
方法二:HTML里不绑定onclick,在JS里写成$(“div”).on(“click”, function(){})

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2015/12/18/\346\265\205\350\260\210jquery\345\205\263\344\272\216select\346\241\206\347\232\204\345\217\226\345\200\274\345\222\214\350\265\213\345\200\274/index.html" "b/2015/12/18/\346\265\205\350\260\210jquery\345\205\263\344\272\216select\346\241\206\347\232\204\345\217\226\345\200\274\345\222\214\350\265\213\345\200\274/index.html" index e69de29b..faa86b92 100644 --- "a/2015/12/18/\346\265\205\350\260\210jquery\345\205\263\344\272\216select\346\241\206\347\232\204\345\217\226\345\200\274\345\222\214\350\265\213\345\200\274/index.html" +++ "b/2015/12/18/\346\265\205\350\260\210jquery\345\205\263\344\272\216select\346\241\206\347\232\204\345\217\226\345\200\274\345\222\214\350\265\213\345\200\274/index.html" @@ -0,0 +1,716 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 浅谈jquery关于select框的取值和赋值 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

浅谈jquery关于select框的取值和赋值

+ + + +
+ + + + + +
+ + + + + +
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
jQuery("#select_id").change(function(){}); // 1.为Select添加事件,当选择其中一项时触发     
var checkValue = jQuery("#select_id").val(); // 2.获取Select选中项的Value
var checkText = jQuery("#select_id :selected").text(); // 3.获取Select选中项的Text
var checkIndex = jQuery("#select_id").attr("selectedIndex");// 4.获取Select选中项的索引值,
或者:jQuery("#select_id").get(0).selectedIndex;
var maxIndex = jQuery("#select_id :last").attr("index"); // 5.获取Select最大的索引值,
或者:jQuery("#select_id :last").get(0).index;


jQuery("#select_id").get(0).selectedIndex = 1; // 1.设置Select索引值为1的项选中
jQuery("#select_id").val(4); // 2.设置Select的Value值为4的项选中
$("#select_id").attr("value","Normal“);
$("#select_id").get(0).value = value;
//根据select的显示值来为select设值
var count=$("#select_id").get(0).options.length;
for(var i=0;i<count;i++){
if($("#select_id").get(0).options[i].text == text)
{
$("#select_id").get(0).options[i].selected = true;
break;
}
}


jQuery("#select_id").append("<option value='新增'>新增option</option>"); // 1.为Select追加一个Option(下拉项)
jQuery("#select_id").prepend("<option value='请选择'>请选择</option>"); // 2.为Select插入一个Option(第一个位置)
jQuery("#select_id").get(0).remove(1); // 3.删除Select中索引值为1的Option(第二个)
jQuery("#select_id :last").remove(); // 4.删除Select中索引值最大Option(最后一个)
jQuery("#select_id [value='3']").remove(); // 5.删除Select中Value='3'的Option
jQuery("#select_id").empty(); // 6.清空下拉列表
+ +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/04/11/create-js\345\260\217\347\273\203\344\271\2401-\345\233\276\345\261\202\346\227\213\350\275\254-\351\274\240\346\240\207\344\272\213\344\273\266/index.html" "b/2016/04/11/create-js\345\260\217\347\273\203\344\271\2401-\345\233\276\345\261\202\346\227\213\350\275\254-\351\274\240\346\240\207\344\272\213\344\273\266/index.html" index e69de29b..bdb2e07a 100644 --- "a/2016/04/11/create-js\345\260\217\347\273\203\344\271\2401-\345\233\276\345\261\202\346\227\213\350\275\254-\351\274\240\346\240\207\344\272\213\344\273\266/index.html" +++ "b/2016/04/11/create-js\345\260\217\347\273\203\344\271\2401-\345\233\276\345\261\202\346\227\213\350\275\254-\351\274\240\346\240\207\344\272\213\344\273\266/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + create.js小练习1----图层旋转+鼠标事件 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

create.js小练习1----图层旋转+鼠标事件

+ + + +
+ + + + + +
+ + + + + +

最近总想学点H5小动画之类的框架,在网上搜了很多框架都不知道该从何下手,最后锁定cocos2d-JS和create.js。这两个都看了一下入门知识,前者适合中大型游戏开发,后者适合小型游戏和动画,但是createJS已经停止维护了,但是觉得create还简单些,拿来动画入门还是不错的,遂做点练习来入门,等练熟之后再往高处走,揣测着H5应用的流行趋势,希望自己的选择是正确的

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://code.createjs.com/easeljs-0.8.2.min.js"></script>

</head>
<body>

<canvas id="demoCanvas" width="500" height="300"></canvas>

<script>
var stage, circle;
stage = new createjs.Stage("demoCanvas");
circle = stage.addChild(new createjs.Container());
circle.x = circle.y = 150;

for (var i = 0; i < 25; i++) {
var shape = new createjs.Shape();
shape.graphics.beginFill(createjs.Graphics.getHSL(Math.random()*360, 100, 50)).drawCircle(0,0,30);
shape.x = Math.random()*300 - 150;
shape.y = Math.random()*300 - 150;
circle.addChild(shape);
}
createjs.Ticker.on("tick",tick);
function tick(){
circle.rotation += 3;
var l = circle.getNumChildren();
for (var i = 0 ;i<l;i++){
var child = circle.getChildAt(i);
child.alpha = 0.1;
var pt = child.globalToLocal(stage.mouseX, stage.mouseY);
if(child.hitTest(pt.x, pt.y)){
child.alpha = 1;
}
}
stage.update();
}
</script>

</body>
</html>

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/04/11/createjs\347\254\254\344\272\214\350\257\276-\350\275\254\346\215\242\345\235\220\346\240\207-\347\242\260\346\222\236\344\272\213\344\273\266/index.html" "b/2016/04/11/createjs\347\254\254\344\272\214\350\257\276-\350\275\254\346\215\242\345\235\220\346\240\207-\347\242\260\346\222\236\344\272\213\344\273\266/index.html" index e69de29b..68eca6ee 100644 --- "a/2016/04/11/createjs\347\254\254\344\272\214\350\257\276-\350\275\254\346\215\242\345\235\220\346\240\207-\347\242\260\346\222\236\344\272\213\344\273\266/index.html" +++ "b/2016/04/11/createjs\347\254\254\344\272\214\350\257\276-\350\275\254\346\215\242\345\235\220\346\240\207-\347\242\260\346\222\236\344\272\213\344\273\266/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + createjs第二课----转换坐标+碰撞事件 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

createjs第二课----转换坐标+碰撞事件

+ + + +
+ + + + + +
+ + + + + +

createjs转换坐标+碰撞事件

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://code.createjs.com/easeljs-0.8.2.min.js"></script>

</head>
<body>

<canvas id="demoCanvas" width="500" height="300"></canvas>

<script>
var stage, arm;
window.onload = function(){
stage = new createjs.Stage("demoCanvas");

target = stage.addChild(new createjs.Shape());
target.graphics.beginFill("red").drawCircle(0, 0 ,45)
.beginFill("white").drawCircle(0,0,30)
.beginFill("red").drawCircle(0,0,15);
target.x = 100;
target.y = 180;

arm = stage.addChild(new createjs.Shape());
arm.graphics.beginFill("black").drawRect(-2,-2,100,4)
.beginFill("blue").drawCircle(100,0,8);
arm.x = 180;
arm.y = 100;

createjs.Ticker.on("tick", tick);
}
function tick(){
arm.rotation += 5;
target.alpha = 0.2;
var pt = arm.localToLocal(100, 0, target);
if (target.hitTest(pt.x, pt.y)){target.alpha = 1;}
stage.update();
}
</script>

</body>
</html>

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/04/12/\345\210\244\346\226\255\345\233\276\347\211\207\346\230\257\345\220\246\345\255\230\345\234\250\357\274\214\344\270\215\345\255\230\345\234\250\345\260\261\346\230\276\347\244\272\351\273\230\350\256\244\345\233\276\347\211\207/index.html" "b/2016/04/12/\345\210\244\346\226\255\345\233\276\347\211\207\346\230\257\345\220\246\345\255\230\345\234\250\357\274\214\344\270\215\345\255\230\345\234\250\345\260\261\346\230\276\347\244\272\351\273\230\350\256\244\345\233\276\347\211\207/index.html" index e69de29b..f4f42633 100644 --- "a/2016/04/12/\345\210\244\346\226\255\345\233\276\347\211\207\346\230\257\345\220\246\345\255\230\345\234\250\357\274\214\344\270\215\345\255\230\345\234\250\345\260\261\346\230\276\347\244\272\351\273\230\350\256\244\345\233\276\347\211\207/index.html" +++ "b/2016/04/12/\345\210\244\346\226\255\345\233\276\347\211\207\346\230\257\345\220\246\345\255\230\345\234\250\357\274\214\344\270\215\345\255\230\345\234\250\345\260\261\346\230\276\347\244\272\351\273\230\350\256\244\345\233\276\347\211\207/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 判断图片是否存在,不存在就显示默认图片 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

判断图片是否存在,不存在就显示默认图片

+ + + +
+ + + + + +
+ + + + + +

利用image对象的onerror事件来判断,如果图片不存在,就更换image对象的src为默认图片的URL。

1
<img src="http://xxx/logo.gif"  onerror="javascript:this.src='http://aaa/logos.gif'" >

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/04/26/JS\346\250\241\346\213\237\351\274\240\346\240\207\347\202\271\345\207\273\345\235\220\346\240\207/index.html" "b/2016/04/26/JS\346\250\241\346\213\237\351\274\240\346\240\207\347\202\271\345\207\273\345\235\220\346\240\207/index.html" index e69de29b..f8fe2bf5 100644 --- "a/2016/04/26/JS\346\250\241\346\213\237\351\274\240\346\240\207\347\202\271\345\207\273\345\235\220\346\240\207/index.html" +++ "b/2016/04/26/JS\346\250\241\346\213\237\351\274\240\346\240\207\347\202\271\345\207\273\345\235\220\346\240\207/index.html" @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JS模拟鼠标点击坐标 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#div1{
position: absolute;
width: 200px;
height: 200px;
background-color: red;
color:white;
text-align: center;
line-height: 200px;

}
#div2{
position: absolute;
left: 300px;
width: 200px;
height: 200px;
background-color: blue;
color:white;
text-align: center;
line-height: 200px;

}

</style>
</head>
<body>
<div id="div1">区域1</div>
<div id="div2">区域2</div>
<script>
function imitateClick(oElement, iClientX, iClientY) { //定义模拟点击事件
var oEvent;

oEvent = document.createEvent("MouseEvents");
oEvent.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0,
iClientX, iClientY/*, false, false, false, false, 0, null*/);
oElement.dispatchEvent(oEvent);
}

var div1 = document.getElementById('div1'); //区域1
var div2 = document.getElementById('div2'); //区域2
div1.onclick = function(event) { //区域1点击方法
alert("点击区域1 (" + event.clientX + "," + event.clientY + ")");
};
div2.onclick = function(event) { //区域2点击方法
alert("点击区域2 (" + event.clientX + "," + event.clientY + ")");
};

imitateClick(div1, 100, 100); //触发模拟点击div1(100,100)的坐标
</script>


</body>
</html>

+

这个网站里介绍了关于他的解释,然后发现这个网站关于web介绍的挺全的,可以作为前端学习的一个工具网站:https://developer.mozilla.org/en-US/docs/Web/API/Document/createEvent

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/04/26/JS\350\256\276\347\275\256\350\266\205\350\277\207\350\256\276\347\275\256\347\232\204\346\226\207\346\234\254\351\225\277\345\272\246\346\230\276\347\244\272\347\232\204\345\206\205\345\256\271/index.html" "b/2016/04/26/JS\350\256\276\347\275\256\350\266\205\350\277\207\350\256\276\347\275\256\347\232\204\346\226\207\346\234\254\351\225\277\345\272\246\346\230\276\347\244\272\347\232\204\345\206\205\345\256\271/index.html" index e69de29b..3e81740b 100644 --- "a/2016/04/26/JS\350\256\276\347\275\256\350\266\205\350\277\207\350\256\276\347\275\256\347\232\204\346\226\207\346\234\254\351\225\277\345\272\246\346\230\276\347\244\272\347\232\204\345\206\205\345\256\271/index.html" +++ "b/2016/04/26/JS\350\256\276\347\275\256\350\266\205\350\277\207\350\256\276\347\275\256\347\232\204\346\226\207\346\234\254\351\225\277\345\272\246\346\230\276\347\244\272\347\232\204\345\206\205\345\256\271/index.html" @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JS设置超过设置的文本长度显示的内容 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

JS设置超过设置的文本长度显示的内容

+ + + +
+ + + + + +
+ + + + + +

当页面上一行字太多,我们需要把超出长度的内容显示为:“内容…”这种形式。如果是字母符号,2个为一个汉字长度,先是获取内容长度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function getStrChineseLength(str)
{
if(typeof(str)=="undefined")return str;
str = str.replace(/[ ]*$/g,"");
var w = 0;
for (var i=0; i<str.length; i++) {
var c = str.charCodeAt(i);
if ((c >= 0x0001 && c <= 0x007e) || (0xff60<=c && c<=0xff9f)) {
w++;
}else {
w+=2;
}
}
var length = w % 2 == 0 ? (w/2) : (parseInt(w/2)+1) ;
return length;
}
getStrChineseLength("都还好滴啊会fds... fse滴啊会独爱");

+

限制之后显示的文本内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function getStrChineseLen(str,len)
{
if(typeof(str)=="undefined")return str;
var w = 0;
str = str.replace(/[ ]*$/g,"");
if(getStrChineseLength(str)>len){
for (var i=0; i<str.length; i++) {
var c = str.charCodeAt(i);
if ((c >= 0x0001 && c <= 0x007e) || (0xff60<=c && c<=0xff9f)) {
w++;
}else {
w+=2;
}
if(parseInt((w+1)/2)>len){
return str.substring(0,i-1)+"...";
break;
}

}
}
return str;
};

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/04/26/js\346\227\266\351\227\264\346\240\274\345\274\217\345\214\226/index.html" "b/2016/04/26/js\346\227\266\351\227\264\346\240\274\345\274\217\345\214\226/index.html" index e69de29b..89237e44 100644 --- "a/2016/04/26/js\346\227\266\351\227\264\346\240\274\345\274\217\345\214\226/index.html" +++ "b/2016/04/26/js\346\227\266\351\227\264\346\240\274\345\274\217\345\214\226/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + js时间格式化 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>

</head>
<body>

<script>
function time(){


var date=new Date();
var y=date.getFullYear();
var m=date.getMonth()+1;
if(m<10)m="0"+m;
var d=date.getDate();
if(d<10)d="0"+d;
var h=date.getHours();
if(h<10)h="0"+h;
var i=date.getMinutes();
if(i<10)i="0"+i;
var s=date.getSeconds();
if(s<10)s="0"+s;
var mmm = y+"-"+m+"-"+d+" "+h+":"+i+":"+s;
console.log(mmm);
};
time();
</script>


</body>
</html>

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/04/28/\345\210\235\350\257\206jQuery-addBack/index.html" "b/2016/04/28/\345\210\235\350\257\206jQuery-addBack/index.html" index e69de29b..ff5aa73e 100644 --- "a/2016/04/28/\345\210\235\350\257\206jQuery-addBack/index.html" +++ "b/2016/04/28/\345\210\235\350\257\206jQuery-addBack/index.html" @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 初识jQuery addBack() | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

初识jQuery addBack()

+ + + +
+ + + + + +
+ + + + + +

干了前端大半年,今天第一次在stackoverflow上见到了addBack()方法,刚开始还以为是别人定义的方法,后来一搜才知道是jQuery中定义的方法,找了网上的demo,记录下,分享之,下面上代码:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<style>
<style>
p, div { margin:5px; padding:5px; }
.border { border: 2px solid red; }
.background { background:yellow; }
.left, .right { width: 45%; float: left;}
.right { margin-left:3%; }
</style>
</style>
</head>
<body>
<div class="left">
<p><strong>Before <code>addBack()</code></strong></p>
<div class="before-addback">
<p>First Paragraph</p>
<p>Second Paragraph</p>
</div>
</div>
<div class="right">
<p><strong>After <code>addBack()</code></strong></p>
<div class="after-addback">
<p>First Paragraph</p>
<p>Second Paragraph</p>
</div>
</div>

<script>
$("div.left, div.right").find("div, div > p").addClass("border");

// First Example
$("div.before-addback").find("p").addClass("background");

// Second Example
$("div.after-addback").find("p").addBack().addClass("background");
</script>
</body>
</html>

+

我理解到的意思就是:$(“div.after-addback”)用A表示,通过A找到的p标签$(“div.after-addback”).find(“p”)用B表示,那么$(“div.after-addback”).find(“p”).addBack()返回的对象就是A+B,如果有错的地方,还请指正。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/05/30/createJS\347\256\200\345\215\225\346\212\275\345\245\226demo/index.html" "b/2016/05/30/createJS\347\256\200\345\215\225\346\212\275\345\245\226demo/index.html" index e69de29b..420611b4 100644 --- "a/2016/05/30/createJS\347\256\200\345\215\225\346\212\275\345\245\226demo/index.html" +++ "b/2016/05/30/createJS\347\256\200\345\215\225\346\212\275\345\245\226demo/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + createJS简单抽奖demo | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

createJS简单抽奖demo

+ + + +
+ + + + + +
+ + + + + +

最近在学createJS, 就做个抽奖来练手,这个createjs库是google研发的,可以做小游戏引擎和H5小动画,感觉性能不错,语法也容易理解,但是google团队在2015年就停止维护了,不知道为啥,国内网上关于这个的教程挺少的,唯一的一个中文网就是按照官网翻译的,而且翻译的还特别生硬,我最近在墙外发现个日本的网站有这个库的教程,非常不错。也一直苦于不知道做H5小动画用哪个框架比较好,之前看过cocos2D,工程量太大了,相比之下,createJS非常的轻便。
另外还备注个求区间随机数的代码:

1
2
3
4
function selectfrom (lowValue,highValue){
var choice=highValue-lowValue+1;
return Math.floor(Math.random()*choice+lowValue);
}

+
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://code.createjs.com/createjs-2015.11.26.min.js"></script>
<style>
</style>
</head>
<body>
<canvas id="demo" width="1000px" height="400px"></canvas>

<script>
var stage = new createjs.Stage("demo");
var container = new createjs.Container();
var shape = new createjs.Shape();
var line = new createjs.Shape();
var text1 = new createjs.Text("手机", "15px Arial", "black");
var text2 = new createjs.Text("电脑", "15px Arial", "black");
var text3 = new createjs.Text("汽车", "15px Arial", "black");
var text4 = new createjs.Text("美女", "15px Arial", "black");
var tip = new createjs.Text("点击红色区域抽奖", "30px Arial", "green");
var result = new createjs.Text("", "30px Arial", "red");
var jiantou = new createjs.Shape();
var jiangpin = ["手机", "电脑", "汽车", "美女"];
var num;
var canClick = true;
jiantou.graphics.beginFill("green")
.moveTo(-5,-5).lineTo(5, -5).lineTo(0, 15);
jiantou.x = 100;
jiantou.y = 40;
text1.x = text2.x = -30;
text1.y = text4.y = -20;
text2.y = text3.y = 20;
text3.x = text4.x = 10;
container.x = 100;
container.y = 100;
tip.x = result.x = 200;
tip.y = 50;
result.y = 80;
shape.graphics.beginFill("red").drawCircle(0,0,50);
line.graphics.beginStroke("#000").setStrokeStyle(2);
line.graphics.moveTo(-50,0).lineTo(50,0).moveTo(0, 50).lineTo(0,-50);
stage.addChild(container, jiantou, tip, result);
container.addChild(shape, line, text1, text2, text3, text4);
createjs.Ticker.setFPS(100);
createjs.Ticker.addEventListener("tick", stage);
stage.addEventListener("mousedown", getNum);
function getNum(){
if(canClick){
canClick = false;
initCircle();
num = Math.floor(Math.random()*3+1);
var rotateReg = Math.floor(Math.random()*(num*90-(num-1)*90+1)+(num-1)*90) + 360*3;
console.log(num,jiangpin[num-1], rotateReg);
rotateCircle(rotateReg);
}
}
function rotateCircle(rotateReg){
createjs.Tween.get(container)
.to({rotation:rotateReg}, 5000, createjs.Ease.quadOut).call(setResult);
}
function initCircle(){
container.rotation = 0;
}
function setResult(){
result.text = "恭喜你得到:" + jiangpin[num-1];
canClick = true;
}
</script>
</body>
</html>
+ +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/05/31/\351\230\256\344\270\200\345\263\260\343\200\212javascript\346\240\207\345\207\206\346\225\231\347\250\213\343\200\213\350\257\273\344\271\246\347\254\224\350\256\260/index.html" "b/2016/05/31/\351\230\256\344\270\200\345\263\260\343\200\212javascript\346\240\207\345\207\206\346\225\231\347\250\213\343\200\213\350\257\273\344\271\246\347\254\224\350\256\260/index.html" index e69de29b..2f3e7122 100644 --- "a/2016/05/31/\351\230\256\344\270\200\345\263\260\343\200\212javascript\346\240\207\345\207\206\346\225\231\347\250\213\343\200\213\350\257\273\344\271\246\347\254\224\350\256\260/index.html" +++ "b/2016/05/31/\351\230\256\344\270\200\345\263\260\343\200\212javascript\346\240\207\345\207\206\346\225\231\347\250\213\343\200\213\350\257\273\344\271\246\347\254\224\350\256\260/index.html" @@ -0,0 +1,713 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 阮一峰《javascript标准教程》读书笔记 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

阮一峰《javascript标准教程》读书笔记

+ + + +
+ + + + + +
+ + + + + +

最近看到阮大神的《javascript标准教程》这本书,其中的内容非常的基础,于是打算过一遍这本书,其中学到的新技巧也会自己记录更新到这里。
PS:阮大神的博文真的是简单易懂,各种术语翻译成大白话真是方便了我等小白。

1、查看对象中的所有键名:

1
2
3
4
5
var o = {
m1: 1,
m2: 2
}
console.log(Object.keys(o)); //["m1", "m2"]

+

2、删除对象中的属性:

1
2
3
4
5
6
var o = {
m1: 1,
m2: 2
}
delete o.m1;
console.log(Object.keys(o)); //["m2"]

+

3、in可以遍历对象中的属性,和hasOwnProperty()的区别是:in会遍历对象继承的属性,hasOwnProperty只遍历对象本身的属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Person(name){
this.name = name;
}
Person.prototype.describe = function() {
return "Name: " + this.name;
};
var person = new Person('Jane');

for(var key in person){
if(person.hasOwnProperty(key)){
console.log(key); //name
}

}

+
1
2
3
4
5
6
7
8
9
10
function Person(name){
this.name = name;
}
Person.prototype.describe = function() {
return "Name: " + this.name;
};
var person = new Person('Jane');
for(var key in person){
console.log(key); //name, describe
}
+ +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/06/01/CSS\346\211\223\345\255\227\346\234\272\346\225\210\346\236\234/index.html" "b/2016/06/01/CSS\346\211\223\345\255\227\346\234\272\346\225\210\346\236\234/index.html" index e69de29b..2064e7db 100644 --- "a/2016/06/01/CSS\346\211\223\345\255\227\346\234\272\346\225\210\346\236\234/index.html" +++ "b/2016/06/01/CSS\346\211\223\345\255\227\346\234\272\346\225\210\346\236\234/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CSS打字机效果 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

CSS打字机效果

+ + + +
+ + + + + +
+ + + + + +

运用css中的border闪烁来模拟打字机效果,可用性不是很高,适合内容只有一行的字。

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
@keyframes typing { from { width: 0; } }
@keyframes blink-caret { 50% { border-color: transparent; } }

h1 {
font: bold 200% Consolas, Monaco, monospace;
border-right: .1em solid;
width: 16.5em; /* fallback */
/* width: 30ch; # of chars */
margin: 2em 1em;
white-space: nowrap;
overflow: hidden;
animation: typing 20s steps(30, end), /* # of steps = # of chars */
blink-caret .5s step-end infinite alternate;
}
</style>
</head>
<body>
<h1>Typing animation by Lea Verou.</h1>
</body>
</html>

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/06/03/php\344\271\213CURL\350\216\267\345\217\226\350\267\250\345\237\237\344\277\241\346\201\257/index.html" "b/2016/06/03/php\344\271\213CURL\350\216\267\345\217\226\350\267\250\345\237\237\344\277\241\346\201\257/index.html" index e69de29b..3fda2147 100644 --- "a/2016/06/03/php\344\271\213CURL\350\216\267\345\217\226\350\267\250\345\237\237\344\277\241\346\201\257/index.html" +++ "b/2016/06/03/php\344\271\213CURL\350\216\267\345\217\226\350\267\250\345\237\237\344\277\241\346\201\257/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + php之CURL获取跨域信息 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

php之CURL获取跨域信息

+ + + +
+ + + + + +
+ + + + + +

让给一个客户做一个接口转换,提交的数据以前是在本站的域名下,现在要到客户的后台,这就要涉及到跨域的问题,我本站用的JSONP,但是客户那边后台反馈回来的格式是json的,不是jsonp的,没有用函数包裹,无奈就需要使用php中转跨域,后台不会存在跨域问题,然后又搜了搜,用curl请求服务端数据,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$arr = array(
"createDate" => $_GET['createDate'],
"name" => $_GET['name'],
"gender" => $_GET['gender'], //接到的前端数据
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, '链接');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $arr);
$result = curl_exec($ch);//向服务器发送数据,返回的是服务端返回的数据
$temp=explode(":",$result);
$num=explode("}",$temp[1]);
$fasong = array("status" => $num[0]);
$json_fasong = json_encode($fasong);
echo $_GET['jsonp_callback'] . "(" . $json_fasong . ")";用函数包裹返回给前端
curl_close($ch);

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/06/13/HTML-input\344\270\212\344\274\240\345\233\276\347\211\207\345\271\266\351\242\204\350\247\210/index.html" "b/2016/06/13/HTML-input\344\270\212\344\274\240\345\233\276\347\211\207\345\271\266\351\242\204\350\247\210/index.html" index e69de29b..3fc6d9a3 100644 --- "a/2016/06/13/HTML-input\344\270\212\344\274\240\345\233\276\347\211\207\345\271\266\351\242\204\350\247\210/index.html" +++ "b/2016/06/13/HTML-input\344\270\212\344\274\240\345\233\276\347\211\207\345\271\266\351\242\204\350\247\210/index.html" @@ -0,0 +1,716 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HTML input上传图片并预览 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

HTML input上传图片并预览

+ + + +
+ + + + + +
+ + + + + +
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input type="file" id="photo">
<div id="click" style="width: 200px; height: 200px; border: 1px solid #000;"></div>
<script>
document.getElementById('photo').addEventListener('change',function(e){

var files = this.files;
var img = new Image();
var reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onload = function(e){
var mb = (e.total/1024)/1024;
if(mb>= 2){
alert('文件大小大于2M');
return;
}
img.src = this.result;
img.style.width = "80%";
document.getElementById('click').style.width="200px";
document.getElementById('click').style.height="200px";
document.getElementById('click').innerHTML = '';
document.getElementById('click').appendChild(img);
}
});
</script>
</body>
</html>
+ +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/06/15/canvas\345\220\210\346\210\220\345\233\276\347\211\207-\346\210\252\345\261\217\346\200\235\350\267\257/index.html" "b/2016/06/15/canvas\345\220\210\346\210\220\345\233\276\347\211\207-\346\210\252\345\261\217\346\200\235\350\267\257/index.html" index e69de29b..8eafc08b 100644 --- "a/2016/06/15/canvas\345\220\210\346\210\220\345\233\276\347\211\207-\346\210\252\345\261\217\346\200\235\350\267\257/index.html" +++ "b/2016/06/15/canvas\345\220\210\346\210\220\345\233\276\347\211\207-\346\210\252\345\261\217\346\200\235\350\267\257/index.html" @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + canvas合成图片 / 截屏思路 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

canvas合成图片 / 截屏思路

+ + + +
+ + + + + +
+ + + + + +

现在很多手机上的应用都有这样一个需求:选择背景图片,然后上传自己头像,然后合成一张图片分享出去。思路是这样的:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
canvas{
width:200px;
height:200px;
position: absolute;
left: 10px;
top: 10px
}
#sc{
border: 10px solid #000;
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<input type="file" id="photo">
<canvas id="cvs"></canvas>
<img id="sc"></div>
<input type="button" value="生成" id="scbtn">
<script>
document.getElementById('photo').addEventListener('change',function(e){
img = new Image();
var files = this.files;
var reader = new FileReader();
reader.readAsDataURL(files[0]);
reader.onload = function(e){
var mb = (e.total/1024)/1024;
if(mb>= 2){
alert('文件大小大于2M');
return;
}
img.src = this.result;
img.style.width = "80%";
var c = document.getElementById("cvs");
var ctx = c.getContext("2d");
ctx.drawImage(img,10,10);
}
});
var btn = document.getElementById("scbtn");
btn.onclick = function(){
var tt = document.getElementById("cvs").toDataURL("image/png");
document.getElementById('sc').setAttribute("src", tt);
}
</script>
</body>
</html>

+

大致思路就是:每上传一张图片,就用canvas的drawImage()方法绘制出来图像,图像会自动叠加,然后生成的时候,用toDataURL方法转换成一张新图片添加到DOM里,这个过程中可以添加拖拽效果之类的

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/07/08/js\344\272\214\347\272\247\350\201\224\345\212\250\350\217\234\345\215\225/index.html" "b/2016/07/08/js\344\272\214\347\272\247\350\201\224\345\212\250\350\217\234\345\215\225/index.html" index e69de29b..07efb6cb 100644 --- "a/2016/07/08/js\344\272\214\347\272\247\350\201\224\345\212\250\350\217\234\345\215\225/index.html" +++ "b/2016/07/08/js\344\272\214\347\272\247\350\201\224\345\212\250\350\217\234\345\215\225/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + js二级联动菜单 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

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
<html>
<head>
<title>This is a test!</title>
</head>
<body>
<form name="frm">
<select name="s1" onChange="redirec(document.frm.s1.options.selectedIndex)">
<option selected>请选择</option>
<option value="四川">四川</option>
<option value="云南">云南</option>
<option value="陕西">陕西</option>
<option value="重庆">重庆</option>
</select>

<select name="s2" id="fk">
<option value="请选择" selected>请选择</option>
</select>


</form>
<script language="javascript">
//获取一级菜单长度
var select1_len = document.frm.s1.options.length;
var select2 = new Array(select1_len);
//把一级菜单都设为数组
for (i=0; i<select1_len; i++)
{ select2[i] = new Array();}
//定义基本选项
select2[0][0] = new Option("请选择", " ");

select2[1][0] = new Option("成都", "成都");
select2[1][1] = new Option("自贡", "自贡");
select2[1][2] = new Option("攀枝花", "攀枝花");
select2[1][3] = new Option("泸州", "泸州");
select2[1][4] = new Option("德阳", "德阳");
select2[1][5] = new Option("绵阳", "绵阳");
select2[1][6] = new Option("广元", "广元");
select2[1][7] = new Option("遂宁", "遂宁");
select2[1][8] = new Option("内江", "内江");
select2[1][9] = new Option("乐山", "乐山");
select2[1][10] = new Option("南充", "南充");
select2[1][11] = new Option("宜宾", "宜宾");
select2[1][12] = new Option("广安", "广安");
select2[1][13] = new Option("达州", "达州");
select2[1][14] = new Option("资阳", "资阳");
select2[1][15] = new Option("巴中", "巴中");
select2[1][16] = new Option("雅安", "雅安");
select2[1][17] = new Option("眉山", "眉山");
select2[1][18] = new Option("阿坝藏族羌族", "阿坝藏族羌族");
select2[1][19] = new Option("甘孜藏族", "甘孜藏族");
select2[1][20] = new Option("凉山彝族", "凉山彝族");
select2[1][21] = new Option("华蓥", "华蓥");
select2[1][22] = new Option("简阳", "简阳");


select2[2][0] = new Option("昆明", "昆明");
select2[2][1] = new Option("曲靖", "曲靖");
select2[2][2] = new Option("玉溪", "玉溪");
select2[2][3] = new Option("昭通", "昭通");
select2[2][4] = new Option("临仓地区", "临仓地区");
select2[2][5] = new Option("丽江地区", "丽江地区");
select2[2][6] = new Option("思茅地区", "思茅地区");
select2[2][7] = new Option("保山", "保山");
select2[2][8] = new Option("文山壮族苗族", "文山壮族苗族");
select2[2][9] = new Option("红河哈尼族彝族", "红河哈尼族彝族");
select2[2][10] = new Option("西双版纳傣族", "西双版纳傣族");
select2[2][11] = new Option("楚雄彝族", "楚雄彝族");
select2[2][12] = new Option("大理白族", "大理白族");
select2[2][13] = new Option("德宏傣族景颇族", "德宏傣族景颇族");
select2[2][14] = new Option("怒江傈僳族", "怒江傈僳族");
select2[2][15] = new Option("迪庆藏族", "迪庆藏族");


select2[3][0] = new Option("西安", "西安");
select2[3][1] = new Option("铜川", "铜川");
select2[3][2] = new Option("宝鸡", "宝鸡");
select2[3][3] = new Option("咸阳", "咸阳");
select2[3][4] = new Option("渭南", "渭南");
select2[3][5] = new Option("延安", "延安");
select2[3][6] = new Option("汉中", "汉中");
select2[3][7] = new Option("榆林", "榆林");
select2[3][8] = new Option("安康", "安康");
select2[3][9] = new Option("商洛", "商洛");

select2[4][0] = new Option("重庆", "重庆");
//联动函数
function redirec(x)
{
document.getElementById("fk").innerHTML = '';
// var temp = document.frm.s2;
for (i=0;i<select2[x].length;i++)
{ document.frm.s2.options[i]=new Option(select2[x][i].text, select2[x][i].value);}
document.frm.s2.options[0].selected=true;
}
</script>
</body>
</html>

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/07/12/JS\350\216\267\345\217\226URL\344\270\255\347\232\204\346\237\220\344\270\252\345\217\202\346\225\260/index.html" "b/2016/07/12/JS\350\216\267\345\217\226URL\344\270\255\347\232\204\346\237\220\344\270\252\345\217\202\346\225\260/index.html" index e69de29b..98143285 100644 --- "a/2016/07/12/JS\350\216\267\345\217\226URL\344\270\255\347\232\204\346\237\220\344\270\252\345\217\202\346\225\260/index.html" +++ "b/2016/07/12/JS\350\216\267\345\217\226URL\344\270\255\347\232\204\346\237\220\344\270\252\345\217\202\346\225\260/index.html" @@ -0,0 +1,716 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JS获取URL中的某个参数 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

JS获取URL中的某个参数

+ + + +
+ + + + + +
+ + + + + +
1
2
3
4
5
6
7
String.prototype.getUrlValue = function(parm) {
var reg = new RegExp("(^|&)" + parm + "=([^&]*)(&|$)");
var r = this.substr(this.indexOf("\?") + 1).match(reg);
if (r != null) return unescape(r[2]);
return null;
}
var id = window.location.href.getUrlValue("uid");
+ +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/07/19/CSS\350\203\214\346\231\257\345\233\276\345\261\205\344\270\255/index.html" "b/2016/07/19/CSS\350\203\214\346\231\257\345\233\276\345\261\205\344\270\255/index.html" index e69de29b..853d0371 100644 --- "a/2016/07/19/CSS\350\203\214\346\231\257\345\233\276\345\261\205\344\270\255/index.html" +++ "b/2016/07/19/CSS\350\203\214\346\231\257\345\233\276\345\261\205\344\270\255/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CSS背景图居中 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

CSS背景图居中

+ + + +
+ + + + + +
+ + + + + +

其实这个东西没什么好说的,可是今天就是因为没搞明白这个background:url() top center no-repeat中的top center被老板骂了,一个1920px的背景图,要在950的屏上居中,我写得是background-size:100% 100%来自适应,哪想到老板说这是自适应不是居中,虽然我的也居中了,但是图片是显示的被压缩的那种,然后老板不厌其烦的跟我说用background:url() top center no-repeat,刚开始我还不信,马丹没想到还真的是居中了,各种被鄙视之后,就去百度了这个属性,基本上就是 “ 背景图相对于标签的显示的位置是顶部,中间铺开 “ ,自己一直觉得写页面布局CSS没什么问题,但是真的还是踩坑了,还被老板打脸,哎,记录一下吧。。另外又有个H5单子找自己,后天要,可是白天上班,晚上回去做,感觉根本来不及,压力蛮大的,所以就没接,现阶段还是多学点东西吧。。会的多了,挣钱以后有的是机会

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/07/21/HTML5\346\211\213\345\212\277\350\247\243\351\224\201/index.html" "b/2016/07/21/HTML5\346\211\213\345\212\277\350\247\243\351\224\201/index.html" index e69de29b..a989d2f6 100644 --- "a/2016/07/21/HTML5\346\211\213\345\212\277\350\247\243\351\224\201/index.html" +++ "b/2016/07/21/HTML5\346\211\213\345\212\277\350\247\243\351\224\201/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HTML5手势解锁 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

HTML5手势解锁

+ + + +
+ + + + + +
+ + + + + +

手机端H5中,实现仿手势解锁,用户按照图标滑出某个图形,即可解锁,效果可见链接
其原理就是:把手势图片分成很多碎段,在touchmove中监听每个触摸坐标是否击中分段图片的开始结尾坐标,如果击中结尾坐标,即把那一段图片显示出来,代码如下:

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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
<html class="hb-loaded ks-webkit537 ks-webkit ks-chrome39 ks-chrome">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=GBK">
<meta charset="gb2312">
<title></title>
<meta name="format-detection" content="telephone=yes">
<meta name="viewport" content="width=device-width,user-scalable=no,initial-scale=1, maximum-scale=1">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="HandheldFriendly" content="true">
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<style>
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,iframe,section{margin:0;padding:0;}
body{font-family:"microsoft yahei";-webkit-text-size-adjust:none;color:#333333;
background:#1f3693 url(http://hubei.sinaimg.cn/ltzt/2014/2014wbzy/zzth5/bg.jpg) no-repeat center top; background-size:cover;}
html{width:100%; height:100%;}
.startpage{width:100%;height:100%;}
.startpage .cont{width:100%;position:relative;}
.startpage .cont .atmain{width:189px;height:188px;position:absolute;top:65%;left:50%;margin:-94px 0 0 -94px;background:url(http://hubei.sinaimg.cn/ltzt/2014/2014wbzy/zzth5/line_18.png);opacity:0;}
.startpage .cont .atmain .atcont{width:189px;height:188px;position:relative;}
.startpage .cont .atmain .atcont .bigxx{width:60px;height:50px;position:absolute;z-index:5;background:url('http://hubei.sinaimg.cn/ltzt/2014/2014wbzy/zzth5/linexx1.png');
transform:scale(1.5,1.5);
-ms-transform:scale(1.5,1.5);
-moz-transform:scale(1.5,1.5);
-webkit-transform:scale(1.5,1.5);
}
.startpage .cont .atmain .atcont .bigxx1{left:89px;top:63px;z-index:5;}

.startpage .cont .atmain .atcont .sxx{width:42px;height:36px;position:absolute;background:url(http://hubei.sinaimg.cn/ltzt/2014/2014wbzy/zzth5/linexxx.png);z-index:5;}
.startpage .cont .atmain .atcont .sxx1{left:63px;top:35px;}
.startpage .cont .atmain .atcont .sxx2{left:35px;top:65px;}
.startpage .cont .atmain .atcont .sxx3{left:42px;top:109px;}
.startpage .cont .atmain .atcont .sxx4{left:85px;top:107px;}
.startpage .cont .atmain .atcont .sxx5{left:136px;top:97px;}
.startpage .cont .atmain .atcont .sxx6{left:136px;top:33px;}
.startpage .cont .atmain .atcont .sxx7{left:79px;top:0px;}
.startpage .cont .atmain .atcont .sxx8{left:17px;top:26px;}
.startpage .cont .atmain .atcont .sxx9{left:-1px;top:89px;}
.startpage .cont .atmain .atcont .sxx10{left:35px;top:143px;}
.startpage .cont .atmain .atcont .sxx11{left:97px;top:152px;}
.startpage .cont .atmain .atcont .sxx12{left:147px;top:131px;}

.startpage .cont .atmain .atcont .atline{position:absolute;z-index:3;display:none;}
.startpage .cont .atmain .atcont .line1{width:60px;height:54px;left:76px;top:33px;}
.startpage .cont .atmain .atcont .line2{width:46px;height:48px;left:33px;top:38px;}
.startpage .cont .atmain .atcont .line3{width:46px;height:46px;left:31px;top:83px;}
.startpage .cont .atmain .atcont .line4{width:70px;height:27px;left:33px;top:123px;}
.startpage .cont .atmain .atcont .line5{width:60px;height:40px;left:75px;top:88px;}
.startpage .cont .atmain .atcont .line6{width:67px;height:40px;left:100px;top:115px;}
.startpage .cont .atmain .atcont .line7{width:44px;height:64px;left:138px;top:54px;}
.startpage .cont .atmain .atcont .line8{width:92px;height:50px;left:89px;top:0px;}
.startpage .cont .atmain .atcont .line9{width:76px;height:42px;left:19px;top:0px;}
.startpage .cont .atmain .atcont .line10{width:54px;height:64px;left:0px;top:42px;}
.startpage .cont .atmain .atcont .line11{width:54px;height:70px;left:0px;top:105px;}
.startpage .cont .atmain .atcont .line12{width:56px;height:36px;left:55px;top:152px;}
.startpage .cont .atmain .atcont .line13{width:70px;height:60px;left:113px;top:127px;}

@keyframes wzout
{
0%{opacity:0;}
100%{opacity:1;}
}
@-ms-keyframes wzout
{
0%{opacity:0;}
100%{opacity:1;}
}
@-moz-keyframes wzout
{
0%{opacity:0;}
100%{opacity:1;}
}
@-webkit-keyframes wzout
{
0%{opacity:0;}
100%{opacity:1;}
}

@keyframes xxsf
{
0%{
transform:scale(1,1);
-ms-transform:scale(1,1);
-moz-transform:scale(1,1);
-webkit-transform:scale(1,1);}
100%{transform:scale(0.5,0.5);
-ms-transform:scale(0.5,0.5);
-moz-transform:scale(0.5,0.5);
-webkit-transform:scale(0.5,0.5);}
}
@-ms-keyframes xxsf
{
0%{
transform:scale(1,1);
-ms-transform:scale(1,1);
-moz-transform:scale(1,1);
-webkit-transform:scale(1,1);}
100%{transform:scale(0.5,0.5);
-ms-transform:scale(0.5,0.5);
-moz-transform:scale(0.5,0.5);
-webkit-transform:scale(0.5,0.5);}
}
@-moz-keyframes xxsf
{
0%{
transform:scale(1,1);
-ms-transform:scale(1,1);
-moz-transform:scale(1,1);
-webkit-transform:scale(1,1);}
100%{transform:scale(0.5,0.5);
-ms-transform:scale(0.5,0.5);
-moz-transform:scale(0.5,0.5);
-webkit-transform:scale(0.5,0.5);}
}
@-webkit-keyframes xxsf
{
0%{
transform:scale(1,1);
-ms-transform:scale(1,1);
-moz-transform:scale(1,1);
-webkit-transform:scale(1,1);}
100%{transform:scale(0.5,0.5);
-ms-transform:scale(0.5,0.5);
-moz-transform:scale(0.5,0.5);
-webkit-transform:scale(0.5,0.5);}
}

@keyframes xxsf1
{
0%{
transform:scale(1.2,1.2);
-ms-transform:scale(1.2,1.2);
-moz-transform:scale(1.2,1.2);
-webkit-transform:scale(1.2,1.2);}
100%{transform:scale(0.5,0.5);
-ms-transform:scale(0.5,0.5);
-moz-transform:scale(0.5,0.5);
-webkit-transform:scale(0.5,0.5);}
}
@-ms-keyframes xxsf1
{
0%{
transform:scale(1.2,1.2);
-ms-transform:scale(1.2,1.2);
-moz-transform:scale(1.2,1.2);
-webkit-transform:scale(1.2,1.2);}
100%{transform:scale(0.5,0.5);
-ms-transform:scale(0.5,0.5);
-moz-transform:scale(0.5,0.5);
-webkit-transform:scale(0.5,0.5);}
}
@-moz-keyframes xxsf1
{
0%{
transform:scale(1.2,1.2);
-ms-transform:scale(1.2,1.2);
-moz-transform:scale(1.2,1.2);
-webkit-transform:scale(1.2,1.2);}
100%{transform:scale(0.5,0.5);
-ms-transform:scale(0.5,0.5);
-moz-transform:scale(0.5,0.5);
-webkit-transform:scale(0.5,0.5);}
}
@-webkit-keyframes xxsf1
{
0%{
transform:scale(1.2,1.2);
-ms-transform:scale(1.2,1.2);
-moz-transform:scale(1.2,1.2);
-webkit-transform:scale(1.2,1.2);}
100%{transform:scale(0.5,0.5);
-ms-transform:scale(0.5,0.5);
-moz-transform:scale(0.5,0.5);
-webkit-transform:scale(0.5,0.5);}
}

.startpage .cont .atmain .ainm .xxact{
animation:xxsf 1s linear 0s infinite alternate;
-ms-animation:xxsf 1s linear 0s infinite alternate;
-moz-animation:xxsf 1s linear 0s infinite alternate;
-webkit-animation:xxsf 1s linear 0s infinite alternate;
}
.startpage .cont .atmain .ainm .xxact1{
animation:xxsf 1s linear 1s infinite alternate;
-ms-animation:xxsf 1s linear 1s infinite alternate;
-moz-animation:xxsf 1s linear 1s infinite alternate;
-webkit-animation:xxsf 1s linear 1s infinite alternate;
}

.startpage .cont .atmain .ainm .xxact3{
animation:xxsf1 .3s linear 0s infinite alternate;
-ms-animation:xxsf1 .3s linear 0s infinite alternate;
-moz-animation:xxsf1 .3s linear 0s infinite alternate;
-webkit-animation:xxsf1 .3s linear 0s infinite alternate;
}


.startpage .cont .p2act1{
animation:wzout .8s ease-out 1s 1 forwards;
-ms-animation:wzout .8s ease-out 1s 1 forwards;
-moz-animation:wzout .8s ease-out 1s 1 forwards;
-webkit-animation:wzout .8s ease-out 1s 1 forwards;
}

</style>
</head>
<body><!-- SUDA_CODE_START -->

<!-- SUDA_CODE_END -->

<div class="startpage">
<div class="cont" style="height: 736px;">
<div class="atmain p2act1" id="atcont">
<div class="atcont ainm">
<p class="bigxx bigxx1 point xxact3"></p>
<p class="sxx sxx1 point xxact"></p>
<p class="sxx sxx2 point xxact1"></p>
<p class="sxx sxx3 point xxact"></p>
<p class="sxx sxx4 point xxact1"></p>
<p class="sxx sxx5 point xxact"></p>
<p class="sxx sxx6 point xxact1"></p>
<p class="sxx sxx7 point xxact"></p>
<p class="sxx sxx8 point xxact1"></p>
<p class="sxx sxx9 point xxact"></p>
<p class="sxx sxx10 point xxact1"></p>
<p class="sxx sxx11 point xxact"></p>
<p class="sxx sxx12 point xxact1"></p>

<p class="atline line1"><img src="img/line1.png"></p>
<p class="atline line2"><img src="img/line2.png"></p>
<p class="atline line3"><img src="img/line3.png"></p>
<p class="atline line4"><img src="img/line4.png"></p>
<p class="atline line5"><img src="img/line5.png"></p>
<p class="atline line6"><img src="img/line6.png"></p>
<p class="atline line7"><img src="img/line7.png"></p>
<p class="atline line8"><img src="img/line8.png"></p>
<p class="atline line9"><img src="img/line9.png"></p>
<p class="atline line10"><img src="img/line10.png"></p>
<p class="atline line11"><img src="img/line11.png"></p>
<p class="atline line12"><img src="img/line12.png"></p>
<p class="atline line13"><img src="img/line13.png"></p>
</div>

</div>

</div>
</div>
<script>
$(function(){

var pointArr = [];
var points;
var start = true;
var end = false;
var tolerance = 30;

var getPointWz = function(){
var offset,w,h;
points = $("#atcont .point");
for(i=0;i<points.length;i++){
offset = points.eq(i).offset();
w = points.eq(i).width()/2;
h = points.eq(i).height()/2;
pointArr[i] = [];
pointArr[i][0] = parseInt(offset.left) + w;
pointArr[i][1] = parseInt(offset.top) + h;
pointArr[i][2] = false;
}
}

var getPointXY = function(x,y,n){
var tXX,tYY,tFF;
tXX = x - pointArr[n][0];
tXX = tXX < 0 ? tXX * -1 : tXX;
tYY = y - pointArr[n][1];
tYY = tYY < 0 ? tYY * -1 : tYY;
tFF = pointArr[n][2];
return{
x : tXX,
y : tYY,
f : tFF
}
}

var atobj = document.getElementById('atcont');

atobj.addEventListener('touchstart', function(event) {
event.preventDefault();
getPointWz();
var x,y,xy;
start = false;
var touch = event.targetTouches[0];

x = touch.pageX;
y = touch.pageY;

$(".atcont").removeClass("ainm");

//$("#wzx span").text(x);
//$("#wzy span").text(y);

if(!end){
xy = getPointXY(x,y,0);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[0][2] = true;
}
}
//$("#fhx span").text(x);
//$("#fhy span").text(y);
//$("#fhff span").text(pointArr[0][2]);
}, false);

atobj.addEventListener('touchmove', function(event) {
event.preventDefault();
if(start) return false;
var x,y,xy;
var touch = event.targetTouches[0];

x = touch.pageX;
y = touch.pageY;

//$("#wzx span").text(x);
//$("#wzy span").text(y);
//$("#fhff span").text(pointArr[0][2]);

if(!end){
if(pointArr[0][2] && !pointArr[1][2]){
xy = getPointXY(x,y,1);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[1][2] = true;
$("#atcont .atline:eq(0)").fadeIn(200);
}
//$("#fhx span").text(x);
//$("#fhy span").text(y);
//$("#fhff span").text(pointArr[1][2]);
}else if(pointArr[1][2] && !pointArr[2][2]){
xy = getPointXY(x,y,2);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[2][2] = true;
$("#atcont .atline:eq(1)").fadeIn(200);
}
}else if(pointArr[2][2] && !pointArr[3][2]){
xy = getPointXY(x,y,3);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[3][2] = true;
$("#atcont .atline:eq(2)").fadeIn(200);
}
}else if(pointArr[3][2] && !pointArr[4][2]){
xy = getPointXY(x,y,4);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[4][2] = true;
$("#atcont .atline:eq(3)").fadeIn(200);
$("#atcont .atline:eq(4)").fadeIn(200);
}
}else if(pointArr[4][2] && !pointArr[5][2]){
xy = getPointXY(x,y,5);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[5][2] = true;
$("#atcont .atline:eq(5)").fadeIn(200);
}
}else if(pointArr[5][2] && !pointArr[6][2]){
xy = getPointXY(x,y,6);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[6][2] = true;
$("#atcont .atline:eq(6)").fadeIn(200);
}
}else if(pointArr[6][2] && !pointArr[7][2]){
xy = getPointXY(x,y,7);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[7][2] = true;
$("#atcont .atline:eq(7)").fadeIn(200);
}
}else if(pointArr[7][2] && !pointArr[8][2]){
xy = getPointXY(x,y,8);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[8][2] = true;
$("#atcont .atline:eq(8)").fadeIn(200);
}
}else if(pointArr[8][2] && !pointArr[9][2]){
xy = getPointXY(x,y,9);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[9][2] = true;
$("#atcont .atline:eq(9)").fadeIn(200);
}
}else if(pointArr[9][2] && !pointArr[10][2]){
xy = getPointXY(x,y,10);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[10][2] = true;
$("#atcont .atline:eq(10)").fadeIn(200);
}
}else if(pointArr[10][2] && !pointArr[11][2]){
xy = getPointXY(x,y,11);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[11][2] = true;
$("#atcont .atline:eq(11)").fadeIn(200);
}
}else if(pointArr[11][2] && !pointArr[12][2]){
xy = getPointXY(x,y,12);
x = xy.x;
y = xy.y;
if(x <= tolerance && y <= tolerance){
pointArr[12][2] = true;
$("#atcont .atline:eq(12)").fadeIn(200);
end = true;
}
}
}
}, false);

atobj.addEventListener('touchend', function(event) {
event.preventDefault();
start = true;

$(".atcont").addClass("ainm");

if(!end){
$("#atcont .atline").fadeOut(200);
}else{
setTimeout(function(){
$(".startpage").fadeOut(800);
setTimeout(function(){
$("#wbzymain").fadeIn(500);
}, 850);
}, 1000);
//$(".banner span").text('搞定');
}
}, false);

})
</script>
</body>
</html>

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/07/21/html\351\241\265\351\235\242\346\210\252\345\261\217\351\201\207\345\210\260\347\232\204\350\267\250\345\237\237\351\227\256\351\242\230\350\256\260\345\275\225\350\264\264/index.html" "b/2016/07/21/html\351\241\265\351\235\242\346\210\252\345\261\217\351\201\207\345\210\260\347\232\204\350\267\250\345\237\237\351\227\256\351\242\230\350\256\260\345\275\225\350\264\264/index.html" index e69de29b..58017561 100644 --- "a/2016/07/21/html\351\241\265\351\235\242\346\210\252\345\261\217\351\201\207\345\210\260\347\232\204\350\267\250\345\237\237\351\227\256\351\242\230\350\256\260\345\275\225\350\264\264/index.html" +++ "b/2016/07/21/html\351\241\265\351\235\242\346\210\252\345\261\217\351\201\207\345\210\260\347\232\204\350\267\250\345\237\237\351\227\256\351\242\230\350\256\260\345\275\225\350\264\264/index.html" @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + html页面截屏遇到的跨域问题记录贴 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

html页面截屏遇到的跨域问题记录贴

+ + + +
+ + + + + +
+ + + + + +

canvas在截屏的时候,先用drawImage再用toDataURL,如果图片的链接中域名不是自己的域名,会报错提示跨域问题,解决办法就是从后端请求图片到前端,把图片转换成64位码,这样就不会有跨域的问题了。贴下主要代码:

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
window.onload = function(){
convertImgToBase64('图片链接', function(base64Img){
div.setAttribute("src", base64Img);
});
var canvas;
var div = document.getElementById("ceshi");
html2canvas(div,{canvas:canvas}).then(function(canvas){
document.body.appendChild(canvas);
canvas.toDataURL();//截屏的图片64位码
})
}
function convertImgToBase64(url, callback, outputFormat){
var canvas = document.createElement('CANVAS'),
ctx = canvas.getContext('2d'),
img = new Image;
img.crossOrigin = 'Anonymous';
img.onload = function(){
canvas.height = img.height;
canvas.width = img.width;
ctx.drawImage(img,0,0);
var dataURL = canvas.toDataURL(outputFormat || 'image/png');
callback.call(this, dataURL);
canvas = null;
};
img.src = url;
}

+

不过应该很少有人遇到这个问题,因为有条件的人,图片都在自己服务器上,可以我这个活儿图片不能放在自己服务器上,所以只能这样搞了

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/08/12/css\345\212\250\347\224\273\346\211\247\350\241\214\345\256\214\346\215\242\345\217\246\344\270\200\344\270\252\345\212\250\347\224\273/index.html" "b/2016/08/12/css\345\212\250\347\224\273\346\211\247\350\241\214\345\256\214\346\215\242\345\217\246\344\270\200\344\270\252\345\212\250\347\224\273/index.html" index e69de29b..3bba8fe1 100644 --- "a/2016/08/12/css\345\212\250\347\224\273\346\211\247\350\241\214\345\256\214\346\215\242\345\217\246\344\270\200\344\270\252\345\212\250\347\224\273/index.html" +++ "b/2016/08/12/css\345\212\250\347\224\273\346\211\247\350\241\214\345\256\214\346\215\242\345\217\246\344\270\200\344\270\252\345\212\250\347\224\273/index.html" @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + css动画执行完换另一个动画 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

css动画执行完换另一个动画

+ + + +
+ + + + + +
+ + + + + +

animation有三个事件,在入场动画执行完想换成另一个循环动画时,用webkitAnimationEnd 事件:

1
2
3
4
$(document).on("webkitAnimationEnd", ".p34", function(){
$(".p34").removeClass('入场动画类');
$(".p34").addClass('循环动画类')
})

+

拓展:animation共有3个事件:可在需要时使用
开始事件 webkitAnimationStart
结束事件 webkitAnimationEnd
重复运动事件 webkitAnimationIteration
css3的过渡属性transition,在动画结束时,也存在结束的事件:webkitTransitionEnd
transition仅仅有这一个事件

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/08/12/\345\212\240\350\275\275img\345\233\276\347\211\207\347\231\276\345\210\206\346\257\224/index.html" "b/2016/08/12/\345\212\240\350\275\275img\345\233\276\347\211\207\347\231\276\345\210\206\346\257\224/index.html" index e69de29b..1968b138 100644 --- "a/2016/08/12/\345\212\240\350\275\275img\345\233\276\347\211\207\347\231\276\345\210\206\346\257\224/index.html" +++ "b/2016/08/12/\345\212\240\350\275\275img\345\233\276\347\211\207\347\231\276\345\210\206\346\257\224/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 加载img图片百分比 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

加载img图片百分比

+ + + +
+ + + + + +
+ + + + + +

首先在html中图片要用img标签,div的background在这里不适用,接着就是加载img图片,根据图片加载状态来计算百分比:

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
var jiazai = 0;
var imgs = document.getElementsByTagName("img");
var imgLen = imgs.length;
for(var i = 0; i < imgLen; i++){
if(imgs[i].complete){ //如果缓存里有这张图片,就是触发complete
jiazai++;
var baifenbi = Math.floor(jiazai/imgLen*100);
setBaiNum(baifenbi);
continue;
}
imgs[i].onload = function(){ //图片加载
jiazai++;
var baifenbi = Math.floor(jiazai/imgLen*100);
setBaiNum(baifenbi);
}
}
function setBaiNum(bai){
$("#baifen_txt").text(bai); //设置百分数到DOM上
if(bai == 100){ //图片加载完毕
setTimeout(function(){
// 显示视图;
}, 1000);

}
}

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/08/25/\346\211\213\346\234\272\347\253\257\351\241\265\351\235\242\347\233\221\346\265\213\346\250\252\345\261\217\347\253\226\345\261\217/index.html" "b/2016/08/25/\346\211\213\346\234\272\347\253\257\351\241\265\351\235\242\347\233\221\346\265\213\346\250\252\345\261\217\347\253\226\345\261\217/index.html" index e69de29b..821a13ed 100644 --- "a/2016/08/25/\346\211\213\346\234\272\347\253\257\351\241\265\351\235\242\347\233\221\346\265\213\346\250\252\345\261\217\347\253\226\345\261\217/index.html" +++ "b/2016/08/25/\346\211\213\346\234\272\347\253\257\351\241\265\351\235\242\347\233\221\346\265\213\346\250\252\345\261\217\347\253\226\345\261\217/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 手机端页面监测横屏竖屏 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

手机端页面监测横屏竖屏

+ + + +
+ + + + + +
+ + + + + +

在做手机端网页时,如果没有做横竖屏自适应,那么横竖屏监测是个很好的用户体验@#¥%……%*&……%代码:

1
2
3
4
5
6
7
8
var updateOrientation = function(){
if(window.orientation == '-90' || window.orientation == '90'){
alert("请将手机竖屏");
}else{
alert("现在是竖屏");
}
}
window.onorientationchange = updateOrientation;

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/09/01/\346\211\213\346\234\272\347\253\257\351\207\215\345\212\233\346\204\237\345\272\224\346\216\245\345\217\243\345\217\212\345\272\224\347\224\250/index.html" "b/2016/09/01/\346\211\213\346\234\272\347\253\257\351\207\215\345\212\233\346\204\237\345\272\224\346\216\245\345\217\243\345\217\212\345\272\224\347\224\250/index.html" index e69de29b..1dbdd095 100644 --- "a/2016/09/01/\346\211\213\346\234\272\347\253\257\351\207\215\345\212\233\346\204\237\345\272\224\346\216\245\345\217\243\345\217\212\345\272\224\347\224\250/index.html" +++ "b/2016/09/01/\346\211\213\346\234\272\347\253\257\351\207\215\345\212\233\346\204\237\345\272\224\346\216\245\345\217\243\345\217\212\345\272\224\347\224\250/index.html" @@ -0,0 +1,721 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 手机端重力感应接口及应用 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

手机端重力感应接口及应用

+ + + +
+ + + + + +
+ + + + + +

现在微信开发如火如荼,各种基于微信的H5市场上也是很火爆,今天做个笔记就是跟大家分享手机端重力感应的应用,根据重力感应接口我们可以得到手机的方向,移动速度,xyz轴偏移量,现在先上所有数据展示,大家有兴趣的也可以亲身测试:

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
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8"/>
<title>H5获取陀螺仪/重力感应(参考网上资源)</title>
<meta name="viewport"
content="width=device-width,initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no,target-densitydpi=device-dpi"/>
<style type="text/css">
body{font-size: 24px;}
span{color:#f00;}
a{text-decoration: none;color:#f00;}
a:hover{color:#000;}
</style>
</head>

<body>
<!--
DeviceOrientationEvent是获取方向,得到device静止时的绝对值;
DeviceMotionEvent是获取移动速度,得到device移动时相对之前某个时间的差值比
设备定位API,该API允许你收集设备的方向和移动信息。此外,该API只在具备陀螺仪功能的设备上使用。
-->
<h3>请用手机浏览器访问</h3>
<p>EGRET白鹭版降临:<br/><a href="http://weixin.shinycg.com/weixin/DeviceOrientation" target="_blank">http://weixin.shinycg.com/weixin/DeviceOrientation</a></p>
<p>左右:<span id="alpha">0</span></p>
<p>前后:<span id="beta">0</span></p>
<p>扭转:<span id="gamma">0</span></p>
<p>指北针指向:<span id="heading">0</span></p>
<p>指北针精度:<span id="accuracy">0</span></p>
<hr/>
<p>x轴加速度:<span id="x">0</span>米每二次方秒</p>
<p>y轴加速度:<span id="y">0</span>米每二次方秒</p>
<p>z轴加速度:<span id="z">0</span>米每二次方秒</p>
<hr/>
<p>x轴加速度(考虑重力加速度):<span id="xg">0</span>米每二次方秒</p>
<p>y轴加速度(考虑重力加速度):<span id="yg">0</span>米每二次方秒</p>
<p>z轴加速度(考虑重力加速度):<span id="zg">0</span>米每二次方秒</p>
<hr/>
<p>左右旋转速度:<span id="Ralpha">0</span>度每秒</p>
<p>前后旋转速度:<span id="Rbeta">0</span>度每秒</p>
<p>扭转速度:<span id="Rgamma">0</span>度每秒</p>
<hr/>
<p>上次收到通知的间隔:<span id="interval">0</span>毫秒</p>

<script type="text/javascript">

init();
function init(){
if (window && window.DeviceMotionEvent)
window.addEventListener("devicemotion", motionHandler, false);
if (window && window.DeviceOrientationEvent)
window.addEventListener("deviceorientation", orientationHandler, false);
}

function orientationHandler(event) {
document.getElementById("alpha").innerHTML = event.alpha||0;
document.getElementById("beta").innerHTML = event.beta||0;
document.getElementById("gamma").innerHTML = event.gamma||0;
document.getElementById("heading").innerHTML = event.webkitCompassHeading||0;
document.getElementById("accuracy").innerHTML = event.webkitCompassAccuracy||0;
}

function motionHandler(event) {
document.getElementById("interval").innerHTML = event.interval||0;
var acc = event.acceleration;
document.getElementById("x").innerHTML = acc.x||0;
document.getElementById("y").innerHTML = acc.y||0;
document.getElementById("z").innerHTML = acc.z||0;
var accGravity = event.accelerationIncludingGravity;
document.getElementById("xg").innerHTML = accGravity.x||0;
document.getElementById("yg").innerHTML = accGravity.y||0;
document.getElementById("zg").innerHTML = accGravity.z||0;
var rotationRate = event.rotationRate;
document.getElementById("Ralpha").innerHTML = rotationRate.alpha||0;
document.getElementById("Rbeta").innerHTML = rotationRate.beta||0;
document.getElementById("Rgamma").innerHTML = rotationRate.gamma||0;
}

</script>
</body>
</html>

+

以上是重力感应接口所有的参数,那么根据这些参数我们就可以做出:
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
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#ceshi{
font-size: 50px;
}
</style>
</head>
<body>
<div id="ceshi"></div>
<script>
function init(){
  if (window.DeviceMotionEvent) {
    // 移动浏览器支持运动传感事件
    window.addEventListener('devicemotion', deviceMotionHandler, false);
    
  }
}

// 那么,我们如何计算用户是否是在摇动手机呢?可以从以下几点进行考虑:
// 1、其实用户在摇动手机的时候始终都是以一个方向为主进行摇动的;
// 2、用户在摇动手机的时候在x、y、z三个方向都会有相应的想速度的变化;
// 3、不能把用户正常的手机运动行为当做摇一摇(手机放在兜里,走路的时候也会有加速度的变化)。
// 从以上三点考虑,针对三个方向上的加速度进行计算,间隔测量他们,考察他们在固定时间段里的变化率,而且需要确定一个阀值来触发摇一摇之后的操作。

// 首先,定义一个摇动的阀值
var SHAKE_THRESHOLD = 3000;
// 定义一个变量保存上次更新的时间
var last_update = 0;
// 紧接着定义x、y、z记录三个轴的数据以及上一次触发的时间
var x;
var y;
var z;
var last_x;
var last_y;
var last_z;

// 为了增加这个例子的一点无聊趣味性,增加一个计数器
var count = 0;

function deviceMotionHandler(eventData) {
  // 获取含重力的加速度
  var acceleration = eventData.accelerationIncludingGravity;
  // 获取当前时间
  var curTime = new Date().getTime();
  var diffTime = curTime -last_update;
  // 固定时间段
  if (diffTime > 100) {
    last_update = curTime;
    x = acceleration.x;
    y = acceleration.y;
    z = acceleration.z;
    var speed = Math.abs(x + y + z - last_x - last_y - last_z) / diffTime * 10000;
    if (speed > SHAKE_THRESHOLD) {
      // TODO:在此处可以实现摇一摇之后所要进行的数据逻辑操作
      count++;
      document.getElementById("ceshi").innerHTML = count;      
    }
    last_x = x;
    last_y = y;
    last_z = z;
  }
}
init()
</script>
</body>
</html>

+

2、左右偏移角度,手机平放是0度,往左偏就是负数度,往右同理,根据这个接口我们就可以做:飞机大战,根据偏转角度来实现主角飞机在屏幕中的移动,可以参考我做的demo:http://www.sanmuweb.com/shoot/index.html(手机端才能正常试玩),效果略简陋,但是逻辑通了。

+

3、还有个跟重力感应相关的插件就是parallax.js,这个插件在电脑端可以通过鼠标实现图片的分层偏移,手机端可以通过重力感应实现,见demo:http://www.sanmuweb.com/zhongli3.html

+

OK,记录一下,欢迎交流。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/09/03/animate-css\351\205\215\345\220\210JS\347\232\204\344\275\277\347\224\250/index.html" "b/2016/09/03/animate-css\351\205\215\345\220\210JS\347\232\204\344\275\277\347\224\250/index.html" index e69de29b..d41875c2 100644 --- "a/2016/09/03/animate-css\351\205\215\345\220\210JS\347\232\204\344\275\277\347\224\250/index.html" +++ "b/2016/09/03/animate-css\351\205\215\345\220\210JS\347\232\204\344\275\277\347\224\250/index.html" @@ -0,0 +1,721 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + animate.css配合JS的使用 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

animate.css配合JS的使用

+ + + +
+ + + + + +
+ + + + + +

刚刚在前端群里看到有人问animate如何配合JS使用,再给他讲解了一下后觉得应该在博客中记录下来,以能帮到更多人的更好的使用animate.css,其实这个CSS库在动效方面蛮好用的,记得我之前面试公司的考试就是做一个动效类的H5,那时候我用的是jqueryUI的库,放在手机上非常的庞大,也略卡顿,划过下一页之后再滑到上一页,就没有动效了。后来去了公司之后才知道的animate.css类库,于是自己又结合JS封装一下方法,页面之间的滑动不管滑多少次都会重新展示动画,废话不多说,上代码:
1、首先引入animate.CSS库和zepto库。

+

2、HTML的代码这样写:

1
2
3
4
5
6
<div class="page page1 animated fadeIn hide">						
<img src="p11.png" class="pos_abs animated p11" data-class="bounceInDown" data-delay="0.3s">
<img src="p12.png" class="pos_abs animated p12" data-class="bounceIn" data-delay="1.3s">
<img src="p13.png" class="pos_abs animated p13" data-class="fadeInUp" data-delay="2.3s">
<img src="p14.png" class="pos_abs animated p14" data-class="fadeInUp1 infinite" data-delay="3.3s" alt="">
</div>

+

animated是需要有动效的元素,data-class是动画效果名称,data-delay是元素延时时间,通过延时时间的排列来达到展示动画的衔接。

+

3、

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
(function(globle){
var ff = (function(){
return{
num: 1,
divHtmlArr:[],
total : $(".page").length,
next : function(){
if(this.num < this.total){
$(".page" + this.num).addClass("fadeOut hide");
this.initHtml(this.num-1, $(".page" + this.num));
this.num++;
this.setAnimation(this.num);
}
},
setHtml : function (index,div){
if(!this.divHtmlArr[index]){
this.divHtmlArr[index] = div; //将每一屏代码存放到数组
}
},
getHtml : function (div){ //获取html代码
return $(div).html();
},
initHtml : function (index,div){ //初始化html代码
$(div).html(this.divHtmlArr[index]);
},
last : function(){
if(this.num > 1){
$(".page" + this.num).addClass("fadeOut hide");
this.initHtml(this.num-1, $(".page" + this.num));
this.num--;
this.setAnimation(this.num);
}
},
setAnimation : function(pageNum){
var html = this.getHtml($(".page" + pageNum));
this.setHtml(pageNum-1, html);
$(".page" + pageNum).removeClass("fadeOut hide");
var AnimateImg = $(".page" + pageNum).find(".animated");
$(AnimateImg).each(function(index, value){
var animationStyle = $(this).data("class");
var animationDelay = $(this).data("delay");
$(this).addClass(animationStyle).css({
"animation-delay":animationDelay,
"-webkit-animation-delay":animationDelay
});
})
},
IsPC : function() {
var userAgentInfo = navigator.userAgent;
var Agents = ["Android", "iPhone",
"SymbianOS", "Windows Phone",
"iPad", "iPod"];
var flag = true;
for (var v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
},
autoView : function(userAgent){
var screen_w=parseInt(window.screen.width),scale=screen_w/640;
if(/Android (\d+\.\d+)/.test(userAgent)){
var version=parseFloat(RegExp.$1);
$("head").prepend(version>2.3?'<meta id="auto_view" name="viewport" content="width=640, initial-scale = '+scale+',user-scalable=1, minimum-scale = '+scale+', maximum-scale = '+scale+', target-densitydpi=device-dpi">':'<meta name="viewport" content="width=640, target-densitydpi=device-dpi">');
}else{
$("head").prepend('<meta id="auto_view" name="viewport" content="width=640, initial-scale = '+scale+' ,minimum-scale = '+scale+', maximum-scale = '+scale+', user-scalable=no, target-densitydpi=device-dpi">');
};
if(this.IsPC()){
document.body.style.margin = "0px auto";
}
},
loadImg : function(){
var totalNum = 0;
var jiazai = 0;
var imgs = document.getElementsByTagName("img");
var imgLen = imgs.length;
function setBaiNum(bai){
$("#baifen_txt").text(bai);
if(bai == 100){
setTimeout(function(){
$(".p1_close").addClass('hide');
ff.setAnimation(1);

}, 500);

}
}
for(var i = 0; i < imgLen; i++){
if(imgs[i].complete){
jiazai++;
var baifenbi = Math.floor(jiazai/imgLen*100);
setBaiNum(baifenbi);
continue;
}
imgs[i].onload = function(){
jiazai++;
var baifenbi = Math.floor(jiazai/imgLen*100);
setBaiNum(baifenbi);

}
}
},
toPage: function(num){
$(".page" + this.num).addClass('hide');
ff.setAnimation(num);
ff.num = num;
}
}
})();
globle.ff = ff;
})(this);

+

这是我对整个动效js的封装的一个对象,在编写好HTML后,直接复制这个代码,当前页滑到下一页可以调用ff.next(),若要通过按钮的点击来滑到某一页就调用ff.toPage(num)。setHtml()、getHtml()的方法是为了初始化HTML代码,以便滑到上一页的时候可以再次展示动效。
注意一点:绑定点击事件用$(document).on(“click”,“.class”,function(){})的方式来绑定。如果用普通的$(“.class”).click(function(){})这种方法来绑定的话,setHtml()方法会把绑定在元素上的事件也抹掉。
(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/09/07/blob\345\257\271\350\261\241\344\271\213\344\270\212\344\274\240\345\233\276\347\211\207\346\234\254\345\234\260\351\242\204\350\247\210/index.html" "b/2016/09/07/blob\345\257\271\350\261\241\344\271\213\344\270\212\344\274\240\345\233\276\347\211\207\346\234\254\345\234\260\351\242\204\350\247\210/index.html" index e69de29b..47567a85 100644 --- "a/2016/09/07/blob\345\257\271\350\261\241\344\271\213\344\270\212\344\274\240\345\233\276\347\211\207\346\234\254\345\234\260\351\242\204\350\247\210/index.html" +++ "b/2016/09/07/blob\345\257\271\350\261\241\344\271\213\344\270\212\344\274\240\345\233\276\347\211\207\346\234\254\345\234\260\351\242\204\350\247\210/index.html" @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + blob对象之上传图片本地预览 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

blob对象之上传图片本地预览

+ + + +
+ + + + + +
+ + + + + +

看到网上有人说blob上传图片到服务器,相对Base64来说是个更好的选择,于是自己尝试了下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<input id="choose" type="file" value="选择">
<img id="img" src="" alt="" height="100px">
<script>
var choose = document.getElementById("choose");
var img = document.getElementById("img");
choose.onchange = function (e){
var f = e.target.files[0];
var src = window.URL.createObjectURL(f);
img.src = src;
}
</script>
</body>
</html>

+

以上即可实现了选择图片本地预览。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/09/14/\346\211\213\346\234\272\347\253\257\345\277\253\351\200\237\347\202\271\345\207\273\346\214\211\351\222\256\346\222\255\346\224\276\351\237\263\346\225\210\347\232\204\344\274\230\345\214\226/index.html" "b/2016/09/14/\346\211\213\346\234\272\347\253\257\345\277\253\351\200\237\347\202\271\345\207\273\346\214\211\351\222\256\346\222\255\346\224\276\351\237\263\346\225\210\347\232\204\344\274\230\345\214\226/index.html" index e69de29b..733498a5 100644 --- "a/2016/09/14/\346\211\213\346\234\272\347\253\257\345\277\253\351\200\237\347\202\271\345\207\273\346\214\211\351\222\256\346\222\255\346\224\276\351\237\263\346\225\210\347\232\204\344\274\230\345\214\226/index.html" +++ "b/2016/09/14/\346\211\213\346\234\272\347\253\257\345\277\253\351\200\237\347\202\271\345\207\273\346\214\211\351\222\256\346\222\255\346\224\276\351\237\263\346\225\210\347\232\204\344\274\230\345\214\226/index.html" @@ -0,0 +1,721 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 手机端快速点击按钮播放音效的优化 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

手机端快速点击按钮播放音效的优化

+ + + +
+ + + + + +
+ + + + + +

今天突发奇想,想试一个在手机端点击按钮,播放音效的效果,这种效果可以用来作为射击子弹,发生碰撞时出现的音效。原理不难,就是添加audio标签,设置MP3地址,然后播放。但是细心的同学就会发现在快速点击按钮时,每一次创建audio标签,然后设置src,就会对一次对音频文件的请求,这样是很不好的,在测试了一番后,总结出了两种解决方法。
1、当点击的时候,先判断前面的audio标签是否播放完毕,上码:

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
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<input type="button" value="播放" id="btn">
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
var audioArr = document.getElementsByTagName("audio");
for(var i = 0; i < audioArr.length; i++){
if(audioArr[i].ended){
audioArr[i].play();
return;
}
}
var audio = document.createElement("audio");
audio.src=audio.src || "http://chongqing.sinaimg.cn/20160913_hack/GameSpawn.mp3";
document.body.appendChild(audio);
audio.autoplay = 'autoplay';
audio.play();
// console.log(audio.ended);
// if(audioArr.length != 0){
// // audioArr[0].pause();
// audioArr[0].currentTime = 0;
// audioArr[0].play();
// }else{
// var audio = document.createElement("audio");
// audio.src = "http://chongqing.sinaimg.cn/20160913_hack/GameSpawn.mp3";
// document.body.appendChild(audio);
// audio.autoplay = 'autoplay';
// audio.play();
// }
}
</script>
</body>
</html>

+

这样的话,刚开始会多加载几次资源,加载的最多数就是你点击的最快数。当你点不到那么快时,这种是很好的优化方法。

+

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
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<input type="button" value="播放" id="btn">
<script>
var btn = document.getElementById("btn");
btn.onclick = function(){
var audioArr = document.getElementsByTagName("audio");
// for(var i = 0; i < audioArr.length; i++){
// if(audioArr[i].ended){
// audioArr[i].play();
// return;
// }
// }
// var audio = document.createElement("audio");
// audio.src=audio.src || "http://chongqing.sinaimg.cn/20160913_hack/GameSpawn.mp3";
// document.body.appendChild(audio);
// audio.autoplay = 'autoplay';
// audio.play();
// console.log(audio.ended);

if(audioArr.length != 0){
// audioArr[0].pause();
audioArr[0].currentTime = 0;
audioArr[0].play();
}else{
var audio = document.createElement("audio");
audio.src = "http://chongqing.sinaimg.cn/20160913_hack/GameSpawn.mp3";
document.body.appendChild(audio);
audio.autoplay = 'autoplay';
audio.play();
}
}
</script>
</body>
</html>

+

这种方法只会请求一次资源,但是在手机端播放效果不如第一种方法理想。

+

总结:所以总的来说,建议还是第一种比较好,另外看create.js对音效的处理也是按第一种方式来的。
另外在手机端要把onclick换成ontouchstart。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/09/20/JS\350\207\252\345\256\232\344\271\211\345\233\236\350\260\203\345\207\275\346\225\260/index.html" "b/2016/09/20/JS\350\207\252\345\256\232\344\271\211\345\233\236\350\260\203\345\207\275\346\225\260/index.html" index e69de29b..6e5dc3d5 100644 --- "a/2016/09/20/JS\350\207\252\345\256\232\344\271\211\345\233\236\350\260\203\345\207\275\346\225\260/index.html" +++ "b/2016/09/20/JS\350\207\252\345\256\232\344\271\211\345\233\236\350\260\203\345\207\275\346\225\260/index.html" @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + JS自定义回调函数 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

JS自定义回调函数

+ + + +
+ + + + + +
+ + + + + +

对于jQuery的回调函数,想搞懂他的原理,然后又想到了之前在公司的代码框架里就有自定义回调函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
function a(callback){
console.log(1);
console.log(2);
if(callback){callback();}
}
function b(){
console.log("回调B");
}
function c(){
console.log("回调C");
}
a(b);
a(c);
</script>
</body>
</html>

+

简单来说,就是传参。记录之

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/09/20/\346\236\204\351\200\240\345\207\275\346\225\260\345\222\214\345\216\237\345\236\213\347\232\204\345\274\202\345\220\214/index.html" "b/2016/09/20/\346\236\204\351\200\240\345\207\275\346\225\260\345\222\214\345\216\237\345\236\213\347\232\204\345\274\202\345\220\214/index.html" index e69de29b..164df580 100644 --- "a/2016/09/20/\346\236\204\351\200\240\345\207\275\346\225\260\345\222\214\345\216\237\345\236\213\347\232\204\345\274\202\345\220\214/index.html" +++ "b/2016/09/20/\346\236\204\351\200\240\345\207\275\346\225\260\345\222\214\345\216\237\345\236\213\347\232\204\345\274\202\345\220\214/index.html" @@ -0,0 +1,727 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 构造函数和原型的异同 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

构造函数和原型的异同

+ + + +
+ + + + + +
+ + + + + +

有两种写法:
1、

1
2
3
4
5
6
7
8
9
10
11
12
13
function a(age){
this.name = "sam";
this.age = age;
var that = this;
this.getAge = function(){
return that.age;
}
}
// a.prototype.getAge = function() {
// return this.age;
// };
var B = new a(200);//200
var C = new a(300);//300

+

2、

1
2
3
4
5
6
7
8
9
10
11
12
13
function a(age){
this.name = "sam";
this.age = age;
var that = this;
// this.getAge = function(){
// return that.age;
// }
}
a.prototype.getAge = function() {
return this.age;
};
var B = new a(200);//200
var C = new a(300);/300

+

以上两种写法虽然执行结果相同,但是原理却不同,第一种是通过构造函数生成实例,第二种是通过prototype原型。他们的不同体现在:
1、两个实例的getAge函数指向不同:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function a(age){
this.name = "sam";
this.age = age;
var that = this;
// this.getAge = function(){
// return that.age;
// }
}
a.prototype.getAge = function() {
return this.age;
};
var B = new a(200);
var C = new a(300);
console.log(B.getAge == C.getAge); //true
console.log(C.getAge);

+

原型的函数指向的都是同一个函数。

+

构造函数指向的确是不同的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function a(age){
this.name = "sam";
this.age = age;
var that = this;
this.getAge = function(){
return that.age;
}
}
// a.prototype.getAge = function() {
// return this.age;
// };
var B = new a(200);
var C = new a(300);
console.log(B.getAge == C.getAge); //false
console.log(C.getAge);

+

2、第二点不同就是生成的实例会占用内存,大量的实例就会出现网页卡顿的情况,比如飞机大战中,每个子弹每个飞机都是实例的话,他们去做碰撞检测时会明显的卡顿,所以尽量写成原型的函数,这样逼格也更高,js代码更优雅。

+

/**更新**/
再看两种写法的对比:
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
function ceshi(){
var current = 1;
function a(){current++;console.log(current);}
function b(){console.log('b');}
function c(){console.log('c');}
return {
a:a,
b:b,
c:c
}
};
var CESHI = new ceshi();
var CESHI2 = new ceshi();
console.log(CESHI.a == CESHI2.a);//false
CESHI.a();//2
CESHI2.a();//2
</script>
</body>
</html>

+

这种就是生成实例,两个实例的指向不同,所以不相等,CESHI和CESHI2没有任何关联。

+

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
ceshi = function (){
var current = 1;
function a(){current++;console.log(current);}
function b(){console.log('b');}
function c(){console.log('c');}
return {
a:a,
b:b,
c:c
}
}();
ceshi.a();//2
ceshi.a();//3
console.log(ceshi.a == ceshi.a);//true
</script>
</body>
</html>

+

这种写法形成了闭包,可以通过ceshi这个变量访问内部变量,所以指向的a()也是相同的。

+

/*更新*/
封装模块写法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
(function(globle){
var module = (function(){
var data = "sectet";
return {
bool : true,
string: "a string",
array : [1, 2, 3, 4, 5],
object : {
lang : 'en-US'
},
getData : function(){
return data;
},
setData : function(value){
return (data = value)
}
};
})();
globle.module = module;
})(this);
module.setData(3);
console.log(module.getData())

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/10/18/HTML-id\346\240\207\347\255\276\344\274\232\350\207\252\345\212\250\347\224\237\346\210\220\345\205\250\345\261\200\345\217\230\351\207\217/index.html" "b/2016/10/18/HTML-id\346\240\207\347\255\276\344\274\232\350\207\252\345\212\250\347\224\237\346\210\220\345\205\250\345\261\200\345\217\230\351\207\217/index.html" index e69de29b..ef9f20d0 100644 --- "a/2016/10/18/HTML-id\346\240\207\347\255\276\344\274\232\350\207\252\345\212\250\347\224\237\346\210\220\345\205\250\345\261\200\345\217\230\351\207\217/index.html" +++ "b/2016/10/18/HTML-id\346\240\207\347\255\276\344\274\232\350\207\252\345\212\250\347\224\237\346\210\220\345\205\250\345\261\200\345\217\230\351\207\217/index.html" @@ -0,0 +1,718 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HTML id标签会自动生成全局变量 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

HTML id标签会自动生成全局变量

+ + + +
+ + + + + +
+ + + + + +

最近在看《你不知道的JavaScript》这本书,里面写道带有ID的HTML标签会自动生成同名的全局变量,我测试了下,上代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<div id="foo"></div>
<script>
console.log(foo);
foo.innerHTML = "123";
</script>
</body>
</html>

+

测试结果:带有ID的HTML标签会自动生成同名的全局变量。
记得去年遇到过这样的问题,当时我还很纳闷,现在看来,也就释然了。所以以后还是少用id属性吧。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/11/03/\346\227\240\345\210\267\346\226\260\344\270\212\344\274\240\346\226\207\344\273\266\347\232\204\344\272\214\347\247\215\346\226\271\346\263\225/index.html" "b/2016/11/03/\346\227\240\345\210\267\346\226\260\344\270\212\344\274\240\346\226\207\344\273\266\347\232\204\344\272\214\347\247\215\346\226\271\346\263\225/index.html" index e69de29b..b80d3a25 100644 --- "a/2016/11/03/\346\227\240\345\210\267\346\226\260\344\270\212\344\274\240\346\226\207\344\273\266\347\232\204\344\272\214\347\247\215\346\226\271\346\263\225/index.html" +++ "b/2016/11/03/\346\227\240\345\210\267\346\226\260\344\270\212\344\274\240\346\226\207\344\273\266\347\232\204\344\272\214\347\247\215\346\226\271\346\263\225/index.html" @@ -0,0 +1,728 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 无刷新上传文件的2种方法 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

无刷新上传文件的2种方法

+ + + +
+ + + + + +
+ + + + + +
今天在网上刷到一篇文章《三种无刷新上传文件的方法》,于是自己亲手试了试,果然可行。自己只学会了其中的两种,就把自己尝试的demo和结果记录下来:
+首先是第一种:
+使用FormData上传文件,formdata可以封装form标签对象,其中对象中是以键值对的形式存在的。我们可以使用append方法来添加键值,如:
+
1
2
var oMyForm = new FormData();
oMyForm.append("name", "ZhangSan");
+
这里我就直接来上代码介绍如何使用formData来上传图片:
+
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<form>
<input type="text" name="firstname">
<input type="file" id="file" name="file">
<button stye="submit" id="submit">提交</button>
</form>
<script>
document.getElementById('submit').onclick = function(event){
if(event.preventDefault){//取消按钮默认提交行为
event.preventDefault();
} else {
event.returnValue = false;
}
var formDOM = document.getElementsByTagName('form')[0];
var formData = new FormData(formDOM);//创建formData对象
var req = new XMLHttpRequest();
req.open("POST", "upload.php");//使用POST发送请求
req.onload = function(event){
if(this.status === 200){
console.log(this.response);//请求成功后打印返回的结果
}
}
req.send(formData);
req = null;
}
</script>
</body>
</html>
+

注释对代码进行了介绍,就是把formData通过ajax发到后端去。
然后php代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php	
$firstname = $_POST['firstname'];

$filename = time() . substr($_FILES['file']['name'], strrpos($_FILES['file']['name'],'.'));

$response = array();

if(move_uploaded_file($_FILES['file']['tmp_name'], $filename)){

$response['status'] = 1; //成功

$response['filename'] = $filename;

$response['firstname'] = $firstname;

} else {

$response['status'] = -1;

}

echo json_encode($response);
?>

+

这样就可以后端就会保存到图片了。以上,整个上传图片的流程结束。

+

接下来是使用iframe来无刷新上传文件的demo

+

普通的按钮,点击后页面会跳转到提交的地址,而这个地址是根据form标签的target属性指定的,所以只要我们创建个iframe标签,然后指定跳转到这个iframe地址就可以获取到后端返回的数据,也不用跳转页面了,拿到数据后,再把iframe删掉就可以了,具体代码如下:
HTML代码:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<form action="upload1.php" method="post" enctype="multipart/form-data">
<input type="text" name="firstname">
<input type="file" id="file" name="file">
<input type="submit" id="submit" value="提交">
</form>
<script>
document.getElementById('submit').onclick = function(event){
var iframe = document.createElement("iframe");
iframe.width = 0;
iframe.height = 0;
iframe.border = 0;
iframe.name = "form-iframe";
iframe.id = "form-iframe";
iframe.setAttribute("style", "width:0;height:0;border:none");
this.form.appendChild(iframe);
this.form.target = "form-iframe";
iframe.onload = function(){
var img = document.createElement("img");
var responseData = this.contentDocument.body.textContent
|| this.contentWindow.document.body.textContent;
//获取iframe的内容,即服务返回的数据
var json = JSON.parse(responseData);//后端返回的json
console.log(json);
img.src = json.filename;
document.getElementsByTagName("form")[0].appendChild(img);//显示图片
setTimeout(function(){//删掉iframe
var _frame = document.getElementById("form-iframe");
_frame.parentNode.removeChild(_frame);
}, 100);
}
}
</script>
</body>
</html>

+

上面的按钮点击函数里,就是创建iframe标签,然后通过target属性指定到这个iframe,再在iframe的load函数里,或者后端返回的数据,拿到数据后,再删除iframe.
php代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php	
$firstname = $_POST['firstname'];

$filename = time() . substr($_FILES['file']['name'], strrpos($_FILES['file']['name'],'.'));

$response = array();

if(move_uploaded_file($_FILES['file']['tmp_name'], $filename)){

$response['status'] = 1; //成功

$response['filename'] = $filename;

$response['firstname'] = $firstname;

} else {

$response['status'] = -1;

}

echo json_encode($response);
?>

+

php后端代码和第一种没有什么区别,都是获取表单数据。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2016/12/16/\350\247\243\345\206\263\342\200\234webkitAnimationEnd\345\205\245\345\234\272\345\212\250\347\224\273\345\210\207\346\215\242\342\200\235\345\234\250\345\256\211\345\215\223\346\234\272\345\205\274\345\256\271\346\200\247\351\227\256\351\242\230/index.html" "b/2016/12/16/\350\247\243\345\206\263\342\200\234webkitAnimationEnd\345\205\245\345\234\272\345\212\250\347\224\273\345\210\207\346\215\242\342\200\235\345\234\250\345\256\211\345\215\223\346\234\272\345\205\274\345\256\271\346\200\247\351\227\256\351\242\230/index.html" index e69de29b..cd1706d3 100644 --- "a/2016/12/16/\350\247\243\345\206\263\342\200\234webkitAnimationEnd\345\205\245\345\234\272\345\212\250\347\224\273\345\210\207\346\215\242\342\200\235\345\234\250\345\256\211\345\215\223\346\234\272\345\205\274\345\256\271\346\200\247\351\227\256\351\242\230/index.html" +++ "b/2016/12/16/\350\247\243\345\206\263\342\200\234webkitAnimationEnd\345\205\245\345\234\272\345\212\250\347\224\273\345\210\207\346\215\242\342\200\235\345\234\250\345\256\211\345\215\223\346\234\272\345\205\274\345\256\271\346\200\247\351\227\256\351\242\230/index.html" @@ -0,0 +1,719 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 解决“webkitAnimationEnd入场动画切换”在安卓机兼容性问题 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

解决“webkitAnimationEnd入场动画切换”在安卓机兼容性问题

+ + + +
+ + + + + +
+ + + + + +

问题描述:
在手机端H5中,当一个图片入场动画执行完毕后,我们想让它循环执行另一个动画,就是用webkitAnimationEnd这个方法,比如代码是这样的:

1
2
3
4
5
6
$(document).on("webkitAnimationEnd", ".p54", function(){
$(".p54").removeClass('rollIn').addClass('pulse infinite').css({
"animation-delay" : "0s",
"-webkit-animation-delay" : "0s",
})
});

+

这个写法在IOS机型中没有问题,但是在安卓机上并不会执行下一个pulse这个动画。
解决方案是:
在p54这个标签外再套一层div,比如命名为p54_parent,当p54动画执行完后,让p54_parent执行下一个动画,代码是这样的:

1
2
3
$(document).on("webkitAnimationEnd", ".p54", function(){
$(".p54_parent").addClass('pulse infinite');
});

+

这样,就可以完美解决这个兼容性问题,安卓机也没有问题

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/02/13/SVG\347\273\230\345\210\266\345\212\250\346\200\201\350\267\257\345\276\204\346\225\210\346\236\234/index.html" "b/2017/02/13/SVG\347\273\230\345\210\266\345\212\250\346\200\201\350\267\257\345\276\204\346\225\210\346\236\234/index.html" index e69de29b..17bf67fb 100644 --- "a/2017/02/13/SVG\347\273\230\345\210\266\345\212\250\346\200\201\350\267\257\345\276\204\346\225\210\346\236\234/index.html" +++ "b/2017/02/13/SVG\347\273\230\345\210\266\345\212\250\346\200\201\350\267\257\345\276\204\346\225\210\346\236\234/index.html" @@ -0,0 +1,720 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SVG绘制动态路径效果 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

SVG绘制动态路径效果

+ + + +
+ + + + + +
+ + + + + +

svg动态绘制路径效果,使用snap.js库,近适用于path标签。

svg标签HTML代码我们可以使用AI软件或者在线制作,具体svg知识大家可以参考张鑫旭,张鑫旭的博客进行基础知识学习。使用软件绘制一条路径后,然后我们导出文件为svg格式,看其代码,复制path标签。例如:

1
2
3
4
5
6
<svg id="svg" width="640" height="1136" xmlns="http://www.w3.org/2000/svg">
<g>
<path id="svg_1" d="m127.5,13.5c56,60 109,17 108.5,46.5c-0.5,29.5 -111.5,13.5 -119,50c-7.5,36.5 168.5,-6.5 182,43c13.5,49.5 -132.5,6.5 -130.5,57.5c2,51 100,29 99.5,28.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="#fff"/>
<ellipse id="yuan" ry="0" rx="0" id="svg_2" cy="332.5" cx="280.5" stroke-width="1.5" stroke="#000" fill="#FFB27C"/>
</g>
</svg>

+

然后引入snap.js,这个库可以操控svg DOM,使用方法也比较容易学习,这里我们直接使用,参考一下代码:

1
2
3
4
5
6
7
8
9
var svg = Snap("#svg");
var snpg = svg.select("#svg_1");
snpg.attr({
strokeDashoffset: snpg.getTotalLength(),
strokeDasharray: snpg.getTotalLength()
});
snpg.animate({
"stroke-dashoffset": 0
}, 2000, mina.easeout);

+

getTotalLength()可以直接获取路径的长度,这样就直接形成了动态路径效果,这个效果用到了路径的strokeDashoffset和strokeDasharray属性,strokeDasharray表示各个虚线段的长度,strokeDashoffset表示虚线的起始偏移量,原理就是先使用attr方法设置成当前的路径长度,然后再使用animate方法使偏移量变为0,变为0的动画效果就形成了动态路径。
通过以上方法,我们就可以绘制多条path路径,然后通过回调函数一条一条的绘制,形成绘制一个物体的动态效果,复制以下代码可以查看效果:

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
<svg id="svg" width="580" height="400" xmlns="http://www.w3.org/2000/svg">
<g>
<path id="svg_6" d="m109.5,67.5l-1.5,258.5" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="#fff"/>
<path id="svg_7" d="m110.5,67.5l89.5,-2.5l-6,260" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="#fff"/>
<path id="svg_8" d="m121.5,92.5c62,-19 64,0 64,0" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="#fff"/>
<path stroke="#000" id="svg_9" d="m123.5,116.5c60,-9.707724 54,-0.225761 54,-0.225761" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" fill="#fff"/>
<path stroke="#000" id="svg_10" d="m126.5,134.5c57,-0.250008 58,0 58,0" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" fill="#fff"/>
<path stroke="#000" id="svg_11" d="m124.5,168.626247c59,13.997647 58,-1.126247 58,-1.126247" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" fill="#fff"/>
<path id="svg_12" d="m125.5,201.5l58.5,7.5" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="#fff"/>
<path stroke="#000" id="svg_13" d="m119.5,231.94206c64,-10.531113 66,0.55794 66,0.55794" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" fill="#fff"/>
<path stroke="#000" id="svg_14" d="m124.5,255.193568c59,-27.578854 56,0.306432 56,0.306432" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" fill="#fff"/>
<path id="svg_15" d="m155.5,84.5c0,0 -3,157 -3.5,156.5" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="#fff"/>
<path id="svg_16" d="m130.5,271.5l-2.5,51.5" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="#fff"/>
<path id="svg_17" d="m131.5,273.5l47.5,1.5l-3,51" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="#fff"/>
<path id="svg_18" d="m152.5,274.5c0,0 -2,47 -2.5,46.5" opacity="0.5" fill-opacity="null" stroke-opacity="null" stroke-width="1.5" stroke="#000" fill="#fff"/>
</g>
</svg>
<script>
var svg = Snap("#svg");
var countArr = [];
function hualou(id){
var snpg = svg.select("#svg_"+id);
snpg.attr({
opacity:1,
strokeDashoffset: 746,
strokeDasharray: 746
});
snpg.animate({

"stroke-dashoffset": 0
}, 2000, mina.easeout);
}
function initLou(id){
var snpg = svg.select("#svg_"+id);
snpg.attr("opacity", 0);
}
window.onclick= function(){
for(var j = 0; j < countArr.length; j++){
clearTimeout(countArr[j]);
}
for(var i = 6; i < 19; i++){
(function(i){
initLou(i);
countArr.push(setTimeout(function(){ hualou(i) }, 300+300*(i-6)));
})(i)
}
}
window.ontouchstart= function(){
for(var j = 0; j < countArr.length; j++){
clearTimeout(countArr[j]);
}
for(var i = 6; i < 19; i++){
(function(i){
initLou(i);
countArr.push(setTimeout(function(){ hualou(i) }, 300+300*(i-6)));
})(i)
}
}
</script>

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/02/13/svg\345\256\236\347\216\260\345\212\250\347\224\273\346\225\210\346\236\234/index.html" "b/2017/02/13/svg\345\256\236\347\216\260\345\212\250\347\224\273\346\225\210\346\236\234/index.html" index e69de29b..7d3b4783 100644 --- "a/2017/02/13/svg\345\256\236\347\216\260\345\212\250\347\224\273\346\225\210\346\236\234/index.html" +++ "b/2017/02/13/svg\345\256\236\347\216\260\345\212\250\347\224\273\346\225\210\346\236\234/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + svg实现动画效果 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

svg实现动画效果

+ + + +
+ + + + + +
+ + + + + +

web动画除了css3的帧动画外,还可以用svg来实现动画效果,例如网上的一个例子参考链接,这个动画就是用svg的animate标签来实现的,同样是通过软件绘制好图形,path标签中,d属性表示路径点坐标,然后使用animate标签来切换路径,animate标签是path标签的子级,使用 attributeName=“d”表示切换父标签path的d属性,然后values属性则等于要切换的另一个路径图形,多个图形可以使用分号”;”来区分,例如一个丑陋的图形变化参考链接
参考信息:http://www.zhangxinxu.com/wordpress/2014/08/so-powerful-svg-smil-animation/

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/02/14/PHP\346\223\215\346\216\247mongodb\345\221\275\344\273\244\345\260\217\347\273\223/index.html" "b/2017/02/14/PHP\346\223\215\346\216\247mongodb\345\221\275\344\273\244\345\260\217\347\273\223/index.html" index e69de29b..56bcabab 100644 --- "a/2017/02/14/PHP\346\223\215\346\216\247mongodb\345\221\275\344\273\244\345\260\217\347\273\223/index.html" +++ "b/2017/02/14/PHP\346\223\215\346\216\247mongodb\345\221\275\344\273\244\345\260\217\347\273\223/index.html" @@ -0,0 +1,717 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PHP操控mongodb命令小结 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

PHP操控mongodb命令小结

+ + + +
+ + + + + +
+ + + + + +

最近学习了非关系型数据库mongodb,以json方式来存储数据,数据内容更灵活。以下是php操作mongodb常用命令,记录一下,便于以后查询。

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
<?php
// 参考 http://php.net/manual/zh/mongo.sqltomongo.php

/* 查询区间范围 */
$rangeQuery = array('count' => array('$gt' => 3, '$lt' => 9));
$doc = $jihe->find($rangeQuery);

/*自定义函数搜索集合*/
$rangeQuery = "function() {
return this.count == '1';
}";
$doc = $jihe->find(array('$where'=> $rangeQuery));

//in操作符
$doc = $jihe->find(array(
'count'=> array('$in' => array(4, 6))
));

//输出集合 使用 iterator_to_array() 会让驱动将强制载入所有搜索结果集到内存,所以对超过内存大小的结果集不要这么做!
方法一:
$doc = $jihe->find();
echo json_encode(iterator_to_array($doc));

方法二:
$doc = $jihe->find();
foreach($doc as $id => $value)
{

echo json_encode($value);
}

//计算文档数量
$doc = $jihe->count();

// 排序 -1降序 1升序
$doc = $jihe->find()->sort(array("count" => -1));

//获取count=3的文档中的title属性
$doc = $jihe->find(array("count" => 3), array("title"=>1));

// 从第5个开始取10个
$doc = $jihe->find()->limit(10)->skip(4);

// 或者条件句
$doc = $jihe->find(array('$or'=>array(
array("count"=>3), array("title"=>"mongodb1")
)
));

// 限制数量1个
$doc = $jihe->find(array('$or'=>array(
array("count"=>3), array("title"=>"mongodb1")
)
))->limit(1);

// 获取符合条件的数据数量
$doc = $jihe->find(array('$or'=>array(
array("count"=>3), array("title"=>"mongodb1")
)
))->count();

// 获取含有count字段的数据数量
$doc = $jihe->find(
array("count"=>array('$exists'=>true))
)->count();

// 获取含有count字段的数据
$doc = $jihe->find(
array("count"=>array('$exists'=>true))
);

// 更改:count=0的数据,title改为mongdb,此处‘$set’参数表示修改,如不加此参数,会重写原数据,将数据的其他字段抹掉
$doc = $jihe->update(
array("count"=>0),array('$set'=>array("title"=>"mongodb"))
);

// 在title=mongodb的那条数据,把count累加10,用‘$inc’方法
$doc = $jihe->update(
array("title"=>"mongodb"), array('$inc'=>array("count"=>10))
);

// 删除title=mongodb1的那条数据
$doc = $jihe->remove(
array("title"=>"mongodb1")
);
?>

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/03/08/\347\256\227\346\263\225\347\254\224\350\256\260/index.html" "b/2017/03/08/\347\256\227\346\263\225\347\254\224\350\256\260/index.html" index e69de29b..41bce699 100644 --- "a/2017/03/08/\347\256\227\346\263\225\347\254\224\350\256\260/index.html" +++ "b/2017/03/08/\347\256\227\346\263\225\347\254\224\350\256\260/index.html" @@ -0,0 +1,723 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 算法与数据结构JS版 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

算法与数据结构JS版

+ + + +
+ + + + + +
+ + + + + +

本篇博客为记录学习《数据结构与算法JavaScript语言描述》的笔。
1、递归算法,比较常见,属于比较简单类型的。

返回数字1-5的之间的整数相乘结果

1
2
3
4
5
6
7
8
function factorial(number){
if(number == 1){
return 1;
} else {
return number * factorial(number-1); //此算法核心在这一句
}
}
console.log(factorial(5)); //150

+

reduce迭代方法同样可以实现累加(乘)效果

1
2
3
4
5
var arr = [7, 4, 122, 20, 3333];
var newArr = arr.reduce(function(a,b){
return a+b;
});
console.log(newArr);

+

2、sort排序,函数中传入ab表示第一个参数和第二个参数,两者相减,返回小于0的数表示是从小到大排序

1
2
3
4
5
6
var arr = [7, 4, 122, 20, 3333];
var newArr = arr.sort(function(a,b){
return a-b;
return b-a; //从大到小排序
});
console.log(newArr);

+

3、创建二维数组,原理是先创建外层数组元素,再对外层元素创建内层数组元素

1
2
3
4
5
6
7
8
9
10
11
12
13
Array.matrix = function(numrows, numcols, initial){
var arr = [];
for(var i = 0; i < numrows; i++){
var col=[];
for(var j = 0; j < numcols; j++){
col[j] = initial;
}
arr[i] = col;
}
return arr;
}
var nums = Array.matrix(5,5,0);
console.log(nums)

+

4、求3个学生的平均成绩:

1
2
3
4
5
6
7
8
9
var grades = [[89, 77, 78], [76, 82, 81], [91,69,70]];
for(var i = 0; i < grades.length; i++){
var col = grades[i];
var total = col.reduce(function(a,b){ //累加求总分
return a+b
});
var pingjun = total / col.length;
console.log("text" + (i+1) + "成绩:" + pingjun);
}

+

5、快速排序算法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function qSort(arr){
if(arr.length == 0){
return [];
}
var left = [];
var right = [];
var pivot = arr[0];
for(var i = 1; i < arr.length; i++){
if(arr[i] < pivot){
left.push(arr[i])
} else {
right.push(arr[i])
}
}
return qSort(left).concat(pivot, qSort(right));
}
var a = [];
for(var i = 0; i < 100000; i++){
a[i] = Math.floor((Math.random()*100)+1)
}

+

书上说这种快速排序算法对大型数据排序很快,但是我经过测试,对100000个数进行排序,花了将近1000ms,而如果用sort方法,只需要40ms左右,所以看来sort还是比这个快速排序算法好用。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/03/21/defineProperty\344\270\216\346\225\260\346\215\256\347\273\221\345\256\232/index.html" "b/2017/03/21/defineProperty\344\270\216\346\225\260\346\215\256\347\273\221\345\256\232/index.html" index e69de29b..fc938c12 100644 --- "a/2017/03/21/defineProperty\344\270\216\346\225\260\346\215\256\347\273\221\345\256\232/index.html" +++ "b/2017/03/21/defineProperty\344\270\216\346\225\260\346\215\256\347\273\221\345\256\232/index.html" @@ -0,0 +1,724 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + defineProperty与数据绑定 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

defineProperty与数据绑定

+ + + +
+ + + + + +
+ + + + + +

defineProperty用来声明一个对象,与对象字面量不同的是,它可以声明内部值get(设置)和set(获取)时的方法,如:

1
2
3
4
5
6
7
8
9
10
11
var obj = {};		
Object.defineProperty(obj, 'hello', {
get: function() {
console.log('get!');
},
set: function(value) {
console.log('set!');
}
});
obj.hello = 1; //打印set
obj.hello; //打印get

+

由此,我们可以利用此特性实现一个简单的双向绑定:

1
2
3
4
5
6
7
8
9
10
11
12
13
var obj = {};		
Object.defineProperty(obj, 'hello', {
get: function() {
console.log('get!');
},
set: function(value) {
document.querySelector(".a").value = value;
document.querySelector(".b").innerHTML = value;
}
});
document.addEventListener('keyup', function(e){
obj.hello = e.target.value;
})

+

###documentFragment
先来看一段代码:

1
2
3
4
<div id="app">
<input type="text" class="a">
<span class="b"></span>
</div>

+
1
2
3
4
5
6
7
8
9
10
function nodeToFragment(node)
{
var flag = document.createDocumentFragment();
while (node.firstChild){
flag.append(node.firstChild); //append方法会把节点从A移动到B
}
return flag;
}
var dom = nodeToFragment(document.getElementById("app"));
console.log(dom);
+

这里打印会把div标签里的所有标签打印出来,而html中div的标签内为空,是因为这段代码把div里需要操作的标签全都转到了documentFragment里了,因为在documentFragment里操作标签比在dom中操作要性能好很多。

+

###简单的通过实例进行数据绑定:

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 compile(node, vm){		//解析赋值
var reg = /\{\{(.*)\}\}/;
if(node.nodeType === 1){
var attr = node.attributes;
for(var i = 0; i < attr.length; i++){
if(attr[i].nodeName == "v-model"){
var name = attr[i].nodeValue;
node.value = vm.data[name];
node.removeAttribute('v-model');
}
}
}
if(node.nodeType === 3){
if(reg.test(node.nodeValue)){
var name = RegExp.$1;
name = name.trim();
node.nodeValue = vm.data[name];
}
}
}
function nodeToFragment(node, vm) //把节点转移到documentFragment进行操作
{
var flag = document.createDocumentFragment();
while (node.firstChild){
compile(node.firstChild,vm);
flag.append(node.firstChild); //append方法会把节点从A移动到B
}
return flag;
}
function Vue(options)
{
this.data = options.data;
var id = options.el;
var dom = nodeToFragment(document.getElementById(id), this);
console.log(dom)
document.getElementById(id).appendChild(dom);
}
var vm = new Vue({
el:'app',
data:{
text:'hello World'
}
})

+

接下来再利用defineProperty进行set数据绑定,即可实现动态双向绑定:
修改代码:

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
function compile(node, vm){		//解析赋值
var reg = /\{\{(.*)\}\}/;
if(node.nodeType === 1){
var attr = node.attributes;
for(var i = 0; i < attr.length; i++){
if(attr[i].nodeName == "v-model"){
var name = attr[i].nodeValue;
node.addEventListener('input', function(e){
vm.data[name] = e.target.value;
})
node.value = vm.data[name];
node.removeAttribute('v-model');
}
}
}
if(node.nodeType === 3){
if(reg.test(node.nodeValue)){
var name = RegExp.$1;
name = name.trim();
node.nodeValue = vm.data[name];
}
}
}
function nodeToFragment(node, vm) //把节点转移到documentFragment进行操作
{
var flag = document.createDocumentFragment();
while (node.firstChild){
compile(node.firstChild,vm);
flag.append(node.firstChild); //append方法会把节点从A移动到B
}
return flag;
}
function Vue(options)
{
this.data = options.data;
var data = this.data;
observe(data, this);
var id = options.el;
var dom = nodeToFragment(document.getElementById(id), this);
console.log(dom)
document.getElementById(id).appendChild(dom);
}
function defineReactive(obj, key, val)
{
Object.defineProperty(obj, key, {
get:function(){
return val
},
set:function(newVal){
if(newVal === val) return;
val = newVal;
console.log(val);
}
})
}
function observe(obj, vm)
{
Object.keys(obj).forEach(function(key){
defineReactive(vm.data, key, vm.data[key]);
})
}
var vm = new Vue({
el:'app',
data:{
text:'hello World'
}
})

+

以上便可实现在输入时,同时打印出data.text,已经和vm.data.text实现了绑定

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/04/11/\344\275\277\347\224\250\344\270\203\347\211\233\344\272\221\345\255\230\345\202\250\344\270\212\344\274\240\347\205\247\347\211\207js-sdk/index.html" "b/2017/04/11/\344\275\277\347\224\250\344\270\203\347\211\233\344\272\221\345\255\230\345\202\250\344\270\212\344\274\240\347\205\247\347\211\207js-sdk/index.html" index e69de29b..83c39492 100644 --- "a/2017/04/11/\344\275\277\347\224\250\344\270\203\347\211\233\344\272\221\345\255\230\345\202\250\344\270\212\344\274\240\347\205\247\347\211\207js-sdk/index.html" +++ "b/2017/04/11/\344\275\277\347\224\250\344\270\203\347\211\233\344\272\221\345\255\230\345\202\250\344\270\212\344\274\240\347\205\247\347\211\207js-sdk/index.html" @@ -0,0 +1,721 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 使用七牛云存储上传照片js-sdk | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

使用七牛云存储上传照片js-sdk

+ + + +
+ + + + + +
+ + + + + +

七牛云存储为个人提供10G的免费云空间,对个人来说,可以作为上传照片文件的云空间还是蛮不错的。官方提供了多种服务器语言sdk,下面就介绍下如何使用js-sdk配合php实现上传照片功能。
1、首先需要注册一个七牛账户,并获取到accessKey和secretKey,可以在空间设置中查看。

+

2、需要一门服务器端语言像七牛服务器通信获取token,并将token返回到前端,这里以php为例获取token:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
require_once './autoload.php';
use Qiniu\Auth;

$bucket = 'save'; //空间名,不是空间域名
$accessKey = '账户accessKey';
$secretKey = '账户secretKey';

$auth = new Auth($accessKey, $secretKey);
$upToken = $auth->uploadToken($bucket);

echo $upToken;
?>

+

php依赖php SDK,需要到七牛官方下载七牛php SDK并引入。初始化实例便可获取token。

+

3、
前端这里以formData的方式提交照片:
七牛官方规定需要提交照片文件与token值,并以form表单的方式提交:

1
2
<input name="token" id="token" type="hidden" value="">
<input id="userfile" name="file" type="file" />

+

token的值需要按照步骤2先获取token。提交地址是七牛提供的url,不同地区提交到不同域名,例如我的demo是提交到:链接,错误的url七牛会报错,并提醒你正确提交的地址。
详情可见demo:http://www.sanmuweb.com/qiniu/index.html

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/04/19/\344\273\216\350\276\223\345\205\245URL\357\274\214\345\210\260\351\241\265\351\235\242\346\230\276\347\244\272\357\274\214\350\277\231\344\270\255\351\227\264\351\203\275\345\217\221\347\224\237\344\272\206\344\273\200\344\271\210\357\274\237/index.html" "b/2017/04/19/\344\273\216\350\276\223\345\205\245URL\357\274\214\345\210\260\351\241\265\351\235\242\346\230\276\347\244\272\357\274\214\350\277\231\344\270\255\351\227\264\351\203\275\345\217\221\347\224\237\344\272\206\344\273\200\344\271\210\357\274\237/index.html" index e69de29b..c6950e25 100644 --- "a/2017/04/19/\344\273\216\350\276\223\345\205\245URL\357\274\214\345\210\260\351\241\265\351\235\242\346\230\276\347\244\272\357\274\214\350\277\231\344\270\255\351\227\264\351\203\275\345\217\221\347\224\237\344\272\206\344\273\200\344\271\210\357\274\237/index.html" +++ "b/2017/04/19/\344\273\216\350\276\223\345\205\245URL\357\274\214\345\210\260\351\241\265\351\235\242\346\230\276\347\244\272\357\274\214\350\277\231\344\270\255\351\227\264\351\203\275\345\217\221\347\224\237\344\272\206\344\273\200\344\271\210\357\274\237/index.html" @@ -0,0 +1,792 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 从输入URL,到页面显示,这中间都发生了什么? | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

从输入URL,到页面显示,这中间都发生了什么?

+ + + +
+ + + + + +
+ + + + + +
+

引言

+
+

“从输入URL,到页面显示,这中间都发生了什么?”,常刷知乎的肯定都知道这在知乎上是一道经典题,把自己能理解的部分做个记录:

+
+
+

过程简述

+
+
    +
  1. 浏览器通过域名查找对应IP;
  2. +
  3. 浏览器通过IP地址与服务器建立链接;
  4. +
  5. 浏览器与服务器通信:浏览器发送请求,服务器处理请求;
  6. +
  7. 浏览器与服务器断开链接;
  8. +
  9. 页面渲染;
  10. +
+

下面就针对以上5条进行简单介绍

+

1.浏览器通过域名查找对应IP:

+
+

URL的基本结构: 协议名称 :// 服务器所在域名或者IP地址 : 端口号 / 所要访问的文件路径

+

PS:浏览器为了保证安全性,设定了跨域保护策略, 即窗口之间的通信必须满足使用相同协议, 相同域名, 相同端口,因此深入理解URL各组成部分的含义有助于我们判断两个窗口之间是否能互相通信。

+

http://www.baidu.com/index.html为例,

+

http表示超文本传输协议

+

www.baidu.com是域名,由于IP协议规定的纯数字难以记忆,所以就用域名来代替便于记忆理解,百度实际的IP地址为119.75.217.109。就像每个人都有身份证号,身份证号是唯一的,但我们不能听过身份证号来跟别人交流,所以就叫别人的名字。在这里,身份证号就是IP,域名就是人的姓名。

+

DNS服务器之间的访问定位还是通过IP来定位的,但是我们输入的是域名,那么就产生了DNS协议,它的作用就是把域名转化为IP,提供该协议服务的服务器就叫DNS服务器。

+

index.html就是我们所要访问的文件名

+
+

2.浏览器通过IP地址与服务器建立链接;

+
+

解析出了服务器的IP地址,浏览器就与服务器建立连接了。连接过程就是俗称的TCP协议“三次握手”:

+

1.主机向服务器发送一个建立连接的请求(您好,我想认识您);

+

2.服务器接到请求后发送同意连接的信号(好的,很高兴认识您);

+

3.主机接到同意连接的信号后,再次向服务器发送了确认信号(我也很高兴认识您),自此,主机与服务器两者建立了连接。

+
+

3.浏览器与服务器通信

+
+

建立连接后,主机与服务器就开始进行通信。

+

1.浏览器根据URL生成HTTP请求,请求中包含请求头和请求体。

+

2.服务器接收到请求后,根据请求的内容,将相对应的文件发送给浏览器。

+
+

4.浏览器与服务器断开链接

+
+

发送完毕后,主机与浏览器断开连接,断开连接过程是一个“四次挥手”的过程,当服务器接收到断开连接的请求时,可能仍然有数据未发送完毕,所以服务器先发送确认信号,等数据全部发送完毕再同意断开。

+
+

5.页面渲染

+
+

1.浏览器开始解析HTML文件,按照从上到下的顺序解析。

+

2.HTML解析器将HTML转成成DOM,构建完DOM树后,触发DomContentLoaded事件。

+

3.CSS解析器将CSS解析为CSSOM(层叠样式表对象模式)

+

4.CSSOM和DOM开始合并渲染布局,计算各个节点的位置信息;

+

5.布局后的渲染树显示到界面上;

+

以上只是自己对整个过程的简单理解,往深了讲,这个题涵盖的知识面太多太广太深。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/04/20/\346\200\247\350\203\275\344\274\230\345\214\226\344\271\213\345\207\275\346\225\260\351\230\262\346\212\226\344\270\216\350\212\202\346\265\201/index.html" "b/2017/04/20/\346\200\247\350\203\275\344\274\230\345\214\226\344\271\213\345\207\275\346\225\260\351\230\262\346\212\226\344\270\216\350\212\202\346\265\201/index.html" index e69de29b..1d281d8b 100644 --- "a/2017/04/20/\346\200\247\350\203\275\344\274\230\345\214\226\344\271\213\345\207\275\346\225\260\351\230\262\346\212\226\344\270\216\350\212\202\346\265\201/index.html" +++ "b/2017/04/20/\346\200\247\350\203\275\344\274\230\345\214\226\344\271\213\345\207\275\346\225\260\351\230\262\346\212\226\344\270\216\350\212\202\346\265\201/index.html" @@ -0,0 +1,740 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 性能优化之函数防抖与节流 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

性能优化之函数防抖与节流

+ + + +
+ + + + + +
+ + + + + +

web端性能优化一直是一个重点和难点。今天在看了一篇关于scroll滚动优化性能的文章后,认识了函数的防抖与节流,觉得其用处蛮大的。在这里记录一下。

+ +
+

前言

+
+

web端性能优化一直是一个重点和难点。今天在看了一篇关于scroll滚动优化性能的文章后,认识了函数的防抖与节流,觉得其用处蛮大的。在这里记录一下。

+
+

应用场景

+
+

当我们在频繁操作触发函数方法的情况下,比如下拉加载,移动端手指移动切换动画。都是属于高频触发函数方法,如果在方法中的操作过多,页面就会看起来非常卡顿不流畅。所以我们就要控制函数执行的次数。由此,便衍生了函数的防抖与节流。

+
+

防抖

+
+

常规操作下我们会这样写:

1
2
3
4
var i = 0;
window.addEventListener('scroll', function(){
console.log(i++);
}, false)

+

以上写法便是个高频操作,如果执行的操作是DOM操作,会频繁的触发页面重绘,帧率降低,影响性能。所以我们要控制他执行的次数,把一连串的触发合并成一次,即滚动事件结束才触发。举个栗子:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function debounce(func, wait) {
var timeout;
return function() {
// 每次触发 scroll handler 时先清除定时器
clearTimeout(timeout);
// 指定 xx ms 后触发真正想进行的操作 handler
timeout = setTimeout(func, wait);
};
};

// 实际想绑定在 scroll 事件上的 handler
function realFunc(){
console.log("Success");
}

// 采用了防抖动
window.addEventListener('scroll',debounce(realFunc,500));
+

只要触发间隔低于500ms,就不会连续触发,即在最后一次触发scroll事件500ms后才去响应执行函数。这便是防抖。

+
+

节流

+
+

如果你试了防抖的方法,会发现他在最后一次触发滚动都才去执行方法,如果我一直下拉滚动,中间却没有执行加载资源。这很明显是不正确的。我们希望在频繁滚动中,也能间隔性的执行加载方法,由此,便产生了节流——至少在xx时间内执行一次,与防抖相比,节流多了一个mustRun参数,即mustRun时间内必须执行一次。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function throttle(fn, wait, mustRun) {
var timeout,
startTime = new Date();
console.log(startTime) //只在页面初始化时执行一次,后续滚动都不会触发这里
return function () {
var context = this;
var args = arguments, curTime = new Date();
clearTimeout(timeout);
if(curTime - startTime >= mustRun){
fn.call(context, args);
startTime = curTime;
} else {
timeout = setTimeout(fn,wait);
}
}
}
function done() {
console.log('success');
}
window.addEventListener('scroll', throttle(done, 500, 1000), false);
+

以上方法,会在滚动频率高于500ms时,保证每1000ms执行一次方法。

+

(完!)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/05/09/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\200-\342\200\224-\347\255\226\347\225\245\346\250\241\345\274\217/index.html" "b/2017/05/09/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\200-\342\200\224-\347\255\226\347\225\245\346\250\241\345\274\217/index.html" index e69de29b..395a36f3 100644 --- "a/2017/05/09/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\200-\342\200\224-\347\255\226\347\225\245\346\250\241\345\274\217/index.html" +++ "b/2017/05/09/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\200-\342\200\224-\347\255\226\347\225\245\346\250\241\345\274\217/index.html" @@ -0,0 +1,731 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 设计模式学习之一 — 策略模式 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

设计模式学习之一 — 策略模式

+ + + +
+ + + + + +
+ + + + + +

js设计模式一直是该语言的核心之一,流弊的设计模式可以让代码功能更明显,函数原理更清晰,代码更通读易懂。

+
+

引言

+
+

js设计模式一直是该语言的核心之一,流弊的设计模式可以让代码功能更明显,函数原理更清晰,代码更通读易懂。js设计模式的应用就像一个匠人,在精心打造自己的艺术品。而我们如果想做一个好匠人,就要懂得应用合适的设计模式。自己最近在学习《JavaScript设计模式与开发实践》,博客作为学习笔记记录。本篇记录第一种设计模式——策略模式。

+
+

策略模式介绍

+
+

当我们在做表单验证的时候,通常手段是获取字段的值,然后一一用if做判断,看是否符合验证规则。
策略模式的思想让我们摒弃if条件句,把判断句封装为策略函数,如:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var strategies = {
isNonEmpty : function( value, errorMsg ){
if(value === ''){
return errorMsg
}
},
minLength : function( value, length, errorMsg ){
if ( value.length < length ){
return errorMsg;
}
},
isMobile : function( value, errorMsg ){
if ( !/(^1[3|5|8][0-9]{9}$)/.test( value ) ){
return errorMsg;
}
}
}
+

之后我们再把获取的字段值去调用这些策略函数。
所以,一个基于策略模式的程序至少有两部分组成,第一部分是策略类,策略类封装具体的算法。第二部分是调用执行类,即点击提交按钮后,去调用策略。

+

我们以提交表单为例,看看基于策略模式下,如何验证表单:

+
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
<form id="registerForm" method="POST" action="#">
<input type="text" name="userName">
<input type="text" name="password">
<input type="text" name="phoneNumber">
<button>提交</button>
</form>
<script>
var strategies = {
isNonEmpty : function( value, errorMsg ){
if(value === ''){
return errorMsg
}
},
minLength : function( value, length, errorMsg ){
if ( value.length < length ){
return errorMsg;
}
},
isMobile : function( value, errorMsg ){
if ( !/(^1[3|5|8][0-9]{9}$)/.test( value ) ){
return errorMsg;
}
}
}
var Validator = function(){
this.cache = [];
}
Validator.prototype.add = function( dom, rules ){
var self = this;
for( var i = 0, rules; rule = rules[ i++ ];){
(function( rule ){
var strategyAry = rule.strategy.split( ':' );
var errorMsg = rule.errorMsg;
self.cache.push(function(){
var strategy = strategyAry.shift();
strategyAry.unshift( dom.value );
strategyAry.push( errorMsg );
return strategies[ strategy ].apply( dom, strategyAry );
});
})(rule)
}
};
Validator.prototype.start = function(){
for ( var i = 0, validatorFunc; validatorFunc = this.cache[ i++ ]; ){
var errorMsg = validatorFunc();
if ( errorMsg ){
return errorMsg;
}
}
}

var registerForm = document.getElementById( 'registerForm' );
var validataFunc = function(){
var validator = new Validator();
validator.add( registerForm.userName, [{
strategy: 'isNonEmpty',
errorMsg: '用户名不能为空'
}, {
strategy: 'minLength:6',
errorMsg: '用户名长度不能小于10位'
}]);

validator.add( registerForm.password, [{
strategy: 'minLength:6',
errorMsg: '密码长度不能小于6位'
}]);

validator.add( registerForm.phoneNumber, [{
strategy: 'isMobile',
errorMsg: '手机号码格式不正确'
}]);

var errorMsg = validator.start();
return errorMsg;
}

registerForm.onsubmit = function(){
var errorMsg = validataFunc();
if ( errorMsg ){
alert( errorMsg );
return false;
}
}
</script>
+

我们通过add方法,为每个字段添加校验规则,并且每个字段可以有多个校验规则,这样便极具扩展性。添加完规则后,我们便用start方法去执行这些规则。

+

应用了策略模式后,我们想添加规则只要在add方法中添加参数即可,而不用深入函数内部去增加判断句。代码整体增强了可读性和扩展性,便于后期维护。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/07/19/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\211-\342\200\224-\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217/index.html" "b/2017/07/19/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\211-\342\200\224-\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217/index.html" index e69de29b..72e8cc19 100644 --- "a/2017/07/19/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\211-\342\200\224-\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217/index.html" +++ "b/2017/07/19/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\211-\342\200\224-\350\247\202\345\257\237\350\200\205\346\250\241\345\274\217/index.html" @@ -0,0 +1,728 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 设计模式学习之三 — 观察者模式 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

设计模式学习之三 — 观察者模式

+ + + +
+ + + + + +
+ + + + + +
+

观察者模式介绍

+
+

又叫发布-订阅模式,是js事件模式中常见的一种,比如jquery的点击事件,在我们声明点击事件后,当我们用trigger方法去触发click事件时,事件会被响应,这就是一种监听者模式,

+
+

观察者模式应用场景

+
+

某一件事中,我们声明了一个事件A,然后想监听A方法的触发。

+
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
var event = {
clientList: [],
listen: function(key, fn){
if( !this.clientList[key] ){
this.clientList[key] = [];
}
this.clientList[key].push(fn);
},
trigger: function(){
var key = Array.prototype.shift.call(arguments),
fns = this.clientList[key];

if(!fns || fns.length == 0){
return false;
}

for(var i=0, fn; fn=fns[i++];){
fn.apply(this, arguments);
}
}
};
var installEvent = function(obj){
for(var i in event){
obj[i] = event[i];
}
};

var salesOffices = {};
installEvent(salesOffices);

salesOffices.listen('squareMeter88', function( price ){
console.log('价格= ' + price);
});
salesOffices.listen("squareMeter110", function(price){
console.log('价格= ' + price);
});

salesOffices.trigger('squareMeter88', 2000000);
salesOffices.trigger('squareMeter88', 3000000);
+

以上代码,把事件的列表放在clientList数组中,listen方法是通过键值对的方式,key为事件,value为事件需要调用的方法,把他们放进数组,trigger是通过遍历数组去找到监听的事件A,然后通过遍历其value去触发对应的方法.
clientList的结构如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
clientList:[
{
squareMeter88: [
fn1,fn2,fn3,...
]
},
{
squareMeter100: [
fn1,fn2,fn3,...
]
},
{
要监听的事件: [
要触发的方法1,要触发的方法2,要触发的方法3,...
]
},
]
+

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/07/19/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\272\214-\342\200\224-\350\277\255\344\273\243\345\231\250\346\250\241\345\274\217/index.html" "b/2017/07/19/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\272\214-\342\200\224-\350\277\255\344\273\243\345\231\250\346\250\241\345\274\217/index.html" index e69de29b..68f1bb30 100644 --- "a/2017/07/19/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\272\214-\342\200\224-\350\277\255\344\273\243\345\231\250\346\250\241\345\274\217/index.html" +++ "b/2017/07/19/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\272\214-\342\200\224-\350\277\255\344\273\243\345\231\250\346\250\241\345\274\217/index.html" @@ -0,0 +1,727 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 设计模式学习之二 — 迭代器模式 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

设计模式学习之二 — 迭代器模式

+ + + +
+ + + + + +
+ + + + + +
+

迭代器模式介绍

+
+

js内置方法中有很多迭代方法,比如forEach,filter,map,every等,这些迭代器都是对数组中的每一项进行操作。

+
+

迭代器模式应用场景

+
+

某一件事中,有ABC三种备选方法,依次尝试ABC,如果A不行,就尝试B,如果B不行,就尝试C。按照普通的思路我们会选择用if else方法来解决,但是这样不优雅,相对其中某一项更改时就需要深入到if else方法中进行修改,于是,我们可以使用迭代器模式

+
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
var A = {
try {
A方法的代码
} catch (e) {
return false; // A方法行不通,返回false
}
};

var B = {
try {
B方法的代码
} catch (e) {
return false; // B方法行不通,返回false
}
};

var C = {
try {
C方法的代码
} catch (e) {
return false; // C方法行不通,返回false
}
};

var resultSolution = function(){
for( var i = 0, fn; fn = arguments[ i++ ]; ){
var theFn = fn();
if( theFn !== false ){
return theFn;
}
}
}

var getTheSolution = resultSolution(A, B, C);
+

这样,我们就能最后获取到是最终可行的是哪个方法,加入再增加两个方案,就直接在resultSolution(A, B, C)中增加D, E即可,而不用再去写if else;

+

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/08/20/\345\217\215\351\246\210\351\241\265\351\235\242\351\241\271\347\233\256\346\200\273\347\273\223/index.html" "b/2017/08/20/\345\217\215\351\246\210\351\241\265\351\235\242\351\241\271\347\233\256\346\200\273\347\273\223/index.html" index e69de29b..32bde186 100644 --- "a/2017/08/20/\345\217\215\351\246\210\351\241\265\351\235\242\351\241\271\347\233\256\346\200\273\347\273\223/index.html" +++ "b/2017/08/20/\345\217\215\351\246\210\351\241\265\351\235\242\351\241\271\347\233\256\346\200\273\347\273\223/index.html" @@ -0,0 +1,734 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 反馈页面项目总结 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

反馈页面项目总结

+ + + +
+ + + + + +
+ + + + + +
+

项目背景

+
+

这个页面是用vue构建,用来内嵌APP中进行用户反馈交互,反馈页面是一个web聊天记录页面,也可以编辑内容上传图片发送对话。

+
+

踩到的坑

+
+

1、每一条对话数据需要显示数据时间,连续一分钟内的几条对话数据只显示第一条对话的时间。通过v-for循环列出数据时间,每一条循环通过index去判断当前item与index-1的item的时间差,但是第一条会报错,因为取不到第0条的数据。
解决方案:因为vue数据绑定属性只能写变量,不能写语句,所以就无法在标签中去判断是否是第一条数据。就算是用二元操作符也无法识别,所以用(dialogItems[index-1] && dialogItems[index-1].createDate) || 0)就可以筛选出第一条,并把他的上一条设为0.

+

2、后端返回的时间格式是2017-10-10 13:30:00的格式,所以用Date.parse()来转化成时间戳进行比较,但是在手机端无法识别-格式的时间,所以Date.parse()无效,需要用.replace(/-/g,'/')来转化成/格式,再用Date.parse()

+

3、对话页面需要一进入就把页面拉到最底部来显示最新对话,可以用scrollTo(0,列表高度)来让页面滚动到底部。

+

4、输入页面的输入框textarea需要根据输入文本高度增加而增加,可以用vue的input事件来监听textarea的scrollHeight,使他的高度等于scrollHeight即可动态变高。

+

5、编辑页面上传图片需要有删除功能,但是当点击删除时,src数据绑定的变量清空后,src并没有清空,需要再把src设为一个字符串,这样页面上的图片便可删除,也可以用vue的$nextTick的回调方法来清空。

+

6、上传图片使用formData来提交,但是一直提交不过去,后来得知,是项目有axios的config配置,把上传的内容给序列化了,在axios中设置header:multipart/form-data,然后在config中去匹配该header使其不序列化即可。

+

7、在对话列表页点击编辑需要跳转到反馈编辑页面并自动弹出手机软键盘,使用focus()方法可以弹出。但是需要在对话列表页点击按钮才弹出,直接进入编辑页面并不会弹出。猜测是手机监测用户交互行为所设的屏障。

+

8、上传完照片后,有个替换功能,可以重新选择照片,就是点击替换按钮去触发input事件,这里有的mouseEvent

+
1
2
const evt = new MouseEvent( 'click', { bubbles: false, cancelable: true, view: window } );
this.$refs.fileBtn.dispatchEvent( evt );
+

这样就可以触发input file的点击事件

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/09/03/nginx\345\217\215\345\220\221\344\273\243\347\220\206\345\222\214\350\264\237\350\275\275\345\235\207\350\241\241\351\205\215\347\275\256/index.html" "b/2017/09/03/nginx\345\217\215\345\220\221\344\273\243\347\220\206\345\222\214\350\264\237\350\275\275\345\235\207\350\241\241\351\205\215\347\275\256/index.html" index e69de29b..c39dfa92 100644 --- "a/2017/09/03/nginx\345\217\215\345\220\221\344\273\243\347\220\206\345\222\214\350\264\237\350\275\275\345\235\207\350\241\241\351\205\215\347\275\256/index.html" +++ "b/2017/09/03/nginx\345\217\215\345\220\221\344\273\243\347\220\206\345\222\214\350\264\237\350\275\275\345\235\207\350\241\241\351\205\215\347\275\256/index.html" @@ -0,0 +1,734 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nginx反向代理和负载均衡配置 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

nginx反向代理和负载均衡配置

+ + + +
+ + + + + +
+ + + + + +
+

nginx介绍

+
+

nginx作为静态服务器,只能解析静态文件,像php文件就属于动态文件,所以无法打开php文件,因为nginx要想解析php文件,须配合php-fpm使用,nginx当需要解析php文件的时候就会把解析任务交给php-fpm服务,php-fpm再把解析结果返给nginx,最终返回给用户。最近研究了下nginx,使用它的反向代理和负载均衡来解决一些常见问题,下面记录一下。

+
+

反向代理

+
+

现在越来越多的前后端分离已经不只是代码上的分离,就连服务器也各自使用,所以前后端通信就会有跨域的现象出现,以往解决跨域就是使用jsonp,但是目前越来越多的人使用nginx反向代理,即前端请求不直接发给后端,而是发到nginx服务器上,nginx再根据你的配置进行转发,由nginx来访问后端地址,相当于是一个中介。下面是配置示例:

+
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
server
{
#监听端口
listen 81;

#域名
server_name 120.27.104.77;

index index.html index.htm index.php;

#站点目录
root /home/nginx;

location /three/
{
proxy_pass http://120.27.104.77:80/three/;
index index.html index.php;
proxy_set_header Host $host;
proxy_buffer_size 64k;
proxy_buffers 32 32k;
proxy_busy_buffers_size 128k;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
access_log on;
access_log /usr/local/webserver/nginx/logs/www_access.log main;
}

location ~* \.php$
{
root /home/sam;
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi.conf;
access_log on;
access_log /usr/local/webserver/nginx/logs/www_phpproxy_access.log main;
}
}
+

上面的配置表示nginx监听81端口,我自己把80端口分给了apache,当访问81端口下的/three目录下的静态文件时,nginx把请求转给80端口下的three文件,其实81端口下是没有任何文件的,nginx只是起到了转发请求的作用。location匹配php文件,当访问的是php文件,就把这个文件请求转到home/sam文件夹下,home/sam是apache的根目录,这样,nginx就把php请求转给了apache。最终,当访问http://120.27.104.77:81/three/index.php,nginx就把请求转给http://120.27.104.77:80/three/index.php,代理完成。

+
+

负载均衡

+
+

负载均衡指的是当一个服务器上的项目有很多用户时,服务器压力增大,需要其他服务器来帮忙分担请求,但是用户输入的网址不能变,所以,就应用到了nginx的负载均衡,负载均衡还是通过反向代理的方式,把请求转发给其他服务器,但是需要每一台服务器上的文件同步。下面是配置示例:

+

在http模块下添加负载均衡配置(默认使用的是轮询方式,weight表示是权重,下面表示82端口和80端口请求次数是1:1):

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
upstream myserver {
server 120.27.104.77:82 weight=1;
server 120.27.104.77:80 weight=1;
}

server模块下添加location规则:

location ~*test.php {
proxy_pass http://myserver;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
+

80端口依然是apache,82端口是nginx服务器,当我访问81端口下的test.php,nginx就把请求转给82端口,再次刷新就把请求转给80端口,依次反复,这样就实现了负载均衡,相当于是有两台服务器在支撑。多设几个就有多个服务器支撑。

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/10/14/python\345\255\246\344\271\240-\345\233\276\347\211\207\350\275\254\345\255\227\347\254\246\347\224\273/index.html" "b/2017/10/14/python\345\255\246\344\271\240-\345\233\276\347\211\207\350\275\254\345\255\227\347\254\246\347\224\273/index.html" index e69de29b..8f1c38cd 100644 --- "a/2017/10/14/python\345\255\246\344\271\240-\345\233\276\347\211\207\350\275\254\345\255\227\347\254\246\347\224\273/index.html" +++ "b/2017/10/14/python\345\255\246\344\271\240-\345\233\276\347\211\207\350\275\254\345\255\227\347\254\246\347\224\273/index.html" @@ -0,0 +1,728 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + python学习-图片转字符画 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

python学习-图片转字符画

+ + + +
+ + + + + +
+ + + + + +
+

前言

+
+

最近在学习python,惊讶于其处理数据方面的方便,以及目前机器学习潮流python占了不可动摇的地位,未来也是一股潮流,于是在熟悉python基本语法之后,决定先从小工具做起,慢慢练习,熟练掌握python的用法,目前觉得python在做一些日常小工具上还是挺方便的,这样对于自己来说,也不会只局限于“前端”,要往“软件工程师”方向发展。

+
+

原理

+
+

整个代码量不多,其中原理便是:颜色的色值区间为0-255,使用PIL的image模块读取图片的颜色值,例如(255,255,255,1),前三个数表示颜色值,第四个表示透明度。我们创建一个字符串数组,例如

+
1
2
3

把读取到的色值按从小到大取数组中的字符串,然后拼凑字符串,写入文件。把图片的像素转为色值的核心算法在于:
```gray = 0.2126 * r + 0.7152 * g + 0.0722 * b
+

我们需要获取在shell中输入的图片名,所以用argparse包来获取shell中的输入的变量。

+

以下是全部代码:

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
from PIL import Image
import argparse

# 灰度值小(暗)的用列表开头的符号,灰度值大(亮)的用列表末尾的符号。
# gray = 0.2126 * r + 0.7152 * g + 0.0722 * b

ascii_char = list("$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. ")
length = len(ascii_char)

# 颜色色值 0-255
MaxValue = 255

def get_char(r,g,b,alpha=256):
if alpha == 0:
return ' '

gray = 0.2126 * r + 0.7152 * g + 0.0722 * b
return ascii_char[int(gray / MaxValue * length )]

parser = argparse.ArgumentParser()

parser.add_argument('file')
parser.add_argument('--output')
parser.add_argument('--width', type = int, default=80)
parser.add_argument('--height', type = int, default = 80)

args = parser.parse_args()

IMG = args.file
WIDTH = args.width
HEIGHT = args.height
OUTPUT = args.output or 'output.txt'


if __name__ == '__main__':

im = Image.open(IMG)
im = im.resize((WIDTH, HEIGHT), Image.NEAREST)

txt = ""

for i in range(HEIGHT):
for j in range(WIDTH):
txt += get_char(*im.getpixel((j, i)))
txt += '\n'

print(txt)

with open(OUTPUT, 'w') as f:
f.write(txt)

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/10/14/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\233\233\342\200\224\350\201\214\350\264\243\351\223\276\346\250\241\345\274\217/index.html" "b/2017/10/14/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\233\233\342\200\224\350\201\214\350\264\243\351\223\276\346\250\241\345\274\217/index.html" index e69de29b..5963a952 100644 --- "a/2017/10/14/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\233\233\342\200\224\350\201\214\350\264\243\351\223\276\346\250\241\345\274\217/index.html" +++ "b/2017/10/14/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\233\233\342\200\224\350\201\214\350\264\243\351\223\276\346\250\241\345\274\217/index.html" @@ -0,0 +1,730 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 设计模式学习之四—职责链模式 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

设计模式学习之四—职责链模式

+ + + +
+ + + + + +
+ + + + + +
+

职责链者模式应用场景

+
+

该模式在业务中比较常见,常见场景是:检测用户是否满足A条件,不满足就检测是否满足B,再不满足就检测是否满足C,直到找到一个他满足的一个条件,但是从A-C是有优先级的,按照优先级一次降级检测。

+
+

职责链者模式应用案例

+
+

现在我们来模拟一个场景使用该模式:
用户来买手机,目前有三个优惠政策,分为优惠500,优惠200,无优惠,售罄。当然,优先级也是按照优惠大小来划分。当用户来买时,我们就要检测他满足哪种优惠。
随手来码代码的话:我们会用if判断来检测他满足哪种优惠,但是if层级太多的话,会显得代码非常乱,于是就用到职责连模式。
我们来看代码,首先列出三种优惠条件:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var order500 = function( orderType, pay, stock ){
if ( orderType === 1 && pay === true ){
console.log( '500 元定金预购,得到 100 优惠券' );
}else{
return 'nextSuccessor'; // 我不知道下一个节点是谁,反正把请求往后面传递
}
};
var order200 = function( orderType, pay, stock ){
if ( orderType === 2 && pay === true ){
console.log( '200 元定金预购,得到 50 优惠券' );
}else{
return 'nextSuccessor'; // 我不知道下一个节点是谁,反正把请求往后面传递
}
};
var orderNormal = function( orderType, pay, stock ){
if ( stock > 0 ){
console.log( '普通购买,无优惠券' );
}else{
console.log( '手机库存不足' );
}
};
+

以上代码,把每个优惠政策分别声明,如果满足该优惠条件,则执行优惠,否则就传给下一节点,但是我们需要把这些节点关联起来才行:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//  声明一个链
var Chain = function( fn ){
this.fn = fn;
this.successor = null;
};
// 设置下一节点
Chain.prototype.setNextSuccessor = function( successor ){
return this.successor = successor;
};
Chain.prototype.passRequest = function(){
// 检测当前节点是否满足条件
var ret = this.fn.apply( this, arguments );
if ( ret === 'nextSuccessor' ){
// 如果不满足,就递交给下一节点来执行
return this.successor && this.successor.passRequest.apply( this.successor, arguments );
}
// 如果满足当前节点条件,就返回当前节点的处理结果
return ret;
};
+

然后实例化各个节点,让他们串联起来:

1
2
3
4
5
6
7
8
//  实例化各个节点
var chainOrder500 = new Chain( order500 );
var chainOrder200 = new Chain( order200 );
var chainOrderNormal = new Chain( orderNormal );

// 通过 setNextSuccessor方法跟下一个节点关联起来
chainOrder500.setNextSuccessor( chainOrder200 );
chainOrder200.setNextSuccessor( chainOrderNormal );

+

检验一下成果:

1
2
3
4
chainOrder500.passRequest( 1, true, 500 ); // 输出:500 元定金预购,得到 100 优惠券
chainOrder500.passRequest( 2, true, 500 ); // 输出:200 元定金预购,得到 50 优惠券
chainOrder500.passRequest( 3, true, 500 ); // 输出:普通购买,无优惠券
chainOrder500.passRequest( 1, false, 0 ); // 输出:手机库存不足

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/10/22/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\272\224-\347\212\266\346\200\201\346\250\241\345\274\217/index.html" "b/2017/10/22/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\272\224-\347\212\266\346\200\201\346\250\241\345\274\217/index.html" index e69de29b..43a63770 100644 --- "a/2017/10/22/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\272\224-\347\212\266\346\200\201\346\250\241\345\274\217/index.html" +++ "b/2017/10/22/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\272\224-\347\212\266\346\200\201\346\250\241\345\274\217/index.html" @@ -0,0 +1,728 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 设计模式学习之五-状态模式 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

设计模式学习之五-状态模式

+ + + +
+ + + + + +
+ + + + + +
+

状态模式应用场景

+
+

这个模式在工作中也比较常见,就是点击按钮,根据按钮目前的状态来决定所要执行的操作,2个状态的比如开关按钮。我们普遍会拿if来做判断。但是状态比较多的情况下,多个if就比较low了。于是就应用到了状态模式

+
+

状态模式应用案例

+
+

比如我们在按灯泡开关的时候,灯泡的状态分为关灯,弱光,强光,超强光。

+

先上代码:

+
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
var OffLightState = function(light){
this.light = light;
}

OffLightState.prototype.buttonWasPressed = function(){
console.log('弱光');
this.light.setState(this.light.weakLightState);
}

var WeakLightState = function(light){
this.light = light;
}

WeakLightState.prototype.buttonWasPressed = function(){
console.log('强光');
this.light.setState(this.light.strongLightState);
}


var StrongLightState = function(light){
this.light = light;
}

StrongLightState.prototype.buttonWasPressed = function(){
console.log('超强光');
this.light.setState(this.light.superstrongLightState);
}

var SuperStrongLightState = function(light){
this.light = light;
}

SuperStrongLightState.prototype.buttonWasPressed = function(){
console.log('关灯');
this.light.setState(this.light.offLightState);
}


var Light = function(){
this.offLightState = new OffLightState(this);
this.weakLightState = new WeakLightState(this);
this.strongLightState = new StrongLightState(this);
this.superstrongLightState = new SuperStrongLightState(this);
this.button = null;
}

Light.prototype.init = function(){
var button = document.createElement('button'),
_self = this;

this.button = document.body.appendChild(button);
this.button.innerHTML = '开关';

this.currState = this.offLightState;

this.button.onclick = function(){
_self.currState.buttonWasPressed();
}
}

Light.prototype.setState = function(newState){
this.currState = newState;
}

var light = new Light();
light.init();
+

这段代码的核心思想就是为每个状态创建个对象,然后每个状态对象里都声明一个buttonWasPressed点击按钮方法,重要的是每个状态里都要显式的写出当前状态的下一个状态,然后切换到下一个状态,这样每次点击按钮,其实触发的是不同状态对象里的buttonWasPressed方法。

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/12/10/vue-cli router history \346\234\215\345\212\241\347\253\257\351\205\215\347\275\256/index.html" "b/2017/12/10/vue-cli router history \346\234\215\345\212\241\347\253\257\351\205\215\347\275\256/index.html" index e69de29b..77868358 100644 --- "a/2017/12/10/vue-cli router history \346\234\215\345\212\241\347\253\257\351\205\215\347\275\256/index.html" +++ "b/2017/12/10/vue-cli router history \346\234\215\345\212\241\347\253\257\351\205\215\347\275\256/index.html" @@ -0,0 +1,734 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + vue-cli router history 服务端配置 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

vue-cli router history 服务端配置

+ + + +
+ + + + + +
+ + + + + +
+

项目背景

+
+

最近在做一个项目,用vue-cli搭建,build之后,传到服务器上,手动输入二级子路由,页面显示404。

+
+

问题原因

+
+

手动输入链接,都是要走服务器http请求的,而vue build之后是一个单页应用,所有的路由配置都是通过index.html用js去解析,所以输入的子路由通过服务器解析后并未找到该文件,因此报错404。

+
+

解决方案

+
+

既然要通过index.html去跳转,我们就要把所有的手动输入子路由都要转向到index.html文件,由于我用的是apache,vue-router也说明了history模式需要后台去配置,因此我们在httpd.conf文件中要开启apache的rewrite模块,然后设置允许通过.htaccess文件来设置override规则。

+

httpd.conf文件:

1
2
3
4
5
6
7
<Directory "/home/sam">
···

AllowOverride All

···
</Directory>

+

然后在项目根目录中添加.htaccess文件,文件中写入vue-router文档中的配置:

1
2
3
4
5
6
7
8
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</IfModule>

+

RewriteBase /指向的是服务器根目录,我的项目是在二级目录,即/jxvote/,因此要把RewriteBase设置为RewriteBase /jxvote/, RewriteRule . /index.html [L]设置为RewriteRule . /jxvote/index.html [L]

+

最后再把router中的base设置为:base:'/jxvote/'

+

这样就可以使用history模式下,手动输入子路由打开页面了。

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/12/10/\345\276\256\344\277\241\345\244\247\345\261\217\345\271\225\346\212\275\345\245\226\351\241\271\347\233\256\346\200\273\347\273\223/index.html" "b/2017/12/10/\345\276\256\344\277\241\345\244\247\345\261\217\345\271\225\346\212\275\345\245\226\351\241\271\347\233\256\346\200\273\347\273\223/index.html" index e69de29b..d991a079 100644 --- "a/2017/12/10/\345\276\256\344\277\241\345\244\247\345\261\217\345\271\225\346\212\275\345\245\226\351\241\271\347\233\256\346\200\273\347\273\223/index.html" +++ "b/2017/12/10/\345\276\256\344\277\241\345\244\247\345\261\217\345\271\225\346\212\275\345\245\226\351\241\271\347\233\256\346\200\273\347\273\223/index.html" @@ -0,0 +1,727 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 微信大屏幕抽奖项目总结 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

微信大屏幕抽奖项目总结

+ + + +
+ + + + + +
+ + + + + +
+

项目背景

+
+

商家要在led上投放个抽奖页面,就是用户扫描二维码进入h5页面报名签到,签到成功后,led上就要及时显示已签到用户信息。

+
+

实现过程

+
+

由于页面要及时显示已签到用户,那么就要后端轮询去查询数据库是否有新用户签到,如果有新用户,就发送给前端。后端我用的是php,于是就打算尝试一下SSE(Server Send Event),新插入的数据中,建立一个send字段来记录是否将已签到用户发送给前端,新插入已签到用户数据时,默认记录send字段值是-1,php去查询send=-1的数据,然后发送给前端,并将这些数据的send值设为1。php的SSE需要声明header('Content-Type: text/event-stream')来表示这是一个事件流脚本,并需要设置不缓存header("Cache-Control:no-cache,must-revalidate"),将数据组织好后,需要这样输出:

+
1
2
3
echo "retry: 3000\n\n";
echo "data:" . json_encode($responseinfo)."\n\n";
flush();
+

retry表示间隔时间是3000ms,输出的数据必须以data开头,以换行符\n结尾,前端收到的数据是字符串格式,所以需要后端组织成json,前端再把数据转成json。最后flush()表示再次执行。

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/12/10/\346\211\213\346\234\272\347\253\257\347\274\226\350\276\221\345\231\250\346\200\273\347\273\223/index.html" "b/2017/12/10/\346\211\213\346\234\272\347\253\257\347\274\226\350\276\221\345\231\250\346\200\273\347\273\223/index.html" index e69de29b..545ef4f9 100644 --- "a/2017/12/10/\346\211\213\346\234\272\347\253\257\347\274\226\350\276\221\345\231\250\346\200\273\347\273\223/index.html" +++ "b/2017/12/10/\346\211\213\346\234\272\347\253\257\347\274\226\350\276\221\345\231\250\346\200\273\347\273\223/index.html" @@ -0,0 +1,741 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 手机端编辑器总结 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

手机端编辑器总结

+ + + +
+ + + + + +
+ + + + + +
+

项目背景

+
+

由于公司业务是做书籍阅读类的。所以产品提出要在webapp的发帖页面中,能输入文本,插入图片,和插入书籍。

+
+

采坑过程

+
+

本来手机端做编辑器可以用现成的插件,文本和图片都是比较容易解决。但是为了插入书籍,只有自己来做这个功能。

+
+

坑 One

+
+

输入框用div的contenteditable属性来做,但是在输入框中输入enter键换行时,换行的文本无法获得焦点,是因为换行时会自动生成div,但生成的div并没有contenteditable属性,于是就监听enter键事件,阻止默认事件,动态重新创建contenteditable的div。

+
+

坑 Two

+
+

删除时,删到开头,要把光标移到上一个文本div。需要监听delete键,手动去删除空白的div,再把光标移动到上一个文本的末尾。iphone端表现良好,但是安卓端无法监听到delete键,所以就意识到用div还是不可行的。

+

于是,还是要尝试用原生的textarea,插入文本就是插入textarea,插入图片和书籍就是在文本节点下面插入图片和书籍节点,但在图片和书籍节点后面要再插入个空白的textarea可以让其继续输入。

+

但是textarea的缺点在于无法动态改变他的高度,但是在网上找到个方案,核心代码如下:

+
1
2
3
4
<div class="expandingArea" data-type="textarea">
<pre><span></span><br></pre>
<textarea data-type="text"></textarea>
</div>
+

每一个创建的textarea标签都需要这样包裹一下,为的是让其可以自适应高度。

+

以上代码在输入textarea时,监听input事件,把textarea的value复制给span标签,expandingArea用相对定位,expandingArea的高度由span标签撑开,span的高度可以跟随文本变化,span的文本又是跟textarea保持一致。这样便可以实现textarea的高度自适应了。但是要注意一点:textarea和pre里的字体样式必须保持一致

+

css代码如下:

+
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
.expandingArea {
position: relative;

/*textarea和pre里的字体样式必须保持一致*/
textarea,
pre {
margin: 0;
padding: 0;
outline: 0;
border: 0;
font-size: 15px;
line-height: 17px;
min-height: 15px;
color: #474e58;
width: 100%;
white-space: pre-wrap;
word-wrap: break-word;
}

textarea {
position: absolute;
top: 0;
left: 0;
height: 100%;
resize: none;
overflow: hidden;
}
pre {
display: block;
visibility: hidden;
}
}
+

插入书籍时,拿到书籍的json然后生成一个div放置在文本div下面,并在书籍div后生成一个新的空白文本div,这样就可以继续在书籍下面输入文本,当删除文本时,假如删到开头,就把当前文本的value附加给上一个文本div,再删除当前的文本节点。这样整个需求算是完成了。

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2017/12/31/vue \351\207\207\345\235\221\346\200\273\347\273\223/index.html" "b/2017/12/31/vue \351\207\207\345\235\221\346\200\273\347\273\223/index.html" index e69de29b..29906c09 100644 --- "a/2017/12/31/vue \351\207\207\345\235\221\346\200\273\347\273\223/index.html" +++ "b/2017/12/31/vue \351\207\207\345\235\221\346\200\273\347\273\223/index.html" @@ -0,0 +1,735 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + vue 采坑总结 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

vue 采坑总结

+ + + +
+ + + + + +
+ + + + + +
+

项目背景

+
+

本文记录自己学习使用vue中所踩到的坑。

+
+

采坑记录

+
+

1、postcss配置
在项目中,如果是用rem单位来布局的话,css中最长用到的就是autoprefixer和px2rem,这两个都是postcss的插件,那么如何在webpack中配置postcss呢?就连webpack上的文档经过亲手尝试,也是报错,经过多重搜索,最后是配置这样的,在module中的rules选项中配置,因为是在解析vue文件时解析css,所以要配在匹配vue的文件下

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
postcss: [
require( 'autoprefixer' )( {
browsers: [ 'last 10 versions', 'Firefox >= 20', '> 1%', 'iOS 4', 'android >= 2.0', 'and_uc > 1' ]
} ),
require( 'postcss-plugin-px2rem' )( {
rootValue: 10,
minPixelValue: 2,
} )
]
}
},
+

然后再加上自适应的方法,动态判断屏幕大小来改变字体大小,如果设计稿宽度是375px:

1
2
3
4
5
6
7
8
9
var response = function () {
var w = document.documentElement.clientWidth;
document.documentElement.style.fontSize = w / 37.5 + 'px';
};
window.onresize = function () {
response();
clearTimeout( this.responseTimer );
this.responseTimer = setTimeout( response, 300 );
};

+

2、webpack代码分割
webpack提供了代码分割功能,可以根据路由来动态加载所需模块,减小了初次加载的体积,在编写路由模块时,将路由component动态引入:

1
2
3
4
5
6
7
8
9
const Index = ( r ) => require.ensure( [], () => r( require( './index.vue' ) ) , 'moduleA');
import ChildrenA from './childrenA/router';

export default {
path: '/a',
name: 'module-a',
component: Index,
children: [ ChildrenA ]
}

+

第一行代码中,moduleA表示为该component命名,当webpack打包时,会将所有同名的组件打包到一个js文件中,当加载到/a的路由时,就会加载该js文件,这个文件中包含了所有名字为moduleA的模块。

+

3、vuex局部模块
vuex可以理解为vue中专门用来处理事务数据的,里面变量在全局可访问,当项目变大,变量变多时,vuex提供了modules属性,可以将数据以模块来划分。

1
2
3
4
5
6
7
8
9
10
11
import moduleA from '../moduleA/store';
import moduleB from '../moduleB/store';

const modules = {
moduleA,
moduleB
};

export default new Vuex.Store({
modules
})

+

moduleA为子模块,它又可以在内部继续划分为多个子模块:

+
1
2
3
4
5
6
7
8
9
10
export default {
namespaced: true,
modules: {
children: childrena
},
state,
types,
mutations,
actions
}
+

需要注意的是,当在内部划分成子模块时,要加上namespaced属性,这样子模块就可以继承父模块的命名空间,当在组件中调用moduleA下的子模块的action时,就要加上前缀:

1
2
3
4
...mapActions( {
'setmoduleA': 'moduleA/moduleAfn',
'setmoduleB': 'moduleB/children/moduleBfn'
} ),

+

4、webpack proxy代理
在devServer中添加proxy代理,要添加pathRewrite属性,这样,当我们请求/api/v2/api/Community/Navigations时,就会转到http://www.baidu.com/v2/api/Community/Navigations

1
2
3
4
5
6
7
8
9
proxy: {
'/api/': {
target: 'http://www.baidu.com/',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}

+

5、webpack压缩问题
webpack自带的压缩功能uglifyjsplugin方法无法对ES6的语法进行压缩,要先在module中添加bable-loader,babel会把ES6转为ES5的语法,然后就可以压缩代码了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
module:{
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
}
}
],
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
]

+

(未完待续)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/01/21/gulp \346\236\204\345\273\272\346\200\273\347\273\223/index.html" "b/2018/01/21/gulp \346\236\204\345\273\272\346\200\273\347\273\223/index.html" index e69de29b..47a76499 100644 --- "a/2018/01/21/gulp \346\236\204\345\273\272\346\200\273\347\273\223/index.html" +++ "b/2018/01/21/gulp \346\236\204\345\273\272\346\200\273\347\273\223/index.html" @@ -0,0 +1,725 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + gulp 构建总结 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

gulp 构建总结

+ + + +
+ + + + + +
+ + + + + +
+

项目背景

+
+

本文记录下自己使用gulp构建的配置。

+
+

代码配置

+
+
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
var gulp = require( 'gulp' );
var htmlmin = require( "gulp-htmlmin" );
var uglify = require( 'gulp-uglify' );
var livereload = require( 'gulp-livereload' );
var babel = require( 'gulp-babel' );
var browserify = require( 'browserify' );
var source = require( 'vinyl-source-stream' );
var postcss = require( 'gulp-postcss' );
var autoprefixer = require( 'autoprefixer' );
var cssnano = require( 'cssnano' );
var less = require( 'gulp-less' );

// 压缩HTML
gulp.task( 'minify-html', function () {

var options = {
removeComments: true, //清除HTML注释
collapseWhitespace: true, //压缩HTML
collapseBooleanAttributes: true, //省略布尔属性的值 <input checked="true"/> ==> <input checked />
removeEmptyAttributes: true, //删除所有空格作属性值 <input id="" /> ==> <input />
removeScriptTypeAttributes: true, //删除<script>的type="text/javascript"
removeStyleLinkTypeAttributes: true, //删除<style>和<link>的type="text/css"
minifyJS: true, //压缩页面JS
minifyCSS: true //压缩页面CSS
};
gulp.src( '*.html' )
.pipe( htmlmin( options ) )
.pipe( gulp.dest( 'dist' ) )
.pipe( livereload() );

} );

// 把图片放到dist中
gulp.task( 'img', function () {
return gulp.src( 'img/*' )
.pipe( gulp.dest( "dist/img" ) );
} )

// 给css使用自动加前缀插件,并压缩css,插件来源于postcss
gulp.task( 'css', function () {
var plugins = [
autoprefixer( { browsers: [ 'last 2 version', '> 0.1%' ] } ),
cssnano()
];

return gulp.src( 'style/*' )
.pipe( less() )
.pipe( postcss( plugins ) )
.pipe( gulp.dest( 'dist/style' ) );
} );

// 给js使用babel,并压缩
gulp.task( 'script', function () {
gulp.src( 'js/*.js' )
.pipe( babel( {
presets: [ 'env' ]
} ) )
.pipe( uglify() )
.pipe( gulp.dest( 'dist/js' ) )
.pipe( livereload() );
} )

// browserify预编译,打包js
gulp.task( "browserify", function () {
var b = browserify( {
entries: "./dist/js/main.js"
} );

return b.bundle()
.pipe( source( "bundle.js" ) )
.pipe( gulp.dest( "dist/js" ) );
} );

// 监听代码热更新并重新执行任务
gulp.task( 'watch', function () {
livereload.listen({port: 12345});
gulp.watch( 'style/*', [ 'css' ] );
gulp.watch( 'wxphp/*', [ 'wxphp' ] );
gulp.watch( 'wxshare/*', [ 'wxshare' ] );
gulp.watch( 'js/*', [ 'script', 'browserify' ] );
gulp.watch( 'index.html', [ 'minify-html' ] );
gulp.watch( 'cj.html', [ 'cj' ] );
} )

gulp.task( 'default', [ 'css', 'script', 'minify-html', 'img', 'browserify', 'watch' ] );
+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/01/21/npm \347\274\226\345\206\231\345\217\221\345\270\203vue\346\217\222\344\273\266\350\256\260\345\275\225/index.html" "b/2018/01/21/npm \347\274\226\345\206\231\345\217\221\345\270\203vue\346\217\222\344\273\266\350\256\260\345\275\225/index.html" index e69de29b..7f453dc5 100644 --- "a/2018/01/21/npm \347\274\226\345\206\231\345\217\221\345\270\203vue\346\217\222\344\273\266\350\256\260\345\275\225/index.html" +++ "b/2018/01/21/npm \347\274\226\345\206\231\345\217\221\345\270\203vue\346\217\222\344\273\266\350\256\260\345\275\225/index.html" @@ -0,0 +1,741 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + npm 编写发布vue插件记录 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

npm 编写发布vue插件记录

+ + + +
+ + + + + +
+ + + + + +
+

项目背景

+
+

本文记录自己学习npm编写vue插件,并导出包文件,发布到npm平台,供其他地方全局调用。

+
+

过程记录

+
+

首先使用vue-cli脚手架下载一个简版的vue框架webpack-simple,然后在src文件中新建lib文件夹用来存放插件代码,在lib中新建index.js和index.vue,在index.vue中写一个按钮,表示是我们的插件

+

index.vue代码:

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
<template>
<div class="button">
<button @click="handler">这是一个按钮</button>
</div>
</template>

<script type="application/ecmascript">
export default {
name: 'test-button',
data() {
return {};
},
methods: {
handler() {
console.log( '点击按钮' );
}
}
};
</script>

<style type="text/less" lang="less" scoped>
.button {
width: 100px;
height: 20px;
text-align: center;
margin: 0 auto;
}
</style>

+

在index.js中将组件模块化,并导出组件

+

index.js代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Index from './index.vue';

const button = {

//通过vue提供的install方法来将组件注册到vue全局中。
install( Vue ) {
Vue.component( Index.name, Index );
}
}

if ( typeof window !== 'undefined' && window.Vue ) {
window.Vue.use( Index );
}

// 将组件导出
export default button;

+
+

打包发布

+
+

插件已经编写完毕,我们只需要访问index.js文件就能使用该组件,接下来就是通过webpack将组件代码打包,在项目根目录新建一个webpack-library.js文件来编写webpack打包组件的配置,里面的配置跟webpack.config.js大致相同,但是需要修改文件打包入口出口。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
//  webpack.config.js的入口是main.js文件,表示是整个项目的入口,但是我们这里只是要打包按钮组件,所以入口要改为lib下的index.js文件
entry: './src/lib/index.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
// 为了将组件打包出来的文件区分出来,我们要重命名打包后的js文件名
filename: 'test-button.js',
// 插件的名字
library: "TestButton",
// 不懂,反正写'umd'就是了
libraryTarget: "umd",
umdNamedDefine: true
},
+

接下来是package.json的配置:
声明一个包文件入口,表示别人下载了组件后,使用时的入口文件,其实就是上面配置后,生成的文件地址

+
1
"main": "./dist/test-button.js",
+

新建一个npm命令用来打包组件

+
1
2
3
4
5
"scripts": {
···
"publish": "webpack --config webpack-library.js"
···
},
+

然后运行npm run publish开始打包,再运行npm publish发布npm包,发布成功后,我们就可以在npm上看到自己写的包了,使用时,就运行npm install vue-plugin,然后在vue项目中引入,注册:

+
1
2
import TestButton from 'vue-plugin';
Vue.use( TestButton );
+

使用:

1
<test-button></test-button>

+

在项目中就可以看到自己编写的组件了。

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/02/21/h5\345\260\217\346\270\270\346\210\217\345\210\206\344\272\253/index.html" "b/2018/02/21/h5\345\260\217\346\270\270\346\210\217\345\210\206\344\272\253/index.html" index e69de29b..d49d465d 100644 --- "a/2018/02/21/h5\345\260\217\346\270\270\346\210\217\345\210\206\344\272\253/index.html" +++ "b/2018/02/21/h5\345\260\217\346\270\270\346\210\217\345\210\206\344\272\253/index.html" @@ -0,0 +1,741 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + H5小游戏分享 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

H5小游戏分享

+ + + +
+ + + + + +
+ + + + + +
+

项目背景

+
+

本文记录自己在公司内部前端组关于h5小游戏的分享。

+
+

特点

+
+

轻量,简单,基于js+canvas

+
+

1.页面适配布局

+
+

由于各个小游戏框架库都是基于canvas,当中的元素坐标基于px,所以rem方案不适用,而是按照640的屏幕去写页面,然后再等比缩放,这样其中的元素该位移多少还是位移多少,不同屏幕下,他的位移值是一样的, 只不过视觉上经过放大缩小后,就适配了布局。

+

a.
横屏或竖屏布局后,当监测到用户手机为非期望屏幕方向时,弹层提示。

+

b.
写2套css,分别为元素横屏和竖屏布局,然后屏幕旋转时,暂停游戏,切换布局,再把当前数据套进去。

+
+

2.js游戏引擎

+
+

a.
createjs,pixijs,phaser
2D,支持canvas,webGL

+

createjs,pixijs两个元素结构 stage-container-sprite

+

b.
egret,LayaAir,cocos2D-js,three.js
2D,3D等中大型游戏

+

3.工具
制作雪碧图-texturePckageGUI
生成雪碧图+json,json中包含各个图的位置信息

+

骨骼动画-dragonbonesPro

+

4.碰撞检测
https://aotu.io/notes/2017/02/16/2d-collision-detection/

+

5.源码网
http://www.codefans.net/jscss/sort/list_7_1.shtml

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/03/31/HTTP\347\274\223\345\255\230\346\234\272\345\210\266/index.html" "b/2018/03/31/HTTP\347\274\223\345\255\230\346\234\272\345\210\266/index.html" index e69de29b..4ea30741 100644 --- "a/2018/03/31/HTTP\347\274\223\345\255\230\346\234\272\345\210\266/index.html" +++ "b/2018/03/31/HTTP\347\274\223\345\255\230\346\234\272\345\210\266/index.html" @@ -0,0 +1,756 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + HTTP缓存机制 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

HTTP缓存机制

+ + + +
+ + + + + +
+ + + + + +

深入理解HTTP缓存

+
+

前言

+
+

在网上看了无计其数关于HTTP缓存的文章,在这里记录下自己的理解和总结,尽量使用最简单的流程来缕清缓存机制的从头到尾的过程。

+
+

疑问

+
+

作为前端开发者,对于浏览器调试界面的network肯定都有所了解,以一个图片资源为例,我们刷新页面,network中此图片资源时而返回status 200,时而返回200(from disk cache),时而返回304 (not modify),我们都知道是缓存导致状态码的不同,但是到底是什么情况下才会返回对应的状态码呢,傻傻分不清楚。

+
+

解析

+
+

假如我们访问这个图片资源,服务器会返回资源文件和关于这个资源的响应信息如下:

+
1
2
3
4
5
6
7
8
9
10
11
12
(Status-Line)      HTTP/1.1 200 OK
Date Sat, 31 Mar 2018 03:42:12 GMT
Server Apache/2.2.11 (Unix)PHP/5.2.9
Last-Modified Thu, 26 Nov 2009 13:50:19 GMT
Expires Wed, 23 Dec 2018 06:04:03 GMT
Etag “8fb8b-14-4794674acdcc0″
Cache-Control max-age=1000
Accept-Ranges bytes
Content-Length 20
Keep-Alive timeout=5, max=100
Connection Keep-Alive
Content-Type text/html
+

以上信息中,关于缓存的key有 Last-Modified Etag Expires Cache-Control,

+
    +
  • Last-Modified: 上次资源修改时间

    +
  • +
  • Etag: 资源的标识符,每次修改资源都会对应生成一个标识符来表示此版本的资源,可以理解成资源版本号

    +
  • +
  • Expires: 资源过期时间,返回的是服务器时间

    +
  • +
  • Cache-Control: 资源缓存有效期,以秒为单位

    +
  • +
+

HTTP缓存机制分为强缓存和协商缓存:

+

· Expires和Cache-Control是触发强缓存的key

+

· Last-Modified和Etag是触发协商缓存的key

+

强缓存优先级高于协商缓存,也就是说,会先看强缓存,强缓存生效,就直接使用强缓存,强缓存过期,再去使用协商缓存。

+

那么当浏览器加载资源时,缓存机制的处理流程如下:

+

1、查看Cache-Control和Expires过期没,如果这两项都没过期,就直接使用浏览器目录chche文件下的缓存文件,返回状态码200(from disk cache),这一步,没有访问服务器。

+

2、假如Cache-Control和Expires都过期了,HTTP请求中就携带Last-Modified和Etag(协商缓存)去访问服务器资源,服务器会根据HTTP带来的信息和当前服务器关于此资源的最新的Last-Modified和Etag进行对比,对比结果有两种:

+
    +
  • 如果HTTP中的Last-Modified和Etag信息和服务器中的Last-Modified和Etag信息一致,就说明没有修改,返回状态码304(Not modify)。

    +
  • +
  • 对比结果不一致,返回状态码200,并返回新的资源文件。

    +
  • +
+

以上便是自己对缓存机制的理解,如有写的不对的地方,还望指正互相交流。

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/03/31/js \345\207\275\346\225\260\346\237\257\351\207\214\345\214\226/index.html" "b/2018/03/31/js \345\207\275\346\225\260\346\237\257\351\207\214\345\214\226/index.html" index e69de29b..5e5007c3 100644 --- "a/2018/03/31/js \345\207\275\346\225\260\346\237\257\351\207\214\345\214\226/index.html" +++ "b/2018/03/31/js \345\207\275\346\225\260\346\237\257\351\207\214\345\214\226/index.html" @@ -0,0 +1,729 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + js 函数柯里化 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

js 函数柯里化

+ + + +
+ + + + + +
+ + + + + +
+

前言

+
+

函数柯里化是一种编程技巧,表现特点是将多个函数,一层一层包裹,执行最外部函数,把参数传给与其相邻的内层函数,递归调用。来看代码:

+
+

代码

+
+
1
2
3
4
5
6
7
8
9
10
11
var testCurried = function ( a ) {
return function ( b ) {
return function ( c ) {
return function ( d ) {
console.log( a + b + c + d );
}
}
}
}

testCurried( 1 )( 2 )( 3 )( 4 ); // 10
+

如果要锁定前三个参数,第四个参数灵活化,那就把前三个方法的调用赋值给一个方法:

+
1
2
3
var test1 = testCurried( 1 )( 2 )( 3 ); // 返回的是个方法

test1( 4 ); // 10
+

对于最后一层调用函数来说,前三个函数形成了闭包,把参数这个变量传递给了最内层函数,test1testCurried( 1 )( 2 )( 3 )的执行结果。

+

以上便是自己对函数柯里化的简单理解。

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/03/31/js\346\267\261\346\213\267\350\264\235/index.html" "b/2018/03/31/js\346\267\261\346\213\267\350\264\235/index.html" index e69de29b..e4100d60 100644 --- "a/2018/03/31/js\346\267\261\346\213\267\350\264\235/index.html" +++ "b/2018/03/31/js\346\267\261\346\213\267\350\264\235/index.html" @@ -0,0 +1,726 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + js深拷贝 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

js深拷贝

+ + + +
+ + + + + +
+ + + + + +
+

前言

+
+

js数据类型分为基本数值类型(Undefined,Boolean,number, string)和引用类型(array,object,null),基本数值类型是在栈中的,引用类型是在堆中的,因此对象是在堆中占据内存的,因此对象的改变,其实是指针指向的对象的改变,因此引用这个对象的对象都会改变。

+
+

代码

+
+
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
const obj1 = {
name: 'sam',
sex: 'man',
love: [ '1', '2', '4' ]
};

// const deepCopy = function ( obj ) {
// let newobj;
//
// console.log( typeof obj );
// switch ( typeof obj ) {
// case 'undefined':
// break;
// case 'string':
// newobj = obj + '';
// break;
// case 'number':
// newobj = obj - 0;
// break;
// case 'boolean':
// newobj = obj;
// break;
// case 'object':
// if ( obj === null ) {
// newobj = null;
// } else {
// if ( obj instanceof Array ) {
// newobj = [];
// for ( let i = 0; i < obj.length; i++ ) {
// newobj.push( deepCopy( obj[ i ] ) );
// }
// } else {
// newobj = {};
// for ( let key in obj ) {
// newobj[ key ] = deepCopy( obj[ key ] );
// }
// }
// }
// break;
// default:
// newobj = obj;
// }
//
// return newobj;
// };

const deepCopy = function ( obj ) {
return JSON.parse( JSON.stringify( obj ) );
};

const obj2 = deepCopy( obj1 );

console.log( obj2 );

obj2.love.push( '3', '3' );

console.log( obj1 );
+

以上是深拷贝方法,对象复制后,新对象的改变不会相互影响。

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/08/01/react\351\241\271\347\233\256\346\220\255\345\273\272\346\265\201\347\250\213/index.html" "b/2018/08/01/react\351\241\271\347\233\256\346\220\255\345\273\272\346\265\201\347\250\213/index.html" index e69de29b..e14e4a41 100644 --- "a/2018/08/01/react\351\241\271\347\233\256\346\220\255\345\273\272\346\265\201\347\250\213/index.html" +++ "b/2018/08/01/react\351\241\271\347\233\256\346\220\255\345\273\272\346\265\201\347\250\213/index.html" @@ -0,0 +1,776 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + react项目搭建流程 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

react项目搭建流程

+ + + +
+ + + + + +
+ + + + + +

基于create-react-app,记录react项目搭建流程。

+

ant-design与css

    +
  • css-modules的css模块化和ant-design的样式冲突。
    解决办法:把webpack-dev中的css解析规则和node_modules分开,原先的规则加入include: /node_modules|antd\.css/,然后把css规则复制一份,再排除antd.css:exclude: /node_modules|antd\.css/
    并定义css命名规则:modules: true, localIdentName: "[local]_[hash:base64:5]"
    需要支持less的话,就在use中push一条:{loader:require.resolve('less-loader')}
    ant-design懒加载:在babel的options中添加属性:
    plugins: [ + ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": 'css' }] + ]
  • +
+

react-router

    +
  • 引入react-router-dom
  • +
  • 编写router配置:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    const routes = [
    {
    path: '/home/dashboard',
    component: DashBoard
    },
    {
    path: '/home/sip/collect',
    component: Collect
    },
    {
    path: '/home/sip/defectWrite',
    component: DefectWrite
    }]
    +
  • +
  • 然后jsx写入到html中:

    +
  • +
+
1
2
3
{routes.map( ( route, index ) => (
<Route key={index} path={route.path} component={route.component}/>
) )}
+
    +
  • js跳转路由:
  • +
+
1
this.props.history.push( key );
+

mobx

    +
  • 声明store

    +
    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
    import {observable, action, computed} from 'mobx';

    class State {
    @observable a = 0; // 声明变量

    @computed
    get b() { // 依赖其他变量的变量
    return this.a+3;
    }
    }

    class Actions {
    constructor({state}){
    this.state = state; // 将state初始化
    }

    @action //action改变变量
    add = () =>{
    this.state.a++;
    }
    }

    const state = new State();

    export default new Actions({state});
    +
  • +
  • 业务层与数据层的连接

    +
  • +
+
1
2
3
4
5
6
7
8
9
@inject( 'state', 'actions' )   //将store注入到业务层
@observer
class DashBoard extends React.Component {
render() {
const {state, actions} = this.props;
<p>a:{state.a}</p>
<Button type="primary" onClick={actions.add}>+</Button>
}
}
+

插槽

    +
  • 创建插槽模板

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    import React from 'react';
    import style from './style.less';

    class Card extends React.Component{
    render(){
    return (
    <div className={style.card}>
    <div className={style.cardTitle}>{this.props.title}</div>
    {this.props.children}
    </div>
    )
    }
    }

    export default Card;
    +
  • +
  • 使用插槽

    +
    1
    2
    3
    4
    5
    6
    import Card from '@/components/common/Card';

    <Card className={style.collectInfo} title='基本信息'>
    <UploadPhoto></UploadPhoto>
    <Message formData={this.state.collectMessage}></Message>
    </Card>
    +
  • +
+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/09/04/\344\275\277\347\224\250fetch\344\273\243\346\233\277ajax/index.html" "b/2018/09/04/\344\275\277\347\224\250fetch\344\273\243\346\233\277ajax/index.html" index e69de29b..2ccf623d 100644 --- "a/2018/09/04/\344\275\277\347\224\250fetch\344\273\243\346\233\277ajax/index.html" +++ "b/2018/09/04/\344\275\277\347\224\250fetch\344\273\243\346\233\277ajax/index.html" @@ -0,0 +1,732 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 使用fetch代替ajax | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

使用fetch代替ajax

+ + + +
+ + + + + +
+ + + + + +

基于fetch API,前后端交互不再依赖第三方包。

+
+

引言

+
+

基于fetch API,前后端交互不再依赖第三方包。
以下是自己项目中使用fetch方法进行交互。

+
    +
  • get

    +
    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
    const fetchGET = ( url, params = {} ) => {

    let headerObj = {
    credentials: 'include', // 设置跨域时,也可以发送cookie
    method: 'GET',
    };

    let urlObj = url;

    if ( JSON.stringify( params ) !== '{}' ) {
    let temp = [];
    const len = Object.keys( params ).length;
    Object.keys( params ).map( ( v, i ) => {
    temp.push( `${v}=${params[ v ]}` );
    if ( i + 1 < len ) {
    temp.push( '&' );
    }
    } );

    urlObj = `${url}?${temp.join( '' )}`;
    }

    return fetch( `${urlObj}`, headerObj )
    .then( ( response ) => {
    return response.json();
    } )
    .then( ( data ) => {
    if ( data.status < 0 ) {
    Message.error( data.msg || '请求失败' );
    } else if (data.status === 1){
    data.msg && Message.success( data.msg );
    }
    return data;
    } )
    .catch( ( e ) => {
    return {
    msg: '请求失败'
    }
    } )
    }
    +
  • +
  • post file
    使用formData进行文件提交。

    +
    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
    const fetchFILE = ( url, params = {} ) => {

    let headerObj = {
    credentials: 'include',
    method: 'POST'
    };

    return fetch( url, {
    ...headerObj,
    body: params
    } ).then( function ( response ) {
    return response.json();
    } ).then(data => {
    if ( data.status < 0 ) {
    Message.error( data.msg || '请求失败' );
    } else if (data.status === 1){
    data.msg && Message.success( data.msg );
    }
    return data;
    }).catch( function ( e ) {
    return {
    msg: '请求失败'
    }
    } )
    }
    +
  • +
  • post

    +
  • +
+
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
const fetchPOST = ( url, params = {}, header = {} ) => {

let body = [];

if ( JSON.stringify( params ) !== '{}' ) {
const len = Object.keys( params ).length;
Object.keys( params ).map( ( v, i ) => {
body.push( `${v}=${params[ v ]}` );
if ( i + 1 < len ) {
body.push( '&' )
}
} )
}

return fetch( url,
{
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: body.join( '' )
} )
.then( ( response ) => {
return response.json();
} )
.then( ( data ) => {
if ( data.status < 0 ) {
Message.error( data.msg || '请求失败' );
} else if (data.status === 1){
data.msg && Message.success( data.msg );
}
return data;
} )
.catch( ( e ) => {
return {
msg: '请求失败'
}
} )
}
+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/09/05/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\205\255-\345\215\225\344\276\213\346\250\241\345\274\217/index.html" "b/2018/09/05/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\205\255-\345\215\225\344\276\213\346\250\241\345\274\217/index.html" index e69de29b..6f727436 100644 --- "a/2018/09/05/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\205\255-\345\215\225\344\276\213\346\250\241\345\274\217/index.html" +++ "b/2018/09/05/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\205\255-\345\215\225\344\276\213\346\250\241\345\274\217/index.html" @@ -0,0 +1,730 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 设计模式学习之六-单例模式 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

设计模式学习之六-单例模式

+ + + +
+ + + + + +
+ + + + + +

单例模式的定义是:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

+
+

核心

+
+

单例模式的核心在于:确保只有一个实例,并提供全局访问。
意思就是关于某个特定功能的实例,有且只有这一个,反复使用这一个实例。

+

举例:

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var Singleton = function( name ){
this.name = name;
this.instance = null;
};

Singleton.prototype.getName = function(){
alert ( this.name );
};
Singleton.getInstance = function( name ){
this.instance = new Singleton( name );
return this.instance;
};
var a = Singleton.getInstance( 'sven1' );
var b = Singleton.getInstance( 'sven2' );

console.log( a===b ) //false
+

显然,a和b是不等的2个实例,当我们使用这种方式应用于页面上的弹窗时,创建弹窗类,页面上的弹窗只有一个,而我们创建
弹窗类的实例也应该只有一个,不应反复创建多个无用的实例,于是在getInstance方法中我们添加:

+
1
2
3
4
5
6
7
8
9
10
Singleton.getInstance = function( name ){

+ if ( !this.instance ){
+ this.instance = new Singleton( name );
+ }

return this.instance;
};

console.log( a === b ) // true
+

这样的好处在于,我们使用的始终是第一个创建的实例,避免了创建多个重复的实例。

+
+

惰性单例

+
+

简而言之,就是在需要这个实例时,才去创建该实例。
比如我们要实现一个点击按钮,弹出弹框的功能,第一种方案是在页面加载完时,就创建该实例,但是我们不一定会触发
点击按钮,所以这个实例并没有被用到,浪费了内存。采用惰性单例的话,是在onclick时,才去创建该实例。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/09/06/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\203-\344\273\243\347\220\206\346\250\241\345\274\217/index.html" "b/2018/09/06/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\203-\344\273\243\347\220\206\346\250\241\345\274\217/index.html" index e69de29b..0a605bf4 100644 --- "a/2018/09/06/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\203-\344\273\243\347\220\206\346\250\241\345\274\217/index.html" +++ "b/2018/09/06/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\270\203-\344\273\243\347\220\206\346\250\241\345\274\217/index.html" @@ -0,0 +1,723 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 设计模式学习之七-代理模式 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

设计模式学习之七-代理模式

+ + + +
+ + + + + +
+ + + + + +

代理模式的意义是: 坚持职责单一原则,每个功能方法只做那一件事。

+
+

应用场景

+
+

在web开发中,我们通常会遇到HTTP请求或者鼠标滚动这样的高触发频率事件,
于是就应用到了函数防抖。

+
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
const synchronousEvent = (id) => {
console.log('开始执行自定义事件: ' + id);
}

const proxySynchronousEvnet = (() => {
const cache = [];
let timer = undefined;

return (id) => {
cache.push(id);

if(timer) return;

timer = setTimeout(() => {
synchronousEvent(cache.join(','));
clearTimeout(timer);
timer = null;
cache.length = 0;
}, 2000);
}
})();

window.onclick = (event) => {
proxySynchronousEvent(event.timeStamp);
}
+

这里通过proxySynchronousEvent来代理事件,以2s为间隔,把2秒内的请求都统一来执行,职责单一的
体现是自定义事件始终是在synchronousEvent方法中,而proxySynchronousEvent才是真正负责
事件触发时机。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/09/12/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\271\235-\350\243\205\351\245\260\350\200\205\346\250\241\345\274\217/index.html" "b/2018/09/12/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\271\235-\350\243\205\351\245\260\350\200\205\346\250\241\345\274\217/index.html" index e69de29b..a2b3b19c 100644 --- "a/2018/09/12/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\271\235-\350\243\205\351\245\260\350\200\205\346\250\241\345\274\217/index.html" +++ "b/2018/09/12/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\344\271\235-\350\243\205\351\245\260\350\200\205\346\250\241\345\274\217/index.html" @@ -0,0 +1,732 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 设计模式学习之九-装饰者模式 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

设计模式学习之九-装饰者模式

+ + + +
+ + + + + +
+ + + + + +

装饰者模式的使用场景: 为对象扩展方法,且不影响原对象。

+
+

场景

+
+

我们声明了一个匿名函数

+
1
2
3
function test() {
console.log('test')
}
+

现在如果我们要扩展该方法,比较保守的做法的是直接修改该方法

+
1
2
3
4
5
function test() {
// 添加新操作
console.log('test');
// 添加新操作
}
+

现在我们用装饰者模式来实现:

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
Function.prototype.before = function ( beforeFn ) {
var __self = this;

return function ( ) {
beforeFn.apply(this, arguments); // before先执行
return __self.apply(this, arguments); // 再执行原本的方法
}
}

Function.prototype.after = function ( afterFn ) {
var __self = this;

return function ( ) {
__self.apply(this, arguments); // 执行原本的方法

return afterFn.apply(this, arguments); // 执行after的扩展方法
}
}

var test = function ( ) {
console.log('test')
}

test = test.before(function ( ) {
console.log('before')
})
test = test.after(function ( ) {
console.log('after')
});

test(); // 输出:'before','test','after'

+

test.before(fn)之后直接赋值覆盖原test方法来实现扩展。

+

比如我们要在ajax方法中扩展before或after,或者要在表单提交时,验证表单,扩展beofre,就可以使用这种方法。

+
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
Function.prototype.before = function ( beforeFn ) {
var __self = this;

return function ( ) {
if(beforeFn.apply(this, arguments) === false){
return;
} // before先执行
return __self.apply(this, arguments); // 再执行原本的方法
}
}

var validata = function() {
if(username.value === ''){
alert('用户名不能为空');
return false;
}
}

var formSubmit = function() {
ajax(url, params);
}

formSubmit = formSubmit.before(validata);

submitBtn.onclick = formSubmit;
+
+

缺点

+
+

装饰者模式其实返回的是新方法来覆盖的原方法。所以原对象中的私有属性也会被丢失。并且多次
return叠加了函数作用域,如果作用域链过长,性能会受到影响。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/09/12/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\205\253-\344\270\255\344\273\213\350\200\205\346\250\241\345\274\217/index.html" "b/2018/09/12/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\205\253-\344\270\255\344\273\213\350\200\205\346\250\241\345\274\217/index.html" index e69de29b..e70dab06 100644 --- "a/2018/09/12/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\205\253-\344\270\255\344\273\213\350\200\205\346\250\241\345\274\217/index.html" +++ "b/2018/09/12/\350\256\276\350\256\241\346\250\241\345\274\217\345\255\246\344\271\240\344\271\213\345\205\253-\344\270\255\344\273\213\350\200\205\346\250\241\345\274\217/index.html" @@ -0,0 +1,737 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 设计模式学习之八-中介者模式 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

设计模式学习之八-中介者模式

+ + + +
+ + + + + +
+ + + + + +

代理模式的使用场景: 多个对象之间有相互依赖关系,为了解决错综复杂的关系,
需要创建个中介者对象来管理他们之间的依赖关系。

+
+

场景

+
+

比如创建个泡泡堂游戏,4v4对战,分别为红方和蓝方,每一方中的每个队员胜利
或失败,都要通知到其他队员,一方人员全部失败,则表示全队阵亡。

+

代码:

+
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

function Player( name, teamColor ) {
this.state = 'alive';
this.name = name;
this.teamColor = teamColor;
}

Player.prototype.win = function() {
console.log('winner: ' + this.name);
}

Player.prototype.lose = function() {
console.log(`loser: ${this.name}`);
}

Player.prototype.die = function() {
this.state = 'dead';

playerDirector.receiveMessage('playerDead', this);
}

Player.prototype.remove = function ( ) {
playerDirector.receiveMessage('removePlayer', this);
}

Player.prototype.changeTeam = function ( color ) {
playerDirector.receiveMessage('changeTeam', this, color);
}
const playerFactory = (name, teamColor) => {
const newPlayer = new Player(name, teamColor);

playerDirector.receiveMessage('addPlayer', newPlayer);

return newPlayer;
}

var playerDirector = (function ( ) {
var players = {},
operations = {};

operations.addPlayer = function ( player ) {
var teamColor = player.teamColor;
players[teamColor] = players[teamColor] || [];

players[teamColor].push(player);
}

operations.removePlayer = function ( player ) {
var teamColor = player.teamColor,
teamPlayers = players[teamColor] || [];

teamPlayers.map( (v,i) => {
if(v === player){
teamPlayers.splice(i, 1);
}
})
}

operations.changeTeam = function ( player, newTeamColor ) {
operations.removePlayer(player);
player.teamColor = newTeamColor;
operations.addPlayer(player);
}

operations.playerDead = function ( player ) {
var teamColor = player.teamColor,
teamPlayers = players[teamColor];

var all_dead = true;

if(teamPlayers.some(v => v.state !== 'dead')){
all_dead = false;
}

if(all_dead){
teamPlayers.map(v => {
v.lose();
})

Object.keys(players).map(v => {
if(v !== teamColor){
var teamPlayers = players[v];
teamPlayers.map( k => {
k.win();
})
}
})

}
}

var receiveMessage = function ( ) {
var message = Array.prototype.shift.call(arguments);
operations[message].apply(this, arguments);
}

return{
receiveMessage: receiveMessage
}
})()

var player1 = playerFactory('皮蛋','red');
var player2 = playerFactory('小乖','red');
var player3 = playerFactory('宝宝','red');
var player4 = playerFactory('小强','red');

var player5 = playerFactory('黑妞','blue');
var player6 = playerFactory('葱头','blue');
var player7 = playerFactory('胖墩','blue');
var player8 = playerFactory('海盗','blue');

player1.changeTeam('blue');
player2.die();
player3.die();
player4.die();
+

在这个案例中,playerDirector是中介对象,负责管理双方队员对象的信息,它内部有2个私有属性,
分别是player玩家对象和operation操作对象。

+
    +
  • player通过key-value的方式表示红队和蓝队,每个队的队员放到数组中,
  • +
+
1
2
3
4
5

player:{
'red': [player1, player2,...],
'blue': [player5, player6, ...]
}
+
    +
  • operation中包含了中介者对象的一些操作方法,并对外暴露一个receiveMessage接口来调用
    内部方法。
  • +
+
1
2
3
4
var receiveMessage = function () {
var message = Array.prototype.shift.call(arguments);
operations[message].apply(this, arguments);
}
+

这样实现起来,对象之间的逻辑关系就比较清晰。所有操作就都由playerDirector来管理。

+
+

总结

+
+

中介者模式的核心概念是让对象与对象之间尽可能的理清关系,一个对象的改变不会影响到其他对象。把他们之间的逻辑关系交给中介者对象
来处理。不过缺点就是中介者对象会越来越庞大臃肿。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/12/13/\345\246\202\344\275\225\347\274\226\345\206\231\344\270\200\344\270\252webpack-loader/index.html" "b/2018/12/13/\345\246\202\344\275\225\347\274\226\345\206\231\344\270\200\344\270\252webpack-loader/index.html" index e69de29b..95ae88c9 100644 --- "a/2018/12/13/\345\246\202\344\275\225\347\274\226\345\206\231\344\270\200\344\270\252webpack-loader/index.html" +++ "b/2018/12/13/\345\246\202\344\275\225\347\274\226\345\206\231\344\270\200\344\270\252webpack-loader/index.html" @@ -0,0 +1,742 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 如何编写一个webpack-loader | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

如何编写一个webpack-loader

+ + + +
+ + + + + +
+ + + + + +

loader在webpack中是一个很重要的角色,babel-loader,vue-loader,json-loader等等,都给我们的开发带来了很好的体验,本篇博文就尝试讲解如何编写一个loader。

+
+

目标

+
+

写一个txt-loader,可以引入txt文本,并在代码中使用。

+
+

开始

+
+

首先mkdir loader, cd loader && npm init来初始化一个前端工程化项目,然后在项目根目录下新建个我们需要用到的test.txt,在里面随便写点内容abcde。然后新建index.js作为入口文件,并在其中引入txt文件:
index.js:

1
2
const txt = require('./test.txt');
console.log(`11, ${txt}`);

+

然后安装webpack,并简单配置一下webpack的入口,出口,loader:

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
var path = require( 'path' );
var CleanWebpackPlugin = require( 'clean-webpack-plugin' );
var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
mode: 'production',
entry: './index.js',

output: {
path: path.resolve( __dirname, './dist' ),
filename: 'bundle.[hash:8].js',
},
module: {
rules: [
{
test: /\.txt$/,
use: {
loader: path.resolve( __dirname, './loaders/txt-loader/index.js' )
}

}
]
},

plugins: [
new CleanWebpackPlugin( './dist' ),

new HtmlWebpackPlugin( {
title: 'Output Management'
} )
],
}

+

对于txt的loader, webpack默认是从node_modules中去查找对应的loader,想要引入本地loader时,有两种方法:

+
    +
  1. 如以上代码,只需要写明本地路径就可以
  2. +
  3. 在config中配置resolveLoader属性,这样webpack就会依次从路径中查找:
    1
    2
    3
    4
    5
    6
    resolveLoader: {
    modules: [
    'node_modules',
    path.resolve(__dirname, 'loaders')
    ]
    }
    +
  4. +
+

当你自己写的loader在本地测试通过后,就可以npm publish发布在npm平台上,供他人使用了。

+

那我们就在本地新建txt-loader文件夹,并在里面新建index.js来编写核心代码:

1
2
3
4
module.exports = function (content) {
var result = content.split('').reverse().join('').toUpperCase();
return `module.exports = '${result}'`;
};

+

这个loader的功能会把字母倒叙并转换成大写,这样我们的loader的功能就编写完了。

+
+

注意:对于一个txt格式使用多个loader时,loader的顺序是倒序的.

1
2
3
4
use: [
'bar-loader',
'foo-loader'
]

+
+

先经过foo-loader,再经过bar-loader。
所以每一个loader方法都会接收上一个loader的产出,因此loader的产出应该为:

1
return `module.exports = '${result}'`;

+

具体的介绍详见webpack官方介绍,这里就不墨迹了。

+

最后,loader的编写就完成了,检测下成果:将打包的index.js引入到html中,打开html,打印出了EDCBA。
完美!

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2018/12/28/ionic\346\267\267\345\220\210APP\345\274\200\345\217\221\345\260\217\347\273\223/index.html" "b/2018/12/28/ionic\346\267\267\345\220\210APP\345\274\200\345\217\221\345\260\217\347\273\223/index.html" index e69de29b..8e6a49ad 100644 --- "a/2018/12/28/ionic\346\267\267\345\220\210APP\345\274\200\345\217\221\345\260\217\347\273\223/index.html" +++ "b/2018/12/28/ionic\346\267\267\345\220\210APP\345\274\200\345\217\221\345\260\217\347\273\223/index.html" @@ -0,0 +1,759 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ionic混合APP开发小结 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

ionic混合APP开发小结

+ + + +
+ + + + + +
+ + + + + +

如果一个前端想要开发APP,并兼容Android和IOS,那么ionic是一个不错的选择。

+
+

前言

+
+

被分到一个项目上做app开发,由于项目没有充足的成本来分配一个安卓+一个ios开发,所以就选择了混合app开发——使用前端h5代码打包发布成2个平台兼容的代码,真正意义上write once, use anywhere。由于我并没有APP开发经验,刚开始听到让我开发APP,我是
懵逼的,就算有react native, 可是RN始终需要原生人员来提供底层设备接口。无奈之下通过多方搜查了解,打听到还有
ionic这个方案。于是就看了看官方文档,下了个demo撸了一下,发现用起来还不错,兼容性也比较好,只需要微调样式,而
框架里用了angular,并封装了webpack,gulp,scss等前端工程化工具,且不需要你去配置,他都帮你搭建好了,你只需要敲击命令即可打包构建,写起来就跟写前端一样的模式,他的底层是用了cordova来提供底层设备接口,并且官方
接口也比较多,社区发展的比较成熟。经过两个月的996,终于到现在完成了2个大的业务模块,并成功安装到安卓上
进行内测。整个项目的技术栈是ionic(UI)+angular+nodejs(中间层)下面就分条介绍一下整个项目中的技术点。

+
+

ionic

+
+

ionic是一个很不错的手机端APP UI库,我第一次接触它是在2015年的时候,那时候它还只是一个纯粹的ui样式库,现在
它已经发展到了v4版本,并自带原生APP接口和angular结合,往混合APP方向发展。他的一些组件也是高度还原
原生APP样式。在用ionic写样式时, 是每个页面组件的根标签,分别对应
APP页面的 头部内容底部,在写html时,要尽量使用ionic提供的组件,因为他的组件已经处理过了安卓和ios的样式兼容。
如果还是使用div的话,放到真机上测试时,发现会有很多兼容性问题。

+

ionic不仅提供了UI样式,还提供了模拟原生APP的组件,比如modal弹窗组件,list列表组件,nav路由组件等,这些组件并内置一些通用方法,比如modal的显示隐藏,路由跳转,
数据传参,list列表的上拉加载,下拉刷新等方法。

+
+

ionic-angular

+
+

js框架是搭配的angular,angular是一个js框架,他和react,vue不同的地方在于,angular内置了http,pipe等方法——它是一个框架,你需要按照他的文档去编写
对应的方法模块,包括按需加载。

+
+

jwt

+
+

全称jsonwebtoken,现代化的用户权限验证机制,他和cookie不同的地方在于,首次设置cookie后,只要在同一个浏览器里访问,cookie会自动传输到服务端,而jwt的机制
是首次登陆时需要在服务端验证用户通过后,在服务端生成token返回给前端,接下来每次接口请求时,需要前端在请求头中加上Authorization=token,服务端接收请求时,需要先验证
该token,如果token正确,表示该用户是有权限的。所以在http方法请求时,手动加上Authorization字段即可。

+
+

nodejs

+
+

由于项目规定不能暴露真实数据服务器地址,所以接口需要在node层去转发接口,合并请求,并在node层设置CORS允许跨域,所以node层就在接收到请求时,先判断是否带token,如果
有token,再允许接下来的业务处理。

+
+

路由

+
+

路由是使用的ionic自带的navControl,直接调用push(组件,options)即可跳转到对应页面,值得一提的是,由于在APP端没有返回键,所以它提供了一些方法可以使你改变
当前路由栈,极大的方便了某些需要改变路由栈的操作。

+
+

数据共享

+
+

angular的数据共享并没有像vuex,redux这样的库,你可以自己建一个js模块文件,里面存放一些全局数据,然后根据自己的需要来共享数据,如果需要规范一些,那就像
vuex一样自己去组织这些方法吧。

+
+

Typescript

+
+

angular自带ts规范,它可以更加规范你自己定义的方法和参数,使你的代码变成强类型,减少代码bug的发生。

+
+

自定义app参数

+
+

在根目录的config.xml中,可以自定义修改关于该APP的名字,icon,启动图等,也可以自己添加app中需要用到的底层插件。

+
+

发布

+
+

在真机测试时,ios遇到一些问题,在更新成最新版Xcode后,成功可以真机测试,这里不再赘述,总之产生问题时,及时google并去ionic的github上去搜索,一般你遇到的
问题,别人都遇到过。

+

(完)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/03/06/docker+node\350\256\260\345\275\225/index.html" "b/2020/03/06/docker+node\350\256\260\345\275\225/index.html" index e69de29b..6ed58c6e 100644 --- "a/2020/03/06/docker+node\350\256\260\345\275\225/index.html" +++ "b/2020/03/06/docker+node\350\256\260\345\275\225/index.html" @@ -0,0 +1,755 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + docker+node记录 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

docker+node记录

+ + + +
+ + + + + +
+ + + + + +

docker+node 快速移植应用,隔离应用

+
+

前言

+
+

docker可以实现快速部署应用,持续构建,隔离多个应用,快速迁移应用。docker+node可以实现多个应用运行在同一台服务器上,并且相互隔离,
互不影响。

+
+

Dockerfile

+
+

首先搭建个简单的node应用, 可以通过localhost:8080输出helloworld即可。然后编写Dockerfile创建镜像

+
1
2
3
4
5
6
7
8
9
10
FROM node:12.16.1-alpine    

RUN mkdir -p /home/node
COPY . /home/node/
WORKDIR /home/node

RUN npm install --production

EXPOSE 8080
CMD ["node", "index.js"]
+

以上代码的意思是:

+
    +
  • 基于node:12.16.1-alpinenode版本作为基础镜像;

    +
  • +
  • 创建个虚拟环境,并创建目录/home/node作为node
    目录

    +
  • +
  • 把当前目录文件拷贝到/home/node

    +
  • +
  • 并以/home/node作为工作目录

    +
  • +
  • 安装npm依赖

    +
  • +
  • 暴露8080端口

    +
  • +
  • 运行node

    +
  • +
+

这样便创建了一个node应用镜像,接下来需要通过docker-compose实例化一个容器。我们可以
通过docker-compose实现多个服务编排在一起,组成一个以node+MongoDB+redis完全体应用。

+

docker-compose.yml:

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
version: '3'
services:
node-docker:
image: node-docker
container_name: node-docker
ports:
- 8081:8080
volumes:
- ~/project/node-docker/logs:/home/node/logs
networks:
- node-docker-network
environment:
WAIT_HOSTS: database:27017, redis:6379

database:
image: mongo:4.2.0
restart: always
ports:
- 27027:27017
command: mongod --bind_ip 0.0.0.0
volumes:
- ~/data/node-docker-db:/data/db
networks:
- node-docker-network

redis:
image: redis:5.0.5
restart: always
networks:
- node-docker-network

networks:
node-docker-network:
name: node-docker-network

+

以上代码我们通过编排任务将node应用和MongoDB和redis连接在同一个网络node-docker-network中,使node可以访问MongoDB和redis,database
就是mongo服务的别名,所以node访问时直接可以通过mongodb://database访问MongoDB。

+

volumes代表着数据卷的映射,当我们重新构建docker服务时,再次实例化镜像,会是一个全新的容器,上一个容器的数据卷会随着容器销毁。
使用volumes可以把对应的目录实时更新到宿主机目录中,再次实例化容器时,又会把宿主机的目录拷贝一份到新的容器目录中。

+

WAIT_HOSTS是一个wait脚本的变量,他代表在启动node应用之前应该等待的服务。即数据库服务应比node应用先启动。
所以应在Dockerfile中加上一句CMD /scripts/wait来执行这个脚本,即在数据库之后才去启动node应用容器

+
+

启动

+
+

那么怎么去运行compose呢——需要个脚本去启动:

+

ssh:

+
1
2
docker build -t node-docker .
docker-compose up -d
+

这样,搭建一个docker+node+mongo的虚拟环境就完成啦!

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2020/05/29/Vue+vue-router+vuex\345\216\237\347\220\206\345\210\206\346\236\220/index.html" "b/2020/05/29/Vue+vue-router+vuex\345\216\237\347\220\206\345\210\206\346\236\220/index.html" index e69de29b..bfcbbc5f 100644 --- "a/2020/05/29/Vue+vue-router+vuex\345\216\237\347\220\206\345\210\206\346\236\220/index.html" +++ "b/2020/05/29/Vue+vue-router+vuex\345\216\237\347\220\206\345\210\206\346\236\220/index.html" @@ -0,0 +1,861 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Vue+vue-router+vuex原理分析 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

Vue+vue-router+vuex原理分析

+ + + +
+ + + + + +
+ + + + + +

Vue源码中有很多零碎知识点值得学习,本篇博文记录学习Vue中常见API的实现原理。

+
+

new Vue初始化流程

+
+
    +
  • 介绍
    Vue初始化是
    1
    2
    3
    4
    5
    6
    new Vue({
    el: '#app',
    data: {
    name: '张三'
    }
    })
    +
  • +
+

传入的参数是一个object,包含了绑定的根节点#app和初始化数据data
查看Vue源码,Vue构造函数执行初始化方法_init(options)_init依次执行了以下方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
vm.$options = mergeOptions() // 扩展vue $options方法,该方法可以merge对象属性,扩展了vue属性
initProxy(vm); //为vue _renderProxy属性设置proxy代理。这层代理会在模板渲染时对一些非法或者没有定义的变量进行筛选判断
vm._self = vm;
initLifecycle(vm); //添加初始化生命周期属性
initEvents(vm); //绑定组件上的事件, 涉及到$on,$once, $off, $emit
initRender(vm); //最主要的方法是defineReactive$$1,通过Object.defineProperty + 观察者模式,实现数据拦截
callHook(vm, 'beforeCreate'); // 调用生命周期钩子 beforeCreate
initInjections(vm); // 解析inject属性
initState(vm); //初始化props,methods, data,computed,watch属性
initProvide(vm); // 解析provide属性
callHook(vm, 'created'); // 调用生命周期钩子 created

...

if (vm.$options.el) {
vm.$mount(vm.$options.el); // 生成template -> 生成render函数 -> 调用beforeMount -> 生成VNode -> vm._update生成真实DOM -> mounted
}

+
+

nextTick

+
+
    +
  • 介绍
    nextTick用于下一次DOM更新执行的方法,当赋值变量之后,DOM节点并没有及时更新,所以此时获取节点内容并不是最新的,因此需要使用nextTick在DOM节点变化之后,获取最新的DOM。

    +
  • +
  • 原理
    nextTick是采用异步控制+优雅降级的方式,以v2.6版本为例,降级策略为根据浏览器兼容性依次判断是否支持Promise -> MutationObserver -> setImmediate -> setTimeout。
    其中,Promise和MutationObserver属于微任务队列,setImmediate和setTimeout属于宏任务队列,微任务比宏任务优先执行。
    nextTick将回调方法收集到callbacks数组中,在异步任务执行时,将callbacks中的函数依次执行。
    例如在使用MutationObserver时,源码中创建了一个node节点,MutationObserver监听此节点内容的变化。当需要执行nextTick的回调函数时,手动触发node节点内容的变化,推动MutationObserver触发监听,执行callbacks中的方法。

    +
  • +
+
+

双向绑定

+
+
    +
  • 介绍
    Vue最基本的功能便是双向绑定,与jQuery相比,极大地方便了DOM操作,可以说是革了jQuery的命。使开发者可以专注于数据操作,数据推动DOM变化。

    +
  • +
  • 原理
    Vue初始化绑定data数据是在initState中的initData

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    function initState (vm) {
    vm._watchers = [];
    var opts = vm.$options;
    if (opts.props) { initProps(vm, opts.props); }
    if (opts.methods) { initMethods(vm, opts.methods); }
    if (opts.data) {
    initData(vm);
    } else {
    observe(vm._data = {}, true /* asRootData */);
    }
    if (opts.computed) { initComputed(vm, opts.computed); }
    if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch);
    }
    }
    +
  • +
+

initData中做了:

+
    +
  1. 判断数据类型是否合规;
  2. +
  3. 判断是否有重名的key,比如props中和data中不能有相同的属性;
  4. +
  5. proxy(vm, "_data", key);代理data中的对象到this下。实现可以app.name可以调用app._data.name
  6. +
  7. observe(data, true /* asRootData */);绑定数据
  8. +
+

再看observe:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function observe (value, asRootData) {
...
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__;
} else if (
shouldObserve &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
ob = new Observer(value);
}
...
}

+

主要是先判断是否有__ob__,如果没有,就把__ob__设为new Observer实例。

+

再看Observer:

1
2
3
4
5
6
7
8
9
10
11
12
var Observer = function Observer (value) {
this.value = value;
this.dep = new Dep();
this.vmCount = 0;
def(value, '__ob__', this); //将Observer绑定到`__ob__`下
if (Array.isArray(value)) {
...
this.observeArray(value);
} else {
this.walk(value);
}
};

+

walkobserveArray是针对对象和数组进行数据绑定,数组的话,就循环针对每一个属性进行绑定。
walk:

1
2
3
4
5
6
Observer.prototype.walk = function walk (obj) {
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++) {
defineReactive$$1(obj, keys[i]);
}
};

+

walk就是针对对象中的每一个属性进行循环绑定。
defineReactive$$1这里就是使用Object.definePropertyset,get进行数据绑定,

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
get: function reactiveGetter () {
//这里主要是判断用户是否自定义了getter,如有,就是用自定义getter
var value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value
},
set: function reactiveSetter (newVal) {

var value = getter ? getter.call(obj) : val;
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (customSetter) {
customSetter();
}
// #7981: for accessor properties without setter
if (getter && !setter) { return }
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
// 新修改的属性,进行数据绑定
childOb = !shallow && observe(newVal);
dep.notify();
}

+

dep用于依赖管理,收集Watcher。它会用subs收集Watcher,当执行setter时,就将subs中的Watcher依次循环,执行每一个Watcher的notify。

+

总的数据管理流程就是:Observer -> dep -> watcher

+
+

Vue异步更新过程

+
+
    +
  • 介绍
    当js中的变量发生变化时,DOM上绑定变量的节点内容并没有立刻发生变化,而是通过nextTick将tick之间发生的内容变化,一次性更新在DOM上的。

    +
  • +
  • 原理
    以如下代码为例:

    +
    1
    2
    3
    <div id="app">
    <p @click="handleClick">{{ test }}</p>
    </div>
    +
  • +
+
1
2
3
4
5
6
7
8
9
10
11
const app = new Vue({
el: '#app',
data:{
test: '111'
},
methods:{
handleClick(){
this.test = this.test * 1 + 1;
}
}
})
+

当点击P标签时,会触发handleClick,首先要获取this.test, Vue是通过proxythis._data下的变量代理到this下的。

1
2
3
4
5
6
7
8
9
function proxy (target, sourceKey, key) {
sharedPropertyDefinition.get = function proxyGetter () {
return this[sourceKey][key]
};
sharedPropertyDefinition.set = function proxySetter (val) {
this[sourceKey][key] = val;
};
Object.defineProperty(target, key, sharedPropertyDefinition);
}

+

proxy的get会调用Object.defineProperty的get。
当给test赋新值时,又通过proxy的set调用Object.defineProperty的set。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
set: function reactiveSetter (newVal) {

var value = getter ? getter.call(obj) : val;
//如果新旧值相同,就不处理
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
//如果有自定义的setter, 就去执行自定义的setter
if (customSetter) {
customSetter();
}
// #7981: for accessor properties without setter
if (getter && !setter) { return }
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
//这里如果新的值是对象的话,就把对象中的每一个key重新绑定响应
childOb = !shallow && observe(newVal);
// 通知dep中的观察者去更新
dep.notify();
}

+
1
2
3
4
5
6
7
8
9
10
11
12
13
Dep.prototype.notify = function notify () {
// stabilize the subscriber list first
var subs = this.subs.slice();
if (!config.async) {
// subs aren't sorted in scheduler if not running async
// we need to sort them now to make sure they fire in correct
// order
subs.sort(function (a, b) { return a.id - b.id; });
}
for (var i = 0, l = subs.length; i < l; i++) {
subs[i].update();
}
};
+

dep中绑定的Watcher,都在subs中。通知每一个Watcher去执行它们的update。

1
2
3
4
5
6
7
8
9
10
Watcher.prototype.update = function update () {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true;
} else if (this.sync) {
this.run();
} else {
queueWatcher(this);
}
};

+

update并不是立即去执行更新,而是通过queueWatcher方法把需要更新的事件放进队列

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
function queueWatcher (watcher) {
var id = watcher.id;
if (has[id] == null) {
has[id] = true;
if (!flushing) {
queue.push(watcher);
} else {
// if already flushing, splice the watcher based on its id
// if already past its id, it will be run next immediately.
var i = queue.length - 1;
while (i > index && queue[i].id > watcher.id) {
i--;
}
queue.splice(i + 1, 0, watcher);
}
// queue the flush
if (!waiting) {
waiting = true;

if (!config.async) {
flushSchedulerQueue();
return
}
nextTick(flushSchedulerQueue);
}
}
}

+

放进队列之后,就通过nextTick去执行队列里的事件。nextTick前面已经介绍过了,nextTick传了一个回调flushSchedulerQueue,Watcher的更新操作是在这个方法中进行

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
function flushSchedulerQueue () {
flushing = true;
var watcher, id;

// Sort queue before flush.
// This ensures that:
// 1. Components are updated from parent to child. (because parent is always
// created before the child)
// 2. A component's user watchers are run before its render watcher (because
// user watchers are created before the render watcher)
// 3. If a component is destroyed during a parent component's watcher run,
// its watchers can be skipped.
/*
给queue排序,这样做可以保证:
1.组件更新的顺序是从父组件到子组件的顺序,因为父组件总是比子组件先创建。
2.一个组件的user watchers比render watcher先运行,因为user watchers往往比render watcher更早创建
3.如果一个组件在父组件watcher运行期间被销毁,它的watcher执行将被跳过。
*/
queue.sort(function (a, b) { return a.id - b.id; });

// do not cache length because more watchers might be pushed
// as we run existing watchers
for (index = 0; index < queue.length; index++) {
watcher = queue[index];
if (watcher.before) {
watcher.before();
}
id = watcher.id;
has[id] = null;
watcher.run(); //执行Watcher
// in dev build, check and stop circular updates.
if (has[id] != null) {
circular[id] = (circular[id] || 0) + 1;
//如果超出最大更新次数,就给个提示。
if (circular[id] > MAX_UPDATE_COUNT) {
warn(
'You may have an infinite update loop ' + (
watcher.user
? ("in watcher with expression \"" + (watcher.expression) + "\"")
: "in a component render function."
),
watcher.vm
);
break
}
}
}

// keep copies of post queues before resetting state
var activatedQueue = activatedChildren.slice();
var updatedQueue = queue.slice();

//重置队列状态
resetSchedulerState();

//调用生命周期钩子
callActivatedHooks(activatedQueue);
callUpdatedHooks(updatedQueue);

// devtool hook
/* istanbul ignore if */
if (devtools && config.devtools) {
devtools.emit('flush');
}
}

+

这样一次tick过程就结束了,总的过程是:setter -> dep.notify -> Watcher.update -> nextTick -> Watcher.run

+
+

patch和diff

+
+
    +
  • 介绍
    Vue在更新DOM时,并不会全部更新DOM,而是把需要更新的节点进行更新,那么他是怎么计算哪些节点需要更新呢,这就要讲到diff算法了。diff算法是一种通过同层的树节点进行比较的高效算法,复杂度只有 O(n)

    +
  • +
  • 分析
    Vue更新操作是在nextTick后执行的flushCallbacks,依次去执行监听者Watcher中的run方法,然后执行vm._update(vm._render(), hydrating), 参数vm._render()就是需要更新的Vnode。_update中有一句vm.$el = vm.__patch__(prevVnode, vnode);,这里就是执行patch方法了。

    +
  • +
+

patch中主要是判断新旧节点的差异:
1.如果vnode不存在,但是oldVnode存在,说明是需要销毁旧节点。
2.如果vnode存在,但是oldVnode不存在,说明是需要创建新节点。
3.当vnode和oldVnode都存在,那就要对节点进行进一步的比较patchVnode

+

patchVnode主要是对节点本身以及节点属性进行比较,对于他们的子节点的比较,就是updateChildren

+
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
function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
var oldStartIdx = 0; //旧节点开始索引
var newStartIdx = 0; //新节点开始索引
var oldEndIdx = oldCh.length - 1; //旧节点结束索引
var oldStartVnode = oldCh[0]; //旧节点开始节点
var oldEndVnode = oldCh[oldEndIdx]; //旧节点结束节点
var newEndIdx = newCh.length - 1; //新节点结束索引
var newStartVnode = newCh[0]; //新节点开始节点
var newEndVnode = newCh[newEndIdx]; //新节点结束节点
var oldKeyToIdx, idxInOld, vnodeToMove, refElm;

// removeOnly is a special flag used only by <transition-group>
// to ensure removed elements stay in correct relative positions
// during leaving transitions
var canMove = !removeOnly;

{
checkDuplicateKeys(newCh);
}

while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
if (isUndef(oldStartVnode)) {
oldStartVnode = oldCh[++oldStartIdx]; // Vnode has been moved left
} else if (isUndef(oldEndVnode)) {
oldEndVnode = oldCh[--oldEndIdx];
} else if (sameVnode(oldStartVnode, newStartVnode)) {
//如果旧开始节点和新开始节点相同,就递归比较他们两个节点,同时索引往中间递增,递增之后,旧开始节点和新开始节点也发生了变化,变成了原节点的相邻节点
patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
oldStartVnode = oldCh[++oldStartIdx];
newStartVnode = newCh[++newStartIdx];
} else if (sameVnode(oldEndVnode, newEndVnode)) {
//如果旧结束节点和新结束节点相同,就递归比较他们两个节点,同时索引往中间递减
patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
oldEndVnode = oldCh[--oldEndIdx];
newEndVnode = newCh[--newEndIdx];
} else if (sameVnode(oldStartVnode, newEndVnode)) {
//如果旧开始节点和新结束节点相同,就递归比较他们两个节点。同时,因为旧开始节点和新结束节点相同,所以把旧开始节点放到旧结束节点的后面。并且变化索引和赋值开始结束节点,继续循环。
patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx);
canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm));
oldStartVnode = oldCh[++oldStartIdx];
newEndVnode = newCh[--newEndIdx];
} else if (sameVnode(oldEndVnode, newStartVnode)) {
//如果旧结束节点和新开始节点相同,就比较他们两个节点。同时,把旧结束节点放到旧开始节点前面。并且变化索引,修改开始结束节点
patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm);
oldEndVnode = oldCh[--oldEndIdx];
newStartVnode = newCh[++newStartIdx];
} else {
//如果都不满足以上四种情形,那说明没有相同的节点可以复用
if (isUndef(oldKeyToIdx)) { oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx); }

idxInOld = isDef(newStartVnode.key)
? oldKeyToIdx[newStartVnode.key]
: findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx);
// 把旧节点用map映射的方法,查找是否有新节点与旧节点相同,如果没有找到相同的,就新建。
if (isUndef(idxInOld)) { // New element
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
} else {
//如果新老节点相同,就比较他们两个节点,并把新节点放到旧开始节点前边
vnodeToMove = oldCh[idxInOld];
if (sameVnode(vnodeToMove, newStartVnode)) {
patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx);
oldCh[idxInOld] = undefined;
canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm);
} else {
//如果不是相同节点,就新建
createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx);
}
}
newStartVnode = newCh[++newStartIdx];
}
}
//如果旧节点列表先循环结束,那么说明新节点列表数量是多于旧节点列表,新开始索引和新结束索引之间的节点就判定为是新增节点,则创建。
if (oldStartIdx > oldEndIdx) {
refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm;
addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue);
} else if (newStartIdx > newEndIdx) {
//如果新节点列表先循环结束,那么说明旧节点列表数量是多于新节点列表,旧开始索引和旧结束索引之间的节点就判定为是多余节点,则删除。
removeVnodes(parentElm, oldCh, oldStartIdx, oldEndIdx);
}
}
+

以上是diff算法在vue中的应用,整个过程是先进行了:
1.旧开始 《-》新开始
2.旧结束 《-》 新结束
3.旧开始 《-》 新结束
4.旧结束 《-》 新开始
这四个方案的比较。如果这四种都不符合,那就再以旧节点为key进行map映射查找是否有新节点相同的节点,如果有,则把新节点放到旧开始节点前边,如果没有找到,则新建节点。
在整个比较过程中,新旧节点顺序始终是不变的,操作的是真实DOM。
这里推荐一篇文章,非常的通俗易懂–>链接

+
+

computed原码分析

+
+
    +
  • 原理分析
    初始化computed属性是在initState中
    1
    2
    3
    4
    5
    function initState (vm) {
    ...
    if (opts.computed) { initComputed(vm, opts.computed); }
    ...
    }
    +
  • +
+

判断如果有computed属性,就执行initComputed初始化computed

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
function initComputed (vm, computed) {
// 创建一个空对象,用来保存watchers对象, 在之后获取computed中的key时,会执行getter,getter就会从vm._computedWatchers中找到对应的key的watcher实例
var watchers = vm._computedWatchers = Object.create(null);
// 判断是否是服务端渲染
var isSSR = isServerRendering();

// 业务代码中声明的computed中的key,对应的方法作为getter
for (var key in computed) {
var userDef = computed[key];
var getter = typeof userDef === 'function' ? userDef : userDef.get;
if (getter == null) {
warn(
("Getter is missing for computed property \"" + key + "\"."),
vm
);
}

if (!isSSR) {
// 创建一个临时watcher实例
watchers[key] = new Watcher(
vm,
getter || noop,
noop,
computedWatcherOptions
);
}

// computed中的key与data,prop不能重复,主要是做判断,如果合法,那就执行defineComputed
if (!(key in vm)) {
defineComputed(vm, key, userDef);
} else {
if (key in vm.$data) {
warn(("The computed property \"" + key + "\" is already defined in data."), vm);
} else if (vm.$options.props && key in vm.$options.props) {
warn(("The computed property \"" + key + "\" is already defined as a prop."), vm);
}
}
}
}

+

接下来就是执行defineComputed

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
function defineComputed (
target,
key,
userDef
) {
var shouldCache = !isServerRendering();
if (typeof userDef === 'function') {
// 使用Object.defineProperty定义computed中的key,getter就是createComputedGetter(key)
sharedPropertyDefinition.get = shouldCache
? createComputedGetter(key)
: createGetterInvoker(userDef);
sharedPropertyDefinition.set = noop;
} else {
sharedPropertyDefinition.get = userDef.get
? shouldCache && userDef.cache !== false
? createComputedGetter(key)
: createGetterInvoker(userDef.get)
: noop;
sharedPropertyDefinition.set = userDef.set || noop;
}
if (sharedPropertyDefinition.set === noop) {
sharedPropertyDefinition.set = function () {
warn(
("Computed property \"" + key + "\" was assigned to but it has no setter."),
this
);
};
}
Object.defineProperty(target, key, sharedPropertyDefinition);
}

+

我们看到该方法是使用Object.defineProperty定义computed中的key,getter就是createComputedGetter(key),看看他是怎么定义的getter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function createComputedGetter (key) {
return function computedGetter () {
var watcher = this._computedWatchers && this._computedWatchers[key];
if (watcher) {
if (watcher.dirty) {
watcher.evaluate();
}
if (Dep.target) {
watcher.depend();
}
return watcher.value
}
}
}

+

getter的定义是从vm._computedWatchers中找到computed的key的watcher实例,创建watcher实例时,dirty是默认为true。第一次获取key,dirty是为true的话,就通过watcher.evaluate去计算key的属性。

1
2
3
4
Watcher.prototype.evaluate = function evaluate () {
this.value = this.get();
this.dirty = false;
};

+

这里我们看到就是执行我们自定义的computed的key的方法,得到值赋值给了watcher实例,进行缓存,之后将dirty变为false,这样再次获取computed的key,就直接取值,避免再次计算。
那么再看get()

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
Watcher.prototype.get = function get () {
// 将watcher实例赋值给了Dep.target,这里准备做依赖收集了
pushTarget(this);
var value;
var vm = this.vm;
try {
// 这里就会去执行我们自定的computed的key的方法,如果方法中用到了data中的响应式属性,就会触发该属性的getter
value = this.getter.call(vm, vm);
} catch (e) {
if (this.user) {
handleError(e, vm, ("getter for watcher \"" + (this.expression) + "\""));
} else {
throw e
}
} finally {
// "touch" every property so they are all tracked as
// dependencies for deep watching
if (this.deep) {
traverse(value);
}
popTarget();
this.cleanupDeps();
}
return value
};

+

这里我们看到去执行我们自定的computed的key的方法,如果方法中用到了data中的响应式属性,就会触发data的属性的getter

1
2
3
4
5
6
7
8
9
10
11
12
13
14
get: function reactiveGetter () {
var value = getter ? getter.call(obj) : val;
// 此时的Dep.target就是computed的key的watcher实例,就会进行依赖收集
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value
},

+

这样一来,当computed的key所依赖的data的key发生变化时,就会触发data的key的dep.notify()

1
2
3
4
5
6
7
8
9
10
11
12
13
Dep.prototype.notify = function notify () {
// stabilize the subscriber list first
var subs = this.subs.slice();
if (!config.async) {
// subs aren't sorted in scheduler if not running async
// we need to sort them now to make sure they fire in correct
// order
subs.sort(function (a, b) { return a.id - b.id; });
}
for (var i = 0, l = subs.length; i < l; i++) {
subs[i].update();
}
};

+

但是在update()中,并不会立即重新计算computed的key的值,而是把它的dirty变为true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Subscriber interface.
* Will be called when a dependency changes.
*/
Watcher.prototype.update = function update () {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true;
} else if (this.sync) {
this.run();
} else {
queueWatcher(this);
}
};

+

这是因为,当data的属性发生变化,就会重新渲染视图,触发_render重新渲染,而视图上依赖了computed的key,就会去获取这个key,触发key的getter,在getter中就会由于dirty为true,而再次evaluate()。
这便是整个computed的处理过程。

+
+

watch源码分析

+
+
    +
  • 原理分析
    初始化watch的入口是在initState中
    1
    2
    3
    4
    5
    6
    function initState (vm) {
    ...
    if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch);
    }
    }
    +
  • +
+

看一下initWatch

1
2
3
4
5
6
7
8
9
10
11
12
function initWatch (vm, watch) {
for (var key in watch) {
var handler = watch[key];
if (Array.isArray(handler)) {
for (var i = 0; i < handler.length; i++) {
createWatcher(vm, key, handler[i]);
}
} else {
createWatcher(vm, key, handler);
}
}
}

+

根据观察的key的操作是否是数组还是单个函数,进行createWatcher操作

1
2
3
4
5
6
7
8
9
10
function createWatcher (
vm,
expOrFn,
handler,
options
) {
...
// 这里的传参就是观察的key,自定义观察的key的函数
return vm.$watch(expOrFn, handler, options)
}

+

返回的vm.$watch就是要去创建一个watcher实例

+
1
2
3
4
5
6
7
8
9
10
Vue.prototype.$watch = function (
expOrFn,
cb,
options
) {
...
var watcher = new Watcher(vm, expOrFn, cb, options);
...
};
}
+
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
var Watcher = function Watcher (
vm,
expOrFn,
cb,
options,
isRenderWatcher
) {
...
// parse expression for getter
if (typeof expOrFn === 'function') {
this.getter = expOrFn;
} else {
this.getter = parsePath(expOrFn);
if (!this.getter) {
this.getter = noop;
warn(
"Failed watching path: \"" + expOrFn + "\" " +
'Watcher only accepts simple dot-delimited paths. ' +
'For full control, use a function instead.',
vm
);
}
}
this.value = this.lazy
? undefined
: this.get();
};
+

在这里会去通过执行this.get()去获取watcher实例的value,这便是准备开始收集依赖了,和computed类似。

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
Watcher.prototype.get = function get () {
//这里会把Dep.target设为watcher实例
pushTarget(this);
var value;
var vm = this.vm;
try {
//然后会去执行观察的data的key的getter
value = this.getter.call(vm, vm);
} catch (e) {
if (this.user) {
handleError(e, vm, ("getter for watcher \"" + (this.expression) + "\""));
} else {
throw e
}
} finally {
// "touch" every property so they are all tracked as
// dependencies for deep watching
if (this.deep) {
traverse(value);
}
popTarget();
this.cleanupDeps();
}
return value
};

+

在这里我们只需要关心先把全局的Dep.target设为watcher实例,然后就去执行Object.defineProperty的getter,在getter中会判断如果有Dep.target,就会进行依赖收集.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
var value = getter ? getter.call(obj) : val;
// 此时的target是上面提到的创建的watcher实例
if (Dep.target) {
//进行依赖收集
dep.depend();
if (childOb) {
childOb.dep.depend();
if (Array.isArray(value)) {
dependArray(value);
}
}
}
return value
},
...
}

+

这样watch的key就完成了依赖的收集,当data的响应式属性变化时,就会dep.notify()通知subs中的watcher实例进行更新。

1
2
3
4
5
6
7
8
9
10
Watcher.prototype.update = function update () {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true;
} else if (this.sync) {
this.run();
} else {
queueWatcher(this);
}
};

+

更新并不是立即更新,而是通过queueWatcher放到队列中,再通过nextTick执行。
以上,便是watch的源码分析。

+
+

vue-router源码分析

+
+
    +
  • 介绍
    vue-router是官方的前端路由库,作为一个单页应用,路由功能可以使单页应用看起来更像个多页应用,可以更好地控制页面跳转。Vue提供的路由方式有hash,history,abstract。本文以v2.8为准来介绍。

    +
  • +
  • 原理分析
    Vue引入插件是通过Vue.use(plugin),use源码是这样定义的:

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    export function initUse (Vue: GlobalAPI) {
    Vue.use = function (plugin: Function | Object) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    if (installedPlugins.indexOf(plugin) > -1) {
    return this
    }

    // additional parameters
    const args = toArray(arguments, 1)
    args.unshift(this)
    if (typeof plugin.install === 'function') {
    plugin.install.apply(plugin, args)
    } else if (typeof plugin === 'function') {
    plugin.apply(null, args)
    }
    installedPlugins.push(plugin)
    return this
    }
    }
    +
  • +
+

主要是判断避免重复引入插件。初始化插件是把插件的install或插件导出的定义在此上下文中执行。

+

install的代码如下:

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
export function install (Vue) {
if (install.installed && _Vue === Vue) return
install.installed = true

_Vue = Vue

const isDef = v => v !== undefined

const registerInstance = (vm, callVal) => {
let i = vm.$options._parentVnode
if (isDef(i) && isDef(i = i.data) && isDef(i = i.registerRouteInstance)) {
i(vm, callVal)
}
}

Vue.mixin({
beforeCreate () {
if (isDef(this.$options.router)) {
this._routerRoot = this
this._router = this.$options.router
this._router.init(this)
Vue.util.defineReactive(this, '_route', this._router.history.current)
} else {
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
}
registerInstance(this, this)
},
destroyed () {
registerInstance(this)
}
})

Object.defineProperty(Vue.prototype, '$router', {
get () { return this._routerRoot._router }
})

Object.defineProperty(Vue.prototype, '$route', {
get () { return this._routerRoot._route }
})

Vue.component('router-view', View)
Vue.component('router-link', Link)

const strats = Vue.config.optionMergeStrategies
// use the same hook merging strategy for route hooks
strats.beforeRouteEnter = strats.beforeRouteLeave = strats.beforeRouteUpdate = strats.created
}

+

该方法使每个组件混入beforeCreatedestroyed方法,并响应式声明_route属性,定义router-view,router-link组件,并定义组件生命周期钩子。

+

install是定义在VueRouter上的一个方法,回看VueRouter类是怎么声明的:

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
...
this.matcher = createMatcher(options.routes || [], this)
//默认是hash模式,如果浏览器不支持history,就选择hash模式
let mode = options.mode || 'hash'
this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false
if (this.fallback) {
mode = 'hash'
}
//如果不是在浏览器,就选择abstract模式
if (!inBrowser) {
mode = 'abstract'
}
this.mode = mode

switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
case 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
if (process.env.NODE_ENV !== 'production') {
assert(false, `invalid mode: ${mode}`)
}
}
...

+

通过createMatcher生成路由映射信息,然后对路由模式优雅降级,然后根据模式,选择具体的路由实体类。

+

router跳转是通过push方法,那么来看看push是怎么定义的:

1
2
3
4
5
6
7
8
9
push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const { current: fromRoute } = this
//先执行transitionTo,并传了个回调成功函数
this.transitionTo(location, route => {
pushState(cleanPath(this.base + route.fullPath))
handleScroll(this.router, route, fromRoute, false)
onComplete && onComplete(route)
}, onAbort)
}

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
transitionTo (location: RawLocation, onComplete?: Function, onAbort?: Function) {
const route = this.router.match(location, this.current)
//先确认是否跳转
this.confirmTransition(route, () => {
this.updateRoute(route)
onComplete && onComplete(route)
this.ensureURL()

// fire ready cbs once
if (!this.ready) {
this.ready = true
this.readyCbs.forEach(cb => { cb(route) })
}
}, err => {
if (onAbort) {
onAbort(err)
}
if (err && !this.ready) {
this.ready = true
this.readyErrorCbs.forEach(cb => { cb(err) })
}
})
}
+

confirmTransition主要是判断是否是同一路由之间的跳转,如果不是的话,就把跳转之后需要调的任务放到任务队列中,这些任务主要是些生命周期钩子。
确认跳转之后就通过updateRoute更新路由,然后再执行push中的回调pushState
具体看下updateRoute:

1
2
3
4
5
6
7
8
updateRoute (route: Route) {
const prev = this.current
this.current = route
this.cb && this.cb(route)
this.router.afterHooks.forEach(hook => {
hook && hook(route, prev)
})
}

+

这里执行cb,那么cb是在哪定义的呢?其实是在init中:

1
2
3
4
5
history.listen(route => {
this.apps.forEach((app) => {
app._route = route
})
})

+

又因为在前面定义了响应式属性_route

1
Vue.util.defineReactive(this, '_route', this._router.history.current),

+

所以就会触发组件的setter, setter中调用dep中收集的依赖,触发render,再通过nextTick重新渲染。
router-view中组件定义了render方法,在该方法中其实是执行$createElement去渲染组件

+
+

Vuex原理分析

+
+
    +
  • 介绍
    Vuex是一个可以全局组件共享数据的插件,通过actions -> mutations -> state的流程,可以更加规范化数据操作。

    +
  • +
  • 原理分析
    Vue通过install方法加载Vuex实例,主要是通过mixinbeforeCreate时来给Vue扩展方法:

    +
    1
    Vue.mixin({ beforeCreate: vuexInit })
    +
  • +
+
1
2
3
4
5
6
7
8
9
10
11
function vuexInit () {
const options = this.$options
// store injection
if (options.store) {
this.$store = typeof options.store === 'function'
? options.store()
: options.store
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store
}
}
+

vuexInit主要是把store实例挂载到this.$store上,子组件从其父组件引用$store属性,层层嵌套进行设置,以此来达到给全局组件注入store的目的。
那么再来看Store是怎么定义的:

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
export class Store {
constructor (options = {}) {
//省略部分代码
...

//当正在执行mutations时,就改变_committing状态,改变结束,再更改回来,用于区分是否是通过mutations来改变state,而不是直接修改state
this._committing = false

//把定义的action方法放进对象做一个映射集
this._actions = Object.create(null)

//把定义的mutation方法放进对象做一个映射集
this._mutations = Object.create(null)


// 定义dispatch和commit
const store = this
const { dispatch, commit } = this
this.dispatch = function boundDispatch (type, payload) {
return dispatch.call(store, type, payload)
}
this.commit = function boundCommit (type, payload, options) {
return commit.call(store, type, payload, options)
}

//初始化data getters
resetStoreVM(this, state)

// 安装插件
plugins.forEach(plugin => plugin(this))
}
}

+

实例化Store中,把定义的mutation和action都各自放进了一个映射集合,然后在执行时,通过方法名称去执行对应方法,然后再看是如何定义了dispatch和commit的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
dispatch (_type, _payload) {
// check object-style dispatch
const {
type,
payload
} = unifyObjectStyle(_type, _payload)

const action = { type, payload }

//通过type找到需要执行的方法
const entry = this._actions[type]
if (!entry) {
if (process.env.NODE_ENV !== 'production') {
console.error(`[vuex] unknown action type: ${type}`)
}
return
}

this._actionSubscribers.forEach(sub => sub(action, this.state))

return entry.length > 1
? Promise.all(entry.map(handler => handler(payload)))
: entry[0](payload)
}

+

commitdispatch类似,只不过多了一句

1
2
3
4
5
 this._withCommit(() => {
entry.forEach(function commitIterator (handler) {
handler(payload)
})
})

+

这个_withCommit就是用来在mutation改变state时,改变一下状态:

1
2
3
4
5
6
_withCommit (fn) {
const committing = this._committing
this._committing = true
fn()
this._committing = committing
}

+

再看state和getter是怎么定义的,这两个的定义是在初始化Store时,有个

1
resetStoreVM(this, state)

+
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
function resetStoreVM (store, state, hot) {
//省略部分代码
...

...
const computed = {}
forEachValue(wrappedGetters, (fn, key) => {
// use computed to leverage its lazy-caching mechanism
computed[key] = () => fn(store)
Object.defineProperty(store.getters, key, {
get: () => store._vm[key],
enumerable: true // for local getters
})
})
...

store._vm = new Vue({
data: {
$$state: state
},
computed
})

...
}
+

可以看到,通过创建一个响应式的data和computed来实现state和getters。
我们在在组件中使用Vuex时,经常会通过import { mapGetters, mapActions } from 'vuex'来直接使用action或mutation的方法,那么他们是怎么实现的呢:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export const mapActions = normalizeNamespace((namespace, actions) => {
const res = {}
normalizeMap(actions).forEach(({ key, val }) => {
res[key] = function mappedAction (...args) {
let dispatch = this.$store.dispatch
//如果有命名空间
if (namespace) {
const module = getModuleByNamespace(this.$store, 'mapActions', namespace)
if (!module) {
return
}
dispatch = module.context.dispatch
}
return typeof val === 'function'
? val.apply(this, [dispatch].concat(args))
: dispatch.apply(this.$store, [val].concat(args))
}
})
return res
})

+

其实就是从_actions方法集合中,找到该方法,dispatch绑定$store上下文,并返回新的方法集合。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2021/06/16/Web\345\256\211\345\205\250\345\244\264/index.html" "b/2021/06/16/Web\345\256\211\345\205\250\345\244\264/index.html" index e69de29b..c9a1d691 100644 --- "a/2021/06/16/Web\345\256\211\345\205\250\345\244\264/index.html" +++ "b/2021/06/16/Web\345\256\211\345\205\250\345\244\264/index.html" @@ -0,0 +1,767 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Web安全头 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

Web安全头

+ + + +
+ + + + + +
+ + + + + +

本文列出了可用于保护网站的最重要的安全标头。使用它来了解基于 Web 的安全功能,了解如何在您的网站上实施它们,并作为您何时需要提醒的参考。

+
+

目前应用在项目中的安全头有如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//  内容安全策略
Content-Security-Policy

// 同源才能通过iframe引入
res.header('X-Frame-Options', 'SAMEORIGIN');

// 只能被同源的网站引入资源
res.header('Cross-Origin-Resource-Policy', 'same-origin');

// 只能被同源网站通过open()打开
res.header( 'Cross-Origin-Opener-Policy', 'same-origin');

// 规定时间内,都应该通过HTTPS访问,并且包括子域
res.header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');

+
+

以上安全头可以兼容大部分浏览器,接下来针对每一个安全头进行细致讲解

+
+

Content-Security-Policy

+
+

该header是配置在meta标签中,表示document加载内容的安全策略,可以有效的防止XSS攻击。比如他可以限制禁止加载某些外部资源,
限制禁止执行script脚本。
可以限制的资源类型如下:

+
    +
  • script-src:外部脚本
  • +
  • style-src:样式表
  • +
  • img-src:图像
  • +
  • media-src:媒体文件(音频和视频)
  • +
  • font-src:字体文件
  • +
  • object-src:插件(比如 Flash)
  • +
  • child-src:框架
  • +
  • frame-ancestors:嵌入的外部资源(比如<iframe>)
  • +
  • connect-src:HTTP 连接(通过 XHR、WebSockets、EventSource等)
  • +
  • worker-src:worker脚本
  • +
  • manifest-src:manifest 文件
  • +
+

每个资源类型的配置项如下:

+
    +
  • 主机名:example.org,https://example.com:443
  • +
  • 路径名:example.org/resources/js/
  • +
  • 通配符:.example.org,://.example.com:(表示任意协议、任意子域名、任意端口)
  • +
  • 协议名:https:、data:
  • +
  • 关键字’self’:当前域名,需要加引号
  • +
  • 关键字’none’:禁止加载任何外部资源,需要加引号
  • +
+

比如我的应用中配置如下:

1
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; font-src * data:; object-src 'none'; img-src * data: blob:; style-src 'self' 'unsafe-inline'">

+
+

X-Frame-Options

+
+

在HTML中,我们可以通过<iframe/>标签引入第三方网址,使用iframe攻击的方式就可以是点击劫持
使用X-Frame-Options可以设置自己的应用是否允许被外部引入。主要有以下配置:

1
2
X-Frame-Options: DENY   //  拒绝引入
X-Frame-Options: SAMEORIGIN // 只限于同源引入

+
+

Cross-Origin-Resource-Policy

+
+

该安全头是指静态资源是否允许被外部网站引入
配置如下:

1
2
3
Cross-Origin-Resource-Policy: same-origin   //  允许被符合同源策略(协议、域名、端口)的站点引入
Cross-Origin-Resource-Policy: same-site // 允许被相同站点引入(只要二级域名相同就行)
Cross-Origin-Resource-Policy: cross-origin // 允许被跨域引入

+

关于same-sitesame-origin的区别,可以见这片文章链接

+
+

Cross-Origin-Opener-Policy

+
+

该安全头是指是否允许通过window.open()打开的窗口与自身窗口进行通信。
众所周知,window.open()可以打开一个新的窗口加载外部链接,攻击者可以使用postMessage在
两个站点之间进行通信。
配置如下:

1
2
3
Cross-Origin-Opener-Policy: same-origin     //  将文档与跨源文档窗口隔离。
Cross-Origin-Opener-Policy: same-origin-allow-popups // 为弹出窗口打开时仍然可以保护文档不被引用,但允许它与自己的弹出窗口进行通信
Cross-Origin-Opener-Policy: unsafe-none // 默认值,该文档可以通过跨域窗口打开并保留相互访问

+
+

Strict-Transport-Security

+
+

简单来说,当我们访问一个配置了https的http链接,服务端会重定向到https链接。
改header通知浏览器它不应该使用 HTTP 加载站点,而是使用 HTTPS。设置后,浏览器将使用 HTTPS 而不是 HTTP 来访问域,而无需在标头中定义的持续时间内进行重定向。

+

只需要配置时间即可:

1
Strict-Transport-Security: max-age=31536000

+

服务器http到https的重定向的状态码为301
在设置的这个时间内,浏览器都会自动将http转为https,而不用服务器去重定向,返回的状态码为307。

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2022/03/17/webpack\344\276\235\350\265\226\346\240\221\346\217\222\344\273\266\345\274\200\345\217\221\346\200\273\347\273\223/index.html" "b/2022/03/17/webpack\344\276\235\350\265\226\346\240\221\346\217\222\344\273\266\345\274\200\345\217\221\346\200\273\347\273\223/index.html" index e69de29b..8ba7455b 100644 --- "a/2022/03/17/webpack\344\276\235\350\265\226\346\240\221\346\217\222\344\273\266\345\274\200\345\217\221\346\200\273\347\273\223/index.html" +++ "b/2022/03/17/webpack\344\276\235\350\265\226\346\240\221\346\217\222\344\273\266\345\274\200\345\217\221\346\200\273\347\273\223/index.html" @@ -0,0 +1,743 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + webpack依赖树插件开发总结 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

webpack依赖树插件开发总结

+ + + +
+ + + + + +
+ + + + + +

记录webpack依赖分析插件开发的过程

+

事情的起因是某日突然接到需求,是要对一个从外部引入的项目进行改造,需要快速熟悉项目,但是当打开这个项目代码时,发现外部插件非常多,全局公共组件多达600+,编译一次要2分钟,这种项目看代码就比较恼火,于是心想是否能有一个插件可以概览整个项目中每个文件中引入的依赖,网上搜索一番,并无此类插件,于是心想不如自己造一个。

+

查阅webpack插件文档及相关文章,plugin hooks中的import hook,可以在执行import语句时,触发事件。而项目中刚好是通过import引入依赖,于是试试写点代码,看看会发生什么

1
2
3
4
5
6
7
8
9
10
11
12
13
apply(compiler) { 
compiler.hooks.compilation.tap(this.pluginName, (compilation, { normalModuleFactory }) => {
const handler = (parser, options) => {
parser.hooks.import.tap(this.pluginName, (statement, source) => {
debugger;
//看看参数能拿到什么有用信息
});
}
normalModuleFactory.hooks.parser
.for("javascript/auto")
.tap(this.pluginName, handler);
});
}

+

那webpack插件开发过程中怎么debug呢?总不能老是console吧。
查阅一番,使用node --inspect-brk index.js即可以在浏览器中进行debug, index.js是项目的入口文件,我初始化一个react项目,通常我们npm run dev启动项目是封装了node命令,那这里我们就要改变启动命令为:cross-env NODE_ENV='development' node --inspect-brk client/scripts/start.js
然后在Google浏览器的中输入chrome://inspect/,
enter image description here
点击这个inspect按钮就可以调试啦。
那我们拿到的hook参数是:
enter image description here
enter image description here
可以看到source就是import需要引入的文件名,statement是这个语句的AST。
但是怎么知道webpack当前是在处理哪个文件呢?
答案是在parser,parser表示处理当前文件的解析器,webpack对不同文件就会使用不同的parser,可以看到webpack处理js文件是通过javascript/auto的type来处理。
enter image description here
parser.state.current就是webpack当前正在处理的文件。

+

假如我们的代码是这样写的:

+

index.js

1
2
3
4
5
6
7
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';
import ReactDOM from 'react-dom';
import React from 'react';
import { Provider } from 'react-redux';
import store from '@src/store/index';
import App from './app';

+

那我们的import hook就会触发7次,这样我们就拿到了这个文件的依赖:

1
2
3
4
5
6
7
8
9
10
11
12
{
resource: ${绝对路径}/index.js
deps: [
'react-app-polyfill/ie11',
'react-app-polyfill/stable',
'react-dom',
'react',
'react-redux',
'@src/store/index',
'./app'
]
}

+

在第一个文件处理完后,接着就会在依赖中的继续触发import hook,但是我们的需求并不需要知道第三方依赖的import, 所以就过滤掉node_modules下的文件

1
2
3
if (parser.state.current.resource.includes('node_modules') || source.includes('node_modules')) {
return;
}

+

接下来会处理的将是@src/store/index./app的依赖,以此类推,直到处理完所有的文件,我们拿到了所有的文件及其依赖。
enter image description here

+

那么怎么知道处理完成所有文件呢?
我们选用finishModules hook

1
2
3
4
5
compiler.hooks.make.tap(this.pluginName, (compilation) => {
compilation.hooks.finishModules.tap(this.pluginName, (modules) => {
// 所有modules处理完成
});
});

+

接下来就是要把一维数组转成树结构,由于我们监听的是import hook, 所以第一个触发这个hook的文件一定是入口文件,即数组的第一项,那就从第一个文件的依赖中来递归组织树结构

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
function getDependencies(file, array) {
const item = array.find(v => v.rawRequest === file);
return item?.dependencies || [];
}
function walk(dependencies, array) {
dependencies.forEach(v => {
v.name = v.source;
// 只处理我们自己写的代码
if (v.source.slice(0, 1) === '@' || v.source.slice(0, 1) === '.') {
v.children = getDependencies(v.source, array);
walk(v.children, array);
}
});
}

const transformArrayToTree = (array) => {
if (!array || array?.length === 0) return null;
const tree = {};
// 默认第一个触发import钩子的文件是入口,作为树的根节点
tree.name = array[0].rawRequest;
tree.children = array[0].dependencies;
walk(tree.children, array);

return tree;
};

+

这样便能拿到树结构了
enter image description here

+

然后就是要把数据转成可视化页面,这里我们需要启动一个node web服务,渲染一个模板页面,把数据填充进去,并自动打开浏览器页面

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

function renderViewer(jsonString) {
return new Promise((resolve) => {
fs.readFile(path.resolve(__dirname, './dependencies.html'), 'utf-8', (err, data) => {
if (err) throw err;
const html = data.replace(/<%=(\w+)%>/g, (match, $1) => jsonString);
resolve(html);
});
});
}

function openBrowser(url, info) {
try {
opener(url);
console.log(info);
} catch (err) {
console.error(`Opener failed to open "${url}":\n${err}`);
}
}

async function startServer(jsonString) {
const port = 8888;
const host = '127.0.0.1';
const isOpenBrowser = true;
const html = await renderViewer(jsonString);
http.createServer((req, res) => {
if (req.method === 'GET' &amp;&amp; req.url === '/') {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end(html);
} else {
res.end('blank page');
}
}).listen(port, host, () => {
const url = `http://${host}:${port}`;

const logInfo = (
`Webpack Source Code Dependencies Analyzer is started at ${(url)}\n`
+ `Use ${('Ctrl+C')} to close it`
);

if (isOpenBrowser) {
openBrowser(url, logInfo);
}
});
}

+

打开的页面是这样子:
enter image description here

+

通过点击节点来查看每个页面的依赖。

+

但是,当检查这些依赖时,发现通过import()动态加载的组件并没有被收集进来,查看webpack hook文档说是import hook会触发所有import,这里就很疑惑。几经搜索与思考,webpack只是打包工具,真正处理这些文件的,还是对应的loader, 那处理import的解析器是babel, babel中识别import是ImportDeclaration,而import()是ImportExpression, 也就是说import()并不会触发import hook, 于是又去查看webpack Parser的源码,发现有个importCall, importCall却并没有出现在webpack文档中,于是试探性的添加一个importCall hook, 果不其然,在解析import()语句时,触发了importCall hook。

+

至此,一个依赖分析插件的雏形就已经出来了,后续就是一些细节上的优化,比如同个文件被两个文件以不同命名的方式引入,这种情况还需要处理下。

+

(完)

+

github源码: [链接地址] (https://github.com/yangguansen/webpack-code-dependency-analysis-plugin)

+ + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/2022/05/24/\344\275\277\347\224\250shadow DOM\350\207\252\345\256\232\344\271\211\347\273\204\344\273\266/index.html" "b/2022/05/24/\344\275\277\347\224\250shadow DOM\350\207\252\345\256\232\344\271\211\347\273\204\344\273\266/index.html" index e69de29b..a4353583 100644 --- "a/2022/05/24/\344\275\277\347\224\250shadow DOM\350\207\252\345\256\232\344\271\211\347\273\204\344\273\266/index.html" +++ "b/2022/05/24/\344\275\277\347\224\250shadow DOM\350\207\252\345\256\232\344\271\211\347\273\204\344\273\266/index.html" @@ -0,0 +1,831 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 使用shadow DOM自定义组件 | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + + + + + + +
+ + + +
+ + + + + + + +
+ + + +

使用shadow DOM自定义组件

+ + + +
+ + + + + +
+ + + + + +

在这篇文章中,我们主要介绍Shadow DOM。

+

Shadow DOM被设计为基于组件创建应用的工具,对比其他普通DOM,它提供了:

+
    +
  • 隔离性:在shadow DOM中元素是与普通DOM隔离的,我们使用document.querySelector()将不会返回node节点,同样也不需要担心class/id冲突。

    +
  • +
  • CSS作用域:在shadow DOM中的CSS只在其内部生效,不会影响页面上的其他样式。

    +
  • +
  • 组装:可以设计一个可声明的,基于标记的组件。

    +
  • +
+

与此同时,Shadow DOM对比普通的DOM还有以下两点不同:

+
    +
  • 在页面上如何创建和使用DOM。
  • +
  • 在页面上其他地方它是如何工作的。
  • +
+

通常情况下,你创建DOM节点,然后把它作为子元素添加到另一个元素中, 在shadow DOM中,你创建一个有作用域的DOM树,然后添加到其他子元素中,这个DMO树就称为shadow tree。包含这个tree的元素就称为shadow host。你添加到shadow tree中的任何元素,都是在host中的,包括<style>标签,这就是shadow DOM如何实现CSS样式作用域的。

+

创建Shadow DOM

shadow root是document片段的根节点,当创建shadow DOM时,你就得到了一个shadow root,为一个元素创建shadow DOM,使用element.arrachShadow():

+
1
2
3
4
5
6
var header = document.createElement('header');
var shadowRoot = header.attachShadow({mode: 'open'});
var paragraphElement = document.createElement('p');

paragraphElement.innerText = 'Shadow DOM';
shadowRoot.appendChild(paragraphElement);
+

Shadow DOM中的组装

组装是Shadow DOM中非常重要的一个特性。
当写HTML时,你通过拼接不同的元素比如<div> <header> <form>等来实现页面UI,组装成的web应用,这些标签可以相互搭配。

+

组装定义了为什么<select><form><video>等标签是可扩展的,并且可以接收其他HTML元素作为子元素实现一些特别的功能。

+

比如,<select>知道在设置了预选项的下拉框组件中,如何渲染<option>元素。

+

Shadow DOM采用以下特性用来实现组装。

+

轻量DOM

这是一个自定义组件的写法,自定义标签中包含真实DOM,想象一下如果你想创建一个组件叫extended-button, 这个组件扩展了原生HTML按钮,并且你想包含一个icon和一些文字,写法大概如下:

+
1
2
3
4
5
<extended-button>
<!-- image 和 span 是 extended-button 的轻量 DOM -->
<img src="boot.png" slot="image">
<span>Launch</span>
</extended-button>
+

这个“extended-button”是你定义的自定义组件,其内部的HTML称为轻量DOM。Shadow DOM在这里就是你创建的“extended-button”,它定义了它的内部结构,CSS作用域,并封装了内部实现。

+

Templates

当你在web页面上必须重复使用相同的DOM结构时,最好是定义一些模板来实现复用,这在以前也是可能实现的,但是现在可以使用HTML

+

看个例子:

+
1
2
3
<template id="my-paragraph">
<p> Paragraph content. </p>
</template>
+

这不会在页面上显示,除非你在Javascript中引用它,并把它添加到其他DOM中。

+
1
2
3
var template = document.getElementById('my-paragraph');
var templateContent = template.content;
document.body.appendChild(templateContent);
+

这在一些框架中可以实现,但是在之前提到的,它更加原生,并且有不错的浏览器兼容性:
s2 (1).png

+

Templates可以和自定义元素搭配,起到更好的效果,我们将自定义元素,此时你应该知道浏览器的customElementsAPI,允许你自定义标签来渲染。

+

让我们用templates的内容作为shadow DOM来定义个web component,我们称为my-parrgraph

+
1
2
3
4
5
6
7
8
9
10
customElements.define('my-paragraph',
class extends HTMLElement {
constructor() {
super();

let template = document.getElementById('my-paragraph');
let templateContent = template.content;
const shadowRoot = this.attachShadow({mode: 'open'}).appendChild(templateContent.cloneNode(true));
}
});
+

这里的关键点是我们添加了一个template子元素的副本到shadow root中,副本是通过Node.cloneNode()方法创建的。

+

同样我们可以添加一些样式到shadow DOM中,我们可以在template中添加<style>标签,它在普通DOM中不会生效。

+

例如:我们可以修改我们的template:

+
1
2
3
4
5
6
7
8
9
10
<template id="my-paragraph">
<style>
p {
color: white;
background-color: #666;
padding: 5px;
}
</style>
<p>Paragraph content. </p>
</template>
+

现在我们的自定义元素可以这样使用:
<my-paragraph></my-paragraph>

+

Slots

Templates有一些缺点,其中之一是它的静态内容不允许我们渲染我们的动态数据。

+

这时,<slot>就派上用场了。

+

你可以认为slots是作为占位符,允许你把你自己的HTML放到tempalte中,它允许你创建通用的HTML templates并通过添加slots实现自定义。

+

让我们看template和slot如何搭配:

+
1
2
3
4
5
<template id="my-paragraph">
<p>
<slot name="my-text">Default text</slot>
</p>
</template>
+

如果元素添加自定义标签时,slot的内容没有定义,或者浏览器不支持slots,<my-paragraph>只会显示它的内容“Default text”。

+

为了定义slot的内容,我们应该在<my-paragraph>中包含一个元素,这个元素包含slot属性,并且它的slot值等于我们想要填充的slot的name。

+

比如:

+
1
2
3
<my-paragraph>
<span slot="my-text">Let's have some different text!</span>
</my-paragraph>
+

这个例子是我们插入了一个span标签,他有slot属性,slot的值等于my-text的name.

+

在被浏览器渲染之后,将会显示为以下DOM树:

+
1
2
3
4
5
6
7
8
<my-paragraph>
#shadow-root
<p>
<slot name="my-text">
<span slot="my-text">Let's have some different text!</span>
</slot>
</p>
</my-paragraph>
+

#shadow-root只是一个shadow DOM存在的指示符

+

样式

shadow DOM的组件样式可以定义在主页面中,也可以自定义在shadow DOM中。

+

自定义组件样式

CSS作用域是Shadow DOM的最棒的特性之一。

+
    +
  • 外部的CSS选择器无法选中你的组件。
  • +
  • 组件自定义样式不会影响页面其他部位,他们只在host元素中生效,所以不必担心id命名冲突。
  • +
+

来看个例子:

1
2
3
4
5
6
7
8
9
10
11
12
#shadow-root
<style>
#container {
background: white;
}
#container-items {
display: inline-flex;
}
</style>

<div id="container"></div>
<div id="container-items"></div>

+

所有的样式只会在#shadow-root中生效。

+

你也可以使用<link>元素来引用样式,也只会在#shadow-root中生效。

+

:host伪类

:host允许你选中shadow tree的根节点。

1
2
3
4
5
<style>
:host {
display: block; /* 默认自定义元素是 display: inline */
}
</style>

+

有一个需要注意点的是外层的:host的优先级高于元素内部的:host,并且:host只在shadow root的作用域中生效。
:host(选择器)允许你在符合状态时选中host,因此你可以在响应交互状态时使用它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<style>
:host {
opacity: 0.4;
}

:host(:hover) {
opacity: 1;
}

:host([disabled]) { /* style when host has disabled attribute. */
background: grey;
pointer-events: none;
opacity: 0.4;
}

:host(.pink) > #tabs {
color: pink; /* color internal #tabs node when host has class="pink". */
}
</style>

+

使用:host-context伪类匹配主题

:host-context(选择器)伪类能够在匹配(选择器)时,选中元素,通常情况下用来结合主题使用。比如:

1
2
3
4
5
<body class="lightheme">
<custom-container>

</custom-container>
</body>

+

:host-context(.lightheme)能够生效,并渲染样式。

1
2
3
4
:host-context(.lightheme) {
color: black;
background: white;
}

+

从组件外侧添加样式

你可以从组件的外侧给组件添加样式,比如这样:

1
2
3
custom-container {
color: red;
}

+

外层的样式比shadow DOM中的样式具有更高的优先级。

+

例如,我们外层给的样式:

1
2
3
custom-container {
width: 500px;
}

+

可以覆盖组件的样式规则:

1
2
3
:host {
width: 300px;
}

+

事件模型

Shadow DOM的事件冒泡机制比较特别,事件的target都由Shadow DOM封装,即组件内部元素的事件,target都会是Shadow DOM组件本身。
以下是Shadow DOM的冒泡事件列表:

+
    +
  • Focus Events: blur, focus, focusin, focusout
  • +
  • Mouse Events: click, dblclick, mousedown, mouseenter, mousemove, etc.
  • +
  • Wheel Events: wheel
  • +
  • Input Events: beforeinput, input
  • +
  • Keyboard Events: keydown, keyup
  • +
  • Composition Events: compositionstart, compositionupdate, compositionend
  • +
  • DragEvent: dragstart, drag, dragend, drop, etc.
  • +
+

自定义事件

自定义事件默认不会冒泡到Shadow DOM外层,如果你想捕获自定义事件且想让它冒泡,你需要添加bubbles: truecomposed: true作为选项。代码如下:

1
2
var container = this.shadowRoot.querySelector('#container');
container.dispatchEvent(new Event('containerchanged', {bubbles: true, composed: true}));

+

浏览器支持

为了检查浏览器是否支持Shadow DOM功能,可以像这样:

1
const supportsShadowDOM = !!HTMLElement.prototype.attachShadow;

+

通常情况下,Shadow DOM与普通DOM有一些行为上的差异,我们可以使用SessionStack库来收集用户事件,网络数据,异常捕获,debug信息,把他们发送到服务端,来让我们能够复现问题。

+

案例

Youtube里大量使用了自定义组件:
enter image description here
其是使用了Polymer library来构建自定义组件。
后面会输出一篇Polymer library的学习笔记,敬请期待。

+

参考文献:

+ + + +
+ + + + + + + + + + + +
+ + + +
+ + + +
+ +
+
+ + +
+ + + + + + +
+
+ + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2015/09/index.html b/archives/2015/09/index.html index e69de29b..b57fff78 100644 --- a/archives/2015/09/index.html +++ b/archives/2015/09/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2015/12/index.html b/archives/2015/12/index.html index e69de29b..e454bf0b 100644 --- a/archives/2015/12/index.html +++ b/archives/2015/12/index.html @@ -0,0 +1,839 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2015/index.html b/archives/2015/index.html index e69de29b..031a154c 100644 --- a/archives/2015/index.html +++ b/archives/2015/index.html @@ -0,0 +1,876 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/04/index.html b/archives/2016/04/index.html index e69de29b..79cd3ac5 100644 --- a/archives/2016/04/index.html +++ b/archives/2016/04/index.html @@ -0,0 +1,839 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/05/index.html b/archives/2016/05/index.html index e69de29b..aced6981 100644 --- a/archives/2016/05/index.html +++ b/archives/2016/05/index.html @@ -0,0 +1,654 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/06/index.html b/archives/2016/06/index.html index e69de29b..f798adc7 100644 --- a/archives/2016/06/index.html +++ b/archives/2016/06/index.html @@ -0,0 +1,728 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/07/index.html b/archives/2016/07/index.html index e69de29b..0683a6b1 100644 --- a/archives/2016/07/index.html +++ b/archives/2016/07/index.html @@ -0,0 +1,765 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/08/index.html b/archives/2016/08/index.html index e69de29b..d9c19615 100644 --- a/archives/2016/08/index.html +++ b/archives/2016/08/index.html @@ -0,0 +1,691 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/09/index.html b/archives/2016/09/index.html index e69de29b..5f14c418 100644 --- a/archives/2016/09/index.html +++ b/archives/2016/09/index.html @@ -0,0 +1,802 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/10/index.html b/archives/2016/10/index.html index e69de29b..c61dcac4 100644 --- a/archives/2016/10/index.html +++ b/archives/2016/10/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/11/index.html b/archives/2016/11/index.html index e69de29b..b90f4834 100644 --- a/archives/2016/11/index.html +++ b/archives/2016/11/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/12/index.html b/archives/2016/12/index.html index e69de29b..c170cd99 100644 --- a/archives/2016/12/index.html +++ b/archives/2016/12/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/index.html b/archives/2016/index.html index e69de29b..df05c08d 100644 --- a/archives/2016/index.html +++ b/archives/2016/index.html @@ -0,0 +1,954 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/page/2/index.html b/archives/2016/page/2/index.html index e69de29b..7f1d4c17 100644 --- a/archives/2016/page/2/index.html +++ b/archives/2016/page/2/index.html @@ -0,0 +1,954 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2016/page/3/index.html b/archives/2016/page/3/index.html index e69de29b..800c2860 100644 --- a/archives/2016/page/3/index.html +++ b/archives/2016/page/3/index.html @@ -0,0 +1,954 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2017/02/index.html b/archives/2017/02/index.html index e69de29b..9787cca8 100644 --- a/archives/2017/02/index.html +++ b/archives/2017/02/index.html @@ -0,0 +1,691 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2017/03/index.html b/archives/2017/03/index.html index e69de29b..de60e678 100644 --- a/archives/2017/03/index.html +++ b/archives/2017/03/index.html @@ -0,0 +1,654 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2017/04/index.html b/archives/2017/04/index.html index e69de29b..358d4063 100644 --- a/archives/2017/04/index.html +++ b/archives/2017/04/index.html @@ -0,0 +1,691 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2017/05/index.html b/archives/2017/05/index.html index e69de29b..8f6ed874 100644 --- a/archives/2017/05/index.html +++ b/archives/2017/05/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2017/07/index.html b/archives/2017/07/index.html index e69de29b..ca6a653d 100644 --- a/archives/2017/07/index.html +++ b/archives/2017/07/index.html @@ -0,0 +1,654 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2017/08/index.html b/archives/2017/08/index.html index e69de29b..fbd6481a 100644 --- a/archives/2017/08/index.html +++ b/archives/2017/08/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2017/09/index.html b/archives/2017/09/index.html index e69de29b..5ccdf283 100644 --- a/archives/2017/09/index.html +++ b/archives/2017/09/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2017/10/index.html b/archives/2017/10/index.html index e69de29b..69cef250 100644 --- a/archives/2017/10/index.html +++ b/archives/2017/10/index.html @@ -0,0 +1,691 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2017/12/index.html b/archives/2017/12/index.html index e69de29b..6a8fbd1e 100644 --- a/archives/2017/12/index.html +++ b/archives/2017/12/index.html @@ -0,0 +1,728 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2017/index.html b/archives/2017/index.html index e69de29b..d54a8d34 100644 --- a/archives/2017/index.html +++ b/archives/2017/index.html @@ -0,0 +1,954 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2017/page/2/index.html b/archives/2017/page/2/index.html index e69de29b..5c83640d 100644 --- a/archives/2017/page/2/index.html +++ b/archives/2017/page/2/index.html @@ -0,0 +1,954 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2018/01/index.html b/archives/2018/01/index.html index e69de29b..a4bac81c 100644 --- a/archives/2018/01/index.html +++ b/archives/2018/01/index.html @@ -0,0 +1,654 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2018/02/index.html b/archives/2018/02/index.html index e69de29b..a158d2f8 100644 --- a/archives/2018/02/index.html +++ b/archives/2018/02/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2018/03/index.html b/archives/2018/03/index.html index e69de29b..76a46914 100644 --- a/archives/2018/03/index.html +++ b/archives/2018/03/index.html @@ -0,0 +1,691 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2018/08/index.html b/archives/2018/08/index.html index e69de29b..711414b2 100644 --- a/archives/2018/08/index.html +++ b/archives/2018/08/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2018/09/index.html b/archives/2018/09/index.html index e69de29b..80a11358 100644 --- a/archives/2018/09/index.html +++ b/archives/2018/09/index.html @@ -0,0 +1,765 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2018/12/index.html b/archives/2018/12/index.html index e69de29b..9705444d 100644 --- a/archives/2018/12/index.html +++ b/archives/2018/12/index.html @@ -0,0 +1,654 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2018/index.html b/archives/2018/index.html index e69de29b..6c649469 100644 --- a/archives/2018/index.html +++ b/archives/2018/index.html @@ -0,0 +1,954 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2018/page/2/index.html b/archives/2018/page/2/index.html index e69de29b..37e1e2c3 100644 --- a/archives/2018/page/2/index.html +++ b/archives/2018/page/2/index.html @@ -0,0 +1,732 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html index e69de29b..2fda16d9 100644 --- a/archives/2020/03/index.html +++ b/archives/2020/03/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/05/index.html b/archives/2020/05/index.html index e69de29b..f38bb4e1 100644 --- a/archives/2020/05/index.html +++ b/archives/2020/05/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2020/index.html b/archives/2020/index.html index e69de29b..3dad7242 100644 --- a/archives/2020/index.html +++ b/archives/2020/index.html @@ -0,0 +1,654 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2021/06/index.html b/archives/2021/06/index.html index e69de29b..7ce990f1 100644 --- a/archives/2021/06/index.html +++ b/archives/2021/06/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2021/index.html b/archives/2021/index.html index e69de29b..5cb17d1a 100644 --- a/archives/2021/index.html +++ b/archives/2021/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2022/03/index.html b/archives/2022/03/index.html index e69de29b..5f712b7f 100644 --- a/archives/2022/03/index.html +++ b/archives/2022/03/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2022/05/index.html b/archives/2022/05/index.html index e69de29b..627df06e 100644 --- a/archives/2022/05/index.html +++ b/archives/2022/05/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2022/index.html b/archives/2022/index.html index e69de29b..7150cc52 100644 --- a/archives/2022/index.html +++ b/archives/2022/index.html @@ -0,0 +1,654 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/2023/08/index.html b/archives/2023/08/index.html index e69de29b..d5508d31 100644 --- a/archives/2023/08/index.html +++ b/archives/2023/08/index.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/page/2/index.html b/archives/page/2/index.html index e69de29b..8fa6867a 100644 --- a/archives/page/2/index.html +++ b/archives/page/2/index.html @@ -0,0 +1,954 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/page/3/index.html b/archives/page/3/index.html index e69de29b..2f357a4a 100644 --- a/archives/page/3/index.html +++ b/archives/page/3/index.html @@ -0,0 +1,959 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/page/4/index.html b/archives/page/4/index.html index e69de29b..62dc24f6 100644 --- a/archives/page/4/index.html +++ b/archives/page/4/index.html @@ -0,0 +1,954 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/page/5/index.html b/archives/page/5/index.html index e69de29b..4b30f408 100644 --- a/archives/page/5/index.html +++ b/archives/page/5/index.html @@ -0,0 +1,959 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/page/6/index.html b/archives/page/6/index.html index e69de29b..6a1eee4f 100644 --- a/archives/page/6/index.html +++ b/archives/page/6/index.html @@ -0,0 +1,954 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/page/7/index.html b/archives/page/7/index.html index e69de29b..88a3ecae 100644 --- a/archives/page/7/index.html +++ b/archives/page/7/index.html @@ -0,0 +1,954 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/archives/page/8/index.html b/archives/page/8/index.html index e69de29b..9e025a08 100644 --- a/archives/page/8/index.html +++ b/archives/page/8/index.html @@ -0,0 +1,922 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 归档 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/css/main.css b/css/main.css index e69de29b..81206d4c 100644 --- a/css/main.css +++ b/css/main.css @@ -0,0 +1,3123 @@ +/* normalize.css v3.0.2 | MIT License | git.io/normalize */ +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} +audio:not([controls]) { + display: none; + height: 0; +} +[hidden], +template { + display: none; +} +a { + background-color: transparent; +} +a:active, +a:hover { + outline: 0; +} +abbr[title] { + border-bottom: 1px dotted; +} +b, +strong { + font-weight: bold; +} +dfn { + font-style: italic; +} +h1 { + font-size: 2em; + margin: 0.67em 0; +} +mark { + background: #ff0; + color: #000; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sup { + top: -0.5em; +} +sub { + bottom: -0.25em; +} +img { + border: 0; +} +svg:not(:root) { + overflow: hidden; +} +figure { + margin: 1em 40px; +} +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} +pre { + overflow: auto; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} +button { + overflow: visible; +} +button, +select { + text-transform: none; +} +button, +html input[type="button"], +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} +button[disabled], +html input[disabled] { + cursor: default; +} +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +input { + line-height: normal; +} +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} +textarea { + overflow: auto; +} +optgroup { + font-weight: bold; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +td, +th { + padding: 0; +} +::selection { + background: #262a30; + color: #fff; +} +body { + position: relative; + font-family: 'Lato', "PingFang SC", "Microsoft YaHei", sans-serif; + font-size: 14px; + line-height: 2; + color: #555; + background: #eee; +} +@media (max-width: 767px) { + body { + padding-right: 0 !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + body { + padding-right: 0 !important; + } +} +@media (min-width: 1600px) { + body { + font-size: 16px; + } +} +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 0; + font-weight: bold; + line-height: 1.5; + font-family: 'Lato', "PingFang SC", "Microsoft YaHei", sans-serif; +} +h2, +h3, +h4, +h5, +h6 { + margin: 20px 0 15px; +} +h1 { + font-size: 22px; +} +@media (max-width: 767px) { + h1 { + font-size: 18px; + } +} +h2 { + font-size: 20px; +} +@media (max-width: 767px) { + h2 { + font-size: 16px; + } +} +h3 { + font-size: 18px; +} +@media (max-width: 767px) { + h3 { + font-size: 14px; + } +} +h4 { + font-size: 16px; +} +@media (max-width: 767px) { + h4 { + font-size: 12px; + } +} +h5 { + font-size: 14px; +} +@media (max-width: 767px) { + h5 { + font-size: 10px; + } +} +h6 { + font-size: 12px; +} +@media (max-width: 767px) { + h6 { + font-size: 8px; + } +} +p { + margin: 0 0 20px 0; +} +a { + color: #555; + text-decoration: none; + outline: none; + border-bottom: 1px solid #999; + word-wrap: break-word; +} +a:hover { + color: #222; + border-bottom-color: #222; +} +blockquote { + margin: 0; + padding: 0; +} +img { + display: block; + margin: auto; + max-width: 100%; + height: auto; +} +hr { + margin: 40px 0; + height: 3px; + border: none; + background-color: #ddd; + background-image: repeating-linear-gradient(-45deg, #fff, #fff 4px, transparent 4px, transparent 8px); +} +blockquote { + padding: 0 15px; + color: #666; + border-left: 4px solid #ddd; +} +blockquote cite::before { + content: "-"; + padding: 0 5px; +} +dt { + font-weight: 700; +} +dd { + margin: 0; + padding: 0; +} +kbd { + border: 1px solid #ccc; + border-radius: 0.2em; + box-shadow: 0.1em 0.1em 0.2em rgba(0,0,0,0.1); + background-color: #f9f9f9; + font-family: inherit; + background-image: -webkit-linear-gradient(top, #eee, #fff, #eee); + padding: 0.1em 0.3em; + white-space: nowrap; +} +.text-left { + text-align: left; +} +.text-center { + text-align: center; +} +.text-right { + text-align: right; +} +.text-justify { + text-align: justify; +} +.text-nowrap { + white-space: nowrap; +} +.text-lowercase { + text-transform: lowercase; +} +.text-uppercase { + text-transform: uppercase; +} +.text-capitalize { + text-transform: capitalize; +} +.center-block { + display: block; + margin-left: auto; + margin-right: auto; +} +.clearfix:before, +.clearfix:after { + content: " "; + display: table; +} +.clearfix:after { + clear: both; +} +.pullquote { + width: 45%; +} +.pullquote.left { + float: left; + margin-left: 5px; + margin-right: 10px; +} +.pullquote.right { + float: right; + margin-left: 10px; + margin-right: 5px; +} +.affix.affix.affix { + position: fixed; +} +.translation { + margin-top: -20px; + font-size: 14px; + color: #999; +} +.scrollbar-measure { + width: 100px; + height: 100px; + overflow: scroll; + position: absolute; + top: -9999px; +} +.use-motion .motion-element { + opacity: 0; +} +table { + margin: 20px 0; + width: 100%; + border-collapse: collapse; + border-spacing: 0; + border: 1px solid #ddd; + font-size: 14px; + table-layout: fixed; + word-wrap: break-all; +} +table>tbody>tr:nth-of-type(odd) { + background-color: #f9f9f9; +} +table>tbody>tr:hover { + background-color: #f5f5f5; +} +caption, +th, +td { + padding: 8px; + text-align: left; + vertical-align: middle; + font-weight: normal; +} +th, +td { + border-bottom: 3px solid #ddd; + border-right: 1px solid #eee; +} +th { + padding-bottom: 10px; + font-weight: 700; +} +td { + border-bottom-width: 1px; +} +html, +body { + height: 100%; +} +.container { + position: relative; + min-height: 100%; +} +.header-inner { + margin: 0 auto; + padding: 100px 0 70px; + width: calc(100% - 252px); +} +@media (min-width: 1600px) { + .container .header-inner { + width: 900px; + } +} +.main { + padding-bottom: 150px; +} +.main-inner { + margin: 0 auto; + width: calc(100% - 252px); +} +@media (min-width: 1600px) { + .container .main-inner { + width: 900px; + } +} +.footer { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + min-height: 50px; +} +.footer-inner { + box-sizing: border-box; + margin: 20px auto; + width: calc(100% - 252px); +} +@media (min-width: 1600px) { + .container .footer-inner { + width: 900px; + } +} +pre, +.highlight { + overflow: auto; + margin: 20px 0; + padding: 0; + font-size: 13px; + color: #4d4d4c; + background: #f7f7f7; + line-height: 1.6; +} +pre, +code { + font-family: consolas, Menlo, "PingFang SC", "Microsoft YaHei", monospace; +} +code { + padding: 2px 4px; + word-wrap: break-word; + color: #555; + background: #eee; + border-radius: 3px; + font-size: 13px; +} +pre { + padding: 10px; +} +pre code { + padding: 0; + color: #4d4d4c; + background: none; + text-shadow: none; +} +.highlight { + border-radius: 1px; +} +.highlight pre { + border: none; + margin: 0; + padding: 10px 0; +} +.highlight table { + margin: 0; + width: auto; + border: none; +} +.highlight td { + border: none; + padding: 0; +} +.highlight figcaption { + font-size: 1em; + color: #4d4d4c; + line-height: 1em; + margin-bottom: 1em; +} +.highlight figcaption:before, +.highlight figcaption:after { + content: " "; + display: table; +} +.highlight figcaption:after { + clear: both; +} +.highlight figcaption a { + float: right; + color: #4d4d4c; +} +.highlight figcaption a:hover { + border-bottom-color: #4d4d4c; +} +.highlight .gutter pre { + padding-left: 10px; + padding-right: 10px; + color: #869194; + text-align: right; + background-color: #eff2f3; +} +.highlight .code pre { + width: 100%; + padding-left: 10px; + padding-right: 10px; + background-color: #f7f7f7; +} +.highlight .line { + height: 20px; +} +.gutter { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.gist table { + width: auto; +} +.gist table td { + border: none; +} +pre .deletion { + background: #fdd; +} +pre .addition { + background: #dfd; +} +pre .meta { + color: #8959a8; +} +pre .comment { + color: #8e908c; +} +pre .variable, +pre .attribute, +pre .tag, +pre .regexp, +pre .ruby .constant, +pre .xml .tag .title, +pre .xml .pi, +pre .xml .doctype, +pre .html .doctype, +pre .css .id, +pre .css .class, +pre .css .pseudo { + color: #c82829; +} +pre .number, +pre .preprocessor, +pre .built_in, +pre .literal, +pre .params, +pre .constant, +pre .command { + color: #f5871f; +} +pre .ruby .class .title, +pre .css .rules .attribute, +pre .string, +pre .value, +pre .inheritance, +pre .header, +pre .ruby .symbol, +pre .xml .cdata, +pre .special, +pre .number, +pre .formula { + color: #718c00; +} +pre .title, +pre .css .hexcolor { + color: #3e999f; +} +pre .function, +pre .python .decorator, +pre .python .title, +pre .ruby .function .title, +pre .ruby .title .keyword, +pre .perl .sub, +pre .javascript .title, +pre .coffeescript .title { + color: #4271ae; +} +pre .keyword, +pre .javascript .function { + color: #8959a8; +} +.full-image.full-image.full-image.full-image { + border: none; + max-width: 100%; + width: auto; + margin: 20px auto 25px; +} +@media (min-width: 992px) { + .full-image.full-image.full-image.full-image { + max-width: none; + width: 118%; + margin: 0 -9%; + } +} +.blockquote-center, +.page-home .post-type-quote blockquote, +.page-post-detail .post-type-quote blockquote { + position: relative; + margin: 40px 0; + padding: 0; + border-left: none; + text-align: center; +} +.blockquote-center::before, +.page-home .post-type-quote blockquote::before, +.page-post-detail .post-type-quote blockquote::before, +.blockquote-center::after, +.page-home .post-type-quote blockquote::after, +.page-post-detail .post-type-quote blockquote::after { + position: absolute; + content: ' '; + display: block; + width: 100%; + height: 24px; + opacity: 0.2; + background-repeat: no-repeat; + background-position: 0 -6px; + background-size: 22px 22px; +} +.blockquote-center::before, +.page-home .post-type-quote blockquote::before, +.page-post-detail .post-type-quote blockquote::before { + top: -20px; + background-image: url("../images/quote-l.svg"); + border-top: 1px solid #ccc; +} +.blockquote-center::after, +.page-home .post-type-quote blockquote::after, +.page-post-detail .post-type-quote blockquote::after { + bottom: -20px; + background-image: url("../images/quote-r.svg"); + border-bottom: 1px solid #ccc; + background-position: 100% 8px; +} +.blockquote-center p, +.page-home .post-type-quote blockquote p, +.page-post-detail .post-type-quote blockquote p, +.blockquote-center div, +.page-home .post-type-quote blockquote div, +.page-post-detail .post-type-quote blockquote div { + text-align: center; +} +.post .post-body .group-picture img { + box-sizing: border-box; + padding: 0 3px; + border: none; +} +.post .group-picture-row { + overflow: hidden; + margin-top: 6px; +} +.post .group-picture-row:first-child { + margin-top: 0; +} +.post .group-picture-column { + float: left; +} +.page-post-detail .post-body .group-picture-column { + float: none; + margin-top: 10px; + width: auto !important; +} +.page-post-detail .post-body .group-picture-column img { + margin: 0 auto; +} +.page-archive .group-picture-container { + overflow: hidden; +} +.page-archive .group-picture-row { + float: left; +} +.page-archive .group-picture-row:first-child { + margin-top: 6px; +} +.page-archive .group-picture-column { + max-width: 150px; + max-height: 150px; +} +.post-body .note { + position: relative; + padding: 15px; + margin-bottom: 20px; + border: 1px solid #eee; + border-left-width: 5px; + border-radius: 3px; +} +.post-body .note h2, +.post-body .note h3, +.post-body .note h4, +.post-body .note h5, +.post-body .note h6 { + margin-top: 0; + margin-bottom: 0; + border-bottom: initial; + padding-top: 0 !important; +} +.post-body .note p:first-child, +.post-body .note ul:first-child, +.post-body .note ol:first-child, +.post-body .note table:first-child, +.post-body .note pre:first-child, +.post-body .note blockquote:first-child { + margin-top: 0; +} +.post-body .note p:last-child, +.post-body .note ul:last-child, +.post-body .note ol:last-child, +.post-body .note table:last-child, +.post-body .note pre:last-child, +.post-body .note blockquote:last-child { + margin-bottom: 0; +} +.post-body .note.default { + border-left-color: #777; +} +.post-body .note.default h2, +.post-body .note.default h3, +.post-body .note.default h4, +.post-body .note.default h5, +.post-body .note.default h6 { + color: #777; +} +.post-body .note.primary { + border-left-color: #6f42c1; +} +.post-body .note.primary h2, +.post-body .note.primary h3, +.post-body .note.primary h4, +.post-body .note.primary h5, +.post-body .note.primary h6 { + color: #6f42c1; +} +.post-body .note.info { + border-left-color: #428bca; +} +.post-body .note.info h2, +.post-body .note.info h3, +.post-body .note.info h4, +.post-body .note.info h5, +.post-body .note.info h6 { + color: #428bca; +} +.post-body .note.success { + border-left-color: #5cb85c; +} +.post-body .note.success h2, +.post-body .note.success h3, +.post-body .note.success h4, +.post-body .note.success h5, +.post-body .note.success h6 { + color: #5cb85c; +} +.post-body .note.warning { + border-left-color: #f0ad4e; +} +.post-body .note.warning h2, +.post-body .note.warning h3, +.post-body .note.warning h4, +.post-body .note.warning h5, +.post-body .note.warning h6 { + color: #f0ad4e; +} +.post-body .note.danger { + border-left-color: #d9534f; +} +.post-body .note.danger h2, +.post-body .note.danger h3, +.post-body .note.danger h4, +.post-body .note.danger h5, +.post-body .note.danger h6 { + color: #d9534f; +} +.post-body .label { + display: inline; + padding: 0 2px; + white-space: nowrap; +} +.post-body .label.default { + background-color: #f0f0f0; +} +.post-body .label.primary { + background-color: #efe6f7; +} +.post-body .label.info { + background-color: #e5f2f8; +} +.post-body .label.success { + background-color: #e7f4e9; +} +.post-body .label.warning { + background-color: #fcf6e1; +} +.post-body .label.danger { + background-color: #fae8eb; +} +.post-body .tabs { + position: relative; + display: block; + margin-bottom: 20px; + padding-top: 10px; +} +.post-body .tabs ul.nav-tabs { + margin: 0; + padding: 0; + display: flex; + margin-bottom: -1px; +} +@media (max-width: 413px) { + .post-body .tabs ul.nav-tabs { + display: block; + margin-bottom: 5px; + } +} +.post-body .tabs ul.nav-tabs li.tab { + list-style-type: none !important; + margin: 0 0.25em 0 0; + border-top: 3px solid transparent; + border-left: 1px solid transparent; + border-right: 1px solid transparent; +} +@media (max-width: 413px) { + .post-body .tabs ul.nav-tabs li.tab { + margin: initial; + border-top: 1px solid transparent; + border-left: 3px solid transparent; + border-right: 1px solid transparent; + border-bottom: 1px solid transparent; + } +} +.post-body .tabs ul.nav-tabs li.tab a { + outline: 0; + border-bottom: initial; + display: block; + line-height: 1.8em; + padding: 0.25em 0.75em; + transition-duration: 0.2s; + transition-timing-function: ease-out; + transition-delay: 0s; +} +.post-body .tabs ul.nav-tabs li.tab a i { + width: 1.285714285714286em; +} +.post-body .tabs ul.nav-tabs li.tab.active { + border-top: 3px solid #fc6423; + border-left: 1px solid #ddd; + border-right: 1px solid #ddd; + background-color: #fff; +} +@media (max-width: 413px) { + .post-body .tabs ul.nav-tabs li.tab.active { + border-top: 1px solid #ddd; + border-left: 3px solid #fc6423; + border-right: 1px solid #ddd; + border-bottom: 1px solid #ddd; + } +} +.post-body .tabs ul.nav-tabs li.tab.active a { + cursor: default; + color: #555; +} +.post-body .tabs .tab-content { + background-color: #fff; +} +.post-body .tabs .tab-content .tab-pane { + border: 1px solid #ddd; + padding: 20px 20px 0 20px; +} +.post-body .tabs .tab-content .tab-pane:not(.active) { + display: none !important; +} +.post-body .tabs .tab-content .tab-pane.active { + display: block !important; +} +.btn { + display: inline-block; + padding: 0 20px; + font-size: 14px; + color: #555; + background: #fff; + border: 2px solid #555; + text-decoration: none; + border-radius: 2px; + transition-property: background-color; + transition-duration: 0.2s; + transition-timing-function: ease-in-out; + transition-delay: 0s; + line-height: 2; +} +.btn:hover { + border-color: #222; + color: #fff; + background: #222; +} +.btn +.btn { + margin: 0 0 8px 8px; +} +.btn .fa-fw { + width: 1.285714285714286em; + text-align: left; +} +.btn-bar { + display: block; + width: 22px; + height: 2px; + background: #555; + border-radius: 1px; +} +.btn-bar+.btn-bar { + margin-top: 4px; +} +.pagination { + margin: 120px 0 40px; + text-align: center; + border-top: 1px solid #eee; +} +.page-number-basic, +.pagination .prev, +.pagination .next, +.pagination .page-number, +.pagination .space { + display: inline-block; + position: relative; + top: -1px; + margin: 0 10px; + padding: 0 11px; +} +@media (max-width: 767px) { + .page-number-basic, + .pagination .prev, + .pagination .next, + .pagination .page-number, + .pagination .space { + margin: 0 5px; + } +} +.pagination .prev, +.pagination .next, +.pagination .page-number { + border-bottom: 0; + border-top: 1px solid #eee; + transition-property: border-color; + transition-duration: 0.2s; + transition-timing-function: ease-in-out; + transition-delay: 0s; +} +.pagination .prev:hover, +.pagination .next:hover, +.pagination .page-number:hover { + border-top-color: #222; +} +.pagination .space { + padding: 0; + margin: 0; +} +.pagination .prev { + margin-left: 0; +} +.pagination .next { + margin-right: 0; +} +.pagination .page-number.current { + color: #fff; + background: #ccc; + border-top-color: #ccc; +} +@media (max-width: 767px) { + .pagination { + border-top: none; + } + .pagination .prev, + .pagination .next, + .pagination .page-number { + margin-bottom: 10px; + border-top: 0; + border-bottom: 1px solid #eee; + padding: 0 10px; + } + .pagination .prev:hover, + .pagination .next:hover, + .pagination .page-number:hover { + border-bottom-color: #222; + } +} +.comments { + margin: 60px 20px 0; +} +.tag-cloud { + text-align: center; +} +.tag-cloud a { + display: inline-block; + margin: 10px; +} +.back-to-top { + box-sizing: border-box; + position: fixed; + bottom: -100px; + right: 30px; + z-index: 1050; + padding: 0 6px; + width: 24px; + background: #222; + font-size: 12px; + opacity: 0.6; + color: #fff; + cursor: pointer; + text-align: center; + -webkit-transform: translateZ(0); + transition-property: bottom; + transition-duration: 0.2s; + transition-timing-function: ease-in-out; + transition-delay: 0s; +} +@media (min-width: 768px) and (max-width: 991px) { + .back-to-top { + display: none !important; + } +} +@media (max-width: 767px) { + .back-to-top { + display: none !important; + } +} +.back-to-top.back-to-top-on { + bottom: 30px; +} +.header { + background: transparent; +} +.header-inner { + position: relative; +} +.headband { + height: 3px; + background: #222; +} +.site-meta { + margin: 0; + text-align: center; +} +@media (max-width: 767px) { + .site-meta { + text-align: center; + } +} +.brand { + position: relative; + display: inline-block; + padding: 0 40px; + color: #fff; + background: #222; + border-bottom: none; +} +.brand:hover { + color: #fff; +} +.logo { + display: inline-block; + margin-right: 5px; + line-height: 36px; + vertical-align: top; +} +.site-title { + display: inline-block; + vertical-align: top; + line-height: 36px; + font-size: 20px; + font-weight: normal; + font-family: 'Lato', "PingFang SC", "Microsoft YaHei", sans-serif; +} +.site-subtitle { + margin-top: 10px; + font-size: 13px; + color: #ddd; +} +.use-motion .brand { + opacity: 0; +} +.use-motion .logo, +.use-motion .site-title, +.use-motion .site-subtitle { + opacity: 0; + position: relative; + top: -10px; +} +.site-nav-toggle { + display: none; + position: absolute; + top: 10px; + left: 10px; +} +@media (max-width: 767px) { + .site-nav-toggle { + display: block; + } +} +.site-nav-toggle button { + margin-top: 2px; + padding: 9px 10px; + background: transparent; + border: none; +} +@media (max-width: 767px) { + .site-nav { + display: none; + margin: 0 -10px; + padding: 0 10px; + clear: both; + border-top: 1px solid #ddd; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .site-nav { + display: block !important; + } +} +@media (min-width: 992px) { + .site-nav { + display: block !important; + } +} +.menu { + margin-top: 20px; + padding-left: 0; + text-align: center; +} +.menu .menu-item { + display: inline-block; + margin: 0 10px; + list-style: none; +} +@media screen and (max-width: 767px) { + .menu .menu-item { + margin-top: 10px; + } +} +.menu .menu-item a { + display: block; + font-size: 13px; + line-height: inherit; + border-bottom: 1px solid transparent; + transition-property: border-color; + transition-duration: 0.2s; + transition-timing-function: ease-in-out; + transition-delay: 0s; +} +.menu .menu-item a:hover, +.menu-item-active a { + border-bottom-color: #222; +} +.menu .menu-item .fa { + margin-right: 5px; +} +.use-motion .menu-item { + opacity: 0; +} +.post-body { + font-family: 'Lato', "PingFang SC", "Microsoft YaHei", sans-serif; +} +@media (max-width: 767px) { + .post-body { + word-break: break-word; + } +} +.post-body .fancybox img { + display: block !important; + margin: 0 auto; + cursor: pointer; + cursor: zoom-in; + cursor: -webkit-zoom-in; +} +.post-body .image-caption, +.post-body .figure .caption { + margin: -20px auto 15px; + text-align: center; + font-size: 14px; + color: #999; + font-weight: bold; + line-height: 1; +} +.post-sticky-flag { + display: inline-block; + font-size: 16px; + -ms-transform: rotate(30deg); + -webkit-transform: rotate(30deg); + -moz-transform: rotate(30deg); + -ms-transform: rotate(30deg); + -o-transform: rotate(30deg); + transform: rotate(30deg); +} +.use-motion .post-block, +.use-motion .pagination, +.use-motion .comments { + opacity: 0; +} +.use-motion .post-header { + opacity: 0; +} +.use-motion .post-body { + opacity: 0; +} +.use-motion .collection-title { + opacity: 0; +} +.posts-expand { + padding-top: 40px; +} +@media (max-width: 767px) { + .posts-expand { + margin: 0 20px; + } + .post-body pre .gutter pre { + padding-right: 10px; + } + .post-body .highlight { + margin-left: 0px; + margin-right: 0px; + padding: 0; + } + .post-body .highlight .gutter pre { + padding-right: 10px; + } +} +@media (min-width: 992px) { + .posts-expand .post-body { + text-align: justify; + } +} +.posts-expand .post-body h2, +.posts-expand .post-body h3, +.posts-expand .post-body h4, +.posts-expand .post-body h5, +.posts-expand .post-body h6 { + padding-top: 10px; +} +.posts-expand .post-body h2 .header-anchor, +.posts-expand .post-body h3 .header-anchor, +.posts-expand .post-body h4 .header-anchor, +.posts-expand .post-body h5 .header-anchor, +.posts-expand .post-body h6 .header-anchor { + float: right; + margin-left: 10px; + color: #ccc; + border-bottom-style: none; + visibility: hidden; +} +.posts-expand .post-body h2 .header-anchor:hover, +.posts-expand .post-body h3 .header-anchor:hover, +.posts-expand .post-body h4 .header-anchor:hover, +.posts-expand .post-body h5 .header-anchor:hover, +.posts-expand .post-body h6 .header-anchor:hover { + color: inherit; +} +.posts-expand .post-body h2:hover .header-anchor, +.posts-expand .post-body h3:hover .header-anchor, +.posts-expand .post-body h4:hover .header-anchor, +.posts-expand .post-body h5:hover .header-anchor, +.posts-expand .post-body h6:hover .header-anchor { + visibility: visible; +} +.posts-expand .post-body ul li { + list-style: circle; +} +.posts-expand .post-body img { + box-sizing: border-box; + margin: auto; + padding: 3px; + border: 1px solid #ddd; +} +.posts-expand .post-body .fancybox img { + margin: 0 auto 25px; +} +@media (max-width: 767px) { + .posts-collapse { + margin: 0 20px; + } + .posts-collapse .post-title, + .posts-collapse .post-meta { + display: block; + width: auto; + text-align: left; + } +} +.posts-collapse { + position: relative; + z-index: 1010; + margin-left: 55px; +} +.posts-collapse::after { + content: " "; + position: absolute; + top: 20px; + left: 0; + margin-left: -2px; + width: 4px; + height: 100%; + background: #f5f5f5; + z-index: -1; +} +@media (max-width: 767px) { + .posts-collapse { + margin: 0 20px; + } +} +.posts-collapse .collection-title { + position: relative; + margin: 60px 0; +} +.posts-collapse .collection-title h1, +.posts-collapse .collection-title h2 { + margin-left: 20px; +} +.posts-collapse .collection-title small { + color: #bbb; + margin-left: 5px; +} +.posts-collapse .collection-title::before { + content: " "; + position: absolute; + left: 0; + top: 50%; + margin-left: -4px; + margin-top: -4px; + width: 8px; + height: 8px; + background: #bbb; + border-radius: 50%; +} +.posts-collapse .post { + margin: 30px 0; +} +.posts-collapse .post-header { + position: relative; + transition-duration: 0.2s; + transition-timing-function: ease-in-out; + transition-delay: 0s; + transition-property: border; + border-bottom: 1px dashed #ccc; +} +.posts-collapse .post-header::before { + content: " "; + position: absolute; + left: 0; + top: 12px; + width: 6px; + height: 6px; + margin-left: -4px; + background: #bbb; + border-radius: 50%; + border: 1px solid #fff; + transition-duration: 0.2s; + transition-timing-function: ease-in-out; + transition-delay: 0s; + transition-property: background; +} +.posts-collapse .post-header:hover { + border-bottom-color: #666; +} +.posts-collapse .post-header:hover::before { + background: #222; +} +.posts-collapse .post-meta { + position: absolute; + font-size: 12px; + left: 20px; + top: 5px; +} +.posts-collapse .post-comments-count { + display: none; +} +.posts-collapse .post-title { + margin-left: 60px; + font-size: 16px; + font-weight: normal; + line-height: inherit; +} +.posts-collapse .post-title::after { + margin-left: 3px; + opacity: 0.6; +} +.posts-collapse .post-title a { + color: #666; + border-bottom: none; +} +.page-home .post-type-quote .post-header, +.page-post-detail .post-type-quote .post-header, +.page-home .post-type-quote .post-tags, +.page-post-detail .post-type-quote .post-tags { + display: none; +} +.posts-expand .post-title { + text-align: center; + word-break: break-word; + font-weight: 400; +} +.posts-expand .post-title-link { + display: inline-block; + position: relative; + color: #555; + border-bottom: none; + line-height: 1.2; + vertical-align: top; +} +.posts-expand .post-title-link::before { + content: ""; + position: absolute; + width: 100%; + height: 2px; + bottom: 0; + left: 0; + background-color: #000; + visibility: hidden; + -webkit-transform: scaleX(0); + -moz-transform: scaleX(0); + -ms-transform: scaleX(0); + -o-transform: scaleX(0); + transform: scaleX(0); + transition-duration: 0.2s; + transition-timing-function: ease-in-out; + transition-delay: 0s; +} +.posts-expand .post-title-link:hover::before { + visibility: visible; + -webkit-transform: scaleX(1); + -moz-transform: scaleX(1); + -ms-transform: scaleX(1); + -o-transform: scaleX(1); + transform: scaleX(1); +} +.posts-expand .post-title-link .fa { + font-size: 16px; +} +.posts-expand .post-meta { + margin: 3px 0 60px 0; + color: #999; + font-family: 'Lato', "PingFang SC", "Microsoft YaHei", sans-serif; + font-size: 12px; + text-align: center; +} +.posts-expand .post-meta .post-category-list { + display: inline-block; + margin: 0; + padding: 3px; +} +.posts-expand .post-meta .post-category-list-link { + color: #999; +} +.posts-expand .post-meta .post-description { + font-size: 14px; + margin-top: 2px; +} +.post-meta-divider { + margin: 0 0.5em; +} +.post-meta-item-icon { + margin-right: 3px; +} +@media (min-width: 768px) and (max-width: 991px) { + .post-meta-item-icon { + display: inline-block; + } +} +@media (max-width: 767px) { + .post-meta-item-icon { + display: inline-block; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .post-meta-item-text { + display: none; + } +} +@media (max-width: 767px) { + .post-meta-item-text { + display: none; + } +} +@media (max-width: 767px) { + .posts-expand .post-comments-count { + display: none; + } +} +.post-button { + margin-top: 40px; +} +.posts-expand .post-tags { + margin-top: 40px; + text-align: center; +} +.posts-expand .post-tags a { + display: inline-block; + margin-right: 10px; + font-size: 13px; +} +.post-nav { + display: table; + margin-top: 15px; + width: 100%; + border-top: 1px solid #eee; +} +.post-nav-divider { + display: table-cell; + width: 10%; +} +.post-nav-item { + display: table-cell; + padding: 10px 0 0 0; + width: 45%; + vertical-align: top; +} +.post-nav-item a { + position: relative; + display: block; + line-height: 25px; + font-size: 14px; + color: #555; + border-bottom: none; +} +.post-nav-item a:hover { + color: #222; + border-bottom: none; +} +.post-nav-item a:active { + top: 2px; +} +.post-nav-item .fa { + position: absolute; + top: 8px; + left: 0; + font-size: 12px; +} +.post-nav-next a { + padding-left: 15px; +} +.post-nav-prev { + text-align: right; +} +.post-nav-prev a { + padding-right: 15px; +} +.post-nav-prev .fa { + right: 0; + left: auto; +} +.posts-expand .post-eof { + display: block; + margin: 80px auto 60px; + width: 8%; + height: 1px; + background: #ccc; + text-align: center; +} +.post:last-child .post-eof.post-eof.post-eof { + display: none; +} +.post-gallery { + display: table; + table-layout: fixed; + width: 100%; + border-collapse: separate; +} +.post-gallery-row { + display: table-row; +} +.post-gallery .post-gallery-img { + display: table-cell; + text-align: center; + vertical-align: middle; + border: none; +} +.post-gallery .post-gallery-img img { + max-width: 100%; + max-height: 100%; + border: none; +} +.fancybox-close, +.fancybox-close:hover { + border: none; +} +.rtl.post-body p, +.rtl.post-body a, +.rtl.post-body h1, +.rtl.post-body h2, +.rtl.post-body h3, +.rtl.post-body h4, +.rtl.post-body h5, +.rtl.post-body h6, +.rtl.post-body li, +.rtl.post-body ul, +.rtl.post-body ol { + direction: rtl; + font-family: UKIJ Ekran; +} +.rtl.post-title { + font-family: UKIJ Ekran; +} +.sidebar { + position: fixed; + right: 0; + top: 0; + bottom: 0; + width: 0; + z-index: 1040; + box-shadow: inset 0 2px 6px #000; + background: #222; + -webkit-transform: translateZ(0); +} +.sidebar a { + color: #999; + border-bottom-color: #555; +} +.sidebar a:hover { + color: #eee; +} +@media (min-width: 768px) and (max-width: 991px) { + .sidebar { + display: none !important; + } +} +@media (max-width: 767px) { + .sidebar { + display: none !important; + } +} +.sidebar-inner { + position: relative; + padding: 20px 10px; + color: #999; + text-align: center; +} +.site-overview-wrap { + overflow: hidden; +} +.site-overview { + overflow-y: auto; + overflow-x: hidden; +} +.sidebar-toggle { + position: fixed; + right: 30px; + bottom: 45px; + width: 14px; + height: 14px; + padding: 5px; + background: #222; + line-height: 0; + z-index: 1050; + cursor: pointer; + -webkit-transform: translateZ(0); +} +@media (min-width: 768px) and (max-width: 991px) { + .sidebar-toggle { + display: none !important; + } +} +@media (max-width: 767px) { + .sidebar-toggle { + display: none !important; + } +} +.sidebar-toggle-line { + position: relative; + display: inline-block; + vertical-align: top; + height: 2px; + width: 100%; + background: #fff; + margin-top: 3px; +} +.sidebar-toggle-line:first-child { + margin-top: 0; +} +.site-author-image { + display: block; + margin: 0 auto; + padding: 2px; + max-width: 120px; + height: auto; + border: 1px solid #eee; +} +.site-author-name { + margin: 0; + text-align: center; + color: #222; + font-weight: 600; +} +.site-description { + margin-top: 0; + text-align: center; + font-size: 13px; + color: #999; +} +.site-state { + overflow: hidden; + line-height: 1.4; + white-space: nowrap; + text-align: center; +} +.site-state-item { + display: inline-block; + padding: 0 15px; + border-left: 1px solid #eee; +} +.site-state-item:first-child { + border-left: none; +} +.site-state-item a { + border-bottom: none; +} +.site-state-item-count { + display: block; + text-align: center; + color: inherit; + font-weight: 600; + font-size: 16px; +} +.site-state-item-name { + font-size: 13px; + color: #999; +} +.feed-link { + margin-top: 20px; +} +.feed-link a { + display: inline-block; + padding: 0 15px; + color: #fc6423; + border: 1px solid #fc6423; + border-radius: 4px; +} +.feed-link a i { + color: #fc6423; + font-size: 14px; +} +.feed-link a:hover { + color: #fff; + background: #fc6423; +} +.feed-link a:hover i { + color: #fff; +} +.links-of-author { + margin-top: 20px; +} +.links-of-author a { + display: inline-block; + vertical-align: middle; + margin-right: 10px; + margin-bottom: 10px; + border-bottom-color: #555; + font-size: 13px; +} +.links-of-author a:before { + display: inline-block; + vertical-align: middle; + margin-right: 3px; + content: " "; + width: 4px; + height: 4px; + border-radius: 50%; + background: #fffbee; +} +.links-of-blogroll { + font-size: 13px; +} +.links-of-blogroll-title { + margin-top: 20px; + font-size: 14px; + font-weight: 600; +} +.links-of-blogroll-list { + margin: 0; + padding: 0; + list-style: none; +} +.links-of-blogroll-item { + padding: 2px 10px; +} +.links-of-blogroll-item a { + max-width: 280px; + box-sizing: border-box; + display: inline-block; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.sidebar-nav { + margin: 0 0 20px; + padding-left: 0; +} +.sidebar-nav li { + display: inline-block; + cursor: pointer; + border-bottom: 1px solid transparent; + font-size: 14px; + color: #555; +} +.sidebar-nav li:hover { + color: #fc6423; +} +.page-post-detail .sidebar-nav-toc { + padding: 0 5px; +} +.page-post-detail .sidebar-nav-overview { + margin-left: 10px; +} +.sidebar-nav .sidebar-nav-active { + color: #fc6423; + border-bottom-color: #fc6423; +} +.sidebar-nav .sidebar-nav-active:hover { + color: #fc6423; +} +.sidebar-panel { + display: none; +} +.sidebar-panel-active { + display: block; +} +.post-toc-empty { + font-size: 14px; + color: #666; +} +.post-toc-wrap { + overflow: hidden; +} +.post-toc { + overflow: auto; +} +.post-toc ol { + margin: 0; + padding: 0 2px 5px 10px; + text-align: left; + list-style: none; + font-size: 14px; +} +.post-toc ol > ol { + padding-left: 0; +} +.post-toc ol a { + transition-duration: 0.2s; + transition-timing-function: ease-in-out; + transition-delay: 0s; + transition-property: all; + color: #666; + border-bottom-color: #ccc; +} +.post-toc ol a:hover { + color: #000; + border-bottom-color: #000; +} +.post-toc .nav-item { + overflow: hidden; + text-overflow: ellipsis; + text-align: justify; + white-space: nowrap; + line-height: 1.8; +} +.post-toc .nav .nav-child { + display: none; +} +.post-toc .nav .active > .nav-child { + display: block; +} +.post-toc .nav .active-current > .nav-child { + display: block; +} +.post-toc .nav .active-current > .nav-child > .nav-item { + display: block; +} +.post-toc .nav .active > a { + color: #fc6423; + border-bottom-color: #fc6423; +} +.post-toc .nav .active-current > a { + color: #fc6423; +} +.post-toc .nav .active-current > a:hover { + color: #fc6423; +} +.footer { + font-size: 14px; + color: #999; +} +.footer img { + border: none; +} +.footer-inner { + text-align: center; +} +.with-love { + display: inline-block; + margin: 0 5px; +} +.powered-by, +.theme-info { + display: inline-block; +} +.cc-license { + margin-top: 10px; + text-align: center; +} +.cc-license .cc-opacity { + opacity: 0.7; + border-bottom: none; +} +.cc-license .cc-opacity:hover { + opacity: 0.9; +} +.cc-license img { + display: inline-block; +} +.theme-next #ds-thread #ds-reset { + color: #555; +} +.theme-next #ds-thread #ds-reset .ds-replybox { + margin-bottom: 30px; +} +.theme-next #ds-thread #ds-reset .ds-replybox .ds-avatar, +.theme-next #ds-reset .ds-avatar img { + box-shadow: none; +} +.theme-next #ds-thread #ds-reset .ds-textarea-wrapper { + border-color: #c7d4e1; + background: none; + border-top-right-radius: 3px; + border-top-left-radius: 3px; +} +.theme-next #ds-thread #ds-reset .ds-textarea-wrapper textarea { + height: 60px; +} +.theme-next #ds-reset .ds-rounded-top { + border-radius: 0; +} +.theme-next #ds-thread #ds-reset .ds-post-toolbar { + box-sizing: border-box; + border: 1px solid #c7d4e1; + background: #f6f8fa; +} +.theme-next #ds-thread #ds-reset .ds-post-options { + height: 40px; + border: none; + background: none; +} +.theme-next #ds-thread #ds-reset .ds-toolbar-buttons { + top: 11px; +} +.theme-next #ds-thread #ds-reset .ds-sync { + top: 5px; +} +.theme-next #ds-thread #ds-reset .ds-post-button { + top: 4px; + right: 5px; + width: 90px; + height: 30px; + border: 1px solid #c5ced7; + border-radius: 3px; + background-image: linear-gradient(#fbfbfc, #f5f7f9); + color: #60676d; +} +.theme-next #ds-thread #ds-reset .ds-post-button:hover { + background-position: 0 -30px; + color: #60676d; +} +.theme-next #ds-thread #ds-reset .ds-comments-info { + padding: 10px 0; +} +.theme-next #ds-thread #ds-reset .ds-sort { + display: none; +} +.theme-next #ds-thread #ds-reset li.ds-tab a.ds-current { + border: none; + background: #f6f8fa; + color: #60676d; +} +.theme-next #ds-thread #ds-reset li.ds-tab a.ds-current:hover { + background-color: #e9f0f7; + color: #60676d; +} +.theme-next #ds-thread #ds-reset li.ds-tab a { + border-radius: 2px; + padding: 5px; +} +.theme-next #ds-thread #ds-reset .ds-login-buttons p { + color: #999; + line-height: 36px; +} +.theme-next #ds-thread #ds-reset .ds-login-buttons .ds-service-list li { + height: 28px; +} +.theme-next #ds-thread #ds-reset .ds-service-list a { + background: none; + padding: 5px; + border: 1px solid; + border-radius: 3px; + text-align: center; +} +.theme-next #ds-thread #ds-reset .ds-service-list a:hover { + color: #fff; + background: #666; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-weibo { + color: #fc9b00; + border-color: #fc9b00; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-weibo:hover { + background: #fc9b00; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-qq { + color: #60a3ec; + border-color: #60a3ec; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-qq:hover { + background: #60a3ec; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-renren { + color: #2e7ac4; + border-color: #2e7ac4; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-renren:hover { + background: #2e7ac4; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-douban { + color: #37994c; + border-color: #37994c; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-douban:hover { + background: #37994c; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-kaixin { + color: #fef20d; + border-color: #fef20d; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-kaixin:hover { + background: #fef20d; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-netease { + color: #f00; + border-color: #f00; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-netease:hover { + background: #f00; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-sohu { + color: #ffcb05; + border-color: #ffcb05; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-sohu:hover { + background: #ffcb05; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-baidu { + color: #2831e0; + border-color: #2831e0; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-baidu:hover { + background: #2831e0; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-google { + color: #166bec; + border-color: #166bec; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-google:hover { + background: #166bec; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-weixin { + color: #00ce0d; + border-color: #00ce0d; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-weixin:hover { + background: #00ce0d; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-more-services { + border: none; +} +.theme-next #ds-thread #ds-reset .ds-service-list .ds-more-services:hover { + background: none; +} +.theme-next #ds-reset .duoshuo-ua-admin { + display: inline-block; + color: #f00; +} +.theme-next #ds-reset .duoshuo-ua-platform, +.theme-next #ds-reset .duoshuo-ua-browser { + color: #ccc; +} +.theme-next #ds-reset .duoshuo-ua-platform .fa, +.theme-next #ds-reset .duoshuo-ua-browser .fa { + display: inline-block; + margin-right: 3px; +} +.theme-next #ds-reset .duoshuo-ua-separator { + display: inline-block; + margin-left: 5px; +} +.theme-next .this_ua { + background-color: #ccc !important; + border-radius: 4px; + padding: 0 5px !important; + margin: 1px 1px !important; + border: 1px solid #bbb !important; + color: #fff; + display: inline-block !important; +} +.theme-next .this_ua.admin { + background-color: #d9534f !important; + border-color: #d9534f !important; +} +.theme-next .this_ua.platform.iOS, +.theme-next .this_ua.platform.Mac, +.theme-next .this_ua.platform.Windows { + background-color: #39b3d7 !important; + border-color: #46b8da !important; +} +.theme-next .this_ua.platform.Linux { + background-color: #3a3a3a !important; + border-color: #1f1f1f !important; +} +.theme-next .this_ua.platform.Android { + background-color: #00c47d !important; + border-color: #01b171 !important; +} +.theme-next .this_ua.browser.Mobile, +.theme-next .this_ua.browser.Chrome { + background-color: #5cb85c !important; + border-color: #4cae4c !important; +} +.theme-next .this_ua.browser.Firefox { + background-color: #f0ad4e !important; + border-color: #eea236 !important; +} +.theme-next .this_ua.browser.Maxthon, +.theme-next .this_ua.browser.IE { + background-color: #428bca !important; + border-color: #357ebd !important; +} +.theme-next .this_ua.browser.baidu, +.theme-next .this_ua.browser.UCBrowser, +.theme-next .this_ua.browser.Opera { + background-color: #d9534f !important; + border-color: #d43f3a !important; +} +.theme-next .this_ua.browser.Android, +.theme-next .this_ua.browser.QQBrowser { + background-color: #78ace9 !important; + border-color: #4cae4c !important; +} +.post-spread { + margin-top: 20px; + text-align: center; +} +.jiathis_style { + display: inline-block; +} +.jiathis_style a { + border: none; +} +.fa { + font-family: FontAwesome !important; +} +.post-spread { + margin-top: 20px; + text-align: center; +} +.bdshare-slide-button-box a { + border: none; +} +.bdsharebuttonbox { + display: inline-block; +} +.bdsharebuttonbox a { + border: none; +} +.local-search-pop-overlay { + position: fixed; + width: 100%; + height: 100%; + top: 0; + left: 0; + z-index: 2080; + background-color: rgba(0,0,0,0.3); +} +.local-search-popup { + display: none; + position: fixed; + top: 10%; + left: 50%; + margin-left: -350px; + width: 700px; + height: 80%; + padding: 0; + background: #fff; + color: #333; + z-index: 9999; + border-radius: 5px; +} +@media (max-width: 767px) { + .local-search-popup { + padding: 0; + top: 0; + left: 0; + margin: 0; + width: 100%; + height: 100%; + border-radius: 0; + } +} +.local-search-popup ul.search-result-list { + padding: 0; + margin: 0 5px; +} +.local-search-popup p.search-result { + border-bottom: 1px dashed #ccc; + padding: 5px 0; +} +.local-search-popup a.search-result-title { + font-weight: bold; + font-size: 16px; +} +.local-search-popup .search-keyword { + border-bottom: 1px dashed #f00; + font-weight: bold; + color: #f00; +} +.local-search-popup .local-search-header { + padding: 5px; + height: 36px; + background: #f5f5f5; + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} +.local-search-popup #local-search-result { + overflow: auto; + position: relative; + padding: 5px 25px; + height: calc(100% - 55px); +} +.local-search-popup .local-search-input-wrapper { + display: inline-block; + width: calc(100% - 90px); + height: 36px; + line-height: 36px; + padding: 0 5px; +} +.local-search-popup .local-search-input-wrapper input { + padding: 8px 0; + height: 20px; + display: block; + width: 100%; + outline: none; + border: none; + background: transparent; + vertical-align: middle; +} +.local-search-popup .search-icon, +.local-search-popup .popup-btn-close { + display: inline-block; + font-size: 18px; + color: #999; + height: 36px; + width: 18px; + padding-left: 10px; + padding-right: 10px; +} +.local-search-popup .search-icon { + float: left; +} +.local-search-popup .popup-btn-close { + border-left: 1px solid #eee; + float: right; + cursor: pointer; +} +.local-search-popup #no-result { + position: absolute; + left: 50%; + top: 50%; + -webkit-transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + -moz-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + -o-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + color: #ccc; +} +.site-uv, +.site-pv, +.page-pv { + display: inline-block; +} +.site-uv .busuanzi-value, +.site-pv .busuanzi-value, +.page-pv .busuanzi-value { + margin: 0 5px; +} +.site-uv { + margin-right: 10px; +} +.site-uv::after { + content: "|"; + padding-left: 10px; +} +.page-archive .archive-page-counter { + position: relative; + top: 3px; + left: 20px; +} +@media (max-width: 767px) { + .page-archive .archive-page-counter { + top: 5px; + } +} +.page-archive .posts-collapse .archive-move-on { + position: absolute; + top: 11px; + left: 0; + margin-left: -6px; + width: 10px; + height: 10px; + opacity: 0.5; + background: #555; + border: 1px solid #fff; + border-radius: 50%; +} +.category-all-page .category-all-title { + text-align: center; +} +.category-all-page .category-all { + margin-top: 20px; +} +.category-all-page .category-list { + margin: 0; + padding: 0; + list-style: none; +} +.category-all-page .category-list-item { + margin: 5px 10px; +} +.category-all-page .category-list-count { + color: #bbb; +} +.category-all-page .category-list-count:before { + display: inline; + content: " ("; +} +.category-all-page .category-list-count:after { + display: inline; + content: ") "; +} +.category-all-page .category-list-child { + padding-left: 10px; +} +#schedule ul#event-list { + padding-left: 30px; +} +#schedule ul#event-list hr { + margin: 20px 0 45px 0 !important; + background: #222; +} +#schedule ul#event-list hr:after { + display: inline-block; + content: 'NOW'; + background: #222; + color: #fff; + font-weight: bold; + text-align: right; + padding: 0 5px; +} +#schedule ul#event-list li.event { + margin: 20px 0px; + background: #f9f9f9; + padding-left: 10px; + min-height: 40px; +} +#schedule ul#event-list li.event h2.event-summary { + margin: 0; + padding-bottom: 3px; +} +#schedule ul#event-list li.event h2.event-summary:before { + display: inline-block; + font-family: FontAwesome; + font-size: 8px; + content: '\f111'; + vertical-align: middle; + margin-right: 25px; + color: #bbb; +} +#schedule ul#event-list li.event span.event-relative-time { + display: inline-block; + font-size: 12px; + font-weight: 400; + padding-left: 12px; + color: #bbb; +} +#schedule ul#event-list li.event span.event-details { + display: block; + color: #bbb; + margin-left: 56px; + padding-top: 3px; + padding-bottom: 6px; + text-indent: -24px; + line-height: 18px; +} +#schedule ul#event-list li.event span.event-details:before { + text-indent: 0; + display: inline-block; + width: 14px; + font-family: FontAwesome; + text-align: center; + margin-right: 9px; + color: #bbb; +} +#schedule ul#event-list li.event span.event-details.event-location:before { + content: '\f041'; +} +#schedule ul#event-list li.event span.event-details.event-duration:before { + content: '\f017'; +} +#schedule ul#event-list li.event-past { + background: #fcfcfc; +} +#schedule ul#event-list li.event-past > * { + opacity: 0.6; +} +#schedule ul#event-list li.event-past h2.event-summary { + color: #bbb; +} +#schedule ul#event-list li.event-past h2.event-summary:before { + color: #dfdfdf; +} +#schedule ul#event-list li.event-now { + background: #222; + color: #fff; + padding: 15px 0 15px 10px; +} +#schedule ul#event-list li.event-now h2.event-summary:before { + -webkit-transform: scale(1.2); + -moz-transform: scale(1.2); + -ms-transform: scale(1.2); + -o-transform: scale(1.2); + transform: scale(1.2); + color: #fff; + animation: dot-flash 1s alternate infinite ease-in-out; +} +#schedule ul#event-list li.event-now * { + color: #fff !important; +} +@-moz-keyframes dot-flash { + from { + opacity: 1; + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -ms-transform: scale(1.1); + -o-transform: scale(1.1); + transform: scale(1.1); + } + to { + opacity: 0; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); + } +} +@-webkit-keyframes dot-flash { + from { + opacity: 1; + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -ms-transform: scale(1.1); + -o-transform: scale(1.1); + transform: scale(1.1); + } + to { + opacity: 0; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); + } +} +@-o-keyframes dot-flash { + from { + opacity: 1; + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -ms-transform: scale(1.1); + -o-transform: scale(1.1); + transform: scale(1.1); + } + to { + opacity: 0; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); + } +} +@keyframes dot-flash { + from { + opacity: 1; + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -ms-transform: scale(1.1); + -o-transform: scale(1.1); + transform: scale(1.1); + } + to { + opacity: 0; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -ms-transform: scale(1); + -o-transform: scale(1); + transform: scale(1); + } +} +.page-post-detail .sidebar-toggle-line { + background: #fc6423; +} +.page-post-detail .comments { + overflow: hidden; +} +.header { + position: relative; + margin: 0 auto; + width: 75%; +} +@media (min-width: 768px) and (max-width: 991px) { + .header { + width: auto; + } +} +@media (max-width: 767px) { + .header { + width: auto; + } +} +.header-inner { + position: absolute; + top: 0; + overflow: hidden; + padding: 0; + width: 240px; + background: #fff; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12); + border-radius: initial; +} +@media (min-width: 1600px) { + .container .header-inner { + width: 240px; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .header-inner { + position: relative; + width: auto; + border-radius: initial; + } +} +@media (max-width: 767px) { + .header-inner { + position: relative; + width: auto; + border-radius: initial; + } +} +.main:before, +.main:after { + content: " "; + display: table; +} +.main:after { + clear: both; +} +@media (min-width: 768px) and (max-width: 991px) { + .main { + padding-bottom: 100px; + } +} +@media (max-width: 767px) { + .main { + padding-bottom: 100px; + } +} +.container .main-inner { + width: 75%; +} +@media (min-width: 768px) and (max-width: 991px) { + .container .main-inner { + width: auto; + } +} +@media (max-width: 767px) { + .container .main-inner { + width: auto; + } +} +.content-wrap { + float: right; + box-sizing: border-box; + padding: 40px; + width: calc(100% - 252px); + background: #fff; + min-height: 700px; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12); + border-radius: initial; +} +@media (min-width: 768px) and (max-width: 991px) { + .content-wrap { + width: 100%; + padding: 20px; + border-radius: initial; + } +} +@media (max-width: 767px) { + .content-wrap { + width: 100%; + padding: 20px; + min-height: auto; + border-radius: initial; + } +} +.sidebar { + position: static; + float: left; + margin-top: 300px; + width: 240px; + background: #eee; + box-shadow: none; +} +@media (min-width: 768px) and (max-width: 991px) { + .sidebar { + display: none; + } +} +@media (max-width: 767px) { + .sidebar { + display: none; + } +} +.sidebar-toggle { + display: none; +} +.footer-inner { + width: 75%; + padding-left: 260px; +} +@media (min-width: 768px) and (max-width: 991px) { + .footer-inner { + width: auto; + padding-left: 0 !important; + padding-right: 0 !important; + } +} +@media (max-width: 767px) { + .footer-inner { + width: auto; + padding-left: 0 !important; + padding-right: 0 !important; + } +} +.sidebar-position-right .header-inner { + right: 0; +} +.sidebar-position-right .content-wrap { + float: left; +} +.sidebar-position-right .sidebar { + float: right; +} +.sidebar-position-right .footer-inner { + padding-left: 0; + padding-right: 260px; +} +.site-brand-wrapper { + position: relative; +} +.site-meta { + padding: 20px 0; + color: #fff; + background: #222; +} +@media (min-width: 768px) and (max-width: 991px) { + .site-meta { + box-shadow: 0 0 16px rgba(0,0,0,0.5); + } +} +@media (max-width: 767px) { + .site-meta { + box-shadow: 0 0 16px rgba(0,0,0,0.5); + } +} +.brand { + padding: 0; + background: none; +} +.brand:hover { + color: #fff; +} +.site-subtitle { + margin: 10px 10px 0; + font-weight: initial; +} +.site-search form { + display: none; +} +.site-nav { + border-top: none; +} +@media (min-width: 768px) and (max-width: 991px) { + .site-nav { + display: none !important; + } +} +@media (min-width: 768px) and (max-width: 991px) { + .site-nav-on { + display: block !important; + } +} +.menu .menu-item { + display: block; + margin: 0; +} +.menu .menu-item a { + position: relative; + box-sizing: border-box; + padding: 5px 20px; + text-align: left; + line-height: inherit; + transition-property: background-color; + transition-duration: 0.2s; + transition-timing-function: ease-in-out; + transition-delay: 0s; +} +.menu .menu-item a:hover, +.menu-item-active a { + background: #f9f9f9; + border-bottom-color: #fff; +} +.menu .menu-item br { + display: none; +} +.menu-item-active a:after { + content: " "; + position: absolute; + top: 50%; + margin-top: -3px; + right: 15px; + width: 6px; + height: 6px; + border-radius: 50%; + background-color: #bbb; +} +.btn-bar { + background-color: #fff; +} +.site-nav-toggle { + left: 20px; + top: 50%; + -webkit-transform: translateY(-50%); + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -ms-transform: translateY(-50%); + -o-transform: translateY(-50%); + transform: translateY(-50%); +} +@media (min-width: 768px) and (max-width: 991px) { + .site-nav-toggle { + display: block; + } +} +.use-motion .sidebar .motion-element { + opacity: 1; +} +.sidebar { + margin-left: -100%; + right: auto; + bottom: auto; + -webkit-transform: none; +} +.sidebar-inner { + box-sizing: border-box; + width: 240px; + color: #555; + background: #fff; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12), 0 -1px 0.5px 0 rgba(0,0,0,0.09); + border-radius: initial; + opacity: 0; +} +.sidebar-inner.affix { + position: fixed; + top: 12px; +} +.sidebar-inner.affix-bottom { + position: absolute; +} +.site-overview { + text-align: left; +} +.site-author:before, +.site-author:after { + content: " "; + display: table; +} +.site-author:after { + clear: both; +} +.sidebar a { + color: #555; +} +.sidebar a:hover { + color: #222; +} +.site-state-item { + padding: 0 10px; +} +.links-of-author-item a:before { + display: none; +} +.links-of-author-item a { + border-bottom: none; + text-decoration: underline; +} +.feed-link { + border-top: 1px dotted #ccc; + border-bottom: 1px dotted #ccc; + text-align: center; +} +.feed-link a { + display: block; + color: #fc6423; + border: none; +} +.feed-link a:hover { + background: none; + color: #e34603; +} +.feed-link a:hover i { + color: #e34603; +} +.links-of-author { + display: flex; + flex-wrap: wrap; + justify-content: center; +} +.links-of-author-item { + margin: 5px 0 0; + width: 50%; +} +.links-of-author-item a { + max-width: 216px; + box-sizing: border-box; + display: inline-block; + margin-right: 0; + margin-bottom: 0; + padding: 0 5px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.links-of-author-item a { + display: block; + text-decoration: none; +} +.links-of-author-item a:hover { + border-radius: 4px; + background: #eee; +} +.links-of-author-item .fa { + margin-right: 2px; + font-size: 16px; +} +.links-of-author-item .fa-globe { + font-size: 15px; +} +.links-of-blogroll { + text-align: center; + margin-top: 20px; + padding: 3px 0 0; + border-top: 1px dotted #ccc; +} +.links-of-blogroll-title { + margin-top: 0; +} +.links-of-blogroll-item { + padding: 0; +} +.links-of-blogroll-inline:before, +.links-of-blogroll-inline:after { + content: " "; + display: table; +} +.links-of-blogroll-inline:after { + clear: both; +} +.links-of-blogroll-inline .links-of-blogroll-item { + margin: 5px 0 0; + width: 50%; + display: inline-block; + width: unset; +} +.links-of-blogroll-inline .links-of-blogroll-item a { + max-width: 216px; + box-sizing: border-box; + display: inline-block; + margin-right: 0; + margin-bottom: 0; + padding: 0 5px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.content-wrap { + padding: initial; + background: initial; + box-shadow: initial; + border-radius: initial; +} +.post-block { + padding: 40px; + background: #fff; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12); + border-radius: initial; +} +#posts > article + article .post-block { + margin-top: 12px; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12), 0 -1px 0.5px 0 rgba(0,0,0,0.09); + border-radius: initial; +} +.comments { + padding: 40px; + margin: initial; + margin-top: 12px; + background: #fff; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12), 0 -1px 0.5px 0 rgba(0,0,0,0.09); + border-radius: initial; +} +.posts-expand { + padding-top: initial; +} +.post-nav-divider { + width: 4%; +} +.post-nav-item { + width: 48%; +} +.post-eof, +.post-spread { + display: none !important; +} +.pagination { + margin: 12px 0 0; + border-top: initial; + background: #fff; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12), 0 -1px 0.5px 0 rgba(0,0,0,0.09); + border-radius: initial; + padding: 10px 0 10px; +} +.pagination .prev, +.pagination .next, +.pagination .page-number { + margin-bottom: initial; + top: initial; +} +.main { + padding-bottom: initial; +} +.footer { + bottom: auto; +} +.post-header h1, +.post-header h2 { + margin: initial; +} +.posts-expand .post-title-link { + line-height: inherit; +} +.posts-expand .post-title { + font-size: 1.7em; +} +.post-body h1 { + font-size: 1.6em; + border-bottom: 1px solid #eee; +} +.post-body h2 { + font-size: 1.45em; + border-bottom: 1px solid #eee; +} +.post-body h3 { + font-size: 1.3em; + border-bottom: 1px dotted #eee; +} +.post-body h4 { + font-size: 1.2em; +} +.post-body h5 { + font-size: 1.07em; +} +.post-body h6 { + font-size: 1.03em; +} +@media (min-width: 768px) and (max-width: 991px) { + .content-wrap { + padding: 10px; + } + .posts-expand { + margin: initial; + } + .posts-expand .post-button { + margin-top: 20px; + } + .post-block { + padding: 20px; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12), 0 -1px 0.5px 0 rgba(0,0,0,0.09); + border-radius: initial; + } + #posts > article + article .post-block { + margin-top: 10px; + } + .comments { + margin-top: 10px; + padding: 10px 20px; + } + .pagination { + margin: 10px 0 0; + } +} +@media (max-width: 767px) { + .content-wrap { + padding: 8px; + } + .posts-expand { + margin: initial; + } + .posts-expand .post-button { + margin-top: 12px; + } + .posts-expand img { + padding: initial !important; + } + .post-block { + padding: 12px; + min-height: auto; + box-shadow: 0 2px 2px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.06), 0 1px 5px 0 rgba(0,0,0,0.12), 0 -1px 0.5px 0 rgba(0,0,0,0.09); + border-radius: initial; + } + #posts > article + article .post-block { + margin-top: 8px; + } + .comments { + margin-top: 8px; + padding: 0 12px; + } + .pagination { + margin: 8px 0 0; + } +} diff --git a/images/algolia_logo.svg b/images/algolia_logo.svg index e69de29b..47024234 100644 --- a/images/algolia_logo.svg +++ b/images/algolia_logo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/images/apple-touch-icon-next.png b/images/apple-touch-icon-next.png index e69de29b..86a0d1d3 100644 Binary files a/images/apple-touch-icon-next.png and b/images/apple-touch-icon-next.png differ diff --git a/images/avatar.gif b/images/avatar.gif index e69de29b..98990257 100644 Binary files a/images/avatar.gif and b/images/avatar.gif differ diff --git a/images/cc-by-nc-nd.svg b/images/cc-by-nc-nd.svg index e69de29b..79a4f2e0 100644 --- a/images/cc-by-nc-nd.svg +++ b/images/cc-by-nc-nd.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/images/cc-by-nc-sa.svg b/images/cc-by-nc-sa.svg index e69de29b..bf6bc26f 100644 --- a/images/cc-by-nc-sa.svg +++ b/images/cc-by-nc-sa.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/images/cc-by-nc.svg b/images/cc-by-nc.svg index e69de29b..36973490 100644 --- a/images/cc-by-nc.svg +++ b/images/cc-by-nc.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/images/cc-by-nd.svg b/images/cc-by-nd.svg index e69de29b..934c61e1 100644 --- a/images/cc-by-nd.svg +++ b/images/cc-by-nd.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/images/cc-by-sa.svg b/images/cc-by-sa.svg index e69de29b..463276a8 100644 --- a/images/cc-by-sa.svg +++ b/images/cc-by-sa.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/images/cc-by.svg b/images/cc-by.svg index e69de29b..4bccd14f 100644 --- a/images/cc-by.svg +++ b/images/cc-by.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/images/cc-zero.svg b/images/cc-zero.svg index e69de29b..0f866392 100644 --- a/images/cc-zero.svg +++ b/images/cc-zero.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/favicon-16x16-next.png b/images/favicon-16x16-next.png index e69de29b..de8c5d3a 100644 Binary files a/images/favicon-16x16-next.png and b/images/favicon-16x16-next.png differ diff --git a/images/favicon-32x32-next.png b/images/favicon-32x32-next.png index e69de29b..e02f5f4d 100644 Binary files a/images/favicon-32x32-next.png and b/images/favicon-32x32-next.png differ diff --git a/images/loading.gif b/images/loading.gif index e69de29b..efb6768d 100644 Binary files a/images/loading.gif and b/images/loading.gif differ diff --git a/images/logo.svg b/images/logo.svg index e69de29b..cbb3937e 100644 --- a/images/logo.svg +++ b/images/logo.svg @@ -0,0 +1,23 @@ + +image/svg+xml diff --git a/images/placeholder.gif b/images/placeholder.gif index e69de29b..efb6768d 100644 Binary files a/images/placeholder.gif and b/images/placeholder.gif differ diff --git a/images/quote-l.svg b/images/quote-l.svg index e69de29b..6dd94a4a 100644 --- a/images/quote-l.svg +++ b/images/quote-l.svg @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/images/quote-r.svg b/images/quote-r.svg index e69de29b..312b64d7 100644 --- a/images/quote-r.svg +++ b/images/quote-r.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/images/searchicon.png b/images/searchicon.png index e69de29b..14a16cad 100644 Binary files a/images/searchicon.png and b/images/searchicon.png differ diff --git a/js/src/affix.js b/js/src/affix.js index e69de29b..11a3d39a 100644 --- a/js/src/affix.js +++ b/js/src/affix.js @@ -0,0 +1,162 @@ +/* ======================================================================== + * Bootstrap: affix.js v3.3.5 + * http://getbootstrap.com/javascript/#affix + * ======================================================================== + * Copyright 2011-2015 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + * ======================================================================== */ + + ++function ($) { + 'use strict'; + + // AFFIX CLASS DEFINITION + // ====================== + + var Affix = function (element, options) { + this.options = $.extend({}, Affix.DEFAULTS, options) + + this.$target = $(this.options.target) + .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this)) + .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this)) + + this.$element = $(element) + this.affixed = null + this.unpin = null + this.pinnedOffset = null + + this.checkPosition() + } + + Affix.VERSION = '3.3.5' + + Affix.RESET = 'affix affix-top affix-bottom' + + Affix.DEFAULTS = { + offset: 0, + target: window + } + + Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) { + var scrollTop = this.$target.scrollTop() + var position = this.$element.offset() + var targetHeight = this.$target.height() + + if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false + + if (this.affixed == 'bottom') { + if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom' + return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom' + } + + var initializing = this.affixed == null + var colliderTop = initializing ? scrollTop : position.top + var colliderHeight = initializing ? targetHeight : height + + if (offsetTop != null && scrollTop <= offsetTop) return 'top' + if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom' + + return false + } + + Affix.prototype.getPinnedOffset = function () { + if (this.pinnedOffset) return this.pinnedOffset + this.$element.removeClass(Affix.RESET).addClass('affix') + var scrollTop = this.$target.scrollTop() + var position = this.$element.offset() + return (this.pinnedOffset = position.top - scrollTop) + } + + Affix.prototype.checkPositionWithEventLoop = function () { + setTimeout($.proxy(this.checkPosition, this), 1) + } + + Affix.prototype.checkPosition = function () { + if (!this.$element.is(':visible')) return + + var height = this.$element.height() + var offset = this.options.offset + var offsetTop = offset.top + var offsetBottom = offset.bottom + var scrollHeight = Math.max($(document).height(), $(document.body).height()) + + if (typeof offset != 'object') offsetBottom = offsetTop = offset + if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element) + if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element) + + var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom) + + if (this.affixed != affix) { + if (this.unpin != null) this.$element.css('top', '') + + var affixType = 'affix' + (affix ? '-' + affix : '') + var e = $.Event(affixType + '.bs.affix') + + this.$element.trigger(e) + + if (e.isDefaultPrevented()) return + + this.affixed = affix + this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null + + this.$element + .removeClass(Affix.RESET) + .addClass(affixType) + .trigger(affixType.replace('affix', 'affixed') + '.bs.affix') + } + + if (affix == 'bottom') { + this.$element.offset({ + top: scrollHeight - height - offsetBottom + }) + } + } + + + // AFFIX PLUGIN DEFINITION + // ======================= + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.affix') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.affix', (data = new Affix(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.affix + + $.fn.affix = Plugin + $.fn.affix.Constructor = Affix + + + // AFFIX NO CONFLICT + // ================= + + $.fn.affix.noConflict = function () { + $.fn.affix = old + return this + } + + + // AFFIX DATA-API + // ============== + + $(window).on('load', function () { + $('[data-spy="affix"]').each(function () { + var $spy = $(this) + var data = $spy.data() + + data.offset = data.offset || {} + + if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom + if (data.offsetTop != null) data.offset.top = data.offsetTop + + Plugin.call($spy, data) + }) + }) + +}(jQuery); diff --git a/js/src/algolia-search.js b/js/src/algolia-search.js index e69de29b..9787e2ac 100644 --- a/js/src/algolia-search.js +++ b/js/src/algolia-search.js @@ -0,0 +1,115 @@ +/* global instantsearch: true */ +/*jshint camelcase: false */ + +$(document).ready(function () { + var algoliaSettings = CONFIG.algolia; + var isAlgoliaSettingsValid = algoliaSettings.applicationID && + algoliaSettings.apiKey && + algoliaSettings.indexName; + + if (!isAlgoliaSettingsValid) { + window.console.error('Algolia Settings are invalid.'); + return; + } + + var search = instantsearch({ + appId: algoliaSettings.applicationID, + apiKey: algoliaSettings.apiKey, + indexName: algoliaSettings.indexName, + searchFunction: function (helper) { + var searchInput = $('#algolia-search-input').find('input'); + + if (searchInput.val()) { + helper.search(); + } + } + }); + + // Registering Widgets + [ + instantsearch.widgets.searchBox({ + container: '#algolia-search-input', + placeholder: algoliaSettings.labels.input_placeholder + }), + + instantsearch.widgets.hits({ + container: '#algolia-hits', + hitsPerPage: algoliaSettings.hits.per_page || 10, + templates: { + item: function (data) { + var link = data.permalink ? data.permalink : (CONFIG.root + data.path); + return ( + '' + + data._highlightResult.title.value + + '' + ); + }, + empty: function (data) { + return ( + '
' + + algoliaSettings.labels.hits_empty.replace(/\$\{query}/, data.query) + + '
' + ); + } + }, + cssClasses: { + item: 'algolia-hit-item' + } + }), + + instantsearch.widgets.stats({ + container: '#algolia-stats', + templates: { + body: function (data) { + var stats = algoliaSettings.labels.hits_stats + .replace(/\$\{hits}/, data.nbHits) + .replace(/\$\{time}/, data.processingTimeMS); + return ( + stats + + '' + + ' Algolia' + + '' + + '
' + ); + } + } + }), + + instantsearch.widgets.pagination({ + container: '#algolia-pagination', + scrollTo: false, + showFirstLast: false, + labels: { + first: '', + last: '', + previous: '', + next: '' + }, + cssClasses: { + root: 'pagination', + item: 'pagination-item', + link: 'page-number', + active: 'current', + disabled: 'disabled-item' + } + }) + ].forEach(search.addWidget, search); + + search.start(); + + $('.popup-trigger').on('click', function(e) { + e.stopPropagation(); + $('body') + .append('
') + .css('overflow', 'hidden'); + $('.popup').toggle(); + $('#algolia-search-input').find('input').focus(); + }); + + $('.popup-btn-close').click(function(){ + $('.popup').hide(); + $('.algolia-pop-overlay').remove(); + $('body').css('overflow', ''); + }); + +}); diff --git a/js/src/bootstrap.js b/js/src/bootstrap.js index e69de29b..d9c33ed0 100644 --- a/js/src/bootstrap.js +++ b/js/src/bootstrap.js @@ -0,0 +1,52 @@ +/* global NexT: true */ + +$(document).ready(function () { + + $(document).trigger('bootstrap:before'); + + NexT.utils.isMobile() && window.FastClick.attach(document.body); + + NexT.utils.lazyLoadPostsImages(); + + NexT.utils.registerESCKeyEvent(); + + NexT.utils.registerBackToTop(); + + // Mobile top menu bar. + $('.site-nav-toggle button').on('click', function () { + var $siteNav = $('.site-nav'); + var ON_CLASS_NAME = 'site-nav-on'; + var isSiteNavOn = $siteNav.hasClass(ON_CLASS_NAME); + var animateAction = isSiteNavOn ? 'slideUp' : 'slideDown'; + var animateCallback = isSiteNavOn ? 'removeClass' : 'addClass'; + + $siteNav.stop()[animateAction]('fast', function () { + $siteNav[animateCallback](ON_CLASS_NAME); + }); + }); + + /** + * Register JS handlers by condition option. + * Need to add config option in Front-End at 'layout/_partials/head.swig' file. + */ + CONFIG.fancybox && NexT.utils.wrapImageWithFancyBox(); + CONFIG.tabs && NexT.utils.registerTabsTag(); + + NexT.utils.embeddedVideoTransformer(); + NexT.utils.addActiveClassToMenuItem(); + + + // Define Motion Sequence. + NexT.motion.integrator + .add(NexT.motion.middleWares.logo) + .add(NexT.motion.middleWares.menu) + .add(NexT.motion.middleWares.postList) + .add(NexT.motion.middleWares.sidebar); + + $(document).trigger('motion:before'); + + // Bootstrap Motion. + CONFIG.motion.enable && NexT.motion.integrator.bootstrap(); + + $(document).trigger('bootstrap:after'); +}); diff --git a/js/src/exturl.js b/js/src/exturl.js index e69de29b..b85062ad 100644 --- a/js/src/exturl.js +++ b/js/src/exturl.js @@ -0,0 +1,15 @@ +/* global NexT: true */ + +$(document).ready(function () { + + // Create Base64 Object + var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(e){var t="";var n,r,i,s,o,u,a;var f=0;e=Base64._utf8_encode(e);while(f>2;o=(n&3)<<4|r>>4;u=(r&15)<<2|i>>6;a=i&63;if(isNaN(r)){u=a=64}else if(isNaN(i)){a=64}t=t+this._keyStr.charAt(s)+this._keyStr.charAt(o)+this._keyStr.charAt(u)+this._keyStr.charAt(a)}return t},decode:function(e){var t="";var n,r,i;var s,o,u,a;var f=0;e=e.replace(/[^A-Za-z0-9+/=]/g,"");while(f>4;r=(o&15)<<4|u>>2;i=(u&3)<<6|a;t=t+String.fromCharCode(n);if(u!=64){t=t+String.fromCharCode(r)}if(a!=64){t=t+String.fromCharCode(i)}}t=Base64._utf8_decode(t);return t},_utf8_encode:function(e){e=e.replace(/rn/g,"n");var t="";for(var n=0;n127&&r<2048){t+=String.fromCharCode(r>>6|192);t+=String.fromCharCode(r&63|128)}else{t+=String.fromCharCode(r>>12|224);t+=String.fromCharCode(r>>6&63|128);t+=String.fromCharCode(r&63|128)}}return t},_utf8_decode:function(e){var t="";var n=0;var r=c1=c2=0;while(n191&&r<224){c2=e.charCodeAt(n+1);t+=String.fromCharCode((r&31)<<6|c2&63);n+=2}else{c2=e.charCodeAt(n+1);c3=e.charCodeAt(n+2);t+=String.fromCharCode((r&15)<<12|(c2&63)<<6|c3&63);n+=3}}return t}}; + + $('.exturl').on('click', function () { + var $exturl = $(this).attr('data-url'); + var $decurl = Base64.decode($exturl); + window.open($decurl, '_blank'); + return false; + }); + +}); diff --git a/js/src/hook-duoshuo.js b/js/src/hook-duoshuo.js index e69de29b..ca64dbd0 100644 --- a/js/src/hook-duoshuo.js +++ b/js/src/hook-duoshuo.js @@ -0,0 +1,115 @@ +/* global DUOSHUO: true */ +/* jshint camelcase: false */ + +typeof DUOSHUO !== 'undefined' ? + hookTemplate() : + ($('#duoshuo-script')[0].onload = hookTemplate); + + +function hookTemplate() { + var post = DUOSHUO.templates.post; + + DUOSHUO.templates.post = function (e, t) { + var rs = post(e, t); + var agent = e.post.agent; + var userId = e.post.author.user_id; + var admin = ''; + + if (userId && (userId == CONFIG.duoshuo.userId)) { + admin = '' + CONFIG.duoshuo.author + ''; + } + + if (agent && /^Mozilla/.test(agent)) { + rs = rs.replace(/<\/div>

/, admin + getAgentInfo(agent) + '

'); + } + + return rs; + }; +} + +function getAgentInfo(string) { + $.ua.set(string); + + var UNKNOWN = 'Unknown'; + var sua = $.ua; + var separator = isMobile() ? '

' : ''; + var osName = sua.os.name || UNKNOWN; + var osVersion = sua.os.version || UNKNOWN; + var browserName = sua.browser.name || UNKNOWN; + var browserVersion = sua.browser.version || UNKNOWN; + var iconMapping = { + os: { + android : 'android', + linux : 'linux', + windows : 'windows', + ios : 'apple', + 'mac os': 'apple', + unknown : 'desktop' + }, + browser: { + chrome : 'chrome', + chromium : 'chrome', + firefox : 'firefox', + opera : 'opera', + safari : 'safari', + ie : 'internet-explorer', + wechat : 'wechat', + qq : 'qq', + unknown : 'globe' + } + }; + var osIcon = iconMapping.os[osName.toLowerCase()]; + var browserIcon = iconMapping.browser[getBrowserKey()]; + + return separator + + '' + + '' + + osName + ' ' + osVersion + + '' + separator + + '' + + '' + + browserName + ' ' + browserVersion + + ''; + + function getBrowserKey () { + var key = browserName.toLowerCase(); + + if (key.match(/WeChat/i)) { + return 'wechat'; + } + + if (key.match(/QQBrowser/i)) { + return 'qq'; + } + + return key; + } + + function isMobile() { + var userAgent = window.navigator.userAgent; + + var isiPad = userAgent.match(/iPad/i) !== null; + var mobileUA = [ + 'iphone', 'android', 'phone', 'mobile', + 'wap', 'netfront', 'x11', 'java', 'opera mobi', + 'opera mini', 'ucweb', 'windows ce', 'symbian', + 'symbianos', 'series', 'webos', 'sony', + 'blackberry', 'dopod', 'nokia', 'samsung', + 'palmsource', 'xda', 'pieplus', 'meizu', + 'midp' ,'cldc' , 'motorola', 'foma', + 'docomo', 'up.browser', 'up.link', 'blazer', + 'helio', 'hosin', 'huawei', 'novarra', + 'coolpad', 'webos', 'techfaith', 'palmsource', + 'alcatel', 'amoi', 'ktouch', 'nexian', + 'ericsson', 'philips', 'sagem', 'wellcom', + 'bunjalloo', 'maui', 'smartphone', 'iemobile', + 'spice', 'bird', 'zte-', 'longcos', + 'pantech', 'gionee', 'portalmmm', 'jig browser', + 'hiptop', 'benq', 'haier', '^lct', + '320x320', '240x320', '176x220' + ]; + var pattern = new RegExp(mobileUA.join('|'), 'i'); + + return !isiPad && userAgent.match(pattern); + } +} diff --git a/js/src/js.cookie.js b/js/src/js.cookie.js index e69de29b..c6c39758 100644 --- a/js/src/js.cookie.js +++ b/js/src/js.cookie.js @@ -0,0 +1,165 @@ +/*! + * JavaScript Cookie v2.1.4 + * https://github.com/js-cookie/js-cookie + * + * Copyright 2006, 2015 Klaus Hartl & Fagner Brack + * Released under the MIT license + */ +;(function (factory) { + var registeredInModuleLoader = false; + if (typeof define === 'function' && define.amd) { + define(factory); + registeredInModuleLoader = true; + } + if (typeof exports === 'object') { + module.exports = factory(); + registeredInModuleLoader = true; + } + if (!registeredInModuleLoader) { + var OldCookies = window.Cookies; + var api = window.Cookies = factory(); + api.noConflict = function () { + window.Cookies = OldCookies; + return api; + }; + } +}(function () { + function extend () { + var i = 0; + var result = {}; + for (; i < arguments.length; i++) { + var attributes = arguments[ i ]; + for (var key in attributes) { + result[key] = attributes[key]; + } + } + return result; + } + + function init (converter) { + function api (key, value, attributes) { + var result; + if (typeof document === 'undefined') { + return; + } + + // Write + + if (arguments.length > 1) { + attributes = extend({ + path: '/' + }, api.defaults, attributes); + + if (typeof attributes.expires === 'number') { + var expires = new Date(); + expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5); + attributes.expires = expires; + } + + // We're using "expires" because "max-age" is not supported by IE + attributes.expires = attributes.expires ? attributes.expires.toUTCString() : ''; + + try { + result = JSON.stringify(value); + if (/^[\{\[]/.test(result)) { + value = result; + } + } catch (e) {} + + if (!converter.write) { + value = encodeURIComponent(String(value)) + .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent); + } else { + value = converter.write(value, key); + } + + key = encodeURIComponent(String(key)); + key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent); + key = key.replace(/[\(\)]/g, escape); + + var stringifiedAttributes = ''; + + for (var attributeName in attributes) { + if (!attributes[attributeName]) { + continue; + } + stringifiedAttributes += '; ' + attributeName; + if (attributes[attributeName] === true) { + continue; + } + stringifiedAttributes += '=' + attributes[attributeName]; + } + return (document.cookie = key + '=' + value + stringifiedAttributes); + } + + // Read + + if (!key) { + result = {}; + } + + // To prevent the for loop in the first place assign an empty array + // in case there are no cookies at all. Also prevents odd result when + // calling "get()" + var cookies = document.cookie ? document.cookie.split('; ') : []; + var rdecode = /(%[0-9A-Z]{2})+/g; + var i = 0; + + for (; i < cookies.length; i++) { + var parts = cookies[i].split('='); + var cookie = parts.slice(1).join('='); + + if (cookie.charAt(0) === '"') { + cookie = cookie.slice(1, -1); + } + + try { + var name = parts[0].replace(rdecode, decodeURIComponent); + cookie = converter.read ? + converter.read(cookie, name) : converter(cookie, name) || + cookie.replace(rdecode, decodeURIComponent); + + if (this.json) { + try { + cookie = JSON.parse(cookie); + } catch (e) {} + } + + if (key === name) { + result = cookie; + break; + } + + if (!key) { + result[name] = cookie; + } + } catch (e) {} + } + + return result; + } + + api.set = api; + api.get = function (key) { + return api.call(api, key); + }; + api.getJSON = function () { + return api.apply({ + json: true + }, [].slice.call(arguments)); + }; + api.defaults = {}; + + api.remove = function (key, attributes) { + api(key, '', extend(attributes, { + expires: -1 + })); + }; + + api.withConverter = init; + + return api; + } + + return init(function () {}); +})); diff --git a/js/src/motion.js b/js/src/motion.js index e69de29b..11291791 100644 --- a/js/src/motion.js +++ b/js/src/motion.js @@ -0,0 +1,352 @@ +/* global NexT: true */ + +$(document).ready(function () { + NexT.motion = {}; + + var sidebarToggleLines = { + lines: [], + push: function (line) { + this.lines.push(line); + }, + init: function () { + this.lines.forEach(function (line) { + line.init(); + }); + }, + arrow: function () { + this.lines.forEach(function (line) { + line.arrow(); + }); + }, + close: function () { + this.lines.forEach(function (line) { + line.close(); + }); + } + }; + + function SidebarToggleLine(settings) { + this.el = $(settings.el); + this.status = $.extend({}, { + init: { + width: '100%', + opacity: 1, + left: 0, + rotateZ: 0, + top: 0 + } + }, settings.status); + } + + SidebarToggleLine.prototype.init = function () { + this.transform('init'); + }; + SidebarToggleLine.prototype.arrow = function () { + this.transform('arrow'); + }; + SidebarToggleLine.prototype.close = function () { + this.transform('close'); + }; + SidebarToggleLine.prototype.transform = function (status) { + this.el.velocity('stop').velocity(this.status[status]); + }; + + var sidebarToggleLine1st = new SidebarToggleLine({ + el: '.sidebar-toggle-line-first', + status: { + arrow: {width: '50%', rotateZ: '-45deg', top: '2px'}, + close: {width: '100%', rotateZ: '-45deg', top: '5px'} + } + }); + var sidebarToggleLine2nd = new SidebarToggleLine({ + el: '.sidebar-toggle-line-middle', + status: { + arrow: {width: '90%'}, + close: {opacity: 0} + } + }); + var sidebarToggleLine3rd = new SidebarToggleLine({ + el: '.sidebar-toggle-line-last', + status: { + arrow: {width: '50%', rotateZ: '45deg', top: '-2px'}, + close: {width: '100%', rotateZ: '45deg', top: '-5px'} + } + }); + + sidebarToggleLines.push(sidebarToggleLine1st); + sidebarToggleLines.push(sidebarToggleLine2nd); + sidebarToggleLines.push(sidebarToggleLine3rd); + + var SIDEBAR_WIDTH = '320px'; + var SIDEBAR_DISPLAY_DURATION = 200; + var xPos, yPos; + + var sidebarToggleMotion = { + toggleEl: $('.sidebar-toggle'), + dimmerEl: $('#sidebar-dimmer'), + sidebarEl: $('.sidebar'), + isSidebarVisible: false, + init: function () { + this.toggleEl.on('click', this.clickHandler.bind(this)); + this.dimmerEl.on('click', this.clickHandler.bind(this)); + this.toggleEl.on('mouseenter', this.mouseEnterHandler.bind(this)); + this.toggleEl.on('mouseleave', this.mouseLeaveHandler.bind(this)); + this.sidebarEl.on('touchstart', this.touchstartHandler.bind(this)); + this.sidebarEl.on('touchend', this.touchendHandler.bind(this)); + this.sidebarEl.on('touchmove', function(e){e.preventDefault();}); + + $(document) + .on('sidebar.isShowing', function () { + NexT.utils.isDesktop() && $('body').velocity('stop').velocity( + {paddingRight: SIDEBAR_WIDTH}, + SIDEBAR_DISPLAY_DURATION + ); + }) + .on('sidebar.isHiding', function () { + }); + }, + clickHandler: function () { + this.isSidebarVisible ? this.hideSidebar() : this.showSidebar(); + this.isSidebarVisible = !this.isSidebarVisible; + }, + mouseEnterHandler: function () { + if (this.isSidebarVisible) { + return; + } + sidebarToggleLines.arrow(); + }, + mouseLeaveHandler: function () { + if (this.isSidebarVisible) { + return; + } + sidebarToggleLines.init(); + }, + touchstartHandler: function(e) { + xPos = e.originalEvent.touches[0].clientX; + yPos = e.originalEvent.touches[0].clientY; + }, + touchendHandler: function(e) { + var _xPos = e.originalEvent.changedTouches[0].clientX; + var _yPos = e.originalEvent.changedTouches[0].clientY; + if (_xPos-xPos > 30 && Math.abs(_yPos-yPos) < 20) { + this.clickHandler(); + } + }, + showSidebar: function () { + var self = this; + + sidebarToggleLines.close(); + + this.sidebarEl.velocity('stop').velocity({ + width: SIDEBAR_WIDTH + }, { + display: 'block', + duration: SIDEBAR_DISPLAY_DURATION, + begin: function () { + $('.sidebar .motion-element').velocity( + 'transition.slideRightIn', + { + stagger: 50, + drag: true, + complete: function () { + self.sidebarEl.trigger('sidebar.motion.complete'); + } + } + ); + }, + complete: function () { + self.sidebarEl.addClass('sidebar-active'); + self.sidebarEl.trigger('sidebar.didShow'); + } + } + ); + + this.sidebarEl.trigger('sidebar.isShowing'); + }, + hideSidebar: function () { + NexT.utils.isDesktop() && $('body').velocity('stop').velocity({paddingRight: 0}); + this.sidebarEl.find('.motion-element').velocity('stop').css('display', 'none'); + this.sidebarEl.velocity('stop').velocity({width: 0}, {display: 'none'}); + + sidebarToggleLines.init(); + + this.sidebarEl.removeClass('sidebar-active'); + this.sidebarEl.trigger('sidebar.isHiding'); + + // Prevent adding TOC to Overview if Overview was selected when close & open sidebar. + if (!!$('.post-toc-wrap')) { + if ($('.site-overview-wrap').css('display') === 'block') { + $('.post-toc-wrap').removeClass('motion-element'); + } else { + $('.post-toc-wrap').addClass('motion-element'); + } + } + } + }; + sidebarToggleMotion.init(); + + NexT.motion.integrator = { + queue: [], + cursor: -1, + add: function (fn) { + this.queue.push(fn); + return this; + }, + next: function () { + this.cursor++; + var fn = this.queue[this.cursor]; + $.isFunction(fn) && fn(NexT.motion.integrator); + }, + bootstrap: function () { + this.next(); + } + }; + + NexT.motion.middleWares = { + logo: function (integrator) { + var sequence = []; + var $brand = $('.brand'); + var $title = $('.site-title'); + var $subtitle = $('.site-subtitle'); + var $logoLineTop = $('.logo-line-before i'); + var $logoLineBottom = $('.logo-line-after i'); + + $brand.size() > 0 && sequence.push({ + e: $brand, + p: {opacity: 1}, + o: {duration: 200} + }); + + NexT.utils.isMist() && hasElement([$logoLineTop, $logoLineBottom]) && + sequence.push( + getMistLineSettings($logoLineTop, '100%'), + getMistLineSettings($logoLineBottom, '-100%') + ); + + hasElement($title) && sequence.push({ + e: $title, + p: {opacity: 1, top: 0}, + o: { duration: 200 } + }); + + hasElement($subtitle) && sequence.push({ + e: $subtitle, + p: {opacity: 1, top: 0}, + o: {duration: 200} + }); + + if (CONFIG.motion.async) { + integrator.next(); + } + + if (sequence.length > 0) { + sequence[sequence.length - 1].o.complete = function () { + integrator.next(); + }; + $.Velocity.RunSequence(sequence); + } else { + integrator.next(); + } + + + function getMistLineSettings (element, translateX) { + return { + e: $(element), + p: {translateX: translateX}, + o: { + duration: 500, + sequenceQueue: false + } + }; + } + + /** + * Check if $elements exist. + * @param {jQuery|Array} $elements + * @returns {boolean} + */ + function hasElement ($elements) { + $elements = Array.isArray($elements) ? $elements : [$elements]; + return $elements.every(function ($element) { + return $.isFunction($element.size) && $element.size() > 0; + }); + } + }, + + menu: function (integrator) { + + if (CONFIG.motion.async) { + integrator.next(); + } + + $('.menu-item').velocity('transition.slideDownIn', { + display: null, + duration: 200, + complete: function () { + integrator.next(); + } + }); + }, + + postList: function (integrator) { + //var $post = $('.post'); + var $postBlock = $('.post-block, .pagination, .comments'); + var $postBlockTransition = CONFIG.motion.transition.post_block; + var $postHeader = $('.post-header'); + var $postHeaderTransition = CONFIG.motion.transition.post_header; + var $postBody = $('.post-body'); + var $postBodyTransition = CONFIG.motion.transition.post_body; + var $collHeader = $('.collection-title, .archive-year'); + var $collHeaderTransition = CONFIG.motion.transition.coll_header; + var $sidebarAffix = $('.sidebar-inner'); + var $sidebarAffixTransition = CONFIG.motion.transition.sidebar; + var hasPost = $postBlock.size() > 0; + + hasPost ? postMotion() : integrator.next(); + + if (CONFIG.motion.async) { + integrator.next(); + } + + function postMotion () { + var postMotionOptions = window.postMotionOptions || { + stagger: 100, + drag: true + }; + postMotionOptions.complete = function () { + // After motion complete need to remove transform from sidebar to let affix work on Pisces | Gemini. + if (CONFIG.motion.transition.sidebar && (NexT.utils.isPisces() || NexT.utils.isGemini())) { + $sidebarAffix.css({ 'transform': 'initial' }); + } + integrator.next(); + }; + + //$post.velocity('transition.slideDownIn', postMotionOptions); + if (CONFIG.motion.transition.post_block) { + $postBlock.velocity('transition.' + $postBlockTransition, postMotionOptions); + } + if (CONFIG.motion.transition.post_header) { + $postHeader.velocity('transition.' + $postHeaderTransition, postMotionOptions); + } + if (CONFIG.motion.transition.post_body) { + $postBody.velocity('transition.' + $postBodyTransition, postMotionOptions); + } + if (CONFIG.motion.transition.coll_header) { + $collHeader.velocity('transition.' + $collHeaderTransition, postMotionOptions); + } + // Only for Pisces | Gemini. + if (CONFIG.motion.transition.sidebar && (NexT.utils.isPisces() || NexT.utils.isGemini())) { + $sidebarAffix.velocity('transition.' + $sidebarAffixTransition, postMotionOptions); + } + } + }, + + sidebar: function (integrator) { + if (CONFIG.sidebar.display === 'always') { + NexT.utils.displaySidebar(); + } + integrator.next(); + } + }; + +}); diff --git a/js/src/post-details.js b/js/src/post-details.js index e69de29b..a82bcc22 100644 --- a/js/src/post-details.js +++ b/js/src/post-details.js @@ -0,0 +1,99 @@ +/* global NexT: true */ + +$(document).ready(function () { + + initScrollSpy(); + + function initScrollSpy () { + var tocSelector = '.post-toc'; + var $tocElement = $(tocSelector); + var activeCurrentSelector = '.active-current'; + + $tocElement + .on('activate.bs.scrollspy', function () { + var $currentActiveElement = $(tocSelector + ' .active').last(); + + removeCurrentActiveClass(); + $currentActiveElement.addClass('active-current'); + + // Scrolling to center active TOC element if TOC content is taller then viewport. + $tocElement.scrollTop($currentActiveElement.offset().top - $tocElement.offset().top + $tocElement.scrollTop() - ($tocElement.height() / 2)); + }) + .on('clear.bs.scrollspy', removeCurrentActiveClass); + + $('body').scrollspy({ target: tocSelector }); + + function removeCurrentActiveClass () { + $(tocSelector + ' ' + activeCurrentSelector) + .removeClass(activeCurrentSelector.substring(1)); + } + } + +}); + +$(document).ready(function () { + var html = $('html'); + var TAB_ANIMATE_DURATION = 200; + var hasVelocity = $.isFunction(html.velocity); + + $('.sidebar-nav li').on('click', function () { + var item = $(this); + var activeTabClassName = 'sidebar-nav-active'; + var activePanelClassName = 'sidebar-panel-active'; + if (item.hasClass(activeTabClassName)) { + return; + } + + var currentTarget = $('.' + activePanelClassName); + var target = $('.' + item.data('target')); + + hasVelocity ? + currentTarget.velocity('transition.slideUpOut', TAB_ANIMATE_DURATION, function () { + target + .velocity('stop') + .velocity('transition.slideDownIn', TAB_ANIMATE_DURATION) + .addClass(activePanelClassName); + }) : + currentTarget.animate({ opacity: 0 }, TAB_ANIMATE_DURATION, function () { + currentTarget.hide(); + target + .stop() + .css({'opacity': 0, 'display': 'block'}) + .animate({ opacity: 1 }, TAB_ANIMATE_DURATION, function () { + currentTarget.removeClass(activePanelClassName); + target.addClass(activePanelClassName); + }); + }); + + item.siblings().removeClass(activeTabClassName); + item.addClass(activeTabClassName); + }); + + // TOC item animation navigate & prevent #item selector in adress bar. + $('.post-toc a').on('click', function (e) { + e.preventDefault(); + var targetSelector = NexT.utils.escapeSelector(this.getAttribute('href')); + var offset = $(targetSelector).offset().top; + + hasVelocity ? + html.velocity('stop').velocity('scroll', { + offset: offset + 'px', + mobileHA: false + }) : + $('html, body').stop().animate({ + scrollTop: offset + }, 500); + }); + + // Expand sidebar on post detail page by default, when post has a toc. + var $tocContent = $('.post-toc-content'); + var isSidebarCouldDisplay = CONFIG.sidebar.display === 'post' || + CONFIG.sidebar.display === 'always'; + var hasTOC = $tocContent.length > 0 && $tocContent.html().trim().length > 0; + if (isSidebarCouldDisplay && hasTOC) { + CONFIG.motion.enable ? + (NexT.motion.middleWares.sidebar = function () { + NexT.utils.displaySidebar(); + }) : NexT.utils.displaySidebar(); + } +}); diff --git a/js/src/schemes/pisces.js b/js/src/schemes/pisces.js index e69de29b..0e6e4267 100644 --- a/js/src/schemes/pisces.js +++ b/js/src/schemes/pisces.js @@ -0,0 +1,57 @@ +$(document).ready(function () { + + var sidebarInner = $('.sidebar-inner'); + + initAffix(); + resizeListener(); + + function initAffix () { + var headerOffset = getHeaderOffset(), + footerOffset = getFooterOffset(), + sidebarHeight = $('#sidebar').height() + NexT.utils.getSidebarb2tHeight(), + contentHeight = $('#content').height(); + + // Not affix if sidebar taller then content (to prevent bottom jumping). + if (headerOffset + sidebarHeight < contentHeight) { + sidebarInner.affix({ + offset: { + top: headerOffset - CONFIG.sidebar.offset, + bottom: footerOffset + } + }); + } + + setSidebarMarginTop(headerOffset).css({ 'margin-left': 'initial' }); + } + + function resizeListener () { + var mql = window.matchMedia('(min-width: 991px)'); + mql.addListener(function(e){ + if(e.matches){ + recalculateAffixPosition(); + } + }); + } + + function getHeaderOffset () { + return $('.header-inner').height() + CONFIG.sidebar.offset; + } + + function getFooterOffset () { + var footerInner = $('.footer-inner'), + footerMargin = footerInner.outerHeight(true) - footerInner.outerHeight(), + footerOffset = footerInner.outerHeight(true) + footerMargin; + return footerOffset; + } + + function setSidebarMarginTop (headerOffset) { + return $('#sidebar').css({ 'margin-top': headerOffset }); + } + + function recalculateAffixPosition () { + $(window).off('.affix'); + sidebarInner.removeData('bs.affix').removeClass('affix affix-top affix-bottom'); + initAffix(); + } + +}); diff --git a/js/src/scroll-cookie.js b/js/src/scroll-cookie.js index e69de29b..34ff200b 100644 --- a/js/src/scroll-cookie.js +++ b/js/src/scroll-cookie.js @@ -0,0 +1,23 @@ +$(document).ready(function() { + + // Set relative link path (without domain) + var rpath = window.location.href.replace(window.location.origin, ""); + + // Write position in cookie + var timeout; + $(window).on("scroll", function() { + clearTimeout(timeout); + timeout = setTimeout(function () { + Cookies.set("scroll-cookie", ($(window).scrollTop() + "|" + rpath), { expires: 365, path: '' }); + }, 250); + }); + + // Read position from cookie + if (Cookies.get("scroll-cookie") !== undefined) { + var cvalues = Cookies.get("scroll-cookie").split('|'); + if (cvalues[1] == rpath) { + $(window).scrollTop(cvalues[0]); + } + } + +}); diff --git a/js/src/scrollspy.js b/js/src/scrollspy.js index e69de29b..f5c5c6cb 100644 --- a/js/src/scrollspy.js +++ b/js/src/scrollspy.js @@ -0,0 +1,182 @@ +/* ======================================================================== +* Bootstrap: scrollspy.js v3.3.2 +* http://getbootstrap.com/javascript/#scrollspy +* ======================================================================== +* Copyright 2011-2015 Twitter, Inc. +* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) +* ======================================================================== */ + +/** + * Custom by iissnan + * + * - Add a `clear.bs.scrollspy` event. + * - Esacpe targets selector. + */ + + ++function ($) { + 'use strict'; + + // SCROLLSPY CLASS DEFINITION + // ========================== + + function ScrollSpy(element, options) { + this.$body = $(document.body) + this.$scrollElement = $(element).is(document.body) ? $(window) : $(element) + this.options = $.extend({}, ScrollSpy.DEFAULTS, options) + this.selector = (this.options.target || '') + ' .nav li > a' + this.offsets = [] + this.targets = [] + this.activeTarget = null + this.scrollHeight = 0 + + this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this)) + this.refresh() + this.process() + } + + ScrollSpy.VERSION = '3.3.2' + + ScrollSpy.DEFAULTS = { + offset: 10 + } + + ScrollSpy.prototype.getScrollHeight = function () { + return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight) + } + + ScrollSpy.prototype.refresh = function () { + var that = this + var offsetMethod = 'offset' + var offsetBase = 0 + + this.offsets = [] + this.targets = [] + this.scrollHeight = this.getScrollHeight() + + if (!$.isWindow(this.$scrollElement[0])) { + offsetMethod = 'position' + offsetBase = this.$scrollElement.scrollTop() + } + + this.$body + .find(this.selector) + .map(function () { + var $el = $(this) + var href = $el.data('target') || $el.attr('href') + var $href = /^#./.test(href) && $(NexT.utils.escapeSelector(href)) // Need to escape selector. + + return ($href + && $href.length + && $href.is(':visible') + && [[$href[offsetMethod]().top + offsetBase, href]]) || null + }) + .sort(function (a, b) { return a[0] - b[0] }) + .each(function () { + that.offsets.push(this[0]) + that.targets.push(this[1]) + }) + + + } + + ScrollSpy.prototype.process = function () { + var scrollTop = this.$scrollElement.scrollTop() + this.options.offset + var scrollHeight = this.getScrollHeight() + var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height() + var offsets = this.offsets + var targets = this.targets + var activeTarget = this.activeTarget + var i + + if (this.scrollHeight != scrollHeight) { + this.refresh() + } + + if (scrollTop >= maxScroll) { + return activeTarget != (i = targets[targets.length - 1]) && this.activate(i) + } + + if (activeTarget && scrollTop < offsets[0]) { + $(this.selector).trigger('clear.bs.scrollspy') // Add a custom event. + this.activeTarget = null + return this.clear() + } + + for (i = offsets.length; i--;) { + activeTarget != targets[i] + && scrollTop >= offsets[i] + && (!offsets[i + 1] || scrollTop <= offsets[i + 1]) + && this.activate(targets[i]) + } + } + + ScrollSpy.prototype.activate = function (target) { + this.activeTarget = target + + this.clear() + + var selector = this.selector + + '[data-target="' + target + '"],' + + this.selector + '[href="' + target + '"]' + + var active = $(selector) + .parents('li') + .addClass('active') + + if (active.parent('.dropdown-menu').length) { + active = active + .closest('li.dropdown') + .addClass('active') + } + + active.trigger('activate.bs.scrollspy') + } + + ScrollSpy.prototype.clear = function () { + $(this.selector) + .parentsUntil(this.options.target, '.active') + .removeClass('active') + } + + + // SCROLLSPY PLUGIN DEFINITION + // =========================== + + function Plugin(option) { + return this.each(function () { + var $this = $(this) + var data = $this.data('bs.scrollspy') + var options = typeof option == 'object' && option + + if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + var old = $.fn.scrollspy + + $.fn.scrollspy = Plugin + $.fn.scrollspy.Constructor = ScrollSpy + + + // SCROLLSPY NO CONFLICT + // ===================== + + $.fn.scrollspy.noConflict = function () { + $.fn.scrollspy = old + return this + } + + + // SCROLLSPY DATA-API + // ================== + + $(window).on('load.bs.scrollspy.data-api', function () { + $('[data-spy="scroll"]').each(function () { + var $spy = $(this) + Plugin.call($spy, $spy.data()) + }) + }) + +}(jQuery); diff --git a/js/src/utils.js b/js/src/utils.js index e69de29b..c1621ef4 100644 --- a/js/src/utils.js +++ b/js/src/utils.js @@ -0,0 +1,339 @@ +/* global NexT: true */ + +NexT.utils = NexT.$u = { + /** + * Wrap images with fancybox support. + */ + wrapImageWithFancyBox: function () { + $('.content img') + .not('[hidden]') + .not('.group-picture img, .post-gallery img') + .each(function () { + var $image = $(this); + var imageTitle = $image.attr('title'); + var $imageWrapLink = $image.parent('a'); + + if ($imageWrapLink.size() < 1) { + var imageLink = ($image.attr('data-original')) ? this.getAttribute('data-original') : this.getAttribute('src'); + $imageWrapLink = $image.wrap('').parent('a'); + } + + $imageWrapLink.addClass('fancybox fancybox.image'); + $imageWrapLink.attr('rel', 'group'); + + if (imageTitle) { + $imageWrapLink.append('

' + imageTitle + '

'); + + //make sure img title tag will show correctly in fancybox + $imageWrapLink.attr('title', imageTitle); + } + }); + + $('.fancybox').fancybox({ + helpers: { + overlay: { + locked: false + } + } + }); + }, + + lazyLoadPostsImages: function () { + $('#posts').find('img').lazyload({ + //placeholder: '/images/loading.gif', + effect: 'fadeIn', + threshold : 0 + }); + }, + + /** + * Tabs tag listener (without twitter bootstrap). + */ + registerTabsTag: function () { + var tNav = '.tabs ul.nav-tabs '; + + // Binding `nav-tabs` & `tab-content` by real time permalink changing. + $(function() { + $(window).bind('hashchange', function() { + var tHash = location.hash; + if (tHash !== '') { + $(tNav + 'li:has(a[href="' + tHash + '"])').addClass('active').siblings().removeClass('active'); + $(tHash).addClass('active').siblings().removeClass('active'); + } + }).trigger('hashchange'); + }); + + $(tNav + '.tab').on('click', function (href) { + href.preventDefault(); + // Prevent selected tab to select again. + if(!$(this).hasClass('active')){ + + // Add & Remove active class on `nav-tabs` & `tab-content`. + $(this).addClass('active').siblings().removeClass('active'); + var tActive = $(this).find('a').attr('href'); + $(tActive).addClass('active').siblings().removeClass('active'); + + // Clear location hash in browser if #permalink exists. + if (location.hash !== '') { + history.pushState('', document.title, window.location.pathname + window.location.search); + } + } + }); + + }, + + registerESCKeyEvent: function () { + $(document).on('keyup', function (event) { + var shouldDismissSearchPopup = event.which === 27 && + $('.search-popup').is(':visible'); + if (shouldDismissSearchPopup) { + $('.search-popup').hide(); + $('.search-popup-overlay').remove(); + $('body').css('overflow', ''); + } + }); + }, + + registerBackToTop: function () { + var THRESHOLD = 50; + var $top = $('.back-to-top'); + + $(window).on('scroll', function () { + $top.toggleClass('back-to-top-on', window.pageYOffset > THRESHOLD); + + var scrollTop = $(window).scrollTop(); + var contentVisibilityHeight = NexT.utils.getContentVisibilityHeight(); + var scrollPercent = (scrollTop) / (contentVisibilityHeight); + var scrollPercentRounded = Math.round(scrollPercent*100); + var scrollPercentMaxed = (scrollPercentRounded > 100) ? 100 : scrollPercentRounded; + $('#scrollpercent>span').html(scrollPercentMaxed); + }); + + $top.on('click', function () { + $('body').velocity('scroll'); + }); + }, + + /** + * Transform embedded video to support responsive layout. + * @see http://toddmotto.com/fluid-and-responsive-youtube-and-vimeo-videos-with-fluidvids-js/ + */ + embeddedVideoTransformer: function () { + var $iframes = $('iframe'); + + // Supported Players. Extend this if you need more players. + var SUPPORTED_PLAYERS = [ + 'www.youtube.com', + 'player.vimeo.com', + 'player.youku.com', + 'music.163.com', + 'www.tudou.com' + ]; + var pattern = new RegExp( SUPPORTED_PLAYERS.join('|') ); + + $iframes.each(function () { + var iframe = this; + var $iframe = $(this); + var oldDimension = getDimension($iframe); + var newDimension; + + if (this.src.search(pattern) > 0) { + + // Calculate the video ratio based on the iframe's w/h dimensions + var videoRatio = getAspectRadio(oldDimension.width, oldDimension.height); + + // Replace the iframe's dimensions and position the iframe absolute + // This is the trick to emulate the video ratio + $iframe.width('100%').height('100%') + .css({ + position: 'absolute', + top: '0', + left: '0' + }); + + + // Wrap the iframe in a new
which uses a dynamically fetched padding-top property + // based on the video's w/h dimensions + var wrap = document.createElement('div'); + wrap.className = 'fluid-vids'; + wrap.style.position = 'relative'; + wrap.style.marginBottom = '20px'; + wrap.style.width = '100%'; + wrap.style.paddingTop = videoRatio + '%'; + // Fix for appear inside tabs tag. + (wrap.style.paddingTop === '') && (wrap.style.paddingTop = '50%'); + + // Add the iframe inside our newly created
+ var iframeParent = iframe.parentNode; + iframeParent.insertBefore(wrap, iframe); + wrap.appendChild(iframe); + + // Additional adjustments for 163 Music + if (this.src.search('music.163.com') > 0) { + newDimension = getDimension($iframe); + var shouldRecalculateAspect = newDimension.width > oldDimension.width || + newDimension.height < oldDimension.height; + + // 163 Music Player has a fixed height, so we need to reset the aspect radio + if (shouldRecalculateAspect) { + wrap.style.paddingTop = getAspectRadio(newDimension.width, oldDimension.height) + '%'; + } + } + } + }); + + function getDimension($element) { + return { + width: $element.width(), + height: $element.height() + }; + } + + function getAspectRadio(width, height) { + return height / width * 100; + } + }, + + /** + * Add `menu-item-active` class name to menu item + * via comparing location.path with menu item's href. + */ + addActiveClassToMenuItem: function () { + var path = window.location.pathname; + path = path === '/' ? path : path.substring(0, path.length - 1); + $('.menu-item a[href^="' + path + '"]:first').parent().addClass('menu-item-active'); + }, + + hasMobileUA: function () { + var nav = window.navigator; + var ua = nav.userAgent; + var pa = /iPad|iPhone|Android|Opera Mini|BlackBerry|webOS|UCWEB|Blazer|PSP|IEMobile|Symbian/g; + + return pa.test(ua); + }, + + isTablet: function () { + return window.screen.width < 992 && window.screen.width > 767 && this.hasMobileUA(); + }, + + isMobile: function () { + return window.screen.width < 767 && this.hasMobileUA(); + }, + + isDesktop: function () { + return !this.isTablet() && !this.isMobile(); + }, + + /** + * Escape meta symbols in jQuery selectors. + * + * @param selector + * @returns {string|void|XML|*} + */ + escapeSelector: function (selector) { + return selector.replace(/[!"$%&'()*+,.\/:;<=>?@[\\\]^`{|}~]/g, '\\$&'); + }, + + displaySidebar: function () { + if (!this.isDesktop() || this.isPisces() || this.isGemini()) { + return; + } + $('.sidebar-toggle').trigger('click'); + }, + + isMist: function () { + return CONFIG.scheme === 'Mist'; + }, + + isPisces: function () { + return CONFIG.scheme === 'Pisces'; + }, + + isGemini: function () { + return CONFIG.scheme === 'Gemini'; + }, + + getScrollbarWidth: function () { + var $div = $('
').addClass('scrollbar-measure').prependTo('body'); + var div = $div[0]; + var scrollbarWidth = div.offsetWidth - div.clientWidth; + + $div.remove(); + + return scrollbarWidth; + }, + + getContentVisibilityHeight: function () { + var docHeight = $('#content').height(), + winHeight = $(window).height(), + contentVisibilityHeight = (docHeight > winHeight) ? (docHeight - winHeight) : ($(document).height() - winHeight); + return contentVisibilityHeight; + }, + + getSidebarb2tHeight: function () { + //var sidebarb2tHeight = (CONFIG.sidebar.b2t) ? document.getElementsByClassName('back-to-top')[0].clientHeight : 0; + var sidebarb2tHeight = (CONFIG.sidebar.b2t) ? $('.back-to-top').height() : 0; + //var sidebarb2tHeight = (CONFIG.sidebar.b2t) ? 24 : 0; + return sidebarb2tHeight; + }, + + getSidebarSchemePadding: function () { + var sidebarNavHeight = ($('.sidebar-nav').css('display') == 'block') ? $('.sidebar-nav').outerHeight(true) : 0, + sidebarInner = $('.sidebar-inner'), + sidebarPadding = sidebarInner.innerWidth() - sidebarInner.width(), + sidebarSchemePadding = this.isPisces() || this.isGemini() ? + ((sidebarPadding * 2) + sidebarNavHeight + (CONFIG.sidebar.offset * 2) + this.getSidebarb2tHeight()) : + ((sidebarPadding * 2) + (sidebarNavHeight / 2)); + return sidebarSchemePadding; + } + + /** + * Affix behaviour for Sidebar. + * + * @returns {Boolean} + */ +// needAffix: function () { +// return this.isPisces() || this.isGemini(); +// } +}; + +$(document).ready(function () { + + initSidebarDimension(); + + /** + * Init Sidebar & TOC inner dimensions on all pages and for all schemes. + * Need for Sidebar/TOC inner scrolling if content taller then viewport. + */ + function initSidebarDimension () { + var updateSidebarHeightTimer; + + $(window).on('resize', function () { + updateSidebarHeightTimer && clearTimeout(updateSidebarHeightTimer); + + updateSidebarHeightTimer = setTimeout(function () { + var sidebarWrapperHeight = document.body.clientHeight - NexT.utils.getSidebarSchemePadding(); + + updateSidebarHeight(sidebarWrapperHeight); + }, 0); + }); + + // Initialize Sidebar & TOC Width. + var scrollbarWidth = NexT.utils.getScrollbarWidth(); + if ($('.site-overview-wrap').height() > (document.body.clientHeight - NexT.utils.getSidebarSchemePadding())) { + $('.site-overview').css('width', 'calc(100% + ' + scrollbarWidth + 'px)'); + } + if ($('.post-toc-wrap').height() > (document.body.clientHeight - NexT.utils.getSidebarSchemePadding())) { + $('.post-toc').css('width', 'calc(100% + ' + scrollbarWidth + 'px)'); + } + + // Initialize Sidebar & TOC Height. + updateSidebarHeight(document.body.clientHeight - NexT.utils.getSidebarSchemePadding()); + } + + function updateSidebarHeight (height) { + height = height || 'auto'; + $('.site-overview, .post-toc').css('max-height', height); + } + +}); diff --git a/lib/Han/dist/font/han-space.otf b/lib/Han/dist/font/han-space.otf index e69de29b..845b1bc2 100644 Binary files a/lib/Han/dist/font/han-space.otf and b/lib/Han/dist/font/han-space.otf differ diff --git a/lib/Han/dist/font/han-space.woff b/lib/Han/dist/font/han-space.woff index e69de29b..6ccc84f8 100644 Binary files a/lib/Han/dist/font/han-space.woff and b/lib/Han/dist/font/han-space.woff differ diff --git a/lib/Han/dist/font/han.otf b/lib/Han/dist/font/han.otf index e69de29b..2ce2f46c 100644 Binary files a/lib/Han/dist/font/han.otf and b/lib/Han/dist/font/han.otf differ diff --git a/lib/Han/dist/font/han.woff b/lib/Han/dist/font/han.woff index e69de29b..011e06c7 100644 Binary files a/lib/Han/dist/font/han.woff and b/lib/Han/dist/font/han.woff differ diff --git a/lib/Han/dist/font/han.woff2 b/lib/Han/dist/font/han.woff2 index e69de29b..02c49afb 100644 Binary files a/lib/Han/dist/font/han.woff2 and b/lib/Han/dist/font/han.woff2 differ diff --git a/lib/Han/dist/han.css b/lib/Han/dist/han.css index e69de29b..9bafab6e 100644 --- a/lib/Han/dist/han.css +++ b/lib/Han/dist/han.css @@ -0,0 +1,1168 @@ +@charset "UTF-8"; + +/*! 漢字標準格式 v3.3.0 | MIT License | css.hanzi.co */ +/*! Han.css: the CSS typography framework optimised for Hanzi */ + +/* normalize.css v4.0.0 | MIT License | github.com/necolas/normalize.css */ +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} +body { + margin: 0; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +main, +menu, +nav, +section, +summary { + /* 1 */ + display: block; +} +audio, +canvas, +progress, +video { + display: inline-block; +} +audio:not([controls]) { + display: none; + height: 0; +} +progress { + vertical-align: baseline; +} +template, +[hidden] { + display: none; +} +a { + background-color: transparent; +} +a:active, +a:hover { + outline-width: 0; +} +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} +b, +strong { + font-weight: inherit; +} +b, +strong { + font-weight: bolder; +} +dfn { + font-style: italic; +} +h1 { + font-size: 2em; + margin: .67em 0; +} +mark { + background-color: #ff0; + color: #000; +} +small { + font-size: 80%; +} +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} +sub { + bottom: -.25em; +} +sup { + top: -.5em; +} +img { + border-style: none; +} +svg:not(:root) { + overflow: hidden; +} +code, +kbd, +pre, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} +figure { + margin: 1em 40px; +} +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} +button, +input, +select, +textarea { + font: inherit; +} +optgroup { + font-weight: bold; +} +button, +input, +select { + /* 2 */ + overflow: visible; +} +button, +input, +select, +textarea { + /* 1 */ + margin: 0; +} +button, +select { + /* 1 */ + text-transform: none; +} +button, +[type="button"], +[type="reset"], +[type="submit"] { + cursor: pointer; +} +[disabled] { + cursor: default; +} +button, +html [type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; /* 2 */ +} +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} +button:-moz-focusring, +input:-moz-focusring { + outline: 1px dotted ButtonText; +} +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: .35em .625em .75em; +} +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} +textarea { + overflow: auto; +} +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} +[type="search"] { + -webkit-appearance: textfield; +} +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} +@font-face { + font-family: "Han Heiti"; + src: local("Hiragino Sans GB"), local("Lantinghei TC Extralight"), local("Lantinghei SC Extralight"), local(FZLTXHB--B51-0), local(FZLTZHK--GBK1-0), local("Pingfang SC Light"), local("Pingfang TC Light"), local("Pingfang-SC-Light"), local("Pingfang-TC-Light"), local("Pingfang SC"), local("Pingfang TC"), local("Heiti SC Light"), local(STHeitiSC-Light), local("Heiti SC"), local("Heiti TC Light"), local(STHeitiTC-Light), local("Heiti TC"), local("Microsoft Yahei"), local("Microsoft Jhenghei"), local("Noto Sans CJK KR"), local("Noto Sans CJK JP"), local("Noto Sans CJK SC"), local("Noto Sans CJK TC"), local("Source Han Sans K"), local("Source Han Sans KR"), local("Source Han Sans JP"), local("Source Han Sans CN"), local("Source Han Sans HK"), local("Source Han Sans TW"), local("Source Han Sans TWHK"), local("Droid Sans Fallback"); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Heiti"; + src: local(YuGothic), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"); +} +@font-face { + font-family: "Han Heiti CNS"; + src: local("Pingfang TC Light"), local("Pingfang-TC-Light"), local("Pingfang TC"), local("Heiti TC Light"), local(STHeitiTC-Light), local("Heiti TC"), local("Lantinghei TC Extralight"), local(FZLTXHB--B51-0), local("Lantinghei TC"), local("Microsoft Jhenghei"), local("Microsoft Yahei"), local("Noto Sans CJK TC"), local("Source Han Sans TC"), local("Source Han Sans TW"), local("Source Han Sans TWHK"), local("Source Han Sans HK"), local("Droid Sans Fallback"); +} +@font-face { + font-family: "Han Heiti GB"; + src: local("Hiragino Sans GB"), local("Pingfang SC Light"), local("Pingfang-SC-Light"), local("Pingfang SC"), local("Lantinghei SC Extralight"), local(FZLTXHK--GBK1-0), local("Lantinghei SC"), local("Heiti SC Light"), local(STHeitiSC-Light), local("Heiti SC"), local("Microsoft Yahei"), local("Noto Sans CJK SC"), local("Source Han Sans SC"), local("Source Han Sans CN"), local("Droid Sans Fallback"); +} +@font-face { + font-family: "Han Heiti"; + font-weight: 600; + src: local("Hiragino Sans GB W6"), local(HiraginoSansGB-W6), local("Lantinghei TC Demibold"), local("Lantinghei SC Demibold"), local(FZLTZHB--B51-0), local(FZLTZHK--GBK1-0), local("Pingfang-SC-Semibold"), local("Pingfang-TC-Semibold"), local("Heiti SC Medium"), local("STHeitiSC-Medium"), local("Heiti SC"), local("Heiti TC Medium"), local("STHeitiTC-Medium"), local("Heiti TC"), local("Microsoft Yahei Bold"), local("Microsoft Jhenghei Bold"), local(MicrosoftYahei-Bold), local(MicrosoftJhengHeiBold), local("Microsoft Yahei"), local("Microsoft Jhenghei"), local("Noto Sans CJK KR Bold"), local("Noto Sans CJK JP Bold"), local("Noto Sans CJK SC Bold"), local("Noto Sans CJK TC Bold"), local(NotoSansCJKkr-Bold), local(NotoSansCJKjp-Bold), local(NotoSansCJKsc-Bold), local(NotoSansCJKtc-Bold), local("Source Han Sans K Bold"), local(SourceHanSansK-Bold), local("Source Han Sans K"), local("Source Han Sans KR Bold"), local("Source Han Sans JP Bold"), local("Source Han Sans CN Bold"), local("Source Han Sans HK Bold"), local("Source Han Sans TW Bold"), local("Source Han Sans TWHK Bold"), local("SourceHanSansKR-Bold"), local("SourceHanSansJP-Bold"), local("SourceHanSansCN-Bold"), local("SourceHanSansHK-Bold"), local("SourceHanSansTW-Bold"), local("SourceHanSansTWHK-Bold"), local("Source Han Sans KR"), local("Source Han Sans CN"), local("Source Han Sans HK"), local("Source Han Sans TW"), local("Source Han Sans TWHK"); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Heiti"; + font-weight: 600; + src: local("YuGothic Bold"), local("Hiragino Kaku Gothic ProN W6"), local("Hiragino Kaku Gothic Pro W6"), local(YuGo-Bold), local(HiraKakuProN-W6), local(HiraKakuPro-W6); +} +@font-face { + font-family: "Han Heiti CNS"; + font-weight: 600; + src: local("Pingfang TC Semibold"), local("Pingfang-TC-Semibold"), local("Heiti TC Medium"), local("STHeitiTC-Medium"), local("Heiti TC"), local("Lantinghei TC Demibold"), local(FZLTXHB--B51-0), local("Microsoft Jhenghei Bold"), local(MicrosoftJhengHeiBold), local("Microsoft Jhenghei"), local("Microsoft Yahei Bold"), local(MicrosoftYahei-Bold), local("Noto Sans CJK TC Bold"), local(NotoSansCJKtc-Bold), local("Noto Sans CJK TC"), local("Source Han Sans TC Bold"), local("SourceHanSansTC-Bold"), local("Source Han Sans TC"), local("Source Han Sans TW Bold"), local("SourceHanSans-TW"), local("Source Han Sans TW"), local("Source Han Sans TWHK Bold"), local("SourceHanSans-TWHK"), local("Source Han Sans TWHK"), local("Source Han Sans HK"), local("SourceHanSans-HK"), local("Source Han Sans HK"); +} +@font-face { + font-family: "Han Heiti GB"; + font-weight: 600; + src: local("Hiragino Sans GB W6"), local(HiraginoSansGB-W6), local("Pingfang SC Semibold"), local("Pingfang-SC-Semibold"), local("Lantinghei SC Demibold"), local(FZLTZHK--GBK1-0), local("Heiti SC Medium"), local("STHeitiSC-Medium"), local("Heiti SC"), local("Microsoft Yahei Bold"), local(MicrosoftYahei-Bold), local("Microsoft Yahei"), local("Noto Sans CJK SC Bold"), local(NotoSansCJKsc-Bold), local("Noto Sans CJK SC"), local("Source Han Sans SC Bold"), local("SourceHanSansSC-Bold"), local("Source Han Sans CN Bold"), local("SourceHanSansCN-Bold"), local("Source Han Sans SC"), local("Source Han Sans CN"); +} +@font-face { + font-family: "Han Songti"; + src: local("Songti SC Regular"), local(STSongti-SC-Regular), local("Songti SC"), local("Songti TC Regular"), local(STSongti-TC-Regular), local("Songti TC"), local(STSong), local("Lisong Pro"), local(SimSun), local(PMingLiU); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Songti"; + src: local(YuMincho), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("MS Mincho"); +} +@font-face { + font-family: "Han Songti CNS"; + src: local("Songti TC Regular"), local(STSongti-TC-Regular), local("Songti TC"), local("Lisong Pro"), local("Songti SC Regular"), local(STSongti-SC-Regular), local("Songti SC"), local(STSong), local(PMingLiU), local(SimSun); +} +@font-face { + font-family: "Han Songti GB"; + src: local("Songti SC Regular"), local(STSongti-SC-Regular), local("Songti SC"), local(STSong), local(SimSun), local(PMingLiU); +} +@font-face { + font-family: "Han Songti"; + font-weight: 600; + src: local("STSongti SC Bold"), local("STSongti TC Bold"), local(STSongti-SC-Bold), local(STSongti-TC-Bold), local("STSongti SC"), local("STSongti TC"); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Songti"; + font-weight: 600; + src: local("YuMincho Demibold"), local("Hiragino Mincho ProN W6"), local("Hiragino Mincho Pro W6"), local(YuMin-Demibold), local(HiraMinProN-W6), local(HiraMinPro-W6), local(YuMincho), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"); +} +@font-face { + font-family: "Han Songti CNS"; + font-weight: 600; + src: local("STSongti TC Bold"), local("STSongti SC Bold"), local(STSongti-TC-Bold), local(STSongti-SC-Bold), local("STSongti TC"), local("STSongti SC"); +} +@font-face { + font-family: "Han Songti GB"; + font-weight: 600; + src: local("STSongti SC Bold"), local(STSongti-SC-Bold), local("STSongti SC"); +} +@font-face { + font-family: cursive; + src: local("Kaiti TC Regular"), local(STKaiTi-TC-Regular), local("Kaiti TC"), local("Kaiti SC"), local(STKaiti), local(BiauKai), local("標楷體"), local(DFKaiShu-SB-Estd-BF), local(Kaiti), local(DFKai-SB); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Kaiti"; + src: local("Kaiti TC Regular"), local(STKaiTi-TC-Regular), local("Kaiti TC"), local("Kaiti SC"), local(STKaiti), local(BiauKai), local("標楷體"), local(DFKaiShu-SB-Estd-BF), local(Kaiti), local(DFKai-SB); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Kaiti CNS"; + src: local(BiauKai), local("標楷體"), local(DFKaiShu-SB-Estd-BF), local("Kaiti TC Regular"), local(STKaiTi-TC-Regular), local("Kaiti TC"); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Kaiti GB"; + src: local("Kaiti SC Regular"), local(STKaiTi-SC-Regular), local("Kaiti SC"), local(STKaiti), local(Kai), local(Kaiti), local(DFKai-SB); +} +@font-face { + font-family: cursive; + font-weight: 600; + src: local("Kaiti TC Bold"), local(STKaiTi-TC-Bold), local("Kaiti SC Bold"), local(STKaiti-SC-Bold), local("Kaiti TC"), local("Kaiti SC"); +} +@font-face { + font-family: "Han Kaiti"; + font-weight: 600; + src: local("Kaiti TC Bold"), local(STKaiTi-TC-Bold), local("Kaiti SC Bold"), local(STKaiti-SC-Bold), local("Kaiti TC"), local("Kaiti SC"); +} +@font-face { + font-family: "Han Kaiti CNS"; + font-weight: 600; + src: local("Kaiti TC Bold"), local(STKaiTi-TC-Bold), local("Kaiti TC"); +} +@font-face { + font-family: "Han Kaiti GB"; + font-weight: 600; + src: local("Kaiti SC Bold"), local(STKaiti-SC-Bold); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Fangsong"; + src: local(STFangsong), local(FangSong); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Fangsong CNS"; + src: local(STFangsong), local(FangSong); +} +@font-face { + unicode-range: U+4E00-9FFF, U+3400-4DB5, U+20000-2A6D6, U+2A700-2B734, U+2B740-2B81D, U+FA0E-FA0F, U+FA11, U+FA13-FA14, U+FA1F, U+FA21, U+FA23, U+FA24, U+FA27-FA29, U+3040-309F, U+30A0-30FF, U+3099-309E, U+FF66-FF9F, U+3007, U+31C0-31E3, U+2F00-2FD5, U+2E80-2EF3; + font-family: "Han Fangsong GB"; + src: local(STFangsong), local(FangSong); +} +@font-face { + font-family: "Biaodian Sans"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local("MS Gothic"), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Serif"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local("MS Gothic"), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local("MS Gothic"), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local("MS Gothic"), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local(SimSun); + unicode-range: U+FF0E; +} +@font-face { + font-family: "Biaodian Sans"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Serif"; + src: local("Songti SC"), local(STSong), local("Heiti SC"), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: local("Songti SC"), local(STSong), local("Heiti SC"), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local("Songti SC"), local(STSong), local("Heiti SC"), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Songti SC"), local(STSong), local("Heiti SC"), local(SimSun); + unicode-range: U+00B7; +} +@font-face { + font-family: "Biaodian Sans"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Serif"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Yakumono Sans"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Arial Unicode MS"), local("MS Gothic"); + unicode-range: U+2014; +} +@font-face { + font-family: "Yakumono Serif"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("MS Mincho"), local("Microsoft Yahei"); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSong), local("Microsoft Yahei"), local(SimSun); + unicode-range: U+2014; +} +@font-face { + font-family: "Biaodian Sans"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(Meiryo), local("MS Gothic"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Serif"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local("MS Mincho"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Yakumono Sans"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(Meiryo), local("MS Gothic"); + unicode-range: U+2026; +} +@font-face { + font-family: "Yakumono Serif"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("MS Mincho"); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSongti), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Sans GB"), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Songti SC"), local(STSongti), local(SimSun), local(PMingLiU); + unicode-range: U+2026; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun), local(PMingLiU); + unicode-range: U+201C-201D, U+2018-2019; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + font-weight: bold; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun), local(PMingLiU); + unicode-range: U+201C-201D, U+2018-2019; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Lisong Pro"), local("Heiti SC"), local(STHeiti), local(SimSun), local(PMingLiU); + unicode-range: U+201C-201D, U+2018-2019; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + font-weight: bold; + src: local("Lisong Pro"), local("Heiti SC"), local(STHeiti), local(SimSun), local(PMingLiU); + unicode-range: U+201C-201D, U+2018-2019; +} +@font-face { + font-family: "Biaodian Sans"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Serif"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local(Georgia), local("Times New Roman"), local(Arial), local("Droid Sans Fallback"); + unicode-range: U+25CF; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("MS Gothic"); + unicode-range: U+3002, U+FF0C, U+3001, U+FF1B, U+FF1A, U+FF1F, U+FF01, U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("MS Mincho"); + unicode-range: U+3002, U+FF0C, U+3001, U+FF1B, U+FF1A, U+FF1F, U+FF01, U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Heiti TC"), local("Lihei Pro"), local("Microsoft Jhenghei"), local(PMingLiU); + unicode-range: U+3002, U+FF0C, U+3001; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Heiti TC"), local("Lihei Pro"), local("Microsoft Jhenghei"), local(PMingLiU), local("MS Gothic"); + unicode-range: U+FF1B, U+FF1A, U+FF1F, U+FF01; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("MS Mincho"); + unicode-range: U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local(STSongti-TC-Regular), local("Lisong Pro"), local("Heiti TC"), local(PMingLiU); + unicode-range: U+3002, U+FF0C, U+3001; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local(PMingLiU), local("MS Mincho"); + unicode-range: U+FF1B, U+FF1A, U+FF1F, U+FF01, U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local(SimSun), local("MS Gothic"); + unicode-range: U+3002, U+FF0C, U+3001, U+FF1B, U+FF1A, U+FF1F, U+FF01, U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Songti SC"), local(STSongti), local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Hiragino Sans GB"), local("Heiti SC"), local(STHeiti), local(SimSun), local("MS Mincho"); + unicode-range: U+3002, U+FF0C, U+3001, U+FF1B, U+FF1A, U+FF1F, U+FF01; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local(PMingLiU), local("MS Mincho"); + unicode-range: U+FF0D, U+FF0F, U+FF3C; +} +@font-face { + font-family: "Biaodian Pro Sans"; + src: local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Yu Gothic"), local(YuGothic), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Pro Serif"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Yu Mincho"), local(YuMincho), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + src: local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Yu Gothic"), local(YuGothic), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Yu Mincho"), local(YuMincho), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + src: local("Hiragino Kaku Gothic ProN"), local("Hiragino Kaku Gothic Pro"), local("Yu Gothic"), local(YuGothic), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + src: local("Hiragino Mincho ProN"), local("Hiragino Mincho Pro"), local("Yu Mincho"), local(YuMincho), local(SimSun), local(PMingLiU); + unicode-range: U+300C-300F, U+300A-300B, U+3008-3009, U+FF08-FF09, U+3014-3015; +} +@font-face { + font-family: "Biaodian Basic"; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Basic"; + font-weight: bold; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Sans"; + font-weight: bold; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans"; + font-weight: bold; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans"; + font-weight: bold; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans CNS"; + font-weight: bold; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Sans GB"; + font-weight: bold; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif"; + font-weight: bold; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif CNS"; + font-weight: bold; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Biaodian Pro Serif GB"; + font-weight: bold; + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+2014, U+2026, U+00B7; +} +@font-face { + font-family: "Latin Italic Serif"; + src: local("Georgia Italic"), local("Times New Roman Italic"), local(Georgia-Italic), local(TimesNewRomanPS-ItalicMT), local(Times-Italic); +} +@font-face { + font-family: "Latin Italic Serif"; + font-weight: 700; + src: local("Georgia Bold Italic"), local("Times New Roman Bold Italic"), local(Georgia-BoldItalic), local(TimesNewRomanPS-BoldItalicMT), local(Times-Italic); +} +@font-face { + font-family: "Latin Italic Sans"; + src: local("Helvetica Neue Italic"), local("Helvetica Oblique"), local("Arial Italic"), local(HelveticaNeue-Italic), local(Helvetica-LightOblique), local(Arial-ItalicMT); +} +@font-face { + font-family: "Latin Italic Sans"; + font-weight: 700; + src: local("Helvetica Neue Bold Italic"), local("Helvetica Bold Oblique"), local("Arial Bold Italic"), local(HelveticaNeue-BoldItalic), local(Helvetica-BoldOblique), local(Arial-BoldItalicMT); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral TF Sans"; + src: local(Skia), local("Neutraface 2 Text"), local(Candara), local(Corbel); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral TF Serif"; + src: local(Georgia), local("Hoefler Text"), local("Big Caslon"); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral TF Italic Serif"; + src: local("Georgia Italic"), local("Hoefler Text Italic"), local(Georgia-Italic), local(HoeflerText-Italic); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Sans"; + src: local("Helvetica Neue"), local(Helvetica), local(Arial); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Italic Sans"; + src: local("Helvetica Neue Italic"), local("Helvetica Oblique"), local("Arial Italic"), local(HelveticaNeue-Italic), local(Helvetica-LightOblique), local(Arial-ItalicMT); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Italic Sans"; + font-weight: bold; + src: local("Helvetica Neue Bold Italic"), local("Helvetica Bold Oblique"), local("Arial Bold Italic"), local(HelveticaNeue-BoldItalic), local(Helvetica-BoldOblique), local(Arial-BoldItalicMT); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Serif"; + src: local(Palatino), local("Palatino Linotype"), local("Times New Roman"); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Italic Serif"; + src: local("Palatino Italic"), local("Palatino Italic Linotype"), local("Times New Roman Italic"), local(Palatino-Italic), local(Palatino-Italic-Linotype), local(TimesNewRomanPS-ItalicMT); +} +@font-face { + unicode-range: U+0030-0039; + font-family: "Numeral LF Italic Serif"; + font-weight: bold; + src: local("Palatino Bold Italic"), local("Palatino Bold Italic Linotype"), local("Times New Roman Bold Italic"), local(Palatino-BoldItalic), local(Palatino-BoldItalic-Linotype), local(TimesNewRomanPS-BoldItalicMT); +} +@font-face { + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+3105-312D, U+31A0-31BA, U+02D9, U+02CA, U+02C5, U+02C7, U+02CB, U+02EA-02EB, U+0307, U+030D, U+0358, U+F31B4-F31B7, U+F0061, U+F0065, U+F0069, U+F006F, U+F0075; + font-family: "Zhuyin Kaiti"; +} +@font-face { + unicode-range: U+3105-312D, U+31A0-31BA, U+02D9, U+02CA, U+02C5, U+02C7, U+02CB, U+02EA-02EB, U+0307, U+030D, U+0358, U+F31B4-F31B7, U+F0061, U+F0065, U+F0069, U+F006F, U+F0075; + font-family: "Zhuyin Heiti"; + src: local("Hiragino Sans GB"), local("Heiti TC"), local("Microsoft Jhenghei"), url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); +} +@font-face { + font-family: "Zhuyin Heiti"; + src: local("Heiti TC"), local("Microsoft Jhenghei"), url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + unicode-range: U+3127; +} +@font-face { + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + font-family: "Zhuyin Heiti"; + unicode-range: U+02D9, U+02CA, U+02C5, U+02C7, U+02CB, U+02EA-02EB, U+31B4, U+31B5, U+31B6, U+31B7, U+0307, U+030D, U+0358, U+F31B4-F31B7, U+F0061, U+F0065, U+F0069, U+F006F, U+F0075; +} +@font-face { + src: url("./font/han.woff2?v3.3.0") format("woff2"), url("./font/han.woff?v3.3.0") format("woff"), url("./font/han.otf?v3.3.0") format("opentype"); + font-family: "Romanization Sans"; + unicode-range: U+0307, U+030D, U+0358, U+F31B4-F31B7, U+F0061, U+F0065, U+F0069, U+F006F, U+F0075; +} +html:lang(zh-Latn), +html:lang(ja-Latn), +html:not(:lang(zh)):not(:lang(ja)), +html *:lang(zh-Latn), +html *:lang(ja-Latn), +html *:not(:lang(zh)):not(:lang(ja)), +article strong:lang(zh-Latn), +article strong:lang(ja-Latn), +article strong:not(:lang(zh)):not(:lang(ja)), +article strong *:lang(zh-Latn), +article strong *:lang(ja-Latn), +article strong *:not(:lang(zh)):not(:lang(ja)) { + font-family: "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} +html:lang(zh), +html:lang(zh-Hant), +[lang^="zh"], +[lang*="Hant"], +[lang="zh-TW"], +[lang="zh-HK"], +article strong:lang(zh), +article strong:lang(zh-Hant) { + font-family: "Biaodian Pro Sans CNS", "Helvetica Neue", Helvetica, Arial, "Zhuyin Heiti", "Han Heiti", sans-serif; +} +html:lang(zh).no-unicoderange, +html:lang(zh-Hant).no-unicoderange, +.no-unicoderange [lang^="zh"], +.no-unicoderange [lang*="Hant"], +.no-unicoderange [lang="zh-TW"], +.no-unicoderange [lang="zh-HK"], +.no-unicoderange article strong:lang(zh), +.no-unicoderange article strong:lang(zh-Hant) { + font-family: "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} +html:lang(zh-Hans), +html:lang(zh-CN), +[lang*="Hans"], +[lang="zh-CN"], +article strong:lang(zh-Hans), +article strong:lang(zh-CN) { + font-family: "Biaodian Pro Sans GB", "Helvetica Neue", Helvetica, Arial, "Han Heiti GB", sans-serif; +} +html:lang(zh-Hans).no-unicoderange, +html:lang(zh-CN).no-unicoderange, +.no-unicoderange [lang*="Hans"], +.no-unicoderange [lang="zh-CN"], +.no-unicoderange article strong:lang(zh-Hans), +.no-unicoderange article strong:lang(zh-CN) { + font-family: "Helvetica Neue", Helvetica, Arial, "Han Heiti GB", sans-serif; +} +html:lang(ja), +[lang^="ja"], +article strong:lang(ja) { + font-family: "Yakumono Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; +} +html:lang(ja).no-unicoderange, +.no-unicoderange [lang^="ja"], +.no-unicoderange article strong:lang(ja) { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +article blockquote i:lang(zh-Latn), +article blockquote var:lang(zh-Latn), +article blockquote i:lang(ja-Latn), +article blockquote var:lang(ja-Latn), +article blockquote i:not(:lang(zh)):not(:lang(ja)), +article blockquote var:not(:lang(zh)):not(:lang(ja)), +article blockquote i *:lang(zh-Latn), +article blockquote var *:lang(zh-Latn), +article blockquote i *:lang(ja-Latn), +article blockquote var *:lang(ja-Latn), +article blockquote i *:not(:lang(zh)):not(:lang(ja)), +article blockquote var *:not(:lang(zh)):not(:lang(ja)) { + font-family: "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} +article blockquote i:lang(zh), +article blockquote var:lang(zh), +article blockquote i:lang(zh-Hant), +article blockquote var:lang(zh-Hant) { + font-family: "Biaodian Pro Sans CNS", "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Zhuyin Heiti", "Han Heiti", sans-serif; +} +.no-unicoderange article blockquote i:lang(zh), +.no-unicoderange article blockquote var:lang(zh), +.no-unicoderange article blockquote i:lang(zh-Hant), +.no-unicoderange article blockquote var:lang(zh-Hant) { + font-family: "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} +.no-unicoderange article blockquote i:lang(zh), +.no-unicoderange article blockquote var:lang(zh), +.no-unicoderange article blockquote i:lang(zh-Hant), +.no-unicoderange article blockquote var:lang(zh-Hant) { + font-family: "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} +article blockquote i:lang(zh-Hans), +article blockquote var:lang(zh-Hans), +article blockquote i:lang(zh-CN), +article blockquote var:lang(zh-CN) { + font-family: "Biaodian Pro Sans GB", "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti GB", sans-serif; +} +.no-unicoderange article blockquote i:lang(zh-Hans), +.no-unicoderange article blockquote var:lang(zh-Hans), +.no-unicoderange article blockquote i:lang(zh-CN), +.no-unicoderange article blockquote var:lang(zh-CN) { + font-family: "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti GB", sans-serif; +} +article blockquote i:lang(ja), +article blockquote var:lang(ja) { + font-family: "Yakumono Sans", "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; +} +.no-unicoderange article blockquote i:lang(ja), +.no-unicoderange article blockquote var:lang(ja) { + font-family: "Latin Italic Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; +} +article figure blockquote:lang(zh-Latn), +article figure blockquote:lang(ja-Latn), +article figure blockquote:not(:lang(zh)):not(:lang(ja)), +article figure blockquote *:lang(zh-Latn), +article figure blockquote *:lang(ja-Latn), +article figure blockquote *:not(:lang(zh)):not(:lang(ja)) { + font-family: Georgia, "Times New Roman", "Han Songti", cursive, serif; +} +article figure blockquote:lang(zh), +article figure blockquote:lang(zh-Hant) { + font-family: "Biaodian Pro Serif CNS", "Numeral LF Serif", Georgia, "Times New Roman", "Zhuyin Kaiti", "Han Songti", serif; +} +.no-unicoderange article figure blockquote:lang(zh), +.no-unicoderange article figure blockquote:lang(zh-Hant) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", "Han Songti", serif; +} +article figure blockquote:lang(zh-Hans), +article figure blockquote:lang(zh-CN) { + font-family: "Biaodian Pro Serif GB", "Numeral LF Serif", Georgia, "Times New Roman", "Han Songti GB", serif; +} +.no-unicoderange article figure blockquote:lang(zh-Hans), +.no-unicoderange article figure blockquote:lang(zh-CN) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", "Han Songti GB", serif; +} +article figure blockquote:lang(ja) { + font-family: "Yakumono Serif", "Numeral LF Serif", Georgia, "Times New Roman", serif; +} +.no-unicoderange article figure blockquote:lang(ja) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", serif; +} +article blockquote:lang(zh-Latn), +article blockquote:lang(ja-Latn), +article blockquote:not(:lang(zh)):not(:lang(ja)), +article blockquote *:lang(zh-Latn), +article blockquote *:lang(ja-Latn), +article blockquote *:not(:lang(zh)):not(:lang(ja)) { + font-family: Georgia, "Times New Roman", "Han Kaiti", cursive, serif; +} +article blockquote:lang(zh), +article blockquote:lang(zh-Hant) { + font-family: "Biaodian Pro Serif CNS", "Numeral LF Serif", Georgia, "Times New Roman", "Zhuyin Kaiti", "Han Kaiti", cursive, serif; +} +.no-unicoderange article blockquote:lang(zh), +.no-unicoderange article blockquote:lang(zh-Hant) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", "Han Kaiti", cursive, serif; +} +article blockquote:lang(zh-Hans), +article blockquote:lang(zh-CN) { + font-family: "Biaodian Pro Serif GB", "Numeral LF Serif", Georgia, "Times New Roman", "Han Kaiti GB", cursive, serif; +} +.no-unicoderange article blockquote:lang(zh-Hans), +.no-unicoderange article blockquote:lang(zh-CN) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", "Han Kaiti GB", cursive, serif; +} +article blockquote:lang(ja) { + font-family: "Yakumono Serif", "Numeral LF Serif", Georgia, "Times New Roman", cursive, serif; +} +.no-unicoderange article blockquote:lang(ja) { + font-family: "Numeral LF Serif", Georgia, "Times New Roman", cursive, serif; +} +i:lang(zh-Latn), +var:lang(zh-Latn), +i:lang(ja-Latn), +var:lang(ja-Latn), +i:not(:lang(zh)):not(:lang(ja)), +var:not(:lang(zh)):not(:lang(ja)), +i *:lang(zh-Latn), +var *:lang(zh-Latn), +i *:lang(ja-Latn), +var *:lang(ja-Latn), +i *:not(:lang(zh)):not(:lang(ja)), +var *:not(:lang(zh)):not(:lang(ja)) { + font-family: "Latin Italic Serif", Georgia, "Times New Roman", "Han Kaiti", cursive, serif; +} +i:lang(zh), +var:lang(zh), +i:lang(zh-Hant), +var:lang(zh-Hant) { + font-family: "Biaodian Pro Serif CNS", "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", "Zhuyin Kaiti", "Han Kaiti", cursive, serif; +} +.no-unicoderange i:lang(zh), +.no-unicoderange var:lang(zh), +.no-unicoderange i:lang(zh-Hant), +.no-unicoderange var:lang(zh-Hant) { + font-family: "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", "Han Kaiti", cursive, serif; +} +i:lang(zh-Hans), +var:lang(zh-Hans), +i:lang(zh-CN), +var:lang(zh-CN) { + font-family: "Biaodian Pro Serif GB", "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", "Han Kaiti GB", cursive, serif; +} +.no-unicoderange i:lang(zh-Hans), +.no-unicoderange var:lang(zh-Hans), +.no-unicoderange i:lang(zh-CN), +.no-unicoderange var:lang(zh-CN) { + font-family: "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", "Han Kaiti GB", cursive, serif; +} +i:lang(ja), +var:lang(ja) { + font-family: "Yakumono Serif", "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", cursive, serif; +} +.no-unicoderange i:lang(ja), +.no-unicoderange var:lang(ja) { + font-family: "Numeral LF Italic Serif", "Latin Italic Serif", Georgia, "Times New Roman", cursive, serif; +} +code:lang(zh-Latn), +kbd:lang(zh-Latn), +samp:lang(zh-Latn), +pre:lang(zh-Latn), +code:lang(ja-Latn), +kbd:lang(ja-Latn), +samp:lang(ja-Latn), +pre:lang(ja-Latn), +code:not(:lang(zh)):not(:lang(ja)), +kbd:not(:lang(zh)):not(:lang(ja)), +samp:not(:lang(zh)):not(:lang(ja)), +pre:not(:lang(zh)):not(:lang(ja)), +code *:lang(zh-Latn), +kbd *:lang(zh-Latn), +samp *:lang(zh-Latn), +pre *:lang(zh-Latn), +code *:lang(ja-Latn), +kbd *:lang(ja-Latn), +samp *:lang(ja-Latn), +pre *:lang(ja-Latn), +code *:not(:lang(zh)):not(:lang(ja)), +kbd *:not(:lang(zh)):not(:lang(ja)), +samp *:not(:lang(zh)):not(:lang(ja)), +pre *:not(:lang(zh)):not(:lang(ja)) { + font-family: Menlo, Consolas, Courier, "Han Heiti", monospace, monospace, sans-serif; +} +code:lang(zh), +kbd:lang(zh), +samp:lang(zh), +pre:lang(zh), +code:lang(zh-Hant), +kbd:lang(zh-Hant), +samp:lang(zh-Hant), +pre:lang(zh-Hant) { + font-family: "Biaodian Pro Sans CNS", Menlo, Consolas, Courier, "Zhuyin Heiti", "Han Heiti", monospace, monospace, sans-serif; +} +.no-unicoderange code:lang(zh), +.no-unicoderange kbd:lang(zh), +.no-unicoderange samp:lang(zh), +.no-unicoderange pre:lang(zh), +.no-unicoderange code:lang(zh-Hant), +.no-unicoderange kbd:lang(zh-Hant), +.no-unicoderange samp:lang(zh-Hant), +.no-unicoderange pre:lang(zh-Hant) { + font-family: Menlo, Consolas, Courier, "Han Heiti", monospace, monospace, sans-serif; +} +code:lang(zh-Hans), +kbd:lang(zh-Hans), +samp:lang(zh-Hans), +pre:lang(zh-Hans), +code:lang(zh-CN), +kbd:lang(zh-CN), +samp:lang(zh-CN), +pre:lang(zh-CN) { + font-family: "Biaodian Pro Sans GB", Menlo, Consolas, Courier, "Han Heiti GB", monospace, monospace, sans-serif; +} +.no-unicoderange code:lang(zh-Hans), +.no-unicoderange kbd:lang(zh-Hans), +.no-unicoderange samp:lang(zh-Hans), +.no-unicoderange pre:lang(zh-Hans), +.no-unicoderange code:lang(zh-CN), +.no-unicoderange kbd:lang(zh-CN), +.no-unicoderange samp:lang(zh-CN), +.no-unicoderange pre:lang(zh-CN) { + font-family: Menlo, Consolas, Courier, "Han Heiti GB", monospace, monospace, sans-serif; +} +code:lang(ja), +kbd:lang(ja), +samp:lang(ja), +pre:lang(ja) { + font-family: "Yakumono Sans", Menlo, Consolas, Courier, monospace, monospace, sans-serif; +} +.no-unicoderange code:lang(ja), +.no-unicoderange kbd:lang(ja), +.no-unicoderange samp:lang(ja), +.no-unicoderange pre:lang(ja) { + font-family: Menlo, Consolas, Courier, monospace, monospace, sans-serif; +} +html, +.no-unicoderange h-char.bd-liga, +.no-unicoderange h-char[unicode="b7"], +ruby h-zhuyin, +h-ruby h-zhuyin, +ruby h-zhuyin h-diao, +h-ruby h-zhuyin h-diao, +ruby.romanization rt, +h-ruby.romanization rt, +ruby [annotation] rt, +h-ruby [annotation] rt { + -moz-font-feature-settings: "liga"; + -ms-font-feature-settings: "liga"; + -webkit-font-feature-settings: "liga"; + font-feature-settings: "liga"; +} +html, +[lang^="zh"], +[lang*="Hant"], +[lang="zh-TW"], +[lang="zh-HK"], +[lang*="Hans"], +[lang="zh-CN"], +article strong, +code, +kbd, +samp, +pre, +article blockquote i, +article blockquote var { + -moz-font-feature-settings: "liga=1, locl=0"; + -ms-font-feature-settings: "liga", "locl" 0; + -webkit-font-feature-settings: "liga", "locl" 0; + font-feature-settings: "liga", "locl" 0; +} +.no-unicoderange h-char.bd-cop:lang(zh-Hant), +.no-unicoderange h-char.bd-cop:lang(zh-TW), +.no-unicoderange h-char.bd-cop:lang(zh-HK) { + font-family: -apple-system, "Han Heiti CNS"; +} +.no-unicoderange h-char.bd-liga, +.no-unicoderange h-char[unicode="b7"] { + font-family: "Biaodian Basic", "Han Heiti"; +} +.no-unicoderange h-char[unicode="2018"]:lang(zh-Hans), +.no-unicoderange h-char[unicode="2019"]:lang(zh-Hans), +.no-unicoderange h-char[unicode="201c"]:lang(zh-Hans), +.no-unicoderange h-char[unicode="201d"]:lang(zh-Hans), +.no-unicoderange h-char[unicode="2018"]:lang(zh-CN), +.no-unicoderange h-char[unicode="2019"]:lang(zh-CN), +.no-unicoderange h-char[unicode="201c"]:lang(zh-CN), +.no-unicoderange h-char[unicode="201d"]:lang(zh-CN) { + font-family: "Han Heiti GB"; +} +i, +var { + font-style: inherit; +} +.no-unicoderange ruby h-zhuyin, +.no-unicoderange h-ruby h-zhuyin, +.no-unicoderange ruby h-zhuyin h-diao, +.no-unicoderange h-ruby h-zhuyin h-diao { + font-family: "Zhuyin Kaiti", cursive, serif; +} +ruby h-diao, +h-ruby h-diao { + font-family: "Zhuyin Kaiti", cursive, serif; +} +ruby.romanization rt, +h-ruby.romanization rt, +ruby [annotation] rt, +h-ruby [annotation] rt { + font-family: "Romanization Sans", "Helvetica Neue", Helvetica, Arial, "Han Heiti", sans-serif; +} diff --git a/lib/Han/dist/han.js b/lib/Han/dist/han.js index e69de29b..75976c6d 100644 --- a/lib/Han/dist/han.js +++ b/lib/Han/dist/han.js @@ -0,0 +1,3005 @@ +/*! + * 漢字標準格式 v3.3.0 | MIT License | css.hanzi.co + * Han.css: the CSS typography framework optimised for Hanzi + */ + +void function( global, factory ) { + + // CommonJS + if ( typeof module === 'object' && typeof module.exports === 'object' ) { + module.exports = factory( global, true ) + // AMD + } else if ( typeof define === 'function' && define.amd ) { + define(function() { return factory( global, true ) }) + // Global namespace + } else { + factory( global ) + } + +}( typeof window !== 'undefined' ? window : this, function( window, noGlobalNS ) { + +'use strict' + +var document = window.document + +var root = document.documentElement + +var body = document.body + +var VERSION = '3.3.0' + +var ROUTINE = [ + // Initialise the condition with feature-detecting + // classes (Modernizr-alike), binding onto the root + // element, possibly ``. + 'initCond', + + // Address element normalisation + 'renderElem', + + // Handle Biaodian + /* 'jinzify', */ + 'renderJiya', + 'renderHanging', + + // Address Biaodian correction + 'correctBiaodian', + + // Address Hanzi and Western script mixed spacing + 'renderHWS', + + // Address presentational correction to combining ligatures + 'substCombLigaWithPUA' + + // Address semantic correction to inaccurate characters + // **Note:** inactivated by default + /* 'substInaccurateChar', */ +] + +// Define Han +var Han = function( context, condition ) { + return new Han.fn.init( context, condition ) +} + +var init = function() { + if ( arguments[ 0 ] ) { + this.context = arguments[ 0 ] + } + if ( arguments[ 1 ] ) { + this.condition = arguments[ 1 ] + } + return this +} + +Han.version = VERSION + +Han.fn = Han.prototype = { + version: VERSION, + + constructor: Han, + + // Body as the default target context + context: body, + + // Root element as the default condition + condition: root, + + // Default rendering routine + routine: ROUTINE, + + init: init, + + setRoutine: function( routine ) { + if ( Array.isArray( routine )) { + this.routine = routine + } + return this + }, + + // Note that the routine set up here will execute + // only once. The method won't alter the routine in + // the instance or in the prototype chain. + render: function( routine ) { + var it = this + var routine = Array.isArray( routine ) + ? routine + : this.routine + + routine + .forEach(function( method ) { + if ( + typeof method === 'string' && + typeof it[ method ] === 'function' + ) { + it[ method ]() + } else if ( + Array.isArray( method ) && + typeof it[ method[0] ] === 'function' + ) { + it[ method.shift() ].apply( it, method ) + } + }) + return this + } +} + +Han.fn.init.prototype = Han.fn + +/** + * Shortcut for `render()` under the default + * situation. + * + * Once initialised, replace `Han.init` with the + * instance for future usage. + */ +Han.init = function() { + return Han.init = Han().render() +} + +var UNICODE = { + /** + * Western punctuation (西文標點符號) + */ + punct: { + base: '[\u2026,.;:!?\u203D_]', + sing: '[\u2010-\u2014\u2026]', + middle: '[\\\/~\\-&\u2010-\u2014_]', + open: '[\'"‘“\\(\\[\u00A1\u00BF\u2E18\u00AB\u2039\u201A\u201C\u201E]', + close: '[\'"”’\\)\\]\u00BB\u203A\u201B\u201D\u201F]', + end: '[\'"”’\\)\\]\u00BB\u203A\u201B\u201D\u201F\u203C\u203D\u2047-\u2049,.;:!?]', + }, + + /** + * CJK biaodian (CJK標點符號) + */ + biaodian: { + base: '[︰.、,。:;?!ー]', + liga: '[—…⋯]', + middle: '[·\/-゠\uFF06\u30FB\uFF3F]', + open: '[「『《〈(〔[{【〖]', + close: '[」』》〉)〕]}】〗]', + end: '[」』》〉)〕]}】〗︰.、,。:;?!ー]' + }, + + /** + * CJK-related blocks (CJK相關字符區段) + * + * 1. 中日韓統一意音文字:[\u4E00-\u9FFF] + Basic CJK unified ideographs + * 2. 擴展-A區:[\u3400-\u4DB5] + Extended-A + * 3. 擴展-B區:[\u20000-\u2A6D6]([\uD840-\uD869][\uDC00-\uDED6]) + Extended-B + * 4. 擴展-C區:[\u2A700-\u2B734](\uD86D[\uDC00-\uDF3F]|[\uD86A-\uD86C][\uDC00-\uDFFF]|\uD869[\uDF00-\uDFFF]) + Extended-C + * 5. 擴展-D區:[\u2B740-\u2B81D](急用漢字,\uD86D[\uDF40-\uDFFF]|\uD86E[\uDC00-\uDC1F]) + Extended-D + * 6. 擴展-E區:[\u2B820-\u2F7FF](暫未支援) + Extended-E (not supported yet) + * 7. 擴展-F區(暫未支援) + Extended-F (not supported yet) + * 8. 筆畫區:[\u31C0-\u31E3] + Strokes + * 9. 意音數字「〇」:[\u3007] + Ideographic number zero + * 10. 相容意音文字及補充:[\uF900-\uFAFF][\u2F800-\u2FA1D](不使用) + Compatibility ideograph and supplement (not supported) + + 12 exceptions: + [\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29] + + https://zh.wikipedia.org/wiki/中日韓統一表意文字#cite_note-1 + + * 11. 康熙字典及簡化字部首:[\u2F00-\u2FD5\u2E80-\u2EF3] + Kangxi and supplement radicals + * 12. 意音文字描述字元:[\u2FF0-\u2FFA] + Ideographic description characters + */ + hanzi: { + base: '[\u4E00-\u9FFF\u3400-\u4DB5\u31C0-\u31E3\u3007\uFA0E\uFA0F\uFA11\uFA13\uFA14\uFA1F\uFA21\uFA23\uFA24\uFA27-\uFA29]|[\uD800-\uDBFF][\uDC00-\uDFFF]', + desc: '[\u2FF0-\u2FFA]', + radical: '[\u2F00-\u2FD5\u2E80-\u2EF3]' + }, + + /** + * Latin script blocks (拉丁字母區段) + * + * 1. 基本拉丁字母:A-Za-z + Basic Latin + * 2. 阿拉伯數字:0-9 + Digits + * 3. 補充-1:[\u00C0-\u00FF] + Latin-1 supplement + * 4. 擴展-A區:[\u0100-\u017F] + Extended-A + * 5. 擴展-B區:[\u0180-\u024F] + Extended-B + * 5. 擴展-C區:[\u2C60-\u2C7F] + Extended-C + * 5. 擴展-D區:[\uA720-\uA7FF] + Extended-D + * 6. 附加區:[\u1E00-\u1EFF] + Extended additional + * 7. 變音組字符:[\u0300-\u0341\u1DC0-\u1DFF] + Combining diacritical marks + */ + latin: { + base: '[A-Za-z0-9\u00C0-\u00FF\u0100-\u017F\u0180-\u024F\u2C60-\u2C7F\uA720-\uA7FF\u1E00-\u1EFF]', + combine: '[\u0300-\u0341\u1DC0-\u1DFF]' + }, + + /** + * Elli̱niká (Greek) script blocks (希臘字母區段) + * + * 1. 希臘字母及擴展:[\u0370–\u03FF\u1F00-\u1FFF] + Basic Greek & Greek Extended + * 2. 阿拉伯數字:0-9 + Digits + * 3. 希臘字母變音組字符:[\u0300-\u0345\u1DC0-\u1DFF] + Combining diacritical marks + */ + ellinika: { + base: '[0-9\u0370-\u03FF\u1F00-\u1FFF]', + combine: '[\u0300-\u0345\u1DC0-\u1DFF]' + }, + + /** + * Kirillica (Cyrillic) script blocks (西里爾字母區段) + * + * 1. 西里爾字母及補充:[\u0400-\u0482\u048A-\u04FF\u0500-\u052F] + Basic Cyrillic and supplement + * 2. 擴展B區:[\uA640-\uA66E\uA67E-\uA697] + Extended-B + * 3. 阿拉伯數字:0-9 + Digits + * 4. 西里爾字母組字符:[\u0483-\u0489\u2DE0-\u2DFF\uA66F-\uA67D\uA69F](位擴展A、B區) + Cyrillic combining diacritical marks (in extended-A, B) + */ + kirillica: { + base: '[0-9\u0400-\u0482\u048A-\u04FF\u0500-\u052F\uA640-\uA66E\uA67E-\uA697]', + combine: '[\u0483-\u0489\u2DE0-\u2DFF\uA66F-\uA67D\uA69F]' + }, + + /** + * Kana (假名) + * + * 1. 日文假名:[\u30A2\u30A4\u30A6\u30A8\u30AA-\u30FA\u3042\u3044\u3046\u3048\u304A-\u3094\u309F\u30FF] + Japanese Kana + * 2. 假名補充[\u1B000\u1B001](\uD82C[\uDC00-\uDC01]) + Kana supplement + * 3. 日文假名小寫:[\u3041\u3043\u3045\u3047\u3049\u30A1\u30A3\u30A5\u30A7\u30A9\u3063\u3083\u3085\u3087\u308E\u3095\u3096\u30C3\u30E3\u30E5\u30E7\u30EE\u30F5\u30F6\u31F0-\u31FF] + Japanese small Kana + * 4. 假名組字符:[\u3099-\u309C] + Kana combining characters + * 5. 半形假名:[\uFF66-\uFF9F] + Halfwidth Kana + * 6. 符號:[\u309D\u309E\u30FB-\u30FE] + Marks + */ + kana: { + base: '[\u30A2\u30A4\u30A6\u30A8\u30AA-\u30FA\u3042\u3044\u3046\u3048\u304A-\u3094\u309F\u30FF]|\uD82C[\uDC00-\uDC01]', + small: '[\u3041\u3043\u3045\u3047\u3049\u30A1\u30A3\u30A5\u30A7\u30A9\u3063\u3083\u3085\u3087\u308E\u3095\u3096\u30C3\u30E3\u30E5\u30E7\u30EE\u30F5\u30F6\u31F0-\u31FF]', + combine: '[\u3099-\u309C]', + half: '[\uFF66-\uFF9F]', + mark: '[\u30A0\u309D\u309E\u30FB-\u30FE]' + }, + + /** + * Eonmun (Hangul, 諺文) + * + * 1. 諺文音節:[\uAC00-\uD7A3] + Eonmun (Hangul) syllables + * 2. 諺文字母:[\u1100-\u11FF\u314F-\u3163\u3131-\u318E\uA960-\uA97C\uD7B0-\uD7FB] + Eonmun (Hangul) letters + * 3. 半形諺文字母:[\uFFA1-\uFFDC] + Halfwidth Eonmun (Hangul) letters + */ + eonmun: { + base: '[\uAC00-\uD7A3]', + letter: '[\u1100-\u11FF\u314F-\u3163\u3131-\u318E\uA960-\uA97C\uD7B0-\uD7FB]', + half: '[\uFFA1-\uFFDC]' + }, + + /** + * Zhuyin (注音符號, Mandarin & Dialect Phonetic Symbols) + * + * 1. 國語注音、方言音符號:[\u3105-\u312D][\u31A0-\u31BA] + Bopomofo phonetic symbols + * 2. 平上去聲調號:[\u02D9\u02CA\u02C5\u02C7\u02EA\u02EB\u02CB] (**註:**國語三聲包含乙個不合規範的符號) + Level, rising, departing tones + * 3. 入聲調號:[\u31B4-\u31B7][\u0358\u030d]? + Checked (entering) tones + */ + zhuyin: { + base: '[\u3105-\u312D\u31A0-\u31BA]', + initial: '[\u3105-\u3119\u312A-\u312C\u31A0-\u31A3]', + medial: '[\u3127-\u3129]', + final: '[\u311A-\u3129\u312D\u31A4-\u31B3\u31B8-\u31BA]', + tone: '[\u02D9\u02CA\u02C5\u02C7\u02CB\u02EA\u02EB]', + checked: '[\u31B4-\u31B7][\u0358\u030d]?' + } +} + +var TYPESET = (function() { + var rWhite = '[\\x20\\t\\r\\n\\f]' + // Whitespace characters + // http://www.w3.org/TR/css3-selectors/#whitespace + + var rPtOpen = UNICODE.punct.open + var rPtClose = UNICODE.punct.close + var rPtEnd = UNICODE.punct.end + var rPtMid = UNICODE.punct.middle + var rPtSing = UNICODE.punct.sing + var rPt = rPtOpen + '|' + rPtEnd + '|' + rPtMid + + var rBDOpen = UNICODE.biaodian.open + var rBDClose = UNICODE.biaodian.close + var rBDEnd = UNICODE.biaodian.end + var rBDMid = UNICODE.biaodian.middle + var rBDLiga = UNICODE.biaodian.liga + '{2}' + var rBD = rBDOpen + '|' + rBDEnd + '|' + rBDMid + + var rKana = UNICODE.kana.base + UNICODE.kana.combine + '?' + var rKanaS = UNICODE.kana.small + UNICODE.kana.combine + '?' + var rKanaH = UNICODE.kana.half + var rEon = UNICODE.eonmun.base + '|' + UNICODE.eonmun.letter + var rEonH = UNICODE.eonmun.half + + var rHan = UNICODE.hanzi.base + '|' + UNICODE.hanzi.desc + '|' + UNICODE.hanzi.radical + '|' + rKana + + var rCbn = UNICODE.ellinika.combine + var rLatn = UNICODE.latin.base + rCbn + '*' + var rGk = UNICODE.ellinika.base + rCbn + '*' + + var rCyCbn = UNICODE.kirillica.combine + var rCy = UNICODE.kirillica.base + rCyCbn + '*' + + var rAlph = rLatn + '|' + rGk + '|' + rCy + + // For words like `it's`, `Jones’s` or `'99` + var rApo = '[\u0027\u2019]' + var rChar = rHan + '|(?:' + rAlph + '|' + rApo + ')+' + + var rZyS = UNICODE.zhuyin.initial + var rZyJ = UNICODE.zhuyin.medial + var rZyY = UNICODE.zhuyin.final + var rZyD = UNICODE.zhuyin.tone + '|' + UNICODE.zhuyin.checked + + return { + /* Character-level selector (字級選擇器) + */ + char: { + punct: { + all: new RegExp( '(' + rPt + ')', 'g' ), + open: new RegExp( '(' + rPtOpen + ')', 'g' ), + end: new RegExp( '(' + rPtEnd + ')', 'g' ), + sing: new RegExp( '(' + rPtSing + ')', 'g' ) + }, + + biaodian: { + all: new RegExp( '(' + rBD + ')', 'g' ), + open: new RegExp( '(' + rBDOpen + ')', 'g' ), + close: new RegExp( '(' + rBDClose + ')', 'g' ), + end: new RegExp( '(' + rBDEnd + ')', 'g' ), + liga: new RegExp( '(' + rBDLiga + ')', 'g' ) + }, + + hanzi: new RegExp( '(' + rHan + ')', 'g' ), + + latin: new RegExp( '(' + rLatn + ')', 'ig' ), + ellinika: new RegExp( '(' + rGk + ')', 'ig' ), + kirillica: new RegExp( '(' + rCy + ')', 'ig' ), + + kana: new RegExp( '(' + rKana + '|' + rKanaS + '|' + rKanaH + ')', 'g' ), + eonmun: new RegExp( '(' + rEon + '|' + rEonH + ')', 'g' ) + }, + + /* Word-level selectors (詞級選擇器) + */ + group: { + biaodian: [ + new RegExp( '((' + rBD + '){2,})', 'g' ), + new RegExp( '(' + rBDLiga + rBDOpen + ')', 'g' ) + ], + punct: null, + hanzi: new RegExp( '(' + rHan + ')+', 'g' ), + western: new RegExp( '(' + rLatn + '|' + rGk + '|' + rCy + '|' + rPt + ')+', 'ig' ), + kana: new RegExp( '(' + rKana + '|' + rKanaS + '|' + rKanaH + ')+', 'g' ), + eonmun: new RegExp( '(' + rEon + '|' + rEonH + '|' + rPt + ')+', 'g' ) + }, + + /* Punctuation Rules (禁則) + */ + jinze: { + hanging: new RegExp( rWhite + '*([、,。.])(?!' + rBDEnd + ')', 'ig' ), + touwei: new RegExp( '(' + rBDOpen + '+)(' + rChar + ')(' + rBDEnd + '+)', 'ig' ), + tou: new RegExp( '(' + rBDOpen + '+)(' + rChar + ')', 'ig' ), + wei: new RegExp( '(' + rChar + ')(' + rBDEnd + '+)', 'ig' ), + middle: new RegExp( '(' + rChar + ')(' + rBDMid + ')(' + rChar + ')', 'ig' ) + }, + + zhuyin: { + form: new RegExp( '^\u02D9?(' + rZyS + ')?(' + rZyJ + ')?(' + rZyY + ')?(' + rZyD + ')?$' ), + diao: new RegExp( '(' + rZyD + ')', 'g' ) + }, + + /* Hanzi and Western mixed spacing (漢字西文混排間隙) + * - Basic mode + * - Strict mode + */ + hws: { + base: [ + new RegExp( '('+ rHan + ')(' + rAlph + '|' + rPtOpen + ')', 'ig' ), + new RegExp( '('+ rAlph + '|' + rPtEnd + ')(' + rHan + ')', 'ig' ) + ], + + strict: [ + new RegExp( '('+ rHan + ')' + rWhite + '?(' + rAlph + '|' + rPtOpen + ')', 'ig' ), + new RegExp( '('+ rAlph + '|' + rPtEnd + ')' + rWhite + '?(' + rHan + ')', 'ig' ) + ] + }, + + // The feature displays the following characters + // in its variant form for font consistency and + // presentational reason. Meanwhile, this won't + // alter the original character in the DOM. + 'display-as': { + 'ja-font-for-hant': [ + // '夠 够', + '查 査', + '啟 啓', + '鄉 鄕', + '值 値', + '污 汚' + ], + + 'comb-liga-pua': [ + [ '\u0061[\u030d\u0358]', '\uDB80\uDC61' ], + [ '\u0065[\u030d\u0358]', '\uDB80\uDC65' ], + [ '\u0069[\u030d\u0358]', '\uDB80\uDC69' ], + [ '\u006F[\u030d\u0358]', '\uDB80\uDC6F' ], + [ '\u0075[\u030d\u0358]', '\uDB80\uDC75' ], + + [ '\u31B4[\u030d\u0358]', '\uDB8C\uDDB4' ], + [ '\u31B5[\u030d\u0358]', '\uDB8C\uDDB5' ], + [ '\u31B6[\u030d\u0358]', '\uDB8C\uDDB6' ], + [ '\u31B7[\u030d\u0358]', '\uDB8C\uDDB7' ] + ], + + 'comb-liga-vowel': [ + [ '\u0061[\u030d\u0358]', '\uDB80\uDC61' ], + [ '\u0065[\u030d\u0358]', '\uDB80\uDC65' ], + [ '\u0069[\u030d\u0358]', '\uDB80\uDC69' ], + [ '\u006F[\u030d\u0358]', '\uDB80\uDC6F' ], + [ '\u0075[\u030d\u0358]', '\uDB80\uDC75' ] + ], + + 'comb-liga-zhuyin': [ + [ '\u31B4[\u030d\u0358]', '\uDB8C\uDDB4' ], + [ '\u31B5[\u030d\u0358]', '\uDB8C\uDDB5' ], + [ '\u31B6[\u030d\u0358]', '\uDB8C\uDDB6' ], + [ '\u31B7[\u030d\u0358]', '\uDB8C\uDDB7' ] + ] + }, + + // The feature actually *converts* the character + // in the DOM for semantic reason. + // + // Note that this could be aggressive. + 'inaccurate-char': [ + [ '[\u2022\u2027]', '\u00B7' ], + [ '\u22EF\u22EF', '\u2026\u2026' ], + [ '\u2500\u2500', '\u2014\u2014' ], + [ '\u2035', '\u2018' ], + [ '\u2032', '\u2019' ], + [ '\u2036', '\u201C' ], + [ '\u2033', '\u201D' ] + ] + } +})() + +Han.UNICODE = UNICODE +Han.TYPESET = TYPESET + +// Aliases +Han.UNICODE.cjk = Han.UNICODE.hanzi +Han.UNICODE.greek = Han.UNICODE.ellinika +Han.UNICODE.cyrillic = Han.UNICODE.kirillica +Han.UNICODE.hangul = Han.UNICODE.eonmun +Han.UNICODE.zhuyin.ruyun = Han.UNICODE.zhuyin.checked + +Han.TYPESET.char.cjk = Han.TYPESET.char.hanzi +Han.TYPESET.char.greek = Han.TYPESET.char.ellinika +Han.TYPESET.char.cyrillic = Han.TYPESET.char.kirillica +Han.TYPESET.char.hangul = Han.TYPESET.char.eonmun + +Han.TYPESET.group.hangul = Han.TYPESET.group.eonmun +Han.TYPESET.group.cjk = Han.TYPESET.group.hanzi + +var $ = { + /** + * Query selectors which return arrays of the resulted + * node lists. + */ + id: function( selector, $context ) { + return ( $context || document ).getElementById( selector ) + }, + + tag: function( selector, $context ) { + return this.makeArray( + ( $context || document ).getElementsByTagName( selector ) + ) + }, + + qs: function( selector, $context ) { + return ( $context || document ).querySelector( selector ) + }, + + qsa: function( selector, $context ) { + return this.makeArray( + ( $context || document ).querySelectorAll( selector ) + ) + }, + + parent: function( $node, selector ) { + return selector + ? (function() { + if ( typeof $.matches !== 'function' ) return + + while (!$.matches( $node, selector )) { + if ( + !$node || + $node === document.documentElement + ) { + $node = undefined + break + } + $node = $node.parentNode + } + return $node + })() + : $node + ? $node.parentNode : undefined + }, + + /** + * Create a document fragment, a text node with text + * or an element with/without classes. + */ + create: function( name, clazz ) { + var $elmt = '!' === name + ? document.createDocumentFragment() + : '' === name + ? document.createTextNode( clazz || '' ) + : document.createElement( name ) + + try { + if ( clazz ) { + $elmt.className = clazz + } + } catch (e) {} + + return $elmt + }, + + /** + * Clone a DOM node (text, element or fragment) deeply + * or childlessly. + */ + clone: function( $node, deep ) { + return $node.cloneNode( + typeof deep === 'boolean' + ? deep + : true + ) + }, + + /** + * Remove a node (text, element or fragment). + */ + remove: function( $node ) { + return $node.parentNode.removeChild( $node ) + }, + + /** + * Set attributes all in once with an object. + */ + setAttr: function( target, attr ) { + if ( typeof attr !== 'object' ) return + var len = attr.length + + // Native `NamedNodeMap``: + if ( + typeof attr[0] === 'object' && + 'name' in attr[0] + ) { + for ( var i = 0; i < len; i++ ) { + if ( attr[ i ].value !== undefined ) { + target.setAttribute( attr[ i ].name, attr[ i ].value ) + } + } + + // Plain object: + } else { + for ( var name in attr ) { + if ( + attr.hasOwnProperty( name ) && + attr[ name ] !== undefined + ) { + target.setAttribute( name, attr[ name ] ) + } + } + } + return target + }, + + /** + * Indicate whether or not the given node is an + * element. + */ + isElmt: function( $node ) { + return $node && $node.nodeType === Node.ELEMENT_NODE + }, + + /** + * Indicate whether or not the given node should + * be ignored (`` or comments). + */ + isIgnorable: function( $node ) { + if ( !$node ) return false + + return ( + $node.nodeName === 'WBR' || + $node.nodeType === Node.COMMENT_NODE + ) + }, + + /** + * Convert array-like objects into real arrays. + */ + makeArray: function( object ) { + return Array.prototype.slice.call( object ) + }, + + /** + * Extend target with an object. + */ + extend: function( target, object ) { + if (( + typeof target === 'object' || + typeof target === 'function' ) && + typeof object === 'object' + ) { + for ( var name in object ) { + if (object.hasOwnProperty( name )) { + target[ name ] = object[ name ] + } + } + } + return target + } +} + +var Fibre = +/*! + * Fibre.js v0.2.1 | MIT License | github.com/ethantw/fibre.js + * Based on findAndReplaceDOMText + */ + +function( Finder ) { + +'use strict' + +var VERSION = '0.2.1' +var NON_INLINE_PROSE = Finder.NON_INLINE_PROSE +var AVOID_NON_PROSE = Finder.PRESETS.prose.filterElements + +var global = window || {} +var document = global.document || undefined + +function matches( node, selector, bypassNodeType39 ) { + var Efn = Element.prototype + var matches = Efn.matches || Efn.mozMatchesSelector || Efn.msMatchesSelector || Efn.webkitMatchesSelector + + if ( node instanceof Element ) { + return matches.call( node, selector ) + } else if ( bypassNodeType39 ) { + if ( /^[39]$/.test( node.nodeType )) return true + } + return false +} + +if ( typeof document === 'undefined' ) throw new Error( 'Fibre requires a DOM-supported environment.' ) + +var Fibre = function( context, preset ) { + return new Fibre.fn.init( context, preset ) +} + +Fibre.version = VERSION +Fibre.matches = matches + +Fibre.fn = Fibre.prototype = { + constructor: Fibre, + + version: VERSION, + + finder: [], + + context: undefined, + + portionMode: 'retain', + + selector: {}, + + preset: 'prose', + + init: function( context, noPreset ) { + if ( !!noPreset ) this.preset = null + + this.selector = { + context: null, + filter: [], + avoid: [], + boundary: [] + } + + if ( !context ) { + throw new Error( 'A context is required for Fibre to initialise.' ) + } else if ( context instanceof Node ) { + if ( context instanceof Document ) this.context = context.body || context + else this.context = context + } else if ( typeof context === 'string' ) { + this.context = document.querySelector( context ) + this.selector.context = context + } + return this + }, + + filterFn: function( node ) { + var filter = this.selector.filter.join( ', ' ) || '*' + var avoid = this.selector.avoid.join( ', ' ) || null + var result = matches( node, filter, true ) && !matches( node, avoid ) + return ( this.preset === 'prose' ) ? AVOID_NON_PROSE( node ) && result : result + }, + + boundaryFn: function( node ) { + var boundary = this.selector.boundary.join( ', ' ) || null + var result = matches( node, boundary ) + return ( this.preset === 'prose' ) ? NON_INLINE_PROSE( node ) || result : result + }, + + filter: function( selector ) { + if ( typeof selector === 'string' ) { + this.selector.filter.push( selector ) + } + return this + }, + + endFilter: function( all ) { + if ( all ) { + this.selector.filter = [] + } else { + this.selector.filter.pop() + } + return this + }, + + avoid: function( selector ) { + if ( typeof selector === 'string' ) { + this.selector.avoid.push( selector ) + } + return this + }, + + endAvoid: function( all ) { + if ( all ) { + this.selector.avoid = [] + } else { + this.selector.avoid.pop() + } + return this + }, + + addBoundary: function( selector ) { + if ( typeof selector === 'string' ) { + this.selector.boundary.push( selector ) + } + return this + }, + + removeBoundary: function() { + this.selector.boundary = [] + return this + }, + + setMode: function( portionMode ) { + this.portionMode = portionMode === 'first' ? 'first' : 'retain' + return this + }, + + replace: function( regexp, newSubStr ) { + var it = this + it.finder.push(Finder( it.context, { + find: regexp, + replace: newSubStr, + filterElements: function( currentNode ) { + return it.filterFn( currentNode ) + }, + forceContext: function( currentNode ) { + return it.boundaryFn( currentNode ) + }, + portionMode: it.portionMode + })) + return it + }, + + wrap: function( regexp, strElemName ) { + var it = this + it.finder.push(Finder( it.context, { + find: regexp, + wrap: strElemName, + filterElements: function( currentNode ) { + return it.filterFn( currentNode ) + }, + forceContext: function( currentNode ) { + return it.boundaryFn( currentNode ) + }, + portionMode: it.portionMode + })) + return it + }, + + revert: function( level ) { + var max = this.finder.length + var level = Number( level ) || ( level === 0 ? Number(0) : + ( level === 'all' ? max : 1 )) + + if ( typeof max === 'undefined' || max === 0 ) return this + else if ( level > max ) level = max + + for ( var i = level; i > 0; i-- ) { + this.finder.pop().revert() + } + return this + } +} + +// Deprecated API(s) +Fibre.fn.filterOut = Fibre.fn.avoid + +// Make sure init() inherit from Fibre() +Fibre.fn.init.prototype = Fibre.fn + +return Fibre + +}( + +/** + * findAndReplaceDOMText v 0.4.3 + * @author James Padolsey http://james.padolsey.com + * @license http://unlicense.org/UNLICENSE + * + * Matches the text of a DOM node against a regular expression + * and replaces each match (or node-separated portions of the match) + * in the specified element. + */ + (function() { + + var PORTION_MODE_RETAIN = 'retain' + var PORTION_MODE_FIRST = 'first' + var doc = document + var toString = {}.toString + var hasOwn = {}.hasOwnProperty + function isArray(a) { + return toString.call(a) == '[object Array]' + } + + function escapeRegExp(s) { + return String(s).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1') + } + + function exposed() { + // Try deprecated arg signature first: + return deprecated.apply(null, arguments) || findAndReplaceDOMText.apply(null, arguments) + } + + function deprecated(regex, node, replacement, captureGroup, elFilter) { + if ((node && !node.nodeType) && arguments.length <= 2) { + return false + } + var isReplacementFunction = typeof replacement == 'function' + if (isReplacementFunction) { + replacement = (function(original) { + return function(portion, match) { + return original(portion.text, match.startIndex) + } + }(replacement)) + } + + // Awkward support for deprecated argument signature (<0.4.0) + var instance = findAndReplaceDOMText(node, { + + find: regex, + + wrap: isReplacementFunction ? null : replacement, + replace: isReplacementFunction ? replacement : '$' + (captureGroup || '&'), + + prepMatch: function(m, mi) { + + // Support captureGroup (a deprecated feature) + + if (!m[0]) throw 'findAndReplaceDOMText cannot handle zero-length matches' + if (captureGroup > 0) { + var cg = m[captureGroup] + m.index += m[0].indexOf(cg) + m[0] = cg + } + + m.endIndex = m.index + m[0].length + m.startIndex = m.index + m.index = mi + return m + }, + filterElements: elFilter + }) + exposed.revert = function() { + return instance.revert() + } + return true + } + + /** + * findAndReplaceDOMText + * + * Locates matches and replaces with replacementNode + * + * @param {Node} node Element or Text node to search within + * @param {RegExp} options.find The regular expression to match + * @param {String|Element} [options.wrap] A NodeName, or a Node to clone + * @param {String|Function} [options.replace='$&'] What to replace each match with + * @param {Function} [options.filterElements] A Function to be called to check whether to + * process an element. (returning true = process element, + * returning false = avoid element) + */ + function findAndReplaceDOMText(node, options) { + return new Finder(node, options) + } + + exposed.NON_PROSE_ELEMENTS = { + br:1, hr:1, + // Media / Source elements: + script:1, style:1, img:1, video:1, audio:1, canvas:1, svg:1, map:1, object:1, + // Input elements + input:1, textarea:1, select:1, option:1, optgroup: 1, button:1 + } + exposed.NON_CONTIGUOUS_PROSE_ELEMENTS = { + + // Elements that will not contain prose or block elements where we don't + // want prose to be matches across element borders: + + // Block Elements + address:1, article:1, aside:1, blockquote:1, dd:1, div:1, + dl:1, fieldset:1, figcaption:1, figure:1, footer:1, form:1, h1:1, h2:1, h3:1, + h4:1, h5:1, h6:1, header:1, hgroup:1, hr:1, main:1, nav:1, noscript:1, ol:1, + output:1, p:1, pre:1, section:1, ul:1, + // Other misc. elements that are not part of continuous inline prose: + br:1, li: 1, summary: 1, dt:1, details:1, rp:1, rt:1, rtc:1, + // Media / Source elements: + script:1, style:1, img:1, video:1, audio:1, canvas:1, svg:1, map:1, object:1, + // Input elements + input:1, textarea:1, select:1, option:1, optgroup: 1, button:1, + // Table related elements: + table:1, tbody:1, thead:1, th:1, tr:1, td:1, caption:1, col:1, tfoot:1, colgroup:1 + + } + exposed.NON_INLINE_PROSE = function(el) { + return hasOwn.call(exposed.NON_CONTIGUOUS_PROSE_ELEMENTS, el.nodeName.toLowerCase()) + } + // Presets accessed via `options.preset` when calling findAndReplaceDOMText(): + exposed.PRESETS = { + prose: { + forceContext: exposed.NON_INLINE_PROSE, + filterElements: function(el) { + return !hasOwn.call(exposed.NON_PROSE_ELEMENTS, el.nodeName.toLowerCase()) + } + } + } + exposed.Finder = Finder + /** + * Finder -- encapsulates logic to find and replace. + */ + function Finder(node, options) { + + var preset = options.preset && exposed.PRESETS[options.preset] + options.portionMode = options.portionMode || PORTION_MODE_RETAIN + if (preset) { + for (var i in preset) { + if (hasOwn.call(preset, i) && !hasOwn.call(options, i)) { + options[i] = preset[i] + } + } + } + + this.node = node + this.options = options + // ENable match-preparation method to be passed as option: + this.prepMatch = options.prepMatch || this.prepMatch + this.reverts = [] + this.matches = this.search() + if (this.matches.length) { + this.processMatches() + } + + } + + Finder.prototype = { + + /** + * Searches for all matches that comply with the instance's 'match' option + */ + search: function() { + + var match + var matchIndex = 0 + var offset = 0 + var regex = this.options.find + var textAggregation = this.getAggregateText() + var matches = [] + var self = this + regex = typeof regex === 'string' ? RegExp(escapeRegExp(regex), 'g') : regex + matchAggregation(textAggregation) + function matchAggregation(textAggregation) { + for (var i = 0, l = textAggregation.length; i < l; ++i) { + + var text = textAggregation[i] + if (typeof text !== 'string') { + // Deal with nested contexts: (recursive) + matchAggregation(text) + continue + } + + if (regex.global) { + while (match = regex.exec(text)) { + matches.push(self.prepMatch(match, matchIndex++, offset)) + } + } else { + if (match = text.match(regex)) { + matches.push(self.prepMatch(match, 0, offset)) + } + } + + offset += text.length + } + } + + return matches + }, + + /** + * Prepares a single match with useful meta info: + */ + prepMatch: function(match, matchIndex, characterOffset) { + + if (!match[0]) { + throw new Error('findAndReplaceDOMText cannot handle zero-length matches') + } + + match.endIndex = characterOffset + match.index + match[0].length + match.startIndex = characterOffset + match.index + match.index = matchIndex + return match + }, + + /** + * Gets aggregate text within subject node + */ + getAggregateText: function() { + + var elementFilter = this.options.filterElements + var forceContext = this.options.forceContext + return getText(this.node) + /** + * Gets aggregate text of a node without resorting + * to broken innerText/textContent + */ + function getText(node, txt) { + + if (node.nodeType === 3) { + return [node.data] + } + + if (elementFilter && !elementFilter(node)) { + return [] + } + + var txt = [''] + var i = 0 + if (node = node.firstChild) do { + + if (node.nodeType === 3) { + txt[i] += node.data + continue + } + + var innerText = getText(node) + if ( + forceContext && + node.nodeType === 1 && + (forceContext === true || forceContext(node)) + ) { + txt[++i] = innerText + txt[++i] = '' + } else { + if (typeof innerText[0] === 'string') { + // Bridge nested text-node data so that they're + // not considered their own contexts: + // I.e. ['some', ['thing']] -> ['something'] + txt[i] += innerText.shift() + } + if (innerText.length) { + txt[++i] = innerText + txt[++i] = '' + } + } + } while (node = node.nextSibling) + return txt + } + + }, + + /** + * Steps through the target node, looking for matches, and + * calling replaceFn when a match is found. + */ + processMatches: function() { + + var matches = this.matches + var node = this.node + var elementFilter = this.options.filterElements + var startPortion, + endPortion, + innerPortions = [], + curNode = node, + match = matches.shift(), + atIndex = 0, // i.e. nodeAtIndex + matchIndex = 0, + portionIndex = 0, + doAvoidNode, + nodeStack = [node] + out: while (true) { + + if (curNode.nodeType === 3) { + + if (!endPortion && curNode.length + atIndex >= match.endIndex) { + + // We've found the ending + endPortion = { + node: curNode, + index: portionIndex++, + text: curNode.data.substring(match.startIndex - atIndex, match.endIndex - atIndex), + indexInMatch: atIndex - match.startIndex, + indexInNode: match.startIndex - atIndex, // always zero for end-portions + endIndexInNode: match.endIndex - atIndex, + isEnd: true + } + } else if (startPortion) { + // Intersecting node + innerPortions.push({ + node: curNode, + index: portionIndex++, + text: curNode.data, + indexInMatch: atIndex - match.startIndex, + indexInNode: 0 // always zero for inner-portions + }) + } + + if (!startPortion && curNode.length + atIndex > match.startIndex) { + // We've found the match start + startPortion = { + node: curNode, + index: portionIndex++, + indexInMatch: 0, + indexInNode: match.startIndex - atIndex, + endIndexInNode: match.endIndex - atIndex, + text: curNode.data.substring(match.startIndex - atIndex, match.endIndex - atIndex) + } + } + + atIndex += curNode.data.length + } + + doAvoidNode = curNode.nodeType === 1 && elementFilter && !elementFilter(curNode) + if (startPortion && endPortion) { + + curNode = this.replaceMatch(match, startPortion, innerPortions, endPortion) + // processMatches has to return the node that replaced the endNode + // and then we step back so we can continue from the end of the + // match: + + atIndex -= (endPortion.node.data.length - endPortion.endIndexInNode) + startPortion = null + endPortion = null + innerPortions = [] + match = matches.shift() + portionIndex = 0 + matchIndex++ + if (!match) { + break; // no more matches + } + + } else if ( + !doAvoidNode && + (curNode.firstChild || curNode.nextSibling) + ) { + // Move down or forward: + if (curNode.firstChild) { + nodeStack.push(curNode) + curNode = curNode.firstChild + } else { + curNode = curNode.nextSibling + } + continue + } + + // Move forward or up: + while (true) { + if (curNode.nextSibling) { + curNode = curNode.nextSibling + break + } + curNode = nodeStack.pop() + if (curNode === node) { + break out + } + } + + } + + }, + + /** + * Reverts ... TODO + */ + revert: function() { + // Reversion occurs backwards so as to avoid nodes subsequently + // replaced during the matching phase (a forward process): + for (var l = this.reverts.length; l--;) { + this.reverts[l]() + } + this.reverts = [] + }, + + prepareReplacementString: function(string, portion, match, matchIndex) { + var portionMode = this.options.portionMode + if ( + portionMode === PORTION_MODE_FIRST && + portion.indexInMatch > 0 + ) { + return '' + } + string = string.replace(/\$(\d+|&|`|')/g, function($0, t) { + var replacement + switch(t) { + case '&': + replacement = match[0] + break + case '`': + replacement = match.input.substring(0, match.startIndex) + break + case '\'': + replacement = match.input.substring(match.endIndex) + break + default: + replacement = match[+t] + } + return replacement + }) + if (portionMode === PORTION_MODE_FIRST) { + return string + } + + if (portion.isEnd) { + return string.substring(portion.indexInMatch) + } + + return string.substring(portion.indexInMatch, portion.indexInMatch + portion.text.length) + }, + + getPortionReplacementNode: function(portion, match, matchIndex) { + + var replacement = this.options.replace || '$&' + var wrapper = this.options.wrap + if (wrapper && wrapper.nodeType) { + // Wrapper has been provided as a stencil-node for us to clone: + var clone = doc.createElement('div') + clone.innerHTML = wrapper.outerHTML || new XMLSerializer().serializeToString(wrapper) + wrapper = clone.firstChild + } + + if (typeof replacement == 'function') { + replacement = replacement(portion, match, matchIndex) + if (replacement && replacement.nodeType) { + return replacement + } + return doc.createTextNode(String(replacement)) + } + + var el = typeof wrapper == 'string' ? doc.createElement(wrapper) : wrapper + replacement = doc.createTextNode( + this.prepareReplacementString( + replacement, portion, match, matchIndex + ) + ) + if (!replacement.data) { + return replacement + } + + if (!el) { + return replacement + } + + el.appendChild(replacement) + return el + }, + + replaceMatch: function(match, startPortion, innerPortions, endPortion) { + + var matchStartNode = startPortion.node + var matchEndNode = endPortion.node + var preceedingTextNode + var followingTextNode + if (matchStartNode === matchEndNode) { + + var node = matchStartNode + if (startPortion.indexInNode > 0) { + // Add `before` text node (before the match) + preceedingTextNode = doc.createTextNode(node.data.substring(0, startPortion.indexInNode)) + node.parentNode.insertBefore(preceedingTextNode, node) + } + + // Create the replacement node: + var newNode = this.getPortionReplacementNode( + endPortion, + match + ) + node.parentNode.insertBefore(newNode, node) + if (endPortion.endIndexInNode < node.length) { // ????? + // Add `after` text node (after the match) + followingTextNode = doc.createTextNode(node.data.substring(endPortion.endIndexInNode)) + node.parentNode.insertBefore(followingTextNode, node) + } + + node.parentNode.removeChild(node) + this.reverts.push(function() { + if (preceedingTextNode === newNode.previousSibling) { + preceedingTextNode.parentNode.removeChild(preceedingTextNode) + } + if (followingTextNode === newNode.nextSibling) { + followingTextNode.parentNode.removeChild(followingTextNode) + } + newNode.parentNode.replaceChild(node, newNode) + }) + return newNode + } else { + // Replace matchStartNode -> [innerMatchNodes...] -> matchEndNode (in that order) + + preceedingTextNode = doc.createTextNode( + matchStartNode.data.substring(0, startPortion.indexInNode) + ) + followingTextNode = doc.createTextNode( + matchEndNode.data.substring(endPortion.endIndexInNode) + ) + var firstNode = this.getPortionReplacementNode( + startPortion, + match + ) + var innerNodes = [] + for (var i = 0, l = innerPortions.length; i < l; ++i) { + var portion = innerPortions[i] + var innerNode = this.getPortionReplacementNode( + portion, + match + ) + portion.node.parentNode.replaceChild(innerNode, portion.node) + this.reverts.push((function(portion, innerNode) { + return function() { + innerNode.parentNode.replaceChild(portion.node, innerNode) + } + }(portion, innerNode))) + innerNodes.push(innerNode) + } + + var lastNode = this.getPortionReplacementNode( + endPortion, + match + ) + matchStartNode.parentNode.insertBefore(preceedingTextNode, matchStartNode) + matchStartNode.parentNode.insertBefore(firstNode, matchStartNode) + matchStartNode.parentNode.removeChild(matchStartNode) + matchEndNode.parentNode.insertBefore(lastNode, matchEndNode) + matchEndNode.parentNode.insertBefore(followingTextNode, matchEndNode) + matchEndNode.parentNode.removeChild(matchEndNode) + this.reverts.push(function() { + preceedingTextNode.parentNode.removeChild(preceedingTextNode) + firstNode.parentNode.replaceChild(matchStartNode, firstNode) + followingTextNode.parentNode.removeChild(followingTextNode) + lastNode.parentNode.replaceChild(matchEndNode, lastNode) + }) + return lastNode + } + } + + } + return exposed +}()) + +); + +var isNodeNormalizeNormal = (function() { + //// Disabled `Node.normalize()` for temp due to + //// issue below in IE11. + //// See: http://stackoverflow.com/questions/22337498/why-does-ie11-handle-node-normalize-incorrectly-for-the-minus-symbol + var div = $.create( 'div' ) + + div.appendChild($.create( '', '0-' )) + div.appendChild($.create( '', '2' )) + div.normalize() + + return div.firstChild.length !== 2 +})() + +function getFuncOrElmt( obj ) { + return ( + typeof obj === 'function' || + obj instanceof Element + ) + ? obj + : undefined +} + +function createBDGroup( portion ) { + var clazz = portion.index === 0 && portion.isEnd + ? 'biaodian cjk' + : 'biaodian cjk portion ' + ( + portion.index === 0 + ? 'is-first' + : portion.isEnd + ? 'is-end' + : 'is-inner' + ) + + var $elmt = $.create( 'h-char-group', clazz ) + $elmt.innerHTML = portion.text + return $elmt +} + +function createBDChar( char ) { + var div = $.create( 'div' ) + var unicode = char.charCodeAt( 0 ).toString( 16 ) + + div.innerHTML = ( + '' + char + '' + ) + return div.firstChild +} + +function getBDType( char ) { + return char.match( TYPESET.char.biaodian.open ) + ? 'bd-open' + : char.match( TYPESET.char.biaodian.close ) + ? 'bd-close bd-end' + : char.match( TYPESET.char.biaodian.end ) + ? ( + /(?:\u3001|\u3002|\uff0c)/i.test( char ) + ? 'bd-end bd-cop' + : 'bd-end' + ) + : char.match(new RegExp( UNICODE.biaodian.liga )) + ? 'bd-liga' + : char.match(new RegExp( UNICODE.biaodian.middle )) + ? 'bd-middle' + : '' +} + +$.extend( Fibre.fn, { + normalize: function() { + if ( isNodeNormalizeNormal ) { + this.context.normalize() + } + return this + }, + + // Force punctuation & biaodian typesetting rules to be applied. + jinzify: function( selector ) { + return ( + this + .filter( selector || null ) + .avoid( 'h-jinze' ) + .replace( + TYPESET.jinze.touwei, + function( portion, match ) { + var elem = $.create( 'h-jinze', 'touwei' ) + elem.innerHTML = match[0] + return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 ) ? elem : '' + } + ) + .replace( + TYPESET.jinze.wei, + function( portion, match ) { + var elem = $.create( 'h-jinze', 'wei' ) + elem.innerHTML = match[0] + return portion.index === 0 ? elem : '' + } + ) + .replace( + TYPESET.jinze.tou, + function( portion, match ) { + var elem = $.create( 'h-jinze', 'tou' ) + elem.innerHTML = match[0] + return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 ) + ? elem : '' + } + ) + .replace( + TYPESET.jinze.middle, + function( portion, match ) { + var elem = $.create( 'h-jinze', 'middle' ) + elem.innerHTML = match[0] + return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 ) + ? elem : '' + } + ) + .endAvoid() + .endFilter() + ) + }, + + groupify: function( option ) { + var option = $.extend({ + biaodian: false, + //punct: false, + hanzi: false, // Includes Kana + kana: false, + eonmun: false, + western: false // Includes Latin, Greek and Cyrillic + }, option || {}) + + this.avoid( 'h-word, h-char-group' ) + + if ( option.biaodian ) { + this.replace( + TYPESET.group.biaodian[0], createBDGroup + ).replace( + TYPESET.group.biaodian[1], createBDGroup + ) + } + + if ( option.hanzi || option.cjk ) { + this.wrap( + TYPESET.group.hanzi, $.clone($.create( 'h-char-group', 'hanzi cjk' )) + ) + } + if ( option.western ) { + this.wrap( + TYPESET.group.western, $.clone($.create( 'h-word', 'western' )) + ) + } + if ( option.kana ) { + this.wrap( + TYPESET.group.kana, $.clone($.create( 'h-char-group', 'kana' )) + ) + } + if ( option.eonmun || option.hangul ) { + this.wrap( + TYPESET.group.eonmun, $.clone($.create( 'h-word', 'eonmun hangul' )) + ) + } + + this.endAvoid() + return this + }, + + charify: function( option ) { + var option = $.extend({ + avoid: true, + biaodian: false, + punct: false, + hanzi: false, // Includes Kana + latin: false, + ellinika: false, + kirillica: false, + kana: false, + eonmun: false + }, option || {}) + + if ( option.avoid ) { + this.avoid( 'h-char' ) + } + + if ( option.biaodian ) { + this.replace( + TYPESET.char.biaodian.all, + getFuncOrElmt( option.biaodian ) + || + function( portion ) { return createBDChar( portion.text ) } + ).replace( + TYPESET.char.biaodian.liga, + getFuncOrElmt( option.biaodian ) + || + function( portion ) { return createBDChar( portion.text ) } + ) + } + if ( option.hanzi || option.cjk ) { + this.wrap( + TYPESET.char.hanzi, + getFuncOrElmt( option.hanzi || option.cjk ) + || + $.clone($.create( 'h-char', 'hanzi cjk' )) + ) + } + if ( option.punct ) { + this.wrap( + TYPESET.char.punct.all, + getFuncOrElmt( option.punct ) + || + $.clone($.create( 'h-char', 'punct' )) + ) + } + if ( option.latin ) { + this.wrap( + TYPESET.char.latin, + getFuncOrElmt( option.latin ) + || + $.clone($.create( 'h-char', 'alphabet latin' )) + ) + } + if ( option.ellinika || option.greek ) { + this.wrap( + TYPESET.char.ellinika, + getFuncOrElmt( option.ellinika || option.greek ) + || + $.clone($.create( 'h-char', 'alphabet ellinika greek' )) + ) + } + if ( option.kirillica || option.cyrillic ) { + this.wrap( + TYPESET.char.kirillica, + getFuncOrElmt( option.kirillica || option.cyrillic ) + || + $.clone($.create( 'h-char', 'alphabet kirillica cyrillic' )) + ) + } + if ( option.kana ) { + this.wrap( + TYPESET.char.kana, + getFuncOrElmt( option.kana ) + || + $.clone($.create( 'h-char', 'kana' )) + ) + } + if ( option.eonmun || option.hangul ) { + this.wrap( + TYPESET.char.eonmun, + getFuncOrElmt( option.eonmun || option.hangul ) + || + $.clone($.create( 'h-char', 'eonmun hangul' )) + ) + } + + this.endAvoid() + return this + } +}) + +$.extend( Han, { + isNodeNormalizeNormal: isNodeNormalizeNormal, + find: Fibre, + createBDGroup: createBDGroup, + createBDChar: createBDChar +}) + +$.matches = Han.find.matches + +void [ + 'setMode', + 'wrap', 'replace', 'revert', + 'addBoundary', 'removeBoundary', + 'avoid', 'endAvoid', + 'filter', 'endFilter', + 'jinzify', 'groupify', 'charify' +].forEach(function( method ) { + Han.fn[ method ] = function() { + if ( !this.finder ) { + // Share the same selector + this.finder = Han.find( this.context ) + } + + this.finder[ method ]( arguments[ 0 ], arguments[ 1 ] ) + return this + } +}) + +var Locale = {} + +function writeOnCanvas( text, font ) { + var canvas = $.create( 'canvas' ) + var context + + canvas.width = '50' + canvas.height = '20' + canvas.style.display = 'none' + + body.appendChild( canvas ) + + context = canvas.getContext( '2d' ) + context.textBaseline = 'top' + context.font = '15px ' + font + ', sans-serif' + context.fillStyle = 'black' + context.strokeStyle = 'black' + context.fillText( text, 0, 0 ) + + return { + node: canvas, + context: context, + remove: function() { + $.remove( canvas, body ) + } + } +} + +function compareCanvases( treat, control ) { + var ret + var a = treat.context + var b = control.context + + try { + for ( var j = 1; j <= 20; j++ ) { + for ( var i = 1; i <= 50; i++ ) { + if ( + typeof ret === 'undefined' && + a.getImageData(i, j, 1, 1).data[3] !== b.getImageData(i, j, 1, 1).data[3] + ) { + ret = false + break + } else if ( typeof ret === 'boolean' ) { + break + } + + if ( i === 50 && j === 20 && typeof ret === 'undefined' ) { + ret = true + } + } + } + + // Remove and clean from memory + treat.remove() + control.remove() + treat = null + control = null + + return ret + } catch (e) {} + return false +} + +function detectFont( treat, control, text ) { + var treat = treat + var control = control || 'sans-serif' + var text = text || '辭Q' + var ret + + control = writeOnCanvas( text, control ) + treat = writeOnCanvas( text, treat ) + + return !compareCanvases( treat, control ) +} + +Locale.writeOnCanvas = writeOnCanvas +Locale.compareCanvases = compareCanvases +Locale.detectFont = detectFont + +Locale.support = (function() { + + var PREFIX = 'Webkit Moz ms'.split(' ') + + // Create an element for feature detecting + // (in `testCSSProp`) + var elem = $.create( 'h-test' ) + + function testCSSProp( prop ) { + var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1) + var allProp = ( prop + ' ' + PREFIX.join( ucProp + ' ' ) + ucProp ).split(' ') + var ret + + allProp.forEach(function( prop ) { + if ( typeof elem.style[ prop ] === 'string' ) { + ret = true + } + }) + return ret || false + } + + function injectElementWithStyle( rule, callback ) { + var fakeBody = body || $.create( 'body' ) + var div = $.create( 'div' ) + var container = body ? div : fakeBody + var callback = typeof callback === 'function' ? callback : function() {} + var style, ret, docOverflow + + style = [ '' ].join('') + + container.innerHTML += style + fakeBody.appendChild( div ) + + if ( !body ) { + fakeBody.style.background = '' + fakeBody.style.overflow = 'hidden' + docOverflow = root.style.overflow + + root.style.overflow = 'hidden' + root.appendChild( fakeBody ) + } + + // Callback + ret = callback( container, rule ) + + // Remove the injected scope + $.remove( container ) + if ( !body ) { + root.style.overflow = docOverflow + } + return !!ret + } + + function getStyle( elem, prop ) { + var ret + + if ( window.getComputedStyle ) { + ret = document.defaultView.getComputedStyle( elem, null ).getPropertyValue( prop ) + } else if ( elem.currentStyle ) { + // for IE + ret = elem.currentStyle[ prop ] + } + return ret + } + + return { + columnwidth: testCSSProp( 'columnWidth' ), + + fontface: (function() { + var ret + + injectElementWithStyle( + '@font-face { font-family: font; src: url("//"); }', + function( node, rule ) { + var style = $.qsa( 'style', node )[0] + var sheet = style.sheet || style.styleSheet + var cssText = sheet ? + ( sheet.cssRules && sheet.cssRules[0] ? + sheet.cssRules[0].cssText : sheet.cssText || '' + ) : '' + + ret = /src/i.test( cssText ) && + cssText.indexOf( rule.split(' ')[0] ) === 0 + } + ) + + return ret + })(), + + ruby: (function() { + var ruby = $.create( 'ruby' ) + var rt = $.create( 'rt' ) + var rp = $.create( 'rp' ) + var ret + + ruby.appendChild( rp ) + ruby.appendChild( rt ) + root.appendChild( ruby ) + + // Browsers that support ruby hide the `` via `display: none` + ret = ( + getStyle( rp, 'display' ) === 'none' || + // but in IE, `` has `display: inline`, so the test needs other conditions: + getStyle( ruby, 'display' ) === 'ruby' && + getStyle( rt, 'display' ) === 'ruby-text' + ) ? true : false + + // Remove and clean from memory + root.removeChild( ruby ) + ruby = null + rt = null + rp = null + + return ret + })(), + + 'ruby-display': (function() { + var div = $.create( 'div' ) + + div.innerHTML = '' + return div.querySelector( 'h-test-a' ).style.display === 'ruby' && div.querySelector( 'h-test-b' ).style.display === 'ruby-text-container' + })(), + + 'ruby-interchar': (function() { + var IC = 'inter-character' + var div = $.create( 'div' ) + var css + + div.innerHTML = '' + css = div.querySelector( 'h-test' ).style + return css.rubyPosition === IC || css.WebkitRubyPosition === IC || css.MozRubyPosition === IC || css.msRubyPosition === IC + })(), + + textemphasis: testCSSProp( 'textEmphasis' ), + + // Address feature support test for `unicode-range` via + // detecting whether it's Arial (supported) or + // Times New Roman (not supported). + unicoderange: (function() { + var ret + + injectElementWithStyle( + '@font-face{font-family:test-for-unicode-range;src:local(Arial),local("Droid Sans")}@font-face{font-family:test-for-unicode-range;src:local("Times New Roman"),local(Times),local("Droid Serif");unicode-range:U+270C}', + function() { + ret = !Locale.detectFont( + 'test-for-unicode-range', // treatment group + 'Arial, "Droid Sans"', // control group + 'Q' // ASCII characters only + ) + } + ) + return ret + })(), + + writingmode: testCSSProp( 'writingMode' ) + } +})() + +Locale.initCond = function( target ) { + var target = target || root + var ret = '' + var clazz + + for ( var feature in Locale.support ) { + clazz = ( Locale.support[ feature ] ? '' : 'no-' ) + feature + + target.classList.add( clazz ) + ret += clazz + ' ' + } + return ret +} + +var SUPPORT_IC = Locale.support[ 'ruby-interchar' ] + +// 1. Simple ruby polyfill; +// 2. Inter-character polyfill for Zhuyin +function renderSimpleRuby( $ruby ) { + var frag = $.create( '!' ) + var clazz = $ruby.classList + var $rb, $ru + + frag.appendChild( $.clone( $ruby )) + + $ + .tag( 'rt', frag.firstChild ) + .forEach(function( $rt ) { + var $rb = $.create( '!' ) + var airb = [] + var irb + + // Consider the previous nodes the implied + // ruby base + do { + irb = ( irb || $rt ).previousSibling + if ( !irb || irb.nodeName.match( /((?:h\-)?r[ubt])/i )) break + + $rb.insertBefore( $.clone( irb ), $rb.firstChild ) + airb.push( irb ) + } while ( !irb.nodeName.match( /((?:h\-)?r[ubt])/i )) + + // Create a real `` to append. + $ru = clazz.contains( 'zhuyin' ) ? createZhuyinRu( $rb, $rt ) : createNormalRu( $rb, $rt ) + + // Replace the ruby text with the new ``, + // and remove the original implied ruby base(s) + try { + $rt.parentNode.replaceChild( $ru, $rt ) + airb.map( $.remove ) + } catch ( e ) {} + }) + return createCustomRuby( frag ) +} + +function renderInterCharRuby( $ruby ) { + var frag = $.create( '!' ) + frag.appendChild( $.clone( $ruby )) + + $ + .tag( 'rt', frag.firstChild ) + .forEach(function( $rt ) { + var $rb = $.create( '!' ) + var airb = [] + var irb, $zhuyin + + // Consider the previous nodes the implied + // ruby base + do { + irb = ( irb || $rt ).previousSibling + if ( !irb || irb.nodeName.match( /((?:h\-)?r[ubt])/i )) break + + $rb.insertBefore( $.clone( irb ), $rb.firstChild ) + airb.push( irb ) + } while ( !irb.nodeName.match( /((?:h\-)?r[ubt])/i )) + + $zhuyin = $.create( 'rt' ) + $zhuyin.innerHTML = getZhuyinHTML( $rt ) + $rt.parentNode.replaceChild( $zhuyin, $rt ) + }) + return frag.firstChild +} + +// 3. Complex ruby polyfill +// - Double-lined annotation; +// - Right-angled annotation. +function renderComplexRuby( $ruby ) { + var frag = $.create( '!' ) + var clazz = $ruby.classList + var $cloned, $rb, $ru, maxspan + + frag.appendChild( $.clone( $ruby )) + $cloned = frag.firstChild + + $rb = $ru = $.tag( 'rb', $cloned ) + maxspan = $rb.length + + // First of all, deal with Zhuyin containers + // individually + // + // Note that we only support one single Zhuyin + // container in each complex ruby + void function( $rtc ) { + if ( !$rtc ) return + + $ru = $ + .tag( 'rt', $rtc ) + .map(function( $rt, i ) { + if ( !$rb[ i ] ) return + var ret = createZhuyinRu( $rb[ i ], $rt ) + + try { + $rb[ i ].parentNode.replaceChild( ret, $rb[ i ] ) + } catch ( e ) {} + return ret + }) + + // Remove the container once it's useless + $.remove( $rtc ) + $cloned.setAttribute( 'rightangle', 'true' ) + }( $cloned.querySelector( 'rtc.zhuyin' )) + + // Then, normal annotations other than Zhuyin + $ + .qsa( 'rtc:not(.zhuyin)', $cloned ) + .forEach(function( $rtc, order ) { + var ret + ret = $ + .tag( 'rt', $rtc ) + .map(function( $rt, i ) { + var rbspan = Number( $rt.getAttribute( 'rbspan' ) || 1 ) + var span = 0 + var aRb = [] + var $rb, ret + + if ( rbspan > maxspan ) rbspan = maxspan + + do { + try { + $rb = $ru.shift() + aRb.push( $rb ) + } catch (e) {} + + if ( typeof $rb === 'undefined' ) break + span += Number( $rb.getAttribute( 'span' ) || 1 ) + } while ( rbspan > span ) + + if ( rbspan < span ) { + if ( aRb.length > 1 ) { + console.error( 'An impossible `rbspan` value detected.', ruby ) + return + } + aRb = $.tag( 'rb', aRb[0] ) + $ru = aRb.slice( rbspan ).concat( $ru ) + aRb = aRb.slice( 0, rbspan ) + span = rbspan + } + + ret = createNormalRu( aRb, $rt, { + 'class': clazz, + span: span, + order: order + }) + + try { + aRb[0].parentNode.replaceChild( ret, aRb.shift() ) + aRb.map( $.remove ) + } catch (e) {} + return ret + }) + $ru = ret + if ( order === 1 ) $cloned.setAttribute( 'doubleline', 'true' ) + + // Remove the container once it's useless + $.remove( $rtc ) + }) + return createCustomRuby( frag ) +} + +// Create a new fake `` element so the +// style sheets will render it as a polyfill, +// which also helps to avoid the UA style. +function createCustomRuby( frag ) { + var $ruby = frag.firstChild + var hruby = $.create( 'h-ruby' ) + + hruby.innerHTML = $ruby.innerHTML + $.setAttr( hruby, $ruby.attributes ) + hruby.normalize() + return hruby +} + +function simplifyRubyClass( elem ) { + if ( !elem instanceof Element ) return elem + var clazz = elem.classList + + if ( clazz.contains( 'pinyin' )) clazz.add( 'romanization' ) + else if ( clazz.contains( 'romanization' )) clazz.add( 'annotation' ) + else if ( clazz.contains( 'mps' )) clazz.add( 'zhuyin' ) + else if ( clazz.contains( 'rightangle' )) clazz.add( 'complex' ) + return elem +} + +/** + * Create and return a new `` element + * according to the given contents + */ +function createNormalRu( $rb, $rt, attr ) { + var $ru = $.create( 'h-ru' ) + var $rt = $.clone( $rt ) + var attr = attr || {} + attr.annotation = 'true' + + if ( Array.isArray( $rb )) { + $ru.innerHTML = $rb.map(function( rb ) { + if ( typeof rb === 'undefined' ) return '' + return rb.outerHTML + }).join('') + $rt.outerHTML + } else { + $ru.appendChild( $.clone( $rb )) + $ru.appendChild( $rt ) + } + + $.setAttr( $ru, attr ) + return $ru +} + +/** + * Create and return a new `` element + * in Zhuyin form + */ +function createZhuyinRu( $rb, $rt ) { + var $rb = $.clone( $rb ) + + // Create an element to return + var $ru = $.create( 'h-ru' ) + $ru.setAttribute( 'zhuyin', true ) + + // - + // - + // - + // - + // - + // - + // - + $ru.appendChild( $rb ) + $ru.innerHTML += getZhuyinHTML( $rt ) + return $ru +} + +/** + * Create a Zhuyin-form HTML string + */ +function getZhuyinHTML( rt ) { + // #### Explanation #### + // * `zhuyin`: the entire phonetic annotation + // * `yin`: the plain pronunciation (w/out tone) + // * `diao`: the tone + // * `len`: the length of the plain pronunciation (`yin`) + var zhuyin = typeof rt === 'string' ? rt : rt.textContent + var yin, diao, len + + yin = zhuyin.replace( TYPESET.zhuyin.diao, '' ) + len = yin ? yin.length : 0 + diao = zhuyin + .replace( yin, '' ) + .replace( /[\u02C5]/g, '\u02C7' ) + .replace( /[\u030D]/g, '\u0358' ) + return len === 0 ? '' : '' + yin + '' + diao + '' +} + +/** + * Normalize `ruby` elements + */ +$.extend( Locale, { + + // Address normalisation for both simple and complex + // rubies (interlinear annotations) + renderRuby: function( context, target ) { + var target = target || 'ruby' + var $target = $.qsa( target, context ) + + $.qsa( 'rtc', context ) + .concat( $target ).map( simplifyRubyClass ) + + $target + .forEach(function( $ruby ) { + var clazz = $ruby.classList + var $new + + if ( clazz.contains( 'complex' )) $new = renderComplexRuby( $ruby ) + else if ( clazz.contains( 'zhuyin' )) $new = SUPPORT_IC ? renderInterCharRuby( $ruby ) : renderSimpleRuby( $ruby ) + + // Finally, replace it + if ( $new ) $ruby.parentNode.replaceChild( $new, $ruby ) + }) + }, + + simplifyRubyClass: simplifyRubyClass, + getZhuyinHTML: getZhuyinHTML, + renderComplexRuby: renderComplexRuby, + renderSimpleRuby: renderSimpleRuby, + renderInterCharRuby: renderInterCharRuby + + // ### TODO list ### + // + // * Debug mode + // * Better error-tolerance +}) + +/** + * Normalisation rendering mechanism + */ +$.extend( Locale, { + + // Render and normalise the given context by routine: + // + // ruby -> u, ins -> s, del -> em + // + renderElem: function( context ) { + this.renderRuby( context ) + this.renderDecoLine( context ) + this.renderDecoLine( context, 's, del' ) + this.renderEm( context ) + }, + + // Traverse all target elements and address + // presentational corrections if any two of + // them are adjacent to each other. + renderDecoLine: function( context, target ) { + var $$target = $.qsa( target || 'u, ins', context ) + var i = $$target.length + + traverse: while ( i-- ) { + var $this = $$target[ i ] + var $prev = null + + // Ignore all `` and comments in between, + // and add class `.adjacent` once two targets + // are next to each other. + ignore: do { + $prev = ( $prev || $this ).previousSibling + + if ( !$prev ) { + continue traverse + } else if ( $$target[ i-1 ] === $prev ) { + $this.classList.add( 'adjacent' ) + } + } while ( $.isIgnorable( $prev )) + } + }, + + // Traverse all target elements to render + // emphasis marks. + renderEm: function( context, target ) { + var method = target ? 'qsa' : 'tag' + var target = target || 'em' + var $target = $[ method ]( target, context ) + + $target + .forEach(function( elem ) { + var $elem = Han( elem ) + + if ( Locale.support.textemphasis ) { + $elem + .avoid( 'rt, h-char' ) + .charify({ biaodian: true, punct: true }) + } else { + $elem + .avoid( 'rt, h-char, h-char-group' ) + .jinzify() + .groupify({ western: true }) + .charify({ + hanzi: true, + biaodian: true, + punct: true, + latin: true, + ellinika: true, + kirillica: true + }) + } + }) + } +}) + +Han.normalize = Locale +Han.localize = Locale +Han.support = Locale.support +Han.detectFont = Locale.detectFont + +Han.fn.initCond = function() { + this.condition.classList.add( 'han-js-rendered' ) + Han.normalize.initCond( this.condition ) + return this +} + +void [ + 'Elem', + 'DecoLine', + 'Em', + 'Ruby' +].forEach(function( elem ) { + var method = 'render' + elem + + Han.fn[ method ] = function( target ) { + Han.normalize[ method ]( this.context, target ) + return this + } +}) + +$.extend( Han.support, { + // Assume that all devices support Heiti for we + // use `sans-serif` to do the comparison. + heiti: true, + // 'heiti-gb': true, + + songti: Han.detectFont( '"Han Songti"' ), + 'songti-gb': Han.detectFont( '"Han Songti GB"' ), + + kaiti: Han.detectFont( '"Han Kaiti"' ), + // 'kaiti-gb': Han.detectFont( '"Han Kaiti GB"' ), + + fangsong: Han.detectFont( '"Han Fangsong"' ) + // 'fangsong-gb': Han.detectFont( '"Han Fangsong GB"' ) +}) + +Han.correctBiaodian = function( context ) { + var context = context || document + var finder = Han.find( context ) + + finder + .avoid( 'h-char' ) + .replace( /([‘“])/g, function( portion ) { + var $char = Han.createBDChar( portion.text ) + $char.classList.add( 'bd-open', 'punct' ) + return $char + }) + .replace( /([’”])/g, function( portion ) { + var $char = Han.createBDChar( portion.text ) + $char.classList.add( 'bd-close', 'bd-end', 'punct' ) + return $char + }) + + return Han.support.unicoderange + ? finder + : finder.charify({ biaodian: true }) +} + +Han.correctBasicBD = Han.correctBiaodian +Han.correctBD = Han.correctBiaodian + +$.extend( Han.fn, { + biaodian: null, + + correctBiaodian: function() { + this.biaodian = Han.correctBiaodian( this.context ) + return this + }, + + revertCorrectedBiaodian: function() { + try { + this.biaodian.revert( 'all' ) + } catch (e) {} + return this + } +}) + +// Legacy support (deprecated): +Han.fn.correctBasicBD = Han.fn.correctBiaodian +Han.fn.revertBasicBD = Han.fn.revertCorrectedBiaodian + +var hws = '<>' + +var $hws = $.create( 'h-hws' ) +$hws.setAttribute( 'hidden', '' ) +$hws.innerHTML = ' ' + +function sharingSameParent( $a, $b ) { + return $a && $b && $a.parentNode === $b.parentNode +} + +function properlyPlaceHWSBehind( $node, text ) { + var $elmt = $node + var text = text || '' + + if ( + $.isElmt( $node.nextSibling ) || + sharingSameParent( $node, $node.nextSibling ) + ) { + return text + hws + } else { + // One of the parental elements of the current text + // node would definitely have a next sibling, since + // it is of the first portion and not `isEnd`. + while ( !$elmt.nextSibling ) { + $elmt = $elmt.parentNode + } + if ( $node !== $elmt ) { + $elmt.insertAdjacentHTML( 'afterEnd', '' ) + } + } + return text +} + +function firstStepLabel( portion, mat ) { + return portion.isEnd && portion.index === 0 + ? mat[1] + hws + mat[2] + : portion.index === 0 + ? properlyPlaceHWSBehind( portion.node, portion.text ) + : portion.text +} + +function real$hwsElmt( portion ) { + return portion.index === 0 + ? $.clone( $hws ) + : '' +} + +var last$hwsIdx + +function apostrophe( portion ) { + var $elmt = portion.node.parentNode + + if ( portion.index === 0 ) { + last$hwsIdx = portion.endIndexInNode-2 + } + + if ( + $elmt.nodeName.toLowerCase() === 'h-hws' && ( + portion.index === 1 || portion.indexInMatch === last$hwsIdx + )) { + $elmt.classList.add( 'quote-inner' ) + } + return portion.text +} + +function curveQuote( portion ) { + var $elmt = portion.node.parentNode + + if ( $elmt.nodeName.toLowerCase() === 'h-hws' ) { + $elmt.classList.add( 'quote-outer' ) + } + return portion.text +} + +$.extend( Han, { + renderHWS: function( context, strict ) { + // Elements to be filtered according to the + // HWS rendering mode. + var AVOID = strict + ? 'textarea, code, kbd, samp, pre' + : 'textarea' + + var mode = strict ? 'strict' : 'base' + var context = context || document + var finder = Han.find( context ) + + finder + .avoid( AVOID ) + + // Basic situations: + // - 字a => 字a + // - A字 => A字 + .replace( Han.TYPESET.hws[ mode ][0], firstStepLabel ) + .replace( Han.TYPESET.hws[ mode ][1], firstStepLabel ) + + // Convert text nodes `` into real element nodes: + .replace( new RegExp( '(' + hws + ')+', 'g' ), real$hwsElmt ) + + // Deal with: + // - '' => '字' + // - "" => "字" + .replace( /([\'"])\s(.+?)\s\1/g, apostrophe ) + + // Deal with: + // - “字” + // - ‘字’ + .replace( /\s[‘“]/g, curveQuote ) + .replace( /[’”]\s/g, curveQuote ) + .normalize() + + // Return the finder instance for future usage + return finder + } +}) + +$.extend( Han.fn, { + renderHWS: function( strict ) { + Han.renderHWS( this.context, strict ) + return this + }, + + revertHWS: function() { + $.tag( 'h-hws', this.context ) + .forEach(function( hws ) { + $.remove( hws ) + }) + this.HWS = [] + return this + } +}) + +var HANGABLE_CLASS = 'bd-hangable' +var HANGABLE_AVOID = 'h-char.bd-hangable' +var HANGABLE_CS_HTML = '' + +var matches = Han.find.matches + +function detectSpaceFont() { + var div = $.create( 'div' ) + var ret + + div.innerHTML = 'a ba b' + body.appendChild( div ) + ret = div.firstChild.offsetWidth !== div.lastChild.offsetWidth + $.remove( div ) + return ret +} + +function insertHangableCS( $jinze ) { + var $cs = $jinze.nextSibling + + if ( $cs && matches( $cs, 'h-cs.jinze-outer' )) { + $cs.classList.add( 'hangable-outer' ) + } else { + $jinze.insertAdjacentHTML( + 'afterend', + HANGABLE_CS_HTML + ) + } +} + +Han.support['han-space'] = detectSpaceFont() + +$.extend( Han, { + detectSpaceFont: detectSpaceFont, + isSpaceFontLoaded: detectSpaceFont(), + + renderHanging: function( context ) { + var context = context || document + var finder = Han.find( context ) + + finder + .avoid( 'textarea, code, kbd, samp, pre' ) + .avoid( HANGABLE_AVOID ) + .replace( + TYPESET.jinze.hanging, + function( portion ) { + if ( /^[\x20\t\r\n\f]+$/.test( portion.text )) { + return '' + } + + var $elmt = portion.node.parentNode + var $jinze, $new, $bd, biaodian + + if ( $jinze = $.parent( $elmt, 'h-jinze' )) { + insertHangableCS( $jinze ) + } + + biaodian = portion.text.trim() + + $new = Han.createBDChar( biaodian ) + $new.innerHTML = '' + biaodian + '' + $new.classList.add( HANGABLE_CLASS ) + + $bd = $.parent( $elmt, 'h-char.biaodian' ) + + return !$bd + ? $new + : (function() { + $bd.classList.add( HANGABLE_CLASS ) + + return matches( $elmt, 'h-inner, h-inner *' ) + ? biaodian + : $new.firstChild + })() + } + ) + return finder + } +}) + +$.extend( Han.fn, { + renderHanging: function() { + var classList = this.condition.classList + Han.isSpaceFontLoaded = detectSpaceFont() + + if ( + Han.isSpaceFontLoaded && + classList.contains( 'no-han-space' ) + ) { + classList.remove( 'no-han-space' ) + classList.add( 'han-space' ) + } + + Han.renderHanging( this.context ) + return this + }, + + revertHanging: function() { + $.qsa( + 'h-char.bd-hangable, h-cs.hangable-outer', + this.context + ).forEach(function( $elmt ) { + var classList = $elmt.classList + classList.remove( 'bd-hangable' ) + classList.remove( 'hangable-outer' ) + }) + return this + } +}) + +var JIYA_CLASS = 'bd-jiya' +var JIYA_AVOID = 'h-char.bd-jiya' +var CONSECUTIVE_CLASS = 'bd-consecutive' +var JIYA_CS_HTML = '' + +var matches = Han.find.matches + +function trimBDClass( clazz ) { + return clazz.replace( + /(biaodian|cjk|bd-jiya|bd-consecutive|bd-hangable)/gi, '' + ).trim() +} + +function charifyBiaodian( portion ) { + var biaodian = portion.text + var $elmt = portion.node.parentNode + var $bd = $.parent( $elmt, 'h-char.biaodian' ) + var $new = Han.createBDChar( biaodian ) + var $jinze + + $new.innerHTML = '' + biaodian + '' + $new.classList.add( JIYA_CLASS ) + + if ( $jinze = $.parent( $elmt, 'h-jinze' )) { + insertJiyaCS( $jinze ) + } + + return !$bd + ? $new + : (function() { + $bd.classList.add( JIYA_CLASS ) + + return matches( $elmt, 'h-inner, h-inner *' ) + ? biaodian + : $new.firstChild + })() +} + +var prevBDType, $$prevCS + +function locateConsecutiveBD( portion ) { + var prev = prevBDType + var $elmt = portion.node.parentNode + var $bd = $.parent( $elmt, 'h-char.biaodian' ) + var $jinze = $.parent( $bd, 'h-jinze' ) + var classList + + classList = $bd.classList + + if ( prev ) { + $bd.setAttribute( 'prev', prev ) + } + + if ( $$prevCS && classList.contains( 'bd-open' )) { + $$prevCS.pop().setAttribute( 'next', 'bd-open' ) + } + + $$prevCS = undefined + + if ( portion.isEnd ) { + prevBDType = undefined + classList.add( CONSECUTIVE_CLASS, 'end-portion' ) + } else { + prevBDType = trimBDClass($bd.getAttribute( 'class' )) + classList.add( CONSECUTIVE_CLASS ) + } + + if ( $jinze ) { + $$prevCS = locateCS( $jinze, { + prev: prev, + 'class': trimBDClass($bd.getAttribute( 'class' )) + }) + } + return portion.text +} + +function insertJiyaCS( $jinze ) { + if ( + matches( $jinze, '.tou, .touwei' ) && + !matches( $jinze.previousSibling, 'h-cs.jiya-outer' ) + ) { + $jinze.insertAdjacentHTML( 'beforebegin', JIYA_CS_HTML ) + } + if ( + matches( $jinze, '.wei, .touwei' ) && + !matches( $jinze.nextSibling, 'h-cs.jiya-outer' ) + ) { + $jinze.insertAdjacentHTML( 'afterend', JIYA_CS_HTML ) + } +} + +function locateCS( $jinze, attr ) { + var $prev, $next + + if (matches( $jinze, '.tou, .touwei' )) { + $prev = $jinze.previousSibling + + if (matches( $prev, 'h-cs' )) { + $prev.className = 'jinze-outer jiya-outer' + $prev.setAttribute( 'prev', attr.prev ) + } + } + if (matches( $jinze, '.wei, .touwei' )) { + $next = $jinze.nextSibling + + if (matches( $next, 'h-cs' )) { + $next.className = 'jinze-outer jiya-outer ' + attr[ 'class' ] + $next.removeAttribute( 'prev' ) + } + } + return [ $prev, $next ] +} + +Han.renderJiya = function( context ) { + var context = context || document + var finder = Han.find( context ) + + finder + .avoid( 'textarea, code, kbd, samp, pre, h-cs' ) + + .avoid( JIYA_AVOID ) + .charify({ + avoid: false, + biaodian: charifyBiaodian + }) + // End avoiding `JIYA_AVOID`: + .endAvoid() + + .avoid( 'textarea, code, kbd, samp, pre, h-cs' ) + .replace( TYPESET.group.biaodian[0], locateConsecutiveBD ) + .replace( TYPESET.group.biaodian[1], locateConsecutiveBD ) + + return finder +} + +$.extend( Han.fn, { + renderJiya: function() { + Han.renderJiya( this.context ) + return this + }, + + revertJiya: function() { + $.qsa( + 'h-char.bd-jiya, h-cs.jiya-outer', + this.context + ).forEach(function( $elmt ) { + var classList = $elmt.classList + classList.remove( 'bd-jiya' ) + classList.remove( 'jiya-outer' ) + }) + return this + } +}) + +var QUERY_RU_W_ANNO = 'h-ru[annotation]' +var SELECTOR_TO_IGNORE = 'textarea, code, kbd, samp, pre' + +function createCompareFactory( font, treat, control ) { + return function() { + var a = Han.localize.writeOnCanvas( treat, font ) + var b = Han.localize.writeOnCanvas( control, font ) + return Han.localize.compareCanvases( a, b ) + } +} + +function isVowelCombLigaNormal() { + return createCompareFactory( '"Romanization Sans"', '\u0061\u030D', '\uDB80\uDC61' ) +} + +function isVowelICombLigaNormal() { + return createCompareFactory( '"Romanization Sans"', '\u0069\u030D', '\uDB80\uDC69' ) +} + +function isZhuyinCombLigaNormal() { + return createCompareFactory( '"Zhuyin Kaiti"', '\u31B4\u0358', '\uDB8C\uDDB4' ) +} + +function createSubstFactory( regexToSubst ) { + return function( context ) { + var context = context || document + var finder = Han.find( context ).avoid( SELECTOR_TO_IGNORE ) + + regexToSubst + .forEach(function( pattern ) { + finder + .replace( + new RegExp( pattern[ 0 ], 'ig' ), + function( portion, match ) { + var ret = $.clone( charCombLiga ) + + // Put the original content in an inner container + // for better presentational effect of hidden text + ret.innerHTML = '' + match[0] + '' + ret.setAttribute( 'display-as', pattern[ 1 ] ) + return portion.index === 0 ? ret : '' + } + ) + }) + return finder + } +} + +var charCombLiga = $.create( 'h-char', 'comb-liga' ) + +$.extend( Han, { + isVowelCombLigaNormal: isVowelCombLigaNormal(), + isVowelICombLigaNormal: isVowelICombLigaNormal(), + isZhuyinCombLigaNormal: isZhuyinCombLigaNormal(), + + isCombLigaNormal: isVowelICombLigaNormal()(), // ### Deprecated + + substVowelCombLiga: createSubstFactory( Han.TYPESET[ 'display-as' ][ 'comb-liga-vowel' ] ), + substZhuyinCombLiga: createSubstFactory( Han.TYPESET[ 'display-as' ][ 'comb-liga-zhuyin' ] ), + substCombLigaWithPUA: createSubstFactory( Han.TYPESET[ 'display-as' ][ 'comb-liga-pua' ] ), + + substInaccurateChar: function( context ) { + var context = context || document + var finder = Han.find( context ) + + finder.avoid( SELECTOR_TO_IGNORE ) + + Han.TYPESET[ 'inaccurate-char' ] + .forEach(function( pattern ) { + finder + .replace( + new RegExp( pattern[ 0 ], 'ig' ), + pattern[ 1 ] + ) + }) + } +}) + +$.extend( Han.fn, { + 'comb-liga-vowel': null, + 'comb-liga-vowel-i': null, + 'comb-liga-zhuyin': null, + 'inaccurate-char': null, + + substVowelCombLiga: function() { + this['comb-liga-vowel'] = Han.substVowelCombLiga( this.context ) + return this + }, + + substVowelICombLiga: function() { + this['comb-liga-vowel-i'] = Han.substVowelICombLiga( this.context ) + return this + }, + + substZhuyinCombLiga: function() { + this['comb-liga-zhuyin'] = Han.substZhuyinCombLiga( this.context ) + return this + }, + + substCombLigaWithPUA: function() { + if ( !Han.isVowelCombLigaNormal()) { + this['comb-liga-vowel'] = Han.substVowelCombLiga( this.context ) + } else if ( !Han.isVowelICombLigaNormal()) { + this['comb-liga-vowel-i'] = Han.substVowelICombLiga( this.context ) + } + + if ( !Han.isZhuyinCombLigaNormal()) { + this['comb-liga-zhuyin'] = Han.substZhuyinCombLiga( this.context ) + } + return this + }, + + revertVowelCombLiga: function() { + try { + this['comb-liga-vowel'].revert( 'all' ) + } catch (e) {} + return this + }, + + revertVowelICombLiga: function() { + try { + this['comb-liga-vowel-i'].revert( 'all' ) + } catch (e) {} + return this + }, + + revertZhuyinCombLiga: function() { + try { + this['comb-liga-zhuyin'].revert( 'all' ) + } catch (e) {} + return this + }, + + revertCombLigaWithPUA: function() { + try { + this['comb-liga-vowel'].revert( 'all' ) + this['comb-liga-vowel-i'].revert( 'all' ) + this['comb-liga-zhuyin'].revert( 'all' ) + } catch (e) {} + return this + }, + + substInaccurateChar: function() { + this['inaccurate-char'] = Han.substInaccurateChar( this.context ) + return this + }, + + revertInaccurateChar: function() { + try { + this['inaccurate-char'].revert( 'all' ) + } catch (e) {} + return this + } +}) + +window.addEventListener( 'DOMContentLoaded', function() { + var initContext + + // Use the shortcut under the default situation + if ( root.classList.contains( 'han-init' )) { + Han.init() + + // Consider ‘a configured context’ the special + // case of the default situation. Will have to + // replace the `Han.init` with the instance as + // well (for future usage). + } else if ( initContext = document.querySelector( '.han-init-context' )) { + Han.init = Han( initContext ).render() + } +}) + +// Expose to global namespace +if ( typeof noGlobalNS === 'undefined' || noGlobalNS === false ) { + window.Han = Han +} + +return Han +}); + diff --git a/lib/Han/dist/han.min.css b/lib/Han/dist/han.min.css index e69de29b..29c753ea 100644 --- a/lib/Han/dist/han.min.css +++ b/lib/Han/dist/han.min.css @@ -0,0 +1,6 @@ +@charset "UTF-8"; + +/*! 漢字標準格式 v3.3.0 | MIT License | css.hanzi.co */ +/*! Han.css: the CSS typography framework optimised for Hanzi */ + +progress,sub,sup{vertical-align:baseline}button,hr,input,select{overflow:visible}[type=checkbox],[type=radio],legend{box-sizing:border-box;padding:0}html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}img{border-style:none}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}button,input,select,textarea{font:inherit;margin:0}optgroup{font-weight:700}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{cursor:pointer}[disabled]{cursor:default}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}button:-moz-focusring,input:-moz-focusring{outline:ButtonText dotted 1px}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{color:inherit;display:table;max-width:100%;white-space:normal}textarea{overflow:auto}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}@font-face{font-family:"Han Heiti";src:local("Hiragino Sans GB"),local("Lantinghei TC Extralight"),local("Lantinghei SC Extralight"),local(FZLTXHB--B51-0),local(FZLTZHK--GBK1-0),local("Pingfang SC Light"),local("Pingfang TC Light"),local("Pingfang-SC-Light"),local("Pingfang-TC-Light"),local("Pingfang SC"),local("Pingfang TC"),local("Heiti SC Light"),local(STHeitiSC-Light),local("Heiti SC"),local("Heiti TC Light"),local(STHeitiTC-Light),local("Heiti TC"),local("Microsoft Yahei"),local("Microsoft Jhenghei"),local("Noto Sans CJK KR"),local("Noto Sans CJK JP"),local("Noto Sans CJK SC"),local("Noto Sans CJK TC"),local("Source Han Sans K"),local("Source Han Sans KR"),local("Source Han Sans JP"),local("Source Han Sans CN"),local("Source Han Sans HK"),local("Source Han Sans TW"),local("Source Han Sans TWHK"),local("Droid Sans Fallback")}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Heiti";src:local(YuGothic),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro")}@font-face{font-family:"Han Heiti CNS";src:local("Pingfang TC Light"),local("Pingfang-TC-Light"),local("Pingfang TC"),local("Heiti TC Light"),local(STHeitiTC-Light),local("Heiti TC"),local("Lantinghei TC Extralight"),local(FZLTXHB--B51-0),local("Lantinghei TC"),local("Microsoft Jhenghei"),local("Microsoft Yahei"),local("Noto Sans CJK TC"),local("Source Han Sans TC"),local("Source Han Sans TW"),local("Source Han Sans TWHK"),local("Source Han Sans HK"),local("Droid Sans Fallback")}@font-face{font-family:"Han Heiti GB";src:local("Hiragino Sans GB"),local("Pingfang SC Light"),local("Pingfang-SC-Light"),local("Pingfang SC"),local("Lantinghei SC Extralight"),local(FZLTXHK--GBK1-0),local("Lantinghei SC"),local("Heiti SC Light"),local(STHeitiSC-Light),local("Heiti SC"),local("Microsoft Yahei"),local("Noto Sans CJK SC"),local("Source Han Sans SC"),local("Source Han Sans CN"),local("Droid Sans Fallback")}@font-face{font-family:"Han Heiti";font-weight:600;src:local("Hiragino Sans GB W6"),local(HiraginoSansGB-W6),local("Lantinghei TC Demibold"),local("Lantinghei SC Demibold"),local(FZLTZHB--B51-0),local(FZLTZHK--GBK1-0),local("Pingfang-SC-Semibold"),local("Pingfang-TC-Semibold"),local("Heiti SC Medium"),local("STHeitiSC-Medium"),local("Heiti SC"),local("Heiti TC Medium"),local("STHeitiTC-Medium"),local("Heiti TC"),local("Microsoft Yahei Bold"),local("Microsoft Jhenghei Bold"),local(MicrosoftYahei-Bold),local(MicrosoftJhengHeiBold),local("Microsoft Yahei"),local("Microsoft Jhenghei"),local("Noto Sans CJK KR Bold"),local("Noto Sans CJK JP Bold"),local("Noto Sans CJK SC Bold"),local("Noto Sans CJK TC Bold"),local(NotoSansCJKkr-Bold),local(NotoSansCJKjp-Bold),local(NotoSansCJKsc-Bold),local(NotoSansCJKtc-Bold),local("Source Han Sans K Bold"),local(SourceHanSansK-Bold),local("Source Han Sans K"),local("Source Han Sans KR Bold"),local("Source Han Sans JP Bold"),local("Source Han Sans CN Bold"),local("Source Han Sans HK Bold"),local("Source Han Sans TW Bold"),local("Source Han Sans TWHK Bold"),local("SourceHanSansKR-Bold"),local("SourceHanSansJP-Bold"),local("SourceHanSansCN-Bold"),local("SourceHanSansHK-Bold"),local("SourceHanSansTW-Bold"),local("SourceHanSansTWHK-Bold"),local("Source Han Sans KR"),local("Source Han Sans CN"),local("Source Han Sans HK"),local("Source Han Sans TW"),local("Source Han Sans TWHK")}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Heiti";font-weight:600;src:local("YuGothic Bold"),local("Hiragino Kaku Gothic ProN W6"),local("Hiragino Kaku Gothic Pro W6"),local(YuGo-Bold),local(HiraKakuProN-W6),local(HiraKakuPro-W6)}@font-face{font-family:"Han Heiti CNS";font-weight:600;src:local("Pingfang TC Semibold"),local("Pingfang-TC-Semibold"),local("Heiti TC Medium"),local("STHeitiTC-Medium"),local("Heiti TC"),local("Lantinghei TC Demibold"),local(FZLTXHB--B51-0),local("Microsoft Jhenghei Bold"),local(MicrosoftJhengHeiBold),local("Microsoft Jhenghei"),local("Microsoft Yahei Bold"),local(MicrosoftYahei-Bold),local("Noto Sans CJK TC Bold"),local(NotoSansCJKtc-Bold),local("Noto Sans CJK TC"),local("Source Han Sans TC Bold"),local("SourceHanSansTC-Bold"),local("Source Han Sans TC"),local("Source Han Sans TW Bold"),local("SourceHanSans-TW"),local("Source Han Sans TW"),local("Source Han Sans TWHK Bold"),local("SourceHanSans-TWHK"),local("Source Han Sans TWHK"),local("Source Han Sans HK"),local("SourceHanSans-HK"),local("Source Han Sans HK")}@font-face{font-family:"Han Heiti GB";font-weight:600;src:local("Hiragino Sans GB W6"),local(HiraginoSansGB-W6),local("Pingfang SC Semibold"),local("Pingfang-SC-Semibold"),local("Lantinghei SC Demibold"),local(FZLTZHK--GBK1-0),local("Heiti SC Medium"),local("STHeitiSC-Medium"),local("Heiti SC"),local("Microsoft Yahei Bold"),local(MicrosoftYahei-Bold),local("Microsoft Yahei"),local("Noto Sans CJK SC Bold"),local(NotoSansCJKsc-Bold),local("Noto Sans CJK SC"),local("Source Han Sans SC Bold"),local("SourceHanSansSC-Bold"),local("Source Han Sans CN Bold"),local("SourceHanSansCN-Bold"),local("Source Han Sans SC"),local("Source Han Sans CN")}@font-face{font-family:"Han Songti";src:local("Songti SC Regular"),local(STSongti-SC-Regular),local("Songti SC"),local("Songti TC Regular"),local(STSongti-TC-Regular),local("Songti TC"),local(STSong),local("Lisong Pro"),local(SimSun),local(PMingLiU)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Songti";src:local(YuMincho),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("MS Mincho")}@font-face{font-family:"Han Songti CNS";src:local("Songti TC Regular"),local(STSongti-TC-Regular),local("Songti TC"),local("Lisong Pro"),local("Songti SC Regular"),local(STSongti-SC-Regular),local("Songti SC"),local(STSong),local(PMingLiU),local(SimSun)}@font-face{font-family:"Han Songti GB";src:local("Songti SC Regular"),local(STSongti-SC-Regular),local("Songti SC"),local(STSong),local(SimSun),local(PMingLiU)}@font-face{font-family:"Han Songti";font-weight:600;src:local("STSongti SC Bold"),local("STSongti TC Bold"),local(STSongti-SC-Bold),local(STSongti-TC-Bold),local("STSongti SC"),local("STSongti TC")}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Songti";font-weight:600;src:local("YuMincho Demibold"),local("Hiragino Mincho ProN W6"),local("Hiragino Mincho Pro W6"),local(YuMin-Demibold),local(HiraMinProN-W6),local(HiraMinPro-W6),local(YuMincho),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro")}@font-face{font-family:"Han Songti CNS";font-weight:600;src:local("STSongti TC Bold"),local("STSongti SC Bold"),local(STSongti-TC-Bold),local(STSongti-SC-Bold),local("STSongti TC"),local("STSongti SC")}@font-face{font-family:"Han Songti GB";font-weight:600;src:local("STSongti SC Bold"),local(STSongti-SC-Bold),local("STSongti SC")}@font-face{font-family:cursive;src:local("Kaiti TC Regular"),local(STKaiTi-TC-Regular),local("Kaiti TC"),local("Kaiti SC"),local(STKaiti),local(BiauKai),local("標楷體"),local(DFKaiShu-SB-Estd-BF),local(Kaiti),local(DFKai-SB)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Kaiti";src:local("Kaiti TC Regular"),local(STKaiTi-TC-Regular),local("Kaiti TC"),local("Kaiti SC"),local(STKaiti),local(BiauKai),local("標楷體"),local(DFKaiShu-SB-Estd-BF),local(Kaiti),local(DFKai-SB)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Kaiti CNS";src:local(BiauKai),local("標楷體"),local(DFKaiShu-SB-Estd-BF),local("Kaiti TC Regular"),local(STKaiTi-TC-Regular),local("Kaiti TC")}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Kaiti GB";src:local("Kaiti SC Regular"),local(STKaiTi-SC-Regular),local("Kaiti SC"),local(STKaiti),local(Kai),local(Kaiti),local(DFKai-SB)}@font-face{font-family:cursive;font-weight:600;src:local("Kaiti TC Bold"),local(STKaiTi-TC-Bold),local("Kaiti SC Bold"),local(STKaiti-SC-Bold),local("Kaiti TC"),local("Kaiti SC")}@font-face{font-family:"Han Kaiti";font-weight:600;src:local("Kaiti TC Bold"),local(STKaiTi-TC-Bold),local("Kaiti SC Bold"),local(STKaiti-SC-Bold),local("Kaiti TC"),local("Kaiti SC")}@font-face{font-family:"Han Kaiti CNS";font-weight:600;src:local("Kaiti TC Bold"),local(STKaiTi-TC-Bold),local("Kaiti TC")}@font-face{font-family:"Han Kaiti GB";font-weight:600;src:local("Kaiti SC Bold"),local(STKaiti-SC-Bold)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Fangsong";src:local(STFangsong),local(FangSong)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Fangsong CNS";src:local(STFangsong),local(FangSong)}@font-face{unicode-range:U+4E00-9FFF,U+3400-4DB5,U+20000-2A6D6,U+2A700-2B734,U+2B740-2B81D,U+FA0E-FA0F,U+FA11,U+FA13-FA14,U+FA1F,U+FA21,U+FA23,U+FA24,U+FA27-FA29,U+3040-309F,U+30A0-30FF,U+3099-309E,U+FF66-FF9F,U+3007,U+31C0-31E3,U+2F00-2FD5,U+2E80-2EF3;font-family:"Han Fangsong GB";src:local(STFangsong),local(FangSong)}@font-face{font-family:"Biaodian Sans";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local("MS Gothic"),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Serif";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Sans";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local("MS Gothic"),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Serif";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local("MS Gothic"),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Serif CNS";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Sans GB";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local("MS Gothic"),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local(SimSun);unicode-range:U+FF0E}@font-face{font-family:"Biaodian Sans";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Serif";src:local("Songti SC"),local(STSong),local("Heiti SC"),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Sans";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Serif";src:local("Songti SC"),local(STSong),local("Heiti SC"),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Serif CNS";src:local("Songti SC"),local(STSong),local("Heiti SC"),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Sans GB";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Songti SC"),local(STSong),local("Heiti SC"),local(SimSun);unicode-range:U+00B7}@font-face{font-family:"Biaodian Sans";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Serif";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Yakumono Sans";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Arial Unicode MS"),local("MS Gothic");unicode-range:U+2014}@font-face{font-family:"Yakumono Serif";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("MS Mincho"),local("Microsoft Yahei");unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Sans";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Serif";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Sans CNS";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Serif CNS";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Sans GB";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Pro Serif GB";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSong),local("Microsoft Yahei"),local(SimSun);unicode-range:U+2014}@font-face{font-family:"Biaodian Sans";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(Meiryo),local("MS Gothic"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Serif";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local("MS Mincho"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Yakumono Sans";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(Meiryo),local("MS Gothic");unicode-range:U+2026}@font-face{font-family:"Yakumono Serif";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("MS Mincho");unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Sans";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Serif";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Sans CNS";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Serif CNS";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSongti),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Sans GB";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Sans GB"),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Serif GB";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype"),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Songti SC"),local(STSongti),local(SimSun),local(PMingLiU);unicode-range:U+2026}@font-face{font-family:"Biaodian Pro Sans GB";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun),local(PMingLiU);unicode-range:U+201C-201D,U+2018-2019}@font-face{font-family:"Biaodian Pro Sans GB";font-weight:700;src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun),local(PMingLiU);unicode-range:U+201C-201D,U+2018-2019}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Lisong Pro"),local("Heiti SC"),local(STHeiti),local(SimSun),local(PMingLiU);unicode-range:U+201C-201D,U+2018-2019}@font-face{font-family:"Biaodian Pro Serif GB";font-weight:700;src:local("Lisong Pro"),local("Heiti SC"),local(STHeiti),local(SimSun),local(PMingLiU);unicode-range:U+201C-201D,U+2018-2019}@font-face{font-family:"Biaodian Sans";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Serif";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Sans";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Serif";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Sans CNS";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Serif CNS";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Sans GB";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Serif GB";src:local(Georgia),local("Times New Roman"),local(Arial),local("Droid Sans Fallback");unicode-range:U+25CF}@font-face{font-family:"Biaodian Pro Sans";src:local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("MS Gothic");unicode-range:U+3002,U+FF0C,U+3001,U+FF1B,U+FF1A,U+FF1F,U+FF01,U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Serif";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("MS Mincho");unicode-range:U+3002,U+FF0C,U+3001,U+FF1B,U+FF1A,U+FF1F,U+FF01,U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Heiti TC"),local("Lihei Pro"),local("Microsoft Jhenghei"),local(PMingLiU);unicode-range:U+3002,U+FF0C,U+3001}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Heiti TC"),local("Lihei Pro"),local("Microsoft Jhenghei"),local(PMingLiU),local("MS Gothic");unicode-range:U+FF1B,U+FF1A,U+FF1F,U+FF01}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("MS Mincho");unicode-range:U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Serif CNS";src:local(STSongti-TC-Regular),local("Lisong Pro"),local("Heiti TC"),local(PMingLiU);unicode-range:U+3002,U+FF0C,U+3001}@font-face{font-family:"Biaodian Pro Serif CNS";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local(PMingLiU),local("MS Mincho");unicode-range:U+FF1B,U+FF1A,U+FF1F,U+FF01,U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Sans GB";src:local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local(SimSun),local("MS Gothic");unicode-range:U+3002,U+FF0C,U+3001,U+FF1B,U+FF1A,U+FF1F,U+FF01,U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Songti SC"),local(STSongti),local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Hiragino Sans GB"),local("Heiti SC"),local(STHeiti),local(SimSun),local("MS Mincho");unicode-range:U+3002,U+FF0C,U+3001,U+FF1B,U+FF1A,U+FF1F,U+FF01}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local(PMingLiU),local("MS Mincho");unicode-range:U+FF0D,U+FF0F,U+FF3C}@font-face{font-family:"Biaodian Pro Sans";src:local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Yu Gothic"),local(YuGothic),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Pro Serif";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Yu Mincho"),local(YuMincho),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Pro Sans CNS";src:local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Yu Gothic"),local(YuGothic),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Pro Serif CNS";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Yu Mincho"),local(YuMincho),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Pro Sans GB";src:local("Hiragino Kaku Gothic ProN"),local("Hiragino Kaku Gothic Pro"),local("Yu Gothic"),local(YuGothic),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Pro Serif GB";src:local("Hiragino Mincho ProN"),local("Hiragino Mincho Pro"),local("Yu Mincho"),local(YuMincho),local(SimSun),local(PMingLiU);unicode-range:U+300C-300F,U+300A-300B,U+3008-3009,U+FF08-FF09,U+3014-3015}@font-face{font-family:"Biaodian Basic";src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Basic";font-weight:700;src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Sans";font-weight:700;src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Sans";font-weight:700;src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Sans";font-weight:700;src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Sans CNS";font-weight:700;src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Sans GB";font-weight:700;src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Serif";font-weight:700;src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Serif CNS";font-weight:700;src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Biaodian Pro Serif GB";font-weight:700;src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+2014,U+2026,U+00B7}@font-face{font-family:"Latin Italic Serif";src:local("Georgia Italic"),local("Times New Roman Italic"),local(Georgia-Italic),local(TimesNewRomanPS-ItalicMT),local(Times-Italic)}@font-face{font-family:"Latin Italic Serif";font-weight:700;src:local("Georgia Bold Italic"),local("Times New Roman Bold Italic"),local(Georgia-BoldItalic),local(TimesNewRomanPS-BoldItalicMT),local(Times-Italic)}@font-face{font-family:"Latin Italic Sans";src:local("Helvetica Neue Italic"),local("Helvetica Oblique"),local("Arial Italic"),local(HelveticaNeue-Italic),local(Helvetica-LightOblique),local(Arial-ItalicMT)}@font-face{font-family:"Latin Italic Sans";font-weight:700;src:local("Helvetica Neue Bold Italic"),local("Helvetica Bold Oblique"),local("Arial Bold Italic"),local(HelveticaNeue-BoldItalic),local(Helvetica-BoldOblique),local(Arial-BoldItalicMT)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral TF Sans";src:local(Skia),local("Neutraface 2 Text"),local(Candara),local(Corbel)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral TF Serif";src:local(Georgia),local("Hoefler Text"),local("Big Caslon")}@font-face{unicode-range:U+0030-0039;font-family:"Numeral TF Italic Serif";src:local("Georgia Italic"),local("Hoefler Text Italic"),local(Georgia-Italic),local(HoeflerText-Italic)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Sans";src:local("Helvetica Neue"),local(Helvetica),local(Arial)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Italic Sans";src:local("Helvetica Neue Italic"),local("Helvetica Oblique"),local("Arial Italic"),local(HelveticaNeue-Italic),local(Helvetica-LightOblique),local(Arial-ItalicMT)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Italic Sans";font-weight:700;src:local("Helvetica Neue Bold Italic"),local("Helvetica Bold Oblique"),local("Arial Bold Italic"),local(HelveticaNeue-BoldItalic),local(Helvetica-BoldOblique),local(Arial-BoldItalicMT)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Serif";src:local(Palatino),local("Palatino Linotype"),local("Times New Roman")}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Italic Serif";src:local("Palatino Italic"),local("Palatino Italic Linotype"),local("Times New Roman Italic"),local(Palatino-Italic),local(Palatino-Italic-Linotype),local(TimesNewRomanPS-ItalicMT)}@font-face{unicode-range:U+0030-0039;font-family:"Numeral LF Italic Serif";font-weight:700;src:local("Palatino Bold Italic"),local("Palatino Bold Italic Linotype"),local("Times New Roman Bold Italic"),local(Palatino-BoldItalic),local(Palatino-BoldItalic-Linotype),local(TimesNewRomanPS-BoldItalicMT)}@font-face{src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+3105-312D,U+31A0-31BA,U+02D9,U+02CA,U+02C5,U+02C7,U+02CB,U+02EA-02EB,U+0307,U+030D,U+0358,U+F31B4-F31B7,U+F0061,U+F0065,U+F0069,U+F006F,U+F0075;font-family:"Zhuyin Kaiti"}@font-face{unicode-range:U+3105-312D,U+31A0-31BA,U+02D9,U+02CA,U+02C5,U+02C7,U+02CB,U+02EA-02EB,U+0307,U+030D,U+0358,U+F31B4-F31B7,U+F0061,U+F0065,U+F0069,U+F006F,U+F0075;font-family:"Zhuyin Heiti";src:local("Hiragino Sans GB"),local("Heiti TC"),local("Microsoft Jhenghei"),url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype")}@font-face{font-family:"Zhuyin Heiti";src:local("Heiti TC"),local("Microsoft Jhenghei"),url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");unicode-range:U+3127}@font-face{src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");font-family:"Zhuyin Heiti";unicode-range:U+02D9,U+02CA,U+02C5,U+02C7,U+02CB,U+02EA-02EB,U+31B4,U+31B5,U+31B6,U+31B7,U+0307,U+030D,U+0358,U+F31B4-F31B7,U+F0061,U+F0065,U+F0069,U+F006F,U+F0075}@font-face{src:url(./font/han.woff2?v3.3.0) format("woff2"),url(./font/han.woff?v3.3.0) format("woff"),url(./font/han.otf?v3.3.0) format("opentype");font-family:"Romanization Sans";unicode-range:U+0307,U+030D,U+0358,U+F31B4-F31B7,U+F0061,U+F0065,U+F0069,U+F006F,U+F0075}article strong :lang(ja-Latn),article strong :lang(zh-Latn),article strong :not(:lang(zh)):not(:lang(ja)),article strong:lang(ja-Latn),article strong:lang(zh-Latn),article strong:not(:lang(zh)):not(:lang(ja)),html :lang(ja-Latn),html :lang(zh-Latn),html :not(:lang(zh)):not(:lang(ja)),html:lang(ja-Latn),html:lang(zh-Latn),html:not(:lang(zh)):not(:lang(ja)){font-family:"Helvetica Neue",Helvetica,Arial,"Han Heiti",sans-serif}[lang*=Hant],[lang=zh-TW],[lang=zh-HK],[lang^=zh],article strong:lang(zh),article strong:lang(zh-Hant),html:lang(zh),html:lang(zh-Hant){font-family:"Biaodian Pro Sans CNS","Helvetica Neue",Helvetica,Arial,"Zhuyin Heiti","Han Heiti",sans-serif}.no-unicoderange [lang*=Hant],.no-unicoderange [lang=zh-TW],.no-unicoderange [lang=zh-HK],.no-unicoderange [lang^=zh],.no-unicoderange article strong:lang(zh),.no-unicoderange article strong:lang(zh-Hant),html:lang(zh).no-unicoderange,html:lang(zh-Hant).no-unicoderange{font-family:"Helvetica Neue",Helvetica,Arial,"Han Heiti",sans-serif}[lang*=Hans],[lang=zh-CN],article strong:lang(zh-CN),article strong:lang(zh-Hans),html:lang(zh-CN),html:lang(zh-Hans){font-family:"Biaodian Pro Sans GB","Helvetica Neue",Helvetica,Arial,"Han Heiti GB",sans-serif}.no-unicoderange [lang*=Hans],.no-unicoderange [lang=zh-CN],.no-unicoderange article strong:lang(zh-CN),.no-unicoderange article strong:lang(zh-Hans),html:lang(zh-CN).no-unicoderange,html:lang(zh-Hans).no-unicoderange{font-family:"Helvetica Neue",Helvetica,Arial,"Han Heiti GB",sans-serif}[lang^=ja],article strong:lang(ja),html:lang(ja){font-family:"Yakumono Sans","Helvetica Neue",Helvetica,Arial,sans-serif}.no-unicoderange [lang^=ja],.no-unicoderange article strong:lang(ja),html:lang(ja).no-unicoderange{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif}article blockquote i :lang(ja-Latn),article blockquote i :lang(zh-Latn),article blockquote i :not(:lang(zh)):not(:lang(ja)),article blockquote i:lang(ja-Latn),article blockquote i:lang(zh-Latn),article blockquote i:not(:lang(zh)):not(:lang(ja)),article blockquote var :lang(ja-Latn),article blockquote var :lang(zh-Latn),article blockquote var :not(:lang(zh)):not(:lang(ja)),article blockquote var:lang(ja-Latn),article blockquote var:lang(zh-Latn),article blockquote var:not(:lang(zh)):not(:lang(ja)){font-family:"Latin Italic Sans","Helvetica Neue",Helvetica,Arial,"Han Heiti",sans-serif}article blockquote i:lang(zh),article blockquote i:lang(zh-Hant),article blockquote var:lang(zh),article blockquote var:lang(zh-Hant){font-family:"Biaodian Pro Sans CNS","Latin Italic Sans","Helvetica Neue",Helvetica,Arial,"Zhuyin Heiti","Han Heiti",sans-serif}.no-unicoderange article blockquote i:lang(zh),.no-unicoderange article blockquote i:lang(zh-Hant),.no-unicoderange article blockquote var:lang(zh),.no-unicoderange article blockquote var:lang(zh-Hant){font-family:"Latin Italic Sans","Helvetica Neue",Helvetica,Arial,"Han Heiti",sans-serif}article blockquote i:lang(zh-CN),article blockquote i:lang(zh-Hans),article blockquote var:lang(zh-CN),article blockquote var:lang(zh-Hans){font-family:"Biaodian Pro Sans GB","Latin Italic Sans","Helvetica Neue",Helvetica,Arial,"Han Heiti GB",sans-serif}.no-unicoderange article blockquote i:lang(zh-CN),.no-unicoderange article blockquote i:lang(zh-Hans),.no-unicoderange article blockquote var:lang(zh-CN),.no-unicoderange article blockquote var:lang(zh-Hans){font-family:"Latin Italic Sans","Helvetica Neue",Helvetica,Arial,"Han Heiti GB",sans-serif}article blockquote i:lang(ja),article blockquote var:lang(ja){font-family:"Yakumono Sans","Latin Italic Sans","Helvetica Neue",Helvetica,Arial,sans-serif}.no-unicoderange article blockquote i:lang(ja),.no-unicoderange article blockquote var:lang(ja){font-family:"Latin Italic Sans","Helvetica Neue",Helvetica,Arial,sans-serif}article figure blockquote :lang(ja-Latn),article figure blockquote :lang(zh-Latn),article figure blockquote :not(:lang(zh)):not(:lang(ja)),article figure blockquote:lang(ja-Latn),article figure blockquote:lang(zh-Latn),article figure blockquote:not(:lang(zh)):not(:lang(ja)){font-family:Georgia,"Times New Roman","Han Songti",cursive,serif}article figure blockquote:lang(zh),article figure blockquote:lang(zh-Hant){font-family:"Biaodian Pro Serif CNS","Numeral LF Serif",Georgia,"Times New Roman","Zhuyin Kaiti","Han Songti",serif}.no-unicoderange article figure blockquote:lang(zh),.no-unicoderange article figure blockquote:lang(zh-Hant){font-family:"Numeral LF Serif",Georgia,"Times New Roman","Han Songti",serif}article figure blockquote:lang(zh-CN),article figure blockquote:lang(zh-Hans){font-family:"Biaodian Pro Serif GB","Numeral LF Serif",Georgia,"Times New Roman","Han Songti GB",serif}.no-unicoderange article figure blockquote:lang(zh-CN),.no-unicoderange article figure blockquote:lang(zh-Hans){font-family:"Numeral LF Serif",Georgia,"Times New Roman","Han Songti GB",serif}article figure blockquote:lang(ja){font-family:"Yakumono Serif","Numeral LF Serif",Georgia,"Times New Roman",serif}.no-unicoderange article figure blockquote:lang(ja){font-family:"Numeral LF Serif",Georgia,"Times New Roman",serif}article blockquote :lang(ja-Latn),article blockquote :lang(zh-Latn),article blockquote :not(:lang(zh)):not(:lang(ja)),article blockquote:lang(ja-Latn),article blockquote:lang(zh-Latn),article blockquote:not(:lang(zh)):not(:lang(ja)){font-family:Georgia,"Times New Roman","Han Kaiti",cursive,serif}article blockquote:lang(zh),article blockquote:lang(zh-Hant){font-family:"Biaodian Pro Serif CNS","Numeral LF Serif",Georgia,"Times New Roman","Zhuyin Kaiti","Han Kaiti",cursive,serif}.no-unicoderange article blockquote:lang(zh),.no-unicoderange article blockquote:lang(zh-Hant){font-family:"Numeral LF Serif",Georgia,"Times New Roman","Han Kaiti",cursive,serif}article blockquote:lang(zh-CN),article blockquote:lang(zh-Hans){font-family:"Biaodian Pro Serif GB","Numeral LF Serif",Georgia,"Times New Roman","Han Kaiti GB",cursive,serif}.no-unicoderange article blockquote:lang(zh-CN),.no-unicoderange article blockquote:lang(zh-Hans){font-family:"Numeral LF Serif",Georgia,"Times New Roman","Han Kaiti GB",cursive,serif}article blockquote:lang(ja){font-family:"Yakumono Serif","Numeral LF Serif",Georgia,"Times New Roman",cursive,serif}.no-unicoderange article blockquote:lang(ja){font-family:"Numeral LF Serif",Georgia,"Times New Roman",cursive,serif}i :lang(ja-Latn),i :lang(zh-Latn),i :not(:lang(zh)):not(:lang(ja)),i:lang(ja-Latn),i:lang(zh-Latn),i:not(:lang(zh)):not(:lang(ja)),var :lang(ja-Latn),var :lang(zh-Latn),var :not(:lang(zh)):not(:lang(ja)),var:lang(ja-Latn),var:lang(zh-Latn),var:not(:lang(zh)):not(:lang(ja)){font-family:"Latin Italic Serif",Georgia,"Times New Roman","Han Kaiti",cursive,serif}i:lang(zh),i:lang(zh-Hant),var:lang(zh),var:lang(zh-Hant){font-family:"Biaodian Pro Serif CNS","Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman","Zhuyin Kaiti","Han Kaiti",cursive,serif}.no-unicoderange i:lang(zh),.no-unicoderange i:lang(zh-Hant),.no-unicoderange var:lang(zh),.no-unicoderange var:lang(zh-Hant){font-family:"Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman","Han Kaiti",cursive,serif}i:lang(zh-CN),i:lang(zh-Hans),var:lang(zh-CN),var:lang(zh-Hans){font-family:"Biaodian Pro Serif GB","Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman","Han Kaiti GB",cursive,serif}.no-unicoderange i:lang(zh-CN),.no-unicoderange i:lang(zh-Hans),.no-unicoderange var:lang(zh-CN),.no-unicoderange var:lang(zh-Hans){font-family:"Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman","Han Kaiti GB",cursive,serif}i:lang(ja),var:lang(ja){font-family:"Yakumono Serif","Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman",cursive,serif}.no-unicoderange i:lang(ja),.no-unicoderange var:lang(ja){font-family:"Numeral LF Italic Serif","Latin Italic Serif",Georgia,"Times New Roman",cursive,serif}code :lang(ja-Latn),code :lang(zh-Latn),code :not(:lang(zh)):not(:lang(ja)),code:lang(ja-Latn),code:lang(zh-Latn),code:not(:lang(zh)):not(:lang(ja)),kbd :lang(ja-Latn),kbd :lang(zh-Latn),kbd :not(:lang(zh)):not(:lang(ja)),kbd:lang(ja-Latn),kbd:lang(zh-Latn),kbd:not(:lang(zh)):not(:lang(ja)),pre :lang(ja-Latn),pre :lang(zh-Latn),pre :not(:lang(zh)):not(:lang(ja)),pre:lang(ja-Latn),pre:lang(zh-Latn),pre:not(:lang(zh)):not(:lang(ja)),samp :lang(ja-Latn),samp :lang(zh-Latn),samp :not(:lang(zh)):not(:lang(ja)),samp:lang(ja-Latn),samp:lang(zh-Latn),samp:not(:lang(zh)):not(:lang(ja)){font-family:Menlo,Consolas,Courier,"Han Heiti",monospace,monospace,sans-serif}code:lang(zh),code:lang(zh-Hant),kbd:lang(zh),kbd:lang(zh-Hant),pre:lang(zh),pre:lang(zh-Hant),samp:lang(zh),samp:lang(zh-Hant){font-family:"Biaodian Pro Sans CNS",Menlo,Consolas,Courier,"Zhuyin Heiti","Han Heiti",monospace,monospace,sans-serif}.no-unicoderange code:lang(zh),.no-unicoderange code:lang(zh-Hant),.no-unicoderange kbd:lang(zh),.no-unicoderange kbd:lang(zh-Hant),.no-unicoderange pre:lang(zh),.no-unicoderange pre:lang(zh-Hant),.no-unicoderange samp:lang(zh),.no-unicoderange samp:lang(zh-Hant){font-family:Menlo,Consolas,Courier,"Han Heiti",monospace,monospace,sans-serif}code:lang(zh-CN),code:lang(zh-Hans),kbd:lang(zh-CN),kbd:lang(zh-Hans),pre:lang(zh-CN),pre:lang(zh-Hans),samp:lang(zh-CN),samp:lang(zh-Hans){font-family:"Biaodian Pro Sans GB",Menlo,Consolas,Courier,"Han Heiti GB",monospace,monospace,sans-serif}.no-unicoderange code:lang(zh-CN),.no-unicoderange code:lang(zh-Hans),.no-unicoderange kbd:lang(zh-CN),.no-unicoderange kbd:lang(zh-Hans),.no-unicoderange pre:lang(zh-CN),.no-unicoderange pre:lang(zh-Hans),.no-unicoderange samp:lang(zh-CN),.no-unicoderange samp:lang(zh-Hans){font-family:Menlo,Consolas,Courier,"Han Heiti GB",monospace,monospace,sans-serif}code:lang(ja),kbd:lang(ja),pre:lang(ja),samp:lang(ja){font-family:"Yakumono Sans",Menlo,Consolas,Courier,monospace,monospace,sans-serif}.no-unicoderange code:lang(ja),.no-unicoderange kbd:lang(ja),.no-unicoderange pre:lang(ja),.no-unicoderange samp:lang(ja){font-family:Menlo,Consolas,Courier,monospace,monospace,sans-serif}.no-unicoderange h-char.bd-liga,.no-unicoderange h-char[unicode=b7],h-ruby [annotation] rt,h-ruby h-zhuyin,h-ruby h-zhuyin h-diao,h-ruby.romanization rt,html,ruby [annotation] rt,ruby h-zhuyin,ruby h-zhuyin h-diao,ruby.romanization rt{-moz-font-feature-settings:"liga";-ms-font-feature-settings:"liga";-webkit-font-feature-settings:"liga";font-feature-settings:"liga"}[lang*=Hant],[lang*=Hans],[lang=zh-TW],[lang=zh-HK],[lang=zh-CN],[lang^=zh],article blockquote i,article blockquote var,article strong,code,html,kbd,pre,samp{-moz-font-feature-settings:"liga=1, locl=0";-ms-font-feature-settings:"liga","locl" 0;-webkit-font-feature-settings:"liga","locl" 0;font-feature-settings:"liga","locl" 0}.no-unicoderange h-char.bd-cop:lang(zh-HK),.no-unicoderange h-char.bd-cop:lang(zh-Hant),.no-unicoderange h-char.bd-cop:lang(zh-TW){font-family:-apple-system,"Han Heiti CNS"}.no-unicoderange h-char.bd-liga,.no-unicoderange h-char[unicode=b7]{font-family:"Biaodian Basic","Han Heiti"}.no-unicoderange h-char[unicode="2018"]:lang(zh-CN),.no-unicoderange h-char[unicode="2018"]:lang(zh-Hans),.no-unicoderange h-char[unicode="2019"]:lang(zh-CN),.no-unicoderange h-char[unicode="2019"]:lang(zh-Hans),.no-unicoderange h-char[unicode="201c"]:lang(zh-CN),.no-unicoderange h-char[unicode="201c"]:lang(zh-Hans),.no-unicoderange h-char[unicode="201d"]:lang(zh-CN),.no-unicoderange h-char[unicode="201d"]:lang(zh-Hans){font-family:"Han Heiti GB"}i,var{font-style:inherit}.no-unicoderange h-ruby h-zhuyin,.no-unicoderange h-ruby h-zhuyin h-diao,.no-unicoderange ruby h-zhuyin,.no-unicoderange ruby h-zhuyin h-diao,h-ruby h-diao,ruby h-diao{font-family:"Zhuyin Kaiti",cursive,serif}h-ruby [annotation] rt,h-ruby.romanization rt,ruby [annotation] rt,ruby.romanization rt{font-family:"Romanization Sans","Helvetica Neue",Helvetica,Arial,"Han Heiti",sans-serif} \ No newline at end of file diff --git a/lib/Han/dist/han.min.js b/lib/Han/dist/han.min.js index e69de29b..a557ad3e 100644 --- a/lib/Han/dist/han.min.js +++ b/lib/Han/dist/han.min.js @@ -0,0 +1,5 @@ +/*! 漢字標準格式 v3.3.0 | MIT License | css.hanzi.co */ +/*! Han.css: the CSS typography framework optimised for Hanzi */ + +void function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=b(a,!0):"function"==typeof define&&define.amd?define(function(){return b(a,!0)}):b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";function c(a){return"function"==typeof a||a instanceof Element?a:void 0}function d(a){var b=0===a.index&&a.isEnd?"biaodian cjk":"biaodian cjk portion "+(0===a.index?"is-first":a.isEnd?"is-end":"is-inner"),c=S.create("h-char-group",b);return c.innerHTML=a.text,c}function e(a){var b=S.create("div"),c=a.charCodeAt(0).toString(16);return b.innerHTML=''+a+"",b.firstChild}function f(a){return a.match(R["char"].biaodian.open)?"bd-open":a.match(R["char"].biaodian.close)?"bd-close bd-end":a.match(R["char"].biaodian.end)?/(?:\u3001|\u3002|\uff0c)/i.test(a)?"bd-end bd-cop":"bd-end":a.match(new RegExp(Q.biaodian.liga))?"bd-liga":a.match(new RegExp(Q.biaodian.middle))?"bd-middle":""}function g(a,b){var c,d=S.create("canvas");return d.width="50",d.height="20",d.style.display="none",L.appendChild(d),c=d.getContext("2d"),c.textBaseline="top",c.font="15px "+b+", sans-serif",c.fillStyle="black",c.strokeStyle="black",c.fillText(a,0,0),{node:d,context:c,remove:function(){S.remove(d,L)}}}function h(a,b){var c,d=a.context,e=b.context;try{for(var f=1;20>=f;f++)for(var g=1;50>=g;g++){if("undefined"==typeof c&&d.getImageData(g,f,1,1).data[3]!==e.getImageData(g,f,1,1).data[3]){c=!1;break}if("boolean"==typeof c)break;50===g&&20===f&&"undefined"==typeof c&&(c=!0)}return a.remove(),b.remove(),a=null,b=null,c}catch(h){}return!1}function i(a,b,c){var a=a,b=b||"sans-serif",c=c||"\u8fadQ";return b=g(c,b),a=g(c,a),!h(a,b)}function j(a){var b,c=S.create("!"),d=a.classList;return c.appendChild(S.clone(a)),S.tag("rt",c.firstChild).forEach(function(a){var c,e=S.create("!"),f=[];do{if(c=(c||a).previousSibling,!c||c.nodeName.match(/((?:h\-)?r[ubt])/i))break;e.insertBefore(S.clone(c),e.firstChild),f.push(c)}while(!c.nodeName.match(/((?:h\-)?r[ubt])/i));b=d.contains("zhuyin")?p(e,a):o(e,a);try{a.parentNode.replaceChild(b,a),f.map(S.remove)}catch(g){}}),m(c)}function k(a){var b=S.create("!");return b.appendChild(S.clone(a)),S.tag("rt",b.firstChild).forEach(function(a){var b,c,d=S.create("!"),e=[];do{if(b=(b||a).previousSibling,!b||b.nodeName.match(/((?:h\-)?r[ubt])/i))break;d.insertBefore(S.clone(b),d.firstChild),e.push(b)}while(!b.nodeName.match(/((?:h\-)?r[ubt])/i));c=S.create("rt"),c.innerHTML=q(a),a.parentNode.replaceChild(c,a)}),b.firstChild}function l(a){var b,c,d,e,f=S.create("!"),g=a.classList;return f.appendChild(S.clone(a)),b=f.firstChild,c=d=S.tag("rb",b),e=c.length,void function(a){a&&(d=S.tag("rt",a).map(function(a,b){if(c[b]){var d=p(c[b],a);try{c[b].parentNode.replaceChild(d,c[b])}catch(e){}return d}}),S.remove(a),b.setAttribute("rightangle","true"))}(b.querySelector("rtc.zhuyin")),S.qsa("rtc:not(.zhuyin)",b).forEach(function(a,c){var f;f=S.tag("rt",a).map(function(a,b){var f,h,i=Number(a.getAttribute("rbspan")||1),j=0,k=[];i>e&&(i=e);do{try{f=d.shift(),k.push(f)}catch(l){}if("undefined"==typeof f)break;j+=Number(f.getAttribute("span")||1)}while(i>j);if(j>i){if(k.length>1)return void console.error("An impossible `rbspan` value detected.",ruby);k=S.tag("rb",k[0]),d=k.slice(i).concat(d),k=k.slice(0,i),j=i}h=o(k,a,{"class":g,span:j,order:c});try{k[0].parentNode.replaceChild(h,k.shift()),k.map(S.remove)}catch(l){}return h}),d=f,1===c&&b.setAttribute("doubleline","true"),S.remove(a)}),m(f)}function m(a){var b=a.firstChild,c=S.create("h-ruby");return c.innerHTML=b.innerHTML,S.setAttr(c,b.attributes),c.normalize(),c}function n(a){if(!a instanceof Element)return a;var b=a.classList;return b.contains("pinyin")?b.add("romanization"):b.contains("romanization")?b.add("annotation"):b.contains("mps")?b.add("zhuyin"):b.contains("rightangle")&&b.add("complex"),a}function o(a,b,c){var d=S.create("h-ru"),b=S.clone(b),c=c||{};return c.annotation="true",Array.isArray(a)?d.innerHTML=a.map(function(a){return"undefined"==typeof a?"":a.outerHTML}).join("")+b.outerHTML:(d.appendChild(S.clone(a)),d.appendChild(b)),S.setAttr(d,c),d}function p(a,b){var a=S.clone(a),c=S.create("h-ru");return c.setAttribute("zhuyin",!0),c.appendChild(a),c.innerHTML+=q(b),c}function q(a){var b,c,d,e="string"==typeof a?a:a.textContent;return b=e.replace(R.zhuyin.diao,""),d=b?b.length:0,c=e.replace(b,"").replace(/[\u02C5]/g,"\u02c7").replace(/[\u030D]/g,"\u0358"),0===d?"":''+b+""+c+""}function r(a,b){return a&&b&&a.parentNode===b.parentNode}function s(a,b){var c=a,b=b||"";if(S.isElmt(a.nextSibling)||r(a,a.nextSibling))return b+X;for(;!c.nextSibling;)c=c.parentNode;return a!==c&&c.insertAdjacentHTML("afterEnd",""),b}function t(a,b){return a.isEnd&&0===a.index?b[1]+X+b[2]:0===a.index?s(a.node,a.text):a.text}function u(a){return 0===a.index?S.clone(Y):""}function v(a){var b=a.node.parentNode;return 0===a.index&&(Z=a.endIndexInNode-2),"h-hws"!==b.nodeName.toLowerCase()||1!==a.index&&a.indexInMatch!==Z||b.classList.add("quote-inner"),a.text}function w(a){var b=a.node.parentNode;return"h-hws"===b.nodeName.toLowerCase()&&b.classList.add("quote-outer"),a.text}function x(){var a,b=S.create("div");return b.innerHTML="a ba b",L.appendChild(b),a=b.firstChild.offsetWidth!==b.lastChild.offsetWidth,S.remove(b),a}function y(a){var b=a.nextSibling;b&&ba(b,"h-cs.jinze-outer")?b.classList.add("hangable-outer"):a.insertAdjacentHTML("afterend",aa)}function z(a){return a.replace(/(biaodian|cjk|bd-jiya|bd-consecutive|bd-hangable)/gi,"").trim()}function A(a){var b,c=a.text,d=a.node.parentNode,e=S.parent(d,"h-char.biaodian"),f=O.createBDChar(c);return f.innerHTML=""+c+"",f.classList.add(ea),(b=S.parent(d,"h-jinze"))&&C(b),e?function(){return e.classList.add(ea),ba(d,"h-inner, h-inner *")?c:f.firstChild}():f}function B(a){var b,c=ca,d=a.node.parentNode,e=S.parent(d,"h-char.biaodian"),f=S.parent(e,"h-jinze");return b=e.classList,c&&e.setAttribute("prev",c),da&&b.contains("bd-open")&&da.pop().setAttribute("next","bd-open"),da=void 0,a.isEnd?(ca=void 0,b.add(ga,"end-portion")):(ca=z(e.getAttribute("class")),b.add(ga)),f&&(da=D(f,{prev:c,"class":z(e.getAttribute("class"))})),a.text}function C(a){ba(a,".tou, .touwei")&&!ba(a.previousSibling,"h-cs.jiya-outer")&&a.insertAdjacentHTML("beforebegin",ha),ba(a,".wei, .touwei")&&!ba(a.nextSibling,"h-cs.jiya-outer")&&a.insertAdjacentHTML("afterend",ha)}function D(a,b){var c,d;return ba(a,".tou, .touwei")&&(c=a.previousSibling,ba(c,"h-cs")&&(c.className="jinze-outer jiya-outer",c.setAttribute("prev",b.prev))),ba(a,".wei, .touwei")&&(d=a.nextSibling,ba(d,"h-cs")&&(d.className="jinze-outer jiya-outer "+b["class"],d.removeAttribute("prev"))),[c,d]}function E(a,b,c){return function(){var d=O.localize.writeOnCanvas(b,a),e=O.localize.writeOnCanvas(c,a);return O.localize.compareCanvases(d,e)}}function F(){return E('"Romanization Sans"',"a\u030d","\udb80\udc61")}function G(){return E('"Romanization Sans"',"i\u030d","\udb80\udc69")}function H(){return E('"Zhuyin Kaiti"',"\u31b4\u0358","\udb8c\uddb4")}function I(a){return function(b){var b=b||J,c=O.find(b).avoid(ia);return a.forEach(function(a){c.replace(new RegExp(a[0],"ig"),function(b,c){var d=S.clone(ja);return d.innerHTML=""+c[0]+"",d.setAttribute("display-as",a[1]),0===b.index?d:""})}),c}}var J=a.document,K=J.documentElement,L=J.body,M="3.3.0",N=["initCond","renderElem","renderJiya","renderHanging","correctBiaodian","renderHWS","substCombLigaWithPUA"],O=function(a,b){return new O.fn.init(a,b)},P=function(){return arguments[0]&&(this.context=arguments[0]),arguments[1]&&(this.condition=arguments[1]),this};O.version=M,O.fn=O.prototype={version:M,constructor:O,context:L,condition:K,routine:N,init:P,setRoutine:function(a){return Array.isArray(a)&&(this.routine=a),this},render:function(a){var b=this,a=Array.isArray(a)?a:this.routine;return a.forEach(function(a){"string"==typeof a&&"function"==typeof b[a]?b[a]():Array.isArray(a)&&"function"==typeof b[a[0]]&&b[a.shift()].apply(b,a)}),this}},O.fn.init.prototype=O.fn,O.init=function(){return O.init=O().render()};var Q={punct:{base:"[\u2026,.;:!?\u203d_]",sing:"[\u2010-\u2014\u2026]",middle:"[\\/~\\-&\u2010-\u2014_]",open:"['\"\u2018\u201c\\(\\[\xa1\xbf\u2e18\xab\u2039\u201a\u201c\u201e]",close:"['\"\u201d\u2019\\)\\]\xbb\u203a\u201b\u201d\u201f]",end:"['\"\u201d\u2019\\)\\]\xbb\u203a\u201b\u201d\u201f\u203c\u203d\u2047-\u2049,.;:!?]"},biaodian:{base:"[\ufe30\uff0e\u3001\uff0c\u3002\uff1a\uff1b\uff1f\uff01\u30fc]",liga:"[\u2014\u2026\u22ef]",middle:"[\xb7\uff3c\uff0f\uff0d\u30a0\uff06\u30fb\uff3f]",open:"[\u300c\u300e\u300a\u3008\uff08\u3014\uff3b\uff5b\u3010\u3016]",close:"[\u300d\u300f\u300b\u3009\uff09\u3015\uff3d\uff5d\u3011\u3017]",end:"[\u300d\u300f\u300b\u3009\uff09\u3015\uff3d\uff5d\u3011\u3017\ufe30\uff0e\u3001\uff0c\u3002\uff1a\uff1b\uff1f\uff01\u30fc]"},hanzi:{base:"[\u4e00-\u9fff\u3400-\u4db5\u31c0-\u31e3\u3007\ufa0e\ufa0f\ufa11\ufa13\ufa14\ufa1f\ufa21\ufa23\ufa24\ufa27-\ufa29]|[\ud800-\udbff][\udc00-\udfff]",desc:"[\u2ff0-\u2ffa]",radical:"[\u2f00-\u2fd5\u2e80-\u2ef3]"},latin:{base:"[A-Za-z0-9\xc0-\xff\u0100-\u017f\u0180-\u024f\u2c60-\u2c7f\ua720-\ua7ff\u1e00-\u1eff]",combine:"[\u0300-\u0341\u1dc0-\u1dff]"},ellinika:{base:"[0-9\u0370-\u03ff\u1f00-\u1fff]",combine:"[\u0300-\u0345\u1dc0-\u1dff]"},kirillica:{base:"[0-9\u0400-\u0482\u048a-\u04ff\u0500-\u052f\ua640-\ua66e\ua67e-\ua697]",combine:"[\u0483-\u0489\u2de0-\u2dff\ua66f-\ua67d\ua69f]"},kana:{base:"[\u30a2\u30a4\u30a6\u30a8\u30aa-\u30fa\u3042\u3044\u3046\u3048\u304a-\u3094\u309f\u30ff]|\ud82c[\udc00-\udc01]",small:"[\u3041\u3043\u3045\u3047\u3049\u30a1\u30a3\u30a5\u30a7\u30a9\u3063\u3083\u3085\u3087\u308e\u3095\u3096\u30c3\u30e3\u30e5\u30e7\u30ee\u30f5\u30f6\u31f0-\u31ff]",combine:"[\u3099-\u309c]",half:"[\uff66-\uff9f]",mark:"[\u30a0\u309d\u309e\u30fb-\u30fe]"},eonmun:{base:"[\uac00-\ud7a3]",letter:"[\u1100-\u11ff\u314f-\u3163\u3131-\u318e\ua960-\ua97c\ud7b0-\ud7fb]",half:"[\uffa1-\uffdc]"},zhuyin:{base:"[\u3105-\u312d\u31a0-\u31ba]",initial:"[\u3105-\u3119\u312a-\u312c\u31a0-\u31a3]",medial:"[\u3127-\u3129]","final":"[\u311a-\u3129\u312d\u31a4-\u31b3\u31b8-\u31ba]",tone:"[\u02d9\u02ca\u02c5\u02c7\u02cb\u02ea\u02eb]",checked:"[\u31b4-\u31b7][\u0358\u030d]?"}},R=function(){var a="[\\x20\\t\\r\\n\\f]",b=Q.punct.open,c=(Q.punct.close,Q.punct.end),d=Q.punct.middle,e=Q.punct.sing,f=b+"|"+c+"|"+d,g=Q.biaodian.open,h=Q.biaodian.close,i=Q.biaodian.end,j=Q.biaodian.middle,k=Q.biaodian.liga+"{2}",l=g+"|"+i+"|"+j,m=Q.kana.base+Q.kana.combine+"?",n=Q.kana.small+Q.kana.combine+"?",o=Q.kana.half,p=Q.eonmun.base+"|"+Q.eonmun.letter,q=Q.eonmun.half,r=Q.hanzi.base+"|"+Q.hanzi.desc+"|"+Q.hanzi.radical+"|"+m,s=Q.ellinika.combine,t=Q.latin.base+s+"*",u=Q.ellinika.base+s+"*",v=Q.kirillica.combine,w=Q.kirillica.base+v+"*",x=t+"|"+u+"|"+w,y="['\u2019]",z=r+"|(?:"+x+"|"+y+")+",A=Q.zhuyin.initial,B=Q.zhuyin.medial,C=Q.zhuyin["final"],D=Q.zhuyin.tone+"|"+Q.zhuyin.checked;return{"char":{punct:{all:new RegExp("("+f+")","g"),open:new RegExp("("+b+")","g"),end:new RegExp("("+c+")","g"),sing:new RegExp("("+e+")","g")},biaodian:{all:new RegExp("("+l+")","g"),open:new RegExp("("+g+")","g"),close:new RegExp("("+h+")","g"),end:new RegExp("("+i+")","g"),liga:new RegExp("("+k+")","g")},hanzi:new RegExp("("+r+")","g"),latin:new RegExp("("+t+")","ig"),ellinika:new RegExp("("+u+")","ig"),kirillica:new RegExp("("+w+")","ig"),kana:new RegExp("("+m+"|"+n+"|"+o+")","g"),eonmun:new RegExp("("+p+"|"+q+")","g")},group:{biaodian:[new RegExp("(("+l+"){2,})","g"),new RegExp("("+k+g+")","g")],punct:null,hanzi:new RegExp("("+r+")+","g"),western:new RegExp("("+t+"|"+u+"|"+w+"|"+f+")+","ig"),kana:new RegExp("("+m+"|"+n+"|"+o+")+","g"),eonmun:new RegExp("("+p+"|"+q+"|"+f+")+","g")},jinze:{hanging:new RegExp(a+"*([\u3001\uff0c\u3002\uff0e])(?!"+i+")","ig"),touwei:new RegExp("("+g+"+)("+z+")("+i+"+)","ig"),tou:new RegExp("("+g+"+)("+z+")","ig"),wei:new RegExp("("+z+")("+i+"+)","ig"),middle:new RegExp("("+z+")("+j+")("+z+")","ig")},zhuyin:{form:new RegExp("^\u02d9?("+A+")?("+B+")?("+C+")?("+D+")?$"),diao:new RegExp("("+D+")","g")},hws:{base:[new RegExp("("+r+")("+x+"|"+b+")","ig"),new RegExp("("+x+"|"+c+")("+r+")","ig")],strict:[new RegExp("("+r+")"+a+"?("+x+"|"+b+")","ig"),new RegExp("("+x+"|"+c+")"+a+"?("+r+")","ig")]},"display-as":{"ja-font-for-hant":["\u67e5 \u67fb","\u555f \u5553","\u9109 \u9115","\u503c \u5024","\u6c61 \u6c5a"],"comb-liga-pua":[["a[\u030d\u0358]","\udb80\udc61"],["e[\u030d\u0358]","\udb80\udc65"],["i[\u030d\u0358]","\udb80\udc69"],["o[\u030d\u0358]","\udb80\udc6f"],["u[\u030d\u0358]","\udb80\udc75"],["\u31b4[\u030d\u0358]","\udb8c\uddb4"],["\u31b5[\u030d\u0358]","\udb8c\uddb5"],["\u31b6[\u030d\u0358]","\udb8c\uddb6"],["\u31b7[\u030d\u0358]","\udb8c\uddb7"]],"comb-liga-vowel":[["a[\u030d\u0358]","\udb80\udc61"],["e[\u030d\u0358]","\udb80\udc65"],["i[\u030d\u0358]","\udb80\udc69"],["o[\u030d\u0358]","\udb80\udc6f"],["u[\u030d\u0358]","\udb80\udc75"]],"comb-liga-zhuyin":[["\u31b4[\u030d\u0358]","\udb8c\uddb4"],["\u31b5[\u030d\u0358]","\udb8c\uddb5"],["\u31b6[\u030d\u0358]","\udb8c\uddb6"],["\u31b7[\u030d\u0358]","\udb8c\uddb7"]]},"inaccurate-char":[["[\u2022\u2027]","\xb7"],["\u22ef\u22ef","\u2026\u2026"],["\u2500\u2500","\u2014\u2014"],["\u2035","\u2018"],["\u2032","\u2019"],["\u2036","\u201c"],["\u2033","\u201d"]]}}();O.UNICODE=Q,O.TYPESET=R,O.UNICODE.cjk=O.UNICODE.hanzi,O.UNICODE.greek=O.UNICODE.ellinika,O.UNICODE.cyrillic=O.UNICODE.kirillica,O.UNICODE.hangul=O.UNICODE.eonmun,O.UNICODE.zhuyin.ruyun=O.UNICODE.zhuyin.checked,O.TYPESET["char"].cjk=O.TYPESET["char"].hanzi,O.TYPESET["char"].greek=O.TYPESET["char"].ellinika,O.TYPESET["char"].cyrillic=O.TYPESET["char"].kirillica,O.TYPESET["char"].hangul=O.TYPESET["char"].eonmun,O.TYPESET.group.hangul=O.TYPESET.group.eonmun,O.TYPESET.group.cjk=O.TYPESET.group.hanzi;var S={id:function(a,b){return(b||J).getElementById(a)},tag:function(a,b){return this.makeArray((b||J).getElementsByTagName(a))},qs:function(a,b){return(b||J).querySelector(a)},qsa:function(a,b){return this.makeArray((b||J).querySelectorAll(a))},parent:function(a,b){return b?function(){if("function"==typeof S.matches){for(;!S.matches(a,b);){if(!a||a===J.documentElement){a=void 0;break}a=a.parentNode}return a}}():a?a.parentNode:void 0},create:function(a,b){var c="!"===a?J.createDocumentFragment():""===a?J.createTextNode(b||""):J.createElement(a);try{b&&(c.className=b)}catch(d){}return c},clone:function(a,b){return a.cloneNode("boolean"==typeof b?b:!0)},remove:function(a){return a.parentNode.removeChild(a)},setAttr:function(a,b){if("object"==typeof b){var c=b.length;if("object"==typeof b[0]&&"name"in b[0])for(var d=0;c>d;d++)void 0!==b[d].value&&a.setAttribute(b[d].name,b[d].value);else for(var e in b)b.hasOwnProperty(e)&&void 0!==b[e]&&a.setAttribute(e,b[e]);return a}},isElmt:function(a){return a&&a.nodeType===Node.ELEMENT_NODE},isIgnorable:function(a){return a?"WBR"===a.nodeName||a.nodeType===Node.COMMENT_NODE:!1},makeArray:function(a){return Array.prototype.slice.call(a)},extend:function(a,b){if(("object"==typeof a||"function"==typeof a)&&"object"==typeof b)for(var c in b)b.hasOwnProperty(c)&&(a[c]=b[c]);return a}},T=function(b){function c(a,b,c){var d=Element.prototype,e=d.matches||d.mozMatchesSelector||d.msMatchesSelector||d.webkitMatchesSelector;return a instanceof Element?e.call(a,b):c&&/^[39]$/.test(a.nodeType)?!0:!1}var d="0.2.1",e=b.NON_INLINE_PROSE,f=b.PRESETS.prose.filterElements,g=a||{},h=g.document||void 0;if("undefined"==typeof h)throw new Error("Fibre requires a DOM-supported environment.");var i=function(a,b){return new i.fn.init(a,b)};return i.version=d,i.matches=c,i.fn=i.prototype={constructor:i,version:d,finder:[],context:void 0,portionMode:"retain",selector:{},preset:"prose",init:function(a,b){if(b&&(this.preset=null),this.selector={context:null,filter:[],avoid:[],boundary:[]},!a)throw new Error("A context is required for Fibre to initialise.");return a instanceof Node?a instanceof Document?this.context=a.body||a:this.context=a:"string"==typeof a&&(this.context=h.querySelector(a),this.selector.context=a),this},filterFn:function(a){var b=this.selector.filter.join(", ")||"*",d=this.selector.avoid.join(", ")||null,e=c(a,b,!0)&&!c(a,d);return"prose"===this.preset?f(a)&&e:e},boundaryFn:function(a){var b=this.selector.boundary.join(", ")||null,d=c(a,b);return"prose"===this.preset?e(a)||d:d},filter:function(a){return"string"==typeof a&&this.selector.filter.push(a),this},endFilter:function(a){return a?this.selector.filter=[]:this.selector.filter.pop(),this},avoid:function(a){return"string"==typeof a&&this.selector.avoid.push(a),this},endAvoid:function(a){return a?this.selector.avoid=[]:this.selector.avoid.pop(),this},addBoundary:function(a){return"string"==typeof a&&this.selector.boundary.push(a),this},removeBoundary:function(){return this.selector.boundary=[],this},setMode:function(a){return this.portionMode="first"===a?"first":"retain",this},replace:function(a,c){var d=this;return d.finder.push(b(d.context,{find:a,replace:c,filterElements:function(a){return d.filterFn(a)},forceContext:function(a){return d.boundaryFn(a)},portionMode:d.portionMode})),d},wrap:function(a,c){var d=this;return d.finder.push(b(d.context,{find:a,wrap:c,filterElements:function(a){return d.filterFn(a)},forceContext:function(a){return d.boundaryFn(a)},portionMode:d.portionMode})),d},revert:function(a){var b=this.finder.length,a=Number(a)||(0===a?Number(0):"all"===a?b:1);if("undefined"==typeof b||0===b)return this;a>b&&(a=b);for(var c=a;c>0;c--)this.finder.pop().revert();return this}},i.fn.filterOut=i.fn.avoid,i.fn.init.prototype=i.fn,i}(function(){function a(a){return String(a).replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")}function b(){return c.apply(null,arguments)||d.apply(null,arguments)}function c(a,c,e,f,g){if(c&&!c.nodeType&&arguments.length<=2)return!1;var h="function"==typeof e;h&&(e=function(a){return function(b,c){return a(b.text,c.startIndex)}}(e));var i=d(c,{find:a,wrap:h?null:e,replace:h?e:"$"+(f||"&"),prepMatch:function(a,b){if(!a[0])throw"findAndReplaceDOMText cannot handle zero-length matches";if(f>0){var c=a[f];a.index+=a[0].indexOf(c),a[0]=c}return a.endIndex=a.index+a[0].length,a.startIndex=a.index,a.index=b,a},filterElements:g});return b.revert=function(){return i.revert()},!0}function d(a,b){return new e(a,b)}function e(a,c){var d=c.preset&&b.PRESETS[c.preset];if(c.portionMode=c.portionMode||f,d)for(var e in d)i.call(d,e)&&!i.call(c,e)&&(c[e]=d[e]);this.node=a,this.options=c,this.prepMatch=c.prepMatch||this.prepMatch,this.reverts=[],this.matches=this.search(),this.matches.length&&this.processMatches()}var f="retain",g="first",h=J,i=({}.toString,{}.hasOwnProperty);return b.NON_PROSE_ELEMENTS={br:1,hr:1,script:1,style:1,img:1,video:1,audio:1,canvas:1,svg:1,map:1,object:1,input:1,textarea:1,select:1,option:1,optgroup:1,button:1},b.NON_CONTIGUOUS_PROSE_ELEMENTS={address:1,article:1,aside:1,blockquote:1,dd:1,div:1,dl:1,fieldset:1,figcaption:1,figure:1,footer:1,form:1,h1:1,h2:1,h3:1,h4:1,h5:1,h6:1,header:1,hgroup:1,hr:1,main:1,nav:1,noscript:1,ol:1,output:1,p:1,pre:1,section:1,ul:1,br:1,li:1,summary:1,dt:1,details:1,rp:1,rt:1,rtc:1,script:1,style:1,img:1,video:1,audio:1,canvas:1,svg:1,map:1,object:1,input:1,textarea:1,select:1,option:1,optgroup:1,button:1,table:1,tbody:1,thead:1,th:1,tr:1,td:1,caption:1,col:1,tfoot:1,colgroup:1},b.NON_INLINE_PROSE=function(a){return i.call(b.NON_CONTIGUOUS_PROSE_ELEMENTS,a.nodeName.toLowerCase())},b.PRESETS={prose:{forceContext:b.NON_INLINE_PROSE,filterElements:function(a){return!i.call(b.NON_PROSE_ELEMENTS,a.nodeName.toLowerCase())}}},b.Finder=e,e.prototype={search:function(){function b(a){for(var g=0,j=a.length;j>g;++g){var k=a[g];if("string"==typeof k){if(f.global)for(;c=f.exec(k);)h.push(i.prepMatch(c,d++,e));else(c=k.match(f))&&h.push(i.prepMatch(c,0,e));e+=k.length}else b(k)}}var c,d=0,e=0,f=this.options.find,g=this.getAggregateText(),h=[],i=this;return f="string"==typeof f?RegExp(a(f),"g"):f,b(g),h},prepMatch:function(a,b,c){if(!a[0])throw new Error("findAndReplaceDOMText cannot handle zero-length matches");return a.endIndex=c+a.index+a[0].length,a.startIndex=c+a.index,a.index=b,a},getAggregateText:function(){function a(d,e){if(3===d.nodeType)return[d.data];if(b&&!b(d))return[];var e=[""],f=0;if(d=d.firstChild)do if(3!==d.nodeType){var g=a(d);c&&1===d.nodeType&&(c===!0||c(d))?(e[++f]=g,e[++f]=""):("string"==typeof g[0]&&(e[f]+=g.shift()),g.length&&(e[++f]=g,e[++f]=""))}else e[f]+=d.data;while(d=d.nextSibling);return e}var b=this.options.filterElements,c=this.options.forceContext;return a(this.node)},processMatches:function(){var a,b,c,d=this.matches,e=this.node,f=this.options.filterElements,g=[],h=e,i=d.shift(),j=0,k=0,l=0,m=[e];a:for(;;){if(3===h.nodeType&&(!b&&h.length+j>=i.endIndex?b={node:h,index:l++,text:h.data.substring(i.startIndex-j,i.endIndex-j),indexInMatch:j-i.startIndex,indexInNode:i.startIndex-j,endIndexInNode:i.endIndex-j,isEnd:!0}:a&&g.push({node:h,index:l++,text:h.data,indexInMatch:j-i.startIndex,indexInNode:0}),!a&&h.length+j>i.startIndex&&(a={node:h,index:l++,indexInMatch:0,indexInNode:i.startIndex-j,endIndexInNode:i.endIndex-j,text:h.data.substring(i.startIndex-j,i.endIndex-j)}),j+=h.data.length),c=1===h.nodeType&&f&&!f(h),a&&b){if(h=this.replaceMatch(i,a,g,b),j-=b.node.data.length-b.endIndexInNode,a=null,b=null,g=[],i=d.shift(),l=0,k++,!i)break}else if(!c&&(h.firstChild||h.nextSibling)){h.firstChild?(m.push(h),h=h.firstChild):h=h.nextSibling;continue}for(;;){if(h.nextSibling){h=h.nextSibling;break}if(h=m.pop(),h===e)break a}}},revert:function(){for(var a=this.reverts.length;a--;)this.reverts[a]();this.reverts=[]},prepareReplacementString:function(a,b,c,d){var e=this.options.portionMode;return e===g&&b.indexInMatch>0?"":(a=a.replace(/\$(\d+|&|`|')/g,function(a,b){var d;switch(b){case"&":d=c[0];break;case"`":d=c.input.substring(0,c.startIndex);break;case"'":d=c.input.substring(c.endIndex);break;default:d=c[+b]}return d}),e===g?a:b.isEnd?a.substring(b.indexInMatch):a.substring(b.indexInMatch,b.indexInMatch+b.text.length))},getPortionReplacementNode:function(a,b,c){var d=this.options.replace||"$&",e=this.options.wrap;if(e&&e.nodeType){var f=h.createElement("div");f.innerHTML=e.outerHTML||(new XMLSerializer).serializeToString(e),e=f.firstChild}if("function"==typeof d)return d=d(a,b,c),d&&d.nodeType?d:h.createTextNode(String(d));var g="string"==typeof e?h.createElement(e):e;return d=h.createTextNode(this.prepareReplacementString(d,a,b,c)),d.data&&g?(g.appendChild(d),g):d},replaceMatch:function(a,b,c,d){var e,f,g=b.node,i=d.node;if(g===i){var j=g;b.indexInNode>0&&(e=h.createTextNode(j.data.substring(0,b.indexInNode)),j.parentNode.insertBefore(e,j));var k=this.getPortionReplacementNode(d,a);return j.parentNode.insertBefore(k,j),d.endIndexInNoden;++n){var p=c[n],q=this.getPortionReplacementNode(p,a);p.node.parentNode.replaceChild(q,p.node),this.reverts.push(function(a,b){return function(){b.parentNode.replaceChild(a.node,b)}}(p,q)),m.push(q)}var r=this.getPortionReplacementNode(d,a);return g.parentNode.insertBefore(e,g),g.parentNode.insertBefore(l,g),g.parentNode.removeChild(g),i.parentNode.insertBefore(r,i),i.parentNode.insertBefore(f,i),i.parentNode.removeChild(i),this.reverts.push(function(){e.parentNode.removeChild(e),l.parentNode.replaceChild(g,l),f.parentNode.removeChild(f),r.parentNode.replaceChild(i,r)}),r}},b}()),U=function(){var a=S.create("div");return a.appendChild(S.create("","0-")),a.appendChild(S.create("","2")),a.normalize(),2!==a.firstChild.length}();S.extend(T.fn,{normalize:function(){return U&&this.context.normalize(),this},jinzify:function(a){return this.filter(a||null).avoid("h-jinze").replace(R.jinze.touwei,function(a,b){var c=S.create("h-jinze","touwei");return c.innerHTML=b[0],0===a.index&&a.isEnd||1===a.index?c:""}).replace(R.jinze.wei,function(a,b){var c=S.create("h-jinze","wei");return c.innerHTML=b[0],0===a.index?c:""}).replace(R.jinze.tou,function(a,b){var c=S.create("h-jinze","tou");return c.innerHTML=b[0],0===a.index&&a.isEnd||1===a.index?c:""}).replace(R.jinze.middle,function(a,b){var c=S.create("h-jinze","middle");return c.innerHTML=b[0],0===a.index&&a.isEnd||1===a.index?c:""}).endAvoid().endFilter()},groupify:function(a){var a=S.extend({biaodian:!1,hanzi:!1,kana:!1,eonmun:!1,western:!1},a||{});return this.avoid("h-word, h-char-group"),a.biaodian&&this.replace(R.group.biaodian[0],d).replace(R.group.biaodian[1],d),(a.hanzi||a.cjk)&&this.wrap(R.group.hanzi,S.clone(S.create("h-char-group","hanzi cjk"))),a.western&&this.wrap(R.group.western,S.clone(S.create("h-word","western"))),a.kana&&this.wrap(R.group.kana,S.clone(S.create("h-char-group","kana"))),(a.eonmun||a.hangul)&&this.wrap(R.group.eonmun,S.clone(S.create("h-word","eonmun hangul"))),this.endAvoid(),this},charify:function(a){var a=S.extend({avoid:!0,biaodian:!1,punct:!1,hanzi:!1,latin:!1,ellinika:!1,kirillica:!1,kana:!1,eonmun:!1},a||{});return a.avoid&&this.avoid("h-char"),a.biaodian&&this.replace(R["char"].biaodian.all,c(a.biaodian)||function(a){return e(a.text)}).replace(R["char"].biaodian.liga,c(a.biaodian)||function(a){return e(a.text)}),(a.hanzi||a.cjk)&&this.wrap(R["char"].hanzi,c(a.hanzi||a.cjk)||S.clone(S.create("h-char","hanzi cjk"))),a.punct&&this.wrap(R["char"].punct.all,c(a.punct)||S.clone(S.create("h-char","punct"))),a.latin&&this.wrap(R["char"].latin,c(a.latin)||S.clone(S.create("h-char","alphabet latin"))),(a.ellinika||a.greek)&&this.wrap(R["char"].ellinika,c(a.ellinika||a.greek)||S.clone(S.create("h-char","alphabet ellinika greek"))),(a.kirillica||a.cyrillic)&&this.wrap(R["char"].kirillica,c(a.kirillica||a.cyrillic)||S.clone(S.create("h-char","alphabet kirillica cyrillic"))),a.kana&&this.wrap(R["char"].kana,c(a.kana)||S.clone(S.create("h-char","kana"))),(a.eonmun||a.hangul)&&this.wrap(R["char"].eonmun,c(a.eonmun||a.hangul)||S.clone(S.create("h-char","eonmun hangul"))),this.endAvoid(),this}}),S.extend(O,{isNodeNormalizeNormal:U,find:T,createBDGroup:d,createBDChar:e}),S.matches=O.find.matches,void["setMode","wrap","replace","revert","addBoundary","removeBoundary","avoid","endAvoid","filter","endFilter","jinzify","groupify","charify"].forEach(function(a){O.fn[a]=function(){return this.finder||(this.finder=O.find(this.context)),this.finder[a](arguments[0],arguments[1]),this}});var V={};V.writeOnCanvas=g,V.compareCanvases=h,V.detectFont=i,V.support=function(){function b(a){var b,c=a.charAt(0).toUpperCase()+a.slice(1),d=(a+" "+e.join(c+" ")+c).split(" ");return d.forEach(function(a){"string"==typeof f.style[a]&&(b=!0)}),b||!1}function c(a,b){var c,d,e,f=L||S.create("body"),g=S.create("div"),h=L?g:f,b="function"==typeof b?b:function(){};return c=[""].join(""),h.innerHTML+=c,f.appendChild(g),L||(f.style.background="",f.style.overflow="hidden",e=K.style.overflow,K.style.overflow="hidden",K.appendChild(f)),d=b(h,a),S.remove(h),L||(K.style.overflow=e),!!d}function d(b,c){var d;return a.getComputedStyle?d=J.defaultView.getComputedStyle(b,null).getPropertyValue(c):b.currentStyle&&(d=b.currentStyle[c]),d}var e="Webkit Moz ms".split(" "),f=S.create("h-test");return{columnwidth:b("columnWidth"),fontface:function(){var a;return c('@font-face { font-family: font; src: url("//"); }',function(b,c){var d=S.qsa("style",b)[0],e=d.sheet||d.styleSheet,f=e?e.cssRules&&e.cssRules[0]?e.cssRules[0].cssText:e.cssText||"":"";a=/src/i.test(f)&&0===f.indexOf(c.split(" ")[0])}),a}(),ruby:function(){var a,b=S.create("ruby"),c=S.create("rt"),e=S.create("rp");return b.appendChild(e),b.appendChild(c),K.appendChild(b),a="none"===d(e,"display")||"ruby"===d(b,"display")&&"ruby-text"===d(c,"display")?!0:!1,K.removeChild(b),b=null,c=null,e=null,a}(),"ruby-display":function(){var a=S.create("div");return a.innerHTML='',"ruby"===a.querySelector("h-test-a").style.display&&"ruby-text-container"===a.querySelector("h-test-b").style.display}(),"ruby-interchar":function(){var a,b="inter-character",c=S.create("div");return c.innerHTML='',a=c.querySelector("h-test").style,a.rubyPosition===b||a.WebkitRubyPosition===b||a.MozRubyPosition===b||a.msRubyPosition===b}(),textemphasis:b("textEmphasis"),unicoderange:function(){var a;return c('@font-face{font-family:test-for-unicode-range;src:local(Arial),local("Droid Sans")}@font-face{font-family:test-for-unicode-range;src:local("Times New Roman"),local(Times),local("Droid Serif");unicode-range:U+270C}',function(){a=!V.detectFont("test-for-unicode-range",'Arial, "Droid Sans"',"Q")}),a}(),writingmode:b("writingMode")}}(),V.initCond=function(a){var b,a=a||K,c="";for(var d in V.support)b=(V.support[d]?"":"no-")+d,a.classList.add(b),c+=b+" ";return c};var W=V.support["ruby-interchar"];S.extend(V,{renderRuby:function(a,b){var b=b||"ruby",c=S.qsa(b,a);S.qsa("rtc",a).concat(c).map(n),c.forEach(function(a){var b,c=a.classList;c.contains("complex")?b=l(a):c.contains("zhuyin")&&(b=W?k(a):j(a)),b&&a.parentNode.replaceChild(b,a)})},simplifyRubyClass:n,getZhuyinHTML:q,renderComplexRuby:l,renderSimpleRuby:j,renderInterCharRuby:k}),S.extend(V,{renderElem:function(a){this.renderRuby(a),this.renderDecoLine(a),this.renderDecoLine(a,"s, del"),this.renderEm(a)},renderDecoLine:function(a,b){var c=S.qsa(b||"u, ins",a),d=c.length;a:for(;d--;){var e=c[d],f=null;do{if(f=(f||e).previousSibling,!f)continue a;c[d-1]===f&&e.classList.add("adjacent")}while(S.isIgnorable(f))}},renderEm:function(a,b){var c=b?"qsa":"tag",b=b||"em",d=S[c](b,a);d.forEach(function(a){var b=O(a);V.support.textemphasis?b.avoid("rt, h-char").charify({biaodian:!0,punct:!0}):b.avoid("rt, h-char, h-char-group").jinzify().groupify({western:!0}).charify({hanzi:!0,biaodian:!0,punct:!0,latin:!0,ellinika:!0,kirillica:!0})})}}),O.normalize=V,O.localize=V,O.support=V.support,O.detectFont=V.detectFont,O.fn.initCond=function(){return this.condition.classList.add("han-js-rendered"),O.normalize.initCond(this.condition),this},void["Elem","DecoLine","Em","Ruby"].forEach(function(a){var b="render"+a;O.fn[b]=function(a){return O.normalize[b](this.context,a),this}}),S.extend(O.support,{heiti:!0,songti:O.detectFont('"Han Songti"'),"songti-gb":O.detectFont('"Han Songti GB"'),kaiti:O.detectFont('"Han Kaiti"'),fangsong:O.detectFont('"Han Fangsong"')}),O.correctBiaodian=function(a){var a=a||J,b=O.find(a);return b.avoid("h-char").replace(/([\u2018\u201c])/g,function(a){var b=O.createBDChar(a.text);return b.classList.add("bd-open","punct"),b}).replace(/([\u2019\u201d])/g,function(a){var b=O.createBDChar(a.text);return b.classList.add("bd-close","bd-end","punct"),b}),O.support.unicoderange?b:b.charify({biaodian:!0})},O.correctBasicBD=O.correctBiaodian,O.correctBD=O.correctBiaodian,S.extend(O.fn,{biaodian:null,correctBiaodian:function(){return this.biaodian=O.correctBiaodian(this.context),this},revertCorrectedBiaodian:function(){try{this.biaodian.revert("all")}catch(a){}return this}}),O.fn.correctBasicBD=O.fn.correctBiaodian,O.fn.revertBasicBD=O.fn.revertCorrectedBiaodian;var X="<>",Y=S.create("h-hws");Y.setAttribute("hidden",""),Y.innerHTML=" ";var Z;S.extend(O,{renderHWS:function(a,b){var c=b?"textarea, code, kbd, samp, pre":"textarea",d=b?"strict":"base",a=a||J,e=O.find(a); +return e.avoid(c).replace(O.TYPESET.hws[d][0],t).replace(O.TYPESET.hws[d][1],t).replace(new RegExp("("+X+")+","g"),u).replace(/([\'"])\s(.+?)\s\1/g,v).replace(/\s[\u2018\u201c]/g,w).replace(/[\u2019\u201d]\s/g,w).normalize(),e}}),S.extend(O.fn,{renderHWS:function(a){return O.renderHWS(this.context,a),this},revertHWS:function(){return S.tag("h-hws",this.context).forEach(function(a){S.remove(a)}),this.HWS=[],this}});var $="bd-hangable",_="h-char.bd-hangable",aa='',ba=O.find.matches;O.support["han-space"]=x(),S.extend(O,{detectSpaceFont:x,isSpaceFontLoaded:x(),renderHanging:function(a){var a=a||J,b=O.find(a);return b.avoid("textarea, code, kbd, samp, pre").avoid(_).replace(R.jinze.hanging,function(a){if(/^[\x20\t\r\n\f]+$/.test(a.text))return"";var b,c,d,e,f=a.node.parentNode;return(b=S.parent(f,"h-jinze"))&&y(b),e=a.text.trim(),c=O.createBDChar(e),c.innerHTML=""+e+"",c.classList.add($),d=S.parent(f,"h-char.biaodian"),d?function(){return d.classList.add($),ba(f,"h-inner, h-inner *")?e:c.firstChild}():c}),b}}),S.extend(O.fn,{renderHanging:function(){var a=this.condition.classList;return O.isSpaceFontLoaded=x(),O.isSpaceFontLoaded&&a.contains("no-han-space")&&(a.remove("no-han-space"),a.add("han-space")),O.renderHanging(this.context),this},revertHanging:function(){return S.qsa("h-char.bd-hangable, h-cs.hangable-outer",this.context).forEach(function(a){var b=a.classList;b.remove("bd-hangable"),b.remove("hangable-outer")}),this}});var ca,da,ea="bd-jiya",fa="h-char.bd-jiya",ga="bd-consecutive",ha='',ba=O.find.matches;O.renderJiya=function(a){var a=a||J,b=O.find(a);return b.avoid("textarea, code, kbd, samp, pre, h-cs").avoid(fa).charify({avoid:!1,biaodian:A}).endAvoid().avoid("textarea, code, kbd, samp, pre, h-cs").replace(R.group.biaodian[0],B).replace(R.group.biaodian[1],B),b},S.extend(O.fn,{renderJiya:function(){return O.renderJiya(this.context),this},revertJiya:function(){return S.qsa("h-char.bd-jiya, h-cs.jiya-outer",this.context).forEach(function(a){var b=a.classList;b.remove("bd-jiya"),b.remove("jiya-outer")}),this}});var ia="textarea, code, kbd, samp, pre",ja=S.create("h-char","comb-liga");return S.extend(O,{isVowelCombLigaNormal:F(),isVowelICombLigaNormal:G(),isZhuyinCombLigaNormal:H(),isCombLigaNormal:G()(),substVowelCombLiga:I(O.TYPESET["display-as"]["comb-liga-vowel"]),substZhuyinCombLiga:I(O.TYPESET["display-as"]["comb-liga-zhuyin"]),substCombLigaWithPUA:I(O.TYPESET["display-as"]["comb-liga-pua"]),substInaccurateChar:function(a){var a=a||J,b=O.find(a);b.avoid(ia),O.TYPESET["inaccurate-char"].forEach(function(a){b.replace(new RegExp(a[0],"ig"),a[1])})}}),S.extend(O.fn,{"comb-liga-vowel":null,"comb-liga-vowel-i":null,"comb-liga-zhuyin":null,"inaccurate-char":null,substVowelCombLiga:function(){return this["comb-liga-vowel"]=O.substVowelCombLiga(this.context),this},substVowelICombLiga:function(){return this["comb-liga-vowel-i"]=O.substVowelICombLiga(this.context),this},substZhuyinCombLiga:function(){return this["comb-liga-zhuyin"]=O.substZhuyinCombLiga(this.context),this},substCombLigaWithPUA:function(){return O.isVowelCombLigaNormal()?O.isVowelICombLigaNormal()||(this["comb-liga-vowel-i"]=O.substVowelICombLiga(this.context)):this["comb-liga-vowel"]=O.substVowelCombLiga(this.context),O.isZhuyinCombLigaNormal()||(this["comb-liga-zhuyin"]=O.substZhuyinCombLiga(this.context)),this},revertVowelCombLiga:function(){try{this["comb-liga-vowel"].revert("all")}catch(a){}return this},revertVowelICombLiga:function(){try{this["comb-liga-vowel-i"].revert("all")}catch(a){}return this},revertZhuyinCombLiga:function(){try{this["comb-liga-zhuyin"].revert("all")}catch(a){}return this},revertCombLigaWithPUA:function(){try{this["comb-liga-vowel"].revert("all"),this["comb-liga-vowel-i"].revert("all"),this["comb-liga-zhuyin"].revert("all")}catch(a){}return this},substInaccurateChar:function(){return this["inaccurate-char"]=O.substInaccurateChar(this.context),this},revertInaccurateChar:function(){try{this["inaccurate-char"].revert("all")}catch(a){}return this}}),a.addEventListener("DOMContentLoaded",function(){var a;K.classList.contains("han-init")?O.init():(a=J.querySelector(".han-init-context"))&&(O.init=O(a).render())}),("undefined"==typeof b||b===!1)&&(a.Han=O),O}); \ No newline at end of file diff --git a/lib/algolia-instant-search/instantsearch.min.css b/lib/algolia-instant-search/instantsearch.min.css index e69de29b..590f6f98 100644 --- a/lib/algolia-instant-search/instantsearch.min.css +++ b/lib/algolia-instant-search/instantsearch.min.css @@ -0,0 +1 @@ +/*! instantsearch.js 1.5.0 | © Algolia Inc. and other contributors; Licensed MIT | github.com/algolia/instantsearch.js */.ais-search-box--powered-by{font-size:.8em;text-align:right;margin-top:2px}.ais-search-box--powered-by-link{display:inline-block;width:45px;height:16px;text-indent:101%;overflow:hidden;white-space:nowrap;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAAAgCAYAAABwzXTcAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAGHRFWHRTb2Z0d2FyZQBwYWludC5uZXQgNC4wLjVlhTJlAAAIJElEQVRoQ+1Za2xURRTugqJVEBAlhICBRFEQeRfodssqiDZaS8vu3dsXVlAbxReJwVfAoqJ/sBqE3S1IgqgBrY9EQ6KJiUAokUfpvQUKogIBlKbyEEUolNL6ndkzw9129+72YaFJv+Rk737nzMyZ756dmXs3oQtd6EJ7oaioqJvX603kr1cl8vPzb+TLzo3MzMx+Xk0r03y+0x5Ne4vpqwoohjeQ4yHYcaYiwcGfVz+ysrIGQfBGsqtWdE37lvLz+nwnmVLIyMjoBd9GxPwL/wKmOw4zCgr6YPBNSGILEviYaVt0dtHxK/DK/BFXq2lad3Z1DJDUqzIBYZrmYldUdLToI4r29HCWmLozUPmEK2AUOgOmRysttRXKTnSPxzMWfD37q0B13DJTUFBwPQatlgKKJJAsu6Oio0VPDlQsTgmajWEWMOaxOyLsRCdQccGez87OHshUxwAJzZbiIYFKkaSmXdJ1fRiHRERHi+4MGk+mBMwXnSVGPj7nQPS3qeLZHRGxRL9ScCAxk8Ur92Rnj5VCItHlHBMRrRDdQRXl8/nG4eaOp5uKz57sC8OkoDEkOWCO5K8CtJRgabnT6TfuS/ZXOKet2duPXVHRDqI7svLz+yPnJCxH07ANuGFDiQ+5WwF0NkWJrOuziEOCm5n7Jy8v7yYRGAHxio4kEyHuK+j3oIyXRr8o2G/wrUXMGIonQbFe18Kq3Ms39By/orw3KnsxKr06fHkxLjkDxubkEuNhMVAE2Ikuni98vsMYtwafQaYVwLvQ9qg1X2mI/xXzyuXQlgGNP+NO/kxLS7tOcOhMda7rz4rACIhH9Ky8vEGY+G4ZZ2ua9hi1gbhvQvBDScu3DUC1j8X1YSV0wDgLsX9m7tJl3lw9onRPDzGoBTFFp1NLyL+WaQUU5GSZG+IuIeYCrhskJ3ivN6o+EYFJDuCOaNBipuXGepI73gMq4k8pluh0E5GsXLoo8U1IMgPLyhDYYExqNL6/Lv1S9FT/7sHOkp0TXCvNYbgBp0hUfB6A2D6rsKn+7YMh9nvOoHkxJL6xLiGhMSzXtoiOfHqDn41ch5MmFC+O1ihEtDnP7c5QHDeJDTSQx8QGTH4E0wLwLWVfo0fXU5kOQyzR0ecL0o/EvoI1O95ZlzcpugAmiKVjKwu+1f2+0Yc9As5VZb3gX4JfQn9XwEyH+HUi1m/kc4hAW0S3A3J9TeaNOWQybQ8aEA0O8IDbmFagM6zsFP5PmA5DTNF5WUH7c7QZMR2GaKK7Ssw0FvyMe2XlIKYVUkrMR4Q/YB6b4t85HKIv5Pj9CY2Xq/3/Ep2qX+aN4prPtD0w2ftlI0z2GaatsJ5qztLPinkFO9Fzc3P7ghfrH/r5nulmiCY6qnhVSEQz4gkKIvvJD2sQS8yqfb3wifWeuN2jOazdRIewibQszszJuYO0yMnJuUXmjbZFHGYPTHAdN7iQOWtWxKMXfPNkx5FujJ3oEHOk9KGfpUw3QzTRsWHuCAloZDFlQaMDN+Ugqrocy8tUJulG/Mg34lGm2iR6YWHhteDnIq8diLmo8gwV0zH5HTGxRcddu1kOhg6PotGCKKbWdVg5N1eIIfpo1VbT3mW6GWxE30cCulbscjOlkLRsb7+UQGUuVOvGlABu0JdC9IChCqS1olNlg9+ocqOY0PG2FrHi1YHi4xJd15+2NorTaLO9h7sQsBOdTieqLX5VTDdD9OXFLCMBm26MdqANV7QpMXWm2iK69VS1AXmm0AmGfOIX4PUmS398omPjFME0oKZtsTPEqDM22qljJcFOdLTtDv4E+2vkM0BT2FR6sRAwaJQyZYuJ2Gyx5NSj2htSPzDpiVGg1aLzfga+mqqeaQX6L0HmjRh70a27Lib5KdNRgZjelsSq3W73NewKEx1xYaITwJVY/IuYDkM00Scv2zGOBETF1+MkM4npqIDga8RNwhMqUwKtFt3n+13wmlbGVBhaJDom9o4MxoQfYtoW6PQLNYDXqx65cX2r4n2+j5hWoN0e/BmOoeUpgDFH0qsFXA+FPQ5/lezDKjoBoq8Ta3TQ/MPl3zWK6XBAOMQtCglu1qcsN8NeScvcIV5d01cadqIjF9o8qd0p+rODaYW4RedBjnBwjbVq7QChPJYBPmda9Ef9sO88fC/NnDnzLnYL4MFqBvk4xt6aiO5ebfSBoLu5gmtxXZzsr0hyBXb1xRFxYHKwwivXfrJkv/EyN1VAn4tk/8hvPebyIK3J5ItR6Qssee1Ageh4drkbn7dT4fC8ZL/RRUeDqZZA2zeIVqAd7eSnud05JKEee3GtnsyEYUlhlwK4MWi3HiZeOVjsF/g+VN+biE6gN4nOYOV3UtiIhvO5028+xU3CgD5vg7B/yzFwXSf3FzvR6Y9s+Lar3GwMbW1Ex7kbHW0iw12bwHRcQPILVVtdn8Y0wYF+52LwChhV+3PMN8N0TARVQu9bJtKLMFAO5HGvSh7VFIpsikaHeNQPGt9A5JMkNG2asP2wJfSuhgMjwpOdPQp5fY0xTiD/vUxL0X8Q88JphWkF8Q5K1+dj7hVoby2Yi+Bq0G4nPkvRdjo36XiI5aaF/zNiUur9DN0Mpu3gmFx8JHH8inKxRLQUcmlpKWhesN4Zc+b0aukcrwSivuynR2lUkHjHjqo53lpBumABKjcRolbBluJ6FpaWKVTNWJ4eQLXQXnD5DwJ852ZdaAsgsvoTwM5wU1Z3hp9spwCqeigELcbS8RPE/QvX9M6iAd/rcH0YtrbJptyFdoYD1dwjPT39hnifD7rQhTiRkPAfxnOcWpCmnRwAAAAASUVORK5CYII=);background-repeat:no-repeat;background-size:contain;vertical-align:middle}.ais-pagination--item{display:inline-block;padding:3px}.ais-range-slider--value,.ais-range-slider--value-sub{font-size:.8em;padding-top:15px}.ais-pagination--item__disabled{visibility:hidden}.ais-hierarchical-menu--list__lvl1,.ais-hierarchical-menu--list__lvl2{margin-left:10px}.ais-range-slider--target{position:relative;direction:ltr;background:#F3F4F7;height:6px;margin-top:2em;margin-bottom:2em}.ais-range-slider--base{height:100%;position:relative;z-index:1;border-top:1px solid #DDD;border-bottom:1px solid #DDD;border-left:2px solid #DDD;border-right:2px solid #DDD}.ais-range-slider--origin{position:absolute;right:0;top:0;left:0;bottom:0}.ais-range-slider--connect{background:#46AEDA}.ais-range-slider--background{background:#F3F4F7}.ais-range-slider--handle{width:20px;height:20px;position:relative;z-index:1;background:#FFF;border:1px solid #46AEDA;border-radius:50%;cursor:pointer}.ais-range-slider--handle-lower{left:-10px;bottom:7px}.ais-range-slider--handle-upper{right:10px;bottom:7px}.ais-range-slider--tooltip{position:absolute;background:#FFF;top:-22px;font-size:.8em}.ais-range-slider--pips{box-sizing:border-box;position:absolute;height:3em;top:100%;left:0;width:100%}.ais-range-slider--value{width:40px;position:absolute;text-align:center;margin-left:-20px}.ais-range-slider--marker{position:absolute;background:#DDD;margin-left:-1px;width:1px;height:5px}.ais-range-slider--marker-sub{background:#DDD;width:2px;margin-left:-2px;height:13px}.ais-range-slider--marker-large{background:#DDD;width:2px;margin-left:-2px;height:12px}.ais-star-rating--star,.ais-star-rating--star__empty{display:inline-block;width:1em;height:1em}.ais-range-slider--marker-large:first-child{margin-left:0}.ais-star-rating--item{vertical-align:middle}.ais-star-rating--item__active{font-weight:700}.ais-star-rating--star:before{content:'\2605';color:#FBAE00}.ais-star-rating--star__empty:before{content:'\2606';color:#FBAE00}.ais-star-rating--link__disabled .ais-star-rating--star:before,.ais-star-rating--link__disabled .ais-star-rating--star__empty:before{color:#C9C9C9}.ais-root__collapsible .ais-header{cursor:pointer}.ais-root__collapsed .ais-body,.ais-root__collapsed .ais-footer{display:none} \ No newline at end of file diff --git a/lib/algolia-instant-search/instantsearch.min.js b/lib/algolia-instant-search/instantsearch.min.js index e69de29b..2bd5d590 100644 --- a/lib/algolia-instant-search/instantsearch.min.js +++ b/lib/algolia-instant-search/instantsearch.min.js @@ -0,0 +1,15 @@ +/*! instantsearch.js 1.5.0 | © Algolia Inc. and other contributors; Licensed MIT | github.com/algolia/instantsearch.js */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.instantsearch=t():e.instantsearch=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}var o=n(1),i=r(o);e.exports=i["default"]},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(t,"__esModule",{value:!0}),n(2),n(3);var o=n(4),i=r(o),a=n(5),s=r(a),u=n(99),l=r(u),c=n(222),f=r(c),p=n(400),d=r(p),h=n(404),m=r(h),v=n(408),g=r(v),y=n(411),b=r(y),_=n(416),C=r(_),w=n(420),x=r(w),P=n(422),E=r(P),R=n(424),S=r(R),O=n(425),T=r(O),k=n(432),N=r(k),j=n(437),A=r(j),M=n(439),F=r(M),I=n(443),D=r(I),U=n(444),L=r(U),H=n(447),V=r(H),B=n(450),q=r(B),W=n(220),K=r(W),Q=(0,i["default"])(s["default"]);Q.widgets={clearAll:f["default"],currentRefinedValues:d["default"],hierarchicalMenu:m["default"],hits:g["default"],hitsPerPageSelector:b["default"],menu:C["default"],refinementList:x["default"],numericRefinementList:E["default"],numericSelector:S["default"],pagination:T["default"],priceRanges:N["default"],searchBox:A["default"],rangeSlider:F["default"],sortBySelector:D["default"],starRating:L["default"],stats:V["default"],toggle:q["default"]},Q.version=K["default"],Q.createQueryString=l["default"].url.getQueryStringFromState,t["default"]=Q},function(e,t){"use strict";Object.freeze||(Object.freeze=function(e){if(Object(e)!==e)throw new TypeError("Object.freeze can only be called on Objects.");return e})},function(e,t){"use strict";var n={};if(!Object.setPrototypeOf&&!n.__proto__){var r=Object.getPrototypeOf;Object.getPrototypeOf=function(e){return e.__proto__?e.__proto__:r.call(Object,e)}}},function(e,t){"use strict";function n(e){var t=function(){for(var t=arguments.length,n=Array(t),o=0;t>o;o++)n[o]=arguments[o];return new(r.apply(e,[null].concat(n)))};return t.__proto__=e,t.prototype=e.prototype,t}var r=Function.prototype.bind;e.exports=n},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function s(){return"#"}function u(e,t){if(!t.getConfiguration)return e;var n=t.getConfiguration(e);return(0,y["default"])({},e,n,function(e,t){return Array.isArray(e)?(0,_["default"])(e,t):void 0})}Object.defineProperty(t,"__esModule",{value:!0});var l=Object.assign||function(e){for(var t=1;te;e+=2){var t=re[e],n=re[e+1];t(n),re[e]=void 0,re[e+1]=void 0}G=0}function v(){try{var e=n(11);return Q=e.runOnLoop||e.runOnContext,f()}catch(t){return h()}}function g(e,t){var n=this,r=n._state;if(r===se&&!e||r===ue&&!t)return this;var o=new this.constructor(b),i=n._result;if(r){var a=arguments[r-1];X(function(){F(r,o,a,i)})}else N(n,o,e,t);return o}function y(e){var t=this;if(e&&"object"==typeof e&&e.constructor===t)return e;var n=new t(b);return S(n,e),n}function b(){}function _(){return new TypeError("You cannot resolve a promise with itself")}function C(){return new TypeError("A promises callback cannot return that same promise.")}function w(e){try{return e.then}catch(t){return le.error=t,le}}function x(e,t,n,r){try{e.call(t,n,r)}catch(o){return o}}function P(e,t,n){X(function(e){var r=!1,o=x(n,t,function(n){r||(r=!0,t!==n?S(e,n):T(e,n))},function(t){r||(r=!0,k(e,t))},"Settle: "+(e._label||" unknown promise"));!r&&o&&(r=!0,k(e,o))},e)}function E(e,t){t._state===se?T(e,t._result):t._state===ue?k(e,t._result):N(t,void 0,function(t){S(e,t)},function(t){k(e,t)})}function R(e,t,n){t.constructor===e.constructor&&n===oe&&constructor.resolve===ie?E(e,t):n===le?k(e,le.error):void 0===n?T(e,t):s(n)?P(e,t,n):T(e,t)}function S(e,t){e===t?k(e,_()):a(t)?R(e,t,w(t)):T(e,t)}function O(e){e._onerror&&e._onerror(e._result),j(e)}function T(e,t){e._state===ae&&(e._result=t,e._state=se,0!==e._subscribers.length&&X(j,e))}function k(e,t){e._state===ae&&(e._state=ue,e._result=t,X(O,e))}function N(e,t,n,r){var o=e._subscribers,i=o.length;e._onerror=null,o[i]=t,o[i+se]=n,o[i+ue]=r,0===i&&e._state&&X(j,e)}function j(e){var t=e._subscribers,n=e._state;if(0!==t.length){for(var r,o,i=e._result,a=0;aa;a++)N(r.resolve(e[a]),void 0,t,n);return o}function L(e){var t=this,n=new t(b);return k(n,e),n}function H(){throw new TypeError("You must pass a resolver function as the first argument to the promise constructor")}function V(){throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.")}function B(e){this._id=he++,this._state=void 0,this._result=void 0,this._subscribers=[],b!==e&&("function"!=typeof e&&H(),this instanceof B?I(this,e):V())}function q(e,t){this._instanceConstructor=e,this.promise=new e(b),Array.isArray(t)?(this._input=t,this.length=t.length,this._remaining=t.length,this._result=new Array(this.length),0===this.length?T(this.promise,this._result):(this.length=this.length||0,this._enumerate(),0===this._remaining&&T(this.promise,this._result))):k(this.promise,this._validationError())}function W(){var e;if("undefined"!=typeof o)e=o;else if("undefined"!=typeof self)e=self;else try{e=Function("return this")()}catch(t){throw new Error("polyfill failed because global object is unavailable in this environment")}var n=e.Promise;n&&"[object Promise]"===Object.prototype.toString.call(n.resolve())&&!n.cast||(e.Promise=me)}var K;K=Array.isArray?Array.isArray:function(e){return"[object Array]"===Object.prototype.toString.call(e)};var Q,$,z,Y=K,G=0,X=function(e,t){re[G]=e,re[G+1]=t,G+=2,2===G&&($?$(m):z())},J="undefined"!=typeof window?window:void 0,Z=J||{},ee=Z.MutationObserver||Z.WebKitMutationObserver,te="undefined"!=typeof e&&"[object process]"==={}.toString.call(e),ne="undefined"!=typeof Uint8ClampedArray&&"undefined"!=typeof importScripts&&"undefined"!=typeof MessageChannel,re=new Array(1e3);z=te?c():ee?p():ne?d():void 0===J?v():h();var oe=g,ie=y,ae=void 0,se=1,ue=2,le=new A,ce=new A,fe=D,pe=U,de=L,he=0,me=B;B.all=fe,B.race=pe,B.resolve=ie,B.reject=de,B._setScheduler=u,B._setAsap=l,B._asap=X,B.prototype={constructor:B,then:oe,"catch":function(e){return this.then(null,e)}};var ve=q;q.prototype._validationError=function(){return new Error("Array Methods must be provided an Array")},q.prototype._enumerate=function(){for(var e=this.length,t=this._input,n=0;this._state===ae&&e>n;n++)this._eachEntry(t[n],n)},q.prototype._eachEntry=function(e,t){var n=this._instanceConstructor,r=n.resolve;if(r===ie){var o=w(e);if(o===oe&&e._state!==ae)this._settledAt(e._state,t,e._result);else if("function"!=typeof o)this._remaining--,this._result[t]=e;else if(n===me){var i=new n(b);R(i,e,o),this._willSettleAt(i,t)}else this._willSettleAt(new n(function(t){t(e)}),t)}else this._willSettleAt(r(e),t)},q.prototype._settledAt=function(e,t,n){var r=this.promise;r._state===ae&&(this._remaining--,e===ue?k(r,n):this._result[t]=n),0===this._remaining&&T(r,this._result)},q.prototype._willSettleAt=function(e,t){var n=this;N(e,void 0,function(e){n._settledAt(se,t,e)},function(e){n._settledAt(ue,t,e)})};var ge=W,ye={Promise:me,polyfill:ge};n(12).amd?(r=function(){return ye}.call(t,n,t,i),!(void 0!==r&&(i.exports=r))):"undefined"!=typeof i&&i.exports?i.exports=ye:"undefined"!=typeof this&&(this.ES6Promise=ye),ge()}).call(this)}).call(t,n(9),function(){return this}(),n(10)(e))},function(e,t){function n(){l=!1,a.length?u=a.concat(u):c=-1,u.length&&r()}function r(){if(!l){var e=setTimeout(n);l=!0;for(var t=u.length;t;){for(a=u,u=[];++c1)for(var n=1;n=u.hosts[e.hostType].length&&(d||!h)?u._promise.reject(r):(u.hostIndex[e.hostType]=++u.hostIndex[e.hostType]%u.hosts[e.hostType].length,r instanceof c.RequestTimeout?v():(d||(f=1/0),t(n,s)))}function v(){return u.hostIndex[e.hostType]=++u.hostIndex[e.hostType]%u.hosts[e.hostType].length,s.timeout=u.requestTimeout*(f+1),t(n,s)}var g;if(u._useCache&&(g=e.url),u._useCache&&r&&(g+="_body_"+s.body),u._useCache&&a&&void 0!==a[g])return i("serving response from cache"),u._promise.resolve(JSON.parse(a[g]));if(f>=u.hosts[e.hostType].length)return!h||d?(i("could not get any response"),u._promise.reject(new c.AlgoliaSearchError("Cannot connect to the AlgoliaSearch API. Send an email to support@algolia.com to report and resolve the issue. Application id was: "+u.applicationID))):(i("switching to fallback"),f=0,s.method=e.fallback.method,s.url=e.fallback.url,s.jsonBody=e.fallback.body,s.jsonBody&&(s.body=l(s.jsonBody)),o=u._computeRequestHeaders(),s.timeout=u.requestTimeout*(f+1),u.hostIndex[e.hostType]=0,d=!0,t(u._request.fallback,s));var y=u.hosts[e.hostType][u.hostIndex[e.hostType]]+s.url,b={body:s.body,jsonBody:s.jsonBody,method:s.method,headers:o,timeout:s.timeout,debug:i};return i("method: %s, url: %s, headers: %j, timeout: %d",b.method,y,b.headers,b.timeout),n===u._request.fallback&&i("using fallback"),n.call(u,y,b).then(p,m)}var r,o,i=n(42)("algoliasearch:"+e.url),a=e.cache,u=this,f=0,d=!1,h=u._useFallback&&u._request.fallback&&e.fallback;this.apiKey.length>p&&void 0!==e.body&&void 0!==e.body.params?(e.body.apiKey=this.apiKey,o=this._computeRequestHeaders(!1)):o=this._computeRequestHeaders(),void 0!==e.body&&(r=l(e.body)),i("request start");var m=t(u._request,{url:e.url,method:e.method,body:r,jsonBody:e.body,timeout:u.requestTimeout*(f+1)});return e.callback?void m.then(function(t){s(function(){e.callback(null,t)},u._setTimeout||setTimeout)},function(t){s(function(){e.callback(t)},u._setTimeout||setTimeout)}):m},_getSearchParams:function(e,t){if(void 0===e||null===e)return t;for(var n in e)null!==n&&void 0!==e[n]&&e.hasOwnProperty(n)&&(t+=""===t?"":"&",t+=n+"="+encodeURIComponent("[object Array]"===Object.prototype.toString.call(e[n])?l(e[n]):e[n]));return t},_computeRequestHeaders:function(e){var t=n(15),r={"x-algolia-agent":this._ua,"x-algolia-application-id":this.applicationID};return e!==!1&&(r["x-algolia-api-key"]=this.apiKey),this.userToken&&(r["x-algolia-usertoken"]=this.userToken),this.securityTags&&(r["x-algolia-tagfilters"]=this.securityTags),this.extraHeaders&&t(this.extraHeaders,function(e){r[e.name]=e.value}),r}},r.prototype.Index.prototype={clearCache:function(){this.cache={}},addObject:function(e,t,n){var r=this;return 1!==arguments.length&&"function"!=typeof t||(n=t,t=void 0),this.as._jsonRequest({method:void 0!==t?"PUT":"POST",url:"/1/indexes/"+encodeURIComponent(r.indexName)+(void 0!==t?"/"+encodeURIComponent(t):""),body:e,hostType:"write",callback:n})},addObjects:function(e,t){var r=n(34),o="Usage: index.addObjects(arrayOfObjects[, callback])";if(!r(e))throw new Error(o);for(var i=this,a={requests:[]},s=0;sa&&(t=a),"published"!==e.status?c._promise.delay(t).then(n):e})}function r(e){s(function(){t(null,e)},c._setTimeout||setTimeout)}function o(e){s(function(){t(e)},c._setTimeout||setTimeout)}var i=100,a=5e3,u=0,l=this,c=l.as,f=n();return t?void f.then(r,o):f},clearIndex:function(e){var t=this;return this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/clear",hostType:"write",callback:e})},getSettings:function(e){var t=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/settings",hostType:"read",callback:e})},setSettings:function(e,t){var n=this;return this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(n.indexName)+"/settings",hostType:"write",body:e,callback:t})},listUserKeys:function(e){var t=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(t.indexName)+"/keys",hostType:"read",callback:e})},getUserKeyACL:function(e,t){var n=this;return this.as._jsonRequest({method:"GET",url:"/1/indexes/"+encodeURIComponent(n.indexName)+"/keys/"+e,hostType:"read",callback:t})},deleteUserKey:function(e,t){var n=this;return this.as._jsonRequest({method:"DELETE",url:"/1/indexes/"+encodeURIComponent(n.indexName)+"/keys/"+e,hostType:"write",callback:t})},addUserKey:function(e,t,r){var o=n(34),i="Usage: index.addUserKey(arrayOfAcls[, params, callback])";if(!o(e))throw new Error(i);1!==arguments.length&&"function"!=typeof t||(r=t,t=null);var a={acl:e};return t&&(a.validity=t.validity,a.maxQueriesPerIPPerHour=t.maxQueriesPerIPPerHour,a.maxHitsPerQuery=t.maxHitsPerQuery,a.description=t.description,t.queryParameters&&(a.queryParameters=this.as._getSearchParams(t.queryParameters,"")),a.referers=t.referers),this.as._jsonRequest({method:"POST",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys",body:a,hostType:"write",callback:r})},addUserKeyWithValidity:u(function(e,t,n){return this.addUserKey(e,t,n)},a("index.addUserKeyWithValidity()","index.addUserKey()")),updateUserKey:function(e,t,r,o){var i=n(34),a="Usage: index.updateUserKey(key, arrayOfAcls[, params, callback])";if(!i(t))throw new Error(a);2!==arguments.length&&"function"!=typeof r||(o=r,r=null);var s={acl:t};return r&&(s.validity=r.validity,s.maxQueriesPerIPPerHour=r.maxQueriesPerIPPerHour,s.maxHitsPerQuery=r.maxHitsPerQuery,s.description=r.description,r.queryParameters&&(s.queryParameters=this.as._getSearchParams(r.queryParameters,"")),s.referers=r.referers),this.as._jsonRequest({method:"PUT",url:"/1/indexes/"+encodeURIComponent(this.indexName)+"/keys/"+e,body:s,hostType:"write",callback:o})},_search:function(e,t,n){return this.as._jsonRequest({cache:this.cache,method:"POST",url:t||"/1/indexes/"+encodeURIComponent(this.indexName)+"/query",body:{params:e},hostType:"read",fallback:{method:"GET",url:"/1/indexes/"+encodeURIComponent(this.indexName),body:{params:e}},callback:n})},as:null,indexName:null,typeAheadArgs:null,typeAheadValueOption:null}},function(e,t,n){"use strict";function r(e,t){var r=n(15),o=this;"function"==typeof Error.captureStackTrace?Error.captureStackTrace(this,this.constructor):o.stack=(new Error).stack||"Cannot get a stacktrace, browser is too old",this.name=this.constructor.name,this.message=e||"Unknown error",t&&r(t,function(e,t){o[t]=e})}function o(e,t){function n(){var n=Array.prototype.slice.call(arguments,0);"string"!=typeof n[0]&&n.unshift(t),r.apply(this,n),this.name="AlgoliaSearch"+e+"Error"}return i(n,r),n}var i=n(7);i(r,Error),e.exports={AlgoliaSearchError:r,UnparsableJSON:o("UnparsableJSON","Could not parse the incoming response as JSON, see err.more for details"),RequestTimeout:o("RequestTimeout","Request timedout before getting a response"),Network:o("Network","Network issue, see err.more for details"),JSONPScriptFail:o("JSONPScriptFail"," + + + + + + + + + + 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/page/3/index.html b/page/3/index.html index e69de29b..c3a71a41 100644 --- a/page/3/index.html +++ b/page/3/index.html @@ -0,0 +1,2021 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/page/4/index.html b/page/4/index.html index e69de29b..442864aa 100644 --- a/page/4/index.html +++ b/page/4/index.html @@ -0,0 +1,1959 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/page/5/index.html b/page/5/index.html index e69de29b..ab35a1dc 100644 --- a/page/5/index.html +++ b/page/5/index.html @@ -0,0 +1,1901 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/page/6/index.html b/page/6/index.html index e69de29b..8743c6f6 100644 --- a/page/6/index.html +++ b/page/6/index.html @@ -0,0 +1,1864 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/page/7/index.html b/page/7/index.html index e69de29b..f3816eb1 100644 --- a/page/7/index.html +++ b/page/7/index.html @@ -0,0 +1,1882 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/page/8/index.html b/page/8/index.html index e69de29b..ca59afbb 100644 --- a/page/8/index.html +++ b/page/8/index.html @@ -0,0 +1,1749 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/AngularJS/index.html b/tags/AngularJS/index.html index e69de29b..56ec8a9d 100644 --- a/tags/AngularJS/index.html +++ b/tags/AngularJS/index.html @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: AngularJS | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/CSS/index.html b/tags/CSS/index.html index e69de29b..4369d5f5 100644 --- a/tags/CSS/index.html +++ b/tags/CSS/index.html @@ -0,0 +1,626 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: CSS | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/JavaScript/index.html b/tags/JavaScript/index.html index e69de29b..4b2ddc52 100644 --- a/tags/JavaScript/index.html +++ b/tags/JavaScript/index.html @@ -0,0 +1,854 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: JavaScript | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/JavaScript/page/2/index.html b/tags/JavaScript/page/2/index.html index e69de29b..fd404271 100644 --- a/tags/JavaScript/page/2/index.html +++ b/tags/JavaScript/page/2/index.html @@ -0,0 +1,854 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: JavaScript | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/JavaScript/page/3/index.html b/tags/JavaScript/page/3/index.html index e69de29b..69091495 100644 --- a/tags/JavaScript/page/3/index.html +++ b/tags/JavaScript/page/3/index.html @@ -0,0 +1,854 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: JavaScript | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/JavaScript/page/4/index.html b/tags/JavaScript/page/4/index.html index e69de29b..5258c668 100644 --- a/tags/JavaScript/page/4/index.html +++ b/tags/JavaScript/page/4/index.html @@ -0,0 +1,686 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: JavaScript | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/Vue/index.html b/tags/Vue/index.html index e69de29b..23e7634a 100644 --- a/tags/Vue/index.html +++ b/tags/Vue/index.html @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: Vue | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/Webpack/index.html b/tags/Webpack/index.html index e69de29b..065a0d67 100644 --- a/tags/Webpack/index.html +++ b/tags/Webpack/index.html @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: Webpack | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/createJS/index.html b/tags/createJS/index.html index e69de29b..82a1d816 100644 --- a/tags/createJS/index.html +++ b/tags/createJS/index.html @@ -0,0 +1,654 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: createJS | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/html/index.html b/tags/html/index.html index e69de29b..1319ff1d 100644 --- a/tags/html/index.html +++ b/tags/html/index.html @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: html | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/index.html b/tags/index.html index e69de29b..a349396b 100644 --- a/tags/index.html +++ b/tags/index.html @@ -0,0 +1,592 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + tags | 三木 + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + +
+ + + +
+
+ +

tags

+ + + +
+ + + + +
+ + + + +
+ + + +
+ + + +
+ + +
+ + + + + +
+ + + + + + + + + +
+
+ + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/jQuery/index.html b/tags/jQuery/index.html index e69de29b..1d2b84de 100644 --- a/tags/jQuery/index.html +++ b/tags/jQuery/index.html @@ -0,0 +1,682 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: jQuery | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/mongodb/index.html b/tags/mongodb/index.html index e69de29b..5059b4c1 100644 --- a/tags/mongodb/index.html +++ b/tags/mongodb/index.html @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: mongodb | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/node-js/index.html b/tags/node-js/index.html index e69de29b..20f291a8 100644 --- a/tags/node-js/index.html +++ b/tags/node-js/index.html @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: node.js | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/php/index.html b/tags/php/index.html index e69de29b..5f645185 100644 --- a/tags/php/index.html +++ b/tags/php/index.html @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: php | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/python/index.html b/tags/python/index.html index e69de29b..2a21b4c1 100644 --- a/tags/python/index.html +++ b/tags/python/index.html @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: python | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tags/svg/index.html b/tags/svg/index.html index e69de29b..681388af 100644 --- a/tags/svg/index.html +++ b/tags/svg/index.html @@ -0,0 +1,626 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: svg | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\346\200\273\347\273\223/index.html" "b/tags/\346\200\273\347\273\223/index.html" index e69de29b..7416f226 100644 --- "a/tags/\346\200\273\347\273\223/index.html" +++ "b/tags/\346\200\273\347\273\223/index.html" @@ -0,0 +1,854 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: 总结 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\346\200\273\347\273\223/page/2/index.html" "b/tags/\346\200\273\347\273\223/page/2/index.html" index e69de29b..0f2c4664 100644 --- "a/tags/\346\200\273\347\273\223/page/2/index.html" +++ "b/tags/\346\200\273\347\273\223/page/2/index.html" @@ -0,0 +1,686 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: 总结 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\347\256\227\346\263\225/index.html" "b/tags/\347\256\227\346\263\225/index.html" index e69de29b..4ec70ed3 100644 --- "a/tags/\347\256\227\346\263\225/index.html" +++ "b/tags/\347\256\227\346\263\225/index.html" @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: 算法 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git "a/tags/\350\256\276\350\256\241\346\250\241\345\274\217/index.html" "b/tags/\350\256\276\350\256\241\346\250\241\345\274\217/index.html" index e69de29b..b6847984 100644 --- "a/tags/\350\256\276\350\256\241\346\250\241\345\274\217/index.html" +++ "b/tags/\350\256\276\350\256\241\346\250\241\345\274\217/index.html" @@ -0,0 +1,822 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 标签: 设计模式 | 三木 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +