Creating a typewriter effect with Vue Js

Hey there, I'm having some trouble with the code below while working on my Vue project. It seems to be functioning correctly, but for some reason it's not working in my Vue environment.

const text = document.getElementById("text");
const phrases = [
  "I'm John Doe",
  "I'm student",
  "I'm developer",
];
let currentPhraseIndex = 0;
let currentCharacterIndex = 0;
let currentPhrase = "";
let isDeleting = false;

function loop() {
  const currentPhraseText = phrases[currentPhraseIndex];

  if (!isDeleting) {
    currentPhrase += currentPhraseText[currentCharacterIndex];
    currentCharacterIndex++;
  } else {
    currentPhrase = currentPhrase.slice(0, -1);
    currentCharacterIndex--;
  }

  text.innerHTML = currentPhrase;

  if (currentCharacterIndex === currentPhraseText.length) {
    isDeleting = true;
  }

  if (currentCharacterIndex === 0) {
    currentPhrase = "";
    isDeleting = false;
    currentPhraseIndex++;
    if (currentPhraseIndex === phrases.length) {
      currentPhraseIndex = 0;
    }
  }

  const spedUp = Math.random() * (80 - 50) + 50;
  const normalSpeed = Math.random() * (300 - 200) + 200;
  const time = isDeleting ? spedUp : normalSpeed;
  setTimeout(loop, time);
}

loop();
<h2 id="text"></h2>

Despite the code appearing to function correctly, it's not behaving as expected within my Vue Js setup. Here are the issues I encountered:

https://i.stack.imgur.com/DnlLU.png

If you have any suggestions for optimizing this code specifically for use with Vue, I'd appreciate your feedback. Thanks!

Answer ā„–1

Make sure to define variables in the data property and functions in methods, or utilize the composition API to make variables reactive:

const { ref, reactive, onMounted } = Vue
const app = Vue.createApp({
  setup() {
    const opt = reactive({
      currentPhraseIndex: 0, 
      currentCharacterIndex: 0, 
      currentPhrase: "", 
      isDeleting: false
    })
    const phrases = reactive([
      "I'm John Doe",
      "I'm student",
      "I'm developer"
    ])
    const text = ref('')
    const loop = () => {
      const currentPhraseText = phrases[opt.currentPhraseIndex];
      if (!opt.isDeleting) {
        opt.currentPhrase += currentPhraseText[opt.currentCharacterIndex];
        opt.currentCharacterIndex++;
      } else {
        opt.currentPhrase = opt.currentPhrase.slice(0, -1);
        opt.currentCharacterIndex--;
      }
      text.value = opt.currentPhrase;
      if (opt.currentCharacterIndex === currentPhraseText.length) {
        opt.isDeleting = true;
      }
      if (opt.currentCharacterIndex === 0) {
        opt.currentPhrase = "";
        opt.isDeleting = false;
        opt.currentPhraseIndex++;
        if (opt.currentPhraseIndex === opt.phrases?.length) {
          opt.currentPhraseIndex = 0;
        }
      }
      const spedUp = Math.random() * (80 - 50) + 50;
      const normalSpeed = Math.random() * (300 - 200) + 200;
      const time = opt.isDeleting ? spedUp : normalSpeed;
      setTimeout(loop, time);
    }
    onMounted(() => {
      loop()
    })
    return {
      text
    }
  }
})
app.mount('#demo')
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<div id="demo">
  <h2>{{ text }}</h2>
</div>

Answer ā„–2

I have discovered the solution to get it functioning properly. The updated code below has been successfully implemented using Vue.js 3.

<script setup>
import { ref } from "vue";

const phrases = [
  "I am John Doe.",
  "I am student.",
  "I am developer.",
];

const currentPhraseIndex = ref(0);
const currentCharacterIndex = ref(0);
const currentPhrase = ref("");
const isDeleting = ref(false);

function loop() {
  const currentPhraseText = phrases[currentPhraseIndex.value];

  if (!isDeleting.value) {
    currentPhrase.value += currentPhraseText[currentCharacterIndex.value];
    currentCharacterIndex.value++;
  } else {
    currentPhrase.value = currentPhrase.value.slice(0, -1);
    currentCharacterIndex.value--;
  }

  if (currentCharacterIndex.value === currentPhraseText.length) {
    isDeleting.value = true;
  }

  if (currentCharacterIndex.value === 0) {
    currentPhrase.value = "";
    isDeleting.value = false;
    currentPhraseIndex.value++;
    if (currentPhraseIndex.value === phrases.length) {
      currentPhraseIndex.value = 0;
    }
  }

  const spedUp = Math.random() * (80 - 50) + 50;
  const normalSpeed = Math.random() * (300 - 200) + 200;
  const time = isDeleting.value ? spedUp : normalSpeed;
  setTimeout(loop, time);
}

loop();
</script>
<template>
    <div>
      <h1 id="title">{{ currentPhrase }}</h1>
    </div>
</template>

Answer ā„–3

Make sure to include the following line

