1. JS 네이티브 Ajax
ajax: 전체 페이지를 새로 고치지 않고 데이터를 요청하는 방법
ajax의 기술 핵심은 XMLHttpRequest 객체입니다.
ajax 요청 프로세스입니다. , 서버에 연결하고 요청을 보내고 응답 데이터를 받습니다.
다음은 나중에 설명할 함수를 간단히 요약한 것입니다.
ajax({ url: "./TestXHR.aspx", //请求地址 type: "POST", //请求方式 data: { name: "super", age: 20 }, //请求参数 dataType: "json", success: function (response, xml) { // 此处放成功后执行的代码 }, fail: function (status) { // 此处放失败后执行的代码 } }); function ajax(options) { options = options || {}; options.type = (options.type || "GET").toUpperCase(); options.dataType = options.dataType || "json"; var params = formatParams(options.data); //创建 - 非IE6 - 第一步 if (window.XMLHttpRequest) { var xhr = new XMLHttpRequest(); } else { //IE6及其以下版本浏览器 var xhr = new ActiveXObject('Microsoft.XMLHTTP'); } //接收 - 第三步 xhr.onreadystatechange = function () { if (xhr.readyState == 4) { var status = xhr.status; if (status >= 200 && status < 300) { options.success && options.success(xhr.responseText, xhr.responseXML); } else { options.fail && options.fail(status); } } } //连接 和 发送 - 第二步 if (options.type == "GET") { xhr.open("GET", options.url + "?" + params, true); xhr.send(null); } else if (options.type == "POST") { xhr.open("POST", options.url, true); //设置表单提交时的内容类型 xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); xhr.send(params); } } //格式化参数 function formatParams(data) { var arr = []; for (var name in data) { arr.push(encodeURIComponent(name) + "=" + encodeURIComponent(data[name])); } arr.push(("v=" + Math.random()).replace(".")); return arr.join("&"); }
생성
1.1, IE7 및 그 이전 버전에서는 기본 XHR 객체를 지원하므로 직접 사용할 수 있습니다. var oAjax = new XMLHttpRequest();
1.2, IE6 및 이전 버전에서는 XHR 객체가 ActiveX를 통해 구현됩니다. MSXML 라이브러리의 개체입니다. 일부 책에서는 IE에 있는 이러한 개체의 세 가지 버전, 즉 MSXML2. =new ActiveXObject('Microsoft.XMLHTTP');
2. 연결 및 전송
2.1. () 기능: 요청 방법, 요청 주소, 비동기 요청 여부(동기 요청은 드물고 지금까지 사용되지 않음)
2.2. GET 요청 방법은 URL 매개변수를 통해 서버에 데이터를 제출합니다. POST는 전송 매개변수로 데이터를 서버에 제출합니다.
2.3. POST 요청에서 데이터를 보내기 전에 양식 제출의 내용 유형을 설정해야 합니다.
2.4. 서버는 encodeURIComponent() 메소드로 인코딩되어야 합니다. 실제로 매개변수 목록 "key=value"에서는 키와 값이 모두 특수 문자를 포함하므로 인코딩되어야 합니다. 요청이 이루어질 때마다 "v=xx" 문자열이 매개변수 목록에 입력됩니다. 이는 캐싱을 거부하고 매번 서버에 직접 요청하는 것입니다.
encodeURI(): 전체 URI를 인코딩하는 데 사용되며 콜론, 슬래시, 물음표 및 파운드 기호와 같은 URI에 속하는 특수 문자는 인코딩하지 않습니다. 해당 디코딩 함수 decodeURI() ;
encodeURIComponent(): URI의 특정 부분을 인코딩하는 데 사용되며, 해당 디코딩 함수 decodeURIComponent()를 인코딩합니다.
statusText: HTTP 상태 설명 ;
3.2. XHR 객체의 ReadyState 속성은 요청/응답 프로세스의 현재 활성 단계를 나타냅니다. 속성은 다음과 같습니다
0 - 초기화되지 않았으며 open() 메서드가 호출되지 않았습니다.
1-Start, open() 메서드가 호출되었지만 send() 메서드가 호출되지 않았습니다. 🎜> 2-보내기, send() 메소드가 호출되었지만 응답이 수신되지 않았습니다.
4-완료, 모든 응답 데이터가 수신되었습니다.
readyState의 값이 변경되는 한 Readystatechange 이벤트가 호출됩니다. (사실 논리적인 원활함을 위해 요청은 전송 중에 이루어지기 때문에 전송 후에 배치할 수 있습니다. 서버는 네트워크 통신을 수행하는데 시간이 소요됩니다.전송 후에 Readystatechange 이벤트 핸들러를 지정하는 것도 가능합니다. 저는 보통 이런 방식으로 사용하지만, 표준화와 크로스 브라우저 호환성을 위해 열기 전에 지정하는 것이 좋습니다.
3.3.readystatechange 이벤트에서 먼저 응답이 수신되었는지 확인한 다음, xhr.status가 2로 시작하는 상태 코드가 성공임을 의미합니다. Obtain, 위의 코드는 각 요청에 임의의 숫자를 추가하므로 값이 캐시에서 검색되지 않으므로 이 상태를 판단할 필요가 없습니다.
function jsonp(options) { options = options || {}; if (!options.url || !options.callback) { throw new Error("参数不合法"); } //创建 script 标签并加入到页面中 var callbackName = ('jsonp_' + Math.random()).replace(".", ""); var oHead = document.getElementsByTagName('head')[0]; options.data[options.callback] = callbackName; var params = formatParams(options.data); var oS = document.createElement('script'); oHead.appendChild(oS); //创建jsonp回调函数 window[callbackName] = function (json) { oHead.removeChild(oS); clearTimeout(oS.timer); window[callbackName] = null; options.success && options.success(json); }; //发送请求 oS.src = options.url + '?' + params; //超时处理 if (options.time) { oS.timer = setTimeout(function () { window[callbackName] = null; oHead.removeChild(oS); options.fail && options.fail({ message: "超时" }); }, time); } }; //格式化参数 function formatParams(data) { var arr = []; for (var name in data) { arr.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[i])); } return arr.join('&'); }
1、因为 script 标签的 src 属性只在第一次设置的时候起作用,导致 script 标签没法重用,所以每次完成操作之后要移除;
2、JSONP这种请求方式中,参数依旧需要编码;
3、如果不设置超时,就无法得知此次请求是成功还是失败;
三、模仿JQuery中的ready()事件
1、DOMContentLoaded事件,在DOM树加载完成之后立即执行,始终会在load之前执行。
IE9+、FF、Chrome、Safari3.1+和Opera9+都支持该事件。
对于不支持该事件的浏览器,可以使用如下代码:
setTimeout(function(){
// 代码块}, 0) ;
DOMContentLoaded 事件只能通过 DOM2 级方式添加,即采用addEventListener()/attachEvent() 方式添加才能够使用。事件对象不会提供任何额外信息。
2、readystatechange事件
IE为DOM文档中的某些部分(区别于 XHR 对象的 readystatechange 事件)提供了该事件,这个事件的目的是提供与文档或元素的加载状态有关的信息,但这个事件的行为有时候也很难预料。支持该事件的对象都有一个readyState属性,注意,不是 event 事件对象。IE、Firefox4+和Opera 支持该事件。
readyState属性的值如下:
“uninitialized” - 未初始化:对象存在但尚未初始化;
“loading” - 正在加载:对象正在加载数据;
“loaded” - 加载完毕,对象加载数据完毕;
“interactive” - 交互:可以操作对象了,但还没有完全加载;
“complete” - 完成:对象已经加载完成;
2.1、并非所有的对象都会经历readyState的这几个阶段,如果这个阶段不适用某个对象,则该对象完全可能跳过该阶段,并没有规定哪个阶段适用于哪个对象。这意味着 readystatechange 事件经常会少于4次,相对应的 readyState 属性值也不是连续的。
2.2、对于 document 而言,interactive 和 complete 阶段会在于 DOMContentLoaded 大致相同的时刻触发 readystatechange 事件;
load 事件和 readystatechange 事件的触发顺序会因页面的外部资源的多少而变化,也就是说,readystatechange 事件并不会一直在 load 事件之前执行。外部资源越多,对 readystatechange 事件就越有利。
interactive 和 complete 的顺序也是不一致的,谁都有可能先执行,引用的外部资源越多,对交互阶段越有利。所以为了尽可能早的执行代码,两个状态要同时判断。
3、doScroll
IE5.5+支持,当页面中有滚动条时,可以用 doScroll("right")/doScroll("down") 等来移动滚动条,这个方法只有等DOM加载完成以后才能用,所以在IE低版本浏览器中可以通过这个属性判断 DOM 结构是否加载完成。介绍这个属性主要是模仿 jquery 中的解决方案。
function ready(readyFn) { //非IE浏览器 if (document.addEventListener) { document.addEventListener('DOMContentLoaded', function () { readyFn && readyFn(); }, false); } else { //方案1和2 哪个快用哪一个 var bReady = false; //方案1 document.attachEvent('onreadystatechange', function () { if (bReady) { return; } if (document.readyState == 'complete' || document.readyState == "interactive") { bReady = true; readyFn && readyFn(); }; }); //方案2 //jquery也会担心doScroll会在iframe内失效,此处是判断当前页是否被放在了iframe里 if (!window.frameElement) { setTimeout(checkDoScroll, 1); } function checkDoScroll() { try { document.documentElement.doScroll("left"); if (bReady) { return; } bReady = true; readyFn && readyFn(); } catch (e) { // 不断检查 doScroll 是否可用 - DOM结构是否加载完成 setTimeout(checkDoScroll, 1); } }; } };
注:
setTimeout(checkDoScroll, 1); 目的是让浏览器尽快执行 checkDoScroll 函数,间隔时间设置为 1ms,对当下的浏览器来说是不太可能的。每个浏览器都有自己默认的最小间隔时间,即使时间设置为最小间隔时间,也只是代表隔这些时间过去之后,JavaScript 会把 checkDoScroll 加入到执行队列中,如果此时 JavaScript 进程空闲,则会立即执行该代码。