DOM element to corresponding vue.js component

JavascriptDomvue.js

Javascript Problem Overview


How can I find the vue.js component corresponding to a DOM element?

If I have

element = document.getElementById(id);

Is there a vue method equivalent to the jQuery

$(element)

Javascript Solutions


Solution 1 - Javascript

Just by this (in your method in "methods"):

element = this.$el;

:)

Solution 2 - Javascript

The proper way to do with would be to use the v-el directive to give it a reference. Then you can do this.$$[reference].

Update for vue 2

In Vue 2 refs are used for both elements and components: http://vuejs.org/guide/migration.html#v-el-and-v-ref-replaced

Solution 3 - Javascript

In Vue.js 2 Inside a Vue Instance or Component:

  • Use this.$el to get the HTMLElement the instance/component was mounted to

From an HTMLElement:

  • Use .__vue__ from the HTMLElement
    • E.g. var vueInstance = document.getElementById('app').__vue__;

Having a VNode in a variable called vnode you can:

  • use vnode.elm to get the element that VNode was rendered to
  • use vnode.context to get the VueComponent instance that VNode's component was declared (this usually returns the parent component, but may surprise you when using slots.
  • use vnode.componentInstance to get the Actual VueComponent instance that VNode is about

Source, literally: vue/flow/vnode.js.

Runnable Demo:

Vue.config.productionTip = false; // disable developer version warning
console.log('-------------------')

Vue.component('my-component', {
  template: `<input>`,
  mounted: function() {
    console.log('[my-component] is mounted at element:', this.$el);
  }
});

Vue.directive('customdirective', {
  bind: function (el, binding, vnode) {
    console.log('[DIRECTIVE] My Element is:', vnode.elm);
    console.log('[DIRECTIVE] My componentInstance is:', vnode.componentInstance);
    console.log('[DIRECTIVE] My context is:', vnode.context);
    // some properties, such as $el, may take an extra tick to be set, thus you need to...
    Vue.nextTick(() => console.log('[DIRECTIVE][AFTER TICK] My context is:', vnode.context.$el))
  }
})

new Vue({
  el: '#app',
  mounted: function() {
    console.log('[ROOT] This Vue instance is mounted at element:', this.$el);
    
    console.log('[ROOT] From the element to the Vue instance:', document.getElementById('app').__vue__);
    console.log('[ROOT] Vue component instance of my-component:', document.querySelector('input').__vue__);
  }
})

<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>

<h1>Open the browser's console</h1>
<div id="app">
  <my-component v-customdirective=""></my-component>
</div>

Solution 4 - Javascript

If you're starting with a DOM element, check for a __vue__ property on that element. Any Vue View Models (components, VMs created by v-repeat usage) will have this property.

You can use the "Inspect Element" feature in your browsers developer console (at least in Firefox and Chrome) to view the DOM properties.

Hope that helps!

Solution 5 - Javascript

  • this.$el - points to the root element of the component
  • this.$refs.<ref name> + <div ref="<ref name>" ... - points to nested element

>  use $el/$refs only after mounted() step of vue lifecycle

<template>
    <div>
        root element
        <div ref="childElement">child element</div>
    </div>
</template>

<script>
    export default {
        mounted() {
            let rootElement = this.$el;
            let childElement = this.$refs.childElement;

            console.log(rootElement);
            console.log(childElement);
        }
    }
</script>

<style scoped>
</style>

> enter image description here

Solution 6 - Javascript

Since v-ref is no longer a directive, but a special attribute, it can also be dynamically defined. This is especially useful in combination with v-for.

For example:

<ul>
    <li v-for="(item, key) in items" v-on:click="play(item,$event)">
        <a v-bind:ref="'key' + item.id" v-bind:href="item.url">
            <!-- content -->
        </a>
    </li>
</ul>

and in Vue component you can use

