如何从同级组件访问 Vue 组件元素 属性

How to access Vue component element property from sibling component

问题
我正在使用 Vue CLI 应用程序。有一个孙组件需要访问另一个组件的元素的属性。它真的只需要 clientHeight 属性.

所以Content2.vue组件需要访问这个元素的clientHeight属性:<div id="header"></div>(在Header.vue).

尝试的解决方案

感谢您的帮助!

那么你可以尝试使用一个叫做 "event bus" 的东西。您可以通过全局事件总线将任何内容的事件发送到另一个内容,而其他内容将监听此事件。然后你执行一个通过事件总线发出高度的函数,你再次用 "on" 监听这个事件并执行一个函数

这可能对您有帮助: https://alligator.io/vuejs/global-event-bus/

如果您完全确定这不能用 CSS 解决并且您确实需要元素的 clientHeight,您只能从以下选项中选择最不糟糕的解决方案:

  1. Header 实例的 idApp 传递到 Content 再到 Content2。然后让 Content2 使用查询选择器来获取高度。这似乎比 Content2 具有硬编码的 id.
  2. 稍微不那么脆弱
  3. Header 计算自己的高度并向 App 发出事件,然后将高度传递给 Content,然后传递给 Content2。请注意,如果高度不固定,您可能需要监听调整大小事件。
  4. 执行 (1) 或 (2),但将其存储在 Vuex 中或使用事件总线而不是传递参数。

您选择哪一个不仅取决于问题中呈现的内容。

如果没有其他组件需要知道 Header 的高度,我会选择 (1)。

如果其他组件需要知道 Header 的高度,或者如果 Header 实例处于确定其自身动态高度的最佳位置,我会选择 (2)。

如果我已经在使用某种全局状态管理器,我会选择 (3)。

截至今天可能的解决方案:

  • $refs

    • $refs 在声明它们的组件上设置。如果你想访问它,你可以via $parent,比如this.$parent.$parent.$children[0].$refs.name
    • 优点:快速且肮脏。有效。
    • 缺点:耦合非常脆弱。从 train wreck 可以看出,没有多少程序员会认为它是一个好的解决方案。
  • Vuex

    • 获取 clientHeight 并将其添加到商店。 (不要添加 $refs,它们不是数据对象)
    • Pros/Cons:似乎有些矫枉过正。如果您还没有 Vuex 并且只会为此目的添加它,那就是。如果不是这种情况,Vuex 存储是 "natural" 存储全局信息的地方之一 clientHeight。几乎没有任何新的项目开发人员会惊讶地发现 clientHeight,它由树中远处的组件共享,在商店中。
  • 原版

    • 使用querySelector or getElementById.
    • Pros/Cons:这里的问题是耦合。并且是隐藏的,最糟糕的一种。这是一个快速而肮脏的解决方案,将是原型制作和所有方面的第一个很好的选择。但是这种隐藏的依赖在应用程序成熟后是非常危险的。
  • this.$root: The root instance

    • 在根组件中创建一个 data() 并在那里有一个 clientHeight 属性。您现在可以使用 this.$root.clientHeight = newValue 从任何组件设置它或使用 this.$root.clientHeight.
    • 读取它
    • 优点:如果您不 want/need 拥有一个完整的 Vuex 商店,那很好。可从树中的任何组件轻松访问。无反应。
    • 缺点:您必须在根组件中声明 data()。需要小心,因为有人可能会开始在那里添加属性,这很快就会变成一个糟糕的情况(有 Vuex 的缺点而没有优点)。如果发生这种情况,你应该开始使用 Vuex。
    • 创建一个 Vue 实例并将其用作事件 hub/bus。这类似于 $root 解决方案,不同之处在于您不是直接设置数据,而是发出和接收事件。
    • 优点:解耦,根目录中不需要 data()
    • 缺点:仍然需要创建将充当 hub/bus 的实例(尽管您也可以为此使用 $root)。这里不好的部分是这个解决方案对你的情况来说并不自然。 clientHeight 的设置在任何方面都不是事件(或者是?),所以这可能是不自然的。
  • 传递道具

    • 组件通过事件向上传递 属性,通过 props 向下传递,一次一跳。换句话说,Header.vueclientHeight(通过事件)传递给 App.vue,然后向下传递到 Content.vue(通过 props),再向下传递到 Content2.vue(通过道具)。
    • 优点:不需要任何全局存储或 $root/hub/bus 个实例。在每个组件的签名(事件或道具)中,每个数据传递(在我们的输出中)都是明确的。
    • 缺点:四处耦合;仅供传递的样板;可以说是使用像 Vuex 这样的商店的主要原因之一。
  • Dependency injection via provide/inject 又名 "long-range-props"

    • 与 props 不同,您可以将 clientHeightHeader.vue 传递给 App.vue,而 App.vue 会声明一个 provide功能。然后 Content2.vue 将在其中使用 inject 。有关更多信息,请参阅 docs or demo
    • 缺点:在 Vue 应用中不是很常见,更多的新手开发者可能不知道。仍然必须通过事件将 clientHeightHeader.vue 传递到 App.vue,尽管那只是一个跃点。
    • 优点:从App.vueContent2.vue的数据传递非常干净,毕竟这就是provide的设计目的。

就我个人而言,我会选择 Vuex,特别是如果您已经配置了它。如果没有,我会使用 $root,但承诺在第一时间使用 Vuex 任何其他道具在全球范围内都是必需的。