2019独角兽企业重金招聘Python工程师标准>>>

项目中发现同事使用了element-ui的el-collapse-transition来做折叠展开效果,打开源码看了下发现挺有意思,来解析学习一番。

el-collapse-transition的引入方式

// fade/zoom 等
import 'element-ui/lib/theme-chalk/base.css';
// collapse 展开折叠
import CollapseTransition from 'element-ui/lib/transitions/collapse-transition';
import Vue from 'vue'Vue.component(CollapseTransition.name, CollapseTransition)

使用方式

<template><div><div><button @click="cb">切换</button></div><el-collapse-transition><div v-if="show" class="testshow"><div>sssssss</div><div>sssssss</div><div>sssssss</div><div>sssssss</div><div>sssssss</div></div></el-collapse-transition></div>
</template><script>
export default {data: () => ({show: true}),methods: {cb() {this.show = !this.show;},}
}
</script>
<style lang="less">
.testshow{padding: 10px 10px;background-color: aqua;
}
<style>

效果,v-if和v-show都可以

下面来解析一下源码的实现

el-collapse-transition写在js文件中,源码路径element-dev/src/transitions/collapse-transition.js

核心的实现方式是通过vue的函数式组件的方式实现的,如下代码

export default {name: 'ElCollapseTransition',functional: true,render(h, { children }) {const data = {on: new Transition()};return h('transition', data, children);}
};

看到此处代码可以得出,实现的原理就是生成一个<transition>标签,通过vue的<transition>来实现折叠动画效果。

return h('transition', data, children);这里用到了data对象,里面绑定了事件,on后面的是一个Transition类的实例

