# 光标跟随效果--前端实现
<body>
<div class="text-container">
<div class="text"></div>
<div class="cursor"></div>
</div>
<script type="text/javascript" src="./index.js"></script>
</body>
光标绘制
.cursor {
display: inline-block;
position: absolute;
top: 0;
left: 0;
transform: translate(0px,0px);
width: 10px;
height: 10px;
background-color: black;
border-radius: 50%;
animation: blinking 1s infinite;
}
@keyframes blinking {
0% { opacity: 1; }
50% { opacity: 0; }
100% { opacity: 1; }
}
文本容器绘制
.text-container {
border: 1px solid #ccc;
border-radius: 5px;
display: inline-block;
position: relative;
width: 100%;
min-height: 100px;
}
思路:
- 找到最后一个文本节点
- js无法添加伪元素 在文本节点最后添加文字,获取文字在容器中的位置
- 根据文字位置设置光标位置
- 删除文字
const textContainer = document.querySelector('.text-container');
const textElem = document.querySelector('.text');
const cursor = document.querySelector('.cursor');
解析截取的内容,更新光标位置
for (let i = 0; i < content.length; i++) {
//截取字符内容
let text = content.slice(0, i);
console.log(text,'==========');
//转换接收的内容
let result = transfer(text);
//将转换结果显示
textElem.innerHTML = result;
//更新光标位置
updateCursor();
//添加延迟
await delay(3);
}
延迟函数
function delay(duration) {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, duration);
});
}
格式显示核心方法:transfer将接收的内容展示为HTML格式内容
这个函数很难写,示例代码有很多bug
function transfer(text) {
// 去除多余的空格和换行符
text = text.trim();
// 段落格式化
const paragraphs = text.split('\n\n');
const formattedText = paragraphs.map(paragraph => {
// 去除段落中的多余空格和换行符
paragraph = paragraph.trim();
// 提取代码段
const codeBlockRegex = /```[\s\S]+?```/g;
const codeBlocks = paragraph.match(codeBlockRegex);
if (codeBlocks) {
// 处理代码段
const codeBlocksWithHighlighting = codeBlocks.map(codeBlock => {
// 去除代码段的语法高亮标签(如果有的话)
const languageRegex = /```(\w+)/;
const language = codeBlock.match(languageRegex)[1];
const code = codeBlock.replace(languageRegex, '').replace(/```/g, '');
// 使用highlight.js库进行语法高亮处理(需要引入该库)
const highlightedCode = hljs.highlight(language, code).value;
return `<pre><code class="language-${language}">${highlightedCode}</code></pre>`;
});
// 将处理后的代码段插入段落中
paragraph = paragraph.replace(codeBlockRegex, codeBlocksWithHighlighting.join(''));
}
// 添加段落标签
return `<p>${paragraph}</p>`;
}).join('');
return formattedText;
}
改变光标位置:
getLastTextNode核心方法:获取最后一个文本节点
在文本节点最后追加一个文本,创建选区对象,选中 临时文本对象
选区对象-->获取文本对象浏览器视口坐标
移动光标元素到指定坐标,删除临时文本节点
function getLastTextNode(node) {
//如果
if(node.nodeType === Node.TEXT_NODE) {
return node;
}
//不是文本节点,获取所有子节点,从最后一个节点循环
let children = node.childNodes;
for (let i = children.length - 1; i >= 0; i--) {
let result = getLastTextNode(children[i]);
if (result) {
return result;
}
}
return null;
}
function updateCursor() {
//找到最后一个文本节点
const lastTextNode = getLastTextNode(textElem);
//加文字
const tempText = document.createTextNode('*');
if(lastTextNode) {
//找到它的父节点
//lastTextNode.parentNode.insertBefore(tempText,lastTextNode.nextSibling );
lastTextNode.parentNode.appendChild(tempText);
} else {
textElem.appendChild(tempText);
}
//根据文字位置设置光标位置
//tempText.getBoundingClientRect(); 节点没有该api
const range = document.createRange();//表示选中文字的范围
range.setStart(tempText,0);
range.setEnd(tempText,0);
const rect = range.getBoundingClientRect();
// console.log(rect);//会打印文本的坐标,是相对于浏览器视口的
//光标位置,绝对定位,相对于父元素定位
//计算最后文字坐标在容器中的坐标
const textRect = textContainer.getBoundingClientRect();
const x = rect.left - textRect.left;
const y = rect.top - textRect.top;
// console.log(x,y,'========');
//设置光标元素位置
cursor.style.transform = `translate(${x}px, ${y}px)`;
// console.log(cursor,'=======');
console.log(`translate(${x}px, ${y}px)`);
//删除文字
tempText.remove();
}
← 说明 html--0.魔术卡片 →