数据访问对象模式
本地数据访问例子
var BaseLocalStorage = function (preId, timeSign) {
this.preId = preId;
this.timeSign = timeSign || '|-|';
}
BaseLocalStorage.prototype = {
status: {
SUCCESS: 0,
FAILURE: 1,
OVERFLOW: 2,
TIMEOUT: 3
},
storage: localStorage || window.localStorage,
getKey: function (key) {
return this.preId + key;
},
set: function (key, value, cb, time) {
var status = this.status.SUCCESS,
key = this.getKey(key);
try {
time = new Date(time).getTime() || time.getTime();
} catch(e) {
time = new Date().getTime() + 1000 * 60 * 60 * 24 * 31;
}
try {
this.storage.setItem(key, time + this.timeSign + value);
} catch(e) {
status = this.status.OVERFLOW;
}
cb && cb.call(this, status, key, value);
},
get: function (key, cb) {
var status = this.status.SUCCESS,
key = this.getKey(key),
value = null,
timeSignLen = this.timeSign.length,
self = this,
index, time, result;
try {
value = self.storage.getItem(key);
} catch(e) {
result = {
status: self.status.FAILURE,
value: null
}
cb && cb.call(this, result.status, result.value);
return result;
}
if(value) {
index = value.indexOf(self.timeSign);
time = +value.slice(0, index);
if(new Date(time).getTime() > new Date().getTime() || time == 0) {
value = value.slice(index + timeSignLen);
} else {
value = null;
status = self.status.TIMEOUT;
self.remove(key);
}
} else {
status = self.status.FAILURE
}
result = {
status: status,
value: value
};
cb && cb.call(this, result.status, result.value);
return result;
},
remove: function (key, cb) {
var status = this.status.FAILURE,
key = this.getKey(key),
value = null;
try {
value = this.storage.getItem(key);
} catch(e) {}
if(value) {
try {
this.storage.removeItem(key);
status = this.status.SUCCESS;
} catch(e) {}
}
cb && cb.call(this, status, status > 0 ? null : value.slice(value.indexOf(this.timeSign) + this.timeSign.length))
}
}
var LS = new BaseLocalStorage('LS__');
var cb = function () {console.log(arguments)}
LS.set('a', 'a label', cb);
LS.get('a', cb);
LS.remove('a', cb);
LS.remove('a', cb);
LS.get('a', cb);
节流模式
- 对重复的业务逻辑进行节流控制,执行最后一次操作病取消其他操作;
节流器-页面滚动例子
var extend = function (source, target) {
target = target || {};
for(var p in source) {
!target[p] && (target[p] = source[p])
}
return target;
};
var throttle = function () {
var isClear = arguments[0], fn, param;
if(typeof isClear === 'boolean') {
fn = arguments[1];
//函数的计时器句柄存在,清除计时器
fn._throttleID && clearTimeout(fn._throttleID);
} else {
fn = isClear;
param = arguments[1];
//对执行的参数适配默认值
var p = extend({
context: null,
args: [],
time: 300
}, param);
//清除执行函数计时器句柄
arguments.callee(true, fn);
//为函数绑定计时器句柄,延迟执行函数
fn._throttleID = setTimeout(function () {
fn.apply(p.context, p.args)
}, p.time)
}
}
function moveScroll () {
console.log('test');
}
window.onscroll = function () {
throttle(moveScroll);
}
优化浮层
- 当光标划入和划出容器时,为避免是用户误操作,应该使用节流器延迟操作;
图片延迟加载优化
- 目标是使可视范围内的图片优先加载;
- 先将获取的
src
设置到图片的data-src
,再延迟设置;
function LazyLoad (id) {
this.container = document.getElementById(id);
//缓存图片
this.imgs = this.getImgs();
this.init();
}
LazyLoad.prototype = {
init: function () {
//加载当前视图图片
this.update();
//绑定事件
this.bindEvent();
},
getImgs: function () {
var arr = [];
var imgs = this.container.getElementsByTagName('img');
for (var i = 0, l = imgs.length; i < l; i++) {
arr.push(imgs[i]);
}
return arr;
},
update: function () {
if(!this.imgs.length) return;
var i = this.imgs.length;
for(--i; i >= 0; i--) {
if(this.shouldShow(i)) {
this.imgs[i].src = this.imgs[i].getAttribute('data-scr');
this.imgs.splice(i, 1);
}
}
},
//判断图片是否在可视范围内
shouldShow: function (i) {
var img = this.imgs[i];
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
var scrollBottom = scrollTop + document.documentElement.clientHeight;
var imgTop = this.pageY(img);
var imgBottom = imgTop + img.offsetHeight;
if(imgBottom > scrollTop && imgBottom < scrollBottom || (imgTop > scrollTop && imgTop < scrollBottom))
return true;
return false;
},
pageY: function (element) {
//如果元素有父元素
if(element.offsetParent) {
return element.offsetTop + this.pageY(element.offsetParent);
} else {
return element.offsetTop;
}
},
on: function (element, type, fn) {
if(element.addEventListener) {
element.addEventListener(type, fn, false);
} else {
element.attachEvent('on' + type, fn, false);
}
},
bindEvent: function () {
var self = this;
this.on(window, 'resize', function () {
throttle(self.update, {context: self})
});
this.on(window, 'scroll', function () {
throttle(self.update, {context: self})
})
}
}
var lazyLoad = new LazyLoad('container');