详解js的延迟对象、跨域、模板引擎、弹出层、AJAX【附实例下载】

前端之家收集整理的这篇文章主要介绍了详解js的延迟对象、跨域、模板引擎、弹出层、AJAX【附实例下载】前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

目录

一、AJAX示例

1.1、优点

1.2、缺点

1.3、jQuery AJAX示例

二、延迟对象(Deferred)

2.1、回调函数

2.2、deferred.done

三、跨域

3.1、什么是跨域

3.2、JSONP跨域

3.3、jQuery使用JSONP跨域

3.4、跨域资源共享(CORS)

3.5、小结

四、弹出层

五、模板引擎

  • 5.1、Hello World
  • 5.2、方法
  • 5.3、与AJAX结合应用

六、示例下载

一、AJAX示例

AJAX全称为“Asynchronous JavaScript And XML”(异步JavaScript和XML) 是指一种创建交互式网页应用的开发技术、改善用户体验,实现无刷新效果

1.1、优点

不需要插件支持

优秀的用户体验

提高Web程序的性能

减轻服务器和带宽的负担

1.2、缺点

浏览器对XMLHttpRequest对象的支持度不足,几乎所有浏览器现在都支持

破坏浏览器“前进”、“后退”按钮的正常功能,可以通过简单的插件弥补

搜索引擎的支持不足

1.3、jQuery AJAX示例

在HTML5中对原生的AJAX核心对象XMLHttpRequest进行升级,也就是XHR2,功能更加强大。

jQuery对AJAX封装的非常好,这里以简单的商品管理为示例使用jQuery完成AJAX应用。

Product.java bean:

名称 */ private String name; /** 价格 */ private double price; /** 图片 */ private String picture; /** 详细 */ private String detail; @Override public String toString() { return "Product [id=" + id + ",name=" + name + ",price=" + price + ",picture=" + picture + ",detail=" + detail + "]"; } public Product(int id,String name,double price,String picture) { super(); this.id = id; this.name = name; this.price = price; this.picture = picture; } public Product(int id,String picture,String detail) { super(); this.id = id; this.name = name; this.price = price; this.picture = picture; this.detail = detail; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String getPicture() { return picture; } public void setPicture(String picture) { this.picture = picture; } public String getDetail() { return detail; } public void setDetail(String detail) { this.detail = detail; } }

IProductService.java:

getAll(); /**添加 * @return */ boolean add(Product entity); /**根据编号获得产品对象*/ Product findById(int id); /**根据编号获得产品对象 * @return */ boolean deleteById(int id); }

ProductService.java:

products; static { products = new ArrayList<>(); Random random = new Random(); for (int i = 1; i <= 10; i++) { Product product = new Product(i,"华为Mate9MHA-AL00/4GB RAM/全网通华为超级闪充技术双后摄设计" + random.nextInt(999),random.nextDouble() * 1000,"pic(" + i + ").jpg","产品详细"); products.add(product); } } /* * (non-Javadoc) * * @see com.gomall.service.IProductService#getAll() */ @Override public List getAll() { return products; } /* * (non-Javadoc) * * @see com.gomall.service.IProductService#add(com.gomall.bean.Product) */ @Override public boolean add(Product entity) { try { entity.setId(products.size() + 1); entity.setPicture("pic(" + entity.getId() + ").jpg"); // uploadify // 上传图片 products.add(entity); } catch (Exception e) { e.printStackTrace(); return false; } return true; } /* * (non-Javadoc) * * @see com.gomall.service.IProductService#findById(int) */ @Override public Product findById(int id) { for (Product product : products) { if (product.getId() == id) { return product; } } return null; } /* * (non-Javadoc) * * @see com.gomall.service.IProductService#deleteById(int) */ @Override public boolean deleteById(int id) { try { Product product = findById(id); if (product != null) { products.remove(product); } } catch (Exception e) { e.printStackTrace(); return false; } return true; } }

ProductAction.java:

添加CORS信息*/ response.addHeader("Access-Control-Allow-Origin","*"); response.addHeader("Access-Control-Allow-Methods","GET,POST"); String json = mapper.writeValueAsString(productService.getAll()); out.append(json); } else if(act.equals("del")){ /**向响应的头部中添加CORS信息*/ response.addHeader("Access-Control-Allow-Origin",POST"); int id=Integer.parseInt(request.getParameter("id")); String json = mapper.writeValueAsString(productService.deleteById(id)); out.append(json); } else if(act.equals("add")){ /**向响应的头部中添加CORS信息*/ response.addHeader("Access-Control-Allow-Origin",POST"); String name=request.getParameter("name"); double price=Double.parseDouble(request.getParameter("price")); String detail=request.getParameter("detail"); Product entity=new Product(0,name,price,"",detail); String json = mapper.writeValueAsString(productService.add(entity)); out.append(json); } } protected void doPost(HttpServletRequest request,IOException { doGet(request,response); } }

