element ui backTop源码解析-逐行逐析

backTop 回到顶部 组件简介

基础概念

返回页面顶部的操作按钮

代码

<template>
  <div>
    <transition name="el-fade-in">
      <div
        v-if="visible"
        @click.stop="handleClick"
        :style="{
          'right': styleRight,
          'bottom': styleBottom
        }"
        class="el-backtop">
        <slot>
          <el-icon name="caret-top"></el-icon>
        </slot>
      </div>
      
    </transition>


  </div>
</template>

<script>
import throttle from 'throttle-debounce/throttle';

const cubic = value => Math.pow(value, 3);
// Math.pow(a,b) 用于计算指定值的次方值,此处是a的b次方
// 此处用到的是箭头函数
const easeInOutCubic = value => value < 0.5
  ? cubic(value * 2) / 2
  : 1 - cubic((1 - value) * 2) / 2;

export default {
  name: 'ElBacktop',
  props: {
    visibilityHeight: {//滚动达到此参数值才出现
      type: Number,
      default: 200
    },
    target: [String],//触发滚动的对象 滚动的容器
    right: {//控制显示位置,距离页面右边距
      type: Number,
      default: 40
    },
    bottom: {//控制显示位置,距离页面顶部距离 
      type: Number,
      default: 40
    }
  },

  data() {
    return {
      el: null,// 触发滚动的对象
      container: null,//滚动的容器
      visible: false//是否可见  页面滚动距离大于指定高度
    };
  },

  computed: {
    styleBottom() {
      return `${this.bottom}px`;
    },
    styleRight() {
      return `${this.right}px`;
    }
  },

  mounted() {
    this.init();
    this.throttledScrollHandler = throttle(300, this.onScroll);
    // 节流 封装一个 函数 将onScroll 包裹一层,限制函数触发的频率
    this.container.addEventListener('scroll', this.throttledScrollHandler);
    // 滚动容器上绑定滚动事件,onScroll 
  },

  methods: {
    init() {
      this.container = document;
      this.el = document.documentElement;
      //document 和 documentElement 的区别
      // document 是文档对象 
      // document.documentElement 是整个文档节点树的根节点元素 即<html>元素
      // container 容器 设置为 document 
      //当前元素的                                                                                                      
      if (this.target) {
        // 有传入选择器 
        this.el = document.querySelector(this.target);
        // 通过选择器获取元素
        if (!this.el) {
          // 如果没有获取到元素则抛出错误
          throw new Error(`target is not existed: ${this.target}`);
        }
        this.container = this.el;
        // 滚动的容器设置为el 
      }
    },
    onScroll() {
      const scrollTop = this.el.scrollTop;//获取滚动条距离顶部的距离
      this.visible = scrollTop >= this.visibilityHeight;//页面滚动距离大于指定高度
    },
    handleClick(e) {
      /* 
         在触发点击的时候
         调用scrollToTop 页面滚动到顶部
         并且向父组件发送click事件,给组件模拟原生的click事件,以方便父组件调用的时候有点击事件的逻辑

      */
      this.scrollToTop();
      // 调用滚动到顶部的函数
      this.$emit('click', e);//向父组件发送click事件,给组件模拟原生的click事件,以方便父组件调用的时候有点击事件的逻辑
    },
    scrollToTop() {
      const el = this.el;
      const beginTime = Date.now();//Date.now()获取到当前时间的时间戳
      const beginValue = el.scrollTop;//scrollTop 容器向上滑动后超出rong'qi
      const rAF = window.requestAnimationFrame || (func => setTimeout(func, 16));
      // 会把每一帧中的所有dom操作集中起来,在一次重绘或重流中完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
      // 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量 
      // requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销
      const frameFunc = () => {
        const progress = (Date.now() - beginTime) / 500;
        // 计算时间间隔 是否大于 500毫秒 
        if (progress < 1) {
          el.scrollTop = beginValue * (1 - easeInOutCubic(progress));
          // scrollTop 值会依次减小
          rAF(frameFunc);
        } else {
          el.scrollTop = 0;
        }
        // 在指定间隔时间里 递归调用 scrollTop 会逐渐减少,然后直到 progress值为1的时候就直接到顶
      };
      rAF(frameFunc);
    }
  },
  events: {
    // 
    scroll() {
      this.onScroll();
    }
  },
  mounted(){
    console.log("this0000",this)
  },
  beforeDestroy() {
    this.container.removeEventListener('scroll', this.throttledScrollHandler);
    // 在组件销毁的生命周期里 移除 container 上绑定的scroll事件
  }
};
</script>

具体分析

props 参数说明

