23、Web开发中的(X)HTML表示与内联编辑技术

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&#8230;</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>&#8230;'

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开发带来更多的可能性。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值