Можете ли вы передать элемент в функцию в шаблоне в Vue? - PullRequest
2 голосов
/ 27 марта 2019

Я пытаюсь вычислить и установить стиль элемента max-height программно на основе количества дочерних элементов.Я должен сделать это для четырех отдельных элементов, каждый из которых имеет разное количество дочерних элементов, поэтому я не могу просто создать одно вычисляемое свойство.У меня уже есть логика для вычисления max-height в функции, но я не могу передать элемент из шаблона в функцию.

Я безуспешно пробовал следующие решения:

  1. <div ref="div1" :style="{ maxHeight: getMaxHeight($refs.div1) }"></div>
    Это не сработало, поскольку $refs еще не определено во время передачи его в функцию.

  2. Попытка передать this или $event.target на getMaxHeight().Это также не сработало, потому что this не ссылается на текущий элемент, и не было никакого события, так как я не в обработчике событий v-on.

Единственное другое решение, о котором я могу думать, - это создание четырех вычисляемых свойств, каждое из которых вызывает getMaxHeight() с помощью $ref, но если я смогу обработать его из одной функции, вызываемой с разными параметрами, будет проще поддерживать.Если возможно, я бы хотел передать сам элемент из шаблона.Кто-нибудь знает способ сделать это или более элегантный подход к решению этой проблемы?

Ответы [ 3 ]

2 голосов
/ 28 марта 2019

Дешевый трюк, который я узнал с помощью Vue, заключается в том, что если вам требуется что-то в шаблоне, которое не загружается при монтировании шаблона, это просто поместить шаблон с v-if:

<template v-if="$refs">
   <div ref="div1" :style="{ maxHeight: getMaxHeight($refs.div1) }"></div>
</template>

вокруг. Поначалу это может показаться грязным, но дело в том, что он выполняет работу без лишнего кода и затрат времени и предотвращает ошибки.

Кроме того, небольшое улучшение длины кода для вашей expandable -функции:

const expandable = el => el.style.maxHeight = 
    ( el.classList.contains('expanded') ?  
        el.children.map(c=>c.scrollHeight).reduce((h1,h2)=>h1+h2)
        : 0 ) + 'px';
1 голос
/ 27 марта 2019

Создание вашей собственной директивы, которая работает непосредственно с элементом div, вероятно, будет вашим лучшим выбором.Вы можете создать компонент директивы, такой как:

export default {
  name: 'maxheight',
  bind(el) {
    const numberOfChildren = el.children.length;

    // rest of your max height logic here

    el.style.maxHeight = '100px';
  }
}

Затем просто убедитесь, что импортировали директиву в файл, который вы планируете использовать, и добавьте ее в свой элемент div:

<div ref="div1" maxheight></div>
0 голосов
/ 27 марта 2019

В итоге я создал директиву, подобную предложенной.Он пытается развернуть / сжать, когда:

  • При нажатии
  • Изменение его классов
  • Обновление элемента или его дочерних элементов


Vue компонент:
<button @click="toggleAccordion($event.currentTarget.nextElementSibling)"></button>
<div @click="toggleAccordion($event.currentTarget)" v-accordion-toggle>
    <myComponent v-for="data in dataList" :data="data"></myComponent>
</div>

.....

private toggleAccordion(elem: HTMLElement): void {
    elem.classList.toggle("expanded");
}


Директива: Accordion.ts
const expandable = (el: HTMLElement) => el.style.maxHeight = (el.classList.contains("expanded") ?
    [...el.children].map(c => c.scrollHeight).reduce((h1, h2) => h1 + h2) : "0") + "px";

Vue.directive("accordion-toggle", {
    bind: (el: HTMLElement, binding: any, vnode: any) => {
        el.onclick = ($event: any) => {
            expandable($event.currentTarget) ; // When the element is clicked
        };

        // If the classes on the elem change, like another button adding .expanded class
        const observer = new MutationObserver(() => expandable(el));        
        observer.observe(el, {
            attributes: true,
            attributeFilter: ["class"],
        });
    },
    componentUpdated: (el: HTMLElement) => {
        expandable(el); // When the component (or its children) update
    }
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...