Wills's blogs


  • 首页

  • 分类

  • 归档

  • 标签
Wills's blogs

Vuex

发表于 2017-05-10 |

安装

直接下载/CDN引用

1
2
<script src="/path/to/vue.js"></script>
<script src="/path/to/vuex.js"></script>

npm

1
npm install vuex --save-dev

Yarn

1
yarn add vuex

在一个模块打包系统中,必须显示地通过Vue.use()来安装Vuex

1
2
3
4
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

Vuex是一个专为Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

使用例子如下:

main.js

1
2
3
4
5
6
7
8
import store from './store'
new Vue({
store,//注入组件当中
el: '#app',
render: h => h(App)
})

store.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
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex);
var state = {
count: 10
};
const mutations = {
increment(state) { //处理状态(数据)变化
state.count++;
},
decrement(state) {
state.count--;
}
};
const actions = {
increment: ({ //处理你要干什么,异步请求,判断,流程控制
commit
}) => {
commit('increment')
},
decrement: ({
commit
}) => {
commit('decrement');
},
clickOdd: ({
commit,
state
}) => {
if (state.count % 2 == 0) {
commit('increment')
}
},
clickAsync: ({
commit
}) => {
new Promise((resolve) => {
setTimeout(function() {
commit('increment');
resolve();
}, 1000);
});
}
};
const getters = {
count(state) {
return state.count;
},
getOdd(state) {
return state.count % 2 == 0 ? '偶数' : '奇数';
}
};
//需要导出Store对象
export default new Vuex.Store({
state,
mutations,
actions,
getters
});

App.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
29
30
<template>
<div id="app">
<h3>welcome vuex-demo</h3>
<input type="button" value="增加" @click="increment">
<input type="button" value="减少" @click="decrement">
<input type="button" value="偶数才能点击+" @click="clickOdd">
<input type="button" value="点击异步" @click="clickAsync">
<div>
现在数字为: {{count}}, 它现在是 {{getOdd}}
</div>
</div>
</template>
<script>
import {mapGetters, mapActions} from 'vuex'
export default{
computed:mapGetters([
'count',
'getOdd'
]),
methods:mapActions([//分发action
'increment',//映射 this.increment() 为 this.$store.dispatch('increment')
'decrement',
'clickOdd',
'clickAsync'
])
}
</script>

Wills's blogs

前端算法题

发表于 2017-03-17 | 分类于 前端开发 |

