vue 实现打字机效果

打字机效果组件,支持像打字机一样模仿键入文本。支持vue 插值语法和表格等打印

ps: 灵感来着于vue-type-writer 但是 这个组件过于简单 就自己整了一个

一、预览

二、代码

组件:

js 复制代码
<template>
  <div :style="{ visibility: visibility }">
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: "vue-text-dot",
  props: {
    // 间隔时间
    interval: { type: Number, default: 75 },
    // 光标 建议有表格的时候不要使用光标 会导致渲染异常
    cursorStr: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      visibility: "hidden", // 
      timer: 0, // 定时器
      initialDom: null, // 记录初始dom
      progress: 0, // 当前文本书写进度
      // writeStatus: "NotStart",// 当前书写状态=> NotStart: 未开始;Processing:书写中;Completed 书写完毕
    };
  },
  mounted() {
    // 拷贝初始所有dom 便于重新开始
    this.initialDom = JSON.parse(JSON.stringify(this.$el.innerHTML));
  },
  methods: {
    // 开始 / 重新开始
    start() {
      this.visibility = "visible";
      this.progress = 0;
      this.$el.innerHTML = "";
      clearInterval(this.timer);
      this.write();
      this.$emit("writeStart");
    },
    // 暂停
    pause() {
      clearInterval(this.timer);
      this.$emit("writePause");
    },
    // 继续
    continueWrite() {
      if(!this.progress || this.progress >= this.initialDom.length){
        return
      }
      clearInterval(this.timer);
      this.write();
      this.$emit("writeContinue");
    },
    // 重置
    reset() {
      this.visibility = "hidden";
      this.progress = 0;
      this.$el.innerHTML = "";
      clearInterval(this.timer);
    },
    // 书写
    write() {
      this.timer = setInterval(() => {
        var current = this.initialDom.substr(this.progress, 1);
        // console.log(current);
        // 跳过 标签渲染
        if (current === "<") {
          this.progress = this.initialDom.indexOf(">", this.progress) + 1;
        } else {
          this.progress++;
        }
        // console.log(this.progress & 1, "this.progress");
        // 如果有光标配置 拼接到最新渲染的地方
        if (this.cursorStr) {
          this.$el.innerHTML =
            this.initialDom.substring(0, this.progress) +
            (this.progress < this.initialDom.length && this.progress & 1
              ? this.cursorStr
              : "");
        } else {
          this.$el.innerHTML = this.initialDom.substring(0, this.progress);
        }
        // 文本书写进度 大于需要书写的总长度 判断为渲染完成
        if (this.progress >= this.initialDom.length) {
          clearInterval(this.timer);
          this.$emit("writeEnd"); // 打字完成后的回调方法
        }
      }, this.interval);
    },
  },
  beforeDestroy() {
    clearInterval(this.timer);
  },
};
</script>

父级组件引用

js 复制代码
<template>
  <div class="app-container home">
    <div class="body">
      <button type="primary" @click="start">开始 / 重新开始</button>
      <button type="primary" @click="pause">暂停</button>
      <button type="primary" @click="continueWrite">继续</button>
      <button type="primary" @click="reset">重置</button>
      <VueTypewriter
        class="tl"
        ref="typewriter"
        :interval="50"
        cursorStr=""
        @writeEnd="writeEnd"
      >
        <div class="comments">
          <p>const array = [1, 2, 2, 3, 4, 4, 5];</p>
          <p>const uniqueArray = Array.from(new Set(array));</p>
          <p>console.log(uniqueArray);</p>
          <p>{{ message }}</p>
        </div>
        <table>
          <tr>
            <td>1</td>
            <td>2</td>
            <td>3</td>
            <td>4</td>
            <td>5</td>
            <td>6</td>
            <td>7</td>
            <td>8</td>
            <td>9</td>
            <td>0</td>
          </tr>
        </table>
      </VueTypewriter>
    </div>
  </div>
</template>

<script>
import VueTypewriter from "./vue-typewriter";
export default {
  name: "Demo",
  components: { VueTypewriter },
  data() {
    return {
      message: "测试插值表达式 是否能够正常渲染",
    };
  },
  methods: {
    // 开始
    start() {
      this.$refs.typewriter.start();
    },
    // 暂停
    pause() {
      this.$refs.typewriter.pause();
    },
    // 继续
    continueWrite() {
      this.$refs.typewriter.continueWrite();
    },
    // 重置
    reset() {
      this.$refs.typewriter.reset();
    },
    // 结束回调
    writeEnd() {
      console.log("end");
    },
  },
};
</script>

<style scoped lang="scss">
.home {
  text-align: left;
  .body {
    width: 890px;
    height: 500px;
    padding: 20px;
    border: #b2c92a solid 10px;
    button {
      margin-right: 20px;
      padding: 8px 20px;
    }
    .comments {
      p {
        font-size: 18px;
        color: green;
      }
    }
    table {
      margin: 20px 0;
      border-collapse: collapse;
      td {
        padding: 10px 20px;
        border: 1px solid #ccc;
      }
    }
  }
}
</style>
相关推荐
usdoc文档预览1 小时前
USDOC系列之PPT文件在线编辑-VUE前端实现在线浏览器在线编辑PPT文档
前端·vue.js·编辑器·office365·ppt在线编辑·office文件在线编辑·文件在线编辑
Java小卷1 小时前
面向 schema 编程,轻松搞定 Element 虚拟化表格复杂应用场景
vue.js·低代码·element
用户2705077725241 小时前
Agent 调工具卡住?3 种超时与取消策略实测对比
前端
LuHang2 小时前
我一行代码没写,把领导派的活做成了公司内部系统😭
前端
明月_清风2 小时前
Meta 开源了一个 AI Native 组件库:Astryx,150+ React 组件,专为 AI Agent 而设计
前端·人工智能·ai编程
仨孩子的爹2 小时前
Lodop、hiprint 与 vue-print-designer:打印控件选型对比
vue.js
用户850869276152 小时前
秒杀系统中 Shell 脚本并发控制 Bug:究竟哪里出了
前端
程序员大阳4 小时前
HTML+CSS+JS对话式实战(3)-活动管理页实现查询、新增、删除API后端接口
javascript·css·html·实战·删除·查询·新增
炫酷的大高个5 小时前
6 亿播放的闪身步,我用前端算出 15 倍重心差
前端·javascript
不可能片场5 小时前
内容运营自动化 配图折行别把词切两半
前端·electron