运行结果:

删除

二、延迟对象(Deferred)

deferred对象就是jQuery1.5版以后新增加的回调函数解决方案。

2.1、回调函数

先看一个示例:

首先,为什么要使用Deferred?

<Meta charset="UTF-8"> 回调

student.json文件:{"name":"tom","id":"01"}

运行结果:

因为AJAX是异步执行的,类似高级语言中的多线程,当发起ajax请求时会有网络延迟,而代码并没有在$.get的位置被阻塞,alert先执行,但数据并没有从远程获取到,所以结果是undefined。

其实初学者经常会犯这种错误,如:

上面的代码是有问题的,原因如前面的示例是一样的。怎么解决,如果你认为是异步带来的问题,当然通过同步是可以解决的,如:

结果:

如果将所有的ajax请求修改为同步的,则ajax的好处就大打折扣了,如果即要异步又要解决上面的问题,可以使用回调方法

示例:

<Meta charset="UTF-8"> 回调

结果:

从这里看回调很完美,其实不然,实际开发中要复杂得多,如当第一个ajax请求完成才可以完成第二个,当第二个完成才可以完成第三个,可能最一个请求要等前面的所有请求都成功时才允许执行或才有条件执行,如

使用ajax编辑用户信息,先加载用户对象,再加载省,加载市,加县,可能代码会这样写:

当回调越来越多,嵌套越深,代码可读性就会越来越差。如果注册了多个回调,那更是一场噩梦,幸好从jQuery1.5开始出现了延迟对象(deferred),可以解决这个问题。

2.2、deferred.done

$.ajax()操作完成后,如果使用的是低于1.5.0版本的jQuery,返回的是XHR对象,你没法进行链式操作;如果高于1.5版,返回的是deferred对象,可以进行链式操作。

当延迟成功时调用一个函数或者数组函数功能与原success类似。

语法:deferred.done(doneCallbacks[,doneCallbacks])

返回值:Deferred Object

该参数可以是一个函数或一个函数的数组。当延迟成功时,doneCallbacks被调用。回调执行是依照他们添加的顺序。一旦deferred.done()返回延迟对象,延迟对象的其它方法也可以链接到了这里,包括增加.done()方法。当延迟解决,doneCallbacks执行使用参数提供给 resolve或 resolveWith方法依照添加的顺序调用

示例代码

<Meta charset="UTF-8"> 延迟对象(deferred)

运行结果:

2.3、deferred.fail

语法:deferred.fail(failCallbacks[,failCallbacks])

返回值:Deferred Object

当延迟失败时调用一个函数或者数组函数功能与原回调方法error类似。

该参数可以是一个函数或一个函数的数组。当延迟失败时,doneCallbacks被调用。回调执行是依照他们添加的顺序。一旦deferred.fail()返回延迟对象,延迟对象的其它方法也可以链接到了这里,包括增加.done()方法。当延迟解决,doneCallbacks执行使用参数提供给 resolve或 resolveWith方法依照添加的顺序调用

示例:

<Meta charset="UTF-8"> 延迟对象(deferred)

运行结果:

2.4、deferred.always

语法:deferred.always(alwaysCallbacks,[alwaysCallbacks])

