diff --git a/packages/devui-vue/devui/back-top/src/back-top-types.ts b/packages/devui-vue/devui/back-top/src/back-top-types.ts index 6f76d1cda94731627d7ff7f283a1370b35a56c66..1209ed581cdbdd9ab01fa60a170b9d5c3eeba582 100644 --- a/packages/devui-vue/devui/back-top/src/back-top-types.ts +++ b/packages/devui-vue/devui/back-top/src/back-top-types.ts @@ -1,7 +1,6 @@ import type { PropType, ExtractPropTypes } from 'vue' export type Position = { - position: 'fixed' bottom: string right: string } @@ -14,6 +13,14 @@ export const backTopProps = { right: { type: String, default: '30px' + }, + target: { + type: String, + default: 'window' + }, + visibleHeight: { + type: Number, + default: 300 } } as const diff --git a/packages/devui-vue/devui/back-top/src/back-top.scss b/packages/devui-vue/devui/back-top/src/back-top.scss index 18685214660f54b68cde866f7200e44b75ac0883..e0d28a369df11ffef577729591a0fdc34e4a9dd9 100644 --- a/packages/devui-vue/devui/back-top/src/back-top.scss +++ b/packages/devui-vue/devui/back-top/src/back-top.scss @@ -1,6 +1,7 @@ @import '../../styles-var/devui-var'; .devui-back-top { + position: fixed; width: 40px; height: 40px; cursor: pointer; @@ -8,12 +9,10 @@ .devui-back-top-base { width: 40px; height: 40px; - box-shadow: 0 0 8px rgba(0, 0, 0, 0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; - &:hover { opacity: 1; } @@ -21,6 +20,7 @@ .devui-back-top-content { opacity: 0.4; background-color: $devui-text-weak; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.2); } .devui-backtop-custom { background-color: #fff; diff --git a/packages/devui-vue/devui/back-top/src/back-top.tsx b/packages/devui-vue/devui/back-top/src/back-top.tsx index f3b7314a37ef35f4bafc214c36100fb4d73aecdb..1939a4e0156f5d74c30d00b4159a0b0f7c12390b 100644 --- a/packages/devui-vue/devui/back-top/src/back-top.tsx +++ b/packages/devui-vue/devui/back-top/src/back-top.tsx @@ -1,6 +1,6 @@ -import { defineComponent } from 'vue' +import { defineComponent, onMounted, ref } from 'vue' import { backTopProps, BackTopProps } from './back-top-types' -import { usePosition } from './hooks' +import { usePosition, useVisibility } from './hooks' import './back-top.scss' import IconTop from './assets/top.svg' @@ -9,11 +9,14 @@ export default defineComponent({ props: backTopProps, emits: [], setup(props: BackTopProps, ctx) { - const position = usePosition(props) const slots = ctx.slots + const backTopRef = ref(null) + + const position = usePosition(props) + let isVisible = useVisibility(props, backTopRef) const scrollToTop = () => { - // 运行在浏览器则调用该方法 + // toTop方法暂定 window && window.scrollTo({ top: 0, @@ -24,13 +27,15 @@ export default defineComponent({ return () => (
void +/* 简陋版待完善 */ +function useEventListener(target: HTMLElement, event: string, cb: cbFn) { + if (target) target.addEventListener(event, cb) +} + +export default useEventListener diff --git a/packages/devui-vue/devui/back-top/src/hooks/use-position.ts b/packages/devui-vue/devui/back-top/src/hooks/use-position.ts index b7c80f161f86ed297e7faf125afdba93e01beeb6..c66c16d531b0dfed3caffae388a36632ad48e4a8 100644 --- a/packages/devui-vue/devui/back-top/src/hooks/use-position.ts +++ b/packages/devui-vue/devui/back-top/src/hooks/use-position.ts @@ -4,7 +4,6 @@ export default function (props: BackTopProps): Position { const { bottom, right } = props return { - position: 'fixed', bottom, right } diff --git a/packages/devui-vue/devui/back-top/src/hooks/use-target.ts b/packages/devui-vue/devui/back-top/src/hooks/use-target.ts new file mode 100644 index 0000000000000000000000000000000000000000..220e770bd7780759ce606729ef9200aa7d09b6a3 --- /dev/null +++ b/packages/devui-vue/devui/back-top/src/hooks/use-target.ts @@ -0,0 +1,19 @@ +import { BackTopProps } from '../back-top-types' + +export default function (props: BackTopProps, backTopRef) { + const target = props.target // target为元素选择器 + + const getTargetEl = () => { + const targetEl = document.querySelector(target) + if (!targetEl) throw new Error(`props ${target} is not existed`) + + // 设置定位 + targetEl.style.position = 'relative' + backTopRef.value.style.position = 'absolute' + return targetEl + } + const currTarget = + target === 'window' ? window || document.documentElement || document.body : getTargetEl() + + return currTarget +} diff --git a/packages/devui-vue/devui/back-top/src/hooks/use-throttle.ts b/packages/devui-vue/devui/back-top/src/hooks/use-throttle.ts new file mode 100644 index 0000000000000000000000000000000000000000..ab5278fc31e2a37d9d94bad7965457cabf132047 --- /dev/null +++ b/packages/devui-vue/devui/back-top/src/hooks/use-throttle.ts @@ -0,0 +1,10 @@ +export default function (fn, delay) { + let last = null + return (...args) => { + const now = +Date.now() + if (now - last > delay) { + last = now + return fn.apply(this, args) + } + } +} diff --git a/packages/devui-vue/devui/back-top/src/hooks/use-visibility.ts b/packages/devui-vue/devui/back-top/src/hooks/use-visibility.ts new file mode 100644 index 0000000000000000000000000000000000000000..5dc7061f9505deb50b02dbdf85f19b35d5521e39 --- /dev/null +++ b/packages/devui-vue/devui/back-top/src/hooks/use-visibility.ts @@ -0,0 +1,21 @@ +import { onMounted, computed, ref } from 'vue' +import { BackTopProps } from '../back-top-types' +import { useTarget, useEventListener, useThrottle } from '.' +export default function (props: BackTopProps, backTopRef) { + const visibleHeight = props.visibleHeight + const currScrollTop = ref(0) + const ThrottleCBFn = function () { + currScrollTop.value = currTarget === window ? window.pageYOffset : currTarget.scrollTop + } + + let currTarget = null + onMounted(() => { + currTarget = useTarget(props, backTopRef) + // 监听滚动事件 手动更新ScrollTop + useEventListener(currTarget, 'scroll', useThrottle(ThrottleCBFn, 150)) + }) + + const isVisible = computed(() => currScrollTop.value >= visibleHeight) + + return isVisible +} diff --git a/packages/devui-vue/docs/components/back-top/index.md b/packages/devui-vue/docs/components/back-top/index.md index f2be59b9ed7b38c1fab6fe7f25fb189add33c192..76cf74ff1a2ba398e10368702e5b615cc491e047 100644 --- a/packages/devui-vue/docs/components/back-top/index.md +++ b/packages/devui-vue/docs/components/back-top/index.md @@ -73,15 +73,80 @@ export default defineComponent({ ::: +### 嵌入容器内部 + +通过设置 target 参数,可对特定容器进行返回顶部操作。 + +:::demo + +```vue + + + + + +``` + +::: + ### d-back-top d-back-top 参数 -| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | -| :----: | :------: | :----: | :------------------------: | :---------------: | -| bottom | `string` | "50px" | 可选,按钮距离页面底部位置 | [示例](#基本用法) | -| right | `string` | "30px" | 可选,按钮距离页面右边距 | [示例](#基本用法) | -| | | | | | +| 参数 | 类型 | 默认 | 说明 | 跳转 Demo | +| :-----------: | :------: | :------: | :-------------------------------------------------------------------: | :-------------------: | +| bottom | `string` | "50px" | 可选,按钮距离页面底部位置 | [示例](#基本用法) | +| right | `string` | "30px" | 可选,按钮距离页面右边距 | [示例](#基本用法) | +| visibleHeight | `number` | 300 | 可选,滚动高度达到 visibleHeight 所设值后展示回到顶部按钮,单位为`px` | [示例](#基本用法) | +| target | `string` | 'window' | 可选,触发滚动的元素选择器 | [示例](#嵌入容器内部) | +| | | | | | d-back-top 事件