概述
首先我们拿到这样一个需求的时候,首先可能想到的是通过伪元素来实现。但是如果这个文本是富文本,里面包含其他的标签,那就不太好实现了。
解决方法
- 找到元素内容的最后一个文本节点
- 在文本节点最后添加一个临时的文字
- 获取最后一个文字相对视口的位置
- 计算出相对文本实际位置,把实际位置给到光标
- 移除临时位置光标
代码实现
既然上面已经有了思路,下面我们实际代码实现一下
样式和html代码
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style type="text/css">
.text-container {
width: 100%;
height: 100%;
position: relative;
display: flex;
}
.text {
width: 80%;
height: 400px;
}
// 光标
.cursor {
position: absolute;
width: 5px;
height: 5px;
background-color: red;
}
</style>
</head>
<body>
<div class="text-container">
<div class="text"></div>
<div class="cursor"></div>
</div>
<script src="./common.js"></script>
</body>
</html>
获取元素
js
const textContainer = document.querySelector('.text-container')
// 文本内容
const textElem = document.querySelector('.text')
// 光标
const cursor = document.querySelector('.cursor')
自动添加文本
js
async function autoAppend() {
function delay(interval) {
return new Promise(resolve => setTimeout(resolve, interval));
}
const content = `自动添加文本 asdf
asides萨福;卡拉屎的飞机啊阿斯顿发生阿斯顿发生地方
卡拉屎的飞机啊阿斯顿发生阿斯顿发生地方卡拉屎的飞机啊阿斯顿发生阿斯顿发生地方
<span>asdf</span>
卡拉屎的飞机啊阿斯顿发生阿斯顿发生wei
`
for (let i = 0; i < content.length; i++) {
let text = content.slice(0, i);
//let result = tranformText(text);
textElem.innerHTML = text;
updateCursor()
await delay(300)
}
}
获取最后一个文本节点
js
function getLastTextNode(node) {
if (node.nodeType === Node.TEXT_NODE) {
return node;
}
let childNodes = node.childNodes;
for (let i = childNodes.length - 1; i >= 0; i--) {
let lastTextNode = getLastTextNode(childNodes[i]);
if (lastTextNode) {
return lastTextNode;
}
}
return null;
}
获取光标位置
js
function updateCursor() {
// 找到最后一个文本节点
const lastTextNode = getLastTextNode(textElem);
// 在最后一个文本节点加文字
const tempNode = document.createTextNode('|');
if (lastTextNode) {
lastTextNode.parentNode.insertBefore(tempNode, lastTextNode.nextSibling);
}else{
textElem.appendChild(tempNode);
}
//根据文本节点设置光标位置
const range = document.createRange();
//选中文本对象
range.setStart(tempNode, 0);
range.setEnd(tempNode, 0);
// 获取相对视口位置
const rect = range.getBoundingClientRect();
// 获取容器相对视口位置
const containerRect = textElem.getBoundingClientRect();
const x = rect.left - containerRect.left;
const y = rect.top - containerRect.top + 10;
cursor.style.transform = `translate(${x}px, ${y}px)`;
tempNode.remove();
}