定义

定义一系列的算法,把他们一个个封装起来,并且使它们可以互相替换
当然策略模式并不仅仅可以封装算法,也可以封装一系列的’业务规则’或者说是’应用逻辑’,只要这些业务规则指向的目标一致,并且可以被替换使用,我们就可以用策略模式来封装它们
策略模式主要是实现了松散耦合

一个使用策略模式文本输入框校验规则样例代码

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
<body>
<!-- 一个使用策略模式文本输入框校验规则样例代码 -->
<form action="javascript:;" id="registerForm" method="post">
请输入用户名: <input type="text" name="userName">
请输入密码: <input type="password" name="password">
请输入手机号码: <input type="phoneName" name="phoneName">
<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;
}
},
//判断手机号是否合法
isMoblile: 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,rule;rule = rules[ i++ ];){
(function(rule){
//规则参数数组
var strategyAry = rule.strategy.split(':');
//错误信息
var errorMsg = rule.errorMsg;
self.cache.push(function(){
//删除参数数组的要校验的规则并用strategy接收
var strategy = strategyAry.shift();
//接收dom的value值作为第一个参数
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: '用户名长度不能小于6位'
}]);
validator.add(registerForm.password,[
{
strategy:'minLength:6',
errorMsg:'密码长度不能小于6位'
}]);
validator.add(registerForm.phoneName,[
{
strategy:'isMoblile',
errorMsg:'手机号码格式不正确'
}]);
//启动校验程序
var errorMsg = validator.start();
return errorMsg;
};
//绑定事件
registerForm.onsubmit = function(){
var errorMsg = validataFunc();
console.log('test');
if(errorMsg){
alert(errorMsg);
return false;
}
return false;
};

</script>
</body>

  • << JavaScript Dom 编程艺术 >> 目前(第二版)
    轻松入门 开始学习javascript

  • << JavaScript 高级程序设计 >> 目前(第三版)
    绝对是学习JavaScript的神书, 全部学完以后带来的是质的飞越

  • << 锋利的 jQuery >> 目前(第二版)
    解决兼容性, 链式编程, 方便的 DOM 操作,完善的Ajax,一切从使用 jQuery开始

  • << 高性能网站建设指南 >>
    一些基本的的性能优化,已经体现在网站的方方面面

  • << 高性能网站建设进阶指南 >>
    一些高级技巧,技术性比较高,有一些已经过时,有的没有实际经验也很难理解

  • << 图解HTTP >>
    HTTP 入门好书 ,轻松入门 ,快速了解 HTTP,书非常迷你,携带方便

  • << HTTP权威指南 >>
    如果想要更深入的学习http 这是一本绝对好书,身边的人都在推荐它,但我还没有看过,作为一个特别平凡的人,精力总是有限的

  • << JavaScript模式 >>
    一本讲解 JS 模式的好书,前半部分对 JS 的概念讲解与拓展,后边的将模式的部分还是有些抽象

  • << JavaScript 设计模式与开发实践 >>
    国内难的的好书之一, 由浅入深, 案例丰富, 绝对值得一看

  • << ECMAScript 6 入门 >>
    想要学习node么, 想要学习最新的框架么, 那你最好先看一下ES6

  • << 深入浅出 nodejs >>
    书如其名, 深入原理

定义

保证一个类仅有一个实例, 并提供一个访问它的全局访问点

一个简单的单例

用一个变量标志当前是否已经为某个类创建过对象, 如果有,则在下一次获取该类的实例时直接返回之前创建的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
var Singleton = function(name){
this.name = name;
this.instance = null;
}
Singleton.prototype.getName = function(){
alert(this.name);
};
Singleton.getInstance = function(name){
if(!this.instance){
this.instance = new Singleton(name);
}
return this.instance;
};
var a = Singleton.getInstance('sven1');
var b = Singleton.getInstance('sven2');

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

</script>

惰性单例

惰性单例指的是在需要的时候才创建对象实例. 并且我没可以把单例的逻辑抽象出来, 形成通用的惰性单例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script>
//抽离出的单例逻辑
var getSingle = function(fn){
var result;
return function(){
return result || (result = fn.apply(this, arguments));
}
};
//执行的函数
var createLoginLayer = function(){
var div = document.createElement('div');
div.innerHTML ='我是登录框';
document.body.appendChild(div);
return div;
};
var createSingleLoginLayer = getSingle(createLoginLayer);

</script>

这是一个创建登录框的案例, 我们可以在任何需要的时候调用

createSingleLoginLayer();

并且如果我们需要创建一个iframe 或其他 DOM 节点只需再写一个 执行的函数 ,并重用getSingle

前言

gulp学习与使用参考网址收录

gulp

官网
中文网
插件
Gitbook

gulp核心API

http://www.ydcss.com/archives/424
http://www.hubwiz.com/class/562089cb1bc20c980538e25b#

常用插件收集

https://markgoodyear.com/2014/01/getting-started-with-gulp/

删除文件和文件夹
del

合并js文件
gulp-concat

合并css文件
gulp-concat-css

重命名文件
gulp-rename

压缩js
gulp-uglify

压缩css
gulp-cssnano

压缩页面
gulp-minify-html

压缩照片
gulp-imagemin

自动打开浏览器
gulp-open

依赖自动加载
[gulp-load-plugins]

自动刷新页面
gulp-livereload

gulp-useref

想知道的太多, 想学的太多, 想玩的也太多, 人的欲望真是无穷尽, 追寻的过程中有时喜悦, 有时迷茫, 有时恐惧. 想必一个天才也不能实现它的追求, 更不要说我这样一个普通人了. 人有七情六欲, 此乃天使, 也是恶魔; 人还有生老病死, 更乃是未知的命运.

我想把一切都做好, 我想知道所有知识, 我想要进行一切的娱乐, 但是那是不可能的, 人的力量终究是有穷尽的, 现实与肉体更是逃不开的枷锁, 奈何 奈何 奈何

简介

indexedDB是HTML5-WebStorage的重要一环,是一种轻量级NOSQL数据库。
IndexedDB是一个相比web sql(sqlite)更加高效,包括索引、事务处理和健壮的查询功能档数据库,它在完全内置于浏览器中的一个沙盒环境中(强制依照(浏览器)同源策略)

基于事务

在indexedDB中,事务会自动提交或回滚。所以无需手动commit或者rollback。
事务分为三种:

IDBTransaction.READ_ONLY              只读
IDBTransaction.READ_WRITE             可读可写
IDBTransaction.VERSION_CHANGE         版本升级

游标

游标是遍历object store的唯一方法。如果在打开游标的时候不设置,默认采用IDBCursor.NEXT。在调用了cursor.continue之后,cursor会重新调用onsuccess句柄上的方法。

基于请求

对数据库的每次操作,描述为通过一个请求打开数据库,访问一个object store,再继续。IndexedDB API天生是基于请求的,这也是API异步本性指示。对于你在数据库执行的每次操作,你必须首先为这个操作创建一个请求。当请求完成,你可以响应由请求结 果产生的事件和错误。
command->request->result的方式

样例

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
IndexedDB练习页面
</body>
<script type="text/javascript">

// 获取indexdb对象,为了兼容性的写法
// 1、获取对象
window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
window.IDBCursor = window.IDBCursor || window.webkitIDBCursor || window.msIDBCursor;

// 2、定义数据库的基本信息
var dbInfo = {
dbName: 'aptdb',
dbVersion: 2019, //用小数会四舍五入,版本号只能越来越大
dbInstance: {},
};

// 3、创建数据库
var dbContent = window.indexedDB.open(dbInfo.dbName, dbInfo.dbVersion);

// 判断数据库版本号是够更新了(创建和修改表结构在这里操作)
// 如果数据库名称和版本号相同,那么该方法只执行一次
dbContent.onupgradeneeded = function (e) {

console.log(e);

// 4、创建数据库store(表)
var _db = e.target.result;
var storeNames = _db.objectStoreNames;

if (!storeNames.contains("cart")) {
// 创建一个表结构出来
_db.createObjectStore("cart", {
keyPath: "goodsId",//相当于关系型数据库中的主键
autoIncrement: true
});
}

// 样例数据
// var a={
// goodsId:123,
// name:"shiguqoing",
// age:32,
// number:"2354657"
// }

// var b={
// goodsId:1234,
// name:"shiguqoing",
// age:32,
// number:"2354657"
// }

}

// 数据库创建成功时候的方法(增删改查操作)
dbContent.onsuccess = function (e) {

// 5、增删改查操作,开启事物,每次只能做一件事情
var _db = e.target.result;
var trans = _db.transaction(["cart"], "readwrite")
var store = trans.objectStore("cart")

// 虽然可以在一次成功打开请求的操作中同时操作多次增删改查命令,但是不推荐,以为这样前面的操作就不能被监听到了
// 增加数据
// var req=store.add({
// goodsId:'df6',
// prise:12.3,
// name:"衣服",
// size:"M",
// age:99
// })



// 修改数据
// var req = store.put({
// goodsId: 'df8',
// prise: 12.3,
// name: "衣服",
// size: "g"
// })

// 删除数据
// var req = store.delete("df7");

// 查询数据
// var req = store.get("df");

// 删除所有数据
// var req = store.clear();

// req.onsuccess=function(e){
// console.log("执行了");
// }
//
// req.onerror=function(){

// }


// 查询所有数据(用了游标)
var cursor=store.openCursor();
var data=[];

cursor.onsuccess=function(e){
var result = e.target.result;
if (result && result !== null) {
data.push(result.value);
// 重新执行onsuccess句柄
result.continue();
}
console.log(data);
}
cursor.onerror=function(){

}

}


// 数据库创建失败
dbContent.onerror = function (e) {
alert("数据库链接失败");
}


</script>
</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
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
<script>
var db = (function(window){

window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange;
window.IDBCursor=window.IDBCursor||window.webkitIDBCursor|| window.msIDBCursor;
var db={
dbName: 'aptdb',
dbVersion: 2046, //用小数会四舍五入
dbInstance: {},

errorHandler: function (error) {
console.log('error: ' + error.target.error.message);
},

// 打开数据库连接
open: function (func,fail) {
var dbContent = window.indexedDB.open(db.dbName, db.dbVersion);
// 数据库打开请求的更新回调函数
dbContent.onupgradeneeded = db.upgrade;
// 数据库打开请求的失败回调函数
dbContent.onerror = db.errorHandler;
// 数据库打开请求的成功回调函数
dbContent.onsuccess = function (e) {
db.dbInstance = dbContent.result;
db.dbInstance.onerror = fail;
func();
};
},
// 数据库版本更新操作
upgrade: function (e) {
var _db = e.target.result,names = _db.objectStoreNames;
// 此处可以创建多个表
var name = "cart";
if (!names.contains(name)) {
// 创建表
_db.createObjectStore(
name,
{
keyPath: 'goodsId',
autoIncrement:false
});
}
},
// 获取表对象
getObjectStore: function (objectStoreName,mode) {
var txn, store;mode = mode || 'readonly';
txn = db.dbInstance.transaction([objectStoreName], mode);
store = txn.objectStore(objectStoreName);
return store;
},
// 增加数据方法
add: function (objectStoreName,data,success,fail) {
db.open(function () {
var store, req, mode = 'readwrite';
store = db.getObjectStore(objectStoreName,mode),
req = store.add(data);
req.onsuccess = success;
req.onerror=fail;
},fail);
},
// 修改数据方法
update: function (objectStoreName,data,success,fail) {
db.open(function () {
var store, req, mode = 'readwrite';
store = db.getObjectStore(objectStoreName,mode),
req = store.put(data);
req.onsuccess = success;
req.onerror=fail;
},fail);
},
// 获取全部数据方法
getAll: function (objectStoreName,success,fail) {
db.open(function () {
var
store = db.getObjectStore(objectStoreName),
cursor = store.openCursor(),
data = [];

cursor.onsuccess = function (e) {
var result = e.target.result;
if (result && result !== null) {
data.push(result.value);
result.continue();
} else {
success(data);
}
};
cursor.onerror=fail;

},fail);
},
// 获取单条数据方法
get: function (id,objectStoreName,success,fail) {
db.open(function () {
var
store = db.getObjectStore(objectStoreName),
req = store.get(id);
req.onsuccess = function (e){
success(e.target.result);
};
req.onerror=fail;
});
},
// delete是保留字
// 删除数据方法
'delete': function (id,objectStoreName,success,fail) {
db.open(function () {
var
mode = 'readwrite',
store, req;
store = db.getObjectStore(objectStoreName,mode);
req = store.delete(id);
req.onsuccess = success;
req.onerror=fail;
});
},
// 删除表数据方法
deleteAll: function (objectStoreName,success,fail) {
db.open(function () {
var mode, store, req;
mode = 'readwrite';
store = db.getObjectStore(objectStoreName,mode);
req = store.clear();
req.onsuccess = success;
req.onerror=fail;
});
}
};

return db;

})(window);
</script>

短轮询

使用定时器与AJAX, 定时发送请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<script>
setInterval(xhrRequest, 2000);
function xhrRequest(){
var xhr = new XMLHttpRequest();
xhr.open('get',url);
xhr.send(null);

xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
// TODO
}
}
}
</script>