js写冒泡排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function bubbleSort(arr){
var arrLen = arr.length;
if(arrLen<=1){
return arr;
}else{
for(var i = 0;i < arrLen-1;i++){
for(var j = i+1;j<arrLen;j++){
if(arr[i]>arr[j]){
var temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
}

js写快速排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function quickSort(arr){
var arrLen = arr.length;
if(arrLen<=1){
return arr;
}else{
var left = [];
var right = [];
var basic = arr[0];
for(var i = 1;i < arrLen; i++){
if(arr[i]<basic){
left.push(arr[i]);
}else{
right.push(arr[i]);
}
}
return quickSort(left).concat(basic,quickSort(right));
}
}

js写二分搜素

1
2
3
4
5
6
7
8
9
10
11
12
function binarySearch(data,dist,startIndex,endIndex){
var startIndex = startIndex || 0;
var endIndex = endIndex || data.length-1;
var midIndex = Math.floor((startIndex+endIndex)/2);
if(dist == data[midIndex]){
return midIndex;
}else if(dist < data[startIndex]){
return binarySearch(data,dist,startIndex,midIndex-1);
}else{
return binarySearch(data,dist,midIndex+1,endIndex);
}
}

数组去重

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function uniq1(arr){
var res = [];
for(var i = 0;i < arr.length;i++){
if(res.indexOf(arr[i])==-1){
res.push(arr[i]);
}
}
return res;
}
function uniq2(arr){
var json = {};
var res = [];
for(var i = 0;i < arr.length;i++){
if(!json[arr[i]]){
json[arr[i]] = true;
res.push(arr[i]);
}
}
return res;
}

对象深度克隆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function deepClone(obj){
var buf;
if(obj instanceof Array){
buf = [];
for(var i = 0; i < obj.length;i++){
buf[i] = deepClone(obj[i]);
}
return buf;
}else if(obj instanceof Object){
buf = {};
for(var k in obj){
buf[k] = deepClone(obj[k]);
}
return buf;
}else{
return obj;
}
}

斐波拉契方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function fibonacci(count){
if(count<0){
return count;
}
if(count <= 1){
return 1;
}
var first = 1;
var second = 1;
var third = 0;
for(var i = 2; i <= count;i++){
third = first + second;
first = second;
second = third;
}
return third;
}

判断一个字符串中出现次数最多的字符,统计这个次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function getCharTimes(str){
var json = {};
for(var i = 0; i < str.length;i++){
if(!json[str.charAt(i)]){
json[str.charAt(i)] = 1;
}else{
json[str.charAt(i)]++;
}
}
var max = 0;
var maxIndex = '';
for(var i in json){
if(json[i]>max){
max = json[i];
maxIndex = i;
}
}
return "出现最多的字符是"+maxIndex+",次数为"+max;
}
Wills's blogs

vuejs权威指南笔记

发表于 2017-01-09 | 分类于 前端开发 |

1. 遇见Vue.js

1.1 MVX模式

1.1.1 MVC
Model controller view
view通过controller来和model联系,协调。view与model不直接联系,基本联系都是单向的
1.1.2 MVP
model controller/presenter view
presenter完全把view和model进行了分离,主要的逻辑都在presenter里实现
1.1.3 MVVM
model view viewModel
view的变化会自动更新到viewModel,viewModel的变化也会同步到view

1.2 Vuejs是什么

特性:

  1. 确实轻量
  2. 数据绑定
  3. 指令
  4. 插件化
    1.2.1 Vuejs与其他框架的区别
    1. 与angularJS的区别
      相同点:
      • 都支持指令–内置指令和自定义指令
      • 都支持过滤器–内置过滤器和自定义过滤器
      • 都支持双向绑定
      • 都不支持低端浏览器(比如IE6/IE7/IE8)
        不同点:
      • angularJS学习成本高
      • 性能上,angular依赖对数据做胀检查,所以Dependency Injection特性,而Vue.js本身提供的API都比较简单直观
    2. 与React的区别
      相同点:
      • React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,两者都需要编译后使用
      • 中心思想相同:一切都是组件,组件实例之间可以嵌套
      • 都提供合理的钩子函数,可以让开发者定制化地去处理需求
      • 都不内置类似AJAX、Router等功能核心包,而是以其他方式(插件)加载
      • 在组件开发中都支持mixins的特性
        不同点:
        React依赖virtual DOM,而VueJs使用的是DOM模板。React采用的virtrual Dom会对渲染出来的结果做胀检查
        Vuejs在模板中提供了命令、过滤器等,非常方便、快捷地操作DOM
Wills's blogs

flex布局

发表于 2017-01-03 | 分类于 前端开发 |

任何一个盒子都可以用以下方式指定为flex布局:

1
2
3
.box{
display: flex;
}

如果盒子是行内元素,也可以用以下方式指定:

1
2
3
.box{
display: inline-flex;
}

webkit内核的浏览器需加上-webkit前缀:

1
2
3
4
.box{
display: -webkit-flex;
display: flex;
}

弹性布局的容器有6个属性,分别是:

  1. flex-direction: row|row-reverse|column|column-reverse
  2. flex-wrap: nowrap|wrap|wrap-reverse;
  3. flex-flow: || ;
  4. justify-content: flex-start | flex-end | center | space-between | space-around;
  5. align-items: flex-start | flex-end | center | baseline | stretch;
  6. align-content: flex-start | flex-end | center | space-between | space-around | stretch;

flex-direction: 控制主轴的方向(即项目的排列方向)

1
2
3
4
row(默认值):主轴为水平方向,起点在左端。
row-reverse:主轴为水平方向,起点在右端。
column:主轴为垂直方向,起点在上沿。
column-reverse:主轴为垂直方向,起点在下沿。

flex-wrap: 默认情况下,项目都排在一条线(又称”轴线”)上。flex-wrap属性定义,如果一条轴线排不下,如何换行。

1
2
3
4
nowrap(默认):不换行。
wrap:换行,第一行在上方。
wrap-reverse:换行,第一行在下方。
justify-content: 定义了项目在主轴上的对齐方式。

flex-flow: flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。

justify-content: 定义了项目在主轴上的对齐方式。

1
2
3
4
5
flex-start(默认值):左对齐
flex-end:右对齐
center: 居中
space-between:两端对齐,项目之间的间隔都相等。
space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

align-items: 定义项目在交叉轴上如何对齐。

1
2
3
4
5
flex-start:交叉轴的起点对齐。
flex-end:交叉轴的终点对齐。
center:交叉轴的中点对齐。
baseline: 项目的第一行文字的基线对齐。
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

align-content: 定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用。

1
2
3
4
5
6
flex-start:与交叉轴的起点对齐。
flex-end:与交叉轴的终点对齐。
center:与交叉轴的中点对齐。
space-between:与交叉轴两端对齐,轴线之间的间隔平均分布。
space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍。
stretch(默认值):轴线占满整个交叉轴。

设置到项目上的6个特性:

  1. order
  2. flex-grow
  3. flex-shrink
  4. flex-basis
  5. flex
  6. align-self
Wills's blogs

常用方法存档

发表于 2016-12-28 | 分类于 前端开发 |
  1. 获取url查询字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 获取url查询字符串
* @param {[[Type]]} name url查询参数
* @returns {[[Type]]} 查询参数值
*/
function getQueryString(name) {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
var r = window.location.search.substr(1).match(reg);
if (r != null) {
return decodeURI(r[2]);
}
return null;
}
  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
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
/* 
 * 处理过长的字符串,截取并添加省略号 
 * 注:半角长度为1,全角长度为2 
 *  
 * pStr:字符串 
 * pLen:截取长度 
 *  
 * return: 截取后的字符串 
 */  
function autoAddEllipsis(pStr, pLen) {  
   if(typeof(pStr)=="undefined" || pStr==""){
 return ""; 
}
    var _ret = cutString(pStr, pLen);  
    var _cutFlag = _ret.cutflag;  
    var _cutStringn = _ret.cutstring;  
  
    if ("1" == _cutFlag) {  
        return _cutStringn + "...";  
    } else {  
        return _cutStringn;  
    }  
}  
  
/* 
 * 取得指定长度的字符串 
 * 注:半角长度为1,全角长度为2 
 *  
 * pStr:字符串 
 * pLen:截取长度 
 *  
 * return: 截取后的字符串 
 */  
function cutString(pStr, pLen) {  
  
    // 原字符串长度  
    var _strLen = pStr.length;  
  
    var _tmpCode;  
  
    var _cutString;  
  
    // 默认情况下,返回的字符串是原字符串的一部分  
    var _cutFlag = "1";  
  
    var _lenCount = 0;  
  
    var _ret = false;  
  
    if (_strLen <= pLen/2) {  
        _cutString = pStr;  
        _ret = true;  
    }  
  
    if (!_ret) {  
        for (var i = 0; i < _strLen ; i++ ) {  
            if (isFull(pStr.charAt(i))) {  
                _lenCount += 2;  
            } else {  
                _lenCount += 1;  
            }  
  
            if (_lenCount > pLen) {  
                _cutString = pStr.substring(0, i);  
                _ret = true;  
                break;  
            } else if (_lenCount == pLen) {  
                _cutString = pStr.substring(0, i + 1);  
                _ret = true;  
                break;  
            }  
        }  
    }  
      
    if (!_ret) {  
        _cutString = pStr;  
        _ret = true;  
    }  
  
    if (_cutString.length == _strLen) {  
        _cutFlag = "0";  
    }  
  
    return {"cutstring":_cutString, "cutflag":_cutFlag};  
}  
  
/* 
 * 判断是否为全角 
 *  
 * pChar:长度为1的字符串 
 * return: true:全角 
 *          false:半角 
 */  
function isFull (pChar) {  
    if ((pChar.charCodeAt(0) > 128)) {  
        return true;  
    } else {  
        return false;  
    }  
}
Wills's blogs

NodeJs课程笔记-NodeJs第三天笔记

发表于 2016-12-20 | 分类于 后端开发 |

一、Express框架
Express框架是后台的Node框架,所以和jQuery、zepto、yui、bootstrap都不一个东西。
Express在后台的受欢迎的程度,和jQuery一样,就是企业的事实上的标准。

● 原生Node开发,会发现有很多问题。比如:
■ 呈递静态页面很不方便,需要处理每个HTTP请求,还要考虑304问题
■ 路由处理代码不直观清晰,需要写很多正则表达式和字符串函数
■ 不能集中精力写业务,要考虑很多其他的东西

我们自己可以把第一天的作业,就是那个静态文件服务给封装成为模块。封装的越多,就自己做出了类似Express的东西。

● EXPRESS的哲学是在你的想法和服务器之间充当薄薄的一层。这并不意味着他不够健壮,或者没有足够的有用特性,而是尽量少干预你,让你充分表达自己的思想,同时提供一些有用的东西。

英语官网:http://expressjs.com/
中文官网:http://www.expressjs.com.cn/

整体感知,Express框架。
安装Express框架,就是使用npm的命令。

1
npm install --save express

–save参数,表示自动修改package.json文件,自动添加依赖项。

路由能力:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var express = require("express");
var app = express();
app.get("/",function(req,res){
res.send("你好");
});
app.get("/haha",function(req,res){
res.send("这是haha页面,哈哈哈哈哈哈");
});
app.get(/^\/student\/([\d]{10})$/,function(req,res){
res.send("学生信息,学号" + req.params[0]);
});
app.get("/teacher/:gonghao",function(req,res){
res.send("老师信息,工号" + req.params.gonghao);
});
app.listen(3000);

静态文件伺服能力:

1
app.use(express.static("./public"));

模板引擎:

1
2
3
4
5
6
7
8
9
10
11
12
13
1 var express = require("express");
2
3 var app = express();
4
5 app.set("view engine","ejs");
6
7 app.get("/",function(req,res){
8 res.render("haha",{
9 "news" : ["我是小新闻啊","我也是啊","哈哈哈哈"]
10 });
11 });
12
13 app.listen(3000);

我们学习的是Express4.X,和Express3.X差别非常大。
二、路由
当用get请求访问一个网址的时候,做什么事情:

1
2
3
1 app.get("网址",function(req,res){
2
3 });

当用post访问一个网址的时候,做什么事情:

1
2
3
1 app.post("网址",function(req,res){
2
3 });

如果想处理这个网址的任何method的请求,那么写all

1
2
3
1 app.all("/",function(){
2
3 });

这里的网址,不分大小写,也就是说,你路由是

1
2
3
1 app.get("/AAb",function(req,res){
2 res.send("你好");
3 });

实际上小写的访问也行。

所有的GET参数,? 后面的都已经被忽略。 锚点#也被忽略
你路由到/a , 实际/a?id=2&sex=nan 也能被处理。

正则表达式可以被使用。正则表达式中,未知部分用圆括号分组,然后可以用req.params[0]、[1]得到。
req.params类数组对象。

1
2
3
1 app.get(/^\/student\/([\d]{10})$/,function(req,res){
2 res.send("学生信息,学号" + req.params[0]);
3 });

冒号是更推荐的写法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1 app.get("/student/:id",function(req,res){
2 var id = req.params["id"];
3 var reg= /^[\d]{6}$/; //正则验证
4 if(reg.test(id)){
5 res.send(id);
6 }else{
7 res.send("请检查格式");
8 }
9 });
```
表单可以自己提交到自己上。
```js
1 app.get("/",function(req,res){
2 res.render("form");
3 });
4
5 app.post("/",function(req,res){
6 //将数据添加进入数据库
7 res.send("成功");
8 });

适合进行 RESTful路由设计。简单说,就是一个路径,但是http method不同,对这个页面的使用也不同。
/student/345345

get 读取学生信息
add 添加学生信息
delete 删除学生新

三、中间件
如果我的的get、post回调函数中,没有next参数,那么就匹配上第一个路由,就不会往下匹配了。
如果想往下匹配的话,那么需要写next()

1
2
3
4
5
6
7
8
1 app.get("/",function(req,res,next){
2 console.log("1");
3 next();
4 });
5
6 app.get("/",function(req,res){
7 console.log("2");
8 });

下面两个路由,感觉没有关系:

1
2
3
4
5
6
7
8
9
1 app.get("/:username/:id",function(req,res){
2 console.log("1");
3 res.send("用户信息" + req.params.username);
4 });
5
6 app.get("/admin/login",function(req,res){
7 console.log("2");
8 res.send("管理员登录");
9 });

但是实际上冲突了,因为admin可以当做用户名 login可以当做id。

解决方法1:交换位置。 也就是说,express中所有的路由(中间件)的顺序至关重要。
匹配上第一个,就不会往下匹配了。 具体的往上写,抽象的往下写。

1
2
3
4
5
6
7
8
9
1 app.get("/admin/login",function(req,res){
2 console.log("2");
3 res.send("管理员登录");
4 });
5
6 app.get("/:username/:id",function(req,res){
7 console.log("1");
8 res.send("用户信息" + req.params.username);
9 });

解决方法2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1 app.get("/:username/:id",function(req,res,next){
2 var username = req.params.username;
3 //检索数据库,如果username不存在,那么next()
4 if(检索数据库){
5 console.log("1");
6 res.send("用户信息");
7 }else{
8 next();
9 }
10 });
11
12 app.get("/admin/login",function(req,res){
13 console.log("2");
14 res.send("管理员登录");
15 });

路由get、post这些东西,就是中间件,中间件讲究顺序,匹配上第一个之后,就不会往后匹配了。next函数才能够继续往后匹配。

app.use()也是一个中间件。与get、post不同的是,他的网址不是精确匹配的。而是能够有小文件夹拓展的。
比如网址: http://127.0.0.1:3000/admin/aa/bb/cc/dd

1
2
3
4
5
6
1 app.use("/admin",function(req,res){
2 res.write(req.originalUrl + "\n"); // /admin/aa/bb/cc/dd
3 res.write(req.baseUrl + "\n"); // /admin
4 res.write(req.path + "\n"); // /aa/bb/cc/dd
5 res.end("你好");
6 });

如果写一个/

1
2
3
4
5
1 //当你不写路径的时候,实际上就相当于"/",就是所有网址
2 app.use(function(req,res,next){
3 console.log(new Date());
4 next();
5 });

app.use()就给了我们增加一些特定功能的便利场所。
实际上app.use()的东西,基本上都从第三方能得到。

● 大多数情况下,渲染内容用res.render(),将会根据views中的模板文件进行渲染。如果不想使用views文件夹,想自己设置文件夹名字,那么app.set(“views”,”aaaa”);
● 如果想写一个快速测试页,当然可以使用res.send()。这个函数将根据内容,自动帮我们设置了Content-Type头部和200状态码。send()只能用一次,和end一样。和end不一样在哪里?能够自动设置MIME类型。
● 如果想使用不同的状态码,可以:

1
res.status(404).send('Sorry, we cannot find that!');

● 如果想使用不同的Content-Type,可以:

1
res.set('Content-Type', 'text/html');

四、GET请求和POST请求的参数
● GET请求的参数在URL中,在原生Node中,需要使用url模块来识别参数字符串。在Express中,不需要使用url模块了。可以直接使用req.query对象。
● POST请求在express中不能直接获得,必须使用body-parser模块。使用后,将可以用req.body得到参数。但是如果表单中含有文件上传,那么还是需要使用formidable模块。

Node中全是回调函数,所以我们自己封装的函数,里面如果有异步的方法,比如I/O,那么就要用回调函数的方法封装。

错误:

1
2
3
1 res.reder("index",{
2 "name" : student.getDetailById(234234).name
3 });

正确:

1
2
3
4
5
6
6
7 student.getDetailByXueHao(234234,function(detail){
8 res.render("index",{
9 "name" : detail.name
10 })
11 });

Wills's blogs

NodeJs课程笔记-NodeJs第二天笔记

发表于 2016-12-20 | 分类于 后端开发 |

一、复习
复习:
Node.js开发服务器,数据、路由。本地关心的效果,交互;
Node.js实际上是极客开发出的一个小玩具,不是银弹。有着别人不具备的怪异特点:
单线程、Non-blocking I/O、Event Driven。 实际上是一个特点。
首先,Node不为每个用户开辟一个线程,所以非常极端的选择了单线程。单线程,要照顾所有的用户,那么就必须有非阻塞I/O,否则一个人的I/O就把别人、自己都阻塞了。一旦有非阻塞I/O,一个人如果I/O去了,就会放弃CPU的使用权,换成另一个人使用CPU(或者执行此人后面的语句)。所以CPU的利用率100%。第一个人I/O结束了,就要用事件来通知线程,执行回调函数。此时必须有事件环,就有一个排队调度机制。Node中有超过半数的C++代码,在搭建事件环。

Node.js和别的老牌3P不一样:
1) 没有自己的语法,使用V8引擎,所以就是JS。V8引擎解析JS的,效率非常高,并且V8中很多东西都是异步的。Node就是将V8中的一些功能自己没有重写(别人做了,自己就站在巨人肩膀上),移植到了服务器上。
2) 没有web容器,就是安装配置完成之后,没有一个根目录。

命令提示符所在路径太重要了,因为程序中的所有相对路径”./”,都是相对这个命令提示符路径的,而不是相对于js文件自己。
系统中,80端口,就是默认http端口。所以当没有端口号的时候,就是80端口。

1
server.listen(80,"127.0.0.1");

二、模块

● 在Node.js中,以模块为单位划分所有功能,并且提供了一个完整的模块加载机制,这时的我们可以将应用程序划分为各个不同的部分。
不可能用一个js文件去写全部的业务。肯定要有MVC。

● 狭义的说,每一个JavaScript文件都是一个模块;而多个JavaScript文件之间可以相互require,他们共同实现了一个功能,他们整体对外,又称为一个广义上的模块。

● Node.js中,一个JavaScript文件中定义的变量、函数,都只在这个文件内部有效。当需要从此JS文件外部引用这些变量、函数时,必须使用exports对象进行暴露。使用者要用require()命令引用这个JS文件。

foo.js文件中的代码:

1
2
var msg = "你好";
exports.msg = msg;

msg这个变量,是一个js文件内部才有作用域的变量。
如果别人想用这个变量,那么就要用exports进行暴露。

使用者:

1
2
var foo = require("./test/foo.js");
console.log(foo.msg);

使用者用foo来接收exports对象,也就是说,这里的foo变量,就是文件中的exports变量。

● 一个JavaScript文件,可以向外exports无数个变量、函数。但是require的时候,仅仅需要require这个JS文件一次。使用的它的变量、函数的时候,用点语法即可。所以,无形之中,增加了一个顶层命名空间。

js文件中,可以用exports暴露很多东西,比如函数、变量。

1
2
3
4
5
6
7
8
var msg = "你好";
var info = "呵呵";
function showInfo(){
console.log(info);
}
exports.msg = msg;
exports.info = info;
exports.showInfo = showInfo;

在使用者中,只需要require一次。

1
var foo = require("./test/foo.js");

相当于增加了顶层变量。所有的函数、变量都要从这个顶层变量走:

1
2
3
console.log(foo.msg);
console.log(foo.info);
foo.showInfo();

Node中,js文件和js文件,就是被一个个exports和require构建成为网状的。
不是靠html文件统一在一起的。

● 可以将一个JavaScript文件中,描述一个类。用
module.export = 构造函数名;
的方式向外暴露一个类。

也就是说,js文件和js文件之间有两种合作的模式:
1) 某一个js文件中,提供了函数,供别人使用。 只需要暴露函数就行了;

1
exports.msg=msg;

2) 某一个js文件,描述了一个类。

