lynxerzhang / jsskills Goto Github PK
View Code? Open in Web Editor NEWLicense: MIT License
License: MIT License
gskinner的Createjs工具库是使用es5语法编写的,其中有一个deprecate方法。
this.createjs = this.createjs||{};
createjs.deprecate = function(fallbackMethod, name) {
"use strict"; //此处的use strict可以将如下的匿名函数中的this限制为undefined, 如果不添加,就是全局的window。
return function() {
var msg = "Deprecated property or method '"+name+"'. See docs for info.";
console && (console.warn ? console.warn(msg) : console.log(msg));
return fallbackMethod && fallbackMethod.apply(this, arguments);
}
};
但是这里面又会引出一个问题,如何判断一个class是否能够覆盖另一个class中的属性,这篇教程详细叙述了如何计算css specificity value。
需要注意,css specificity value的数值不是十进制的,所以它使用的是诸如,(1, 0, 0, 0),(0, 1, 0, 0),也就是其中有逗号分隔。
以(1, 0, 0, 0)为例,从左到右specificity value从高到低,依次递减。第一等是内联元素的style,第二等为元素id,第三等为元素的class,伪类,属性选择,第四类为元素本身。同时要注意!important的影响,其中pseudo-class和pseudo-elements是不同的,比如first-line就是pseudo-elements,计算下来为(0, 0, 0, 1),而不像pseudo-class为(0, 0, 1, 0)
var colorToRGB = (function(){
return function(colorHex) {
if(typeof colorHex == 'number'){
colorHex = "#" + colorHex.toString(16);
}
var hashTag = colorHex.charAt(0) === "#";
if(hashTag){
colorHex = colorHex.slice(1);
}
var shorthand = colorHex.length == 3;
var alpha = colorHex.length == 8;
if(shorthand){
var h = colorHex.split("").map(function(s){
return s + s;
});
colorHex = h.join("");
}
var hex = parseInt(colorHex, 16);
return "rgb" + (alpha ? "a" : "") + "(" +
(alpha ? (((hex >> 24) & 0xFF) + ", ") : "") +
((hex >> 16) & 0xFF) + ", " + ((hex >> 8) & 0xFF) + ", " +
(hex & 0xFF) + ")";
}
})();
console.log(colorToRGB('#ffff6600')); // rgba(255, 255, 102, 0)
//如下输出都为rgb(255, 102, 0)
console.log(colorToRGB('ff6600'));
console.log(colorToRGB('#f60'));
console.log(colorToRGB('f60'));
console.log(colorToRGB(0xff6600));
var root = document.getElementById("playground");
var e = createChild();
root.appendChild(e);
function createChild() {
var e = document.createElement("div");
e.style.position = "absolute";
e.style.width = "50px";
e.style.height = "10px";
e.style.top = "10px";
e.style.left = "500px";
e.style.background = "blue";
return e;
}
setTimeout(function(){
var d = new DomAnimationX(e, {"x":-550 * .5, "duration":5000 * .5});
d.add("complete", function(){
setTimeout(function(){
d = new DomAnimationX(e, {"x":-550, "duration":5000 * .5});
f.add(d);
}, 3000);
})
var f = new TickDomManager();
f.add(d);
f.start();
}, 0);
//使用transform对dom进行位移,同时又使用transition监听dom上的transfrom位移来达到线性动画的目的。
var TickDomManager = (function(){
function TickDomManager(){
this.domAnList = [];
var self = this;
this.tick = new Animation(function(t){
self.tickCallback(t);
});
}
var p = TickDomManager.prototype;
p.start = function() {
this.tick.start();
var len = this.domAnList.length;
var d;
for(var i = 0; i < len; i ++){
d = this.domAnList[i];
if(d){
d.start();
}
}
}
p.stop = function() {
this.tick.stop();
var len = this.domAnList.length;
var d;
for(var i = 0; i < len; i ++){
d = this.domAnList[i];
if(d){
d.stop();
}
}
}
p.tickCallback = function(time) {
var len = this.domAnList.length;
var d;
for(var i = 0; i < len; i ++){
d = this.domAnList[i];
if(d){
d.tick(time);
}
}
}
p.add = function(domAn) {
domAn.start();
var self = this;
domAn.add("complete", function(){
self.remove(this);
this.destroy();
}.bind(domAn)); //bind 方法执行上下文环境
this.domAnList.push(domAn);
}
p.remove = function(domAn) {
var len = this.domAnList.length;
var d;
for(var i = len - 1; i >= 0; i --){
d = this.domAnList[i];
if(d && d == domAn){
break;
}
}
if(i >= 0 && i < len){
this.domAnList.splice(i, 1);
}
}
return TickDomManager;
})();
var DomAnimationX = (function(){
function DomAnimationX(dom, data) {
this.dom = dom;
this.data = data;
this.duration = data.duration;
this.lifeDuration = this.duration;
this.delay = data.delay || 0;
this.watch = createEventDispatch();
}
var p = DomAnimationX.prototype;
p.destroy = function() {
this.dom = null;
this.data = null;
this.watch = null;
}
p.start = function() {
Animation.setTransition(this.dom, "transform " +
this.lifeDuration + "ms linear " + this.delay + "ms");
Animation.setTransform(this.dom, "translateX(" + this.data.x + "px)");
this.dispatch("start");
}
p.stop = function() {
var d = this.data.x * ((this.duration - this.lifeDuration) / this.duration);
Animation.setTransition(this.dom, "");
Animation.setTransform(this.dom, "translateX(" + d + "px)");
this.dispatch("stop");
}
p.tick = function(time) {
if(this.lifeDuration <= 0){
this.lifeDuration = 0;
this.dispatch("complete");
return;
}
this.lifeDuration -= time;
}
p.add = function(e, h) {
this.watch.add(e, h);
}
p.remove = function(e, h) {
this.watch.remove(e, h);
}
p.dispatch = function(e) {
this.watch.dispatch(e);
}
return DomAnimationX;
})();
var createEventDispatch = (function(){
return function() {
var watch = {};
watch.listener = {};
watch.add = function(e, h){
var s = this.listener[e];
if(!s){
this.listener[e] = [h];
}
else{
if(s.indexOf(h) < 0){
s.push(h);
}
}
}
watch.remove = function(e, h) {
var s = this.listener[e];
if(s){
var len = s.length;
if(arguments.length == 1){
s.length = 0;
s = null;
this.listener[e] = s;
}else{
for(var i = len - 1; i >= 0; i--){
if(s[i] == h){
break;
}
}
if(i >= 0 && i < len){
s.splice(i, 1);
}
}
}
}
watch.dispatch = function(e){
var s = this.listener[e];
if(s){
var len = s.length;
var d;
for(var i = len - 1; i >= 0; i --){
d = s[i];
d(e);
}
}
}
return watch;
}
})();
var Animation = (function(){
function Animation(callback){
this.callback = callback;
this.running = false;
this.shouldKill = false;
this.last = 0;
this.now = 0;
}
Animation.setTransition = function(dom, trans) {
dom.style.transition = trans;
dom.style.webkitTransition = trans;
dom.style.mozTransition = trans;
dom.style.msTransition = trans;
dom.style.oTransition= trans;
}
Animation.setTransform = function(dom, trans){
dom.style.transform = trans;
dom.style.webkitTransform = trans;
dom.style.mozTransform = trans;
dom.style.msTransform = trans;
dom.style.oTransform = trans;
}
Animation.request = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback){
callback();
};
})();
var p = Animation.prototype;
p.start = function() {
this.last = new Date().getTime();
this.shouldKill = false;
if (!this.running) {
this.running = true;
this.render();
}
};
p.stop = function() {
this.shouldKill = true;
this.last = 0;
this.now = 0;
};
p.toggle = function() {
if (this.running) {
this.stop();
}
else {
this.start();
}
};
p.render = function() {
if(this.shouldKill) {
this.shouldKill = false;
this.running = false;
}
if (this.running) {
this.now = new Date().getTime();
if (this.callback) {
this.callback(this.now - this.last);
}
this.last = this.now;
var self = this;
//Animation.request的调用需要如此,不然会报错,原因是该方法上下文执行环境被修改
Animation.request.call(null, function(){
self.render();
});
}
};
p.dispose = function() {
this.stop();
this.callback = null;
this.running = false;
this.shouldKill = false;
};
return Animation;
})();
如果什么标签都不加的话,代码加载和执行是同步的,它会中断解析document,直到它完成执行,并且代码的加载和执行的顺序都是根据script标签的位置决定的。
defer标签会在document还在加载解析的过程中去下载对应的script, 但是并不执行,必须等到document解析全部完成才会去执行对应的script, 并且执行的顺序是根据script标签的位置来决定的。可以理解成执行script的代码是放在DOMContentLoaded事件回调中。
async标签会在document还在加载解析的时候去下载对应的script, 但是下载好后会中断document的解析, 去执行之前下载好的script, 同时async标签不会保证按照script的顺序来执行。
//@see https://30secondsofinterviews.org/
What are defer and async attributes on a <script> tag?
Note: both attributes must only be used if the script has a src attribute (i.e. not an inline script).
<script src="myscript.js"></script>
<script src="myscript.js" defer></script>
<script src="myscript.js" async></script>
参考介绍git clean 命令
中文参考介绍git clean 命令
基本上常用的就是 git clean -fn,这里f是强制删除(force)之意, n是提示,也就是这个删除不是真删除,它会列出将会删除的文件,需要你来确认,没有问题了,可以放心使用git clean -f
也可以使用git clean -f -i, 会调出交互式询问窗口,这样更安全,不但列出即将删除的文件,还会询问你是如何计划的,删除或者什么都不做退出。
利用 git whatchanged --stat 命令查看修改历史,比单纯git log更为详细直观
Xshell 属性中设置UTF-8
git config --global i18n.commitencoding utf-8
git config --global i18n.logoutputencoding utf-8
export LESSCHARSET=utf-8
可以参考该讨论
<a id="myLink" href="javascript:MyFunction();">link text</a> //bad
<a id="myLink" href="#" onclick="MyFunction();">link text</a> //good
<a id="myLink" href="#" onclick="MyFunction();return false;">link text</a> //better
....
//获取指定cookie值
function readCookie(name) {
var g = new RegExp('(?:^|;)\\s*' + name + '\\s*=\\s*([^;]+)');
var s = document.cookie;
var d = null;
if (g.test(s)) {
d = s.match(g);
if(d){
d = d.pop();
}
}
return d;
}
如上实现中的正则表达式做过一个优化,就是使用'非捕捉group'来简化返回值,也就是?:修饰符,
其中字符串的match函数的返回内容,会根据填入的正则表达式是否添加全局搜索修饰符g而不一样,
如果没有填入g,它的返回形式和RegExp的exec方法很像,会返回各种capture group和index值,如果
添加g,返回的就是简单的数组匹配项。
@see https://github.com/Chalarangelo/30-seconds-of-code
//indexOfAll
var indexOfAll = (function(){
return function(ary, val) {
return ary.reduce(function(prev, cur, i){
return cur === val ? prev.concat(i) : prev;
}, []);
}
})();
indexOfAll([1, 2, 3, 1, 2, 3], 1);
// [0,3]
//getLongItem
var getLongItem = (function(){
return function (val){
var c = arguments.length - 1;
var list = [val];
if(c > 0){
for(var i = 0; i < c; i ++){
list.push(arguments[i + 1]);
}
}
return list.reduce(function(prev, current){
return current.length > prev.length ? current : prev;
});
}
})();
getLongItem([1, 2, 3], [1, 2], [1, 2, 3, 4, 5]);
// [1, 2, 3, 4, 5]
//mapObject
var mapObject = (function(){
return function(ary, keyFunc, valueFunc) {
var d = [ary.map(keyFunc), ary.map(valueFunc)];
return d[0].reduce(function(prev, current, index){
return prev[current] = d[1][index], prev;
}, {});
}
})();
var result = mapObject(["a1+1", "a2+2", "a3+3"], function(a){
return a.split("+")[0];
}, function(a){
return a.split("+")[1]
});
//{a1: "1", a2: "2", a3: "3"}
//partitionReduce
var partitionReduce = (function(){
return function(ary, check) {
return ary.reduce(function(prev, cur, index, array){
prev[check(cur) ? 0 : 1].push(cur);
return prev;
}, [[], []]);
}
})();
var ary = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
partitionReduce(ary, function(n){
return n % 2 == 0;
});
//[[2, 4, 6, 8, 10],[1, 3, 5, 7, 9]]
//pickFilter
var pickFilter = (function(){
return function(obj, ary){
return ary.reduce(function(prev, cur, index, array){
if(obj.hasOwnProperty(cur)){
prev[cur] = obj[cur];
}
return prev;
}, {});
}
})();
pickFilter({ a: 1, b: '2', c: 3 }, ['a', 'b']); // {a: 1, b: "2"}
可参考该描述,以及这篇,从父级定位至子级,希望子级中的最后一个元素执行额外的样式,发现不起作用,可以查看该父级是否只有一种该类型的子级,比如父级的类型为ul,子级如果都是li,则可以生效,如果其中夹杂着其它类型元素,比如span之类,则不起作用
如下代码,html 和 css 可以在codepen中调试
<ul>
<li>3</li>
<li class="complete">1</li>
<li class="complete">2</li>
<li>3</li>
<li>4</li>
<span></span>
</ul>
//如果span不加在最后,而是成为ul的第一个元素,也可以正常执行
li.complete:last-child{
background-color: green;
}
li.complete:first-of-type {
background-color: green;
}
这个帖子很好的说明了两者的区别,现在整理如下:
1. 在function外声明的变量, let无法通过window来访问到
var canfound = 2;
let cannotFound = 2;
console.log(window.canfound); //2
console.log(window.cannotFound); //undefined
2. let 无法被重新声明
let canNotBeRedeclaration = 1;
let canNotBeRedeclaration = 2;
//Identifier 'canNotBeRedeclaration' has already been declared
var canBeRedeclaration = 1;
var canBeRedeclaration = 2;
console.log(canBeRedeclaration); //2
3. let在function中的作用域
//let
function testletScope() {
//无法访问i ReferenceError: i is not defined
for(let i = 0; i < 5; i ++){
//可以访问i
}
//无法访问i ReferenceError: i is not defined
}
//var
function testvarScope() {
//由于变量提升,i为undefined
for(var i = 0; i < 5; i ++){
//可以访问i
}
//可以访问i
}
利用css的backgroundImage属性可以设置渐变色,但是利用js来动态设置时,设置颜色值的时候有个地方需要注意,不然可能造成显示问题(比如css属性添加不上)。
这个需要注意的就是颜色值本身。
问题重现:
//我需要把这个数组中的每一个项,变成字符串,比如第一项0xff2a46,经过转换就是#ff2a46,
var d = [0xff2a46,0xff7522,0xd8c206,0x09d49d,0x3c78ff,0x991aff];
//利用toString方法,可以很容易做到。
//下面这个数组就是转换过的。
var e = ["#ff2a46", "#ff7522“, "#d8c206", "#9d49d", "#3c78ff", "#991aff"];
但是很快发现,无法添加渐变色,查了好久发现0x09d49d变成了"#9d49d", 这个本身没有问题,但是就是因为少了个0,就不显示渐变色了,
所以,做了个判断,24位颜色值的16进制值字符串因为长度最长就是6,所以可以判断下,如果长度不满6,字符串前面就填充0。
那“#9d49d”就变成了“#09d49d”,修改后发现显示正常
//gradientBackgroundColorList传进来的是一个颜色值数组,比如[0xFF0000, 0xFFFF00, 0xFF00FF]
Object.defineProperty(CoreComment.prototype, "gradientBackgroundColorList", {
get: function () {
return this._gradientBackgroundColorList;
},
set: function (c) {
this._gradientBackgroundColorList = c;
if(this._gradientBackgroundColorList){
var list = this._gradientBackgroundColorList;
var g_css = ["left"];
for(var i = 0; i < list.length; i ++){
g_css.push("#" + list[i].toString(16)); //这个版本粗看没有什么问题
}
this.dom.style.backgroundImage = "-webkit-linear-gradient(" + g_css.join(",") + ")";
}
else{
this.dom.style.backgroundImage = "none";
}
},
enumerable: true,
configurable: true
});
//修正版本
Object.defineProperty(CoreComment.prototype, "gradientBackgroundColorList", {
get: function () {
return this._gradientBackgroundColorList;
},
set: function (c) {
this._gradientBackgroundColorList = c;
if(this._gradientBackgroundColorList){
var list = this._gradientBackgroundColorList;
var g_css = ["left"];
var c = "";
for(var i = 0; i < list.length; i ++){
c = list[i].toString(16);
if(c.length < 6){
c = (new Array((6 - c.length) + 1).join("0")) + c; //关键在于这个判断,如果字符长度不满6,就需要用0来填充
}
g_css.push("#" + c);
}
this.dom.style.backgroundImage = "-webkit-linear-gradient(" + g_css.join(",") + ")";
}
else{
this.dom.style.backgroundImage = "none";
}
},
enumerable: true,
configurable: true
});
visibilitychange 这个事件只能针对当前标签页是否失去焦点来进行判断,所以需要再加上判断document的hidden属性来做到对标签页是否切换的判断。
var tabPageVisibilityManager = (function(){
var hiddenProperty = ["hidden", "webkitHidden", "mozHidden", "msHidden"];
var len = hiddenProperty.length;
var propertyKey = "";
for(var i = 0; i < len; i ++){
if(hiddenProperty[i] in document){
propertyKey = hiddenProperty[i];
break;
}
}
var eventKey = "";
if(propertyKey && propertyKey != ""){
eventKey = propertyKey.replace(/hidden/i, "visibilitychange");
}
return function(pause_callback, resume_callback) {
document.addEventListener(eventKey, function(){
if(!document[propertyKey]){
if(resume_callback != null){
resume_callback();
}
}else{
if(pause_callback != null){
pause_callback();
}
}
});
}
})();
tabPageVisibilityManager(function(){
console.log("pause");
}, function(){
console.log("resume");
});
彻底搞懂git rebase
Git Book关于git rebase描述
Git Book关于git rebase交互式描述
常用git命令详解
详细阐述了git rebase命令
可以发现这个命令如果在没有push到远程的分支上运用,或者说只是在本地分支单人操作,不存在多人协作还是安全的。
最常用的组合是修改历史命令 git rebase -i HEAD~2 (这个HEAD不一定是指master, ~2就是往前倒退2个commit)
常见场景可以说是譬如收到一个bug需要修改,这时候切出了一个分支专门修改bug,这个分支是自己单独进行修改的,但是因为有其它事情,在还没有完成的情况下就commit了,或者是习惯性commit,这时会有很多无意义的commit,这当然是允许的,但是对以后排查这个bug的修改会非常不利,很多commit实际上只是为了修复一个bug。
这时候git rebase -i 命令可以排上用场了。它可以把之前十几个commit压缩成一个commit!
示例为master和bb分支
如下所示,最新提交的commit是在最下面的,也就是 516a658, 这2个提交我想合并成一个commit, 根据如下注释提示,进行修改,默认都是pick,也就是不做任何修改历史commit的操作。
方便期间,可以输入缩写,譬如如下,r和s分别代表reword, squash。
然后wq保存退出。发现出现如下界面。这是修改commit 提交信息的界面,根据提示可以发现我们可以修改这个commit信息。
可以不修改,直接wq保存退出,这时进入合并阶段,这时候所有的commit提交信息都会显示在这里,可以删除一些commit不需要的信息,这样最终合并就不会包含那些commit。
继续wq保存退出,发现成功合并这些commits为一个commit!
合并结束后,这时候可以和master做合并了,可以git rebase master 也可以git merge master。
如果master在我们修改的时候已经有新的提交了,那需要注意git rebase可能会有冲突,这个和git merge一样,但是git rebase的好处就是可以把提交历史保持线性,尽管实际开发历史不一定是如此标准的线性。
如果master正好处在当前分支上游,那么即使使用git rebase, 也正好是fast-forward。
如果包含有冲突,这很正常,因为分叉提交了,而且即便是使用git merge也会有冲突,
按照上面的提示进行修改冲突, git add 后 继续git rebase --continue,如果在rebase的任何阶段后悔了,可以使用git rebase --abort消除任何git rebase的影响和修改,回到最初始阶段。
修改完冲突后, 继续git rebase --continue
没有问题!这时候查看git log发现,分支和master的提交历史是线性的!
// getBoundingClientRect 方法返回元素的边界,
// window的innerWidth和innerHeight返回当前窗口的实际长宽,不包括标题栏地址栏
var isVisibleInViewport = (function(){
return function(element, inInsideWindow) {
var rect = element.getBoundingClientRect();
var innerWidth = window.innerWidth;
var innerHeight = window.innerHeight;
var top = rect.top;
var left = rect.left;
var right = rect.right;
var bottom = rect.bottom;
if(!inInsideWindow){
inInsideWindow = false;
}
var isInside = false;
if(inInsideWindow){
isInside = top >= 0 && left >= 0 &&
right <= innerWidth && bottom <= innerHeight;
}else{
isInside = ((top >= 0 && top < innerHeight) ||
(bottom > 0 && bottom <= innerHeight)) &&
((left >= 0 && left < innerWidth) ||
(right > 0 && right <= innerWidth));
}
return isInside;
}
})();
Object.assign的复制对象方法需要注意,该复制行为为浅复制
var d = {"a":1, "b":2, "c":[1, 2, 3]};
var e = Object.assign({}, d);
d.c.push(4);
console.log(d.c); //1,2,3,4
console.log(e.c); //1,2,3,4
var logPName = (function(){
return function(obj, callback) {
Object.keys(obj).forEach(function(value, key, obj){
callback(value, key, obj); //值,键,对象
});
}
})();
//example
logPName({"a":1, "b":2, "c":3}, function(key){
console.log(key); //具体callback接受的参数少于调用的也不要紧,可以通过arguments来获取
});
//针对Object.keys的polyfill问题可参考
//@see http://tokenposts.blogspot.com/2012/04/javascript-objectkeys-browser.html
if (!Object.keys) Object.keys = function(o) {
if (o !== Object(o))
throw new TypeError('Object.keys called on a non-object'); //判断是否为对象,注意 !== 符号
var k=[],p;
for (p in o) if (Object.prototype.hasOwnProperty.call(o,p)) k.push(p); //利用Object.prototype.hasOwnProperty 来避免原生的hasOwnProperty被覆盖
return k;
}
var round = (function(){
return function(d, e){
return Number(Math.round(Number(d + "e" + e)) + "e-" + e);
}
})();
var floor = (function(){
return function(d, e){
return Number(Math.floor(Number(d + "e" + e)) + "e-" + e);
}
})();
var ceil = (function(){
return function(d, e){
return Number(Math.ceil(Number(d + "e" + e)) + "e-" + e);
}
})();
//参考:https://mokiee.com/code/193
var tabPageVisibilityManager = (function(){
var hiddenProperty = ["hidden", "webkitHidden", "mozHidden", "msHidden"];
var len = hiddenProperty.length;
var propertyKey = "";
for(var i = 0; i < len; i ++){
if(hiddenProperty[i] in document){
propertyKey = hiddenProperty[i]; //获取具体的hidden属性名
break;
}
}
var eventKey = "";
if(propertyKey && propertyKey != ""){
eventKey = propertyKey.replace(/hidden/i, "visibilitychange");
}
//获取具体事件名eventKey
return function(pause_callback, resume_callback) {
document.addEventListener(eventKey, function(){
if(!document[propertyKey]){
if(resume_callback != null){
resume_callback();
}
}else{
if(pause_callback != null){
pause_callback();
}
}
});
}
})();
//使用
tabPageVisibilityManager(function(){
console.log("pause"); //暂停
}, function(){
console.log("resume"); //恢复
});
//如下实现是对JQuery的hasClass方法进行简化,直接书写成function格式
//获取className, 也可以通过访问元素的className属性来获取
function getClass(elem) {
return elem.getAttribute && elem.getAttribute("class") || "";
}
//jQuery的实现会判断nodeType是否为1,同时需要注意className和selector的左右
//都被添加了一个空格字符,这是为了后面使用indexOf判断的准确性
function hasClass(elem, selector) {
var className = " " + selector + " ";
if(elem){
if ( elem.nodeType === 1 &&
( " " +
stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
return true;
}
}
return false;
}
//stripAndCollapse中正则表达式中的\x20,就是指的空格键,\x标明数值20是16进制,
//换成十进制就是32
function stripAndCollapse( value ) {
var tokens = value.match( /[^\x20\t\r\n\f]+/g) || [];
return tokens.join( " " );
}
//*************************************************************
//如下是一个简单的实现方法(没有做一些细致的检查)
function hasClass(elem, name){
return " " + elem.className + " ".indexOf(" " + name + " ") > -1;
}
//利用stringReplace方法可以方便拼接html
var stringReplace = (function(){
function isArray(arr) {
return Object.prototype.toString.call(arr) === '[object Array]';
}
return function(str){
var args = [];
for(var i = 1; i < arguments.length; i ++){
args.push(arguments[i]);
}
var r, provider;
if (args.length == 1 && typeof(args[0]) == "object" && !isArray(args[0])) {
r = /\(([a-z]+)\)|\{([a-z]+)\}|\[([a-z]+)\]/gi;
provider = args[0];
} else {
r = /\(\d+\)|\{\d+\}|\[\d+\]/gi;
if (isArray(args[0])) {
provider = args[0];
} else {
provider = args;
}
}
str = str.replace(r, function (match) {
return provider[match.slice(1, match.length - 1)];
});
return str;
}
})();
其实在es6中已经提供了类似方法,但在老版本js中,可以利用该方法
var demo = '<div class="demo_parent {demo_parent_class}">' +
'<div class="demo_child1 {demo_child1_class}">' +
'<img class="demo_child1_img" src={demo_child1_img_src}>' +
'</div>' +
'<div class="demo_child2 {demo_child2_class}">' +
'<img class="demo_child2_img" src={demo_child2_img_src}>' +
'</div>' +
'<span class="demo_txt {demo_txt_class}">test</span>' +
'</div>'
demo = stringReplace(demo,
{"demo_parent_class":"xxx",
"demo_child1_class":"xxx",
"demo_child1_img_src": "xxx",
"demo_child2_class": "xxx",
"demo_child2_img_src": "xxx",
"demo_txt_class": "xxx"});
var d = document.createElement("div");
d.innerHTML= demo;
self 会一直指向window对象,而this会根据执行作用域的不同而变化
//https://github.com/tejacques/crosstab 参考crosstab库中的实现
var generateId = (function(){
var pad = function(num, width, paddingStr){
paddingStr = paddingStr || "0";
num = num.toString();
if(num.length >= width){
return num;
}
return new Array((width - num.length) + 1).join(paddingStr) + num;
}
var time = function() {
return new Date().getTime();
}
return function(){
return time().toString() + pad((Math.random() * 0x7FFFFFFF)|0, 10);
}
})();
//example
var id = generateId(); //
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.