vue中,实现GPT中打字机效果和光标跟随文字效果

<template>
  <div class="typing-container" ref="typingContainer" id="typingContainer">
    <v-md-preview :text="displayedText" ref="ppp"></v-md-preview>
  </div>
</template>

<script>
export default {
  data () {
    return {
      fullText: `** AIM-9 空空导弹(以AIM-9X Block II为例)的具体参数与部件关系解析

一、基本参数
1. 型号:AIM-9X Block II(最新改进型)
2. **类型**:红外制导短程空对空导弹
3. **长度**:约3米
4. **直径**:127毫米(弹体)
5. **翼展**:430毫米(折叠式尾翼展开后)
6. **重量**:约85千克
7. **射程**:最大约35公里(受发射条件及目标机动性影响)
8. **速度**:超音速(约2.5马赫)
9. **制导方式**:红外成像(IIR,抗干扰能力强)
`,
      displayedText: '', // 当前显示的文字
      currentIndex: 0, // 当前字符的索引
    };
  },

  mounted () {
    this.startTyping(); //typingContainer
  },

  methods: {
    startTyping () {
      const container = this.$refs.typingContainer.childNodes[0].childNodes[0];
      if (this.currentIndex < this.fullText.length) {
        this.displayedText += this.fullText[this.currentIndex]; // 逐个字符添加到 displayedText
        this.currentIndex++;
        setTimeout(this.startTyping, 100); // 控制打字速度,50ms 显示一个字符

        this.$nextTick(() => {
          // 移除之前的光标(如果有)
          const previousCursor = container.querySelector('.cursorCss');
          if (previousCursor) {
            previousCursor.remove();
          }
          const textNode = this.getLastTextNode(container); // 获取最后一个文本节点
          const cursor = document.createElement('span')//document.createTextNode('●'); // 光标
          cursor.className = 'cursorCss';
          if (textNode) {
            // 如果找到文本节点,将光标插入到文本节点后面
            textNode.parentNode.insertBefore(cursor, textNode.nextSibling);
          } else {
            // 如果没有找到文本节点,将光标插入到容器末尾
            container.appendChild(cursor);
          }

        });
      } else {
        // 移除之前的光标(如果有)
          const previousCursor = container.querySelector('.cursorCss');
          if (previousCursor) {
            previousCursor.remove();
          }
      }
    },

    getLastTextNode (node) {
      if (!node) {
        return null;
      }
      // 如果当前节点是文本节点,直接返回
      if (node.nodeType === Node.TEXT_NODE && node.textContent.trim() !== '') {
        return node;
      }
      // 遍历子节点,从最后一个开始
      for (let i = node.childNodes.length - 1; i >= 0; i--) {
        const childNode = node.childNodes[i];
        // 递归查找子节点中的最后一个文本节点
        const textNode = this.getLastTextNode(childNode);
        if (textNode) {
          return textNode;
        }
      }

      // 如果没有找到文本节点,返回 null
      return null;
    }
  },
};
</script>

<style lang="scss">
.cursorCss {
  color: blue;
  font-size: 26px;
  padding-top: 10px;
  padding-left: 10px;
  position: relative;
  &::after {
    content: '';
    display: inline-block;
    width: 10px;
    height: 10px;
    background-color: rgb(73, 73, 165);
    border-radius: 50%;
    animation: blink 1s infinite;
  }
}
</style>

其中v-md-preview是解析MD的插件,可以在main.js中引用以下代码


npm i @kangc/v-md-editor -S


import VMdPreviewfrom '@kangc/v-md-editor';
import '@kangc/v-md-editor/lib/style/base-editor.css';
import githubTheme from '@kangc/v-md-editor/lib/theme/github.js';
import '@kangc/v-md-editor/lib/theme/style/github.css';

VMdPreview.use(githubTheme);
app.use(VMdPreview)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值