【问题标题】:Can you pass an element to a function within the template in Vue?你可以将元素传递给 Vue 模板中的函数吗?
【发布时间】:2019-08-18 03:42:51
【问题描述】:

我正在尝试根据元素的子元素数量以编程方式计算和设置元素的 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,但如果我可以通过使用不同参数调用的单个函数来处理它,它会更容易维护。如果可能的话,我想从模板中传递元素本身。有谁知道这样做的方法,或更优雅的方法来解决这个问题?

【问题讨论】:

标签: javascript vue.js vuejs2


【解决方案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>

【讨论】:

    【解决方案2】:

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

    • 点击了
    • 它的类发生变化
    • 元素或其子元素更新


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

    【讨论】:

      【解决方案3】:

      我从 Vue 学到的一个便宜的技巧是,如果您需要在模板中安装模板时未加载的任何内容,只需在其上放置一个带有 v-if 的模板:

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

      围绕它。起初这可能看起来很脏,但问题是,它可以在没有额外代码和时间花费的情况下完成这项工作,并且可以防止错误。

      另外,您的expandable-function 的代码长度略有改进:

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

      【讨论】:

      • 我喜欢在事情可能为空/未定义时使用v-if。这是我经常使用的东西,但我认为这里的指令方法是一个更好的解决方案,因为我将尝试在整个项目的几个地方使用它。我更喜欢你的expandable 代码,我会这样实现它。谢谢!
      猜你喜欢
      • 2015-05-16
      • 2021-02-10
      • 2018-07-04
      • 2022-06-12
      • 1970-01-01
      • 1970-01-01
      • 2018-08-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多