Vue.js refs 未定义,即使 this.$refs 显示在那里

Kyl*_*lie 21 javascript vue.js

我有一个组件的引用

 <Gmap ref="mapRef">
Run Code Online (Sandbox Code Playgroud)

在安装中,我正在这样做,只是为了查看对象可用

 mounted(){
   let self = this
   console.log(self.$refs) // Shows the mapRef object reference
   console.log(self.$refs.mapRef) // returns undefined ???
 }
Run Code Online (Sandbox Code Playgroud)

self.$refs 显示...

  mapRef: VueComponent {_uid: 207, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
Run Code Online (Sandbox Code Playgroud)

那么为什么 self.$refs.mapRef 返回 undefined 呢??即使它明显在那里??

Kyl*_*lie 23

我通过使用 v-show 而不是 v-if 解决了这个问题。

我有一个 v-if 语句中的组件。

 <div v-if="!isLoading"> 
   <GMap ref="mapRef" />
 </div>
Run Code Online (Sandbox Code Playgroud)

我只是把它改成了 v-show

<div v-show="!isLoading"> 
   <GMap ref="mapRef" />
 </div>
Run Code Online (Sandbox Code Playgroud)

现在该对象在mounted() 中可用。仍然觉得很奇怪,console.log(this.$refs) 显示它可以作为 this.$refs 的一个键,即使它实际上不是?那是奇怪的行为。

另一个奇怪的事情是,即使我试图在我的数据加载部分访问 this.$refs.mapRef,在加载数据之后(即在 isLoading=false 之后),我仍然无法访问它。即使那样,它也应该可用,因为 v-if 已通过。

所以 v-show 解决了这个问题,只是隐藏了 div,而不是不渲染它。愚蠢的小解决方法。

  • `this.$refs` 被挂载后填充。当您打开对象时,console.log 会显示该对象的当前版本。尝试以下操作:`let a = {foo: 1}; 控制台.log(a); a.bar = 2;` 它将生成一个同时具有 foo 和 bar 属性的 a。 (2认同)

chr*_*arx 13

我在获取传单地图实例的引用时遇到了类似的问题,请尝试等待“nextTick”

mounted(){
  this.$nextTick(()=>{
    let self = this
    console.log(self.$refs) // Shows the mapRef object reference
    console.log(self.$refs.mapRef) // returns undefined ???
  });
}
Run Code Online (Sandbox Code Playgroud)

更多信息请参见文档 - https://vuejs.org/v2/api/#vm-nextTickhttps://vuejs.org/v2/api/#mounted

  • 不,仍然返回未定义。我难住了:( (4认同)
  • 我解决了它,引用的 GMap 位于 v-if 语句内。我将其更改为 v-show,现在可以使用了。奇怪的是 console.log(this.$refs) 仍然显示它“在那里”。 (3认同)

Nic*_*Yap 5

主要解决方案是确保您的组件不是动态导入的

您仍然需要避免v-ifthis.$refs.mapRefin包装组件并使用in mounted(),而不是created()

我没有使用 Vue Google Maps 插件/组件,而是我自己的自定义组件


方法一

用:

import CustomComponent from './CustomComponent ';

export default {
  components: {
    CustomComponent,
  },
  ...
}
Run Code Online (Sandbox Code Playgroud)

代替

export default {
  components: {
    CustomComponent: () => import('./CustomComponent'),
  },
  ...
}
Run Code Online (Sandbox Code Playgroud)

方法二

使用this.$refs.mapRefinmounted()而不是created()

通过这种方式,setTimeout()this.$nextTick()不是需要

正确做法:

import CustomComponent from './CustomComponent ';

export default {
  components: {
    CustomComponent,
  },
  ...
}
Run Code Online (Sandbox Code Playgroud)

错误的方法:

export default {
  components: {
    CustomComponent: () => import('./CustomComponent'),
  },
  ...
}
Run Code Online (Sandbox Code Playgroud)

方法三

不要使用 包装子组件v-ifv-show而是使用。

正确做法:

mounted(){
  //works! child components were loaded
  console.log(this.$refs.mapRef) 
}
Run Code Online (Sandbox Code Playgroud)

错误的方法:

created(){
  //DON'T DO THIS! child components hasn't loaded
  console.log(this.$refs.mapRef) 

  //might work but it's an unreliable workaround
  setTimeout(()=>{
    console.log(this.$refs.mapRef)
  }, 0);

  //might work but it's an unreliable workaround
  this.$nextTick(()=>{
    console.log(this.$refs.mapRef)
  });

}
Run Code Online (Sandbox Code Playgroud)

其他方法(不合适且不是解决方案)

以下是我尝试过的方法,但直到我使用了上面的方法(停止使用动态导入)才起作用

我已经把this.$refs.mapRefmounted()试图用其包装setTimeout()和2层this.$nextTick()

它仅适用于热重载,但在页面刷新后不再有效

mounted(){
  setTimeout(()=>{
    this.$nextTick(()=>{
      this.$nextTick(()=>{
        console.log(this.$refs.mapRef) // returns undefined
      });
    });
  }, 0);
}
Run Code Online (Sandbox Code Playgroud)

感谢另一个答案中的评论: How to access to a child method from the parent in vue.js