1
module.exports = People;

● 如果在require命令中,这么写:

1
var foo = require("foo.js"); //没有写./,所以不是一个相对路径。是一个特殊的路径

那么Node.js将该文件视为node_modules目录下的一个文件

● node_modules文件夹并不一定在同级目录里面,在任何直接祖先级目录中,都可以。甚至可以放到NODE_PATH环境变量的文件夹中。这样做的好处稍后你将知道:分享项目的时候,不需要带着modules一起给别人。

● 我们可以使用文件夹来管理模块,比如

1
var bar = require("bar");

那么Node.js将会去寻找node_modules目录下的bar文件夹中的index.js去执行。

每一个模块文件夹中,推荐都写一个package.json文件,这个文件的名字不能改。node将自动读取里面的配置。有一个main项,就是入口文件:

1
2
3
4
5
{
"name": "kaoladebar",
"version": "1.0.1",
"main" : "app.js"
}

package.json文件,要放到模块文件夹的根目录去。

我们刚才学习了,模块就是一些功能的封装,所以一些成熟的、经常使用的功能,都有人封装成为了模块。并且放到了社区中,供人免费下载。
这个伟大的社区,叫做npm。 也是一个工具名字 node package management
https://www.npmjs.com/

去社区搜索需求,然后点进去,看api。
如果要配置一个模块,那么直接在cmd使用

