백엔드 개발 PHP 튜토리얼 프론트엔드 프레임워크 Heng.js에 대한 자세한 설명

프론트엔드 프레임워크 Heng.js에 대한 자세한 설명

Mar 10, 2018 pm 02:58 PM
javascript 액자

프레임워크 설명: 객체 지향 프로그래밍 아이디어를 기반으로 하고 기본 js 언어로 구현되어 타사 js 라이브러리에 의존하지 않으며 외부 코드 조각을 참조하지 않습니다! 프레임워크의 유연성과 견고성을 보장하기 위해 다양한 애플리케이션 시나리오를 완전히 고려하십시오.
* 구현 기능: jQuery와 완전히 일치하는 아키텍처 및 내부 세부 사항을 구현합니다. 설정 작업의 내부 루프는 일치하는 모든 노드를 설정할 수 있으며 메서드는 체인에서 호출될 수 있습니다.
* 메소드 분류: 정적 메소드는 데이터 로직, DOM 전처리 및 기타 전역 비 DOM 작업을 위해 프레임워크 내에서 사용되며 해당 UI 구성요소를 호출합니다.
* 매개변수 구성: 실제 필요에 따라 다양한 매개변수를 구성하고 유연하게 호출합니다. 매개변수가 없는 경우 기본 구성을 사용합니다.
* 선택기 지원: ID, 클래스, 라벨, 하위 선택기, dom 노드, 인스턴스화된 객체 H("css 선택기").
* 호환성: 모든 방법은 브라우저 간 완벽하게 호환되며 대부분의 최신 브라우저(IE6/7/8/9/10/11, Chrome, Firefox, Safari 등)와 호환됩니다.
* 변수 안전성: 클로저 환경에서 프레임워크 자체 변수의 안전성이 보장되고 변수 충돌이 방지됩니다.
* 프레임워크 성능: 코드를 최적화하여 성능을 향상시키고 브라우저 리플로우 및 다시 그리기를 최소화합니다. null 값을 할당하여 메모리를 해제합니다. DOM, BOM 및 ECMAScript 간의 아일랜드 통신을 방지합니다. 문서 조각을 기반으로 DOM 작업을 수행하여 컬렉션 이벤트를 처리합니다...
*
* [호출]
* 정적 메서드: H. Method(value)
* 인스턴스 메소드: H("css selector").Method(value), H("css selector").Method({key:value})
* H(sel).Method({ 속성 이벤트 구성}), H(sel).Method(컴포넌트 메소드, 메소드 매개변수)
* 체인 호출: H("css selector").Method({key:value}).Method()
* DOM 트리 로드 후 실행: H(fn)은 jQuery 라이브러리의 $(fn)===$(document).ready(fn)
과 동일합니다. * 내부 루프: 인스턴스 메소드는 내부적으로 H("css selector")와 일치합니다. 노드 컬렉션은 내부 루프를 수행합니다. 일치하는 모든 노드를 동시에 작동할 수 있습니다
* 속성 메소드: opts는 컴포넌트 속성 이벤트를 설정합니다. 컴포넌트 메소드 메소드(컴포넌트 메소드, 매개변수)
* 제스처 터치: 모바일 단말기에 대한 터치 제스처 이벤트(Tap)가 캡슐화됩니다. , Hold, Swipe)을 수행하고 e.data를 통해 해당 제스처의 상태를 보고합니다. 핀치 줌 계수, 슬라이딩 방향, 슬라이딩 거리 등
*
* 작성자: wheng

* 날짜: 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)
로그인 후 복사

*생성자에서는 "공용 데이터 귀속" 규칙에 따라 DOM 노드의 기능을 얻고 노드 속성에 노드를 저장하기 위해 "css 선택기"가 구현됩니다.

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 &#39;#&#39;:
                    childElements = []; //清除上一组值再更新
                    childElements.push(this.getId(nodes[i].substring(1)));
                    node = childElements;
                    break;
                case &#39;.&#39;:
                    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 &#39;#&#39;:
                this.nodes.push(this.getId(sel.substring(1)));
                break;
            case &#39;.&#39;:
                this.nodes = this.getClass(sel.substring(1));
                break;
            default:
                this.nodes = this.getTagName(sel);
            }
        }
    } else if (typeof sel == &#39;object&#39;) { //sel为dom节点
        if (sel != undefined) {
            this.nodes[0] = sel;
        }
    }
}
로그인 후 복사

*정적 메서드는 인스턴스화가 필요하지 않으며 프레임워크 내에서 데이터 논리 및 DOM 전처리 또는 기타 전역 비DOM 작업에 사용됩니다. sel 일치 구성 요소 항목이 있는 경우 인스턴스 메서드는 DOM 노드와 결합됩니다. 설정하면 모든 노드가 메소드의 논리와 기능을 실현할 수 있습니다.

//静态方法
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(&#39;ul&#39;);
        ……
    }
}
로그인 후 복사

