您可以将元素传递给Vue模板中的函数吗?

时间:2019-03-27 14:19:01

标签: javascript vue.js vuejs2

我正在尝试根据其具有的子代数以编程方式计算和设置元素的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 个答案:

答案 0 :(得分:1)

做出一个直接在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>

答案 1 :(得分:1)

我在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';

答案 2 :(得分:0)

我最终创建了一条建议的指令。它会在以下情况下尝试扩展/压缩:

  • 被点击
  • 它的班级改变了
  • 该元素或其子元素更新


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