Проект Vue - Uncaught TypeError: невозможно прочитать свойства ошибки null (чтение 'offsetWidth') для пользовательского сценария js

поэтому я конвертирую собственный HTML-шаблон в проект vuejs. Я импортировал все файлы css и js для использования на моей домашней странице. Файлы css загружаются нормально. Для файлов JS тема поставляется с несколькими пользовательскими сценариями js вместе с обычными библиотеками, такими как three.js и т. д. Я импортирую их все ниже моего HomeComponent в теге скрипта. Но я сталкиваюсь с этой ошибкой:

"Uncaught TypeError: Cannot read properties of null (reading 'offsetWidth')
    at eval (demo3.js?dad6:2:20)
    at ./src/assets/assets/js/demo3.js (app.js:92:1)
    at __webpack_require__ (app.js:1124:33)
    at fn (app.js:1357:21)
    at eval (index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/HomeComponent.vue?vue&type=script&lang=js:26:85)
    at ./node_modules/babel-loader/lib/index.js??clonedRuleSet-40.use[0]!./node_modules/vue-loader/dist/index.js??ruleSet[0].use[0]!./src/components/HomeComponent.vue?vue&type=script&lang=js (app.js:30:1)
    at __webpack_require__ (app.js:1124:33)
    at fn (app.js:1357:21)
    at eval (HomeComponent.vue?vue&type=script&lang=js:5:216)
    at ./src/components/HomeComponent.vue?vue&type=script&lang=js (app.js:296:1)"

Ниже приведен мой код App.vue:

<template>
  <router-view />
</template>
<script>
export default {
  name: "App",
  components: {},
};
</script>

Ниже приведен мой код homecomponent.vue (частично — некоторый код скрыт внутри шаблона):

<template>
  <header class = "offcanvas-menu">
    <input type = "checkbox" id = "toogle-menu" />

    <label for = "toogle-menu" class = "toogle-open"><span></span></label>

    <nav>
      <div>
        <label for = "toogle-menu" class = "toogle-close">
          <span></span>
        </label>
      </div>
      <ul>
        <li><a href = "#section1">Section </a></li>
        <li><a href = "#section2">Section </a></li>
        <li><a href = "#section3">Section </a></li>
        <li><a href = "#section4">Section </a></li>
        <li><a href = "#section5">Section </a></li>
      </ul>
    </nav>
  </header>
  <main>
    <div class = "content">
      <canvas class = "scene scene--full" id = "scene"></canvas>
      <div class = "content__inner">
        <h2 class = "content__title">مؤشر المعلوماتية</h2>
        <div class = "content-button mt-2">
          <button
            type = "button"
            class = "btn btn-relief-primary btn-large menu-trigger display-5"
          >
            <i data-feather = "menu"></i> القائمة
          </button>
        </div>
      </div>
    </div>

    <nav class = "grim">
      <div class = "grim__item">
        <div class = "grim__item-bg grim__item-bg--5"></div>
      </div>
      <div class = "grim__item">
        <div class = "grim__item-bg grim__item-bg--5"></div>
      </div>
      <div class = "grim__item">
        <div class = "grim__item-bg grim__item-bg--5"></div>
        <div class = "grim__item-content">
          <div class = "grim__item-inner"></div>
        </div>
      </div>
  ..
   
    
      <div class = "grim__item">
        <div class = "grim__item-bg grim__item-bg--9"></div>
        <div class = "grim__item-img grim__item-img--4"></div>
        <a href = "dashboard-region.html" class = "grim__link grim__item-content">
          <div class = "grim__item-inner">
            <h3 class = "grim__item-title">test</h3>
            <span class = "grim__item-desc">test</span>
          </div>
        </a>
        <div class = "grim__item-bg grim__item-bg-cover grim__item-bg--9"></div>
      </div>
      <div class = "grim__item">
        <div class = "grim__item-bg grim__item-bg--10"></div>
        <div class = "grim__item-img grim__item-img--5" style = ""></div>
        <a href = "wizard.html" class = "grim__link grim__item-content">
          <div class = "grim__item-inner">
            <h3 class = "grim__item-title">test</h3>
            <span class = "grim__item-desc"
              >test</span
            >
          </div>
        </a>
        <div class = "grim__item-bg grim__item-bg-cover grim__item-bg--10"></div>
      </div>
    </nav>
  </main>
  <!-- home -->
</template>
<style>
@import url("https://fonts.googleapis.com/css?family=Barlow:400,500,700|Poppins:600");
@import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,300;0,400;0,500;0,600;1,400;1,500;1,600");
</style>
<script>
//All css files
import "../assets/assets/css/base.css";

import "../assets/app-assets/css-rtl/bootstrap.css";
import "../assets/app-assets/css-rtl/bootstrap-extended.css";
import "../assets/app-assets/css-rtl/colors.css";
import "../assets/app-assets/css-rtl/themes/dark-layout.css";
import "../assets/assets/css/menu.css";

import "../assets/app-assets/css-rtl/custom-rtl.css";
import "../assets/assets/css/style-rtl.css";

export default {
  name: "HomeComponent",
};

//All JS files
import "../assets/assets/js/demo.js";
import "../assets/assets/js/three.min.js";
import "../assets/assets/js/perlin.js";
import "../assets/assets/js/TweenMax.min.js";
import "../assets/assets/js/demo3.js";
import "../assets/assets/js/grid.js";
import "../assets/assets/js/imagesloaded.pkgd.min.js";
import "../assets/assets/js/anime.min.js";
import "../assets/assets/js/menu2.js";
</script>