返回值:Deferred Object

当递延对象是解决(成功,resolved)或拒绝(失败,rejected)时被调用添加处理程序,与回调方法complete类似。

示例:

<Meta charset="UTF-8"> 延迟对象(deferred)

运行结果

成功时:

失败时:

2.5、deferred.then

deferred.then(doneFilter [,failFilter ] [,progressFilter ])

添加处理程序被调用时,递延对象得到解决或者拒绝,一次指定多个事件。

所有三个参数(包括progressCallbacks ,在jQuery的1.7 )可以是一个单独的函数或一个函数的数组。 其中一个参数,也可以为空,如果没有该类型的回调是需要的。或者,使用.done()或.fail()仅设置doneCallbacks或failCallbacks。当递延解决,doneCallbacks被调用。若递延代替拒绝,failCallbacks被调用。回调按他们添加的顺序执行。一旦deferred.then返回延迟对象,延迟对象的其它方法也可以链接到了这里,包括增加.then()方法

示例:

<Meta charset="UTF-8"> 延迟对象(deferred)

结果:

2.6、应用延迟对象

前面的示例中我们都是使用jQuery ajax返回的deferred对象,其实我们也可以在自定义代码中使用deferred对象,恰当的使用deferred对象或以优雅的解决不少问题。

示例:

<Meta charset="UTF-8"> 延迟对象(deferred)

失败时:

成功时:

promise()在原来的deferred对象上返回另一个deferred对象,后者只开放与改变执行状态无关的方法(比如done()方法和fail()方法),屏蔽与改变执行状态有关的方法(比如resolve()方法和reject()方法),从而使得执行状态不能被改变。

2.7、总结

(1) 生成一个对象。  

  • 指定操作成功时的回调函数  
  • 指定操作失败时的回调函数  
  • 没有参数时,返回一个新的对象,该对象的运行状态无法被改变;接受参数时,作用为在参数对象上部署接口。  
  • 手动改变对象的运行状态为已完成,从而立即触发方法。  
  • 这个方法与正好相反,调用后将对象的运行状态变为已失败,从而立即触发方法。  
  • .Deferred()生成一个deferred对象。  

(2)deferred.done()指定操作成功时的回调函数  

(3)deferred.fail()指定操作失败时的回调函数  

(4)deferred.promise()没有参数时,返回一个新的deferred对象,该对象的运行状态无法被改变;接受参数时,作用为在参数对象上部署deferred接口。  

(5)deferred.resolve()手动改变deferred对象的运行状态为"已完成",从而立即触发done()方法。  

(6)deferred.reject()这个方法与deferred.resolve()正好相反,调用后将deferred对象的运行状态变为"已失败",从而立即触发fail()方法。  

(7).when() 为多个操作指定回调函数。 除了这些方法以外,deferred对象还有二个重要方法,上面的教程中没有涉及到。

(8)deferred.then() 有时为了省事,可以把done()和fail()合在一起写,这就是then()方法。 如果then()有两个参数,那么第一个参数是done()方法的回调函数,第二个参数是fail()方法的回调方法。如果then()只有一个参数,那么等同于done()。

(9)deferred.always() 这个方法也是用来指定回调函数的,它的作用是,不管调用的是deferred.resolve()还是deferred.reject(),最后总是执行。

三、跨域

互联网上的主机由IP来标识,为了方便记忆,创建了域名系统.域名与IP对应,域名的作用是不用让你记复杂的IP地址,能唯一定位资源,URL的格式是协议://主机名.公司名称.机构类型.地域类型:端口/路径,如

3.1、什么是跨域

JavaScript同源策略的限制,A域名下的JavaScript无法操作B或是C域名下的对象,如下所示:

假设页面:

客户端代码d05.html,

6.4.9、跨域AJAX请求

6.4.9、跨域AJAX请求

另一个域下面一般处理程序,

/// 根据用户编号获得用户 /// public class FindUserById : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; String name = ""; int id = Convert.ToInt32(context.Request.Params["id"]); if (id == 1001) { name = "Mark"; } else if (id == 1002) { name = "Jack"; } context.Response.Write(name); } public bool IsReusable { get { return false; } } } }