npm install 模块名字

就可以安装。 模块名字全球唯一。
安装的时候,要注意,命令提示符的所在位置。

1.我们的依赖包,可能在随时更新,我们永远想保持更新,或者某持某一个版本;
2.项目越来越大的时候,给别人看的时候,没有必要再次共享我们引用的第三方模块。

我们可以用package.json来管理依赖。
在cmd中,使用npm init可以初始化一个package.json文件,用回答问题的方式生成一个新的package.json文件。
使用

npm install 将能安装所有依赖。
npm也有文档,这是package.json的介绍:
https://docs.npmjs.com/files/package.json

require()别的js文件的时候,将执行那个js文件。

注意:
require()中的路径,是从当前这个js文件出发,找到别人。而fs是从命令提示符找到别人。
所以,桌面上有一个a.js, test文件夹中有b.js、c.js、1.txt
a要引用b:

1
var b = require(“./test/b.js”);

b要引用c:

1
1 var b = require(“./c.js”);

但是,fs等其他的模块用到路径的时候,都是相对于cmd命令光标所在位置。
所以,在b.js中想读1.txt文件,推荐用绝对路径:

1
2
3
4
fs.readFile(__dirname + "/1.txt",function(err,data){
if(err) { throw err; }
console.log(data.toString());
});

