Как получить доступ к свойству элемента компонента Vue из одноуровневого компонента - PullRequest
0 голосов
/ 02 октября 2019

Проблема
Я работаю с приложением Vue CLI . Существует компонент внука, которому нужен доступ к свойствам элемента другого компонента. Ему действительно нужно только свойство clientHeight.

component structure

Итак, Content2.vue компоненту необходим доступ к свойству clientHeightэтого элемента: <div id="header"></div>Header.vue ).

Попытки решения

  • Я пробовалиспользуя $refs. И согласно этот ответ на стекопоток $refs доступен только для компонентов, непосредственно связанных как родитель / потомок.

  • Я также рассмотрел добавление $refs илиclientHeight в магазин ( vuex ), но это кажется излишним.

  • Я всегда могу пойти ванилью и использовать querySelector или getElementById . Но думал, что может быть что-то лучше.

Спасибо за вашу помощь!

Ответы [ 3 ]

1 голос
/ 02 октября 2019

Если вы абсолютно уверены, что это не может быть решено с помощью CSS, и вам действительно нужно clientHeight элемента, вам остается выбрать наименее плохое решение из следующих:

  1. Passid экземпляра Header от App до Content до Content2. Затем Content2 используйте селектор запросов, чтобы получить высоту. Это кажется немного менее хрупким, чем Content2 с жестко запрограммированным id.
  2. Имеет Header вычисление своей собственной высоты и выдачу события в App, которое затем передает высоту в Content а затем Content2. Обратите внимание, что вам может потребоваться прослушивать события изменения размера, если высота не фиксирована.
  3. Делайте (1) или (2), но сохраняйте их в Vuex или используйте шину событий вместо передачи параметров.

Выбор того, что вы выберете, зависит не только от того, что представлено в вопросе.

Я бы выбрал (1), если другие компоненты не должны знать высоту Header.

Я бы выбрал (2), если другим компонентам нужно знать высоту Header или если экземпляр Header находится в наилучшем положении для определения собственной динамической высоты.

Я бы выбрал (3), если бы уже использовал какой-то глобальный менеджер состояний.

1 голос
/ 02 октября 2019

Возможные решения на сегодняшний день:

  • $refs

    • $refs установлены на компоненте, где они находятсяобъявлен. Если вы хотите получить к нему доступ, вы можете сделать это через $parent, например this.$parent.$parent.$children[0].$refs.name.
    • Плюсы: быстро и грязно. Работает.
    • Минусы: очень хрупкая муфта. Вы можете видеть из поезда, потерпевшего крушение , не так много программистов нашли бы это хорошим решением.
  • Vuex

    • ПолучитеclientHeight и добавьте его в магазин. (Не добавляйте $refs, они не являются объектами данных)
    • Плюсы / минусы: кажется излишним. И это если у вас еще нет Vuex, и вы бы добавили его только для этой цели. Если это не так, хранилище Vuex является одним из «естественных» мест для хранения такой глобальной информации, как clientHeight. Вряд ли любой новый разработчик вашего проекта будет удивлен, узнав, что clientHeight, который используется компонентами далеко в дереве, находится в магазине.
  • Vanilla

    • Используйте querySelector или getElementById .
    • Плюсы / минусы: проблема здесь заключается в соединении. И это скрытый, худший вид. Это быстрое и грязное решение, которое было бы хорошей первой альтернативой для прототипирования и всего остального. Но этот вид скрытой зависимости очень опасен, когда приложения становятся более зрелыми.
  • this.$root: корневой экземпляр

    • Создайте data() в корневом компоненте и укажите там свойство clientHeight. Теперь вы можете установить его из любого компонента с помощью this.$root.clientHeight = newValue или прочитать его с помощью this.$root.clientHeight.
    • Плюсы: хорошо, если вы не хотите / не нуждаетесь в полном хранилище Vuex для этого. Легко доступны из любого компонента в дереве. Реактивный.
    • Минусы: вы должны объявить data() в корневом компоненте. Требуется осторожность, так как кто-то может начать добавлять туда свойства, что может быстро стать плохой ситуацией (имея недостатки у Vuex без плюсов). Если это произойдет, вы должны начать использовать Vuex.
  • Концентратор / шина событий

    • Создать экземпляр Vue и использоватьэто как центр событий / автобус. Это похоже на решение $root, с той разницей, что вместо прямой установки данных вы отправляете и получаете события.
    • Плюсы: отделены, нет необходимости в data() в корне.
    • Минусы: по-прежнему необходимо создать экземпляр, который будет действовать как концентратор / шина (хотя вы также можете использовать $root для этого). Плохая часть в том, что это решение не является естественным для вашего случая. Настройка clientHeight ни в коем случае не является событием (или это так?), Поэтому это может быть неестественно.
  • Обход реквизита

    • Компонент передает свойство вверх через события и вниз через реквизиты, по одному прыжку за раз. Другими словами, Header.vue передает clientHeight (через событие) в App.vue, который проходит до Content.vue (через реквизит), который проходит далее до Content2.vue (через реквизит).
    • Плюсы: нет необходимости в глобальном магазине или экземплярах $root / hub / bus. Каждая передача данных (с нашей стороны) очевидна в сигнатуре (событиях или подпорках) каждого компонента.
    • Минусы: соединение вокруг;шаблон просто для прохождения;возможно, одна из главных причин, по которым магазины, такие как Vuex, используются.
  • Внедрение зависимостей через provide / inject aka "long-range-props "

    • В отличие от реквизита, вы должны передать (например, через событие) clientHeight из Header.vue в App.vue, а App.vue объявит функцию provide. Тогда Content2.vue будет использовать inject в нем. Для получения дополнительной информации см. docs или demo .
    • Минусы: нечасто встречается в приложениях Vue, некоторые новички могут этого не знать. Тем не менее, пришлось бы передавать clientHeight из Header.vue в App.vue через событие, хотя это всего лишь один переход.
    • Плюсы: передача данных из App.vue в Content2.vue довольно чистая,в конце концов, именно для этого и была разработана provide.

Лично я бы пошел на Vuex, особенно если он уже настроен. Если нет, я бы использовал $root, но с обещанием использовать Vuex в первый момент, когда любая другая опора станет необходимой в глобальном масштабе.

0 голосов
/ 02 октября 2019

Ну, вы можете попробовать использовать то, что называется "шиной событий". Вы можете отправить событие из любого контента через глобальную шину событий в другой контент, а другой контент прослушивает это событие. Затем вы выполняете функцию, которая излучает через шину событий высоту, и снова слушаете «on» этого события и выполняете функцию

. Это может помочь вам: https://alligator.io/vuejs/global-event-bus/

...