使用 Vue 3 实现打字机效果

在现代前端开发中,添加一些视觉效果可以提升用户体验。其中,打字机效果是一种常见且吸引人的效果,可以用于展示动态文本。本文将介绍如何在 Vue 3 中实现打字机效果。

实现步骤

1. 创建自定义指令

我们首先创建一个自定义指令 v-typewriter,用于实现打字机效果。这个指令将逐字显示绑定的文本内容。

const typeWriter = ref(null);

const typewriterDirective = (el, binding) => {
  const indexValue = el.getAttribute('data-index');
  const delay = 150; // 设置延迟时间,默认150ms
  let i = 0;

  typeWriter.value = setInterval(() => {
    if (binding?.value && i < binding.value.length) {
      if (textList.value && textList.value[indexValue]) {
        textList.value[indexValue].typewriterText += binding.value.charAt(i) || '';
      }
      i++;
    } else {
      clearInterval(typeWriter.value);
      stop(textList.value[indexValue], indexValue, true);
    }
  }, delay);
};

const vTypewriter = {
  mounted(el, binding) {
    typewriterDirective(el, binding);
  }
};

2. 使用自定义指令

在 Vue 组件中使用自定义指令 v-typewriter。该指令会在元素挂载时自动触发,逐字显示文本内容。

<template>
  <div class="left-content mr-16">
    <el-scrollbar ref="scrollRef" height="100%" class="scroll">
      <div class="flex mb-48" v-for="(item, index) in textList" :key="item.updateKey">
        <div class="user-avatar">
          <img v-if="item.resultTts || item.library" src="/img/avatar.png" alt="" />
          <img v-else src="/img/user_avatar.png" alt="" />
        </div>
        <div class="ml-12">
          <div class="time mb-11">
            <span v-if="item.resultTts || item.library">智能馆员{{ item.time }}</span>
            <span v-else>读者{{ item.time }}</span>
          </div>
          <div>
            <div
              class="answer"
              :class="item.resultTts || item.library ? 'libarary-bg' : 'user-color '"
            >
              <div v-if="item.resultTts || item.library">
                <van-loading v-if="!item.resultMessage" type="spinner" color="#1989fa" />
                <div v-if="item.isStop && item.stopText">{{ item.stopText }}</div>
                <div
                  v-if="item.resultTts && !item.isStop"
                  v-typewriter="item.resultTts"
                  :data-index="index"
                >
                  {{ item.typewriterText }}
                </div>
              </div>
              <div v-else>{{ item.resultMessage }}</div>
            </div>
            <div
              v-if="(!item.isStop && item.resultTts) || !item.resultMessage"
              class="stop-icon mt-18"
              @click="stop(item, index)"
            >
              停止生成
            </div>
          </div>
          <BookList
            v-if="item.dataList?.length && item.isStop"
            :data-list="item.dataList"
          ></BookList>
        </div>
      </div>
    </el-scrollbar>

  </div>
</template>

<script>
import { ref } from 'vue';
import { useEventBus } from '@/hooks/useEventBus';

const emits = defineEmits(['watchTypeWriter', 'handleStop']);

const textList = ref([]);
useEventBus('clearChatInfo', () => {
  textList.value = [];
});
useEventBus('changeAction', (message) => {
// message其它组件传递的数据 
  clearInterval(typeWriter.value);
  if (!textList.value.length || !message.resultTts) {
    textList.value.push({
      time: ` ${dayjs().format('HH:mm:ss')}`,
      isStop: false,  // 是否停止
      stopText: '',   // 打字机停止后的内容
      typewriterText: '',  // 动态展示打字机内容的文本
      updateKey: dayjs().valueOf(), // 每次增加一条数据的唯一key
      ...message
    });
    return;
  }

  if (textList.value.length && message.resultTts) {
    textList.value[textList.value.length - 1] = {
      ...textList.value[textList.value.length - 1],
      ...message
    };
  }
});

const stop = (item, index, isFinish = false) => {
  if (!item.resultMessage) {
    item.isStop = true;
    emits('handleStop');
    return;
  }
  if (item.isStop) {
    return;
  }

  const curText = document.querySelector(`[data-index="${index}"]`);
  item.isStop = true;
  item.stopText = curText?.innerText;
};
</script>

<style scoped lang="scss">
/* 自定义样式*/
</style>

相关推荐

  1. 使用 Vue 3 实现打字机效果

    2024-07-11 13:18:03       23 阅读
  2. vue2 el-input里实现打字机 效果

    2024-07-11 13:18:03       45 阅读
  3. Unity Text文本实现打字机(一个一个出来)的效果

    2024-07-11 13:18:03       53 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-11 13:18:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-11 13:18:03       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-11 13:18:03       58 阅读
  4. Python语言-面向对象

    2024-07-11 13:18:03       69 阅读

热门阅读

  1. 设计模式-单例模式

    2024-07-11 13:18:03       22 阅读
  2. 达梦数据库系列—23. DSC集群搭建

    2024-07-11 13:18:03       17 阅读
  3. RabbitMQ 迁移

    2024-07-11 13:18:03       21 阅读
  4. 【编程范式】理解响应式编程(reactive programming)

    2024-07-11 13:18:03       26 阅读
  5. Python 循环语句

    2024-07-11 13:18:03       21 阅读
  6. 【EasyExcel】动态替换表头内容并应用样式

    2024-07-11 13:18:03       21 阅读