Vue/Nuxt 3 — невозможно установить свойства null (настройка textContent)

У меня есть функция, которая должна менять слова каждые несколько секунд. Все работает как положено, но каждые несколько секунд я получаю следующую ошибку в консоли VSC:

TypeError: невозможно установить свойства null (настройка textContent) в Timeout._onTimeout (.../components/home/Hero.vue:36:28) в listOnTimeout (узел: внутренний/таймеры: 564:17)

Я не понимаю, почему я получаю эту ошибку, потому что когда я запускаю console.info word.value, я получаю элемент. Так что у меня есть к нему доступ и функция работает, слова меняются каждые несколько секунд, как и положено. Я немного запутался и не знаю, как решить проблему. Я не получаю ошибку в консоли Google Chrome, только в VSC.

<span ref = "word"></span>
onMounted(() => {
  randomizeText()
  wordChanger
})

onBeforeRouteLeave(() => {
  clearTimeout(wordChanger)
})

const wordChanger = setInterval(randomizeText, 4000)

const word = ref(null)
const words = reactive(['Word-1', 'Word-2'])
let i = 0

function randomizeText() {
  i = randomNum(i, words.length)
  const newWord = words[i]

  setTimeout(() => {
    word.value.textContent = newWord
  }, 200) // time to allow opacity to hit 0 before changing word
}

function randomNum(num, max) {
  let j = Math.floor(Math.random() * max)

  // ensure diff num every time
  if (num === j) {
    return randomNum(i, max)
  } else {
    return j
  }
}
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
83
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вместо того, чтобы использовать const word = ref(null) как refs. Вы можете напрямую назвать это константой word в своем шаблоне. Он должен работать так же.

<template>
  <div>
    <span>{{ word }}</span>
  </div>
</template>

Внутри функции setTimeout измените это word.value.textContent = newWord на это word.value = newWord.

Вот обновленные коды. Проверено, и это работает.

<script setup lang = "ts">
onMounted(() => {
  randomizeText()
  wordChanger
})

onBeforeRouteLeave(() => {
  clearTimeout(wordChanger)
})

const wordChanger = setInterval(randomizeText, 4000)

const word = ref('') // UPDATED
const words = reactive(['Word-1', 'Word-2'])
let i = 0

function randomizeText() {
  i = randomNum(i, words.length)
  const newWord = words[i]

  setTimeout(() => {
    word.value = newWord // UPDATED
  }, 200) // time to allow opacity to hit 0 before changing word
}

function randomNum(num, max) {
  let j = Math.floor(Math.random() * max)

  // ensure diff num every time
  if (num === j) {
    return randomNum(i, max)
  } else {
    return j
  }
}
</script>
<template>
  <div>
    <span>{{ word }}</span>
  </div>
</template>

Надеюсь, это поможет вам.

Вероятно, это проблема синхронизации (элемент не смонтирован, пока он изменяется кодом)

Вы можете сделать это, не устанавливая свойство textContent напрямую, используя директиву v-html и просто изменяя ссылочную переменную (ref) Кроме того, вы можете просто начать интервал в крючке onMounted().

import {onMounted, reactive, ref} from "vue";
import {onBeforeRouteLeave} from "vue-router";

let wordChanger;

onMounted(() => {
    randomizeText()
    wordChanger = setInterval(randomizeText, 4000);
})

onBeforeRouteLeave(() => {
    clearTimeout(wordChanger)
})

let word = ref('Hoi')
const words = reactive(['Word-1', 'Word-2'])
let i = 0

function randomizeText() {
    i = randomNum(i, words.length)
    const newWord = words[i]

    setTimeout(() => {
        word.value = newWord
    }, 200) // time to allow opacity to hit 0 before changing word
}

function randomNum(num, max) {
    let j = Math.floor(Math.random() * max)

    // ensure diff num every time
    if (num === j) {
        return randomNum(i, max)
    } else {
        return j
    }
}
<span v-html = "word"></span>

Вы, вероятно, неправильно используете ref 'word' и некоторые другие детали, которыми я делюсь ниже: - примечание: я добавляю комментарии к строкам, которые я изменил, чтобы помочь вам лучше понять

setup() {
    

    const word = ref(null);
    const words = reactive(['Word-1', 'Word-2']);

    function randomizeText(i) {
      const p = randomNum(i, words.length);
      const newWord = words[p];

      setTimeout(() => {
        word.value = newWord;
      }, 200); // time to allow opacity to hit 0 before changing word
    }

    function randomNum(num, max) {
      let j = Math.floor(Math.random() * max);

      // ensure diff num every time
      if (num === j) {
        // notice here as well I use num instead of i
        return randomNum(num, max);
      } else {
        return j;
      }
    }
    
    const wordChanger = setInterval(randomizeText, 4000);
    
    onMounted(() => {
      randomizeText(0); // start with 0
      // wordChanger; // no need using this here
    });

    onBeforeRouteLeave(() => {
      clearTimeout(wordChanger);
    });

    return {
      word,
    };
  },
<span>{{ word }}</span>

вот демо: - https://stackblitz.com/edit/vue-rap7bb?file=src/components/HelloWorld.vue

Другие вопросы по теме