长轮询

使用AJAX, 在响应完成时再次发送请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function longPull(url, callback){
var xhr = new XMLHttpRequest();
xhr.open('post',url);
xhr.setRequestHeader('Content-type','application/x-www-form-unlencoded');
xhr.send(null);

xhr.onreadystatechange = function(){
if(xhr.readeState == 4){
callback(xhr.responseText);
//发送另一个请求
xhr.open('get',url);
xhr.send(null);
}
}
}

XHR流

使用AJAX并在服务器端设置打印打输出缓存然后刷新,使readyState的状态维持为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
服务器端
<?php
$i = 0;
while(true){
//输出一些数据,然后立即刷新缓存输出
echo "Number is $i";
flush();

sleep(10);
$i++;
}
?>
客户端
<script>
function xhrStreaming(url, callback){
var xhr = new XMLHttpRequest();
xhr.open('get', url);
var lastSize = 0;
xhr.onreadystatechange = function(){
var result;
if(xhr.readyState == 3){
reuslt = xhr.responseText.subString(lastSize);
lastSize = xhr.responseText.length;
callback(result);
}
if(xhr.readyState == 4){
xhrStreaming(url, callback);
}
}
xhr.send(null);
}
</script>

SSE

Web Sockets

本来想写一写, 去 MDN 上一看突然发现