三、post请求

1
var alldata = "";

1
2
3
4
5
6
7
//下面是post请求接收的一个公式
//node为了追求极致,它是一个小段一个小段接收的。
//接受了一小段,可能就给别人去服务了。防止一个过大的表单阻塞了整个进程
req.addListener("data",function(chunk){
alldata += chunk;
});
1
2
3
4
5
//全部传输完毕
req.addListener("end",function(){
console.log(alldata.toString());
res.end("success");
});

原生写POST处理,比较复杂,要写两个监听。文件上传业务比较难写。
所以,用第三方模块。formidable。

只要涉及文件上传,那么form标签要加一个属性:

1
<form action="http://127.0.0.1/dopost" method="post" enctype="multipart/form-data">

四、模板引擎

1
<a href="<%= url %>"><img src="<%= imageURL %>" alt=""></a>

数据绑定,就成为一个完整的html字符串了。
前台的模板,我们现在要学习的是后台的模板。
后台模板,著名的有两个,第一个叫做ejs; 第二个叫做jade。

是npm第三方包。

先说EJS(Embedded JavaScript templates)
后台模板引擎

1
2
3
4
5
<ul>
<% for(var i = 0 ; i < news.length ; i++){ %>
<li><%= news[i] %></li>
<% } %>
</ul>