运行结果:

3.2、JSONP跨域

JSONP跨域是利用script脚本允许引用不同域下的js实现的,将回调方法带入服务器,返回结果时回调。

2.1、JSONP跨域原理

客户端:

运行结果:

在jQuery中如果使用JSONP只需要将返回数据类型设置为jsonp就可以了,但是这种方法支持get请求,不支持post请求;请求是同步的;服务器返回数据要处理,要添加回调函数,麻烦。

3.4、跨域资源共享(CORS)

跨域资源共享(CORS)是一种网络浏览器的技术规范,它为Web服务器定义了一种方式,允许网页从不同的域访问其资源。

CORS与JSONP相比:

1、 JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。 2、 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。 3、 JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS。

CORS有两种模型可以实现:

1.简单模型

支持get/post/put/delete请求,例如返回Access-Control-Allow-Origin:*,但是不允许自定义header且会忽略cookies,且post数据格式有限制,只支持‘text/plain','application/x-www-urlencoded'and'multipart/form-data',其中'text/plain'默认支持,后面两种需要下面的预检请求和服务器协商。

2.协商模型/预检请求(Preflighted Request)

举例:浏览器发出PUT请求,OPTION请求返回Access-Control-Allow-Origin:*,Access-Control-Allow-Methods:'PUT',服务器同意所有域的PUT请求,浏览器收到并继续发出真正的PUT请求,服务器响应并再次返回Access-Control-Allow-Origin:*,允许浏览器的脚本执行服务器返回的数据。

response.addHeader("Access-Control-Allow-Origin","");

Access-Control-Allow-Origin:允许跨域访问的域名,如果是公共的则返回*即可

response.addHeader("Access-Control-Allow-Methods",POST,OPTIONS");

Access-Control-Allow-Methods:允许跨域访问的谓词(方法),如GET,DELETE,PUT(REST)

.Net服务器一般处理程序代码:

/// FindUserById 的摘要说明 /// public class FindUserById : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; context.Response.Headers.Add("Access-Control-Allow-Origin","*"); context.Response.Headers.Add("Access-Control-Allow-Methods",POST"); String name = ""; int id = Convert.ToInt32(context.Request.Params["id"]); if (id == 1001) { name = "Mark"; } else if (id == 1002) { name = "Jack"; } context.Response.Write(name); } public bool IsReusable { get { return false; } } } }

客户端脚本:

6.4.9、跨域AJAX请求

6.4.9、跨域AJAX请求

运行结果:

从上图可以看到实现跨域且为异步请求。

Java Servlet后台脚本:

String json = mapper.writeValueAsString(productService.getAll());
out.append(json);
}
}
protected void doPost(HttpServletRequest request,response);
}
}

客户端代码:

AJAX

运行结果:

2.4、CORS跨域的问题

a)、如果认为每次需要修改HTTP头部比较麻烦,在java中可以使用过滤器,.Net可以使用Module或HttpHandler全局注册(注册到Web.Config中,部署时还需要注意)。

b)、如果需要考虑IE8实现CORS则要插件支持,因为IE8并没有完全支持CORS。

插件名称:javascript-jquery-transport-xdr

github:

示例代码

<Meta charset="UTF-8"> AJAX

运行结果:

支持CORS跨域的过滤器,详细说明:

3.5、小结

当然除了兼容老浏览器的jsonp跨域与HTML5中的CORS跨域还有很多其它办法如利用iframe和location.hash、window.name实现的跨域数据传输、使用HTML5 postMessage、利用flash等办法。个人认为CORS应该才是未来主要的跨域选择,其它的方法都只是hack。

四、弹出层

前面AJAX示例中添加功能如果放在一个弹出层中布局会更加紧凑一些,像登录,提示信息经常会需要弹出层。

常见的弹出层有:FancyBox,LightBox,colorBox,artDialog,BlockUI,Layer等,这里介绍腾讯开源的artDialog,轻量,实用。

