Vuejs can't access refs from component

2019-04-03 05:31发布

I am trying to get the canvas element which is inside a template of a component, found great documentations for vuejs1 but not for vuejs2 where "ref" is the only way to get the element. I am getting the object though, but when I try to access the variable it is undefined.

My html

<div id="app>
  <template id="image-capture">
    <div class="row" >
      <canvas ref="icanvas" ></canvas>
    </div>
  </template>
</div>

My js

const ic = {
  template: '#image-capture' ,

  created () {
    console.log(this.$refs); //this returns object
    console.log(this.$refs.icanvas); // but this is undefined
  }


}

const routes = [
  { path: '/ic', component:   ic},
]

const router = new VueRouter({
  routes 
})

 new Vue({
  router,
   }).$mount('#app')

I need to get the icanvas element.

here is console log

4条回答
劫难
2楼-- · 2019-04-03 05:44

Normally, you can access the ref in mounted, just like @Mihai Vilcu posted:

mounted: function() {
    console.log(this.$refs.icanvas);
}

However, as @BrownBe said,

it's still an issue if your refs on a v-for element. The DOM isn't acctualy eable to access this ref when mounted hook is fired.

Until 2018.10.27, it is still a question, and here is the latest issues.

The reason can be found here:

An important note about the ref registration timing: because the refs themselves are created as a result of the render function, you cannot access them on the initial render - they don’t exist yet!

And here is what I do to solve this question:

  mounted() {
    this.$_xsl__watchRefs(this.$el, '.lazy_image').then(refs => {
      //do something with `refs`
    })
  }

And here is the $_xsl__watchRefs

   $_xsl__watchRefs(targetNode, refsSelector) {
      return new Promise(function(resolve) {
        let observer = new MutationObserver(callback)
        let config = { childList: true, subtree: true }
        observer.observe(targetNode, config)

        function callback(mutationsList, observer) {
          mutationsList.forEach(mutation => {
            if (mutation.type == 'childList') {
              let refs = targetNode.querySelectorAll(refsSelector)
              if (refs.length !== 0) {
                observer.disconnect()
                resolve(Array.from(refs))
              }
            }
          })
        }
      })
    }

You can alter it as you need. Here is MutationObserver which supported IE11+.

Another easy choice. Suppose you use v-for like:

<li class="list__item" v-for="(item,index) in pubList" :key="index">
   <img
      class="list__img lazy_image"
      ref="lazyImages"
    >
</li>

And

 props: ['pubList'],

In this case, you can try:

  watch: {
    'pubList.length': function() {
      this.$nextTick(function() {
        console.log(this.$refs.lazyImages)
      })
    }
  },

In some cases, both methods won't work because this.$refs.lazyImages has already existed. So, the safest method is:

  mounted() {
    if (this.$refs.lazyImages) {
      //do something with `this.$refs.lazyImages`
    } else {
      this.$_xsl__watchRefs(this.$el, '.lazy_image').then(refs => {
        //do something with `refs`
      })
    }
  },
查看更多
啃猪蹄的小仙女
3楼-- · 2019-04-03 05:52

The created is fired before the template is processed.
You can find more details here: https://vuejs.org/v2/guide/instance.html#Lifecycle-Diagram

You should be able to access the $refs on the mounted event

mounted: function() {
    console.log(this.$refs.icanvas);
},
查看更多
Emotional °昔
4楼-- · 2019-04-03 06:00

i had the exact same issue, in my case i solved it by accessing the ref in the method that changes the v-if with nextTick.

methods: {
open() {
  this.show = true; //v-if condition
    this.$nextTick(function() {
      this.titleWidth = this.$refs.titleBg.clientWidth - 30;
    });
}
查看更多
该账号已被封号
5楼-- · 2019-04-03 06:01

You can use $nextTick() function, code inside $nextTick() will run after DOM update.

this.$nextTick(function () {

    console.log(this.$refs.ANY_COMPONENT_REF)

})
查看更多
登录 后发表回答