目录结构
模型
基类 TFAction
get - 获取一行数据
gets - 获取多行数据
getID - 获取数据主键
add - 添加一行数据
mod - 修改一行数据
del - 删除一行数据
getLIID - 获取最新插入数据主键
视图
模板
控制器
路由
介绍
路由入口文件是项目根目录上的 RouteMap.php 和 RouteMapConsole.php
其中 RouteMap.php 用于 WebServer 的路由程序
然后 RouteMapConsole.php 用于控制台 的路由程序
RouteMap
内容如下
// load config file
if(strstr(getenv('OS'),'Windows')) define('OS_WINNT', 1);
define('PATH_SLASH', (defined('OS_WINNT')) ? '\\' : '/');
define('DOC_ROOT_DIR', dirname(__FILE__). PATH_SLASH);
define('WEB_INF', DOC_ROOT_DIR. 'WEB-INF'. PATH_SLASH);
define('REQ_URI', $_SERVER['QUERY_STRING']);
include(WEB_INF. 'WebConfig.inc.php');
// load entry
RouteTool::addEntry('api', RouteTool::T_ENTRY_REST, 'REST', 'api/');
RouteTool::addEntry('admin', RouteTool::T_ENTRY_HTML, 'Admin', 'admin/');
RouteTool::addEntry('demo', RouteTool::T_ENTRY_HTML, 'Demo', 'demo/');
RouteTool::mapEntry();路由规则
TFWEB的路由是根据请求路径(request uri)进行匹配的,我们可以根据请求路径前缀(request uri prefix)进行不同的路由转向。
每一组路由规则都是由一个名称,一个类型,一个入口程序文件名,一个请求路径前缀组成的。
RouteTool::addEntry( 'demo', // 表示入口的名称,重复会被覆盖 RouteTool::T_ENTRY_HTML, // 入口的类型,目前支持 HTML 和 REST 'Demo', // 入口的程序文件名称 'demo/' // 入口匹配的请求地址前缀 );
默认规则
通常情况下我们可以不设置任何规则,使用默认路由规则进行处理。
系统会自动添加如下规则,用以匹配全部请求地址
RouteTool::addEntry('Default', RouteTool::T_ENTRY_HTML, "Default", "");入口程序
入口程序保存在 WEB-INF/Classes/Controllers/Route/ 目录下
可以通过复制现有的入口程序进行简单修改来创建新的入口程序
请求路径
介绍
请求路径规范可以参考RESTFul规范,我们的请求路径也是按照这个规范设计的。
即:[资源1][参数1][资源2][参数2]...
示例
/user - 用户列表 /user/3 - 用户3的详情 /categ/6/news - 分类6下面的新闻列表 /categ/6/news/10010 - 分类6下面的新闻10010的详情
映射视图
介绍
每一个请求路径都对应这一套负责处理的视图
一套视图包括程序逻辑和前端模板两个部分
对应关系
示例1
/user WEB-INF/Classes/Views/user/index.inc.php WEB-INF/Templates/Tpl/user/index.html
示例2
/user/3 WEB-INF/Classes/Views/userDetail.inc.php WEB-INF/Templates/Tpl/userDetail.html
RESTFul
默认项目根目录会有一个 api 目录,该目录下面会有一个 REST.php 路由程序
这个程序用来实现 RESTFul 风格的接口
路由入口文件 REST.php 内容
class TFREST extends FieldSystemRest {
public function __construct($opts){
parent::__construct($opts);
}
protected function prepareData(){
$myRESTLoaderObj = new TFRESTLoader($this->PEO);
$myRESTLoaderObj->auth(
// enable auth
true,
// rules
array(
// default auth method
'default'=>"authDefault",
// other auth methods
'matches'=>array(
"user.add"=>"authAdmin", // add for user use authAdmin auth method
),
// no auth models
'noAuthModels'=>array(
"user.get"=>true, // get of user is public
"demo"=>true, // all of demo is public
),
)
);
$myRESTLoaderObj->load($this->PEO->input->server->TFREST);
return $myRESTLoaderObj->getData();
}
}
$pageObj = new TFREST(array(
));
$pageObj->OP();前端UI
基础
前端UI框架基于MVVM的Vue开发,驱动文件是 js/plugins/UI.Vue.js
每一个前端UI的实例都是一整套实现表格(table)、表单(form)、对话框(dialog)等等元素渲染的组件库
这里我们提供了一个PC版本的库,一个移动版本的库
PC版本的库风格为 Inspinia 前端框架风格(该前端框架原基于Bootstrap实现),库文件是 js/plugins/UI.Vue.Inspinia.js
移动版本的库风格为 SUI Mobile 前端框架风格,库文件是 js/plugins/UI.Vue.SuiMobile.js
在前端组件库基础之上我们就可以组件自己的项目组件库了,我们的官方项目 TFHome 的组件库文件是 js/UI.Vue.Template.js 和 js/UI.Vue.TemplateM.js,分别对应的PC版本和移动版本
在后面就是我们的业务层的实现了,这里面还是以DOM风格的jQuery为基础,对应的文件是 js/UI.Vue.TFHome.js 和 js/UI.Vue.TFHomeM.js,分别对应的PC版本和移动版本
入门
我们提供了几个方法用来管理组件库当中的组件,用于方便的调用组件,实例化组件
系统组件
表单
<!-- 输入框 --> <form-text :elem="elem"></form-text> <!-- 密码框 --> <form-password :elem="elem"></form-password> <!-- 单选框 --> <form-radios :elem="elem"></form-radios> <!-- 复选框 --> <form-checkboxs :elem="elem"></form-checkboxs> <!-- 下拉框 --> <form-select :elem="elem"></form-select> <!-- 多行输入框 --> <form-textarea :elem="elem"></form-textarea> <!-- 文件上传框 --> <form-file :elem="elem"></form-file> <!-- 提交按钮 --> <form-submit :elem="elem"></form-submit> <!-- 普通按钮 --> <form-button :elem="elem"></form-button> <!-- 单照片 --> <form-photo :elem="elem"></form-photo> <!-- 验证码 --> <form-vrycode :elem="elem"></form-vrycode> <!-- TFEditor --> <form-tftb :elem="elem"></form-tftb> <!-- 表单项目容器(单行) --> <form-row-box :elem="elem"></form-row-box> <!-- 表单项目容器(提交行) --> <form-row-boxright :elem="elem"></form-row-boxright> <!-- 表单 --> <form-box :info="info" :hiddens="hiddens" :callbacks="callbacks" :validators="validators"></form-box> <!-- 对话框 --> <dialog-box :args="args"></dialog-box>
用户组件
自定义表单示例
Vue.component('form-example', {
props: {
indlg: {
default: false
}
},
data: function () {
return {
info: {
title: '测试表单',
descript: '测试表单',
method: 'post',
action: $.U('api/demo/_form_formExample')
},
validators: {
text: {triggers: ['blur'], rules: [{min: 4, msg: '用户名最少4个字符'}, {max: 20, msg: '用户名最多20个字符'}]},
password: {triggers: ['blur'], rules: [{min: 4, msg: '密码最少4个字符'}]}
},
elements: {
text: {
label: '用户名',
name: "text",
placeholder: "enter a word",
error: ""
},
password: {
label: '密码',
name: "password",
placeholder: "enter a password",
error: ""
},
submit: {
name: "submit",
value: "提交"
},
button: {
name: "button",
value: "关闭"
}
},
callbacks: {
success: function (d) {
alert(JSON.stringify(d));
},
ready: function () {
}
}
}
},
methods: {
validate: function (obj, name, msg) {
if (msg != null) {
this.elements[name].error = msg;
}
else {
this.elements[name].error = '';
}
},
closeParentDlg: function () {
VueGEC.$emit('closeDlg');
}
},
template: '<form-box :info="info" :callbacks="callbacks" :validators="validators" @validate="validate">' +
'<form-row-box :elem="elements.text">' +
' <form-text :elem="elements.text"></form-text>' +
'</form-row-box>' +
'<form-row-box :elem="elements.password">' +
' <form-password :elem="elements.password"></form-password>' +
'</form-row-box>' +
'<form-row-boxright>' +
' <form-submit :elem="elements.submit"></form-submit> ' +
' <form-button :elem="elements.button" :fnclick="closeParentDlg" v-if="indlg == true"></form-button>' +
'</form-row-boxright>' +
'</form-box>'
});加载组件
我们可以使用 $.componentLoad( [组件名称], [组件实例id], [组件实例化参数对象] ) 调用一个组件
$.componentLoad('form-user-login', 'form-user-login', {
// compBox 参数用来指定新组件实例放置的父容器的selector
// 也就是说你要告诉系统你想把这个组件创建在什么位置上
compBox : '#user-login',
// compBoxCB 当父容器无法描述为一个selector的时候就要用到这个参数了
// 回调函数的唯一参数 o 就是新组件的句柄,你可以通过任意方式将其移动到指定位置上
compBoxCB : function(o){
$('.user-icon').after(o);
},
// bindData 想组件传入参数,注意这里面设置的任何参数都会添加到组件实例的属性里
// 记得不要忘记在组件定义的时候用 props 接收一下哦~~
bindData : {
args : {
}
}
});更新组件
$.componentUpdate( [组件实例id], [更新数据] )
$.componentUpdate('form-user-login', {
args : {
}
});批量更新组件
$.componentMultiUpdate( [多组件实例id的匹配正则表达式], [更新数据] )
$.componentMultiUpdate( /^form\-user/ , {
args : {
}
});异步组件
form-xxx
声明
Vue.component('form-login', function (resolve, reject) {
resolve(TFHomeUI._makeAsyncFormComponent('login'));
});form-xxx异步组件通过TFHomeUI._makeAsyncFormComponent得到组件参数,而真正的组件参数在TFHomeUI对象内部设定
参数
window.TFHomeUI = {
asyncDialogFormCompoents : {
...
forms: {
//////// login ////////
login: {
info: {
title: '用户登录',
descript: '用户登录',
method: 'post',
action: $.U('model/user/login')
},
validators: {
user: {triggers: ['blur'], rules: [{min: 2, msg: '用户名最少2个字符'}, {max: 20, msg: '用户名最多20个字符'}]},
pwd: {triggers: ['blur'], rules: [{min: 6, msg: '密码最少6个字符'}]},
vrycode: {triggers: ['blur'], rules: [{regex: /^[0-9]{4}$/, msg: '验证码错误'}]}
},
elements: {
user: {
type: 'text',
label: '用户名',
name: "user",
placeholder: "用户名",
error: ""
},
pwd: {
type: 'password',
label: '密码',
name: "pwd",
placeholder: "密码",
error: ""
},
vrycode: {
type: 'vrycode',
label: "验证码",
name: "vrycode",
imgUrl: $.U('plugins/verifycode'),
error: ""
}
},
submitButtons: {
submitLabel: '登录'
}
},
}
}
}
}以上是一个登录表单的参数,如果未定义则会调用失败
模板
<form-box :info="info" :hiddens="args.hiddens" :callbacks="args.callbacks" :validators="validators" @validate="validate"></form-box>
可以看到form-xxx的模板就是系统组件form-box
参数info:用来表示表单基本信息的,默认值来自TFHomeUI
参数validators:用来做表单验证规则的,默认值来自TFHomeUI
方法validate:用来将错误信息处理转交给调用层自行处理的,默认值来自TFHomeUI
参数args.hiddens:可以设置默认隐藏表单域内容
参数args.callbacks:可以设置回调方法
其他参数:如果要传入其他参数请通过args带入
调用
$.componentLoad('form-login', 'form-login', {
compBox : '#user-login',
bindData : {
myArg : "myArg"
}
});dialog-xxx
声明
Vue.component('dialog-login', function (resolve, reject) {
resolve(TFHomeUI._makeAsyncDialogComponent('login'));
});dialog-xxx异步组件通过TFHomeUI._makeAsyncDialogComponent得到组件参数,而真正的组件参数在TFHomeUI对象内部通过对应的表单获得
也就是说要创造dialog-xxx就必须先有form-xxx,而TFHomeUI._makeAsyncDialogComponent的参数就是xxx,也就是一个表单实例名称
参数
window.TFHomeUI = {
asyncDialogFormCompoents : {
...
dialogs: {
login : {}
}
}
}
}以上是一个对话框的参数,默认都是空对象,如果未定义则会调用失败
模板
<dialog-box :args="args"> <form-xxx :args="args"></form-xxx> </dialog-box>
大家可能已经发现了dialog-xxx的内部只有一个slot就是form-xxx,而且只传递了一个参数args,也就是说其他参数info、validators和方法validate都是不能从外面设置的,只能通过TFHomeUI对象内部进行初始化设定
异步组件dialog-xxx的最外层用的是系统组件dialog-box
参数args:唯一参数,这里面有个重要的参数就是args.info.visible,它控制对话框是否显示,默认为false
其他参数:如果要传入其他参数请通过args带入
调用
$.componentLoad('dialog-login', 'dialog-login', {
bindData : {
args : {
visible : true,
myArg : "myArg"
}
}
});