class Transition {beforeEnter(el) {addClass(el, 'collapse-transition');if (!el.dataset) el.dataset = {};el.dataset.oldPaddingTop = el.style.paddingTop;el.dataset.oldPaddingBottom = el.style.paddingBottom;el.style.height = '0';el.style.paddingTop = 0;el.style.paddingBottom = 0;}enter(el) {el.dataset.oldOverflow = el.style.overflow;if (el.scrollHeight !== 0) {el.style.height = el.scrollHeight + 'px';el.style.paddingTop = el.dataset.oldPaddingTop;el.style.paddingBottom = el.dataset.oldPaddingBottom;} else {el.style.height = '';el.style.paddingTop = el.dataset.oldPaddingTop;el.style.paddingBottom = el.dataset.oldPaddingBottom;}el.style.overflow = 'hidden';}afterEnter(el) {// for safari: remove class then reset height is necessaryremoveClass(el, 'collapse-transition');el.style.height = '';el.style.overflow = el.dataset.oldOverflow;}beforeLeave(el) {if (!el.dataset) el.dataset = {};el.dataset.oldPaddingTop = el.style.paddingTop;el.dataset.oldPaddingBottom = el.style.paddingBottom;el.dataset.oldOverflow = el.style.overflow;el.style.height = el.scrollHeight + 'px';el.style.overflow = 'hidden';}leave(el) {if (el.scrollHeight !== 0) {// for safari: add class after set height, or it will jump to zero height suddenly, weiredaddClass(el, 'collapse-transition');el.style.height = 0;el.style.paddingTop = 0;el.style.paddingBottom = 0;}}afterLeave(el) {removeClass(el, 'collapse-transition');el.style.height = '';el.style.overflow = el.dataset.oldOverflow;el.style.paddingTop = el.dataset.oldPaddingTop;el.style.paddingBottom = el.dataset.oldPaddingBottom;}
}

这个Transition类里面封装的其实就是<transition>的钩子函数

<transitionv-on:before-enter="beforeEnter"v-on:enter="enter"v-on:after-enter="afterEnter"v-on:enter-cancelled="enterCancelled"v-on:before-leave="beforeLeave"v-on:leave="leave"v-on:after-leave="afterLeave"v-on:leave-cancelled="leaveCancelled"
><!-- ... -->
</transition>

所以实现原理就很清晰了,通过<transition>组件上的javascript钩子来实现动画效果,那我们来具体看看钩子里面的函数执行了什么就可以了

this.show 从false切换到true,触发的钩子是before-enter="beforeEnter"、enter="enter"、after-enter="afterEnter"

before-enter钩子会被第一个触发,执行beforeEnter代码,这里的el元素就是class=testshow这个div容器,下面统一称作容器元素

beforeEnter(el) {addClass(el, 'collapse-transition');if (!el.dataset) el.dataset = {};el.dataset.oldPaddingTop = el.style.paddingTop;el.dataset.oldPaddingBottom = el.style.paddingBottom;el.style.height = '0';el.style.paddingTop = 0;el.style.paddingBottom = 0;
}

beforeEnter方法中,首先给容器元素添加collapse-transition类,这个类的样式是

.collapse-transition {transition: 0.3s height ease-in-out, 0.3s padding-top ease-in-out, 0.3s padding-bottom ease-in-out;
}

添加这个样式之后,当改变height padding-top padding-bottom时会按照上述代码出现效果

js代码紧接着在容器元素上创建自定义属性,将容器元素原有的padding-top和padding-bottom值存到相对应的自定义属性中。

然后,将容器元素的height padding-top padding-bottom置为0

before-enter钩子执行完之后,进入enter钩子执行,这时如果在即将执行enter方法第一句代码打上断点的话,可以发现在执行enter钩子时,在vue中已经将容器元素中包裹的内容显示出来,然后我们看一下enter方法的代码是怎么处理的

enter(el) {el.dataset.oldOverflow = el.style.overflow;if (el.scrollHeight !== 0) {el.style.height = el.scrollHeight + 'px';el.style.paddingTop = el.dataset.oldPaddingTop;el.style.paddingBottom = el.dataset.oldPaddingBottom;} else {el.style.height = '';el.style.paddingTop = el.dataset.oldPaddingTop;el.style.paddingBottom = el.dataset.oldPaddingBottom;}el.style.overflow = 'hidden';
}

enter方法首先将容器元素的overflow属性值存到相对应的自定义属性之中,然后恢复height padding-top padding-bottom的值。height的值使用scrollHeight恢复(后面讲解为啥用scrollHeight),将存在自定义属性中的padding-top和padding-bottom值拿出来恢复。然后将容器元素的overflow置为hidden。置为hidden是因为,如果不置为hidden,那么容器元素中的内容就会立刻显示出来,而此时容器元素的高度和padding是按照0.3秒的动效慢慢展开,那么就会是下图效果,所以要先隐藏内容,随着容器的慢慢展开而出现内容。

展开的过程,最后执行afterEnter方法

afterEnter(el) {// for safari: remove class then reset height is necessaryremoveClass(el, "collapse-transition");el.style.height = "";el.style.overflow = el.dataset.oldOverflow;
},

这个方法,将collapse-transition类删除掉,将overflow恢复为容器元素本来的状态,将height置为'',其实就是相当于auto。

看到这里也就是要注意,容器元素的高度不要用内联样式,否则会被覆盖掉。

上面说的为什么用scrollHeight来恢复height的值?

因为在没有滚动条的时候scrollHeight的值和clientHeight的值相等,也就是等于padding-box的值,height = scrollHeight赋值的位置,padding值还为0,所以获取的是准确的height值,拿去恢复height的值刚刚好。但是,如果容器元素的height小于包含的内容的高度,有滚动条的话,scrollHeight高度超过height原值,尽管afterEnter中的代码会把height恢复为auto,还是会出问题,如下图

.testshow{padding: 10px 10px;background-color: aqua;height: 70px;overflow: auto;
}

解决这个问题的方法就是,在现在这个元素容器外面再套一层新的容器元素

<div v-show="showdiv"><div  class="testshow"><div>sssssss</div><div>sssssss</div><div>sssssss</div><div>sssssss</div><div>sssssss</div></div></div>

这样就解决了,如下图

也就是说,使用这个组件实现折叠展开效果,放在组件里面的内容的容器元素,尽量不要添加height overflow这种样式,就可以不出现这些问题了。

this.show 从true到false就是逆过程,就不用单独分析了。

以上就是我对el-collapse-transition组件的解析学习,还是有挺多收获的。

转载于:https://my.oschina.net/wangch5453/blog/3003815

element-ui之el-collapse-transition(折叠展开动画)源码解析学习相关推荐

  1. 直播系统源代码实现RecyclerView折叠展开动画

    直播系统源代码实现RecyclerView折叠展开动画的相关代码 首先来看看布局文件 <?xml version="1.0" encoding="utf-8&quo ...

  2. VUE实现折叠展开动画效果

