这是我最终实现的设计。我远未找到完整的解决方案,但我认为这是一个好的开始。
数据模型
在我的例子中,用户需要能够建立一个任务列表,其中任务可以有不同的类型和属性。任务还可以嵌入其他对象。在某种意义上类似于表单构建器,尽管我正在处理更深层次的嵌套对象。这里的关键是确保您的后端应用程序只公开与您的应用程序域相关的对象(在Domain Driven Design 的意义上),以便您的客户端代码在从服务器调用并在序列化它以准备保存之前。在这种情况下,我不得不对我的服务器端表示层进行一些更改,但结果我认为我的客户端代码更简洁,更专注于处理实际的用户事件。
数据序列化
我选择 JSON 作为数据交换格式。在客户端,我有两个处理数据序列化和反序列化的函数。实现非常简单(部分归功于我为公开域模型对象所做的一些更改)。我在下面粘贴了一个简化版本。唯一的挑战是 Rails 用来处理 PUT 请求的 _method 参数似乎不适用于 JSON Content-Type。见Using HTTP PUT to send JSON with Jquery and Rails 3
var todoList = {};
$.getJSON("/users/123/todolists/456.json", function(data) {
loadTodoList(data);
...
});
function loadTodoList(data) {
todoList = data.todoList;
}
function saveTodoList() {
$.ajax({
type: 'POST',
url: "/users/123/todolists/456",
data: JSON.stringify({ todoList: todoList }),
contentType: 'application/json',
dataType: 'script', // could be "json", "html" too
beforeSend: function(xhr){
xhr.setRequestHeader("X-Http-Method-Override", "put");
}
});
}
在服务器端,Rails 也可以轻松处理 JSON(JSON 的序列化和反序列化由框架自动且透明地执行)。我只是在我的 TodoList 模型上覆盖了 to_json() 方法,以避免来回传递无用的数据(例如 create_at、modified_at 属性)。在获取我的顶级对象(即 TodoList)时,还必须确保包含所有嵌套对象。
# TodoListsController
def show
@todolist = TodoList.find_by_id(params[:id], :include => [:tasks, ...])
respond_to do |format|
format.json do
render :json => @todolist.to_json
end
end
end
# TodoList model
def to_json
super(:only => :name,
:include => { :tasks => { :only => [:name, :description, ...],
:include => ... }})
end
客户端持久性
这里的目标是避免意外丢失尚未保存的用户编辑。到目前为止,我直接使用 HTML5 本地存储(localStorage 变量),但最终会寻找一个 jQuery 插件,如果不支持 HTML5,它会自动处理回退到 cookie 存储。
动态 HTML 生成
我依靠 jQuery Template 来生成 HTML。构建器的主要功能是动态生成 HTML,所以这个插件非常方便。我已经为我的待办事项列表模型的所有构建块定义了模板(例如任务、笔记……)。每当创建这些对象的新实例并需要渲染时,就会调用模板。
我认为这奠定了大部分基础。其余的主要是核心 Javascript,用于处理与表单/todoList 构建器的所有用户交互。