框架说明:基于面向对象编程思想以原生js语言实现,不依赖任何第三方js库, 未引用任何外部代码片段!充分考虑不同的应用场景保证框架的灵活与健壮。
* 实现功能:实现了与jquery完全一致的架构和内部细节,设置操作内部循环可设置所有匹配节点,方法可链式调用。
* 方法分类:静态方法用于框架内部进行数据逻辑和dom预处理以及其它全局非dom操作;实例方法调用对应ui组件。
* 参数配置:根据实际需求配置不同参数灵活调用,无参数时使用默认配置。
* 选择器支持:id、class、标签、后代选择器、dom节点,实例化对象h(css选择器)。
* 兼容性:所有方法做了跨浏览器全兼容处理,兼容当前绝大部分浏览器(ie6/7/8/9/10/11,chrome,firefox,safari等)。
* 变量安全:闭包环境中,保障框架自身安变量全,避免变量冲突
* 框架性能:优化代码提升性能,尽量减少浏览器重排和重绘。如赋空值释放内存; 避免dom,bom,ecmascript间孤岛通信; 基于文档碎片进行dom操作; 冒泡委托处理集合事件......
*
* 【调用】
* 静态方法: h.method(value)
* 实例方法: h(css选择器).method(value), h(css选择器).method({key:value})
* h(sel).method({属性事件配置}), h(sel).method(组件方法,方法参数)
* 链式调用: h(css选择器).method({key:value}).method()
* dom树加载完毕执行: h(fn) 等价于jquery库中的$(fn)===$(document).ready(fn)
* 内部循环:实例方法内部对h(css选择器)匹配的节点集合进行内部循环, 可同时操作所有匹配节点
* 属性方法:opts设置组件属性事件;组件方法method(组件方法,参数);
* 手势触控:针对移动端封装了触控手势事件(tap轻敲、pinch捏合、hold长按、swipe滑动),通过e.data报告相应手势的状态。如捏合缩放系数,滑动方向,滑动距离等。
*
* author: wheng
* date: 2015-07-25
*/
* 框架源码 http://whwheng.gitee.io/csdn
*
*【结构简叙】
* 框架主体在闭包环境中保证自身安全,避免变量冲突;通过h或heng向外引用基础类。
(function(){
……框架主体……;
window.h=window.heng=h;//向外部引用基础类
})();
h(sel).method()或heng.(sel).method();//外部实例化
*内部已做了heng基础类实例化处理new heng(sel);实际使用时h(sel)即为创建对象,若sel为函数内嵌代码在形成完整dom树时立即执行。
h(fn)实现了jqyuey库中的$(fn)===$(document).ready(fn)形成完整dom树即可执行。
var h=function (sel){
if(typeof sel=="function"){ h.ready(sel) }
else{ return new heng(sel); }
};
h(function(){ h(sel).method();});//dom树加载完毕h(fn)等价于jqyuey库中的$(fn)===$(document).ready(fn)
*构造函数中实现“css选择器”获取dom节点的功能并将节点存储到nodes属性上,遵循“公共数据属性化”的规则。
function heng(sel) {
//【原选择器理】:选择器拆分数组,从document开始上级get后代作为下级祖先
this.sel = sel;
this.nodes = []; //选择器匹配的节点数组
if (typeof sel == 'string') {
if (sel.indexof(' ') != -1) {
var nodes = sel.split(' ');
var childelements = [];
var node = []; //实时祖先节点数组
for (var i = 0; i < nodes.length; i++) {
if (node.length == 0)
node.push(document);
switch (nodes[i].charat(0)) {
case '#':
childelements = []; //清除上一组值再更新
childelements.push(this.getid(nodes[i].substring(1)));
node = childelements;
break;
case '.':
childelements = [];
for (var j = 0; j < node.length; j++) {
var temps = this.getclass(nodes[i].substring(1), node[j]);
for (var k = 0; k < temps.length; k++) {
childelements.push(temps[k]);
}
}
node = childelements;
break;
default:
childelements = [];
for (var j = 0; j < node.length; j++) {
var temps = this.gettagname(nodes[i], node[j]);
for (var k = 0; k < temps.length; k++) {
childelements.push(temps[k]);
}
}
node = childelements;
}
}
this.nodes = childelements;
} else { //sel为无空格选择器字符串
switch (sel.charat(0)) {
case '#':
this.nodes.push(this.getid(sel.substring(1)));
break;
case '.':
this.nodes = this.getclass(sel.substring(1));
break;
default:
this.nodes = this.gettagname(sel);
}
}
} else if (typeof sel == 'object') { //sel为dom节点
if (sel != undefined) {
this.nodes[0] = sel;
}
}
}
*静态方法不需实例化,用于框架内部进行数据逻辑和dom预处理或其它全局非dom操作;实例方法结合dom节点完成需求,如果sel匹配组件入口为一个集合,则所有节点都可以实现方法的逻辑与功能。
//静态方法
h.method() = function (arg) {
…code…
};
//实例方法
heng.prototype.method = function (opts) {
……
var nodes = this.nodes[i]; //sel匹配的的节点数组
for (var i = 0; i < this.nodes.length; i++) {//内部循环
var op = this.nodes[i];
var aul = op.getelementsbytagname('ul');
……
}
}
*面向对象编程不可避免会出现this指向混乱的情况,所有类似问题通过闭包在函数外部声明var this=this;修正this指向。
heng.prototype.slide = function (opts) {
……
var this = this;
node = function (opts) { //node为dom节点
//原型上的方法getclass只能通过指向实例的this去引用,此时的this为node节点
this.getclass(classstring, parrent);
/*this.getclass(classstring,parrent)错误*/
}
}
*每一个实例方法都可以通过修改参数对象otps实现不同的需求,未指定的数据会使用默认值。
//模态框
heng.prototype.dialog = function (opts) {
//opts={"animate":是否开启动画,"enterdir":进入方向,"maskopa":遮罩透明度,"warncount":警告闪烁次数,"content":弹框内容}
var def = {
"animate" : false,
"enterdir" : "top",
"maskbg" : "#000000",
"maskopa" : 0.5,
"warncount" : 5,
"content" : "<h1>hello world</h1>"
};//def为默认值
opts = h.extend(def, opts);//数据合并
……
}
*
*【实例方法案例】
h("form").formcheck();一行代码完成页面所有表单验证,实现功能如下:
*对h("form")匹配到的所有表单内部任意类型的表单元素都会进行校验。
*每个表单元素在失去焦点时会各自进行独立验证。
*表单提交时内部所有元素进行统一验证,分为“逐一校验(遇到验证未通过的元素则中断后续检查)”和“一次校验(一次性检查所有元素)”两种模式,通过配置opts["submitcheck"]=true/false切换两种模式。
*无论验证通过与否,都会有相应验证类型成功或失败的提示信息,可以配置opts参数自定义提示的内容和样式信息。
*内置常用数据类型的验证,亦可通过opts["customtype"]、opts["customreg"]扩展验证类型,极大的提高了表单验证的灵活性。
heng.prototype.formcheck = function (opts) {
//opts={"customtype":"无formcheck的class值","customreg":"必须的自定义类型的正则文本","customtip":"必须的自定义类型的错误提示"}
//自定义校验类型用"formcheck-"+opts["customtype"]作为class值
var def = {
"user" : "*请输入3-16位字母数字",
"password" : "*请输入5-17位以字母开头的字符数字组合",
"email" : "*请输入正确邮箱地址",
"mobilephone" : "*请输入正确手机号",
"radiobox" : "请选择",
"ch" : "请输入中文字符",
"wrongstyle" : "font-size:12px; color:#f00;",
"passcontent" : "成功",
"passstyle" : "font-size:12px; color:#0c0;",
"submitcheck" : false //提交时逐条验证还是一次验证显示所有错误信息。默认一次校验
};
opts = h.extend(def, opts);
//datatype绑定到具体表单元素class值
var datatype = ["formcheck-user", "formcheck-password", "formcheck-email", "formcheck-mobilephone", "formcheck-ch", "formcheck-radiobox"];
var reg = {
"user" : "^[a-za-z0-9_]{3,16}$",
"password" : "^[a-za-z]+\w{5,17}$",
"email" : "^([a-za-z0-9]+[_|\_|\.]?)*[a-za-z0-9]+@([a-za-z0-9]+[_|\_|\.]?)*[a-za-z0-9]+\.[a-za-z]{2,3}$",
"mobilephone" : "^(13+\d{9})|(159+\d{8})|(153+\d{8})$",
"ch" : "[\u4e00-\u9fa5]"
};
if (opts["customtype"]) {
reg[opts["customtype"]] = opts["customreg"];
opts[opts["customtype"]] = opts["customtip"];
//需要放在formcheck-radiobox之前
datatype.splice((datatype.length - 2), 1, ("formcheck-" + opts["customtype"]));
}
var this = this;
for (var i = 0; i < this.nodes.length; i++) {
var form = this.nodes[i];
form.nodes = []; //datatype匹配的表单元素集合的超集,保存在每个form下
for (var j = 0; j < datatype.length; j++) { //表单元素超集_二维数组;
var resultarr = this.getclass(datatype[j], form);
if (resultarr.length != 0) {
resultarr.dataclass = datatype[j]; //将对应class值绑定在子数组上
form.nodes.push(resultarr);
}
}
for (var k = 0; k < form.nodes.length; k++) { //绑定blur事件
(function () {
if (form.nodes[k].dataclass != "formcheck-radiobox") {
var regoptskey = form.nodes[k].dataclass.slice(form.nodes[k].dataclass.indexof("-") + 1);
var regtest = new regexp(reg[regoptskey]);
for (var l = 0; l < form.nodes[k].length; l++) {
form.nodes[k][l].onblur = function () {
var wrongspan = this.getclass("formcheck-wrong", this.parentnode)[0];
if (!regtest.test(this.value)) {
wrongspan.innerhtml = opts[regoptskey];
wrongspan.style.csstext = def["wrongstyle"];
} else {
wrongspan.innerhtml = def["passcontent"];
wrongspan.style.csstext = def["passstyle"];
}
}
}
} else {
if (form.nodes[k].dataclass == "formcheck-radiobox") {
for (var m = 0; m < form.nodes[k].length; m++) {
var rba = form.nodes[k][m];
(function (rba) {
//每组radio或checkbox的input集合,form.nodes[k][m].radioboxarr三维数组
form.nodes[k][m].radioboxarr = form.nodes[k][m].parentnode.getelementsbytagname("input");
for (var n = 0; n < form.nodes[k][m].radioboxarr.length; n++) {
if (form.nodes[k][m].radioboxarr[n].checked) {
var statepre = true;
break;
} else {
var statepre = false;
}
form.nodes[k][m].state = statepre;
form.nodes[k][m].radioboxarr[n].onclick = function () {
for (var n = 0; n < rba.radioboxarr.length; n++) {
if (rba.radioboxarr[n].checked) {
var statepre = true;
break;
} else {
var statepre = false;
}
}
rba.state = statepre;
var wrongspan = this.getclass("formcheck-wrong", this.parentnode)[0];
if (rba.state) {
wrongspan.innerhtml = opts["passcontent"];
wrongspan.style.csstext = opts["passstyle"];
} else {
wrongspan.innerhtml = opts["radiobox"];
wrongspan.style.csstext = opts["wrongstyle"];
}
}
}
})(rba)
}
}
}
})()
}
(function (form) {
form.onsubmit = function (e) {
var e = e || window.event;
for (var k = 0; k < form.nodes.length; k++) {
var regoptskey = form.nodes[k].dataclass.slice(form.nodes[k].dataclass.indexof("-") + 1);
var regtest = new regexp(reg[regoptskey]);
for (var l = 0; l < form.nodes[k].length; l++) {
if (def["submitcheck"]) {
if (form.nodes[k].dataclass != "formcheck-radiobox") {
var wrongspan = this.getclass("formcheck-wrong", form.nodes[k][l].parentnode)[0];
if (!regtest.test(form.nodes[k][l].value)) {
wrongspan.innerhtml = opts[regoptskey];
wrongspan.style.csstext = def["wrongstyle"];
return false; //停止执行中断循环,阻止默认
} else {
wrongspan.innerhtml = def["passcontent"];
wrongspan.style.csstext = def["passstyle"];
}
} else if (form.nodes[k].dataclass == "formcheck-radiobox") {
var wrongspan = this.getclass("formcheck-wrong", form.nodes[k][l].parentnode)[0];
if (form.nodes[k][l].state) {
wrongspan.innerhtml = opts["passcontent"];
wrongspan.style.csstext = opts["passstyle"];
} else {
wrongspan.innerhtml = opts["radiobox"];
wrongspan.style.csstext = opts["wrongstyle"];
return false;
}
}
} else {
if (form.nodes[k].dataclass != "formcheck-radiobox") {
var wrongspan = this.getclass("formcheck-wrong", form.nodes[k][l].parentnode)[0];
if (!regtest.test(form.nodes[k][l].value)) {
wrongspan.innerhtml = opts[regoptskey];
wrongspan.style.csstext = opts["wrongstyle"];
e.preventdefault();
e.returnvalue = false;
} else {
wrongspan.innerhtml = opts["passcontent"];
wrongspan.style.csstext = opts["passstyle"];
}
} else if (form.nodes[k].dataclass == "formcheck-radiobox") {
var wrongspan = this.getclass("formcheck-wrong", form.nodes[k][l].parentnode)[0];
if (form.nodes[k][l].state) {
wrongspan.innerhtml = opts["passcontent"];
wrongspan.style.csstext = opts["passstyle"];
} else {
wrongspan.innerhtml = opts["radiobox"];
wrongspan.style.csstext = opts["wrongstyle"];
e.preventdefault();
e.returnvalue = false;
}
}
}
}
}
}
})(form)
}
}
*
h(".wrap").page(opts);页面容器传入必须参数page实例化即可实现分页控件:
*总页数pagesize=totaldata总数据条数÷pageitems每页数据条数(商向上取整)。必要的配置数据在初始化时由服务器传回。
*pagesize<6页码按钮基于pagesize生成,强制pagebtns等于pagesize,生成静态页码。
*6≤pagesize<10页码基于nowpage生成,强制删除上下页按钮,定义pagebtns=6,区分nowpage在开始、结尾和中间3种情形。
*pagesize≥10页码基于nowpage生成,考虑有无上下页分别就nowpage在开始、结尾和中间2*3=6种情形。
*页码序数基于等差数列通项公式【an=a1+(n-1)*d】推导并输出在按钮data-page上,a1由pagebtns、pagesize确定。
*上下页、首尾页、当前页、禁用页、省略页按钮根据不同情况重写data-page和内容,并判断启用或者禁用,对比nowpage报告当前页等。
*监听容器点击操作修改nowpage并更新所有页码,回调函数opts["cb"]接收nowpage用于数据请求,需过滤无效页码按钮避免无效更新浪费性能。
*本控件充分利用事件委托,文档碎片createdocumentfragment()原理优化批量节点的事件处理和dom操作,节约性能损耗。
heng.prototype.page = function (opts) {
/*opts={"totaldata":总数据条数(后台取),"pageitems":每页数据条数(后台取),"pagesize":总页数","pagebtns":所有按钮总数(含省略号上下页),
"prenext":有无上下页,"nowpage":当前页码,"active":激活样式class,"disable",禁用样式class,"headtext":"首页","endtext":"尾页","cb":回调函数}
"pretext":上一页按钮文本,"nexttext":"下一页按钮文本"*/
/*总页数=总数据条数÷每页数据条数并向上取整 && pagesize>=6基于nowpage生成页码时有上下页pagebtns>=10最佳 && 无上下页pagebtns>= 6最佳 && pagesize<6时基于pagesize生成页码强制pagesize==pagebtns*/
var def = {
"pagesize" : math.ceil(opts["totaldata"] / opts["pageitems"]),
"prenext" : true,
"pretext" : "上一页",
"nexttext" : "下一页",
"nowpage" : 1,
"headtext" : "1",
"endtext" : opts["pagesize"],
"pagebtns" : 10
};
opts = h.extend(def, opts);
var ishead,
isend,
isheadpn,
isendpn,
frag = document.createdocumentfragment();
for (var i = 0; i < this.nodes.length; i++) {
var wrap = this.nodes[i];
int();
wrap.onclick = function (e) { //点击更新页码,确定当前页,执行回调函数
var e = e || window.event;
var target = e.target || e.srcelement;
if (target.getattribute("data-page") && target.getattribute("data-page") != opts["nowpage"]) {
//全部页码基于nowpage及其所在位置生成,更新nowpage才能更新页码
opts["nowpage"] = parseint(target.getattribute("data-page"));
int();
} else if (target.getattribute("data-page") && target.getattribute("data-page") == opts["nowpage"]) {
opts["cb"] && opts["cb"](opts["nowpage"]);
} else if (!target.getattribute("data-page")) {
return false
}
}
wrap.onselectstart = function () {
return false
}
}
function int() {
wrap.innerhtml && (wrap.innerhtml = null);
if (opts["pagesize"] < 10 && opts["pagesize"] >= 6) {
opts["prenext"] = false;
opts["pagebtns"] = 6;
} else if (opts["pagesize"] < 6) {
static();
opts["pagesize"];
}
if (opts["prenext"]) { //循环外判断一次即可
if (opts["pagebtns"] % 2 == 1) {
isheadpn = opts["nowpage"] <= (opts["pagebtns"] + 1) / 2;
isendpn = opts["nowpage"] >= opts["pagesize"] + 1 - (opts["pagebtns"] - 1) / 2;
}
if (opts["pagebtns"] % 2 == 0) {
isheadpn = opts["nowpage"] <= opts["pagebtns"] / 2;
isendpn = opts["nowpage"] >= [opts["pagesize"] + 1 - (opts["pagebtns"] / 2)]
}
} else {
if (opts["pagebtns"] % 2 == 1) {
ishead = opts["nowpage"] <= (opts["pagebtns"] + 1) / 2;
isend = opts["nowpage"] >= [opts["pagesize"] - (opts["pagebtns"] - 1) / 2];
}
if (opts["pagebtns"] % 2 == 0) {
ishead = opts["nowpage"] <= (opts["pagebtns"] / 2);
isend = opts["nowpage"] >= [opts["pagesize"] - opts["pagebtns"] / 2]
}
}
if (opts["pagesize"] >= 6) {
for (var j = 1; j <= opts["pagebtns"]; j++) {
var osp = document.createelement("span");
if (opts["prenext"] && (opts["pagesize"] >= 10)) {
if (opts["pagebtns"] < 10) {
opts["pagebtns"] = 10;
};
if (isheadpn) { //nowpage靠近头部
osp.innerhtml = j - 1;
osp.setattribute("data-page", j - 1);
if (j == opts["pagebtns"] - 2) {
osp.innerhtml = "…"; //重写倒数第三项
osp.removeattribute("data-page");
}
} else if (isendpn) { //nowpage靠近尾部
osp.innerhtml = opts["pagesize"] - opts["pagebtns"] + j + 1;
osp.setattribute("data-page", opts["pagesize"] - opts["pagebtns"] + j + 1)
if (j == 3) {
osp.innerhtml = "…"; //重写第三项
osp.removeattribute("data-page");
}
} else { //nowpage中间,页码基于nowpage生成
middle();
if (j == opts["pagebtns"] - 2 || j == 3) {
osp.innerhtml = "…"; //重写第三项和倒数第三项
osp.removeattribute("data-page");
}
}
//重写所有的第一项和倒数第一项
if (j == 1) {
osp.innerhtml = opts["pretext"];
if (opts["nowpage"] == 1) {
osp.setattribute("class", opts["disable"]);
osp.removeattribute("data-page");
} else {
osp.setattribute("data-page", opts["nowpage"] - 1);
}
} else if (j == opts["pagebtns"]) {
osp.innerhtml = opts["nexttext"];
if (opts["nowpage"] == opts["pagesize"]) {
osp.setattribute("class", opts["disable"]);
osp.removeattribute("data-page");
} else {
osp.setattribute("data-page", opts["nowpage"] + 1);
}
}
//重写所有的第二项和倒数第二项
if (j == 2) {
osp.innerhtml = opts["headtext"];
osp.setattribute("data-page", 1)
} else if (j == opts["pagebtns"] - 1) {
osp.innerhtml = opts["endtext"];
osp.setattribute("data-page", opts["pagesize"])
}
} else if (!opts["prenext"] && (opts["pagesize"] >= 6)) {
if (opts["pagebtns"] < 6) {
opts["pagebtns"] = 6
};
if (ishead) {
osp.innerhtml = j;
osp.setattribute("data-page", j);
if (j == opts["pagebtns"] - 1) {
osp.innerhtml = "…";
osp.removeattribute("data-page");
}
} else if (isend) {
osp.innerhtml = opts["pagesize"] - opts["pagebtns"] + j;
osp.setattribute("data-page", opts["pagesize"] - opts["pagebtns"] + j)
if (j == 2) {
osp.innerhtml = "…";
osp.removeattribute("data-page");
}
} else {
middle();
if (j == opts["pagebtns"] - 1 || j == 2) {
osp.innerhtml = "…";
osp.removeattribute("data-page");
}
}
//重写第一项和倒数第一项
if (j == 1) {
osp.innerhtml = opts["headtext"];
osp.setattribute("data-page", 1)
} else if (j == opts["pagebtns"]) {
osp.innerhtml = opts["endtext"];
osp.setattribute("data-page", opts["pagesize"])
}
}
if (osp.getattribute("data-page") === opts["nowpage"].tostring()) {
osp.setattribute("class", opts["active"]);
}
osp.style.cursor = "pointer";
(!osp.getattribute("data-page")) && (osp.style.cursor = "auto");
frag.appendchild(osp);
} //for
wrap.appendchild(frag);
}
function middle() {
if (opts["pagebtns"] % 2 == 1) {
osp.innerhtml = opts["nowpage"] - [(opts["pagebtns"] + 1) / 2] + j;
osp.setattribute("data-page", opts["nowpage"] - [(opts["pagebtns"] + 1) / 2] + j)
} else if (opts["pagebtns"] % 2 == 0) {
osp.innerhtml = opts["nowpage"] - (opts["pagebtns"] / 2) + j;
osp.setattribute("data-page", opts["nowpage"] - (opts["pagebtns"] / 2) + j)
}
}
function static() {
for (var k = 1; k <= opts["pagesize"]; k++) {
var osp = document.createelement("span");
osp.innerhtml = k;
osp.setattribute("data-page", k);
frag.appendchild(osp);
if (osp.getattribute("data-page") === opts["nowpage"].tostring()) {
osp.setattribute("class", opts["active"]);
}
}
wrap.appendchild(frag);
}
opts["cb"] && opts["cb"](opts["nowpage"]) //报告当前页发送请求用
} //int
}
*
h("p").on ("tap",fn/{"tap":fn,"hold":fn});自定义事件处理程序实现触控手势操作:
*触控手势不属于系统事件,需一套在数据层管理事件及函数添加、销毁、遍历执行的机制,模拟系统原生add/removeeventlistener方法的功能。
*触控手势事件的触发依赖系统touchstart/touchmove/touchend,触点id号identifier跟踪同一手指。通过e.data报告手势状态。
*tap:屏幕停留时间小于250ms,因不可避免手指抖动、力度不均影响触点状态,手指离屏时坐标偏移需小于阀值(水平:10px,垂直:5px)。
*pinch:手指移动中水平或垂直方向坐标相对进屏时偏移大于10px时可触发,两根手指水平垂直偏移量4个值中的最大者作为缩放系数e.data.k。
*hold:手指在屏幕停留时间大于500ms,如果提前离开或者手指偏移量大于阀值(水平:10px,垂直:5px)则停止定时器不触发。
*swipe:手指需在1000ms内连续(中途不反向)移动至少30px,对比进出屏触点坐标水平垂直偏移量,取较大者来确定e.data报告滑动方向和距离。
/*自定义事件处理程序*/
h.addevent = function (type, handler) {
this.handlers = {}; //{type1:[fn],type2:[fn]}
if (typeof this.handlers[type] == "undefined") {
this.handlers[type] = [];
}
this.handlers[type].push(handler);
};
h.fireevent = function (type, data) {//调用对应类型函数触发事件
if (this.handlers[type]instanceof array) {
var arrayevent = this.handlers[type];
for (var i = 0, len = arrayevent.length; i < len; i++) {
if (typeof arrayevent[i] === "function") {
arrayevent[i](data);
}
}
}
};
h.removeevent = function (type, handler) {
if (this.handlers[type]instanceof array) {
var arrayevent = this.handlers[type];
for (var i = 0, len = arrayevent.length; i < len; i++) {
if (arrayevent[i] === handler) {
arrayevent.splice(i, 1);
break;
}
}
}
}
/*触控手势实现和事件绑定*/
heng.prototype.on = function (handle, fn) { //调用方式(type,fn) 或 ({type1:fn1,type2:fn2})
for (var i = 0; i < this.nodes.length; i++) {
var node = this.nodes[i];
var istouch = false;
var hastap = false,
haspinch = false,
hashold = false,
hasswipeleft = false,
hasswiperight = false;
left = true,
right = true,
up = true,
down = true;
var intime,
outtime,
touchid,
touchid1,
inx,
iny,
inx1,
iny1,
outx,
outy,
movex,
movey,
movex1,
movey1,
disx,
disy,
disx1,
disy1,
t;
if (arguments.length == 1) {
for (var k in handle) {
if ((k === "tap") || (k === "pinch") || (k === "hold") || (k === "swipe")) {
istouch = true; //触控和鼠标事件不和共用
this.istouch = istouch;
checktype(k);
}
}
} else {
istouch = (handle === "tap") || (handle === "pinch") || (handle === "hold") || (handle === "swipe");
this.istouch = istouch;
checktype(handle);
}
if (istouch) {
h.bind(node, "touchstart", tsfn);
h.bind(node, "touchend", tefn);
if (!hastap) {
h.bind(node, "touchmove", tmfn);
}
if (arguments.length == 1) {
for (var j in handle) {
h.addevent(j, handle[j]);
}
} else {
h.addevent(handle, fn);
}
} else {
if (arguments.length == 1) {
for (var j in handle) {
h.bind(node, j, handle[j]);
}
} else {
h.bind(node, handle, fn)
}
}
}
function checktype(x) {
switch (x) {
case "tap":
hastap = true;
break;
case "pinch":
haspinch = true;
break;
case "hold":
hashold = true;
break;
case "swipeleft":
hasswipe = true;
break;
}
}
function tsfn(e) {
touchid = e.changedtouches[0].identifier;
intime = new date().gettime();
inx = e.changedtouches[0].clientx;
iny = e.changedtouches[0].clienty;
if (e.changedtouches[1]) {
touchid1 = e.changedtouches[1].identifier;
inx1 = e.changedtouches[1].clientx;
iny1 = e.changedtouches[1].clienty;
}
if (hashold) {
if (e.targettouches.length === 1 && e.changedtouches[0].identifier === touchid) {
t = window.settimeout(function () {
h.fireevent("hold", e);
}, 500)
}
}
}
function tmfn(e) {
if (hashold) {
if ([math.abs(movey - iny) >= 5] && [math.abs(movex - inx) >= 10]) {
window.cleartimeout(t);
}
} else if (haspinch && e.targettouches.length === 2 && e.changedtouches[1].identifier === touchid1 && e.changedtouches[0].identifier === touchid) {
e.preventdefault();
disx = math.abs(inx1 - inx);
disy = math.abs(iny1 - iny);
disx1 = math.abs(movex1 - movex);
disy1 = math.abs(movey1 - movey);
if ((math.abs(disx - disx1) >= 10) || (math.abs(disy - disy1) >= 10)) {
e.data.k = (math.abs(disx - disx1) > math.abs(disy - disy1)) ? (disx1 / disx) : (disy1 / disy); //缩放因子
h.fireevent("pinch", e);
}
} else if (hasswipe && e.targettouches.length === 2) {
if (e.changedtouches[0].clientx >= movex) {
left = true
} //对比相邻两次的移动判断是否中途反向
else {
right = false
}
if (e.changedtouches[0].clienty >= movey) {
up = true
} else {
down = false
}
e.preventdefault();
}
movex = e.changedtouches[0].clientx;
movey = e.changedtouches[0].clienty;
if (e.changedtouches[1]) {
movex1 = e.changedtouches[1].clientx;
movey1 = e.changedtouches[1].clienty;
}
}
function tefn(e) {
outtime = new date().gettime();
outx = e.changedtouches[0].clientx;
outy = e.changedtouches[0].clienty;
if (hastap && e.targettouches.length === 1 && e.changedtouches[0].identifier === touchid) {
if ([(outtime - intime) <= 250] && [math.abs(outy - iny) <= 5] && [math.abs(outx - inx) <= 10]) {
h.fireevent("tap", e);
}
} else if (hashold && (outtime - intime) <= 500) {
window.cleartimeout(t);
} else if (hasswipe && e.targettouches.length === 1 && e.changedtouches[0].identifier === touchid) {
if (math.abs(outx - inx) >= math.abs(outy - iny)) {
e.data.dis = math.abs(outx - inx);
if (outx >= inx) {
e.data.direction = "right"
} else {
e.data.direction = "left"
}
} else {
e.data.dis = math.abs(outy - iny);
if (outy >= iny) {
e.data.direction = "down"
} else {
e.data.direction = "up"
}
}
if ((outtime - intime) <= 1000 && (math.abs(outy - iny) >= 30 || math.abs(outx - inx) >= 30)) {
if ((left && right) || (up && down)) { //保证中途连续不反向
h.fireevent("swipe", e);
}
}
}
}
return this;
};
*
*【静态方法案例】
h.ajaxjsonp(opts);数据请求包含ajax和jsonp两大模块:
*jsonp:基于src跨域特性动态插入script标签发送get请求远程调用本地同名函数opts["jsonpcbname"],数据以函数传参为载体传回本地。
*发送数据opts['data']自动序列化(支持array、object、string等类型);通过success获取ajax或jsonp请求结果并自动解析。
*post必须定义content-type类型,默认setrequestheader("content-type","application/x-www-form-urlencoded)。
*区分同步异步请求过程,并处理了success、error、progress、complete等四个状态事件。
*若opts['datatype']=jsonp将切换为jsonp 请求,其它值为ajax,opts['data']自动拼接到get请求地址或推入send()后post数据。
*jsonp回调函数名默认随机生成并自动发送,执行回调后立即清除本次生成的script标签防止无限插入,同时清空回调释放内存。
/*ajax and jsonp*/
h.ajaxjsonp = function (opts) {
/*opts={"method":"get/post","url":地址,"async":布尔,"data":数组对象(内部序列化)或已序列化的字符串,"cache":是否禁用缓存,
"datatype":期望返回数据类型(如果取值jsonp将进行jsonp请求),"jsonp":后台获取回调函数名的键名默认callback,
"jsonpcbname":回调函数名默认随机生成,"time":超时,"contenttype":发送文件类型,
"success":fn(response)与jsonp请求共用回调函数,"error":fn(status, statustext),"progress":fn,"complete":fn}*/
//返回结果已内部解析
var def = {
"method" : "post",
"async" : true,
"data" : null,
"cache" : true,
"time" : 800,
"datatype" : "text",
"contenttype" : "application/x-www-form-urlencoded",
"jsonp" : "callback"
};
for (var p in opts) {
def[p] = opts[p];
};
opts = def;
var datastr = "";
if (opts['data']) {
datatype = object.prototype.tostring.call(opts['data']).tolowercase();
if (datatype == "[object array]") {
for (var i = 0; i < opts['data'].length; i++) {
opts['data'][i] = "" + i + "=" + encodeuricomponent(opts['data'][i]);
}
datastr = opts['data'].join("&");
} else if (datatype == "[object object]") {
for (x in opts['data']) {
datastr += "&" + x + "=" + encodeuricomponent(opts['data'][x]);
}
} else if (datatype == "[object string]") {
/*需为序列化字符串*/
datastr = opts['data'];
}
}
if (opts['datatype'] == 'jsonp') { //jsonp请求
var a = math.floor(math.random() * 26) + "a".charcodeat(0);
var b = math.floor(math.random() * 26) + "a".charcodeat(0);
var c = math.floor(math.random() * 26) + "a".charcodeat(0);
var d = math.floor(math.random() * 26) + "a".charcodeat(0);
opts["jsonpcbname"] = opts["jsonpcbname"] || string.fromcharcode(a, b, c, d);
if (opts['url'].indexof('?') === -1) {
opts['url'] += '?' + opts['jsonp'] + '=' + opts['jsonpcbname'] + '&' + datastr;
} else {
opts['url'] += '&' + opts['jsonp'] + '=' + opts['jsonpcbname'] + '&' + datastr;
}
if (opts['cache']) {
opts['url'] += '&cache=' + date.now();
}
var script = document.createelement('script');
script.id = "" + opts["jsonpcbname"];
script.src = opts['url'];
document.getelementsbytagname('head')[0].appendchild(script);
window[opts["jsonpcbname"]] = function (response) { //服务器调用的函数
opts['success'] && opts['success'](response);
document.getelementbyid(opts["jsonpcbname"]).parentnode.removechild(document.getelementbyid(opts["jsonpcbname"]));
window[opts["jsonpcbname"]] = null;
}
} else { //ajax请求
var xhr = new xmlhttprequest();
if (opts.method === 'get') {
opts.url += opts.url.indexof('?') == -1 ? '?' + datastr : '&' + datastr;
}
if (opts.async === true) {
xhr.onreadystatechange = function () {
if (xhr.readystate == 0) {
opts.progress();
} else if (xhr.readystate == 4) {
callback();
opts.complete();
}
};
}
xhr.open(opts.method, opts.url, opts.async);
if (opts["cache"]) {
xhr.setrequestheader("cache-control", "no-cache");
xhr.setrequestheader("if-modified-since", "0");
}
xhr.responsetype = opts["datatype"];
xhr.timeout && (xhr.timeout = opts["time"])
if (opts.method === 'post') { //实际发送文件类型post必须
xhr.setrequestheader("content-type", opts["contenttype"]);
xhr.send(datastr);
} else {
xhr.send(null);
}
if (opts.async === false) {
callback();
opts.complete();
}
function callback() {
var response;
if (xhr.status == 200) {
try {
response = json.parse(xhr.responsetext);
} catch (er) {
response = eval("(" + xhr.responsetext + ")");
}
opts.success(response);
} else {
opts.error(xhr.status, xhr.statustext);
}
}
} //ajax end
}
相关推荐:
前端框架thinkjs框架详解
layui前端框架日期控件使用方法
最新的前端框架、类库、工具比较
以上就是前端框架heng.js详解的详细内容。