Проблема связана с файлом demo3.js.

Демо3.js

var canvas = document.querySelector("#scene");
var width = canvas.offsetWidth,
  height = canvas.offsetHeight;

var renderer = new THREE.WebGLRenderer({
  canvas: canvas,
  antialias: true,
});
renderer.setPixelRatio(window.devicePixelRatio > 1 ? 2 : 1);
renderer.setSize(width, height);
renderer.setClearColor(0x161d31);

var scene = new THREE.Scene();

var camera = new THREE.PerspectiveCamera(100, width / height, 0.1, 10000);
camera.position.set(120, 0, 300);

var light = new THREE.HemisphereLight(0xffffff, 0x0c056d, 0.6);
scene.add(light);

var light = new THREE.DirectionalLight(0x590d82, 0.5);
light.position.set(100, 300, 400);
scene.add(light);
var light2 = light.clone();
light2.position.set(-100, 300, 400);
scene.add(light2);

var geometry = new THREE.IcosahedronGeometry(120, 4);
for (var i = 0; i < geometry.vertices.length; i++) {
  var vector = geometry.vertices[i];
  vector._o = vector.clone();
}
var material = new THREE.MeshPhongMaterial({
  emissive: 0x23f660,
  emissiveIntensity: 0.4,
  shininess: 0,
});
var shape = new THREE.Mesh(geometry, material);
scene.add(shape);

function updateVertices(a) {
  for (var i = 0; i < geometry.vertices.length; i++) {
    var vector = geometry.vertices[i];
    vector.copy(vector._o);
    var perlin = noise.simplex3(
      vector.x * 0.006 + a * 0.0002,
      vector.y * 0.006 + a * 0.0003,
      vector.z * 0.006
    );
    var ratio = perlin * 0.4 * (mouse.y + 0.3) + 0.9;
    vector.multiplyScalar(ratio);
  }
  geometry.verticesNeedUpdate = true;
}

function render(a) {
  requestAnimationFrame(render);
  updateVertices(a);
  renderer.render(scene, camera);
}

function onResize() {
  canvas.style.width = "";
  canvas.style.height = "";
  width = canvas.offsetWidth;
  height = canvas.offsetHeight;
  camera.aspect = width / height;
  camera.updateProjectionMatrix();
  renderer.setSize(width, height);
}

var mouse = new THREE.Vector2(0.8, 0.5);
function onMouseMove(e) {
  TweenMax.to(mouse, 0.8, {
    y: e.clientY / height,
    x: e.clientX / width,
    ease: Power1.easeOut,
  });
}

requestAnimationFrame(render);
window.addEventListener("mousemove", onMouseMove);
var resizeTm;
window.addEventListener("resize", function () {
  resizeTm = clearTimeout(resizeTm);
  resizeTm = setTimeout(onResize, 200);
});

Итак, мое приложение вообще не загружается. теперь я потерял, как это решить. Это мой первый опыт преобразования html-шаблона в vuejs. Хз чего ожидать. Скриншот файловой структуры (https://i.stack.imgur.com/dKzTb.png)

скриншот сведений об ошибке в console.info (https://i.stack.imgur.com/9Rzap.png)

В demo3.js эта строка дает вам нулевой объект var canvas = document.querySelector("#scene"); Итак, ваш холст = null, и вы не можете получить доступ к offsetWidth

Legit007 17.01.2023 09:32

@ Legit007, как это исправить? Я понимаю, что это так, я должен как-то смонтировать дом до загрузки js, но не знаю, как

Sam 17.01.2023 09:33

Может быть, вы можете попробовать использовать асинхронный смонтированный экспорт по умолчанию: lavalite.org/blog/created-and-mountedin-vuejs и вызвать свой js в смонтированном блоке

Legit007 17.01.2023 09:35

не сработало :( @Legit007

Sam 17.01.2023 09:40

Итак, вы вызвали свою js-функцию в смонтированной функции и все еще получаете null с помощью document.querySelector("#scene")? Вам нужно добавить смонтированную функцию в homecomponent.vue. Вам не следует импортировать 'import "../assets/assets/js/demo3.js"; вам нужно импортировать функцию. Like -> import {yourFunction} из "demo3.js";

Legit007 17.01.2023 09:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
94
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вы импортируете свой файл demo3.js (и, следовательно, выполняете его) до того, как приложение отобразит DOM. Итак, элемент #scene еще не существует, в результате получается null.

Несколько решений для этого:

  1. Вы динамически импортируете свой файл demo3.js после хука mounted:
mounted() {
  import('../assets/assets/js/demo3.js') // dynamic import
}
  1. Вы заключаете свой код demo3.js в функцию и экспортируете его.
// demo3.js

export function renderScene() {
  var canvas = document.querySelector("#scene");
  var width = canvas.offsetWidth,
    height = canvas.offsetHeight;
  // [...]
}
import { renderScene } from '../assets/assets/js/demo3.js'

export default {
  mounted() {
    renderScene()
  }
}
  1. Вы перемещаете свой код demo3.js в компонент vue и используете ссылки на шаблоны.
mounted() {
  const scene = this.$refs.scene
  if (scene) {
    const width = canvas.offsetWidth,
      height = canvas.offsetHeight;

    const renderer = new THREE.WebGLRenderer({
      canvas: canvas,
      antialias: true,
    });
    // [...]
  }
}

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