前言
当开发页面内容较多,如介绍官网产品之类【只有一个产品的当我没说~】的,应该有不少童鞋都碰到过一键回到顶部的需求,那么一键回到顶部具体是怎么实现的呢?今天就一起来看一下element-plus的el-backtop
的源码,研究一下具体的实现!
收获清单
- 源码调试分析
- 回到顶部组件实现
组件介绍
- 功能
返回页面顶部的操作按钮。 - 属性
名称 | 说明 | 类型 | 默认值 |
---|---|---|---|
target | 触发滚动的对象 | string | — |
visibility-height | 滚动高度达到此参数值才出现 | number | 200 |
right | 控制其显示位置,距离页面右边距 | number | 40 |
bottom | 控制其显示位置,距离页面底部距离 | number | 40 |
源码下载
git clone https://github.com/element-plus/element-plus.git
cd element-plus
pnpm install
// 本地打开文档
pnpm docs:dev
// 本地运行例子
pnpm run dev
- 利用vue-tools打开源码位置
我们可以在
play\src\App.vue
引入官网例子,然后运行pnpm run dev
,这样就可以借助vue-tools
打开源码位置了,效果如下:
源码分析
- 入口文件 index.ts
import { withInstall } from '@element-plus/utils'
import Backtop from './src/backtop.vue'
export const ElBacktop = withInstall(Backtop)
export default ElBacktop
export * from './src/backtop'
export type { BacktopInstance } from './src/instance'
入口文件的作用主要是全局注册ElBacktop组件,并且导出相关实例和组件供全局使用,我们也可以在这里打debugger调试一下,看withInstall的作用:
- backtop.vue
<template>
<transition :name="`${ns.namespace.value}-fade-in`">
<div
v-if="visible"
:style="backTopStyle"
:class="ns.b()"
@click.stop="handleClick"
>
<!-- 可以自定义backtop组件的显示 -->
<slot>
<el-icon :class="ns.e('icon')"><caret-top /></el-icon>
</slot>
</div>
</transition>
</template>
<script lang="ts" setup>
import { computed } from 'vue'
import { ElIcon } from '@element-plus/components/icon'
import { CaretTop } from '@element-plus/icons-vue'
import { useNamespace } from '@element-plus/hooks'
import { backtopEmits, backtopProps } from './backtop'
import { useBackTop } from './use-backtop'
const COMPONENT_NAME = 'ElBacktop'
defineOptions({
name: COMPONENT_NAME,
})
// 支持传入visibilityHeight、target、 right、bottom等属性
const props = defineProps(backtopProps)
// emit click事件
const emit = defineEmits(backtopEmits)
// 命名空间
const ns = useNamespace('backtop')
// 响应点击事件和获取控制backtop组件显示隐藏的属性
const { handleClick, visible } = useBackTop(props, emit, COMPONENT_NAME)
// 样式
const backTopStyle = computed(() => ({
right: `${props.right}px`,
bottom: `${props.bottom}px`,
}))
</script>
- use-backtop.ts
import { onMounted, ref, shallowRef } from 'vue'
import { useEventListener, useThrottleFn } from '@vueuse/core'
import { throwError } from '@element-plus/utils'
import type { SetupContext } from 'vue'
import type { BacktopEmits, BacktopProps } from './backtop'
export const useBackTop = (
props: BacktopProps,
emit: SetupContext<BacktopEmits>['emit'],
componentName: string
) => {
const el = shallowRef<HTMLElement>()
const container = shallowRef<Document | HTMLElement>()
const visible = ref(false)
// 滚动到大于可视高度的位置时显示el-backtop组件
const handleScroll = () => {
if (el.value) visible.value = el.value.scrollTop >= props.visibilityHeight
}
// 利用scrollTo使界面滚动到指定位置,其中smooth 表示平滑滚动并产生过渡效果
const handleClick = (event: MouseEvent) => {
el.value?.scrollTo({ top: 0, behavior: 'smooth' })
emit('click', event)
}
// 创建一个节流函数,在300 毫秒内最多执行 handleScroll 一次的函数
const handleScrollThrottled = useThrottleFn(handleScroll, 300, true)
// 给document设置滚动事件的监听器
useEventListener(container, 'scroll', handleScrollThrottled)
// onMounted时赋值,若指定target则目标元素为target否则将文档对象(document)的根元素的只读属性(如 HTML 文档的 <html> 元素)赋值给el
onMounted(() => {
container.value = document
el.value = document.documentElement
if (props.target) {
el.value = document.querySelector<HTMLElement>(props.target) ?? undefined
if (!el.value) {
throwError(componentName, `target does not exist: ${props.target}`)
}
container.value = el.value
}
// Give visible an initial value, fix #13066
handleScroll()
})
return {
visible,
handleClick,
}
}
由以上代码我们可以总结出el-backtop主要是通过scrollTo来实现一键回到顶部的效果,同时给监听的滚动事件设置节流的优化手段也是我们在日常开发中可以借鉴的~
总结
今天的源码学习就告一段落,源码调试的方式有多种,也可以借助测试用例来调试。el-backtop组件的源码比较简单,当然可能主要还是因为功能比较简单,当想要学源码却无从下手的时候就可以挑一些比较易懂的开始(如这一期),因为这样可以逐渐增加自己学习的动力~