    VUE实现折叠展开动画效果 第一种情况:从中间向两边展开效果(水平缩放) .input-search {position: absolute;bottom: 8px;right: 0px;width: ...

  3. 最新UI界面很简洁的方盒子iApp源码+适合做工具箱

    正文: 分享一个UI界面很简洁的方盒子iapp源码,非常适合拿来做工具箱的,这个UI源码已经很久的了,在网上看到的,就拿出来再分享一下吧! 程序: wwxjes.lanzoup.com/ishUo0k ...

  4. 2022全新UI呆错简约大气的导航网站源码

    正文: 2022全新UI呆错简约大气的导航网站源码 特点: 无任何加密代码.源代码完全公开. 系统稳定,内核安全稳定.PHP+MYSQL/Sqlite架构.跨平台运行.ThinkPhp+Jquery+ ...

  5. 精美UI强大娱乐功能组合微信小程序源码

    介绍: 这是一个多娱乐功能的小程序 具体由以下功能组合: 网易云在线音乐(***音乐和网易云功能界面一样) 外卖CPS(外卖平台优惠劵) 打车CPS(打车平台优惠劵) 头像功能(多分类头像,另外还支持 ...

  6. 【iapp源码】UI界面很简洁的方盒子iapp源码

    分享一个UI界面很简洁的方盒子iapp源码,非常适合拿来做工具箱的, 这个UI源码已经很久的了,在网上看到的,就拿出来再分享一下吧!

  7. 简洁UI自带稳定接口去水印小程序源码

    这是一款UI超简洁的一款去水印小程序源码 到底有多简洁呢,小编只能说要多简洁就有多简洁 首先保存视频的时候不会显示下载进度,所以你就会误以为没反应 其实视频已经在下载了,当然啦下载好了以后还是会有下载 ...

  8. 【小程序源码】精美UI强大娱乐功能组合微信小程序源码下载,安装简单

    这是一个多娱乐功能的小程序 具体由以下功能组合: 在线音乐 短视频去印 外卖CPS(外卖平台优惠劵) 打车CPS(打车平台优惠劵) 头像功能(多分类头像,另外还支持姓氏头像制作) 图片加水印 表情包功 ...

  9. 新款UI动态壁纸头像潮图小程序源码

    小子亲测了下,不错挺棒的,安装也特别简单 新款UI动态壁纸头像潮图小程序源码,不需要域名服务器,直接添加合法域名,上传发布就能使用. 可以对接开通流量主,个人也能运营,不需要服务器源码完整.整合头像, ...

最新文章

  1. 漫长的数据中心绿化之路到底该如何走www.shzhenai.com
  2. USACO SEC.1.3 No.1 Mixing Milk
  3. Java高级工程师必备知识!java入门书籍pdf
  4. 《Python Cookbook 3rd》笔记(4.11):同时迭代多个序列
  5. java中堆栈的基本操作_玩儿转队列和栈的基本操作及其应用:Java 版
  6. 华为徐直军:华为云成为智能世界五朵云之一,2021年大力支持伙伴持续创新
  7. ethtool查看网卡以及修改网卡配置
  8. c# 执行js方法
  9. CCNA自学教材推荐(转)
  10. 有道词典 PC端 手机端 单词 背 个数 不同步 解决
  11. ArcGIS中地理配准与空间校正的不同
  12. 汤姆猫代码python_IOS 汤姆猫核心代码
  13. 解决Win10系统“win32错误报告,拒绝访问”问题,正解!!!
  14. php liger 表格排序,LigerUI之grid表格点击表头标题排序实现
  15. 惠普笔记本U盘重装系统教程(转载)
  16. python手写数字识别实验报告_Python代码实现简单的MNIST手写数字识别(适合初学者看)...
  17. python计算机视觉——立体匹配与NCC算法
  18. 常用限流方案的设计和实现
  19. Pwn2Own 2022 温哥华大赛Master of Pwn 诞生
  20. GBASE南大通用携手长亮科技 重磅推出金融数据仓库联合解决方案

热门文章

  1. 三个办公室随机分配8位老师,且每个办公室不能少于2个老师
  2. 线性回归 假设_线性回归的假设
  3. 根据查询结果导出表格数据
  4. Golang 浮点数格式化输出,保留一位小数
  5. UE4反射机制的通俗理解【生成第一个UClass】
  6. 渗透安全及渗透测试流程
  7. Python学习日记 第九天 EX20-21
  8. 本科论文开题报告字体及格式规范是怎么样的?
  9. 缩放动画 ScaleAnimation 总结
  10. conda 装tensorboardx_Pytorch数据可视化:TensorboardX安装及使用(安装测试+实例演示)...