EasyOPOA 框架使用手册

Please enter OPOA in English Version.

EasyOPOA是一个进行OPOA程序开发的框架,为OPOA程序开发定义出了一套完整的标准概念和规范。仅需几步简单的配置即能够快速、灵活的开发出优质的OPOA程序。能帮你简单快速的构建出像Gmail一样的复杂单页面程序。

OPOA(One Page,One Application),又叫Single Page Application,是目前流行的在单个页面利用Ajax来完成所有请求处理的设计和开发方式。拥有加载速度快、节省流量、高效、利于设计等诸多优点。

OPOA开发的核心是Ajax,由于Ajax本身对于地址不更新的特点。开发OPOA程序还要考虑到动作定位和前进后退两大问题。动作定位主要通过location.hash完成,前进后退需要History API的协助。
除了客户的体验之外,对搜索引擎的友好也相当重要,由于现有的搜索引擎技术并不会从Ajax中加载内容,不同hash锚记的内容会被忽略,所以采取了OPOA设计的Web程序,由于只有一个页面,搜索引擎根本无法爬取到Ajax加载的信息内容,无法收录,不利于SEO,影响了OPOA的实用性。

这些不同传统客户体验的问题,既影响了用户对OPOA程序更好的使用感受,也影响了OPOA的实用性。

EasyOPOA 开发框架主要特点:

  1. 支持动作定位,解决了OPOA程序的动作定位问题,能够实现存书签存储,使用户可以收藏分享链接。能够在同一个URL下通过不同hash动作加载不同请求。

  2. 支持浏览器前进后退,解决OPOA程序利用浏览器前进后退问题(需要HTML5支持,低版本浏览器采取hash兼容策略,使用者完全透明化)。

  3. 支持搜索引擎对OPOA程序的内容抓取和收录,解决了OPOA程序的在搜索引擎中无法抓取的难点。结合RSP(Rich Server Page,富服务器端页面设计/胖服务器端设计,与传统OPOA的瘦服务器端设计对应)设计可提供更友好的SEO优化方案。

  4. 支持在One Page页面多个不同区域实现OPOA,可以在一个页面的不同区域使用多个独立OPOA程序。

  5. 支持在动作中使用数据参数(路由配置),让动作匹配更加灵活,在客户端实现RESTful风格的高级动作自定义。

  6. 支持动作记忆功能,能够记录最后访问的动作,实现OPOA动作恢复。

  7. 支持AMD规范

  8. 同时兼容各种浏览器(Trident、Gecko、Webkit、Presto),支持多系统和平台应用(PC,TabletPC,Mobile)。

使用框架编程有助于将公共问题统一解决,在大项目时能构建更加有序、统一、标准的项目;在框架一定的基础之上进行开发,能将开发精力更多集中在具体业务上。也对程序日后的拓展和维护有很大帮助。

EasyOPOA 框架让OPOA程序的具体内部结构对开发和使用者完全透明,同时它既满足了客户对传统Web应用的使用感受的需要,又能将开发人员从繁琐混乱没有标准的的OPOA程序抽离,带来良好的使用体验,同时兼顾对搜索引擎的友好。

EasyOPOA 秉承了作者始终坚持的“More Easy, More Powerful.”追求理念:轻量,简单,灵活,全面。在提供强大全面功能的前提下并未限制使用者在开发上的灵活性。

Fork me on github

1、EasyOPOA 框架核心介绍

EasyOPOA框架从全局层面深度剖析和全新理解了OPOA程序,为OPOA程序开发定义出了一套完整的标准概念和规范。面对传统OPOA开发,EasyOPOA框架化无序为有序,化分散为集中,化混乱为统一,为OPOA层面的程序开发提供灵活全面的框架层支持。

EasyOPOA框架对传统无序的OPOA程序开发进行了高度抽象,将EasyOPOA中的每一个请求看作一个“Hash动作实例(Hash Action Instance)”,并把与请求相关的配置以“OPOA实例(OPOA Instance)”的形式封装。

EasyOPOA frameWork structure

Hash动作实例(Hash Action Instance)是EasyOPOA框架的的核心对象,EasyOPOA中要执行的每一个请求都是一个“Hash动作实例(Hash Action Instance)”,每一个Hash动作实例(Hash Action Instance)都由hashurlOPOAInstance三个相关部分组成:

{
    hash : [ url, OPOAInstance ]
};

hash:Hash动作名称(也叫动作hash),字符串。是EasyOPOA触发Hash动作实例的唯一标识,在EasyOPOA中,所有的请求,都是通过hash来进行触发。

url:定义动作要加载的URL请求,字符串。

OPOAInstance:OPOA实例,定义了当动作执行时,加载请求、渲染页面的方式和细节参数。

完成一个Hash动作实例的三个步骤:

EasyOPOA Hash Action Instance work

