Web开发中的(X)HTML表示与内联编辑技术
1. 使用(X)HTML表示
在Web开发中,有时候我们需要以简洁且结构化的方式来构建HTML元素。传统的方法可能会导致全局命名空间的污染,不过我们可以通过选择一个对象作为命名空间来避免这种情况,同时还能获得一定的简洁性。
1.1 避免全局命名空间污染
可以使用自定义对象作为命名空间,示例代码如下:
var B = {}
Builder.dump(B);
B.H1(B.CODE('Builder'))
也可以简单地将
Builder
进行别名处理,保持统一的接口:
var B = Builder;
Builder.dump(B);
B.H1('Builder') // <=> B.node('h1', 'Builder')
1.2 使用(X)HTML语法构建片段
虽然
Builder.node()
方法提供了一种结构化的方式来构建HTML元素,但有时候使用XHTML语法来表达要构建的片段会更加简洁。例如,下面的简单片段:
<h1 id="intro">Introduction to the <code>Builder</code> object</h1>
使用
node()
方法或便捷方法来构建它的代码如下:
Builder.node('h1', { id: 'intro' }, [
'Introduction to the ', Builder.node('code', 'Builder'), ' object'])
// 或者...
H1({ id: 'intro' }, ['Introduction to the ', CODE('Builder'), ' object'])
当需要基于XHTML片段进行工作时,可以使用
Builder.build()
方法:
Builder.build(html) → Element
需要注意的是,传递的片段必须有一个整体的容器元素。如果有多个顶级元素,只会返回第一个元素。示例如下:
// 单个容器元素:没问题
Builder.build(
'<h1 id="intro">Introduction to the <code>Builder</code> object</h1>')
// 多个顶级元素:糟糕!
// 我们只会得到 <h1> 元素!
Builder.build('<h1>Intro</h1><p>So the story goes…</p>')
Builder.build()
方法的工作原理与
Element.update()
类似,但它不需要一个元素来作为工作的内部元素。实际上,它完全依赖于
Element.update()
,在页面DOM之外创建一个临时的
<div>
来使用它。
1.3 流程图
graph TD;
A[开始] --> B[选择构建方式];
B --> C{使用XHTML语法?};
C -- 是 --> D[使用Builder.build()];
C -- 否 --> E[使用Builder.node()或便捷方法];
D --> F[检查是否有整体容器元素];
F -- 是 --> G[构建成功];
F -- 否 --> H[仅返回第一个元素];
E --> G;
G --> I[结束];
H --> I;
2. 内联编辑
内联编辑是Web 2.0风格应用程序的一个标志性特性,它允许用户直接在页面上编辑非可编辑内容,如
<p>
、
<h1>
或
<div>
元素,通过简单的点击操作将静态元素转换为可编辑区域,并弹出提交和取消按钮(或链接),以便用户提交或撤销修改,然后通过Ajax在服务器端同步编辑内容,最后将元素恢复为不可编辑状态。
2.1 内联编辑的基本概念
内联编辑主要涉及两个类:
Ajax.InPlaceEditor
和
Ajax.InPlaceCollectionEditor
。其中,
Ajax.InPlaceEditor
是最常用的,它依赖于自由输入的文本字段来进行内容修改;
Ajax.InPlaceCollectionEditor
是前者的特例,它通过使用下拉列表来限制用户的选择。
2.2 版本注意事项
在1.8版本中,负责内联编辑的两个类进行了大规模的重构,公共API发生了一些变化,特别是在可用选项和回调方面。
2.3 内联编辑器的生命周期
内联编辑器的生命周期可以分为以下几个阶段:
1.
使元素可内联编辑
:通过创建一个基于相关元素的包装对象来实现,通常只需要一次调用。
2.
鼠标悬停效果
:当用户将鼠标悬停在元素上时,会有一些特性标记该元素为可内联编辑,默认效果包括:
- 立即高亮显示元素。
- 短暂停留后,显示元素的
title
属性(默认设置为 “Click to edit”)作为工具提示。
- 鼠标移出时,通过快速淡出来取消高亮显示。
3.
进入编辑模式
:点击元素进入编辑模式,会动态创建一个合适的
<form>
元素,包含一个合适的编辑器UI(如单行文本字段、下拉列表、提交和取消按钮或链接等)。
4.
编辑操作
:在常规模式下,按下
Return
键(单行编辑器)或触发提交控件(按钮或链接)提交修改;按下
Esc
键或触发取消控件撤销修改。也可以选择不使用OK/取消控件,提交操作在按下
Return
键或离开字段时进行,撤销操作仍然绑定到
Esc
键。
5.
保存修改
:如果编辑被取消,恢复原始内容;如果提交,编辑UI消失,显示一条消息表示正在保存修改;修改保存后,原始元素重新出现,内容更新。
6.
高亮显示效果
:元素会进行快速高亮显示,以表明最近的修改。
2.4 使用内联编辑器的代码示例
要在代码中使用内联编辑器,需要加载
controls.js
模块,由于内联编辑的默认行为严重依赖于
Effect.Highlight
对象,还需要包含
effects.js
。加载脚本的代码如下:
<script type="text/javascript"
src="scriptaculous.js?load=effects,controls"></script>
2.4.1 简单示例
以下是一个简单的内联编辑示例,包括模板文件、CSS文件、JavaScript文件和服务器脚本:
模板文件
index.rhtml
:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" >
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US" xml:lang="en-US">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Simple in-place editing</title>
<link rel="stylesheet" type="text/css" href="demo.css" />
<script type="text/javascript" src="prototype.js"></script>
<script type="text/javascript"
src="scriptaculous.js?load=effects,controls"></script>
<script type="text/javascript" src="demo.js"></script>
</head>
<body>
<h1>Simple in-place editing</h1>
<p id="freeZone"><%= editableHTML %></p>
</body>
</html>
CSS文件
demo.css
:
h1 { font-size: 1.5em; }
JavaScript文件
demo.js
:
document.observe('dom:loaded', function() {
new Ajax.InPlaceEditor('freeZone', '/update');
});
服务器脚本
server.rb
:
#! /usr/bin/env ruby
require 'cgi'
require 'erb'
require 'webrick'
include WEBrick
template_text = File.read('index.rhtml')
template = ERB.new(template_text)
server = HTTPServer.new(:Port => 8042)
server.mount('/', HTTPServlet::FileHandler, '.')
editableHTML =
'Click here to edit with <code>Ajax.InPlaceEditor</code>…'
server.mount_proc('/home') do |request, response|
response['Content-Type'] = 'text/html'
response.body = template.result(binding)
end
server.mount_proc('/update') do |request, response|
editableHTML = request.query['value']
response.body = editableHTML
end
trap('INT') { server.shutdown }
server.start
2.5 调整Ajax持久化
默认情况下,内联编辑依赖于
Ajax.Updater
调用,以元素作为成功容器,没有特定的Ajax选项(使用异步POST),并传递两个参数:
value
参数包含可编辑字段的值,
editorId
参数包含原始元素的
id
(如果元素没有
id
,则该参数不存在)。
可以进行以下自定义:
| 自定义项 | 描述 | 默认值 |
| ---- | ---- | ---- |
|
paramName
| 更改保存字段值的参数名称 |
'value'
|
| 自定义回调 | 替换默认的参数序列化回调,可添加额外参数或转换传递的值 |
function(form) { return Form.serialize(form); }
|
|
ajaxOptions
| 为Ajax调用提供自定义选项 |
{evalScripts: true}
|
|
htmlResponse
| 指定服务器是否返回最终的标记 |
true
|
2.6 自定义外观
内联编辑器的外观可以通过多种方式进行定制,包括按钮或链接的类型、额外的文本、CSS类和回调函数等。
2.6.1 按钮与链接
可以通过
okControl
和
cancelControl
选项来选择OK和取消控件的类型(
'button'
、
'link'
或
false
),还可以使用
okText
和
cancelText
选项来更改按钮或链接的文本。此外,通过设置
submitOnBlur
选项为
true
,可以在焦点离开可编辑字段时自动提交修改。
2.6.2 额外文本
可以在OK和取消控件之前、之间和之后插入自定义文本,还可以自定义鼠标悬停时显示的工具提示和保存内容时显示的文本。
2.6.3 CSS类和样式属性
内联编辑器定义了多个CSS类,可以在样式表中自定义这些类的样式。同时,还提供了一些选项来指定自定义类名,如
hoverClassName
、
formClassName
、
loadingClassName
和
savingClassName
等。
2.6.4 回调函数
Ajax.InPlaceEditor
提供了多个回调函数,可以在编辑器的不同阶段进行自定义操作,如
onEnterHover
、
onLeaveHover
、
onEnterEditMode
、
onFailure
、
onComplete
和
onLeaveEditMode
等。
通过以上这些方法,我们可以根据自己的需求灵活地定制内联编辑器的外观和行为,为用户提供更加个性化的编辑体验。
2.7 不同编辑器使用不同样式
虽然部分CSS类名无法自定义,且未来版本可能会移除自定义类选项,但我们仍能基于每个编辑器的表单ID,在不同ID上下文中使用相同的类,实现每个编辑器的完全自定义。
2.7.1 表单ID规则
- 元素无ID且未指定formId :表单将没有ID,无法区分。
-
元素有ID但未指定formId
:包装表单的ID是元素ID后加上
-inplaceeditor。例如,<p id="freeZone1">对应的表单ID为freeZone1 - inplaceeditor。若已有元素使用该ID,则不会使用。 -
指定formId
:可通过
formId选项指定表单ID,但系统会在原元素位置创建新表单,而非在现有表单内构建编辑器。
2.7.2 示例代码
以下是根据上述规则调整的示例,展示如何使用不同样式:
CSS文件
demo.css
:
h1 { font-size: 1.5em; }
.editable.hovered {
border: 1px dashed #880;
}
form.first {
border: 3px solid silver;
background: #ddd;
padding: 0.5em;
margin-bottom: 1em;
}
.inplaceeditor - saving {
height: 16px;
padding - left: 20px;
background: url(/spinner.gif) no - repeat left center;
font: italic smaller/16px sans - serif;
color: gray;
}
JavaScript文件
demo.js
:
document.observe('dom:loaded', function() {
new Ajax.InPlaceEditor('freeZone1', '/update', {
hoverClassName: 'hovered',
formClassName: 'first'
});
new Ajax.InPlaceEditor('freeZone2', '/update', {
hoverClassName: 'hovered'
});
new Ajax.InPlaceEditor('freeZone3', '/update', {
hoverClassName: 'hovered'
});
new Ajax.InPlaceEditor('freeZone4', '/update', {
hoverClassName: 'hovered',
savingText: 'Hang on, I\'m saving this...'
});
});
2.8 流程图
graph TD;
A[开始] --> B[创建内联编辑器];
B --> C{鼠标操作};
C -- 悬停 --> D[触发onEnterHover];
C -- 移出 --> E[触发onLeaveHover];
C -- 点击 --> F[进入编辑模式];
F --> G[创建表单和编辑器UI];
G --> H{编辑操作};
H -- 提交 --> I[触发保存请求];
H -- 取消 --> J[恢复原始内容];
I --> K{保存结果};
K -- 成功 --> L[更新元素内容并触发onLeaveEditMode];
K -- 失败 --> M[触发onFailure];
D --> C;
E --> C;
L --> N[结束];
J --> N;
M --> N;
3. 总结
在Web开发中,使用(X)HTML表示和内联编辑技术能显著提升用户体验和开发效率。通过
Builder
相关方法,我们可以灵活地构建HTML元素,避免全局命名空间污染,同时利用XHTML语法的简洁性。而内联编辑技术则让用户能够直接在页面上编辑内容,实现实时更新,这是Web 2.0风格应用的重要特性。
内联编辑技术提供了丰富的自定义选项,包括调整Ajax持久化、自定义外观等。我们可以根据项目需求,定制内联编辑器的行为和样式,如选择不同的控件类型、添加额外文本、使用CSS类和回调函数等。此外,还能通过表单ID为不同的编辑器应用不同的样式,实现个性化的设计。
通过合理运用这些技术和方法,开发者可以创建出更加交互性强、用户体验好的Web应用程序。无论是简单的页面内容编辑,还是复杂的动态数据更新,这些技术都能发挥重要作用。未来,随着Web技术的不断发展,这些技术也将不断完善和拓展,为Web开发带来更多的可能性。
超级会员免费看
7793

被折叠的 条评论
为什么被折叠?