if (opt.currentCharacterIndex === currentPhraseText.length) {
  opt.isDeleting = true;
  opt.currentPhraseIndex = 0; //  <===== don't forget this part 
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Cannon-js: Experience dynamic body bouncing on the y axis as it reacts to force applied on the x and z axes

Currently, I am working on an FPS game where the player controller applies force based on keyboard inputs to a dynamic cannon body. The angular dampening is set to 1 on the player body. The PlayerController class takes both the player class (which extends ...

A method for consolidating multiple enum declarations in a single TypeScript file and exporting them under a single statement to avoid direct exposure of individual enums

I am looking to consolidate multiple enums in a single file and export them under one export statement. Then, when I import this unified file in another file, I should be able to access any specific enum as needed. My current setup involves having 2 separ ...

Organize based on 2 factors, with emphasis on 1

Looking for a way to sort a list of posts by two variables - date (created) and score (score>). The main goal is to prioritize the sorting based on the score, so that the highest scoring posts appear first.</p> <p>To clarify, the desired so ...

Preventing Past Dates from Being Selected in JQuery Date Picker

Need help with a date picker that only allows selection of the 1st and 15th dates of each month. How can I prevent users from selecting previous dates? <link href="https://code.jquery.com/ui/1.12.1/themes/smoothness/jquery-ui.css" rel="stylesheet" ty ...

Upload an array of choices to the server by utilizing ng-model

I have almost resolved my issue, but now I need help with sending the data to the server. In my current situation, there is a form that includes employee details and projects for that employee (which can be multiple). When the user wants to add projects, ...

Managing iframes in React using reference methods

Trying to set the content of an iframe within a React component can be a bit tricky. There is a component that contains a handleStatementPrint function which needs to be called when the iframe finishes loading. The goal is to print the loaded iframe conten ...

Encountering an issue: Unable to initiate a local server when running `npm start`

Currently diving into the world of React, I successfully set up a React app. However, upon running npm install after typing cd davidsapp, I encountered numerous warnings and errors. Subsequently, when issuing the command npm start, all of the errors are di ...

JavaScript prototypal inheritance concept

During my free time, I like to dabble in JavaScript, but Iā€™m currently struggling with this particular topic. var person = new Person("Bob", "Smith", 52); var teacher = new Teacher("Adam", "Greff", 209); function Humans(firstName, lastName) { this. ...

Struggling to reset the jscrollpane scroller

When using jscrollpane in my horizontal division to enable scrolling, I encounter an issue when loading data with ajax. The scrollbar doesn't appear until the browser width is changed. To address this, I currently utilize the following method to rein ...

Exploring the source code of NPM public and private packages within the node_modules directory

As someone who is new to javascript development, I want to create a private npm package that cannot be accessed by users. However, I have noticed that I can still view the code of other npm packages labeled as closed-source by entering their node_modules s ...

Combine multiple jQuery click functions into a single function

One issue I am facing on my website is that there are multiple modules, each of which can be disabled by the user. The problem lies in the fact that I have a separate script for each module. Hence, my query: How can I combine these scripts into one (perhap ...

In order to set a condition for the mat date picker to display a text box in Angular if the selected date is for someone under 18 years old

I need assistance with displaying a text field based on age validation. The requirement is to show the input field only if the age is less than 18. Below is the code snippet I am currently working with: <form [formGroup]="form"> ...

Top method for filling an array with strings

Imagine having an array called 'newArray'. var newArray = []; You can add strings to it like this: var thisString = 'watch'; newArray.push(thisString); Now, if you want to have 50 instances of the 'thisString' in the newAr ...

If a specific class is identified, add a border to the div when clicked using JavaScript

Is there a way to use javascript/jquery to add a border to a selected div? I have multiple rows with columns, and I want only one column per row to be highlighted with a border when clicked. Each row should have one column with a border, so it's clear ...

How to update MongoDB documents with referenced objects using Mongoose?

Apologies for any language barriers. I am using node.js + express.js + mongoose.js Here is my schema in mongoose for groups: var groupSchema = new mongoose.Schema({ name: String, users: [{type: mongoose.Schema.ObjectId, ref: 'User'}] ...

The issue with the $(window).width() property not functioning correctly in Internet Explorer

Currently, I have a Div element with absolute positioning: <div id="target" style="height: 300px; position: absolute; top: 275px;"></div> My goal is to calculate the horizontal resolution of the screen using JavaScript. With this width, I the ...

Building a WordPress calculator form that retains user input without requiring a resubmit and incorporates custom field values

Currently tackling a challenge on my Wordpress website. Without any code yet (after numerous attempts at rewriting 4 different forms), I'll simply outline what I aim to accomplish, confident it's a straightforward task with something crucial elud ...

What could be causing the malfunction of my Nextjs Route Interception Modal?

I'm currently exploring a different approach to integrating route interception into my Nextjs test application, loosely following this tutorial. Utilizing the Nextjs app router, I have successfully set up parallel routing and now aiming to incorporate ...

Creating custom directives in Vue2 is just like adding a functionality similar to v

I am in the process of developing a unique directive similar to v-if that will only render if the data passed into the element is not empty. For instance: <div v-if="!_.isEmpty(data.employer)">{{ data.employer.name }}</div> This code snippet ...

What is the most efficient method for storing text in my web application?

Hey there, I'm looking for a way to easily store and access the wording used in my application so that I can use them again whenever needed. For example, loading messages, validation messages, or informational messages are some of the wordings I want ...