Home > Software design >  Vue project - Uncaught TypeError: Cannot read properties of null (reading 'offsetWidth') e
Vue project - Uncaught TypeError: Cannot read properties of null (reading 'offsetWidth') e

Time:01-20

so I'm converting a custom html template to a vuejs project. I've imported all css and js files to be used in my homepage. Css files are loading fine. For JS files, the theme came with a few custom js scripts along with usual libraries like three.js etc. I'm importing all of them below my HomeComponent in the script tag. But I run into this error:

"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)"

Below is my App.vue code:

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

Below is my homecomponent.vue code (partial - some code hidden from inside template):

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

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

    <nav>
      <div>
        <label for="toogle-menu" >
          <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 >
      <canvas  id="scene"></canvas>
      <div >
        <h2 >مؤشر المعلوماتية</h2>
        <div >
          <button
            type="button"
            
          >
            <i data-feather="menu"></i> القائمة
          </button>
        </div>
      </div>
    </div>

    <nav >
      <div >
        <div ></div>
      </div>
      <div >
        <div ></div>
      </div>
      <div >
        <div ></div>
        <div >
          <div ></div>
        </div>
      </div>
  ..
   
    
      <div >
        <div ></div>
        <div ></div>
        <a href="dashboard-region.html" >
          <div >
            <h3 >test</h3>
            <span >test</span>
          </div>
        </a>
        <div ></div>
      </div>
      <div >
        <div ></div>
        <div  style=""></div>
        <a href="wizard.html" >
          <div >
            <h3 >test</h3>
            <span 
              >test</span
            >
          </div>
        </a>
        <div ></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>

The issue is with the demo3.js file.

Demo3.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 onm ouseMove(e) {
  TweenMax.to(mouse, 0.8, {
    y: e.clientY / height,
    x: e.clientX / width,
    ease: Power1.easeOut,
  });
}

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

So, my app is not loading at all. now I'm lost how to resolve this. This is my first time converting html template to vuejs. Idk what to expect. Screenshot of file scructure (https://i.stack.imgur.com/dKzTb.png)

screenshot of error details in console.log (https://i.stack.imgur.com/9Rzap.png)

CodePudding user response:

You are importing your demo3.js file (and thus executing it) before the app rendered the DOM. So the element #scene doesn't exist yet, resulting in being null.

Several solutions for this:

  1. You import dynamically your demo3.js file after mounted hook:
mounted() {
  import('../assets/assets/js/demo3.js') // dynamic import
}
  1. You wrap your demo3.js code inside a function and export it.
// 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. You move your demo3.js code to a vue component, and use template refs.
mounted() {
  const scene = this.$refs.scene
  if (scene) {
    const width = canvas.offsetWidth,
      height = canvas.offsetHeight;

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