var recordingModel = new Vue({
  el:'#rec-container',
  data:{
    items:[]
  },

  methods:{
    play:function(item,e){
      // it contains the bound reference
      console.log(this.$refs['key'+item.id]);
    }
  }
});

Solution 7 - Javascript

So I figured $0.__vue__ doesn't work very well with HOCs (high order components).

// ListItem.vue
<template>
    <vm-product-item/>
<template>

From the template above, if you have ListItem component, that has ProductItem as it's root, and you try $0.__vue__ in console the result unexpectedly would be the ListItem instance.

Here I got a solution to select the lowest level component (ProductItem in this case).

Plugin

// DomNodeToComponent.js
export default {
  install: (Vue, options) => {
    Vue.mixin({
      mounted () {
        this.$el.__vueComponent__ = this
      },
    })
  },
}

Install

import DomNodeToComponent from'./plugins/DomNodeToComponent/DomNodeToComponent'
Vue.use(DomNodeToComponent)

Use

  • In browser console click on dom element.
  • Type $0.__vueComponent__.
  • Do whatever you want with component. Access data. Do changes. Run exposed methods from e2e.

Bonus feature

If you want more, you can just use $0.__vue__.$parent. Meaning if 3 components share the same dom node, you'll have to write $0.__vue__.$parent.$parent to get the main component. This approach is less laconic, but gives better control.

Solution 8 - Javascript

I found this snippet here. The idea is to go up the DOM node hierarchy until a __vue__ property is found.

function getVueFromElement(el) {
  while (el) {
	if (el.__vue__) {
	  return el.__vue__
	} else {
	  el = el.parentNode
	}
  }
}

In Chrome:

Usage in Chrome

Solution 9 - Javascript

Solution for Vue 3

I needed to create a navbar and collapse the menu item when clicked outside. I created a click listener on windows in mounted life cycle hook as follows

mounted() {
    window.addEventListener('click', (e)=>{
        if(e.target !== this.$el)
            this.showChild = false;
    })
}

You can also check if the element is child of this.$el. However, in my case the children were all links and this didn't matter much.

Solution 10 - Javascript

If you want listen an event (i.e OnClick) on an input with "demo" id, you can use:

new Vue({
  el: '#demo',
  data: {
    n: 0
  },
  methods: {
   onClick: function (e) {
     console.log(e.target.tagName) // "A"
     console.log(e.targetVM === this) // true
  }
 }
})

Solution 11 - Javascript

Exactly what Kamil said,

element = this.$el

But make sure you don't have fragment instances.

Solution 12 - Javascript

Since in Vue 2.0, no solution seems available, a clean solution that I found is to create a vue-id attribute, and also set it on the template. Then on created and beforeDestroy lifecycle these instances are updated on the global object.

Basically:

created: function() {
    this._id = generateUid();
    globalRepo[this._id] = this;
},

beforeDestroy: function() {
    delete globalRepo[this._id]
},

data: function() {
    return {
        vueId: this._id
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGhigoView Question on Stackoverflow
Solution 1 - JavascriptKamil KiełczewskiView Answer on Stackoverflow
Solution 2 - JavascriptblockheadView Answer on Stackoverflow
Solution 3 - JavascriptacdcjuniorView Answer on Stackoverflow
Solution 4 - JavascriptBigBlueHatView Answer on Stackoverflow
Solution 5 - JavascriptJossef Harush KadouriView Answer on Stackoverflow
Solution 6 - JavascriptKathan ShahView Answer on Stackoverflow
Solution 7 - JavascriptYauheni PrakopchykView Answer on Stackoverflow
Solution 8 - JavascriptbernieView Answer on Stackoverflow
Solution 9 - Javascriptmayank1513View Answer on Stackoverflow
Solution 10 - JavascriptcandlejackView Answer on Stackoverflow
Solution 11 - JavascriptanonymousView Answer on Stackoverflow
Solution 12 - Javascriptbogdan.mustiataView Answer on Stackoverflow