Deprecated
This feature has been removed from the Web standards. 
Though some browsers may still support it, it is in the process of being dropped. 
Do not use it in old or new projects. 
Pages or Web apps using it may break at any time.

其已被废弃并从标准中移除, 便不再整理
(更多信息来自MDN)[https://developer.mozilla.org/en-US/docs/Web/HTML/Using_the_application_cache]

在HTML5的规范中,我们可以通过为元素标签增加

draggable="true"

属性来设置此元素是否可以进行拖拽操作,其中图片、链接默认是开启的。

事件

拖拽元素
页面中设置了draggable=”true”属性的元素

drag      应用于拖拽元素,整个拖拽过程会不断调用
dragstart 应用于拖拽元素,当拖拽开始时调用
dragleave 应用于拖拽元素,当鼠标离开拖拽元素时调用
dragend   应用于拖拽元素,当拖拽结束时调用

目标元素
页面中任何一个元素都可以成为目标元素

dragenter 应用于目标元素,当拖拽元素进入时调用
dragover  应用于目标元素,当停留在目标元素上时会不断调用
drop      应用于目标元素,当在目标元素上松开鼠标时调用
dragleave 应用于目标元素,当鼠标离开目标元素时调用

事件对象的方法

event.dataTransfer.setData(k, v); 设置被拖数据的数据类型和值
event.dataTransfer.getData(k); 获得被拖的数据

默认地,无法将数据/元素放置到其他元素中。如果需要设置允许放置,我们必须阻止对元素的默认处理方式。
这要通过调用 ondragover 事件的 event.preventDefault() 方法

event.preventDefault()

(更多信息来自w3school)[http://www.w3school.com.cn/html5/html_5_draganddrop.asp]

旧方法

旧版本中我们用 BOM 的 history 对象来管理历史记录

history.back(); 回退
history.forward(); 前进
history.go(n);  前进/后退n步,正值前进,负值后退
history.length; 历史记录条数(同一个站点下的历史记录的长度)

新方法

  • pushState(data, title, url)

追加一条历史记录:
在当前页面之前插入一个一模一样的页面并将当前页面的 url 更改为方法中设置的 url

data 用于存储自定义数据,通常设为null
title 网页标题,基本上没有被浏览器支持,一般设为空
url 以当前域为基础增加一条历史记录,不可跨域设置

例:

<script>
    // 1、pushState可以往历史记录添加一条记录
    var btn = document.getElementById('btn');       
    btn.onclick = function () {
        // history对象的新方法pushState
        // 可以追加一条历史记录
        // 追加完成后,当前页面并未刷新
        history.pushState(null, 'title', '/text.html');
        // 1、代表是传递的数据,一般可能传null
        // 2、代表网页标题,但是浏览器不支持
        // 3、追加的历史记录
    }       
</script>
  • replaceState(data, title, url)

与pushState()基本相同,不同之处在于replaceState(),只是替换当前url,不会增加/减少历史记录。

事件监听

onpopstate;

当前进或后退时则触发,通过事件对象ev.state可以读取到存储的数据,监听是要给window。
例:

<script>
    var btn = document.getElementById('btn');
    btn.onclick = function () {
        // 追加历史记录
        history.pushState({key: 123}, 'title', '/text.html');
    }
    // 监听历史的变化
    window.onpopstate = function (ev) {
        console.log(ev.state);
        console.log(ev);
    }
</script>