1
2
3
4
var dictionary = {
a:6,
news : ["1期班太牛逼了","高薪就业","哈哈哈哈哈"]
};
Wills's blogs

NodeJs课程笔记-NodeJs第一天笔记

发表于 2016-12-19 | 分类于 后端开发 |

一、Node.js简介

1.1 简介

V8引擎本身就是用于Chrome浏览器的JS解释部分,但是Ryan Dahl(瑞恩达尔)这哥们,鬼才般的,把这个V8搬到了服务器上,用于做服务器的软件。
Node.js是一个专注于实现高性能Web服务器优化的专家,几经探索,几经挫折后,遇到V8而诞生的项目。

Node.js是一个让JavaScript运行在服务器端的开发平台,它让JavaScript的触角伸到了服务器端,可以与PHP、JSP、Python、Ruby平起平坐。
但Node似乎有点不同:
● Node.js不是一种独立的语言,与PHP、JSP、Python、Perl、Ruby的“既是语言,也是平台”不同,Node.js的使用JavaScript进行编程,运行在JavaScript引擎上(V8)。
● 与PHP、JSP等相比(PHP、JSP、.net都需要运行在服务器程序上,Apache、Naginx、Tomcat、IIS。
),Node.js跳过了Apache、Naginx、IIS等HTTP服务器,它自己不用建设在任何服务器软件之上。Node.js的许多设计理念与经典架构(LAMP = Linux + Apache + MySQL + PHP)有着很大的不同,可以提供强大的伸缩能力。一会儿我们就将看到,Node.js没有web容器。
Node.js自身哲学,是花最小的硬件成本,追求更高的并发,更高的处理性能。

官网:https://nodejs.org/en/
特点:Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient.

1.2 特点

所谓的特点,就是Node.js是如何解决服务器高性能瓶颈问题的。

  • 单线程
    在Java、PHP或者.net等服务器端语言中,会为每一个客户端连接创建一个新的线程。而每个线程需要耗费大约2MB内存。也就是说,理论上,一个8GB内存的服务器可以同时连接的最大用户数为4000个左右。要让Web应用程序支持更多的用户,就需要增加服务器的数量,而Web应用程序的硬件成本当然就上升了。
    Node.js不为每个客户连接创建一个新的线程,而仅仅使用一个线程。当有用户连接了,就触发一个内部事件,通过非阻塞I/O、事件驱动机制,让Node.js程序宏观上也是并行的。使用Node.js,一个8GB内存的服务器,可以同时处理超过4万用户的连接。
    另外,带线程的带来的好处,还有操作系统完全不再有线程创建、销毁的时间开销。
    坏处,就是一个用户造成了线程的崩溃,整个服务都崩溃了,其他人也崩溃了。
    Alt text Alt text
    多线程、单线程的一个对比。
    也就是说,单线程也能造成宏观上的“并发”。

  • 非阻塞I/O non-blocking I/O
    例如,当在访问数据库取得数据的时候,需要一段时间。在传统的单线程处理机制中,在执行了访问数据库代码之后,整个线程都将暂停下来,等待数据库返回结果,才能执行后面的代码。也就是说,I/O阻塞了代码的执行,极大地降低了程序的执行效率。
    由于Node.js中采用了非阻塞型I/O机制,因此在执行了访问数据库的代码之后,将立即转而执行其后面的代码,把数据库返回结果的处理代码放在回调函数中,从而提高了程序的执行效率。
    当某个I/O执行完毕时,将以事件的形式通知执行I/O操作的线程,线程执行这个事件的回调函数。为了处理异步I/O,线程必须有事件循环,不断的检查有没有未处理的事件,依次予以处理。
    阻塞模式下,一个线程只能处理一项任务,要想提高吞吐量必须通过多线程。而非阻塞模式下,一个线程永远在执行计算操作,这个线程的CPU核心利用率永远是100%。所以,这是一种特别有哲理的解决方案:与其人多,但是好多人闲着;还不如一个人玩命,往死里干活儿。

  • 事件驱动event-driven
    在Node中,客户端请求建立连接,提交数据等行为,会触发相应的事件。在Node中,在一个时刻,只能执行一个事件回调函数,但是在执行一个事件回调函数的中途,可以转而处理其他事件(比如,又有新用户连接了),然后返回继续执行原事件的回调函数,这种处理机制,称为“事件环”机制。
    Node.js底层是C++(V8也是C++写的)。底层代码中,近半数都用于事件队列、回调函数队列的构建。用事件驱动来完成服务器的任务调度,这是鬼才才能想到的。针尖上的舞蹈,用一个线程,担负起了处理非常多的任务的使命。
    Alt text

