JavaScript实现点击contenteditable的span标签后全选标签文字,类似于this.select()方法
本文完整阅读约需 12 分钟,如时间较长请考虑收藏后慢慢阅读~
在JavaScript中,我们通常使用
this.select()
实现可编辑文本框中的全选操作,但对于通过添加contenteditable="true"
参数来实现可编辑的span
标签,这个方案却并不能奏效,需要多写一些代码来实现相同的功能。这篇文章为大家分享一种在可编辑的span
标签内实现全选的方法。
0x01 做个小实验
首先我们来做个小实验。
实验源码如下所示:
<html>
<head>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, minimum-scale=1.0">
<title>实验</title>
</head>
<body>
<h1>实验</h1>
<input type="text" placeholder="在这里输入文字">
<br/>
<span contenteditable="true">在这里输入文字</span>
</body>
</html>
可以在这里在线运行该实验源码:实验源码
在浏览器中运行该段代码后,会出现两个编辑框,一个是<input>
标签所提供的,另一个则是设置了可编辑的<span>
标签所提供。
然后我们打开控制台,输入以下代码:
let input = document.getElementsByTagName("input")[0];
let span = document.getElementsByTagName("span")[0];
接下来我们分别输入input.select()
与span.select()
,会发现前者让输入框变成全选状态,后者却只能得到报错:Uncaught TypeError: span.select is not a function
:
出现图中的报错,说明span
标签尽管可以通过配置参数实现可编辑,但却依旧无法使用正常可编辑标签可以使用的select()
方法。
0x02 前置知识
那么应该如何让span
标签也支持这一方法呢?
这里要首先介绍JavaScript中Selection
与Range
两个对象。
Selection对象
这个对象用于描述用户选择文本的范围或者插入符号的位置,如果你遇到一些网站在你选择文本后弹出快捷菜单(例如百度文库),那么在大部分情况下,它们都通过这个对象来获取你的选择。此外,Selection对象除了能获取你的选择项以外,也可以进行选择操作。
Range对象
这个对象用于表示一个包含节点与文本节点的一部分的文档片段。其用途非常广泛,例如你要从文本中剔除某个字符,除了使用String.prototype.replace()
方法以外,你也可以使用Range
对象实现——只是会更复杂,除非有极为特殊的需要,否则大部分时候不需要这么做。
在继续阅读前,我推荐你先稍微查看一下以上两个对象的相关文档,以加深印象,避免后续代码给你带来困惑。
0x03 实际操作
了解完这两个对象之后,我们来实际写一段代码实现select()
方法吧。
我们还是回到第一节的实验,但愿你没有关闭那个窗口,否则还需要重新输入一遍实验代码。
我们在Console中输入以下代码:
let range = document.createRange();
range.selectNodeContents(span);
let sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
然后你会惊喜的发现——span
标签被选中了!
就是这么简单,五行代码就能实现!
0x04 原理解释
尽管在第二节我给了前置知识,但我还是打算讲解一下每行代码的含义,避免基础不太扎实的读者迷惑于其中。
第一行代码
let range = document.createRange();
这行代码的作用是创建一个Range
对象,可以参考这篇文档。
第二行代码
range.selectNodeContents(span);
这行代码使用我们刚刚简历的Range
对象选中了我们的span
节点对象,可以参考这篇文档。
但需要注意的是,目前我们只是将其选中在了Range
对象中,而非显示在了屏幕上。如果想要看到它选择的文本,可以通过Range.toString()
方法将其输出为字符串。
第三行代码
let sel = window.getSelection();
这行代码新建了一个Selection
对象,可以参考这篇文档。
第四行代码
sel.removeAllRanges();
这行代码的目的是取消当前的选择,但考虑到你在实际用鼠标选择span
标签的时候就已经做了取消选择的操作,你也可以不使用这段代码,不过以防万一,在这里我们还是加上它: )。关于这个API可以参考这篇文档。
第五行代码
sel.addRange(range);
这行代码的目的是将之前我们选中的Range
对象变成实际在屏幕上可以显示的Selection
对象。可以参考这篇文档。
0x05 简化API
尽管以上五行代码已经足够简单,但如果你的项目中需要大量使用它,将它包装成一个方法也许是不错的选择。
但如果别人也要用呢?为了避免让大家也遇到Uncaught TypeError: span.select is not a function
的错误,将它扩展成<span>
标签的方法如何?
其实很简单!
HTMLSpanElement.prototype.select = function() {
let range = document.createRange();
range.selectNodeContents(this);
let sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
}
将这行代码放在你的JavaScript代码之前,你的所有<span>
标签就可以拥有select()
方法啦!