简体   繁体   English

如何从兄弟组件访问 Vue 组件元素属性

[英]How to access Vue component element property from sibling component

Problem问题
I'm working with a Vue CLI application.我正在使用Vue CLI应用程序。 There is a grandchild component that needs access to another component's element's properties.有一个孙子组件需要访问另一个组件的元素属性。 It really only needs the clientHeight property.它实际上只需要clientHeight属性。

组件结构

So Content2.vue component needs access to the clientHeight property of this element: <div id="header"></div> (in Header.vue ).所以Content2.vue组件需要访问这个元素的clientHeight属性: <div id="header"></div> (在Header.vue中)。

Attempted Solutions尝试的解决方案

  • I've tried using $refs .我试过使用$refs And according to this stackoverflow answer $refs are only available to components directly related as parent/child.并且根据this stackoverflow answer $refs仅适用于与父/子直接相关的组件。

  • I've also considered adding the $refs or clientHeight to the store ( vuex ), but its seems like overkill.我还考虑将$refsclientHeight添加到商店( vuex ),但这似乎有点过分了。

  • I could always go vanilla and use querySelector or getElementById .我总是可以 go vanilla 并使用querySelectorgetElementById But thought there may be something better.但认为可能有更好的东西。

Thanks for your help!谢谢你的帮助!