*객체 지향 프로그래밍은 필연적으로 이 포인터에 대한 혼란을 야기합니다. 모든 유사한 문제의 경우 클로저를 통해 함수 외부에 var 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); 페이지 컨테이너는 페이징 제어를 인스턴스화하기 위해 필수 매개변수 페이지를 전달합니다.

*총 페이지 수 pageSize=totalDataTotal 데이터 항목 수 ¶pageItems per 페이지 데이터 항목 수입니다(몫은 반올림됨). 필요한 구성 데이터는 초기화 중에 서버에서 반환됩니다.

*pageSize<6페이지 번호 버튼은 pageSize를 기준으로 생성되며, pageBtns를 pageSize와 동일하게 하고 정적 페이지 번호를 생성합니다.

*6≤pageSize<10 nowPage를 기준으로 페이지 번호를 생성하고, 페이지 업, 다운 버튼을 강제 삭제하고, pageBtns=6을 정의하고, 시작, 끝, 중간에서 nowPage의 세 가지 상황을 구분합니다.

*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[&#39;data&#39;]) {
        dataType = Object.prototype.toString.call(opts[&#39;data&#39;]).toLowerCase();
        if (dataType == "[object array]") {
            for (var i = 0; i < opts[&#39;data&#39;].length; i++) {
                opts[&#39;data&#39;][i] = "" + i + "=" + encodeURIComponent(opts[&#39;data&#39;][i]);
            }
            dataStr = opts[&#39;data&#39;].join("&");
        } else if (dataType == "[object object]") {
            for (x in opts[&#39;data&#39;]) {
                dataStr += "&" + x + "=" + encodeURIComponent(opts[&#39;data&#39;][x]);
            }
        } else if (dataType == "[object string]") {
            /*需为序列化字符串*/
            dataStr = opts[&#39;data&#39;];
        }
    }
    if (opts[&#39;dataType&#39;] == &#39;jsonp&#39;) { //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[&#39;url&#39;].indexOf(&#39;?&#39;) === -1) {
            opts[&#39;url&#39;] += &#39;?&#39; + opts[&#39;jsonp&#39;] + &#39;=&#39; + opts[&#39;jsonpCBname&#39;] + &#39;&&#39; + dataStr;
        } else {
            opts[&#39;url&#39;] += &#39;&&#39; + opts[&#39;jsonp&#39;] + &#39;=&#39; + opts[&#39;jsonpCBname&#39;] + &#39;&&#39; + dataStr;
        }
        if (opts[&#39;cache&#39;]) {
            opts[&#39;url&#39;] += &#39;&cache=&#39; + Date.now();
        }
        var script = document.createElement(&#39;script&#39;);
        script.id = "" + opts["jsonpCBname"];
        script.src = opts[&#39;url&#39;];
        document.getElementsByTagName(&#39;head&#39;)[0].appendChild(script);
        window[opts["jsonpCBname"]] = function (response) { //服务器调用的函数
            opts[&#39;success&#39;] && opts[&#39;success&#39;](response);
            document.getElementById(opts["jsonpCBname"]).parentNode.removeChild(document.getElementById(opts["jsonpCBname"]));
            window[opts["jsonpCBname"]] = null;
        }

    } else { //Ajax请求
        var xhr = new XMLHttpRequest();
        if (opts.method === &#39;get&#39;) {
            opts.url += opts.url.indexOf(&#39;?&#39;) == -1 ? &#39;?&#39; + dataStr : &#39;&&#39; + 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 === &#39;post&#39;) { //实际发送文件类型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에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Java 프레임워크에 대한 상용 지원의 비용 효율성을 평가하는 방법 Java 프레임워크에 대한 상용 지원의 비용 효율성을 평가하는 방법 Jun 05, 2024 pm 05:25 PM

Java 프레임워크에 대한 상용 지원의 비용/성능 평가에는 다음 단계가 포함됩니다. 필요한 보증 수준과 SLA(서비스 수준 계약) 보장을 결정합니다. 연구지원팀의 경험과 전문성. 업그레이드, 문제 해결, 성능 최적화와 같은 추가 서비스를 고려하십시오. 위험 완화 및 효율성 향상을 기준으로 비즈니스 지원 비용을 평가합니다.

PHP 프레임워크의 경량 옵션은 애플리케이션 성능에 어떤 영향을 줍니까? PHP 프레임워크의 경량 옵션은 애플리케이션 성능에 어떤 영향을 줍니까? Jun 06, 2024 am 10:53 AM

경량 PHP 프레임워크는 작은 크기와 낮은 리소스 소비를 통해 애플리케이션 성능을 향상시킵니다. 그 특징은 다음과 같습니다: 작은 크기, 빠른 시작, 낮은 메모리 사용량, 향상된 응답 속도 및 처리량, 리소스 소비 감소 실제 사례: SlimFramework는 500KB에 불과한 REST API를 생성하며 높은 응답성과 높은 처리량을 제공합니다.

PHP 프레임워크의 학습 곡선은 다른 언어 프레임워크와 어떻게 비교됩니까? PHP 프레임워크의 학습 곡선은 다른 언어 프레임워크와 어떻게 비교됩니까? Jun 06, 2024 pm 12:41 PM

PHP 프레임워크의 학습 곡선은 언어 숙련도, 프레임워크 복잡성, 문서 품질 및 커뮤니티 지원에 따라 달라집니다. PHP 프레임워크의 학습 곡선은 Python 프레임워크에 비해 높고 Ruby 프레임워크에 비해 낮습니다. Java 프레임워크에 비해 PHP 프레임워크는 학습 곡선이 적당하지만 시작하는 데 걸리는 시간이 더 짧습니다.

Java 프레임워크의 성능 비교 Java 프레임워크의 성능 비교 Jun 04, 2024 pm 03:56 PM

벤치마크에 따르면 소규모 고성능 애플리케이션의 경우 Quarkus(빠른 시작, 낮은 메모리) 또는 Micronaut(TechEmpower 우수)가 이상적인 선택입니다. SpringBoot는 대규모 풀 스택 애플리케이션에 적합하지만 시작 시간과 메모리 사용량이 약간 느립니다.

Golang 프레임워크 문서화 모범 사례 Golang 프레임워크 문서화 모범 사례 Jun 04, 2024 pm 05:00 PM

Golang 프레임워크에서는 명확하고 포괄적인 문서를 작성하는 것이 중요합니다. 모범 사례에는 Google의 Go 코딩 스타일 가이드와 같은 확립된 문서 스타일을 따르는 것이 포함됩니다. 제목, 부제, 목록 등 명확한 조직 구조를 사용하고 탐색 기능을 제공하세요. 시작 안내서, API 참조 및 개념을 포함하여 포괄적이고 정확한 정보를 제공합니다. 코드 예제를 사용하여 개념과 사용법을 설명합니다. 문서를 계속 업데이트하고, 변경 사항을 추적하고, 새로운 기능을 문서화하세요. GitHub 문제 및 포럼과 같은 지원 및 커뮤니티 리소스를 제공합니다. API 문서와 같은 실용적인 예제를 만듭니다.

다양한 애플리케이션 시나리오에 가장 적합한 golang 프레임워크를 선택하는 방법 다양한 애플리케이션 시나리오에 가장 적합한 golang 프레임워크를 선택하는 방법 Jun 05, 2024 pm 04:05 PM

애플리케이션 시나리오를 기반으로 최고의 Go 프레임워크를 선택하세요. 애플리케이션 유형, 언어 기능, 성능 요구 사항 및 생태계를 고려하세요. Common Go 프레임워크: Gin(웹 애플리케이션), Echo(웹 서비스), Fiber(높은 처리량), gorm(ORM), fasthttp(속도). 실제 사례: REST API(Fiber) 구축 및 데이터베이스(gorm)와 상호 작용. 프레임워크를 선택하세요. 주요 성능을 ​​위해서는 fasthttp를 선택하고, 유연한 웹 애플리케이션을 위해서는 Gin/Echo를, 데이터베이스 상호작용을 위해서는 gorm을 선택하세요.

golang 프레임워크 개발에 대한 자세한 실제 설명: 질문과 답변 golang 프레임워크 개발에 대한 자세한 실제 설명: 질문과 답변 Jun 06, 2024 am 10:57 AM

Go 프레임워크 개발에서 일반적인 과제와 해결 방법은 다음과 같습니다. 오류 처리: 관리에는 오류 패키지를 사용하고 중앙에서 오류를 처리하려면 미들웨어를 사용합니다. 인증 및 권한 부여: 타사 라이브러리를 통합하고 사용자 정의 미들웨어를 생성하여 자격 증명을 확인합니다. 동시 처리: 고루틴, 뮤텍스 및 채널을 사용하여 리소스 액세스를 제어합니다. 단위 테스트: 격리를 위해 getest 패키지, 모의 및 스텁을 사용하고, 충분성을 보장하기 위한 코드 적용 도구를 사용합니다. 배포 및 모니터링: Docker 컨테이너를 사용하여 배포를 패키징하고, 데이터 백업을 설정하고, 로깅 및 모니터링 도구를 사용하여 성능과 오류를 추적합니다.

Golang 프레임워크 성능 비교: 현명한 선택을 위한 측정항목 Golang 프레임워크 성능 비교: 현명한 선택을 위한 측정항목 Jun 05, 2024 pm 10:02 PM

Go 프레임워크를 선택할 때 핵심 성과 지표(KPI)에는 응답 시간, 처리량, 동시성 및 리소스 사용량이 포함됩니다. 프레임워크의 KPI를 벤치마킹하고 비교함으로써 개발자는 예상 로드, 성능이 중요한 섹션 및 리소스 제약 조건을 고려하여 애플리케이션 요구 사항에 따라 정보에 입각한 선택을 내릴 수 있습니다.

See all articles