单线程,单线程的好处,减少了内存开销,操作系统的内存换页。
如果某一个事情,进入了,但是被I/O阻塞了,所以这个线程就阻塞了。

非阻塞I/O, 不会傻等I/O语句结束,而会执行后面的语句。
非阻塞就能解决问题了么?比如执行着小红的业务,执行过程中,小刚的I/O回调完成了,此时怎么办??

事件机制,事件环,不管是新用户的请求,还是老用户的I/O完成,都将以事件方式加入事件环,等待调度。

说是三个特点,实际上是一个特点,离开谁都不行,都玩儿不转了。
Node.js很像抠门的餐厅老板,只聘请1个服务员,服务很多人。结果,比很多服务员效率还高。
Node.js中所有的I/O都是异步的,回调函数,套回调函数。

1.3 适合开发什么?

Node.js适合用来开发什么样的应用程序呢?
善于I/O,不善于计算。因为Node.js最擅长的就是任务调度,如果你的业务有很多的CPU计算,实际上也相当于这个计算阻塞了这个单线程,就不适合Node开发。
当应用程序需要处理大量并发的I/O,而在向客户端发出响应之前,应用程序内部并不需要进行非常复杂的处理的时候,Node.js非常适合。Node.js也非常适合与web socket配合,开发长连接的实时交互应用程序。
比如:
● 用户表单收集
● 考试系统
● 聊天室
● 图文直播
● 提供JSON的API(为前台Angular使用)

1.4 Node.js无法挑战老牌3P

Alt text

Wills's blogs

Ajax图片上传与图片预览方法

发表于 2016-11-29 | 分类于 前端开发 |
  1. H5—xhr2(XmlHttpRequest level 2)上传
    xhr2的特点:
  • 可以设置HTTP请求的时限。
  • 可以获取服务器端的(或向服务端发送)二进制数据。
  • 可以使用FormData对象管理表单数据。
  • 可以上传文件。xhr.upload(upload = XMLHttpRequestUpload)
  • 可以获得数据传输的进度信息, xhr.upload.onprogess。
  • 可以请求不同域名下的数据(跨域请求)
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
/**
* 上传图片
* @param {string} type input[file]的name值
*/
function uploadImg(type){
var formData= new FormData();
formData.append("from", "expert");
formData.append("debug", "1");
formData.append("expertId", "1");
var picFileList = $("#" + type).get(0).files;
for(var i=0; i< picFileList.length; i++){
formData.append(type , picFileList[i] );
}
var xhr = new XMLHttpRequest();
xhr.open("POST", requestUrl + "/expert/updatePicA");
xhr.onreadystatechange = function(){
var XMLHttpReq = xhr;
if (XMLHttpReq.readyState == 4) {
if (XMLHttpReq.status == 200) {
var text = XMLHttpReq.responseText;
eval("rt=" + text);
if(rt.error!==""){
alert(rt.error);
}else{
alert("操作成功");
window.location.reload()
}
}
}
};
xhr.send(formData);
}

xhr2在结合H5的其他特性,可以实现上述flash上传的所以功能外,还可以实现拖拽上传功能。

由于诸多HTML5特性(Blob ,xhr2,FileReader,ArrayBuffer等)在IE10+中才有效,
所以xhr2上传更适合在chrome,firefox等高版本的浏览器或和移动端使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 预览图片
function seeImg(el,imgBox){
function getObjectURL(file) {
var url = null;
if (window.createObjectURL != undefined) { // basic
url = window.createObjectURL(file);
} else if (window.URL != undefined) { // mozilla(firefox)
url = window.URL.createObjectURL(file);
} else if (window.webkitURL != undefined) { // webkit or chrome
url = window.webkitURL.createObjectURL(file);
}
return url;
}
el.on("change",function(){
var objUrl = getObjectURL(el[0].files[0]) ;
if (objUrl) {
imgBox.attr("src", objUrl);
imgBox.attr("class", "fileImg");
}
el.parent().find(".register-file-val").text(el.val());
})
}

使用jquery:

1
2
3
4
5
<form id= "uploadForm">
<p >指定文件名: <input type="text" name="filename" value= ""/></p >
<p >上传文件: <input type="file" name="file"/></ p>
<input type="button" value="上传" onclick="doUpload()" />
</form>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function doUpload() {
var formData = new FormData($( "#uploadForm" )[0]);
$.ajax({
url: 'http://localhost:8080/cfJAX_RS/rest/file/upload' ,
type: 'POST',
data: formData,
async: false,
cache: false,
contentType: false,
processData: false,
success: function (returndata) {
alert(returndata);
},
error: function (returndata) {
alert(returndata);
}
});
}

可参考:
https://developer.mozilla.org/zh-CN/docs/Web/Guide/Using_FormData_Objects

https://developer.mozilla.org/zh-CN/docs/Web/Guide/Using_FormData_Objects

Wills's blogs

使用REM进行手机屏幕适配!

发表于 2016-11-29 | 分类于 前端开发 |

