DOM 元素到对应的 vue.js 组件

Posted

技术标签:

【中文标题】DOM 元素到对应的 vue.js 组件【英文标题】:DOM element to corresponding vue.js component 【发布时间】:2015-01-10 23:18:12 【问题描述】:

如何找到一个DOM元素对应的vue.js组件?

如果我有

element = document.getElementById(id);

有没有相当于jQuery的vue方法

$(element)

【问题讨论】:

据我所知,没有办法做到这一点。 你介意接受我的回答吗? 【参考方案1】:

如果您想在带有“演示”ID 的输入上监听事件(即 OnClick),您可以使用:

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

【讨论】:

从一个 dom 元素开始,我试图了解控制该元素的 vue 组件是什么(如果有的话)。【参考方案2】:

正确的做法是使用v-el 指令给它一个参考。那你就可以this.$$[reference]了。

vue 2 更新

在 Vue 2 中,元素和组件都使用引用:http://vuejs.org/guide/migration.html#v-el-and-v-ref-replaced

【讨论】:

在 Vue 2 中,v-el 指令似乎不再存在了。 在 Vue 2 中,我将 ref="myid" 添加到元素中,但必须在 javascript 中使用 this.$refs["myid"] 引用它。 关于 ref 的一个很酷的地方是它可以动态定义::ref="'item' + item.id"。但是,这很少是必要的,因为在循环中定义的 refs 会自动进入数组 this.$refs['combo-inside-loop'][index]【参考方案3】:

如果您从 DOM 元素开始,请检查该元素上的 __vue__ 属性。任何 Vue 视图模型(组件,由 v-repeat 使用创建的 VM)都将具有此属性。

您可以使用浏览器开发者控制台(至少在 Firefox 和 Chrome 中)中的“检查元素”功能来查看 DOM 属性。

希望有帮助!

【讨论】:

专业提示:在开发者控制台的“元素”选项卡中找到元素,选择该元素,然后在控制台中输入c = $0.__vue__。现在c 是你的 Vue 组件,你可以检查它的所有属性。 :)【参考方案4】:

就这样(在“方法”中的方法中):

element = this.$el;

:)

【讨论】:

这不是问题要问的。问题是如果你有一个节点的引用,你怎么能得到对渲染它的 Vue 组件的引用,而不是组件的根元素是什么。如果您在 methods 中,则您已经通过 this 引用了该组件。 问题标题欺骗了我——但是因为有些人(也被问题标题欺骗)在这里找到了答案,所以我会留下这个答案。 提示其他人:渲染后,在我使用 Vue 1.x 的环境中,this.$el 只是一个 HTML 注释对象,甚至不是根对象。 确保你至少在mounted()之后依赖这个。例如在created() 这是undefined【参考方案5】:

正是卡米尔所说的,

element = this.$el

但请确保您没有fragment instances。

【讨论】:

正是我对卡米尔的评论。这不是问题所问的。 如果卡米尔已经回答了这个问题,那你为什么提供同样的答案?【参考方案6】:

由于在 Vue 2.0 中,似乎没有可用的解决方案,我发现一个干净的解决方案是创建一个 vue-id 属性,并将其设置在模板上。然后在 createdbeforeDestroy 生命周期中,这些实例在全局对象上更新。

基本上:

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

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

data: function() 
    return 
        vueId: this._id
    

【讨论】:

在 vue 2 中你使用 refs【参考方案7】:

由于 v-ref 不再是指令,而是特殊属性,所以也可以动态定义。这在与 v-for 结合使用时特别有用。

例如:

<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>

在 Vue 组件中你可以使用

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

【讨论】:

【参考方案8】:

所以我认为$0.__vue__ 不适用于 HOC(高阶组件)。

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

从上面的模板中,如果你有ListItem 组件,它有ProductItem 作为它的根,你在控制台中尝试$0.__vue__,结果出乎意料地是ListItem 实例。

这里我有一个选择最低级别组件的解决方案(在本例中为ProductItem)。

插件

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

安装

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

使用

在浏览器控制台中单击 dom 元素。 输入$0.__vueComponent__。 用组件做任何你想做的事。访问数据。做改变。从 e2e 运行公开的方法。

奖励功能

如果你想要更多,你可以使用$0.__vue__.$parent。这意味着如果 3 个组件共享同一个 dom 节点,则您必须编写 $0.__vue__.$parent.$parent 才能获取主要组件。这种方法不那么简洁,但可以提供更好的控制。

【讨论】:

【参考方案9】:

在 Vue.js 2 中的 Vue 实例中组件:

使用this.$el 获取实例/组件安装到的HTMLElement

来自HTMLElement

使用 HTMLElement 中的.__vue__ 例如var vueInstance = document.getElementById('app').__vue__;

在名为vnode 的变量中包含VNode,您可以:

使用vnode.elm 获取VNode 被渲染到的元素 使用vnode.context获取声明VNode组件的VueComponent实例(这通常返回父组件,但使用slots时可能会让您感到惊讶。 使用vnode.componentInstance获取VNode所在的Actual VueComponent实例

来源,字面意思:vue/flow/vnode.js

可运行演示:

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/vue@2.5.15/dist/vue.min.js"></script>

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

【讨论】:

github.com/vuejs/vue/blob/dev/src/core/instance/lifecycle.js 给定一个 "Vue" instance vm: vm._vnode = vnode 有了它,你可以遍历 DOM 节点树,即VNode (VDOM) 树和 Vue 树。 vnode.elm 记录在哪里? vnode.contextvnode.componentInstance 有什么区别 @Archsx context 是 Vue 实例(根组件)。 componentInstance 是组件实例(可能是根组件,也可能不是根组件。如果它是您创建的自定义组件的实例——例如,通过Vue.component('my-comp', ...),它就不是根组件)。 @Archsx 也许vnode.context.$el (jsfiddle.net/acdcjunior/9emvr5az/2) 对你有用。似乎vnode.context 指向组件被声明 的元素。在那个小提琴的情况下,&lt;Child&gt; 在根中声明(“插入”到&lt;Parent&gt;)跨度> 【参考方案10】:

我找到了这个 sn-p here。这个想法是在 DOM 节点层次结构中向上,直到找到 __vue__ 属性。

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

在 Chrome 中:

【讨论】:

【参考方案11】: this.$el - 指向组件的根元素 this.$refs.&lt;ref name&gt; + &lt;div ref="&lt;ref name&gt;" ... - 指向嵌套元素

?仅在vue lifecycle的mounted()步骤之后使用$el/$refs

<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>

【讨论】:

【参考方案12】:

Vue 3 解决方案

我需要创建一个导航栏并在外部单击时折叠菜单项。我在mounted生命周期钩子中的windows上创建了一个点击监听器,如下

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

你也可以检查元素是否是 this.$el 的子元素。但是,在我的情况下,孩子都是链接,这并不重要。

【讨论】:

以上是关于DOM 元素到对应的 vue.js 组件的主要内容,如果未能解决你的问题,请参考以下文章

销毁父组件时,UIkit 模态元素不会从 DOM 中删除(Vue.js)

vue.js 指令详解

vue.js中ref和$refs的使用及示例讲解

vue.js 中slot 用处大(转载)

Vue.js 源码分析 ref属性详解

vue.js怎样解决按钮多次点击重复提交