Javascript 调整大小时未定义Vue画布$ref。抛出错误,但works似乎仍能正常工作?

Javascript 调整大小时未定义Vue画布$ref。抛出错误,但works似乎仍能正常工作?,javascript,html,vue.js,Javascript,Html,Vue.js,在我的应用程序中,我有一个选项卡式界面,在选项卡的一个“窗口”中,有一个画布,每次调整窗口大小时,它都会自动适应窗口大小。一切正常,但当我切换选项卡并切换回来,然后尝试调整窗口大小时,它仍然可以工作,但会抛出“this.$refs.canvas is undefined”错误 我已经建立了一个简单的示例,可以切换画布元素的开和关。如果要尝试调试,则代码已完成。如果在加载后立即调整窗口的大小,并且窗口可以正常工作,那么没有问题,但是如果打开和关闭画布,它将抛出一个错误 主应用程序文件: <t

在我的应用程序中,我有一个选项卡式界面,在选项卡的一个“窗口”中,有一个画布,每次调整窗口大小时,它都会自动适应窗口大小。一切正常,但当我切换选项卡并切换回来,然后尝试调整窗口大小时,它仍然可以工作,但会抛出“this.$refs.canvas is undefined”错误

我已经建立了一个简单的示例,可以切换画布元素的开和关。如果要尝试调试,则代码已完成。如果在加载后立即调整窗口的大小,并且窗口可以正常工作,那么没有问题,但是如果打开和关闭画布,它将抛出一个错误

主应用程序文件:

<template>
  <div id="app">
    <button class="toggleBtn" @click="toggleCanvas()">Toggle Canvas</button>
    <component class="canvasBox" :is="canvasElX" />
  </div>
</template>

<script>
import ResizeCanvas from './components/ResizeCanvas.vue'

export default {
  name: 'App',
  components: {
    ResizeCanvas
  },
  data(){
    return {
      canvasShow: true,
      canvasEl: null
    }
  },
  computed: {
    canvasElX(){
      if (this.canvasShow){
        return ResizeCanvas;
      }
      else{
        return null;
      }
    }
  },
  methods: {
    toggleCanvas(){
      this.canvasShow = !this.canvasShow;
    }
  }
}
</script>

<style>
html, body{
  margin: 0px;
  padding: 0px;
  width: 100%;
  height: 100%;
}

#app {
  display: flex;
  width: 100%;
  height: 100%;
}

.toggleBtn{
  width: 150px;
}

.canvasBox{
  flex-grow: 1;
}
</style>

切换画布
从“./components/ResizeCanvas.vue”导入ResizeCanvas
导出默认值{
名称:“应用程序”,
组成部分:{
调整画布大小
},
数据(){
返回{
拉票秀:没错,
画布:空
}
},
计算:{
canvasElX(){
如果(本次拉票){
返回大小调整画布;
}
否则{
返回null;
}
}
},
方法:{
切换画布(){
this.canvasShow=!this.canvasShow;
}
}
}
html,正文{
边际:0px;
填充:0px;
宽度:100%;
身高:100%;
}
#应用程序{
显示器:flex;
宽度:100%;
身高:100%;
}
.toggleBtn{
宽度:150px;
}
.拉票箱{
柔性生长:1;
}
调整画布组件的大小:

<template>
  <div ref="resizeCanvas" class="resizeCanvas">
    <canvas ref="canvas" class="canvas">
      //Error loading canvas
    </canvas>
  </div>
</template>

<script>
export default {
  name: 'ResizeCanvas',
  mounted(){
    window.addEventListener('resize', ()=>{this.resizeCanvas()});

    this.resizeCanvas();
    this.drawCanvas();
  },
  beforeDestroy(){
    window.removeEventListener('resize', ()=>{this.resizeCanvas()});
  },
  methods: {
    resizeCanvas(){
      let canvas = this.$refs.canvas;

      canvas.width = this.$refs.resizeCanvas.clientWidth;
      canvas.height = this.$refs.resizeCanvas.offsetHeight;

      this.drawCanvas();
    },
    drawCanvas(){
      let canvas = this.$refs.canvas;
      let ctx = canvas.getContext('2d');

      ctx.fillStyle = 'black';
      ctx.fillRect(0, 0, 50, 50);
      ctx.fillRect(canvas.width - 50, canvas.height - 50, 50, 50);
    }
  }
}
</script>

<style scoped>
  .resizeCanvas{
    position: relative;
    width: 100%;
    height: 100%;
  }

  .canvas{
    position: absolute;
  }
</style>

//加载画布时出错
导出默认值{
名称:“ResizeCanvas”,
安装的(){
window.addEventListener('resize',()=>{this.resizeCanvas()});
这个.resizeCanvas();
这个.drawCanvas();
},
在…之前{
window.removeEventListener('resize',()=>{this.resizeCanvas()});
},
方法:{
调整画布大小(){
让canvas=this.$refs.canvas;
canvas.width=此。$refs.resizeCanvas.clientWidth;
canvas.height=此。$refs.resizeCanvas.offsetHeight;
这个.drawCanvas();
},
drawCanvas(){
让canvas=this.$refs.canvas;
设ctx=canvas.getContext('2d');
ctx.fillStyle='黑色';
ctx.fillRect(0,0,50,50);
ctx.fillRect(canvas.width-50,canvas.height-50,50);
}
}
}
.resizeCanvas{
位置:相对位置;
宽度:100%;
身高:100%;
}
.帆布{
位置:绝对位置;
}

这是一个相当令人费解的问题。尽管它似乎无论如何都能工作,但我担心这可能会在后台造成一些隐秘的问题,我将来必须找出困难的办法。

这里的问题是,您将不断添加新的事件侦听器,而旧的事件侦听器仍在运行,对
this的引用陈旧。$refs

这是因为您不幸没有正确使用(这是一个非常容易犯的错误)。要正常工作,您需要将与您在
addEventListener
中注册的完全相同的函数传递给它

只要传入对组件
方法的引用,就可以取消匿名箭头函数

mounted(){
window.addEventListener('resize',this.resizeCanvas)//传递方法引用
这个是resizeCanvas()
this.drawCanvas()
},
在…之前{
window.removeEventListener('resize',this.resizeCanvas)//相同的函数引用
},


如果您不想在每次激活选项卡时都重新加载画布,那么您可能会对以下内容感兴趣。

谢谢,工作起来很有魅力!这真的很令人沮丧,因为我以为我正在删除事件侦听器,所以我不知道它还能是什么。谢谢你澄清这一点。我真的不想让它保持活力,因为我更愿意释放内存,但“保持活力”这句话听起来在未来可能真的很有用,所以也谢谢你。