
2025-04-04 日报 Day146

今日的鸡汤
与大雁齐飞,目之所及皆是广袤天空;与苍蝇为伍,所到之处皆是污秽狼藉。
今日学习内容
1、JS 红皮书 P597-609 第十九章:表单脚本
今日笔记
1、选择框编程: 选择框是使用
- 选项处理: 对于只允许选择一项的选择框,获取选项最简单的方式是使用选择框的 selectedIndex 属性,如下面的例子所示:
1 | let selectedOption = selectbox.options[selectbox.selectedIndex]; |
- 添加选项: 可以使用 JavaScript 动态创建选项并将它们添加到选择框。首先,可以使用 DOM 方法,如下所示:
1 | let newOption = document.createElement("option"); |
- 移除选项: 与添加选项类似,移除选项的方法也不止一种。第一种方式是使用 DOM 的 removeChild()方法并传入要移除的选项,比如:
1 | selectbox.removeChild(selectbox.options[0]); // 移除第一项 |
第二种方式是使用选择框的 remove()方法。这个方法接收一个参数,即要移除选项的索引,比如:
1 | selectbox.remove(0); // 移除第一项 |
最后一种方式是直接将选项设置为等于 null。这同样也是 DOM 之前浏览器实现的方式。下面是一个例子:
1 | selectbox.options[0] = null; // 移除第一项 |
- 移动和重排选项: 在 DOM 之前,从一个选择框向另一个选择框移动选项是非常麻烦的,要先从第一个选择框移除选项,然后以相同文本和值创建新选项,再将新选项添加到第二个选择框。DOM 方法则可以直接将某个选项从第一个选择框移动到第二个选择框,只要对相应选项使用 appendChild()方法即可。如果给这个方法传入文档中已有的元素,则该元素会先从其父元素中移除,然后再插入指定位置。例如,下面的代码会从选择框中移除第一项并插入另一个选择框:
1 | let selectbox1 = document.getElementById("selLocations1"); |
移动选项和移除选项都会导致每个选项的 index 属性重置。
2、表单序列化: 表单序列化(form serialization)已经成为一个常见需求。表单在 JavaScript 中可以使用表单字段的 type 属性连同其 name 属性和 value 属性来进行序列化。在写代码之前,我们需要理解浏览器如何确定在提交表单时要把什么发送到服务器。
字段名和值是 URL 编码的并以和号(&)分隔。
禁用字段不会发送。
复选框或单选按钮只在被选中时才发送。
类型为”reset”或”button”的按钮不会发送。
多选字段的每个选中项都有一个值。
通过点击提交按钮提交表单时,会发送该提交按钮;否则,不会发送提交按钮。类型为”image”的元素视同提交按钮。
1 | function serialize(form) { |
3、富文本编辑: 在网页上编写富文本内容是 Web 应用开发中很常见的需求。
- 使用contenteditable: 给页面中的任何元素指定 contenteditable 属性,然后该元素会立即被用户编辑。这种方式更受欢迎,因为不需要额外的 iframe、空页面和 JavaScript,只给元素添加一个 contenteditable 属性即可,比如:
- 与富文本交互: 与富文本编辑器交互的主要方法是使用 document.execCommand()。这个方法在文档上执行既定的命令,可以实现大多数格式化任务。document.execCommand()可以接收 3 个参数:要执行的命令、表示浏览器是否为命令提供用户界面的布尔值和执行命令必需的值(如果不需要则为 null)。为跨浏览器兼容,第二个参数应该始终为 false,因为 Firefox 会在其为 true 时抛出错误。不同浏览器支持的命令也不一样。下表列出了最常用的命令。
命令 值 说明 bold null 设置选中文本为粗体 italic null 设置选中文本为斜体 underline null 设置选中文本为下划线 strikethrough null 设置选中文本为删除线 subscript null 设置选中文本为下标 superscript null 设置选中文本为上标 justifyLeft null 设置选中文本左对齐 justifyCenter null 设置选中文本居中对齐 justifyRight null 设置选中文本右对齐 justifyFull null 设置选中文本两端对齐 indent null 向右缩进选中文本 outdent null 向左缩进选中文本 insertOrderedList null 插入有序列表 insertUnorderedList null 插入无序列表 insertHorizontalRule null 插入水平线 createLink URL 创建超链接 unlink null 删除超链接 insertImage URL 插入图像 insertText 文本 插入文本 insertHTML HTML 插入 HTML 代码 还有与命令相关的其他一些方法。第一个方法是 queryCommandEnabled(),此方法用于确定对当前选中文本或光标所在位置是否可以执行相关命令。它只接收一个参数,即要检查的命令名。如果可编辑区可以执行该命令就返回 true,否则返回 false。来看下面的例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<html>
<head>
<meta charset="UTF-8">
<title>简易富文本编辑器</title>
<style>
#editor {
width: 90%;
height: 300px;
border: 1px solid #ccc;
margin-top: 10px;
}
.toolbar button {
margin-right: 5px;
}
</style>
</head>
<body>
<h2>富文本编辑器(基于 designMode)</h2>
<div class="toolbar">
<button onclick="execCmd('bold')">加粗</button>
<button onclick="execCmd('italic')">斜体</button>
<button onclick="execCmd('underline')">下划线</button>
<button onclick="execCmd('insertUnorderedList')">无序列表</button>
<button onclick="execCmd('createLink', prompt('请输入链接地址'))">插入链接</button>
<button onclick="alert(getEditorContent())">获取内容</button>
</div>
<iframe id="editor"></iframe>
<script>
// 激活 designMode
const editor = document.getElementById('editor');
editor.contentDocument.designMode = "on";
// 执行命令
function execCmd(command, value = null) {
editor.contentDocument.execCommand(command, false, value);
}
// 获取当前编辑器内容
function getEditorContent() {
return editor.contentDocument.body.innerHTML;
}
</script>
</body>
</html>
1 | let result = frames["richedit"].document.queryCommandEnabled("bold"); |
另一个方法 queryCommandState()用于确定相关命令是否应用到了当前文本选区。例如,要确定当前选区的文本是否为粗体,可以这样:
1 | let isBold = frames["richedit"].document.queryCommandState("bold"); |
最后一个方法是 queryCommandValue(),此方法可以返回执行命令时使用的值
1 | let fontSize = frames["richedit"].document.queryCommandValue("fontsize"); |
4、富文件选择: 在内嵌窗格中使用 getSelection()方法,可以获得富文本编辑器的选区。这个方法暴露在document 和 window 对象上,返回表示当前选中文本的 Selection 对象。每个 Selection 对象都拥有以下属性
- anchorNode: 选区的起始节点。
- anchorOffset: 选区的起始偏移量。
- focusNode: 选区的结束节点。
- focusOffset: 选区的结束偏移量。
- isCollapsed: 如果选区没有选中任何内容,则为 true。
- rangeCount: 选区包含的 Range 对象数量。
- type: 选区的类型,可能的值有”None”、”Caret”和”Range”。
- toString(): 返回选区的文本内容。
- getRangeAt(index): 返回选区中指定索引的 Range 对象。
- removeAllRanges(): 清除选区中的所有 Range 对象。
- addRange(range): 将指定的 Range 对象添加到选区中。
- collapse(node, offset): 将选区折叠到指定的节点和偏移量。
- extend(node, offset): 扩展选区到指定的节点和偏移量。
- selectAllChildren(node): 选中指定节点的所有子节点。
- deleteFromDocument(): 从文档中删除选区的内容。
- containsNode(node, allowPartial): 检查选区是否包含指定的节点。
- getClientRects(): 返回选区的所有矩形区域。
- getRangeAt(index): 返回选区中指定索引的 Range 对象。
- isCollapsed: 如果选区没有选中任何内容,则为 true。
- rangeCount: 选区包含的 Range 对象数量。
- type: 选区的类型,可能的值有”None”、”Caret”和”Range”。
- toString(): 返回选区的文本内容。
Selection 对象的这个方法极其强大,充分利用了 DOM 范围来管理选区。操纵 DOM 范围可以实现比 execCommand()更细粒度的控制,因为可以直接对选中文本的 DOM 内容进行操作。来看下面的例子:5、通过表单提交富文本: 因为富文本编辑是在内嵌窗格中或通过为元素指定 contenteditable 属性实现的,而不是在表单控件中实现,所以富文本编辑器技术上与表单没有关系。这意味着要把富文本编辑的结果提交给服务器,必须手工提取 HTML 并自己提交。通常的解决方案是在表单中添加一个隐藏字段,使用内嵌窗格或contenteditable 元素的 HTML 更新它的值。在表单提交之前,从内嵌窗格或 contenteditable 元素中提取出 HTML 并插入隐藏字段中。例如,以下代码在使用内嵌窗格实现富文本编辑时,可以用在表单的 onsubmit 事件处理程序中:1
2
3
4
5
6
7
8
9let selection = frames["richedit"].getSelection();
// 取得选中的文本
let selectedText = selection.toString();
// 取得表示选区的范围
let range = selection.getRangeAt(0);
// 高亮选中的文本
let span = frames["richedit"].document.createElement("span");
span.style.backgroundColor = "yellow";
range.surroundContents(span);1
2
3
4
5form.addEventListener("submit", (event) => {
let target = event.target;
target.elements["comments"].value =
frames["richedit"].document.body.innerHTML;
});