同步操作将从 南漂一卒/EasyWebApp 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
EasyWebApp 是一个基于 jQuery API 的 轻量级 SPA(单页应用)引擎, 网页设计、后端接口、前端组件 充分解耦 —— 只用 原生 HTML 做模板,对 JSON 数据的结构几无硬性要求,完全兼容现有的 jQuery 插件。
本引擎广泛使用的最新开源稳定版 v2.5 脱胎于 3 个 移动端网页应用(微信公众平台)和 3 个 桌面端网页系统(某公司开放平台),是一个有较高 抽象性、 普适性的 SPA 引擎, 个人独立开发、 团队协作开发 都能轻松胜任~
EasyWebApp 与其作者开发的 EasyWebUI(Web 前端 UI 框架)的理念一致 ——
充分利用 HTML 标签、属性 原生的语义、样式、功能,力求 Web 前端代码 表达上的简练、架构上的解耦!
这使得本引擎 ——
演示源码的授权协议与本项目的 开源协议一致 —— 自由使用、自主修改,保留署名、分享改进!
【实战项目】 EasyWiki(易维基)百科系统 —— http://git.oschina.net/Tech_Query/EasyWiki
iQuery.Observer()
重构到 WebApp 对象上$.CommonView()
抽象视图接口
_Data_Path_
、_Data_Name_
$.fn.dataRender()
、$.fn.dataReader()
,方便业务逻辑复用WebApp
对象继承 iQuery+ v1.4 内置的 $.EventInterface()
抽象接口,实现 事件多回调采用最后一次有效返回数据$.ajaxPrefilter()
统一处理#!
静态路径导航_File_Path_
、_File_Name_
、_Ext_Name_
)head > link
链接元素加载内页<link />
声明 多数据源
本节总述 EasyWebApp 建议的 SPA 开发流程,后面三节是本流程具体步骤的示例讲解 ——
本项目的开发最早基于 iQuery(相当于 jQuery v1.x 的精简与扩展),若要用 jQuery 官方版来驱动本引擎,需要同时加载 iQuery 项目中的 jQuery+.js 来启用扩展的 jQuery API(一些 jQuery 插件)。
本引擎 v1.3 开始支持的 MarkDown 规范代码渲染 还需要加载 marked.js(推荐引用 中国大陆 CDN)。
<!DocType HTML>
<html><head>
<meta http-equiv="X-UA-Compatible" content="IE=Edge, Chrome=1" />
<script src="path/to/iQuery.js"></script>
<script src="path/to/iQuery+.js"></script>
<script src="path/to/marked.js"></script>
<script src="path/to/EasyWebApp.js"></script>
<script>
$(document).ready(function () {
$('body > section').WebApp();
});
</script>
</head><body>
<header>
...
</header>
<section>
...
</section>
<footer>
...
</footer>
</body></html>
本引擎模板 把 HTML name 属性 推而广之,应用在任何 HTML 元素上,用作 JSON 数据的“ 键值对应”,自动填充 数据容器元素的 innerHTML
、value
、src
、href
乃至 background-image
,仅有很少的 宽松规范 ——
ul, ol, dl, tbody, select, datalist, *[multiple]:not(input)
的数据容器元素(有 name 属性的),其对应的数据结构是一个 以普通对象为元素的数组,其子元素(它也可以有子元素)只需有一个,引擎会自动复制这个子元素的作为 数组迭代的模板
<img src="" />
、<a href="" />
中,其次会尝试设为 枝节点元素(有子元素的)的 background-image,最后才会被赋给 叶节点元素(无子元素的)的 innerHTML<div multiple name="list" max="6">
<img name="avatar" />XXX
</div>
本引擎的网页模板不采用“自创模板语言”,而直接使用 原生 HTML 的常用属性 来标记引擎的特性 ——
SPA 链接元素 是指 —— 不限于 <a />
的 HTML 可见元素,在添加 SPA 专用属性后,将由 SPA 引擎响应 用户操作,执行 SPA 页面切换、接口调用、整页刷新 等程序逻辑,起到 传统网页中 <a />
的作用。
因此,直接用普通元素作为链接 ——
<a />
在部分老版移动浏览器上禁用默认事件行为无效的 Bug<script>
(function (BOM, $) {
$('body > section').WebApp()
.on('PageRender', 'page_1.html', function (iData, This_Page, Prev_Page) {
// iData 是 API 返回的 JSON,格式自定义,默认为 空对象
if (iData.code == 200)
return iData.data;
BOM.alert(iData.message);
BOM.history.go(-1);
});
})(self, self.jQuery);
</script>
<div target="_self" title="New Page" href="path/to/page_1.html"
src="path/to/data/api/{id}" data-arg_1="data_name_1">
<img src="path/to/logo.png" />XXX
</div>
【注】上述代码加载的内页 可以是 HTML 代码片段(包括 所有可见元素、style 元素),无需重复编码。
<script>
(function (BOM, $) {
$('body > section').WebApp()
.on('appExit', function () {
// 若 SPA 链接元素 是 form,则 iData 为 表单提交所返回的数据
iData = arguments[2];
if (iData.code > 200) {
alert(iData.message);
return false; // 阻止页面刷新、跳转
}
});
})(self, self.jQuery);
</script>
<div target="_top" href="path/to/page_2.html" data-arg_1="data_name_1">
<img src="path/to/logo.png" />XXX
</div>
<script>
(function ($) {
$('body > section').WebApp()
.on('apiCall', function () {
// iData 为 API 返回的数据
iData = arguments[1].data;
if (iData.code > 200)
alert(iData.message);
});
})(self.jQuery);
</script>
<button target="_blank" src="path/to/data/api/{id}" data-arg_3="data_name_3">
喜欢
</button>
【注】 纯 API 调用返回的数据 会合并到 当前内页的数据栈
若首屏渲染时的数据来自 HTTP API,则可复用“调用接口”功能的 HTML 语义,在 <head />
中用 <link />
声明数据来源即可 ——
<head>
...
<link target="_blank" src="path/to/data/api_0/{id}" data-arg_a="data_name_a" />
<link target="_blank" src="path/to/data/api_1/{id}" data-arg_b="data_name_b" />
</head>
此外,因为 前一个 WebApp 实例(加载外页、整页刷新 跳转到当前实例)的 SPA 链接元素的数据子集、本页 URL query 参数 会被首先压入当前 SPA 的数据栈,所以它们也会参与到首屏渲染。
【注】前文所述的 SPA 内页代码中也可用形如以上的 <link />
标签来声明 多数据源,此时,打开此内页的 SPA 链接元素上就可以省略 src 属性。
SPA 中所有 可见表单 均会被本引擎用 AJAX 提交接管,用户在表单内填写的数据、表单提交返回的数据 都会被压入引擎的数据栈。
同时,上述表单的源码标签上也可使用 SPA 链接元素的属性,用以在表单提交后继续 加载内外页面(但 表单提交的 Method 与 接口调用的不可不同)~
<script>
(function ($) {
$('body > section').WebApp()
.on('formSubmit', function () {
var iData = arguments[2];
alert( iData.message );
return (iData.code == 200) && iData;
});
})(self.jQuery);
</script>
<form method="POST" action="path/to/api/{uid}"
target="_top" href="path/to/app_1.html" data-arg_2="data_name_2">
<input type="hidden" name="uid" />
<input type="email" name="email" placeholder="注册电邮" />
<input type="password" name="password" placeholder="密码" />
<input type="submit" />
</form>
$.ajaxPrefilter(function (iOption) {
iOption.contentType = 'application/json';
iOption.url += '&custom=xxx';
});
$.ajaxPrefilter(function (iOption) {
iOption.url = 'http://proxy.com/?url=' + BOM.encodeURIComponent(iOption.url);
});
var URL_Args = $.paramJSON();
$.ajaxPrefilter(function (iOption) {
if ( iOption.url.match(/\.(html|md)/) ) return;
iOption.xhrFields = $.extend(iOption.xhrFields || { }, {
withCredentials: true
});
var iData = (typeof iOption.data == 'string') ?
('?' + iOption.data) : iOption.data;
var iArgs = {
AppID: URL_Args.AppID,
sign: md5($.paramSign(iData || iOption.url) + URL_Args.AppKey)
};
if (iOption.type == 'GET')
iOption.url = iOption.url.split('?')[0] + '?' +
$.param($.extend($.paramJSON(iOption.url), iArgs, {
token: URL_Args.token
}));
else {
iOption.url += 'token=' + URL_Args.token;
iOption.data = $.param($.extend(iData, iArgs));
}
});
【注】上述代码中的 $.paramJSON()
、$.paramSign()
来自 iQuery。
// 幂等方法,不会重复初始化,且总返回 WebApp 实例对象
var iWebApp = $_AppRoot.WebApp(
Init_Data, // 可选,一般为 登录后的会话数据
'http://api.demo.net/root', // 可选,API 服务器 与 静态网页资源服务器 不同时设置
Cache_Second, // 可选,DOM 缓存时限(秒,默认无限)
URL_Change // 可选,Boolean,控制 地址栏网址 是否改变
);
// 层次、递进结构
$_Gradation.dataRender( iObject );
// 水平展开的迭代结构
$_Iteration.dataRender( iArray );
var iData = $_Any.dataReader();
iWebApp.on(
'pageRender', // (必填)事件名
'path/to/InnerPage.html', // (选填)String 或 Regexp,匹配当前内页 HTML 文件路径
'path/to/Data_JSON', // (选填)String 或 Regexp,匹配当前内页 JSON API 路径
function (This_Page, Prev_Page, iData) {
// 数据结构 整理逻辑
return iData.data; // 返回处理过的数据用于渲染
}
);
iWebApp.off('pageRender', iCallback);
// 完整参数写法
iWebApp.loadLink({
title: "局部刷新",
href: HTML_URL,
method: 'POST',
src: API_URL,
}, {
arg_1: 'arg_1_name'
});
// 参数简写形式(只能用于加载内页)
iWebApp.loadLink('path/to/template.html', 'path/to/api', {
arg_1: 'arg_1_name'
});
【注】传参规则 请参考本引擎的 页面串接规则(上文【使用入门】第四大节)
本引擎不支持“在 jQuery 插件 初始化时传入各种回调函数”的方式,一切 可编程点均直接在 WebApp 实例对象上触发 自定义事件,开发者只需使用 类 jQuery 事件监听方法,就可以在其回调函数中调用 WebApp 实例的方法。
【事件分类】
return false;
return {...};
【事件总表】
EasyWebApp v2.x 的基本模型(对照 MVC 模式)——
UNIX-Shell、Windows-CMD 通用脚本 ——
npm install -g requirejs
npm install -g uglify-js
mkdir ./EasyWebApp
git clone https://git.oschina.net/Tech_Query/EasyWebApp.git ./EasyWebApp
node r.js -o build/source.js
uglifyjs EasyWebApp.js -c -m -o EasyWebApp.min.js --source-map=EasyWebApp.min.map
EasyWebApp 算是其作者与 产品、设计、后端的各种“撕逼”后,或坚持、或折中的结果。其 HTML 模板机制 源于作者早期的一个 PHP 前端项目 EasyWebTemplate(基于 phpQuery),而其 事件驱动的 API 则源于文首提到的开放平台首个版本的 智能表单引擎 JSON_Web.js(强数据格式依赖、不支持不规律的界面设计,未到达开源水准,但会继续吸收其优秀的特性)。虽然前面这些小项目 都有些幼稚,但却又是 敢于把独立思考成果付诸实践的有益尝试,若没有这些沉淀,就没有本项目自 2015年6月29日的26天 内即发布 开源稳定版的成绩~
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。