Skip to content

Commit

Permalink
feat: backTop
Browse files Browse the repository at this point in the history
  • Loading branch information
BeADre committed Feb 6, 2021
1 parent ee7be71 commit efaf596
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 71 deletions.
1 change: 1 addition & 0 deletions packages/varlet-icons/svg/uF015-chevron-up.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
97 changes: 97 additions & 0 deletions packages/varlet-ui/src/back-top/BackTop.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<template>
<div class="var-back-top" :class="[show ? 'var-back-top--active' : null]" @click.stop="click">
<slot>
<var-button type="primary" round class="var-back-top__button">
<var-icon name="chevron-up" />
</var-button>
</slot>
</div>
</template>
<script lang="ts">
import { defineComponent, ref, Ref, onMounted, onBeforeUnmount } from 'vue'
import Button from '../button'
import Icon from '../icon'
import { props } from './props'
import { isString, easeInOutCubic, throttle } from '../utils/shared'
import { getScrollTop, requestAnimationFrame } from '../utils/elements'
export default defineComponent({
name: 'VarBackTop',
components: {
[Button.name]: Button,
[Icon.name]: Icon,
},
props,
setup(props) {
const element: Ref<Element | null> = ref(null)
const show: Ref<boolean> = ref(false)
const click = () => {
props.onClick?.()
const top = getScrollTop(element.value as Element)
const startTime = Date.now()
const frameFunc = () => {
const progress = (Date.now() - startTime) / props.duration
if (progress < 1) {
;(element.value as Element).scrollTop = top * (1 - easeInOutCubic(progress))
requestAnimationFrame(frameFunc)
} else {
;(element.value as Element).scrollTop = 0
}
}
requestAnimationFrame(frameFunc)
}
const scroll = () => {
show.value = getScrollTop(element.value as Element) >= +props.visibilityHeight
}
const throttleScroll = throttle(scroll, 200)
const getElement = () => {
if (!isString(props.target)) throw Error('[Varlet] BackTop: type of prop "target" should be a string')
const el = document.querySelector(props.target)
if (!el) throw Error('[Varlet] BackTop: "target" should be a selector')
return el
}
onMounted(() => {
element.value = getElement()
if (!element.value) return
element.value.addEventListener('scroll', throttleScroll)
})
onBeforeUnmount(() => {
if (!element.value) return
element.value.removeEventListener('scroll', throttleScroll)
})
return {
show,
click,
}
},
})
</script>

<style lang="less">
.var {
&-back-top {
position: fixed;
right: 50px;
bottom: 50px;
transform: scale(0);
transition: 0.3s cubic-bezier(0.25, 0.8, 0.5, 1);
&__button {
width: 54px;
height: 54px;
}
&--active {
transform: scale(1);
}
}
}
</style>
7 changes: 7 additions & 0 deletions packages/varlet-ui/src/back-top/__tests__/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const BackTop = require('../../../cjs/back-top').default
const { render } = require('@testing-library/vue')

test('test backTop', async () => {
const wrapper = render(BackTop)
console.log(wrapper)
})
Empty file.
Empty file.
40 changes: 40 additions & 0 deletions packages/varlet-ui/src/back-top/example/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<template>
<div class="var-back-top__example">
<div>
<div v-for="list in lists" :key="list">Scroll to bottom {{ list }}</div>
<var-back-top target=".var-back-top__example" visibility-height="100" :duration="300" @click="test" />
</div>
</div>
</template>

<script>
import { defineComponent } from 'vue'
import BackTop from '..'
const lists = [...Array(100).keys()]
export default defineComponent({
name: 'BackTopExample',
components: {
[BackTop.name]: BackTop,
},
setup() {
const test = () => {
console.log('click')
}
return {
test,
lists,
}
},
})
</script>

<style scoped>
.var-back-top__example {
height: calc(100vh - 130px);
overflow: auto;
margin-top: 18px;
}
</style>
8 changes: 8 additions & 0 deletions packages/varlet-ui/src/back-top/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { App } from 'vue'
import BackTop from './BackTop.vue'

BackTop.install = function (app: App) {
app.component(BackTop.name, BackTop)
}

export default BackTop
16 changes: 16 additions & 0 deletions packages/varlet-ui/src/back-top/props.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const props = {
visibilityHeight: {
type: [Number, String],
default: 200,
},
duration: {
type: Number,
default: 300,
},
target: {
type: String,
},
onClick: {
type: Function,
},
}
13 changes: 9 additions & 4 deletions packages/varlet-ui/src/utils/shared.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
export interface CacheInstance<T> {
cache: T[]
cache: T[]

has(key: T): boolean
has(key: T): boolean

add(key: T): void
add(key: T): void

remove(key: T): void
remove(key: T): void
}

export const isString = (val: unknown): val is string => typeof val === 'string'
Expand Down Expand Up @@ -96,3 +96,8 @@ export const createCache = <T>(max: number): CacheInstance<T> => {
},
}
}

export const cubic = (value: number): number => value ** 3

export const easeInOutCubic = (value: number): number =>
value < 0.5 ? cubic(value * 2) / 2 : 1 - cubic((1 - value) * 2) / 2
Loading

0 comments on commit efaf596

Please sign in to comment.