Possible solutions as of today:截至今天的可能解决方案:

  • $refs

    • $refs are set on the component where they are declared. $refs在声明它们的组件上设置。 If you want to access it, you can do it via $parent , like this.$parent.$parent.$children[0].$refs.name .如果你想访问它,你可以通过$parent来实现,比如this.$parent.$parent.$children[0].$refs.name
    • Pros: quick and dirty.优点:又快又脏。 Works.作品。
    • Cons: very fragile coupling.缺点:非常脆弱的耦合。 You can see from the train wreck not many programmers would find it a good solution.你可以从火车残骸中看到,没有多少程序员会发现它是一个好的解决方案。
  • Vuex Vuex

    • Get the clientHeight and add it to the store.获取clientHeight并将其添加到商店。 (Don't add the $refs , they are not data objects) (不要添加$refs ,它们不是数据对象)
    • Pros/Cons: seems overkill.优点/缺点:似乎矫枉过正。 And it is if you don't have Vuex yet and would only add it for this purpose.如果你还没有 Vuex 并且只会为此目的添加它。 If this is not the case, the Vuex store is one of the "natural" places to store such global information as clientHeight .如果不是这种情况,Vuex 存储是存储诸如clientHeight之类的全局信息的“自然”位置之一。 Hardly any new developer to your project will be surprised to know that clientHeight , which is shared by components far in the tree, is in the store.几乎没有任何新的项目开发人员会惊讶地发现clientHeight被树中远处的组件共享,在 store 中。
  • Vanilla香草

    • Use querySelector or getElementById .使用querySelectorgetElementById
    • Pros/Cons: the problem here is the coupling.优点/缺点:这里的问题是耦合。 And is a hidden one, the worse kind.并且是一个隐藏的,更糟糕的一种。 It's a quick and dirty solution which would be a good first alternative for prototyping and all.这是一个快速而肮脏的解决方案,这将是原型设计和所有其他方面的一个很好的首选替代方案。 But this kind of hidden dependency is very dangerous when apps go mature.但是当应用程序 go 成熟时,这种隐藏的依赖是非常危险的。
  • this.$root : The root instance this.$root : 根实例

    • Create a data() in the root component and have a clientHeight property there.在根组件中创建一个data()并在那里有一个clientHeight属性。 You can now set it from any component using this.$root.clientHeight = newValue or read it using this.$root.clientHeight .您现在可以使用this.$root.clientHeight = newValue从任何组件设置它或使用this.$root.clientHeight读取它。
    • Pros: good if you don't want/need to have a full Vuex store for that.优点:如果您不想/不需要为此拥有完整的 Vuex 商店,那就太好了。 Easily accessible from any component in the tree.从树中的任何组件都可以轻松访问。 Reactive.反应性。
    • Cons: you have to declare the data() in the root component.缺点:您必须在根组件中声明data() Requires care as someone may begin to add properties there, which can quickly become a bad situation (having the downsides of Vuex without the upsides).需要小心,因为有人可能会开始在那里添加属性,这很快就会变成一个糟糕的情况(有 Vuex 的缺点而没有优点)。 If this happens, you should begin using Vuex.如果发生这种情况,您应该开始使用 Vuex。
  • Event Hub/bus事件中心/总线

    • Create a Vue instance and use it as event hub/bus.创建一个 Vue 实例并将其用作事件中心/总线。 This is similar to the $root solution, the difference being that instead of setting the data directly, you emit and receive events.这类似于$root解决方案,不同之处在于您不是直接设置数据,而是发出和接收事件。
    • Pros: decoupled, no need for data() in the root.优点:解耦,根目录中不需要data()
    • Cons: still needs to create the instance that will act as hub/bus (although you could also use the $root for that).缺点:仍然需要创建将充当集线器/总线的实例(尽管您也可以为此使用$root )。 The bad part here is that this solution is not natural to your case.这里的坏处是这种解决方案对您的情况不自然。 The setting of the clientHeight is not an event in any way (or is it?), so this could be unnatural. clientHeight的设置无论如何都不是事件(或者是?),所以这可能是不自然的。
  • Passing around props传递道具

    • Component passes the property up via events and down via props, one hop at a time.组件通过事件向上传递属性并通过道具向下传递,一次一跳。 In other words, Header.vue passes clientHeight (via event) to App.vue , that passes down to Content.vue (via props) that passes further down to Content2.vue (via props).换句话说, Header.vueclientHeight (通过事件)传递给App.vue ,然后传递给Content.vue (通过道具), Content2.vue (通过道具)。
    • Pros: no need for any global store or $root /hub/bus instances.优点:不需要任何全局存储或$root /hub/bus 实例。 Every data passing (in our out) is clear in the signature (events or props) of each component.每个传递的数据(在我们的输出中)在每个组件的签名(事件或道具)中都是明确的。
    • Cons: coupling all around;缺点:四处耦合; boilerplate just for passing around;仅用于传递的样板; arguably one of the main reasons stores like Vuex are used for.可以说是使用 Vuex 等商店的主要原因之一。
  • Dependency injection via provide / inject aka "long-range-props" 通过provide / inject又名“远程道具”进行依赖注入

    • Differently from props, you would pass (eg via event) the clientHeight from Header.vue to the App.vue and App.vue would declare a provide function.与 props 不同的是,您可以(例如通过事件)将clientHeightHeader.vue传递给App.vue ,而App.vue将声明provide function。 Then the Content2.vue would use inject in it.然后Content2.vue将在其中使用inject For more, see docs or demo .有关更多信息,请参阅文档演示
    • Cons: not very common in Vue apps, some more novice devs may not know it.缺点:在 Vue 应用中不太常见,一些新手开发者可能不知道。 Still would have to pass clientHeight from Header.vue to App.vue via event, although that's just one hop.仍然必须通过事件将clientHeightHeader.vue传递给App.vue ,尽管这只是一跳。
    • Pros: the passing of the data from App.vue to Content2.vue is quite clean, after all, that's what provide was designed for.优点:从App.vueContent2.vue的数据传递非常干净,毕竟,这就是provide的目的。

Personally, I'd go for Vuex, specially if you already have it configured.就个人而言,我会为 Vuex 使用 go,特别是如果您已经配置了它。 If not, I'd use $root , but with the promise of using Vuex the first moment any other prop becomes necessary globally.如果不是,我会使用$root ,但是在使用 Vuex 的 promise 的第一刻,任何其他道具在全球范围内都是必要的。

If you are absolutely sure this can't be solved with CSS and you really do need the element's clientHeight , you are left choosing the least-bad solution from the following:如果您绝对确定 CSS 无法解决此问题,并且您确实需要元素的clientHeight ,那么您只能从以下选择最不坏的解决方案:

  1. Pass the id of the Header instance from App to Content to Content2 .Header实例的idApp传递到ContentContent2 Then have Content2 use a query selector to get the height.然后让Content2使用查询选择器来获取高度。 This seems slightly less brittle than having Content2 have a hard-coded id .这似乎比Content2有一个硬编码的id更脆弱。
  2. Have Header compute its own height and emit an event to App , which then passes the height to Content and then to Content2 . Header计算自己的高度并向App发出事件,然后将高度传递给Content ,然后传递给Content2 Note that you may need to listen for resize events if the height is not fixed.请注意,如果高度不固定,您可能需要监听调整大小事件。
  3. Do either (1) or (2) but store it in Vuex or use an Event Bus instead of passing around params.执行 (1) 或 (2) 但将其存储在 Vuex 中或使用事件总线而不是传递参数。

Which one you choose depends on more than what's presented in the question.您选择哪一个不仅取决于问题中提出的内容。

I'd choose (1) if no other components need to know the height of the Header .如果没有其他组件需要知道Header的高度,我会选择 (1)。

I'd choose (2) if other components need to know the height of the Header or if the Header instance is in the best position to determine its own dynamic height.如果其他组件需要知道Header的高度,或者Header实例是否在最佳 position 中以确定其自己的动态高度,我会选择 (2)。

I'd choose (3) if I was already using some sort of global state manager.如果我已经在使用某种全局 state 管理器,我会选择 (3)。

Well you can try to use something called "event bus".好吧,您可以尝试使用称为“事件总线”的东西。 You can emit an event from any content over the global event bus to another content, and the other content listen to this event.您可以通过全局事件总线从任何内容向另一个内容发出事件,而其他内容会监听此事件。 Then you execute an function that emits over the event bus the height and u listen again with "on" on this event and execute an function然后你执行一个 function,它在事件总线上发出高度,你再次用“on”监听这个事件并执行一个 function

This might help you: https://alligator.io/vuejs/global-event-bus/这可能会对您有所帮助: https://alligator.io/vuejs/global-event-bus/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM