简易封装 XHR:支持 GET/POST/PUT/DELETE/JSONP/FormData

简介: AJAX 就是 XHR 的应用,无需多说。请看看小弟我第 N 次的封装工作。首先声明命名空间,先占一个位:// base goes here...ajaxjs = {}; // Setup a top namespace然后依赖一些方法:/* * -------------------...

AJAX 就是 XHR 的应用,无需多说。请看看小弟我第 N 次的封装工作。

首先声明命名空间,先占一个位:

// base goes here...
ajaxjs = {}; // Setup a top namespace
然后依赖一些方法:
/*
 * -------------------------------------------------------- 
 * 函数委托 参见
 * http://blog.csdn.net/zhangxin09/article/details/8508128 
 * @return {Function}
 * --------------------------------------------------------
 */
Function.prototype.delegate = function() {
	var self = this, scope = this.scope, args = arguments, aLength = arguments.length, fnToken = 'function';

	return function() {
		var bLength = arguments.length, Length = (aLength > bLength) ? aLength
				: bLength;

		// mission one:
		for (var i = 0; i < Length; i++)
			if (arguments[i])
				args[i] = arguments[i]; // 拷贝参数

		args.length = Length; // 在 MS
								// jscript下面,arguments作为数字来使用还是有问题,就是length不能自动更新。修正如左:

		// mission two:
		for (var i = 0, j = args.length; i < j; i++) {
			var _arg = args[i];
			if (_arg && typeof _arg == fnToken && _arg.late == true)
				args[i] = _arg.apply(scope || this, args);
		}

		return self.apply(scope || this, args);
	};
};
接着主角登场,XHR:

/*
 * -------------------------------------------------------- 
 * 封装 XHR,支持 GET/POST/PUT/DELETE/JSONP/FormData
 * --------------------------------------------------------
 */
ajaxjs.xhr = {
	json2url : ajaxjs.params.json2url,

	// 注意 url 部分带有 # 的话则不能传参数过来
	request : function(url, cb, args, cfg, method) {
		var params = this.json2url(args), xhr = new XMLHttpRequest();

		method = method.toUpperCase();

		if (method == 'POST' || method == 'PUT') {
			xhr.open(method, url);
		} else
			xhr.open(method, url + (params ? '?' + params : ''));

		cb.url = url; // 保存 url 以便记录请求路径,可用于调试

		xhr.onreadystatechange = this.callback.delegate(null, cb, cfg && cfg.parseContentType);

		if (method == 'POST' || method == 'PUT') {
			xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
			xhr.send(params);
		} else {
			xhr.send(null);
		}
	},

	callback : function(event, cb, parseContentType) {
		if (this.readyState === 4 && this.status === 200) {
			var responseText = this.responseText.trim();

			try {
				if (!responseText)
					throw '服务端返回空的字符串!';

				var data = null;
				switch (parseContentType) {
				case 'text':
					data = this.responseText;
					break;
				case 'xml':
					data = this.responseXML;
					break;
				case 'json':
				default:
					data = JSON.parse(responseText);
				}
			} catch (e) {
				alert('AJAX 错误:\n' + e + '\nThe url is:' + cb.url); // 提示用户 异常
			}

			if (!cb)
				throw '你未提供回调函数';

			cb(data, this);
		}
	},

	/**
	 * e.g XMLHttpRequest.jsonp(
	 * 'http://u1.3gtv.net:2080/pms-service/section/content_list', { start:0,
	 * limit:10, sort:0, portalId:45, id:3290 }, function(json){
	 * console.log(json); } );
	 * 
	 * @param url
	 *            请求远程路径
	 * @param params
	 *            参数
	 * @param cb
	 *            回调函数
	 * @param cfg
	 *            该次请求的配置
	 */
	jsonp : function(url, params, cb, cfg) {
		var globalMethod_Token = 'globalMethod_'
				+ parseInt(Math.random() * (200000 - 10000 + 1) + 10000);

		if (!window.$$_jsonp)
			window.$$_jsonp = {};
		// Map<String, Function>
		window.$$_jsonp[globalMethod_Token] = cb;

		params = params || {};
		params[cfg && cfg.callBackField || 'callBack'] = '$$_jsonp.'+ globalMethod_Token;

		var scriptTag = document.createElement('script');
		scriptTag.src = this.json2url(params, url);
		document.getElementsByTagName('head')[0].appendChild(scriptTag);
	},

	form : function(form, cb, cfg) {
		if (!window.FormData) {
			var msg = 'The version of your browser is too old, please upgrade it.';
			throw msg;
		}

		if (typeof form == 'string')
			form = document.querySelector(form);

		if (!form.action)
			throw 'Please fill the url in ACTION attribute.';
	 
		// form.method always GET, so form.getAttribute('method') instead
		var method = form.getAttribute('method').toLowerCase();
		if (!method)
			method = 'post';

		
		form.addEventListener('submit', function(e, cb, cfg) {
			if (cfg && cfg.beforeSubmit && cfg.beforeSubmit(form, formData) === false) 
				return;
			e.preventDefault();// 禁止 form 默认提交
			var form = e.target;
			var json = {};
			
			var formData = new FormData(form);
			formData.forEach(function(value, key){
				json[key] = value;
			});
			ajaxjs.xhr.post(form.action, cb, json);
		}.delegate(null, cb, cfg));
	}
};
所谓  GET/POST/PUT/DELETE,也就是 Open 时候参数不同,故适合 delegate 预先指定参数。
// GET 请求
ajaxjs.xhr.get = ajaxjs.xhr.request.delegate(null, null, null, null, 'GET');
ajaxjs.xhr.post = ajaxjs.xhr.request.delegate(null, null, null, null, 'POST');
ajaxjs.xhr.put = ajaxjs.xhr.request.delegate(null, null, null, null, 'PUT');
ajaxjs.xhr.dele = ajaxjs.xhr.request.delegate(null, null, null, null, 'DELETE');
表单 AJAX 请求使用了 H5 的 FormData 新特性,不需要自己去遍历表单了。
// 不需要了……
function serializeForm(formEl, isStringOutput, isIgnroEmpty /* 是否忽略空字符串的字段 */) {
	var formData = {};

	eachChild4form(
			formEl,
			function(el) {
				var elType = el.type, key = el.name;

				if (elType == "text" || elType == "hidden"
						|| elType == "password" || elType == "textarea") {
					formData[key] = getPrimitives(el.value);
				} else if (elType == "radio" || elType == "checkbox") {
					if (el.checked)// 选中才会加入数据
						formData[key] = getPrimitives(el.value);
				} else if (elType == "select-one"
						|| elType == "select-multiple") {
					for (var opt, optValue, p = 0, q = el.options.length; p < q; p++) {
						opt = el.options[p];
						if (opt.selected) {
							optValue = opt.hasAttribute ? opt
									.hasAttribute('value') : opt
									.getAttribute('value') !== null
							optValue = optValue ? opt.value : opt.text;

							formData[key] = getPrimitives(optValue);
						}
					}
				}

				if (typeof formData[key] == 'string') { // url 编码
					formData[key] = encodeURIComponent(formData[el.name]);
				}
			});

	if (isIgnroEmpty) {
		for ( var i in formData) {
			if (formData[i] === "")
				delete formData[i];
		}
	}

	return isStringOutput ? utils.json2url(formData) : formData;
}

// 遍历表单
function eachChild4form(formEl, fn) {
    // 豁免:没有 name 属性的不要;禁止了的不要;特定的字段不要
    // !el.checked // 未选择的要来干嘛??
    var ignore = /file|undefined|reset|button|submit/i;

    for (var el, i = 0, j = formEl.elements.length; i < j; i++) {
        el = formEl.elements[i];
        if (!el.name || el.disabled || ignore.test(el.type))
            continue;
        fn(el, i);
    }
}

// 判断form的内容是否有改变
function isFormChanged(formEl) {
    var i = 0;
    eachChild4form(formEl, function(el) {
        switch (el.type) {
        case "text":
        case "hidden":
        case "password":
        case "textarea":
            if (el.defaultValue != el.value)
                return true;
            break;
        case "radio":
        case "checkbox":
            if (el.defaultChecked != el.checked)
                return true;
            break;
        case "select-one":
            i = 1;
        case "select-multiple":
            opts = el.options;
            for (; i < opts.length; i++)
                if (opts[i].defaultSelected != opts[i].selected)
                    return true;
            break;
        }
    });

    return false;
}
上面的代码留个纪念……

注意 AJAX 表单很多新手都会犯个错误,就是没有禁止 form 默认提交事件。你可以去掉 form 标签,或者:

e.preventDefault();// 禁止 form 默认提交
// or
return false;
 AJAX 还有另外一种选择 Fetch API,貌似差别不大。


目录
相关文章
|
24天前
|
网络协议 数据安全/隐私保护
get和post的区别
get和post的区别
19 0
|
JSON 数据格式
okhttp3 模拟get、post(json参数传递,form表单提交)
本文是博主学习okhttp3 的记录,希望对大家有所帮助。
1553 0
|
4月前
|
前端开发 JavaScript 安全
AJAX - $().load(url,data,function(response,status,xhr))
AJAX - $().load(url,data,function(response,status,xhr))
29 0
|
4月前
|
Web App开发 前端开发 JavaScript
AJAX POST请求中参数以form data和request payload形式在servlet中的获取方式
AJAX POST请求中参数以form data和request payload形式在servlet中的获取方式
32 0
|
4月前
|
缓存 安全 数据安全/隐私保护
GET和POST有什么区别
GET和POST有什么区别
|
10月前
|
网络协议 安全 数据安全/隐私保护
GET与POST的区别
GET与POST的区别
97 0
|
JavaScript API
js:object转FormData提交数据
js:object转FormData提交数据
89 0
|
前端开发 数据库
浅谈Ajax请求中的GET,POST,PUT,DELETE,PATCH,OPTIONS
浅谈Ajax请求中的GET,POST,PUT,DELETE,PATCH,OPTIONS 在日常的前后端交互,数据请求中最长用的就是Ajax,当然在面试时也经常会被问道请求的方式有哪些?分别什么不同?一般我们都会回答GET请求和POST请求,但其实在后端配置接口时,请求方式不仅这两种,还会有PUT,DELETE,PATCH等,当然我们在开发的时候偶尔也会遇到接口要求使用这几种方式进行请求,下面我们就来讲一讲这几种方式分别有什么不同。 首先先要了解http定义与服务器进行交互的方式,其中基本的有GET,POST,PUT,DELETE,PATCH是后增的方式。同时还要知道URL代表的是 统一资源
浅谈Ajax请求中的GET,POST,PUT,DELETE,PATCH,OPTIONS
|
网络协议 安全
GET 和 POST 的区别
GET 和 POST 的区别
104 0
|
缓存 安全 前端开发
GET和POST有什么区别?
GET和POST有什么区别?
GET和POST有什么区别?