1.前几个DOM操作的自己测试过,后面那些都是有时候用到的,没测试,有问题的希望提出来,还没完全封装完,后期还会更新这个工具函数。
(function (window) {
var Tools = {
getElem: getElem,//获取元素
getFirst: getFirst,//获取元素第一个子元素
getPre: getPre,//获取元素的前一个兄弟节点
getNext: getNext,//获取元素的下一个兄弟节点
getLast: getLast,//获取元素的最后一个子节点
getStyle: getStyle,//获取元素的外联计算样式
addClass: addClass,//给元素添加类
arrIndexOf: arrIndexOf,//数组查找
removeClass: removeClass,//移除一个类
setScroll: setScroll,//滚动条高度和宽度的获取
getClientSize: getClientSize,//可视区域的大小
getDatetoString: getDatetoString,//返回指定格式的日期
browserRedirect: browserRedirect,//判断设备
getUrlParams: getUrlParams,//获取path的值,例如:name = "Tom"
//eventTools:eventTools,//对事件的封装
animate: animate,//轮播图动画实现函数
setSize: setSize,//响应式设置rem
mouseDrop: mouseDrop,//鼠标拖拽事件
getWH: getWH,//获取元素不带单位的宽度和高度
setPosition: setPosition,//对轮播图进行封装
ajax: ajax,//对ajax封装
};
//通过标签名,类名,标签名获取元素
function getElem(selector, parent) {
parent = parent || document;
var firstChar = selector.charAt(0);
if (firstChar === "#") {
return document.getElementById(selector.substring(1));
} else if (firstChar === ".") {
var allEles = parent.getElementsByTagName("*");
var arr = [];
for (var i = 0; i < allEles.length; i++) {
var arrClassName = allEles[i].className.split(" ");
for (var j = 0; j < arrClassName.length; j++) {
if (arrClassName[j] == selector.slice(1)) {
arr.push(allEles[i]);
break;
}
}
}
return arr;
} else {
return parent.getElementsByTagName(selector);
}
}
//获取元素的第一个子节点
function getFirst(ele) {
var firstEle = ele.firstElementChild || ele.firstChild;
if (!firstEle || firstEle.nodeType != 1) {
return null;
} else {
return firstEle;
}
}
//获取前一个兄弟节点
function getPre(ele) {
var prevEle = ele.previousElementSibling || ele.previousSibling;
if (!prevEle || prevEle.nodeType != 1) {
return null;
} else {
return prevEle;
}
}
//获取后一个兄弟节点
function getNext(ele) {
var nextEle = ele.nextElementSibling || ele.nextSibling;
if (!nextEle || nextEle.nodeType != 1) {
return null;
} else {
return nextEle;
}
}
//获取最后一个元素
function getLast(ele) {
var lastEle = ele.lastElementChild || ele.lastChild;
if (!lastEle || lastEle.nodeType != 1) {
return null;
} else {
return lastEle;
}
}
//获取元素外联样式
function getStyle(obj, attr) {
return obj.currentStyle ? obj.currentStyle[attr] : getComputedStyle(obj)[attr];
}
//获取元素的实际宽度和高度
function getWH(obj) {
return {
width: obj.offsetWidth,
height: obj.offsetHeight
}
}
//封装了一个添加类的函数
function addClass(obj, myClass) {
//如果没有类 使用直接添加类的方式
if (obj.className == "") {
obj.className = myClass;
} else {
//进来里面 说明 它原来有类
// 将它的类 转化成数组
var arrClassName = obj.className.split(" ");
//调用数组的查找方法 返回索引
var _index = arrIndexOf(arrClassName, myClass);
// 判断索引是否为-1 说明没找到 则加进去
if (_index == -1) {
obj.className += " " + myClass;
}
}
}
// 用于数组查找的函数
function arrIndexOf(arr, myClass) {
//循环数组 进行比较 如果找到 返回对应下标
for (var i = 0; i < arr.length; i++) {
if (arr[i] === myClass) {
return i;
}
}
// 经过循环 之后说明没找到 则返回-1
return -1;
}
//封装一个移除class的函数
function removeClass(obj, myClass) {
if (obj.className != "") {
// 将标签上的class 转成数组
var arrClassName = obj.className.split(" ");
// 调用数组查找方法 返回一个索引
var _index = arrIndexOf(arrClassName, myClass);//[xixi, gaga, haha, hehe, jiji]
if (_index != -1) {
// 如果不等于-1
// 将类的数组 通过删除方法去删除那一项
arrClassName.splice(_index, 1);
// 将删除那一项之后的数组重新通过join方法 转换回字符串 赋给标签的class
obj.className = arrClassName.join(" ");
}
}
}
//滚动条高度和宽度的获取
function setScroll() {
return {
scrollTop: document.body.scrollTop ||
window.pageYOffset ||
document.documentElement.scrollTop || 0,
scrollLeft: document.body.scrollLeft ||
window.pageXOffset ||
document.documentElement.scrollLeft || 0
}
}
//可视区域的大小
function getClientSize() {
return {
clientX: window.innerWidth ||
document.body.clientWidth ||
document.documentElement.clientWidth || 0,
clientY: window.innerHeight ||
document.body.clientHeight ||
document.documentElement.clientHeight || 0
}
}
// 返回指定格式的日期
function getDatetoString(date) {
var strDate;//存储日期的字符串
//获取年
var year = date.getFullYear();
//获取月
var month = date.getMonth() + 1;
//获取日
var day = date.getDate();
//获取小时
var hour = date.getHours();
//获取分钟
var minute = date.getMinutes();
//获取秒
var second = date.getSeconds();
hour = hour < 10 ? "0" + hour : hour;
minute = minute < 10 ? "0" + minute : minute;
second = second < 10 ? "0" + second : second;
//拼接
strDate = year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;//隐藏问题,关于变量声明的位置
return strDate;
}
//判断设备
function browserRedirect() {
var sUserAgent = navigator.userAgent.toLowerCase();
var bIsIpad = sUserAgent.match(/ipad/i) == "ipad";
var bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os";
var bIsMidp = sUserAgent.match(/midp/i) == "midp";
var bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";
var bIsUc = sUserAgent.match(/ucweb/i) == "ucweb";
var bIsAndroid = sUserAgent.match(/android/i) == "android";
var bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";
var bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";
/*document.writeln("您的浏览设备为:");*/
if (bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {
/* 链接到不同的网址 这个是手机的 */
window.location.href = 'http://m.jd.com'
} else {
/* 链接到不同的网址 这个是PC的 */
window.location.href = 'http://www.jd.com'
}
}
//获取path的值,例如:name = "Tom"
function getUrlParams(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;
}
//所有属性都到达目标值之后才能清理定时器
//封装 能够让 任意对象 的指定属性 变到指定值 的动画函数
function animate(obj, json, fn) {
clearInterval(obj.timer);
obj.timer = setInterval(function () {
var flag = true;
for (var k in json) {
if (k === "opacity") {//特殊处理
//var leader = parseInt(getStyle(obj, k)) || 0;
var leader = getStyle(obj, k) * 100;//1
// 0 || 1 结果是1 那么如果透明度当前的值是0 就会变成1
//所以这里不能给默认值 而且也没有必要
//透明度没有单位px 所以也不用parseInt 参与运算自动变为数字
var target = json[k] * 100;//0.5
var step = (target - leader) / 10;//0.5-1=-0.5
step = step > 0 ? Math.ceil(step) : Math.floor(step);//-1
leader = leader + step;
//obj.style[k] = leader + "px";
obj.style[k] = leader / 100;//opacity没有单位
} else if (k === "zIndex") {
obj.style.zIndex = json[k];//无需渐变 直接设置即可
} else {
var leader = parseInt(getStyle(obj, k)) || 0;
var target = json[k];
var step = (target - leader) / 10;
step = step > 0 ? Math.ceil(step) : Math.floor(step);
leader = leader + step;
obj.style[k] = leader + "px";
}
if (leader !== target) {
flag = false;
}
}
if (flag) {
clearInterval(obj.timer);
if (fn) {//如果有才调用
fn();//动画执行完成后执行
}
}
}, 15);
}
function getStyle(obj, attr) {
if (window.getComputedStyle) {
return window.getComputedStyle(obj, null)[attr];
} else {
return obj.currentStyle[attr];
}
}
//封装rem设置实现响应式
function setSize() {
var oHtml = document.documentElement;
// 获取屏幕的宽度
var screenWidth = oHtml.offsetWidth;
// 设计图的宽度,根据自己的设计图去填写
var uiWidth = 750;
// 自己设定的html的font值
var fonts = 40;
var rate = uiWidth / fonts;
// 最开始的时候调用一次
getSize();
// resize的时候动态监听
window.addEventListener('resize', getSize);
function getSize() {
screenWidth = oHtml.offsetWidth;
// 如果说屏幕小于320 就限制在320对应的fontsize
// 如果说大于设计图的宽度,就限制在设计图的宽度
// 都不满足,就代表在正常的区间里面,就可以自由的动态计算
if (screenWidth <= 320) {
oHtml.style.fontSize = 320 / rate + 'px';
} else if (screenWidth >= uiWidth) {
oHtml.style.fontSize = uiWidth / rate + 'px';
} else {
// 动态设置当前屏幕对应的html的font值
oHtml.style.fontSize = screenWidth / rate + 'px';
}
}
}
//对轮播图的移动进行的一个封装
function setPosition(obj, target, num) {
clearInterval(obj.timer);
obj.timer = setInterval(function () {
var leader = obj.offsetLeft,
step = num;
step = obj.offsetLeft < target ? step : -step;
if (Math.abs(obj.offsetLeft - target) > Math.abs(step)) {
leader = leader + step;
obj.style.left = leader + "px";
} else {
// leader = leader + step;
obj.style.left = target + "px";
clearInterval(obj.timer);
}
}, 15);
}
//鼠标拖拽事件
function mouseDrop(argus1, argus2) {//参数1,是整个被拖拽移动的元素,参数2是拖拽区域
//鼠标在 拖动条上按下的时候可以拖动 鼠标移动的时候 获取鼠标的位置 整个盒子跟着鼠标的位置走
argus2.onmousedown = function (event) {
var event = event || window.event;
var pageX = event.pageX || event.clientX + document.documentElement.scrollLeft;
var pageY = event.pageY || event.clientY + document.documentElement.scrollTop;
var spaceX = pageX - argus1.offsetLeft;
var spaceY = pageY - argus1.offsetTop;
document.onmousemove = function (event) {
var event = event || window.event;
var pageX = event.pageX || event.clientX + document.documentElement.scrollLeft;
var pageY = event.pageY || event.clientY + document.documentElement.scrollTop;
argus1.style.left = pageX - spaceX + "px";
argus1.style.top = pageY - spaceY + "px";
//清理选中的文字
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
}
};
document.onmouseup = function () {
document.onmousemove = null;
}
}
//对ajax进行封装
function ajax(options) {
var xhr = new XMLHttpRequest();
if (options.type.toLocaleString() === "get") {
options.url = options.url + "?" + params(options.data);
options.data = null
} else {
options.data = params(options.data)
}
xhr.open(options.type, options.url);
if (options.type.toLocaleString() === "post") {
xhr.setRequestHeader("Content-type','application/x-www-form-urlencoded");
}
options.beforeSend && options.beforeSend();
xhr.send(options.data);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200 || xhr.status === 304) {
var data = xhr.responseText;
options.success && options.success(data);
} else {
options.error && options.error(xhr.status);
}
options.complete && options.complete();
}
}
}
function params(options) {
var str = "";
for (var attr in options) {
str += attr + "=" + options[attr] + "&";
}
return str.slice(0, -1);
}
window.Tools = Tools;
})(window);
2.算是迭代的第二版,里面90%的代码全部实际猜测用过,后期还会用jQuery封装原理封装。
下面贴几个测试用例
第一个是封装轮播图动画函数,这里里面用到了获取元素的各种方式
(function () {
Tools.setSize();
var timer = null;
var num = 0;
var square = 0;
var oLeft = Tools.getElem(".left");
var oRight = Tools.getElem(".right");
var arrow = Tools.getElem(".arrow");
console.log(arrow[0]);
var outter = Tools.getElem(".wrap");
var WrapWidth = Tools.getWH(outter[0]).width;
console.log(WrapWidth);
var inner = Tools.getElem("ul");
var ulLis = Tools.getElem("li", inner[0]);
var oOl = Tools.getElem("ol");
var oFrag = document.createDocumentFragment();
for (var i = 0; i < ulLis.length; i++) {
var li = document.createElement("li");
if (i === 0) {
Tools.addClass(li, "active");
}
li.innerHTML = i + 1;
oFrag.appendChild(li);
}
oOl[0].appendChild(oFrag);
// 克隆第一张放在最后边
var firsClone = ulLis[0].cloneNode(true);
inner[0].appendChild(firsClone);
//重新计算一下ul的宽度
var cUlLis = Tools.getElem("li", inner[0]);
var liWidth = Tools.getWH(cUlLis[0]);
var ulWidth = (liWidth.width) * (cUlLis.length);
inner[0].style.width = ulWidth + "px";
//自动播放
timer = setInterval(playNext, 1000);
//实现鼠标划过小方块显示颜色
var oOlis = Tools.getElem("li", oOl[0]);
for (var i = 0; i < oOlis.length; i++) {
oOlis[i].index = i;
oOlis[i].onmouseover = function () {
for (var i = 0; i < oOlis.length; i++) {
oOlis[i].className = "";
}
oOlis[this.index].className = "active";
var target = -this.index * WrapWidth;
Tools.setPosition(inner[0], target, 10);
num = this.index;
square = this.index;
}
}
// 对左右箭头进行监听
oLeft[0].addEventListener("click", function () {
playPre();
});
oRight[0].addEventListener("click", function () {
playNext();
});
//单击小方块对对应相应图片,同时小方块的索引也要同步
for (var i = 0; i < oOlis.length; i++) {
oOlis[i].index = i;
oOlis[i].onclick = function () {
for (var i = 0; i < oOlis.length; i++) {
oOlis[i].className = "";
}
target = -this.index * WrapWidth;
Tools.setPosition(inner[0], target, 10);
this.className = "active";
num = this.index;
}
}
outter[0].onmouseover = function () {
clearInterval(timer);
arrow[0].style.display = "block";
};
outter[0].onmouseout = function () {
arrow[0].style.display = "none";
timer = setInterval(playNext, 1000);
};
// 封装向右点击事件
function playNext() {
if (num === cUlLis.length - 1) {
num = 0;
inner[0].style.left = 0;
}
num++;
target = -num * WrapWidth;
Tools.setPosition(inner[0], target, 10);
if (square < oOlis.length - 1) {
square++;
} else {
square = 0;
}
for (var i = 0; i < oOlis.length; i++) {
oOlis[i].className = "";
}
oOlis[square].className = "active";
}
function playPre() {
if (num === 0) {
num = cUlLis.length - 1;
target = -num * WrapWidth + "px";
inner[0].style.left = target;
}
num--;
target = -num * WrapWidth;
Tools.setPosition(inner[0], target, 10);
if (square > 0) {
square--;
} else {
square = oOlis.length - 1;
}
for (var i = 0; i < oOlis.length; i++) {
oOlis[i].className = "";
}
oOlis[square].className = "active";
}
})();
第二个,封装了ajax
(function () {
var cityData;
var select = Tools.getElem("select");
console.log(select);
Tools.ajax({
url: "city.php",
type: "get",
success: function (data) {
// console.log(data) ;
data = JSON.parse(data);
// console.log(data);
var str = template("tpl", data);
// console.log(str);
cityData = data;
var province = Tools.getElem("#province");
province.innerHTML = str;
}
});
select[0].addEventListener("change", function () {
select[1].innerHTML = '<option value="">请选择市区</option>';
select[2].innerHTML = '<option value="">请选择区域</option>';
var pro = this.value;
for (var i = 0; i < cityData.provinces.length; i++) {
// console.log(1);
if (pro === cityData.provinces[i].provinceName) {
var citys = {
city: cityData.provinces[i].citys
};
var str = template("tpl2", citys);
// console.log(str);
select[1].innerHTML = str;
}
}
});
// 由于json文件没有县所以没法实现
// 原理与选择省分之后如何渲染出市是一样的,当select[1]发生了change事件,对数据进行判断,选出该市下面的县
})();