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>
相关推荐
四喜花露水7 分钟前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy16 分钟前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie1 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust1 小时前
css:基础
前端·css
帅帅哥的兜兜1 小时前
css基础:底部固定,导航栏浮动在顶部
前端·css·css3
工业甲酰苯胺1 小时前
C# 单例模式的多种实现
javascript·单例模式·c#
yi碗汤园1 小时前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
就是个名称1 小时前
购物车-多元素组合动画css
前端·css
编程一生1 小时前
回调数据丢了?
运维·服务器·前端
丶21362 小时前
【鉴权】深入了解 Cookie:Web 开发中的客户端存储小数据
前端·安全·web