【问题标题】:Vue.js refs are undefined, even though this.$refs shows theyre thereVue.js refs 是未定义的,即使 this.$refs 显示它们在那里
【发布时间】:2019-06-18 16:53:40
【问题描述】:

我有一个组件的引用

 <Gmap ref="mapRef">

在挂载中我这样做,只是为了查看对象是否可用

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

self.$refs 显示...

  mapRef: VueComponent {_uid: 207, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}

那么为什么 self.$refs.mapRef 返回 undefined? 明明就在那里??

【问题讨论】:

  • 普通的旧 this.$refs 怎么样?
  • 请注意,mounted 并不能保证所有子组件也已安装docs
  • 我确实提供了链接,但这里又是mounted docs
  • 使用debugger(或放置断点)代替console.log(),并检查值
  • 您可以查看this questionconsole.log 有一些怪癖

标签: javascript vue.js


【解决方案1】:

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

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

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

【讨论】:

  • 不,仍然返回未定义。我难倒:(
  • 我试过 jsFiddle。它在那里工作。不幸的是,它似乎只发生在我的项目中。我在地图上使用 vue2-google-maps 组件。所以也许它与那个特定的组件生命周期或类似的东西有关?不太确定。
  • 我查看了 vue2-google-maps 存储库,似乎以 nextTick 为主要答案解决了类似的问题,但也许这里的一些回复会有所帮助 - github.com/xkjyeah/vue-google-maps/issues/260跨度>
  • 我解决了,引用的 GMap 在 v-if 语句中。我将其更改为 v-show 并且现在可以使用。奇怪的是,console.log(this.$refs) 仍然显示为“在那里”。
【解决方案2】:

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

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

 <div v-if="!isLoading"> 
   <GMap ref="mapRef" />
 </div>

我只是把它改成了 v-show

<div v-show="!isLoading"> 
   <GMap ref="mapRef" />
 </div>

现在该对象在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}; console.log(a); a.bar = 2; 这将导致 a 同时具有 foo 和 bar 属性。
【解决方案3】:

您可以将您的函数包装在vue2-google-maps 提供的$mapPromise 方法中,这将确保地图在运行您的代码之前已经完全渲染:

let self = this;
self.$refs.mapRef.$mapPromise.then(() => {
    console.log(self.$refs.mapRef);
})

这应该可以解决您的代码依赖 Google 地图完全呈现才能运行的任何问题。

*注意:$mapPromise 在过去的版本中被命名为 $mapCreated

见文档:https://github.com/Jeson-gk/vue2-google-maps/blob/master/API.md#mapcreated--promisegooglemapsmap

-

console.log(self.$refs); 在您查看时显示该值的原因是,self.$refs 是通过引用传递的。因此,当您查看控制台时,其余数据在几毫秒内完成加载。并且self.$ref.mapRef 不是通过引用传递的,所以它仍然是undefined,就像在运行时一样。

尝试在console.log(self.$refs); 之后和console.log(self.$refs.mapRef); 之前直接添加一个断点,您可能会发现数据没有加载。

【讨论】:

    【解决方案4】:

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

    您仍然需要避免使用v-if 包装您的组件,并在mounted() 中使用this.$refs.mapRef,而不是created()

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


    方法一

    用途:

    import CustomComponent from './CustomComponent ';
    
    export default {
      components: {
        CustomComponent,
      },
      ...
    }
    

    代替

    export default {
      components: {
        CustomComponent: () => import('./CustomComponent'),
      },
      ...
    }
    

    方法二

    mounted() 中使用this.$refs.mapRef 而不是created()

    这样,setTimeout()this.$nextTick() 就不需要了

    正确方法:

    mounted(){
      //works! child components were loaded
      console.log(this.$refs.mapRef) 
    }
    

    错误的方式:

    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)
      });
    
    }
    

    方法3

    不要使用v-if 包裹子组件,而是使用v-show

    正确方法:

     <div v-show="!isLoading"> 
       <GMap ref="mapRef" />
     </div>
    

    错误的方式:

     <div v-if="!isLoading"> 
       <GMap ref="mapRef" />
     </div>
    

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

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

    我已经将this.$refs.mapRef 放入mounted() 尝试用setTimeout() 和2​​ 层this.$nextTick() 包裹它。

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

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

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

    【讨论】:

      【解决方案5】:

      在我的例子中,我将 ref 与 v-for 一起使用,我错过了仅在 v-for 在 dom 中呈现后才生成 ref 的事实,并且我将 v-for 与填充的状态数组属性一起使用在调用 mount 后几秒钟,我试图在填充状态数组之前访问我的 ref。

      【讨论】:

        【解决方案6】:

        您可以按如下方式使用它,但我不知道它是否会破坏商业项目的 typescript 实现。

        (this as any).$refs.mapRef
        

        【讨论】:

        • 但这完全与问题无关。
        猜你喜欢
        • 2019-02-23
        • 2020-03-31
        • 2016-12-15
        • 1970-01-01
        • 2020-07-18
        • 2020-09-08
        • 1970-01-01
        • 2019-06-15
        • 2023-02-10
        相关资源
        最近更新 更多