参数名参数说明
visibilityHeight页面滚动出去的距离大于此值时才显示组件 visible 为true
target触发滚动的对象 滚动的容器
right控制显示位置,距离页面右边距
bot tom控制显示位置,距离页面顶部距离

data 参数说明

参数名说明
el触发滚动的对象
container滚动的容器
visible是否可见 页面滚动距离大于指定高

computed

  • styleBottom 根据传入的bottom拼接成px为单位的字符串
  • styleRight 根据传入的 right 拼接成px为单位的字符串

mounted

  • 调用初始化事件
  • 声明一个节流函数
  • 给container元素注册滚动的监听事件

methods

init 初始化函数
  • 根据条件判断 给 el 和 container 赋值
onScroll 滚动的函数
  • 动态获取到el的scrollTop值
  • 格努scrollTop值和visibilityHeight对比,给visible 赋值
handleClick 点击事件
  • 在触发点击的时候 调用scrollToTop 页面滚动到顶部
  • 并且向父组件发送click事件,给组件模拟原生的click事件,以方便父组件调用的时候有点击事件的逻辑
scrollToTop 滚动到顶部
  scrollToTop() {
      const el = this.el;
      const beginTime = Date.now();//Date.now()获取到当前时间的时间戳
      const beginValue = el.scrollTop;//scrollTop 容器向上滑动后超出rong'qi
      const rAF = window.requestAnimationFrame || (func => setTimeout(func, 16));
      // 会把每一帧中的所有dom操作集中起来,在一次重绘或重流中完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
      // 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量 
      // requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销
      const frameFunc = () => {
        const progress = (Date.now() - beginTime) / 500;
        // 计算时间间隔 是否大于 500毫秒 
        if (progress < 1) {
          el.scrollTop = beginValue * (1 - easeInOutCubic(progress));
          // scrollTop 值会依次减小
          rAF(frameFunc);
        } else {
          el.scrollTop = 0;
        }
        // 在指定间隔时间里 递归调用 scrollTop 会逐渐减少,然后直到 progress值为1的时候就直接到顶
      };
      rAF(frameFunc);
    }
注意 window.requestAnimationFrame
  • 会把每一帧中的所有dom操作集中起来,在一次重绘或重流中完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率
  • 在隐藏或不可见的元素中,requestAnimationFrame将不会进行重绘或回流,这当然就意味着更少的CPU、GPU和内存使用量
  • requestAnimationFrame是由浏览器专门为动画提供的API,在运行时浏览器会自动优化方法的调用,并且如果页面不是激活状态下的话,动画会自动暂停,有效节省了CPU开销
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要修改Element UI码,以便控制Backtop组件的滚动时长,可以按照以下步骤进: 1. 克隆Element UI码仓库到本地。可以在GitHub上找到Element UI的仓库,并使用git命令或其他工具将其克隆到本地。 2. 进入克隆的Element UI码目录,并找到Backtop组件的码文件。通常在`packages/backtop`目录下可以找到。 3. 打开Backtop组件的码文件,通常是`index.vue`或类似的文件。在该文件中,你将看到与Backtop组件相关的代码。 4. 在该文件中找到处理点击事件的代码块。通常会有一个像`handleClick`这样的方法来处理点击事件。 5. 在`handleClick`方法中,可以使用`requestAnimationFrame`来实现滚动动画并控制滚动时长。你可以修改该方法中的代码如下: ```javascript handleClick() { const el = document.documentElement || document.body const start = el.scrollTop const end = 0 const duration = 200 // 设置滚动时长,单位为毫秒 let current = start const step = () => { const timestamp = Date.now() const progress = Math.min((timestamp - start) / duration, 1) const easeInOutQuad = (t) => t<.5 ? 2*t*t : -1+(4-2*t)*t current = start + (end - start) * easeInOutQuad(progress) el.scrollTop = current if (progress < 1) { requestAnimationFrame(step) } } requestAnimationFrame(step) } ``` 在上述代码中,我们使用了`requestAnimationFrame`来实现滚动动画。通过计算当前时间与开始时间的差值,以及设置的滚动时长,可以得到滚动的进度。然后使用缓动函数(这里使用了`easeInOutQuad`)计算当前滚动位置,并设置`el.scrollTop`来实现滚动效果。 6. 保存修改并重新构建Element UI。根据Element UI的构建和打包方式,你可能需要运一些命令来重新构建Element UI,以使你的修改生效。 请注意,修改Element UI码并重新构建可能会带来一些风险和维护问题。建议在修改之前备份码,并确保理解修改的影响。另外,当Element UI更新时,你可能需要重新应用你的修改。 希望以上步骤可以帮助你修改Element UI码,实现对Backtop组件滚动时长的控制。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值