- 1 仿ECMAScript5中Object.create()函数
- 2 仿ECMAScript5中String.trim()函数
- 3 仿ECMAScript5中Array.reduce()函数
- 4 在数组中查找所有出现的元素方法
- 5 数据类型检测,特殊情况特殊处理
- 6 仿ECMAScript5中Object.keys()函数
- 7 仿Math.max方法(不定实参函数)
- 8 仿ECMAScript5中Function.bind()函数
- 9 仿ECMAScript5中Array.map()函数
- 10 数组去重
- 11 冒泡排序
- 12 仿String.match()方法实现
- 13 返回元素的第n层祖先元素
- 14 返回元素的第n个兄弟元素
- 15 返回元素的第n个子代元素
- 16 表格的行排序
- 17 生成目录表
- 18 从URL解析参数
- 19 获取纯文本的元素内容
- 20 手写一个JSONP实现
- 21 插入节点
- 22 使用innerHTML实现outerHTML属性
- 23 倒序排列子节点
- 24 查询窗口滚动条的位置
- 25 查询窗口的视口尺寸
- 26 返回函数的名字
- 27 原生JS实现CSS动画1
- 28 原生JS实现CSS动画2
- 29 仿HTML5的classList属性
- 30 查询纯文本形式的内容
- 31 查找元素的后代中节点中的所有Text节点
- 32 使用innerHTML实现insertAdjacentHTML()
- 33 拖拽
仿ECMAScript5中Object.create()函数
function
inherit(obj) {
if
(obj ===
null
)
throw
TypeError();
if
(Object.create)
return
Object.create(obj);
var
t =
typeof
obj;
if
(t !==
"object"
&& t !==
"function"
)
throw
TypeError();
function
Fn() {};
Fn.prototype = obj;
return
new
Fn();
}
|
仿ECMAScript5中String.trim()函数
String.prototype.mytrim =
function
() {
String.prototype.trim ||
function
() {
if
(!
this
)
return
this
;
//空字符串不做处理
return
this
.replace(/^\s+|\s+$/g,
""
)
//使用正则表达式经行空格替换
}
}
|
仿ECMAScript5中Array.reduce()函数
var
reduce = Array.prototype.reduce ?
function
(ary, fn, initial) {
if
(arguments.length > 2) {
//如果reduce()方法存在的话
return
ary.reduce(fn, initial);
//如果传入了一个初始值
}
else
{
return
ary.reduce(fn);
//否则初始值
}
} :
function
(ary, fn, initial) {
//以特定的初始值开始,否则第一个值取自ary
var
i = 0,
len = ary.length,
accumulator;
if
(arguments.length > 2) {
accumulator = initial;
}
else
{
//找到数组中第一个已经定义的索引
if
(len == 0)
throw
TypeError();
while
(i < len) {
if
(i
in
ary) {
accumulator = ary[i++];
break
;
}
else
{
i++;
}
}
if
(i == len)
throw
TypeError();
}
while
(i < len) {
//对于数组中剩下的元素依次调用fn
if
(i
in
ary) {
accumulator = fn.call(undefined, accumulator, ary[i], i, ary)
}
i++;
}
return
accumulator;
}
|
在数组中查找所有出现的元素方法
function
findAll(ary, ele) {
var
results = [],
len = a.length,
pos = 0;
while
(pos < len) {
pos = ary.indexOf(ele, pos);
if
(pos === -1)
break
;
results.push(pos);
pos++;
}
return
results;
}
|
数据类型检测,特殊情况特殊处理
function
classOf(obj) {
if
(obj ===
null
)
return
"Null"
;
if
(obj === undefined)
return
'Undefined'
;
return
Object.prototype.toString.call(obj).slice(8, -1);
}
|
仿ECMAScript5中Object.keys()函数
function
keys(obj) {
if
(
typeof
obj !==
"object"
) {
throw
TypeError();
}
var
result = [];
for
(
var
prop
in
obj) {
if
(obj.hasOwnProperty(prop)) {
result.push(prop);
}
}
return
result;
}
|
仿Math.max方法(不定实参函数)
function
max() {
var
max = Number.NEGATIVE_INFINITY;
for
(
var
i = 0; i < arguments.length; i++) {
if
(arguments[i] > max) max = arguments[i];
}
return
max;
}
|
仿ECMAScript5中Function.bind()函数
if
(!Function.prototype.bind) {
Function.prototype.bind =
function
(obj) {
var
self =
this
,
boundArgs = arguments;
return
function
() {
var
args = [],
i;
for
(i = 1; i < boundArgs.length; i++) args.push(boundArgs[i]);
for
(i = 1; i < arguments.length; i++) args.push(arguments[i]);
return
self.apply(obj, args);
}
}
}
|
仿ECMAScript5中Array.map()函数
var
map = Array.prototype.map ?
function
(ary, fn) {
return
ary.map(fn);
} :
function
(ary, fn) {
var
results = [];
for
(
var
i = 0, len = ary.length; i < len; i++) {
if
(i
in
ary) {
results[i] = fn.call(
null
, ary[i], i, ary);
}
}
return
results;
}
|
数组去重
Array.prototype.unique =
function
unique() {
var
obj = {};
for
(
var
i = 0; i <
this
.length; i++) {
var
current =
this
[i];
if
(obj[current] === current) {
current =
this
[
this
.length - 1];
this
.length--;
i--;
continue
;
}
obj[current] = current
}
obj =
null
;
return
this
;
}
|
冒泡排序
Array.prototype.bubbleSort =
function
bubbleSort() {
var
temp =
null
;
for
(
var
i = 0; i <
this
.length - 1; i++) {
for
(
var
k = 0; k <
this
.length - 1 - i; k++) {
if
(
this
[k] >
this
[k + 1]) {
temp =
this
[k];
this
[k] =
this
[k + 1];
this
[k + 1] = temp;
}
}
}
return
this
;
}
|
仿String.match()方法实现
String.prototype.mymatch =
function
(reg) {
var
ary = [];
var
res = reg.exec(
this
);
while
(res) {
ary.push(res[0]);
res = reg.exec(
this
);
}
return
ary;
}
|
返回元素的第n层祖先元素
/**
*返回元素ele的第n层祖先元素,如果不存在此类祖先或祖先不是Element,
*(例如Document或者DocumentFragment)则返回null
*如果n为0,则返回e本身。如果n为1(或省略),则返回其父元素
*如果n为2,则返回其祖父元素,依次类推
*/
function
parent(ele, n) {
if
(n === nudefined) n = 1;
while
(n-- && ele) {
ele = ele.parentNode;
}
if
(!ele || ele.nodeTope !== 1)
return
null
;
return
ele;
}
|
返回元素的第n个兄弟元素
/**
*返回元素ele的第n个兄弟元素
*如果n为正,返回后续的第n个兄弟元素
*如果n为负,返回前面的第n个兄弟元素
*如果n为零,返回ele本身
*/
function
sibling(ele, n) {
while
(ele && n !== 0) {
//如果ele未定义,即刻返回它
if
(n > 0) {
//查找后续的兄弟元素
if
(ele.nextElementSibling) {
ele = ele.nextElementSibling;
}
else
{
for
(ele = ele.nextSibling; ele && ele.nodeType !== 1; ele = ele.nextSibling)
/*空循环*/
;
}
n--;
}
else
{
//查找前面的兄弟元素
if
(ele.previousElementSibing) {
ele = ele.previousElementSibling;
}
else
{
for
(ele = ele.previousSibling; ele && ele.nodeType !== 1; ele = ele.previousSibling)
/*空循环*/
;
}
n++;
}
}
return
ele;
}
|
返回元素的第n个子代元素
/**
*返回元素ele的第n代子元素,如果不存在则为null
*负值n代表从后往前计数。0表示第一个子元素,而-1代表最后一个,-2代表倒数第二个,依次类推
*/
function
child(ele, n) {
if
(ele.children) {
//如果children数组存在
if
(n < 0) n += ele.children.length;
//转换负的n为数组索引
if
(n < 0)
return
null
;
//如果它仍然为负,说明没有子元素
return
ele.children[n];
//返回指定的子元素
}
//如果e没有children数组,找到第一个子元素并向前数,或找到最后一个子元素并往回数
if
(n >= 0) {
//n非负:从第一个子元素向前数
//找到元素e的第一个子元素
if
(ele.firstElementChild) {
ele = ele.firstElementChild;
}
else
{
for
(ele = ele.firstChild; ele && ele.nodeType !== 1; ele = ele.nextSibling)
/*空循环*/
;
}
return
sibling(ele, n);
//返回第一个子元素的第n个兄弟元素
}
else
{
//n为负:从最后一个子元素往回数
if
(ele.lastElementChild) {
ele = ele.lastElementChild;
}
else
{
for
(ele = ele.lastChild; ele && ele.nodeType !== 1; ele = ele.previousSibling)
/*空循环*/
;
}
return
sibling(ele, n + 1);
//+1来转化最后1个子元素为最后1个兄弟元素
}
}
|
表格的行排序
//根据指定表格每行第n个单元格的值,对第一个<tbody>中的行进行排序
//如果存在comparator函数则使用它,否则按字母表顺序比较
function
sortrows(table, n, comparator) {
var
tbody = table.tBodies[0];
//第一个<tbody>,可能是隐式创建的
var
rows = tbody.getElementsByTagName(
"tr"
);
//tbody中的所有行
rows = Array.prototype.slice.call(rows, 0);
//真实数组中的快照
//基于第n个<td>元素的值对行排序
rows.sort(
function
(row1, row2) {
var
cell1 = row1.getElementsByTagName(
"td"
)[n];
//获得第n个单元格
var
cell2 = row2.getElementsByTagName(
"td"
)[n];
//两行都是
var
val1 = cell1.textContent || cell1.innerText;
//获得文本内容
var
val2 = cell2.textContent || cell2.innerText;
//两单元格都是
if
(comparator)
return
comparator(val1, val2);
//进行比较
if
(val1 < val2) {
return
-1;
}
else
if
(val1 > val2) {
return
1;
}
else
{
return
0;
}
});
//在tbody中按它们的顺序把行添加到最后
//这将自动把它们从当前位置移走,故没必要预先删除它们
//如果<tbody>还包含了除了<tr>的任何其他元素,这些节点将会悬浮到顶部位置
for
(
var
i = 0; i < rows.length; i++) tbody.appendChild(rows[i]);
}
//查找表格的<th>元素(假设只有一行),让它们可单击,
//以便单击列标题,按该列对行排序
function
makeSortable(table) {
var
headers = table.getElementsByTagName(
"th"
);
for
(
var
i = 0; i < headers.length; i++) {
(
function
(n) {
//嵌套函数来创建本地作用域
headers[i].onclick =
function
() {
sortrows(table, n);
};
}(i));
//将i的值赋给局部变量n
}
}
|
生成目录表
/**
*
*这个模块注册一个可在页面加载完成后自动运行的匿名函数。当执行这个函数时会去文档中查找
*id为"TOC"的元素。如果这个元素不存在,就创建一个元素
*
*生成的TOC目录应当具有自己的CSS样式。整个目录区域的样式className设置为"TOCEntry"
*同样我们为不同层级的目录标题定义不同的样式。<h1>标签生成的标题
*className为"TOCLevel1",<h2>标签生成的标题className为"TOCLevel2",以此类推
*段编号的样式为"TOCSectNum"
*
*完整的CSS样式代码如下:
*
*#TOC{border:solid black 1px;margin:10px;padding:10px;}
*.TOCEntry{font-family:sans-serif;}
*.TOCEntry a{text-decoration:none;}
*.TOCLevel1{font-size:16pt;font-weight:bold;}
*.TOCLevel2{font-size:12pt;margin-left:.5in;}
*.TOCSectNum:after{content:":";}
*
*这段代码的最后一行表示每个段编号之后都有一个冒号和空格符。要想隐藏段编号,
*请使用这行代码:
*.TOCSectNum{display:none}
*
**/
(
function
() {
//匿名函数定义了一个局部作用域
//查找TOC容器元素
//如果不存在,则在文档开头处创建一个
var
toc = document.getElementById(
"TOC"
);
if
(!toc) {
toc = document.createElement(
"div"
);
toc.id =
"TOC"
;
document.body.insertBefore(toc, document.body.firstChild);
}
//查找所有的标题元素
var
headings;
if
(document.querySelectorAll)
//我们是否能用这个简单的方法?
headings = document.querySelectorAll(
"h1,h2,h3,h4,h5,h6"
);
else
//否则,查找方法稍微麻烦一些
headings = findHeadings(document.body, []);
//递归遍历document的body,查找标题元素
function
findHeadings(root, sects) {
for
(
var
c = root.firstChild; c !=
null
; c = c.nextSibling) {
if
(c.nodeType !== 1)
continue
;
if
(c.tagName.length == 2 && c.tagName.charAt(0) ==
"H"
)
sects.push(c);
else
findHeadings(c, sects);
}
return
sects;
}
//初始化一个数组来保持跟踪章节号
var
sectionNumbers = [0, 0, 0, 0, 0, 0];
//现在,循环已找到的标题元素
for
(
var
h = 0; h < headings.length; h++) {
var
heading = headings[h];
//跳过在TOC容器中的标题元素
if
(heading.parentNode == toc)
continue
;
//判定标题的级别
var
level = parseInt(heading.tagName.charAt(1));
if
(isNaN(level) || level < 1 || level > 6)
continue
;
//对于该标题级别增加sectionNumbers对应的数字
//重置所有标题比它级别低的数字为零
sectionNumbers[level - 1]++;
for
(
var
i = level; i < 6; i++) sectionNumbers[i] = 0;
//现在,将所有标题级别的章节号组合产生一个章节号, 如2 .3 .1
var
sectionNumber = sectionNumbers.slice(0, level).join(
"."
)
//为标题级别增加章节号
//把数字放在<span>中,使得其可以用样式修饰
var
span = document.createElement(
"span"
);
span.className =
"TOCSectNum"
;
span.innerHTML = sectionNumber;
heading.insertBefore(span, heading.firstChild);
//用命名的锚点将标题包起来,以便为它增加链接
var
anchor = document.createElement(
"a"
);
anchor.name =
"TOC"
+ sectionNumber;
heading.parentNode.insertBefore(anchor, heading);
anchor.appendChild(heading);
//现在为该节创建一个链接
var
link = document.createElement(
"a"
);
link.href =
"#TOC"
+ sectionNumber;
//链接的目标地址
link.innerHTML = heading.innerHTML;
//链接文本与实际标题一致
//将链接放在一个div中,div用基于级别名字的样式修饰
var
entry = document.createElement(
"div"
);
entry.className =
"TOCEntry TOCLevel"
+ level;
entry.appendChild(link);
//该div添加到TOC容器中
toc.appendChild(entry);
}
}());
|
从URL解析参数
/*
*这个函数用来解析来自URL的查询串中的name=value参数对
*它将name=value对存储在一个对象的属性中,并返回该对象
*这样来使用它
*
*var args=urlArgs();//从URL中解析参数
*var q=args.q||"";//如果参数定义了的话就使用参数;否则使用一个默认值
*var n=args.n?parseInt(args.n):10;
*/
function
urlArgs() {
var
args = {};
//定义一个空对象
var
query = location.search.substring(1);
//查找到查询串,并去掉'?'
var
pairs = query.split(
"&"
);
//根据"&"符号将查询字符串分隔开
for
(
var
i = 0; i < pairs.length; i++) {
//对于每个片段
var
pos = pairs[i].indexOf(
'='
);
//查找"name=value"
if
(pos == -1)
continue
;
//如果没有找到的话,就跳过
var
name = pairs[i].substring(0, pos);
//提取name
var
value = pairs[i].substring(pos + 1);
//提取value
value = decodeURIComponent(value);
//对value进行解码
args[name] = value;
//存储为属性
}
return
args;
//返回解析后的参数
}
|
获取纯文本的元素内容
/**
*一个参数,返回元素的textContent或innerText
*两个参数,用value参数的值设置元素的textContent或innerText
*/
function
textContent(element, value) {
var
content = element.textContent;
//检测textContent是否有定义
if
(value === undefined) {
//没传递value,因此返回当前文本
if
(content !== undefined) {
return
content;
}
else
{
return
element.innerText;
}
}
else
{
//传递了value,因此设置文本
if
(content !== undefined) {
element.textContent = value;
}
else
{
element.innerText = value;
}
}
}
|
手写一个JSONP实现
//根据指定的URL发送一个JSONP请求
//然后把解析得到的响应数据传递给回调函数
//在URL中添加一个名为jsonp的查询参数,用于指定该请求的回调函数的名称
function
getJSONP(url, callback) {
//为本次请求创建一个唯一的回调函数名称
var
cbnum =
"cb"
+ getJSONP.counter++;
//每次自增计数器
var
cbname =
"getJSONP."
+ cbnum;
//作为JSONP函数的属性
//将回调函数名称以表单编码的形式添加到URL的查询部分中
//使用jsonp作为参数名,一些支持JSONP的服务
//可能使用其他的参数名,比如callback
if
(url.indexOf(
"?"
) === -1)
//URL没有查询部分
url +=
"?jsonp="
+ cbname;
//作为查询部分添加参数
else
//否则
url +=
"&jsonp="
+ cbname;
//作为新的参数添加它
//创建script元素用于发送请求
var
script = document.createElement(
"script"
);
//定义将被脚本执行的回调函数
getJSONP[cbnum] =
function
(response) {
try
{
callback(response);
//处理响应数据
} finally {
//即使回调函数或响应抛出错误
delete
getJSONP[cbnum];
//删除该函数
script.parentNode.removeChild(script);
//移除script元素
}
};
//立即触发HTTP请求
script.src = url;
//设置脚本的URL
document.body.appendChild(script);
//把它添加到文档中
}
getJSONP.counter = 0;
//用于创建唯一回调函数名称的计数器
|
插入节点
//将child节点插入到parent中,使其成为第n个子节点
function
insertAt(parent, child, n) {
if
(n < 0 || n > parent.childNodes.length) {
throw
new
Error(
"invalid index"
);
}
else
if
(n == parent.childNodes.length) {
parent.appendChild(child);
}
else
{
parent.insertBefore(child, parent.childNodes[n]);
}
}
|
使用innerHTML实现outerHTML属性
//为那些不支持它的浏览器实现outerHTML属性
//假设浏览器确实支持innerHTML,并有个可扩展的Element.prototype,
//并且可以定义getter和setter
(
function
() {
//如果outerHTML存在,则直接返回
if
(document.createElement(
"div"
).outerHTML)
return
;
//返回this所引用元素的外部HTML
function
outerHTMLGetter() {
var
container = document.createElement(
"div"
);
//虚拟元素
container.appendChild(
this
.cloneNode(
true
));
//复制到该虚拟节点
return
container.innerHTML;
//返回虚拟节点的innerHTML
}
//用指定的值设置元素的外部HTML
function
outerHTMLSetter(value) {
//创建一个虚拟元素,设置其内容为指定的值
var
container = document.createElement(
"div"
);
container.innerHTML = value;
//将虚拟元素中的节点全部移动到文档中
while
(container.firstChild)
//循环,直到container没有子节点为止
this
.parentNode.insertBefore(container.firstChild,
this
);
//删除所被取代的节点
this
.parentNode.removeChild(
this
);
}
//现在使用这两个函数作为所有Element对象的outerHTML属性的getter和setter
//如果它存在则使用ES5的Object.defineProperty()方法,
//否则,退而求其次,使用__defineGetter__()和__defineSetter__()
if
(Object.defineProperty) {
Object.defineProperty(Element.prototype,
"outerHTML"
, {
get: outerHTMLGetter,
set: outerHTMLSetter,
enumerable:
false
,
configurable:
true
});
}
else
{
Element.prototype.__defineGetter__(
"outerHTML"
, outerHTMLGetter);
Element.prototype.__defineSetter__(
"outerHTML"
, outerHTMLSetter);
}
}());
|
倒序排列子节点
//倒序排列节点n的子节点
function
reverse(n) {
//创建一个DocumentFragment作为临时容器
var
f = document.createDocumentFragment();
//从后至前循环子节点,将每一个子节点移动到文档片段中
//n的最后一个节点变成f的第一个节点,反之亦然
//注意,给f添加一个节点,该节点自动地会从n中删除
while
(n.lastChild) f.appendChild(n.lastChild);
//最后,把f的所有子节点一次性全部移回n中
n.appendChild(f);
}
|
查询窗口滚动条的位置
//以一个对象的x和y属性的方式返回滚动条的偏移量
function
getScrollOffsets(w) {
//使用指定的窗口,如果不带参数则使用当前窗口
w = w || window;
//除了IE 8及更早的版本以外,其他浏览器都能用
if
(w.pageXOffset !=
null
)
return
{
x: w.pageXOffset,
y: w.pageYOffset
};
//对标准模式下的IE(或任何浏览器)
var
d = w.document;
if
(document.compatMode ==
"CSS1Compat"
)
return
{
x: d.documentElement.scrollLeft,
y: d.documentElement.scrollTop
};
//对怪异模式下的浏览器
return
{
x: d.body.scrollLeft,
y: d.body.scrollTop
};
}
|
查询窗口的视口尺寸
//作为一个对象的w和h属性返回视口的尺寸
function
getViewportSize(w) {
//使用指定的窗口,如果不带参数则使用当前窗口
w = w || window;
//除了IE 8及更早的版本以外,其他浏览器都能用
if
(w.innerWidth !=
null
)
return
{
w: w.innerWidth,
h: w.innerHeight
};
//对标准模式下的IE(或任何浏览器)
var
d = w.document;
if
(document.compatMode ==
"CSS1Compat"
)
return
{
w: d.documentElement.clientWidth,
h: d.documentElement.clientHeight
};
//对怪异模式下的浏览器
return
{
w: d.body.clientWidth,
h: d.body.clientWidth
};
}
|
返回函数的名字
Function.prototype.getName =
function
() {
return
this
.name ||
this
.toString().match(/
function
\s*(\w*)\s*\(/)[1];
}
|
原生JS实现CSS动画1
//将e转化为相对定位的元素,使之左右"震动"
//第一个参数可以是元素对象或者元素的id
//如果第二个参数是函数,以e为参数,它将在动画结束时调用
//第三个参数指定e震动的距离,默认是5像素
//第四个参数指定震动多久,默认是500毫秒
function
shake(e, oncomplete, distance, time) {
//句柄参数
if
(
typeof
e ===
"string"
) e = document.getElementById(e);
if
(!time) time = 500;
if
(!distance) distance = 5;
var
originalStyle = e.style.cssText;
//保存e的原始style
e.style.position =
"relative"
;
//使e相对定位
var
start = (
new
Date()).getTime();
//注意,动画的开始时间
animate();
//动画开始
//函数检查消耗的时间,并更新e的位置
//如果动画完成,它将e还原为原始状态
//否则,它更新e的位置,安排它自身重新运行
function
animate() {
var
now = (
new
Date()).getTime();
//得到当前时间
var
elapsed = now - start;
//从开始以来消耗了多长时间?
var
fraction = elapsed / time;
//是总时间的几分之几?
if
(fraction < 1) {
//如果动画未完成
//作为动画完成比例的函数,计算e的x位置
//使用正弦函数将完成比例乘以4pi
//所以,它来回往复两次
var
x = distance * Math.sin(fraction * 4 * Math.PI);
e.style.left = x +
"px"
;
//在25毫秒后或在总时间的最后尝试再次运行函数
//目的是为了产生每秒40帧的动画
setTimeout(animate, Math.min(25, time - elapsed));
}
else
{
//否则,动画完成
e.style.cssText = originalStyle
//恢复原始样式
if
(oncomplete) oncomplete(e);
//调用完成后的回调函数
}
}
}
|
原生JS实现CSS动画2
function
fadeOut(e, oncomplete, time) {
if
(
typeof
e ===
"string"
) e = document.getElementById(e);
if
(!time) time = 500;
//使用Math.sqrt作为一个简单的“缓动函数”来创建动画
//精巧的非线性:一开始淡出得比较快,然后缓慢了一些
var
ease = Math.sqrt;
var
start = (
new
Date()).getTime();
//注意:动画开始的时间
animate();
//动画开始
function
animate() {
var
elapsed = (
new
Date()).getTime() - start;
//消耗的时间
var
fraction = elapsed / time;
//总时间的几分之几?
if
(fraction < 1) {
//如果动画未完成
var
opacity = 1 - ease(fraction);
//计算元素的不透明度
e.style.opacity = String(opacity);
//设置在e上
setTimeout(animate,
//调度下一帧
Math.min(25, time - elapsed));
}
else
{
//否则,动画完成
e.style.opacity =
"0"
;
//使e完全透明
if
(oncomplete) oncomplete(e);
//调用完成后的回调函数
}
}
}
|
仿HTML5的classList属性
/*
*如果e有classList属性则返回它。否则,返回一个为e模拟DOMTokenList API的对象
*返回的对象有contains()、add()、remove()、toggle()和toString()等方法
*来检测和修改元素e的类集合。如果classList属性是原生支持的,
*返回的类数组对象有length和数组索引属性。模拟DOMTokenList不是类数组对象,
*但是它有一个toArray()方法来返回一个含元素类名的纯数组快照
*/
function
classList(e) {
if
(e.classList)
return
e.classList;
//如果e.classList存在,则返回它
else
return
new
CSSClassList(e);
//否则,就伪造一个
}
//CSSClassList是一个模拟DOMTokenList的JavaScript类
function
CSSClassList(e) {
this
.e = e;
}
//如果e.className包含类名c则返回true否则返回false
CSSClassList.prototype.contains =
function
(c) {
//检查c是否是合法的类名
if
(c.length === 0 || c.indexOf(
" "
) != -1)
throw
new
Error(
"Invalid class name:'"
+ c +
"'"
);
//首先是常规检查
var
classes =
this
.e.className;
if
(!classes)
return
false
;
//e不含类名
if
(classes === c)
return
true
;
//e有一个完全匹配的类名
//否则,把c自身看做一个单词,利用正则表达式搜索c
//\b在正则表达式里代表单词的边界
return
classes.search(
"\\b"
+ c +
"\\b"
) != -1;
};
//如果c不存在,将c添加到e.className中
CSSClassList.prototype.add =
function
(c) {
if
(
this
.contains(c))
return
;
//如果存在,什么都不做
var
classes =
this
.e.className;
if
(classes && classes[classes.length - 1] !=
""
)
c =
""
+ c;
//如果需要加一个空格
this
.e.className += c;
//将c添加到className中
};
//将在e.className中出现的所有c都删除
CSSClassList.prototype.remove =
function
(c) {
//检查c是否是合法的类名
if
(c.length === 0 || c.indexOf(
" "
) != -1)
throw
new
Error(
"Invalid class name:'"
+ c +
"'"
);
//将所有作为单词的c和多余的尾随空格全部删除
var
pattern =
new
RegExp(
"\\b"
+ c +
"\\b\\s*"
,
"g"
);
this
.e.className =
this
.e.className.replace(pattern,
""
);
};
//如果c不存在,将c添加到e.className中,并返回true
//否则,将在e.className中出现的所有c都删除,并返回false
CSSClassList.prototype.toggle =
function
(c) {
if
(
this
.contains(c)) {
//如果e.className包含c
this
.remove(c);
//删除它
return
false
;
}
else
{
//否则
this
.add(c);
//添加它
return
true
;
}
};
//返回e.className本身
CSSClassList.prototype.toString =
function
() {
return
this
.e.className;
};
//返回在e.className中的类名
CSSClassList.prototype.toArray =
function
() {
return
this
.e.className.match(/\b\w+\b/g) || [];
};
|
查询纯文本形式的内容
/**
*一个参数,返回元素的textContent或innerText
*两个参数,用value参数的值设置元素的textContent或innerText
*/
function
textContent(element, value) {
var
content = element.textContent;
//检测textContent是否有定义
if
(value === undefined) {
//没传递value,因此返回当前文本
if
(content !== undefined)
return
content;
else
return
element.innerText;
}
else
{
//传递了value,因此设置文本
if
(content !== undefined) element.textContent = value;
else
element.innerText = value;
}
}
|
textContent属性在除了IE的所有当前的浏览器中都支持。在IE中,可以用Element的innerText属性来代替。
查找元素的后代中节点中的所有Text节点
//返回元素e的纯文本内容,递归进入其子元素
//该方法的效果类似于textContent属性
function
textContent(e) {
var
child, type, s =
""
;
//s保存所有子节点的文本
for
(child = e.firstChild; child !=
null
; child = child.nextSibling) {
type = child.nodeType;
if
(type === 3 || type === 4)
//Text和CDATASection节点
s += child.nodeValue;
else
if
(type === 1)
//递归Element节点
s += textContent(child);
}
return
s;
}
|
使用innerHTML实现insertAdjacentHTML()
//本模块为不支持它的浏览器定义了Element.insertAdjacentHTML
//还定义了一些可移植的HTML插入函数,它们的名字比insertAdjacentHTML更符合逻辑:
//Insert.before()、Insert.after()、Insert.atStart()和Insert.atEnd()
var
Insert = (
function
() {
//如果元素有原生的insertAdjacentHTML,
//在4个函数名更明了的HTML插入函数中使用它
if
(document.createElement(
"div"
).insertAdjacentHTML) {
return
{
before:
function
(e, h) {
e.insertAdjacentHTML(
"beforebegin"
, h);
},
after:
function
(e, h) {
e.insertAdjacentHTML(
"afterend"
, h);
},
atStart:
function
(e, h) {
e.insertAdjacentHTML(
"afterbegin"
, h);
},
atEnd:
function
(e, h) {
e.insertAdjacentHTML(
"beforeend"
, h);
}
};
}
//否则,无原生的insertAdjacentHTML
//实现同样的4个插入函数,并使用它们来定义insertAdjacentHTML
//首先,定义一个工具函数,传入HTML字符串,返回一个DocumentFragment,
//它包含了解析后的HTML的表示
function
fragment(html) {
var
elt = document.createElement(
"div"
);
//创建空元素
var
frag = document.createDocumentFragment();
//创建空文档片段
elt.innerHTML = html;
//设置元素内容
while
(elt.firstChild)
//移动所有的节点
frag.appendChild(elt.firstChild);
//从elt到frag
return
frag;
//然后返回frag
}
var
Insert = {
before:
function
(elt, html) {
elt.parentNode.insertBefore(fragment(html), elt);
},
after:
function
(elt, html) {
elt.parentNode.insertBefore(fragment(html), elt.nextSibling);
},
atStart:
function
(elt, html) {
elt.insertBefore(fragment(html), elt.firstChild);
},
atEnd:
function
(elt, html) {
elt.appendChild(fragment(html));
}
};
//基于以上函数实现insertAdjacentHTML
Element.prototype.insertAdjacentHTML =
function
(pos, html) {
switch
(pos.toLowerCase()) {
case
"beforebegin"
:
return
Insert.before(
this
, html);
case
"afterend"
:
return
Insert.after(
this
, html);
case
"afterbegin"
:
return
Insert.atStart(
this
, html);
case
"beforeend"
:
return
Insert.atEnd(
this
, html);
}
};
return
Insert;
//最后返回4个插入函数
}());
|
拖拽
/**
*Drag.js:拖动绝对定位的HTML元素
*
*这个模块定义了一个drag()函数,它用于mousedown事件处理程序的调用
*随后的mousemove事件将移动指定元素,mouseup事件将终止拖动
*这些实现能同标准和IE两种事件模型一起工作
*
*参数:
*
*elementToDrag:接收mousedown事件的元素或某些包含元素
*它必须是定位的元素,元素的样式必须是行内样式
*它的style.left和style.top值将随着用户的拖动而改变
*
*event:mousedown事件对象
**/
function
drag(elementToDrag, event) {
//初始鼠标位置,转换为文档坐标
var
startX = event.clientX;
var
startY = event.clientY;
//在文档坐标下,待拖动元素的初始位置
//因为elementToDrag是绝对定位的,
//所以我们可以假设它的offsetParent就是文档的body元素
var
origX = parseFloat(elementToDrag.style.left);
var
origY = parseFloat(elementToDrag.style.top);
//计算mousedown事件和元素左上角之间的距离
//我们将它另存为鼠标移动的距离
if
(document.addEventListener) {
//标准事件模型
//在document对象上注册捕获事件处理程序
document.addEventListener(
"mousemove"
, moveHandler,
true
);
document.addEventListener(
"mouseup"
, upHandler,
true
);
}
else
if
(document.attachEvent) {
//用于IE5~8的IE事件模型
//在IE事件模型中,
//捕获事件是通过调用元素上的setCapture()捕获它们
elementToDrag.setCapture();
elementToDrag.attachEvent(
"onmousemove"
, moveHandler);
elementToDrag.attachEvent(
"onmouseup"
, upHandler);
//作为mouseup事件看待鼠标捕获的丢失
elementToDrag.attachEvent(
"onlosecapture"
, upHandler);
}
//我们处理了这个事件,不让任何其他元素看到它
if
(event.stopPropagation) event.stopPropagation();
//标准模型
else
event.cancelBubble =
true
;
//IE
//现在阻止任何默认操作
if
(event.preventDefault) event.preventDefault();
//标准模型
else
event.returnValue =
false
;
//IE
/**
* 当元素正在被拖动时, 这就是捕获mousemove事件的处理程序
*它用于移动这个元素
**/
function
moveHandler(e) {
if
(!e) e = window.event;
//IE事件模型
//移动这个元素到当前鼠标位置,
//通过滚动条的位置和初始单击的偏移量来调整
var
targetLeft = e.clientX - startX + origX;
var
targetTop = e.clientY - startY + origY;
var
minLeft = 0;
var
minTop = 0;
var
maxLeft = (document.documentElement.clientWidth || document.body.clientWidth) - elementToDrag.offsetWidth;
var
maxTop = (document.documentElement.clientHeight || document.body.clientHeight) - elementToDrag.offsetHeight;
targetLeft = targetLeft > maxLeft ? maxLeft : (targetLeft < minLeft ? minLeft : targetLeft);
targetTop = targetTop > maxTop ? maxTop : (targetTop < minTop ? minTop : targetTop);
elementToDrag.style.left = targetLeft +
"px"
;
elementToDrag.style.top = targetTop +
"px"
;
if
(e.stopPropagation) e.stopPropagation();
//标准
else
e.cancelBubble =
true
;
//IE
}
/**
*这是捕获在拖动结束时发生的最终mouseup事件的处理程序
**/
function
upHandler(e) {
if
(!e) e = window.event;
//IE事件模型
//注销捕获事件处理程序
if
(document.removeEventListener) {
//DOM事件模型
document.removeEventListener(
"mouseup"
, upHandler,
true
);
document.removeEventListener(
"mousemove"
, moveHandler,
true
);
}
else
if
(document.detachEvent) {
//IE 5+事件模型
elementToDrag.detachEvent(
"onlosecapture"
, upHandler);
elementToDrag.detachEvent(
"onmouseup"
, upHandler);
elementToDrag.detachEvent(
"onmousemove"
, moveHandler);
elementToDrag.releaseCapture();
}
//并且不让事件进一步传播
if
(e.stopPropagation) e.stopPropagation();
//标准模型
else
e.cancelBubble =
true
;
//IE
}
}
|