2
votes

Pouvez-vous passer un élément à une fonction dans le modèle dans Vue?

J'essaie de calculer et de définir le style max-height d'un élément par programmation en fonction du nombre d'enfants qu'il a. Je dois le faire sur quatre éléments distincts, chacun avec un nombre d'enfants différent, donc je ne peux pas simplement créer une seule propriété calculée. J'ai déjà la logique pour calculer la max-height dans la fonction, mais je ne peux pas passer un élément du modèle dans une fonction.

J'ai essayé les solutions suivantes sans succès:


  1. Cela n'a pas fonctionné car $ refs n'est pas encore défini au moment où je le transmets à la fonction.

  2. Tentative de passer this ou $ event.target à getMaxHeight () . Cela n'a pas fonctionné non plus car this ne fait pas référence à l'élément actuel, et il n'y a pas eu d'événement puisque je ne suis pas dans un gestionnaire d'événements v-on . < / p>

La seule autre solution à laquelle je puisse penser est de créer quatre propriétés calculées que chacune appelle getMaxHeight () avec le $ ref , mais si je peux le gérer à partir d'un fonction appelée avec différents paramètres, il serait plus facile à maintenir. Si possible, je voudrais passer l'élément lui-même du modèle. Quelqu'un connaît-il un moyen de le faire ou une approche plus élégante pour résoudre ce problème?


1 commentaires

Pensez à la directive personnalisée - vous pouvez simplement accéder à l'élément lié à l'intérieur. vuejs.org/v2/guide/custom-directive.html


3 Réponses :


1
votes

Créer une directive personnalisée qui opère directement sur l'élément div serait probablement votre meilleure solution. Vous pouvez créer un composant directive comme:

<div ref="div1" maxheight></div>

Ensuite, assurez-vous simplement d'importer la directive dans le fichier que vous prévoyez de l'utiliser, et ajoutez-la à votre élément div:

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

    // rest of your max height logic here

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


0 commentaires

1
votes

J'ai fini par créer une directive comme celle suggérée. Il essaie de se développer / compresser lorsque:

  • Il a cliqué
  • Ses classes changent
  • L'élément ou ses enfants sont mis à jour


Composant Vue:

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

.....

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


Directive: Accordion.ts

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


0 commentaires

2
votes

Une astuce bon marché que j'ai apprise avec Vue est que si vous avez besoin de quelque chose dans le modèle qui n'est pas chargé lorsque le modèle est monté, il suffit de mettre un modèle avec un v-if dessus:

const expandable = el => el.style.maxHeight = 
    ( el.classList.contains('expanded') ?  
        el.children.map(c=>c.scrollHeight).reduce((h1,h2)=>h1+h2)
        : 0 ) + 'px';

autour d'elle. Cela peut sembler sale au début, mais le fait est que cela fait le travail sans beaucoup de code et de temps supplémentaires et évite les erreurs.

De plus, une petite amélioration de la longueur du code sur votre extensible -fonction:

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


1 commentaires

J'aime utiliser v-if quand les choses peuvent être nulles / indéfinies. C'est quelque chose que j'utilise assez souvent, mais je pense que l'approche directive ici est une meilleure solution puisque je vais essayer de l'utiliser à quelques endroits tout au long du projet. J'aime mieux votre code extensible , je vais l'implémenter comme ça. Merci!