仿chatgpt光标自动移动到文本最后效果

概述

首先我们拿到这样一个需求的时候,首先可能想到的是通过伪元素来实现。但是如果这个文本是富文本,里面包含其他的标签,那就不太好实现了。

解决方法

  • 找到元素内容的最后一个文本节点
  • 在文本节点最后添加一个临时的文字
  • 获取最后一个文字相对视口的位置
  • 计算出相对文本实际位置,把实际位置给到光标
  • 移除临时位置光标

代码实现

既然上面已经有了思路,下面我们实际代码实现一下

样式和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();
}
相关推荐
i听风逝夜36 分钟前
Web 3D地球实时统计访问来源
前端·后端
iMonster40 分钟前
React 组件的组合模式之道 (Composition Pattern)
前端
呐呐呐呐呢1 小时前
antd渐变色边框按钮
前端
元直数字电路验证1 小时前
Jakarta EE Web 聊天室技术梳理
前端
wadesir1 小时前
Nginx配置文件CPU优化(从零开始提升Web服务器性能)
服务器·前端·nginx
牧码岛1 小时前
Web前端之canvas实现图片融合与清晰度介绍、合并
前端·javascript·css·html·web·canvas·web前端
灵犀坠1 小时前
前端面试八股复习心得
开发语言·前端·javascript
9***Y481 小时前
前端动画性能优化
前端
网络点点滴1 小时前
Vue3嵌套路由
前端·javascript·vue.js
牧码岛1 小时前
Web前端之Vue+Element打印时输入值没有及时更新dom的问题
前端·javascript·html·web·web前端