什么是REM?
在rem之前,我们知道em是相对于父元素的字体来设置字体大小的,这样就会存在一个问题,进行任何元素设置,都有可能需要知道他父元素的大小,在我们多次使用时,就会带来无法预知的错误风险。而rem是相对于根元素,这样就意味着,我们只需要在根元素确定一个参考值,,在根元素中设置多大的字体,这完全可以根据您自己的所需。

浏览器的兼容性?
虽然rem是CSS3新引进来的一个度量单位,但是它支持的浏览器还是挺多的,比如:Mozilla Firefox 3.6+、Apple Safari 5+、Google Chrome、IE9+和Opera11+。只是可怜的IE6-8无法,你们就把他们当透明了吧,我向来都是如此。

不过使用单位设置字体,可不能完全不考虑IE了,如果你想使用这个REM,但也想兼容IE下的效果,可你可考虑“px”和“rem”一起使用,用”px”来实现IE6-8下的效果,然后使用“Rem”来实现代浏览器的效果,就让IE6-8不能随文字的改变而改变吧,现在基本要抛弃这些古老的浏览器了。

首先我们来看看使用 rem 实现手机屏幕适配的常用方案。

以设计稿的宽度为640px,即:designWidth = 640,同时设定在640px屏宽下 1rem=100px ,即:rem2px = 100。

设置 1rem=100px 的优点不言而喻。前端开发者在切图、重构页面的时候,通过直接位移小数点的方式,就可以将UI图中测量到的 px 值换算成对应的 rem 值,方便快捷。
此外,在 head 中我们还设置了:

1
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />

先来看看具体方案
方案1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@media screen and (min-width: 320px) {html{font-size:50px;}}
@media screen and (min-width: 360px) {html{font-size:56.25px;}}
@media screen and (min-width: 375px) {html{font-size:58.59375px;}}
@media screen and (min-width: 400px) {html{font-size:62.5px;}}
@media screen and (min-width: 414px) {html{font-size:64.6875px;}}
@media screen and (min-width: 440px) {html{font-size:68.75px;}}
@media screen and (min-width: 480px) {html{font-size:75px;}}
@media screen and (min-width: 520px) {html{font-size:81.25px;}}
@media screen and (min-width: 560px) {html{font-size:87.5px;}}
@media screen and (min-width: 600px) {html{font-size:93.75px;}}
@media screen and (min-width: 640px) {html{font-size:100px;}}
@media screen and (min-width: 680px) {html{font-size:106.25px;}}
@media screen and (min-width: 720px) {html{font-size:112.5px;}}
@media screen and (min-width: 760px) {html{font-size:118.75px;}}
@media screen and (min-width: 800px) {html{font-size:125px;}}
@media screen and (min-width: 960px) {html{font-size:150px;}}

方案2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@media screen and (min-width: 320px) {html{font-size:312.5%;}}
@media screen and (min-width: 360px) {html{font-size:351.5625%;}}
@media screen and (min-width: 375px) {html{font-size:366.211%;}}
@media screen and (min-width: 400px) {html{font-size:390.625%;}}
@media screen and (min-width: 414px) {html{font-size:404.2969%;}}
@media screen and (min-width: 440px) {html{font-size:429.6875%;}}
@media screen and (min-width: 480px) {html{font-size:468.75%;}}
@media screen and (min-width: 520px) {html{font-size:507.8125%;}}
@media screen and (min-width: 560px) {html{font-size:546.875%;}}
@media screen and (min-width: 600px) {html{font-size:585.9375%;}}
@media screen and (min-width: 640px) {html{font-size:625%;}}
@media screen and (min-width: 680px) {html{font-size:664.0625%;}}
@media screen and (min-width: 720px) {html{font-size:703.125%;}}
@media screen and (min-width: 760px) {html{font-size:742.1875%;}}
@media screen and (min-width: 800px) {html{font-size:781.25%;}}
@media screen and (min-width: 960px) {html{font-size:937.5%;}}

方案3:

1
2
3
4
var designWidth = 640, rem2px = 100;
document.documentElement.style.fontSize =
((window.innerWidth / designWidth) * rem2px) + 'px';

注:目标屏幕宽度和设计稿的宽度的比:

1
2
window.innerWidth / designWidth * rem2px + 'px'

方案4:

1
2
3
4
var designWidth = 640, rem2px = 100;
document.documentElement.style.fontSize =
((((window.innerWidth / designWidth) * rem2px) / 16) * 100) + '%';

注:由于浏览器默认字体大小为 16px,所以当我们使用百分比作为根节点 html 的字体大小时,即html元素的font-size值设置为一个百分比值,rem 的计算方式就会改为:

1
2
defaultFontSize = 16px
1rem = 1 * htmlFontSize * defaultFontSize

同样的可以得到所有屏幕大小下,html 的 font-size 值的计算公式,即为方案4:

1
window.innerWidth / designWidth * rem2px / 16 * 100 + '%'

方案5:

1
2
3
4
5
6
7
8
9
setRem();
window.addEventListener("orientationchange",setRem);//监听横屏
window.addEventListener("resize",setRem);//监听屏幕大小变化
function setRem(){
var $html = document.querySelector("html");
var width = $html.getBoundingClientRect().width;
$html.style.fontSize = width / 16 + "px";//按比例设置不同大小屏幕下根节点的字体
}
12
Wills

Wills

wills blogs,前端开发博客,技术博客,前端学习笔记

17 日志
2 分类
14 标签
GitHub
© 2017 Wills
由 Hexo 强力驱动
主题 - NexT.Pisces