在Vue中创建可重用的 Transition

开发 前端
如果我们可以将它们封装到组件中,并在多个项目中简单地重用它们,结果会怎样呢?我们将介绍几种定义transition的方法,并深入研究如何使它们真正可重用。

本文转载自微信公众号「大迁世界」,转载本文请联系大迁世界公众号。

Vue.js中的transition确实很棒。毫无疑问,它们可以非常轻松地让应用程序栩栩如生,但是通常必须在每个项目中从头开始编写它们,甚至还需要引入animate.css之类的CSS库来使它们功能更强大。

如果我们可以将它们封装到组件中,并在多个项目中简单地重用它们,结果会怎样呢?我们将介绍几种定义transition的方法,并深入研究如何使它们真正可重用。

[[328523]]

原始transition组件和CSS

定义transition的最简单方法是使用transition·或transition-group组件。这需要为transition定义一个name`和一些CSS。

  1. <template> 
  2.   <div id="app"> 
  3.     <button v-on:click="show = !show"> 
  4.       Toggle 
  5.     </button> 
  6.     <transition name="fade"> 
  7.       <p v-if="show">hello</p> 
  8.     </transition> 
  9.   </div> 
  10. </template> 
  11. <script> 
  12. export default { 
  13.   name: "App", 
  14.   data() { 
  15.     return { 
  16.       show: true 
  17.     }; 
  18.   } 
  19. }; 
  20. </script> 
  21. <style> 
  22. .fade-enter-active, 
  23. .fade-leave-active { 
  24.   transition: opacity 0.3s; 
  25. .fade-enter, 
  26. .fade-leave-to { 
  27.   opacity: 0; 
  28. </style> 

 

看起来容易,对吧?然而,这种方法有一个问题。我们不能在另一个项目中真正重用这个transition。

封装transition组件

如果我们将前面的逻辑封装到一个组件中,并将其用作一个组件,结果会怎样呢?

  1. // FadeTransition.vue 
  2. <template> 
  3.   <transition name="fade"> 
  4.     <slot></slot> 
  5.   </transition> 
  6. </template> 
  7. <script> 
  8. export default { 
  9.    
  10. }; 
  11. </script> 
  12. <style> 
  13. .fade-enter-active, 
  14. .fade-leave-active { 
  15.   transition: opacity 0.3s; 
  16. .fade-enter, 
  17. .fade-leave-to { 
  18.   opacity: 0; 
  19. </style> 
  20.  
  21. // App.vue 
  22.  
  23. <template> 
  24.   <div id="app"> 
  25.     <button v-on:click="show = !show"> 
  26.       Toggle transition 
  27.     </button> 
  28.     <fade-transition> 
  29.       <div v-if="show" class="box"></div> 
  30.     </fade-transition> 
  31.   </div> 
  32. </template> 
  33. <script>...</script> 
  34. <style>...</style> 

通过在transition组件中提供一个slot,我们几乎可以像使用基本transition组件一样使用它。这比前面的例子稍微好一点,但是如果我们想要传递其他特定于transition的prop,比如mode或者一些hook,该怎么办呢

封装的包装器transition组件

幸运的是,Vue 中有一个功能,使我们可以将用户指定的所有额外props和监听器传递给我们的内部标签/组件。如果你还不知道,则可以通过$attrs访问额外传递的 props,并将它们与v-bind结合使用以将它们绑定为props。这同样适用于通过$listeners进行的事件,并通过v-on对其进行应用。

  1. // FadeTransition.vue 
  2.  
  3. <template> 
  4.   <transition name="fade" v-bind="$attrs" v-on="$listeners"> 
  5.     <slot></slot> 
  6.   </transition> 
  7. </template> 
  8. <script> 
  9. export default {}; 
  10. </script> 
  11. <style> 
  12. .fade-enter-active, 
  13. .fade-leave-active { 
  14.   transition: opacity 0.3s; 
  15. .fade-enter, 
  16. .fade-leave-to { 
  17.   opacity: 0; 
  18. </style> 
  19.  
  20. // App.vue 
  21.  
  22. ... 
  23.  
  24. <fade-transition mode="out-in"> 
  25.   <div key="blue" v-if="show" class="box"></div> 
  26.   <div key="red" v-else class="red-box"></div> 
  27. </fade-transition> 
  28.  
  29. ... 
 
 

「完整事例地址:https://codesandbox.io/s/yjl1wjyoy1?from-embed」

现在,我们可以传递普通transition组件可以接受的任何事件和支持,这使得我们的组件更加可重用。但为什么不更进一步,增加通过 prop 轻松定制持续时间的可能性。

显式持续时间 prop

Vue 为transition组件提供了一个duration prop,然而,它是为更复杂的动画链接而设计的,它帮助 Vue 正确地将它们链接在一起。

在我们的案例中,我们真正需要的是通过组件prop控制CSS animation/transition。我们可以通过不在CSS中指定显式的CSS动画持续时间,而是将其作为样式来实现。我们可以借助transition hook来做到这一点,该transition hook与组件生命周期 hook 非常相似,但是它们在过渡所需元素之前和之后被调用。让我们看看效果如何。

  1. // FadeTransition.vue 
  2.  
  3. <template> 
  4.   <transition name="fade" 
  5.               enter-active-class="fadeIn" 
  6.               leave-active-class="fadeOut" 
  7.               v-bind="$attrs" 
  8.               v-on="hooks"> 
  9.       <slot></slot> 
  10.   </transition> 
  11. </template> 
  12. <script> 
  13. export default { 
  14.   props: { 
  15.     duration: { 
  16.       type: Number, 
  17.       default: 300 
  18.     } 
  19.   }, 
  20.   computed: { 
  21.     hooks() { 
  22.       return { 
  23.         beforeEnter: this.setDuration, 
  24.         afterEnter: this.cleanUpDuration, 
  25.         beforeLeave: this.setDuration, 
  26.         afterLeave: this.cleanUpDuration, 
  27.         ...this.$listeners 
  28.       }; 
  29.     } 
  30.   }, 
  31.   methods: { 
  32.     setDuration(el) { 
  33.       el.style.animationDuration = `${this.duration}ms`; 
  34.     }, 
  35.     cleanUpDuration(el) { 
  36.       el.style.animationDuration = ""
  37.     } 
  38.   } 
  39. }; 
  40. </script> 
  41. <style> 
  42. @keyframes fadeIn { 
  43.   from { 
  44.     opacity: 0; 
  45.   } 
  46.   to { 
  47.     opacity: 1; 
  48.   } 
  49. .fadeIn { 
  50.   animation-name: fadeIn; 
  51. @keyframes fadeOut { 
  52.   from { 
  53.     opacity: 1; 
  54.   } 
  55.   to { 
  56.     opacity: 0; 
  57.   } 
  58. .fadeOut { 
  59.   animation-name: fadeOut; 
  60. </style> 

 

「完整事例地址:https://codesandbox.io/s/j4qnjvmwz9?from-embed」

现在,我们可以控制实际的可见过渡时间,这使我们可重用的过渡变得灵活且易于使用。但是,如何过渡多个元素(如列表项)呢?

Transition group 支持

你想到的最直接的方法可能是创建一个新组件,比如fade-transition-group,然后将当前transition标签替换为transition-group标签,以实现 group transition。如果我们可以在相同的组件中这样做,并公开一个将切换到transition-group实现的group prop,那会怎么样呢?幸运的是,我们可以通过render函数或component和is属性来实现这一点。

  1. // FadeTransition.vue 
  2.  
  3. <template> 
  4.   <component :is="type" 
  5.              :tag="tag" 
  6.              enter-active-class="fadeIn" 
  7.              leave-active-class="fadeOut" 
  8.              move-class="fade-move" 
  9.              v-bind="$attrs" 
  10.              v-on="hooks"> 
  11.       <slot></slot> 
  12.   </component> 
  13. </template> 
  14. <script> 
  15. export default { 
  16.   props: { 
  17.     duration: { 
  18.       type: Number, 
  19.       default: 300 
  20.     }, 
  21.     group: { 
  22.       type: Boolean, 
  23.       default: false 
  24.     }, 
  25.     tag: { 
  26.       type: String, 
  27.       default: "div" 
  28.     } 
  29.   }, 
  30.   computed: { 
  31.     type() { 
  32.       return this.group ? "transition-group" : "transition"; 
  33.     }, 
  34.     hooks() { 
  35.       return { 
  36.         beforeEnter: this.setDuration, 
  37.         afterEnter: this.cleanUpDuration, 
  38.         beforeLeave: this.setDuration, 
  39.         afterLeave: this.cleanUpDuration, 
  40.         leave: this.setAbsolutePosition, 
  41.         ...this.$listeners 
  42.       }; 
  43.     } 
  44.   }, 
  45.   methods: { 
  46.     setDuration(el) { 
  47.       el.style.animationDuration = `${this.duration}ms`; 
  48.     }, 
  49.     cleanUpDuration(el) { 
  50.       el.style.animationDuration = ""
  51.     }, 
  52.     setAbsolutePosition(el) { 
  53.       if (this.group) { 
  54.         el.style.position = "absolute"
  55.       } 
  56.     } 
  57.   } 
  58. }; 
  59. </script> 
  60. <style> 
  61. @keyframes fadeIn { 
  62.   from { 
  63.     opacity: 0; 
  64.   } 
  65.   to { 
  66.     opacity: 1; 
  67.   } 
  68. .fadeIn { 
  69.   animation-name: fadeIn; 
  70. @keyframes fadeOut { 
  71.   from { 
  72.     opacity: 1; 
  73.   } 
  74.   to { 
  75.     opacity: 0; 
  76.   } 
  77. .fadeOut { 
  78.   animation-name: fadeOut; 
  79. .fade-move { 
  80.   transition: transform 0.3s ease-out; 
  81. </style> 
  82.  
  83. // App.vue 
  84.  
  85. ... 
  86.  
  87. <div class="box-wrapper"> 
  88.   <fade-transition group :duration="300"> 
  89.     <div class="box" 
  90.          v-for="(item, index) in list" 
  91.          @click="remove(index)" 
  92.          :key="item" 
  93.      > 
  94.     </div> 
  95.   </fade-transition> 
  96. </div> 
  97.  
  98. ... 

「完整事例地址:https://codesandbox.io/s/pk9r5j2257?from-embed」

 

[文档中][6]介绍了一个带有transition-group元素的警告。我们基本上必须在元素离开时将每个项目的定位设置为absolute,以实现其他项目的平滑移动动画。我们也必须添加一个move-class并手动指定过渡持续时间,因为没有用于移动的 JS hook。我们将这些调整添加到我们的上一个示例中。

再做一些调整,通过在mixin中提取 JS 逻辑,我们可以将其应用于轻松创建新的transition组件,只需将其放入下一个项目中即可。

Vue Transition

在此之前描述的所有内容基本上都是这个小型 [transition 集合][7]所包含的内容。它有 10 个封装的transition组件,每个约1kb(缩小)。我认为它非常方便,可以轻松地在不同的项目中使用。你可以试一试:)

总结

我们从一个基本的过渡示例开始,并最终通过可调整的持续时间和transition-group支持来创建可重用的过渡组件。我们可以使用这些技巧根据并根据自身的需求创建自己的过渡组件。希望读者从本文中学到了一些知识,并且可以帮助你们建立功能更好的过渡组件。

 

 

 

 

 

责任编辑:赵宁宁 来源: 大迁世界
相关推荐

2023-10-17 07:23:00

Vue组件代码

2024-01-03 08:00:00

Java软件开发代码

2011-07-21 13:24:14

java

2023-11-08 13:55:27

2011-04-12 16:01:04

MySQL查询编写

2018-11-08 15:50:18

前端Javascript重用性

2010-06-09 09:15:58

JSF 2Ajax组件

2013-04-23 09:14:22

可重用云工具Java安全框架云中间件

2013-04-23 09:24:51

2013-12-04 14:19:40

JavaScript代码重用

2011-07-12 15:45:29

java

2023-06-15 09:02:14

Python模块和包

2009-06-23 14:18:00

Java代码可重用性

2021-06-26 06:29:14

Vue 2Vue 3开发

2022-07-05 09:27:35

Iframe前端平台架构

2020-11-02 11:33:52

ReactVue应用

2021-08-28 10:06:29

VueJavascript应用

2020-10-30 12:44:05

USBLinux

2009-03-13 15:24:50

catchDisposeWCF

2023-04-19 08:12:00

VueAPI组合式
点赞
收藏

51CTO技术栈公众号