artDialog是一个设计得十分巧妙的对话框组件,小巧身材却拥有丰富的接口与漂亮的外观。

特点是自适应内容、优雅的接口、细致的体验、跨平台兼容、轻量实用。

项目源码:

帮助信息:

文档与示例:

AngularJS 版本:

使用方法:

artDialog

运行结果:

属性:

',// 标题 title: '',// 对话框状态栏区域 HTML 代码 statusbar: '',// 自定义按钮 button: null,// 确定按钮回调函数 ok: null,// 取消按钮回调函数 cancel: null,// 确定按钮文本 okValue: 'ok',// 取消按钮文本 cancelValue: 'cancel',cancelDisplay: true,// 内容宽度 width: '',// 内容高度 height: '',// 内容与边界填充距离 padding: '',// 对话框自定义 className skin: '',// 是否支持快捷关闭(点击遮罩层自动关闭) quickClose: false,// css 文件路径,留空则不会使用 js 自动加载样式 // 注意:css 只允许加载一个 cssUri: '../css/ui-dialog.css',

事件:

/**

  • 显示对话框(模态)
  • @name artDialog.prototype.showModal
  • @param {HTMLElement Object,Event Object} 指定位置(可选)
    */

/**

  • 关闭对话框
  • @name artDialog.prototype.close
  • @param {String,Number} 返回值,可被 onclose 事件收取(可选)
    */

/**

  • 销毁对话框
  • @name artDialog.prototype.remove
    */

/**

  • 重置对话框位置
  • @name artDialog.prototype.reset
    */

/**

  • 让对话框聚焦(同时置顶)
  • @name artDialog.prototype.focus
    */

/**

  • 让对话框失焦(同时置顶)
  • @name artDialog.prototype.blur
    */

/**

  • 添加事件
  • @param {String} 事件类型
  • @param {Function} 监听函数
  • @name artDialog.prototype.addEventListener
    */

/**

  • 删除事件
  • @param {String} 事件类型
  • @param {Function} 监听函数
  • @name artDialog.prototype.removeEventListener
    */

/**

  • 对话框显示事件,在 show()、showModal() 执行
  • @name artDialog.prototype.onshow
  • @event
    */

/**

  • 关闭事件,在 close() 执行
  • @name artDialog.prototype.onclose
  • @event
    */

/**

  • 销毁前事件,在 remove() 前执行
  • @name artDialog.prototype.onbeforeremove
  • @event
    */

/**

  • 销毁事件,在 remove() 执行
  • @name artDialog.prototype.onremove
  • @event
    */

/**

  • 重置事件,在 reset() 执行
  • @name artDialog.prototype.onreset
  • @event
    */

/**

  • 焦点事件,在 foucs() 执行
  • @name artDialog.prototype.onfocus
  • @event
    */

/**

  • 失焦事件,在 blur() 执行
  • @name artDialog.prototype.onblur
  • @event
    */

该插件使用比较简单,可以看示例与源代码。

五、模板引擎

在AJAX示例中javascript中有大量的html字符串,html中有一些像onclick样的javascript,这样javascript中有html,html中有javascript,代码的偶合度很高,不便于修改与维护,使用模板引擎可以解决问题。

模板引擎(这里特指用于Web开发的模板引擎)是为了使用户界面与业务数据(内容)分离而产生的,它可以生成特定格式的文档,用于网站的模板引擎就会生成一个标准的HTML文档。前后端都有模板引擎,比如T4、FreeMarker、Velocity,这里主要讲前端模板引擎:

上图是常见的一些前端模板引擎,速度相对快的是artTemplate,与artDialog是同一个作者,当然一个好的模板引擎不仅是速度还有很多方面都关键。

源码与帮助:

5.1、Hello World

示例代码

<Meta charset="UTF-8"> artTemplate

<script type="text/html" id="template2">
$$each hobbies as hobby index##

  • $$index+1## $$#hobby##
  • $$/each##

    运行结果:

    5.3、与AJAX结合应用

    示例脚本:

    <Meta charset="UTF-8"> 商品管理