1、使用hash触发Hash动作实例(hash值会显示在浏览器URL中#hash

http://domain/home.jsp#hash

2、动作实例后台自动使用Ajax请求url

http://domain/hash

3、根据opoaInstance(OPOA实例)加载和渲染

OPOA实例(OPOA Instance)是Hash动作实例的组成部分之一。描述了动作执行时,对url请求加载和渲染过程中的方式和具体细节。

一个OPOA实例对象包含12个与Ajax请求和页面渲染相关的属性:actionsshowhashurlfindnotfoundmethodpushHashpreventactionMapsurlErrorsloading

opoa实例默认定义:

var opoa = {
    // jQuery的DOM选择器,让DOM具有动作触发能力,自动创建Hash动作实例
    // 单击(click)该DOM元素时即会触发一个Hash动作实例
    // (可从选择的DOM中获得'Hash动作实例'所需的hash,url)
    // (结合当前opoa实例,自动创建DOM点击时触发的'Hash动作实例')
    // 例如,通过该参数选择菜单选项,让OPOA程序的菜单选项能够触发Hash动作实例
    "actions" : null,
    // jQuery的DOM选择器,显示从请求的url加载到的内容
    // 将动作请求url返回的结果显示到选择器指定的区域
    "show" : null,
    // 从DOM节点中获取'Hash动作实例'的hash值的DOM属性名称
    // 默认值:hash
    "hash" : "hash",
    // 从DOM节点中获取'Hash动作实例'的url值的DOM属性名称
    // 默认值:hash (url值默认也等同于hash值)
    "url":"hash",
    // 从服务器获得的数据中,利用find指定的jQuery DOM选择器筛选出指定区域的数据
    // 例如,从服务器中返回的数据中仅获取某个DIV中的内容
    "find" : null,
    // 当find参数的选择器,没有从服务器返回的数据中找到内容时,显示的内容
    // 可选值为"empty","all","自定义内容",function
    // "empty" 显示空内容
    // "all" 显示加载到的所有数据
    // "自定义内容" 将自定义内容的内容显示(可使用消息或图片提示用户)
    // function 执行该函数
    // 默认值:empty
    "notfound" : "empty",
    // 对url进行Ajax请求的具体方式 :post/get
    // post方式会自动将url请求后的参数转换为post参数发送
    // 默认值:post
    "method" : "post",
    // 是否改变浏览器地址栏的hash,用来定位动作
    // 在支持HTML5的浏览器可以实现基于hash的前进后退
    // 如果设为false,则加载内容时不会记录点击的动作,浏览器地址栏不会改变
    // 默认值:true
    "pushHash" : true,
    // 阻止默认事件动作。如A标签点击时不触发href
    "prevent" : true,
    // 使用actionMaps修改指定hash对应的默认url为其他值
    // Hash动作映射的`opoaInstance`默认即为当前opoa对象this
    "actionMaps" : {
        // "hash":"url",
        // "demo":"demo.jsp"
    },
    // 当对url的请求从服务器端返回错误代码时,如何处理
    // 一组数值的HTTP代码和函数对象,当响应时调用了相应的代码。
    "urlErrors" : {
        // 如果执行的动作发生404错误时,如何处理
        // 默认:如果发生404加载错误,页面不会有任何响应
        404 : function() {
        },
        // 如果执行的动作发生500错误时,如何处理
        // 默认:如果发生500加载错误,页面不会有任何响应
        500 : function() {
        }
        // 也可定义其他状态
    },
    // 在ajax请求的不同状态时分别调用的函数,可用来进行loading提示
    "loading" : {
        // ajax请求开始
        "start" : function(hash, url, opoa, postData) {
        },
        // ajax请求成功
        "success" : function(hash, url, opoa, postData) {
        },
        // ajax请求出错
        "error" : function(hash, url, opoa, postData) {
        },
        // ajax请求结束(无论成功失败都会调用)
        "end" : function(hash, url, opoa, postData) {
        }
    }
};

EasyOPOA.Configs全局配置对象

EasyOPOA.Configs保存了OPOA实例属性全局的默认值。

所以,以上OPOA实例配置参数的全局默认值,均可以通过EasyOPOA.Configs来重新设置,示例:

// 如果从服务器返回的数据中没有找到find指定的内容,则显示所有
EasyOPOA.Configs.notFound="all";
// 获取url值的DOM属性
EasyOPOA.Configs.url="href";
    ...

2、EasyOPOA框架快速开发

OPOA首页home.jsp:

<body>
    <!-- 头部DIV -->
    <div id="headDIV">
        <h1>EasyOPOA开发框架</h1>
        <h3>实现浏览器前进后退,仅在HTML5下支持</h3>
    </div>
    <!-- 菜单DIV -->
    <div id="menuDIV">
        <!-- 增加href,指向对应的真实抓取地址 -->
        <a class="menu" hash="demo.jsp">实例</a> 
        <a class="menu" hash="readme.jsp"说明文档</a> 
        <a class="menu" hash="about.jsp">关于</a>
    </div>
    <!-- 内容DIV -->
    <div id="contentDIV">
        <h1>欢迎使用!</h1>
    </div>
    <!-- 底部DIV -->
    <div id="footDIV">
        © 2013 - 2014 Ray <br /> Email:<a href="mailto:inthinkcolor@gmail.com">inthinkcolor@gmail.com</a>
    </div>
</body>

OPOA的主页面home.jsp结构非常清晰和简单,点击菜单,加载内容,显示在内容DIV中。实例说明文档关于三个菜单分别对应加载demo.jspreadme.jspabout.jsp的内容(url值默认和hash值一致)。

这里由于OPOA程序是使用Ajax进行内容加载,所以菜单的A标签并没有使用href属性来跳转,而是添加了一个hash属性,指定了要加载的不同动作,DOM对象的hash属性的值会作为Hash动作实例的hashurl。同样,由于并不利用和依赖A标签的href属性,可以使用任意标签来触发动作,如DIV也可以作为菜单。

class=”menu”可以标识这是一个可点击的菜单,便于后面利用jQuery对菜单项进行筛选,利用EasyOPOA框架进行自动Hahs动作触发绑定。

OPOA首页home.jsp实例使用到的CSS:

<style type="text/css">
    *{ margin: 0; padding: 0; }

    #headDIV { margin-top: 0; height: 100px; background-color: #008400; color:#fff; text-align: center; line-height: 50px; }

    #menuDIV { margin: 20px auto; height: 50px; border-bottom: 1px solid #ddd; text-align: center; }
    #menuDIV A { margin: 10 30px; color: #0084C6; text-decoration: underline; font-weight: bold; font-size: 24px; cursor: pointer; }
    #menuDIV A:hover { color: #840000; text-decoration: none; font-weight: bold; font-size: 24px; cursor: pointer; }

    #footDIV { padding-top: 10px; border-top: 1px solid #ddd; text-align: center; line-height: 28px; }
    #footDIV A { color: #007BC3; }
</style>

html菜单加载的页面内容:

demo.jsp:

<h1 style="color: red">这是DEMO。</h1>

readme.jsp:

<h1 style="color: green">这是说明文档。</h1>

about.jsp:

<h1 style="color: blue">这是关于我们。</h1>

引入所需JS文件(EasyOPOA依赖jQuery进行DOM处理),使用EasyOPOA.start(opoaList)可初始化Hash动作实例,并直接启动OPOA程序。

opoaList:OPOA实例的集合(数组集合,对象集合)。

EasyOPOA框架启动代码:

<!-- 引入jQuery和EasyOPOA(EasyOPOA依赖jQuery进行DOM处理) -->
<script type="text/javascript" src="js/jquery-1.10.2.min.js"></script>
<script type="text/javascript" src="js/easy.opoa.min.js"></script>

<script type="text/javascript">
    //定义opoa实例
    var opoa={

        //触发Hash动作实例的DOM元素
        "actions":"#menuDIV .menu",

        //显示URL加载到内容的DOM元素
        "show":"#contentDIV"

    }

    //启动OPOA,参数为集合
    EasyOPOA.start([ opoa ]);
</script>

OPOA实例参数说明:

actionsshow是OPOA实例的两个核心参数。

actions:jQuery的DOM选择器,指定在EasyOPOA中具有触发Hash动作实例能力的DOM元素,自动创建Hash动作实例。让选择器指定的DOM元素在click单击时可以触发Hash动作实例。

<a class="menu" hash="readme.jsp">说明文档</a> 

触发的动作实例默认的hash值和url值均为当前DOM元素中hash属性(取决于EasyOPOA.Configs.hashEasyOPOA.Configs.href的值)的值。如上代码,由于EasyOPOA的EasyOPOA.Configs.hashEasyOPOA.Configs.href默认值为hash,则该DOM元素被单击时,触发的动作hash为readme.jsp,url也为readme.jsp

show:hash触发动作后请求url返回的结果,将渲染显示在show指定的DOM元素中。

EasyOPOA的初始化代码和start启动函数,并不强制要求必须在页面加载完成之后执行,也无需注册页面加载完成的事件处理函数来调用。可在任意位置编写。

只需要通过上面简单的几行代码,就已经实现了基于EasyOPOA框架的OPOA程序开发。

使用EasyOPOA设计不仅非常简单,还能够同时解决了两个OPOA程序设计的主要问题:

  1. 地址栏书签存储,动作定位问题

    当点击相应菜单,浏览器地址栏会在当前Home页面的链接home.jsp后添加不同hash值,代表不同请求:

     http://127.0.0.1:8080/opoa/home.jsp#demo.jsp
     http://127.0.0.1:8080/opoa/home.jsp#readme.jsp
     http://127.0.0.1:8080/opoa/home.jsp#about.jsp

    而用户存储书签后,可直接访问带有hash的链接。

    而通过在HOME首页请求后添加的不同hash值(#demo.jsp、#readme.jsp、#about.jsp),即可完成不同动作的请求定位。

  1. 浏览器前进后退(需要HTML5支持)

    EasyOPOA支持利用浏览器的前进后退按钮,来为用户提供与传统Web应用相同的客户体验感受。对于不支持HTML5的浏览器,EasyOPOA使用了兼容性做法,无需进行任何额外处理,完全透明,不影响程序使用。

3、增加搜索引擎抓取OPOA程序内容功能

除了解决动作定位和浏览器前进后退问题外,EasyOPOA在框架设计时,还考虑到了对搜素引擎的友好,解决了传统OPOA程序内容无法被搜索引擎抓取的问题。

解决这个问题,仅需改造一下菜单链接,为菜单链接添加
href属性,指向爬虫需要爬取的seURL(SearchEgine URL)即可。

<!-- 菜单DIV -->
<div id="menuDIV">
    <!-- 增加href,指向对应的真实抓取地址seURL(SearchEgine URL) -->
    <a class="menu" hash="demo.jsp" href="demo.jsp">实例</a> 
    <a class="menu" hash="readme.jsp" href="readme.jsp">说明文档</a> 
    <a class="menu" hash="about.jsp" href="about.jsp">关于</a>
</div>

这样搜索引擎爬到相应链接对href的地址进行访问就有可以抓取到与当前动作相关的具体内容(为了让爬虫能获得相关信息,服务器端还需提供与当前seURL(SearchEgine URL)请求相关的处理程序返回信息)

注意:添加的href属性定义的链接为seUrl(SearchEngine URL,搜索引擎爬取地址),并不会被EasyOPOA触发,也不会作为Hash动作实例触发时的url请求地址。该属性仅仅用做为搜索引擎爬虫提供相应爬取页面。

4、EasyOPOA中hash、url、seURL(SearchEngine URL)三者配置和关系:

EasyOPOA hash url seURL

一般情况,OPOA程序客户请求展示的url和服务器抓取内容的seURL应该是相同的(这样内容是一致的)。

设计原因:

由于利用Ajax请求数据,并不依赖A标签的href属性,所以任意元素(DIV,P,……)都可以通过单击触发Hash动作实例,完成请求加载。所以EasyOPOA通过hash动作的概念来定义触发请求的标识,然后利用内部的Hash动作映射列表将hash动作同请求的url行关联,可以避免依赖href,例如在DIV或Button上进行动作请求时就不必强迫用户为DIV和Button添加href属性。

同时,EasyOPOA采取这样的设计,可以让用户触发动作的hash值、背后Ajax执行的url请求值、搜索引擎爬取的seURL值三者完全无关(hashurlseURL可以相同也可以不同)。在高级应用中还可以让用户加载的请求及内容(url)与搜索引擎加载的请求及内容(seURL)不同,提供更灵活的个性化方案选择。

在EasyOPOA中href是一个完全可以省略的属性,但在A标签上使用href来指定服务器加载路径seURL能够让搜索引擎对OPOA程序的内容抓取和收录,解决了OPOA程序的在搜索引擎中无法收录问题,结合RSP可提供更友好的SEO优化。

5、使用RSP设计优化搜索引擎爬取

为了让搜索引擎在抓取内容时能获得到更多有意义的信息,例如网页关键字,描述等……服务器端对应的seURL页面可采取RSP设计,来提供更友好的搜索引擎优化方案。

RSP:Rich Server Page,富服务器端页面设计/胖服务器端设计,与传统的瘦服务器端设计对应。

例如,可以基于OPOA设计的传统demo.jsp页面:

<h1 style="color: red">这是DEMO。</h1>

转换为RSP设计的demo.jsp页面:

<html>
  <head>    
    <title>OPOA 演示DEMO</title>
    <meta http-equiv="keywords" content="easyopoa,opoa,demo,single page">
    <meta http-equiv="description" content="EasyOPOA 框架开发实例">
  </head>
  <body>
      <!--因为HTML页面只能有一个body,使用div包裹内容-->
      <div id="content">  
          <h1 style="color: red">这是演示DEMO。</h1>
      </div>
  <body>
</html>

这将有利于SEO和搜索引擎收录。

6、从RSP返回的数据中,筛选提取指定内容 find、notFound

在RSP设计时,服务器端返回的内容包含了一些与内容并非直接相关的信息。一般来说网页标题、关键字、描述等信息并不会对加载和显示造成任何影响。但如果在Ajax加载到信息后,希望剔除无用的标签项,或筛选提取出指定内容,可借助findnotFound参数实现。

find: jQuery DOM选择器,从服务器获得的数据中筛选出指定区域的数据

notFound:当find参数的选择器,没有从服务器返回的数据中找到内容时,显示的内容或调用的函数。有四个可选值”empty“,”all“,”自定义内容“,function。默认值:empty

7、EasyOPOA 首页(静态和动态)方案配置

常见的OPOA程序首页设计有两种模式:

  1. 静态首页(首页的页面内容为静态内容,要展示的内容直接写在内容区域)
    <!-- 静态内容DIV -->
    <div id="contentDIV">
        <h1>欢迎使用!</h1>
    </div>
  2. 动态首页(首页需要利用Ajax加载一个指定的请求,将请求返回的内容显示在内容区域)

    例如,首页加载时通过Ajax请求welcome.jsp,并将welcome.jsp的内容显示在内容区域。

    welcome.jsp:

    <h1>Welcome.欢迎使用EasyOPOA框架!</h1>

EasyOPOA框架对前进后退的处理:

当用户通过浏览器的前进后退按钮进行前进或返回时,在EasyOPOA中会自动触发和加载与当前hash相关的信息并自动显示,解决静态内容更新的问题。而对于首页的信息展示,EasyOPOA框架建议在EasyOPOA程序初始化时,根据首页模式指定具体的首页内容加载方案,以防止后退到首页时信息无法更新和加载。

8、EasyOPOA 框架在url请求时向服务器端提交参数数据

在EasyOPOA框架中可以向请求的url提交参数数据postData,有两种方法:

(postData选项是参数字符串,比如 key1=value1&key2=value2)

1.直接通过url?postdata实现:

EasyOPOA.home("welcome.jsp?user=jack&role=admin", opoa);

2.通过函数定义的postdata参数实现(EasyOPOA.home( url, opoa[, postData])):

EasyOPOA.home("welcome.jsp", opoa, "user=jack&role=admin");

以上两种方法也可以同时使用:

EasyOPOA.home("welcome.jsp?a=1&b=2", opoa, "user=jack&role=admin");

9、EasyOPOA 框架请求提交方式(post / get)设置

在EasyOPOA框架中请求url时,默认以post方式提交,通过method参数可以调整提交请求的方式。

如果提交方式为post:

在EasyOPOA框架内部,对post请求,会自动将所有url中的参数提取,并以post的方式提交。

例如,在post提交方式下,请求如下地址:

welcome.jsp?user=jack&role=admin

该url在Ajax请求时的地址为welcome.jsp,参数user=jack&role=admin并不会在请求的url后,而是以post方式提交。

10、opoaList OPOA实体集合定义

在EasyOPOA中,opoaList OPOA实体集合是框架启动的必须参数。EasyOPOA.start(opoaList)函数通过opoaList OPOA实体集合参数完成EasyOPOA框架的初始化工作。

EasyOPOA支持多种集合定义方式(数组集合和对象集合):

1.数组集合方式:

//opoa实例
var opoa={
    "actions":"#menuDIV .menu",
    "show":"#contentDIV"
}

//...

//数组集合opoa实例
var opoaList=[ opoa ,... ];

//使用opoaList启动
EasyOPOA.start(opoaList);

2.对象集合方式:

数组方式在从定义的列表中获取指定相关opoa实例时不够直观和方便,对象集合定义方式能够为不同功能和作用的OPOA实例指定名称,在其他动作引用opoa实例时会更方便:

//opoa实例
var opoa={
    "actions":"#menuDIV .menu",
    "show":"#contentDIV"
}

//....

//opoa实例对象集合
var opoaList={
    //为指定的opoa实例,指定名称为menu
    "menu":opoa,
    //...
}

//使用opoaList启动
EasyOPOA.start(opoaList);

使用opoaList.menu即可引用menu配置的opoa实例。

11、hash和url的动作映射配置

每一个Hash动作实例(Hash Action Instance)的结构都是通过动作映射对象(ActionMap Object)组织和保存(可以将Hash动作实例和动作映射对象看作同一回事,因为Hash动作实例本身就是通过动作映射对象定义和存储)。

一个标准的动作映射对象(ActionMap Object)的结构如下:

{
    hash: [ url, opoaInstance ]
}

其中一组的多个hash和url可以共享一个OPOA实例。

动作映射对象,负责将hashurlopoaInstance绑定在一定。完成一个Hash动作实例分为三步:

1、使用hash触发Hash动作实例(hash值会显示在浏览器URL中#hash

http://domain/home.jsp#hash

2、动作实例使用Ajax请求url

http://domain/hash

3、根据opoaInstance(OPOA实例)加载和渲染

opoa实例的actions属性使用DOM选择器,来设置DOM触发对象,并同时能自动从DOM的属性中获取所需的hash和url创建相应动作映射对象来定义Hash动作实例。除此之外,EasyOPOA还支持多种更加灵活的配置途径定义动作映射。

11.1. 使用DOM属性指定映射的hash和url

默认创建一个Hash动作实例的hashurl均为DOM的hash属性的值。这是由EasyOPOA.Configs中的默认配置定义和决定。

// 从DOM节点中获取'Hash动作实例'的hash值的DOM属性名称
// 默认值:hash
"hash":"hash",
// 从DOM节点中获取'Hash动作实例'的url值的DOM属性名称
// 默认值:hash (url值默认也等同于hash值)
"url":"hash",

修改hash和url配置可以让hash值和url的值来自不同属性。例如,让DOM对象的hash属性定义hash值,href属性定义url值。

<a class="menu" hash="demo" href="demo.jsp">实例2</a> 
<a class="menu" hash="readme" href="readme.jsp">说明文档</a>

11.2. 使用OPOA实例的actionMaps属性配置映射

actionMaps属性可修改指定hash对应的默认url为其他值。

默认情况下EasyOPOA根据当前DOM的hash属性值来创建Hash动作实例,其中Hash动作实例的hashurl的值均为DOM的hash属性值。如:

<a class="menu" hash="demo.jsp">实例</a>

默认动作映射为:

//{ hash : [url, opoaInstance] }

{"demo.jsp" : ["demo.jsp" , this]}

而使用actionMaps属性可修改指定hash对应的默认url为其他值。语法:

actionMaps: {
    // "hash名称" : "执行的url"
    "demo":"demo.jsp",
    "about":"about.jsp",
    //...
}

配置:

如下代码配置了将hash为demoreadme的DOM元素触发Hash动作实例执行的url。

var opoa={
    // 使用actionMaps修改指定hash对应的默认url为其他值
    actionMaps:{
        // "hash名称" : "执行的url"
        "demo":"demo.jsp",
        "readme":"readme.jsp"
    },
    actions:"#menuDIV .menu",
    show:"#contentDIV"
}

测试:

定义如下可触发Hash动作实例的超链接的hash分别为demo和readme:

<a class="menu" hash="demo" >实例2</a> 
<a class="menu" hash="readme">说明文档</a> 

点击实例2,浏览器地址栏为(hash为demo):

http://127.0.0.1:8080/opoa/home.jsp#demo
http://127.0.0.1:8080/opoa/home.jsp#readme

加载的请求为(请求为demo.jsp):

http://127.0.0.1:8080/opoa/demo.jsp
http://127.0.0.1:8080/opoa/readme.jsp

11.3. 直接使用addActionMap(hash,url,opoa)函数配置映射

修改指定hash对应的默认url为其他值,必须指定具体渲染相关的OPOA实例。

//hash, url, opoa
EasyOPOA.addActionMap("demo",  "demo.jsp" ,opoaList.menu);
EasyOPOA.addActionMap("readme",  "readme.jsp" ,opoaList.menu);

addActionMap函数还支持传入数组列表参数(动作映射元素可使用对象或数组表示):

语法:

[ 
    // 基于标准动作映射对象
    {hash: [ url, opoaInstance ]}, 
    {hash: [ url, opoaInstance ]}, 
    ... 
]

实例:

EasyOPOA.addActionMap([
    // 基于标准动作映射对象
    // {hash: [ url, opoaInstance ]}
    {"demo" : [ "demo.jsp" ,opoaList.menu]},
    {"readme" : [ "readme.jsp",opoaList.menu ]}
]);

语法:

[ 
    // 基于数组
    [hash, url, opoaInstance] , 
    [hash, url, opoaInstance] , 
    ... 
]

实例:

 EasyOPOA.addActionMap([
    // 基于数组
    // [hash, url, opoaInstance]
    ["demo", "demo.jsp", opoaList.menu],
    ["readme", "readme.jsp", opoaList.menu]
]);

11.4. 在start()启动函数中使用actionMaps参数

start(opoaList [, actionMaps ]):start启动函数有一个可选参数actionMaps,可以在启动时传入定义的映射对象。

actionMaps:可以为标准的动作映射对象或者数组列表参数(动作映射元素可使用对象或数组表示)。

//标准动作映射对象
var actionMap={"demo":[ "demo.jsp" ,opoaList.menu]};

//使用opoaList和actionMaps启动
EasyOPOA.start(opoaList,actionMap);
var actionMaps=[
    // 基于标准动作映射对象
    // {hash: [ url, opoaInstance ]}
    {"demo" : [ "demo.jsp" ,opoaList.menu]},
    {"readme" : [ "readme.jsp",opoaList.menu ]}
];

//使用opoaList和actionMaps启动
EasyOPOA.start(opoaList,actionMap);
var actionMaps2=[
    // 基于数组
    // [hash, url, opoaInstance]
    ["demo", "demo.jsp", opoaList.menu],
    ["readme", "readme.jsp", opoaList.menu]
];

//使用opoaList和actionMaps启动
EasyOPOA.start(opoaList,actionMap2);

12、指定获取hash值的DOM属性

默认情况下EasyOPOA框架启动时,会自动从OPOA实例的actions属性中获取选择器选择的DOM元素,绑定动作触发事件,并自动创建相应Hash动作实例。

在创建Hash动作实例时,默认的hashurl值与DOM的hash属性值相同。

<a class="menu" hash="demo.jsp">实例</a> 
<a class="menu" hash="readme.jsp">说明文档</a> 
<a class="menu" hash="about.jsp">关于</a>

如果在某些情况下,hash属性与其他元素冲突,或者想使用其他属性代替hash属性,则可以通过如下方法修改。

使用opoahash属性代替默认的hash进行定义:

    <a class="menu" opoahash="demo.jsp" href="demo.jsp">实例</a> 
    <a class="menu" opoahash="readme.jsp" href="readme.jsp">说明文档</a> 
    <a class="menu" opoahash="about.jsp" href="about.jsp">关于</a>

注意,在EasyOPOA框架内部,如果hash指定的属性没有找到,则会尝试加载href属性作为动作的hash值和url值。

13、无效hash动作定位处理函数notHash

有时候用户存储的书签或收藏的连接已经失效,或用户传入了无效未定义的hash动作。EasyOPOA框架会调用EasyOPOA.notHash(hash)函数处理(默认为空)。

如下,访问一个不存在的hash动作定位mydemo

http://127.0.0.1:8080/opoa/home.jsp#mydemo

此时可向EasyOPOA框架的notHash参数注册一个处理函数,函数的参数为当前用户请求的无效hash值:

EasyOPOA.notHash=function(hash){
    alter("您指定的动作‘"+hash+"’已经失效!");
    // EasyOPOA.load("welcome.jsp","");
}

注意,低版本IE(6,7,8)不支持console.info(),请更换为alter或其他方式后才可运行。

14、使用loading处理对象对Ajax请求状态管理

在Ajax应用开发中,由于浏览器并不刷新,所以在请求URL的过程中,使用文字或图片进行进行Loading加载提示对客户体验来说显得非常重要。也有一些情况下,当Hash动作请求加载完成后页面还需要执行新任务或完成一些内容的更新(例如加载完后,当前菜单状态要改变)。

EasyOPOA 框架支持定义loading处理对象(loadingObject)来进行状态管理,一个loading处理对象包含4个Ajax请求状态注册函数进行处理:请求开始(start)、请求成功(success,在渲染页面之前)、请求出错(error)、请求结束(end,无论成功失败都会调用)。在ajax请求的不同状态时分别调用的函数,可用来进行loading提示。

每个状态处理函数都可以传入四个可选参数:hash,url,opoa,postData
hash:当前触发动作的的hash值
url:当前请求的url
opoa:opoa实例
postData:向服务器提交的数据

语法:

// loading处理对象
"loading":{
    // ajax请求开始
    start:function(hash,url,opoa,postData){},
    // ajax请求成功
    success:function(hash,url,opoa,postData){},
    // ajax请求出错
    error:function(hash,url,opoa,postData){},
    // ajax请求结束(无论成功失败都会调用)
    end:function(hash,url,opoa,postData){}
}

提示:end状态处理函数常用来在请求加载完成后进行菜单状态更新,子页面动作初始化和启动等。

在页面内容DIVcontentDIV上定义一个显示Loading提示的loadingDIV

<!-- Loading提示DIV -->
<div id="loadingDIV" >
    <h1>Loading……</h1>
</div>

Ajax请求开始时显示LoadingDIV,请求结束后隐藏LoadingDIV。

15、使用loading对象处理url页面返回的动作

在实际OPOA开发和使用中,并不仅仅是简单的加载请求,从请求获得内容并显示出来而已。加载的请求返回的内容中往往可能也包含了新的触发EasyOPOA动作的DOM对象,需要通过start函数来初始化这些Hash动作实例。

16、对HTTP代码进行响应处理

除了要进行友好的Loading提示外,在Ajax请求过程中服务器可能产生错误,对于发生的不同错误也应当及时给用户给出必要提示。如,404代表请求没有找到,500代表服务器错误……

每一个提交的请求都会由服务器返回相应数值的HTTP代码,EasyOPOA使用urlErrors代表HTTP代码响应对象(urlErrors Object),支持在在返回不同HTTP代码时,调用相应函数响应。

17、EasyOPOA 框架手动hash动作触发 load

load函数可以让动作的触发的控制权受开发者管理。

一般默认情况下EasyOPOA框架可以自动管理动作的触发,之前的动作触发都是通过点击页面的DOM元素触发。如果要手动触发一个已定义的Hash动作实例,则使用EasyOPOA.load函数。

EasyOPOA.load(hash[, postData]):手动触发指定的hash动作,postData为可选的提交请求参数数据( key1=value1&key2=value2)。

注意:load函数必须在EasyOPOA框架调用start函数启动后(对Hash动作实例初始化完成)才能使用。

EasyOPOA.load("readme.jsp");

18、 执行hash动作链

load函数可以出发指定的一个动作,loadLinked函数可以按顺序连续加载多个动作,每个动作(hash)都在上一个动作完全完成后触发,并且支持在执行动作时附加提交请求参数(postData)。

EasyOPOA.loadLinked([ [hash, postData], [hash2, postData2], [hash3, postData3], ... ]);

手动按顺序加载指定的hash动作名称列表。可用来实现依次多级点击加载的效果。例如,加载一个hash请求内部启动的hash请求,需要依次加载。

 // 依次触发api、EasyImageUtilsAPI hash动作
 EasyOPOA.loadLinked([ [ "api" ], [ "EasyImageUtilsAPI", "lang=en&version=1.1" ] ]);

19、 初次Hash加载前置处理函数preFirstHash

EasyOPOA框架可以自动处理所有的浏览器地址中发生的hash动作,当引擎第一次处理浏览器中的hash动作时,可能会希望在解析hash动作前执行一些自定义的操作,甚至终止默认的解析。
例如,当加载一个hash动作,但该动作必须在某个动作执行之后才能执行时,可以终止默认的解析,手动进行动作解析。
preFirstHash函数包含一个第一次加载到的hash动作参数,能在第一次加载hash前执行,如果返回false还可以终止默认hash执行。

// 处理 API 菜单内的指定API动作加载
OPOA.preFirstHash = function(hash) {
         if (hash.indexOf("API") != "-1") {
               //加载对应API
               if (hash == "EasyImageUtilsAPI") {
                     // 依次触发api、EasyImageUtilsAPI hash
                     EasyOPOA.loadLinked([ [ "api" ], [ "EasyImageUtilsAPI" ] ]);
               } else if (hash == "EasyObjectUtilsAPI") {
                     EasyOPOA.loadLinked([ [ "api" ], [ "EasyObjectUtilsAPI" ] ]);
               } else if (hash == "EasyPropertiesUtilsAPI") {
                     EasyOPOA.loadLinked([ [ "api" ], [ "EasyPropertiesUtilsAPI" ] ]);
               }
               return false; //终止解析
         }
         return true; //正常解析
}

20、带参数的hash动作映射配置

传统的hash,默认hash值作为请求的url。如果hash和请求的url不一致,则需要使用addActionMap函数为每个hash单独指定具体的请求url。

例如:

<a class="menu" href="demo">实例</a>
// ...

EasyOPOA.addActionMap("demo",  "demo.jsp" ,opoaList.menu);
// ...

但如果hash为动态生成,并且和url不一致,请求的url需要从hash值中获得提交的参数数据,则通过这样的方法就非常不可行:

//定义的hash(demo/版本/标识)
<a class="menu" hash="demo/v1/123">实例A</a>
<a class="menu" hash="demo/v2/456">实例A</a>
// ...

//hash获得参数数值,转换为url(demo.jsp?v=版本&id=标识)
demo.jsp?v=v1&id=123
demo.jsp?v=v2&id=456
// ...


EasyOPOA 不仅为OPOA程序提供了加载引擎。还提供了灵活的动作配置,支持在动作中使用数据参数(路由配置),让动作匹配更加灵活,在客户端实现RESTful风格的高级动作自定义。


使用带数据参数的hash动作时,仅需在hash动作配置中指定占位符,在url中即可引用占位符对应的参数值。hash动作配置支持两种类型的占位符:

:param:参数占位符,冒号(:)开头,匹配斜线/之间的 URL 组件。

*splat:通配符占位符,星号(*)开头,匹配多个 URL 组件,支持匹配斜线/。

(如果你熟悉Backbone的Backbone.Router的话,这里的参数配置完全相同。)

21、动作定位的记忆功能(动作状态恢复)

当用户直接访问OPOA程序的home页面时,如 http://127.0.0.1:8080/opoa/home.jsp 时,一般每次都是加载显示相同的默认首页内容。

如果希望当用户下次访问home.jsp首页时,能为用户展示其上次最后所执行的动作内容,为用户提供动作状态的保存与恢复。则可在EasyOPOA框架中开启动作定位记忆功能。

EasyOPOA框架默认开启了动作记忆功能,仅需加入依赖的jquery.cookie.js和json2.js即可实现功能。

<!-- jquery.cookie和json2可选,如果要开启对最后动作定位的记忆功能,则需要引入 -->
<script type="text/javascript" src="js/jquery.cookie.js"></script>
<script type="text/javascript" src="js/json2.js"></script>

如果需要禁用动作记忆功能,移除js文件或将cookieLast设为false即可。

EasyOPOA.cookieLast=false;

22、EasyOPOA.noConflict非冲突对象返回函数

使用EasyOPOAOPOA全局变量均可引用EasyOPOA框架对象。

EasyOPOA.noConflict( [boolean] ):可以将EasyOPOA和OPOA的控制权释放,使用返回的结果引用EasyOPOA框架对象,防止与其他名为EasyOPOA或OPOA的对象发生冲突。

运行这个函数将变量OPOA的控制权让渡给第一个实现它的那个库。

var $OPOA=EasyOPOA.noConflict();

运行这个函数将变量OPOAEasyOPOA的控制权让渡给第一个实现它的那个库。

var $OPOA=EasyOPOA.noConflict(true);

23、prevent参数

prevent参数一般请勿修改,该参数为true,在动作触发时会取消DOM默认的动作。
例如:在点击超链标签时取消默认对href的跳转。

如需要修改,可通过全局设置:

EasyOPOA.Configs.prevent=false;

或opoa实例设置:

//opoa实例
var opoa={
    "actions":"#menuDIV .menu",
    "show":"#contentDIV",

    prevent:false;
}

24、模块化编程支持——AMD规范

EasyOPOA支持模块化编程, 并支持AMD(Asynchronous Module Definition,异步模块定义)规范。

EasyOPOA依赖jQuery,但并不绝对依赖jquery.cookiejson2(仅仅在需要使用动作记忆功能时需要)。

jQueryjquery.cookie内部都已经提供了对AMD规范的支持,但json2还并未支持任何规范。所以对于json2可以直接引入,或根据相应模块定义规范进行改造。

1、AMD支持

home.jsp:

<!-- 由于json2并未支持AMD规范,直接引入(也可自行改造,具体参见AMD规范) -->
<script type="text/javascript" src="js/json2.js"></script>
<!-- 加载主文件模块(入口模块) -->
<script src="amd/require.min.js" data-main="js/main_amd"></script>

js/main_amd.js:

//配置jquery和jqueryCookie路径
require.config({
    paths:{
        "jquery":"jquery-1.10.2.min",
        "jqueryCookie":"jquery.cookie"
    }
});

//引入依赖,加载模块(jqueryCookie为可选模块)
//EasyOPOA的引擎文件内部已经引用了jquery的依赖
//所以如果不需要在启动模块中使用jquery,也可以不引入jquery
require(['easy.opoa','jquery','jqueryCookie'],function(EasyOPOA,$){
    //……
}

WebRoot文件结构:

+amd
    require.min.js
+js
    main_amd.js
    jquery-1.10.2.min.js
    jquery.cookie.js
    json2.js

25、EasyOPOA和BackboneJS在OPOA系统构建时的比较

BackBoneJS也是一个进行OPOA程序设计的有利技术。使用EasyOPOA和BackBoneJS都可以完成OPOA程序的设计。

从设计角度:EasyOPOA侧重于为构建OPOA系统(System);而BackBoneJS侧重于利用前端MVC构建系统中的某个模块 (Module)。

从技术角度:EasyOPOA是一个纯粹的OPOA程序构建框架;而BackboneJS本质是一个前端JS的MVC框架,而非OPOA框架。

结束

如果您有更好意见,建议或想法,请联系我。

留言评论

联系、反馈、定制、培训 Email:inthinkcolor@gmail.com


支付宝钱包扫一扫捐助:

支付宝钱包扫一扫捐助