提交 98e7468d 编写于 作者: S suzigang

refactor: backtop

上级 c6c19b9e
<template>
<div class="demo" id="elId" ref="scroll">
<div class="demo" id="elId">
<div class="text-data">我是测试数据1</div>
<div class="text-data">我是测试数据2</div>
<div class="text-data">我是测试数据3</div>
......@@ -24,10 +24,19 @@
<div class="text-data">我是测试数据22</div>
<div class="text-data">我是测试数据23</div>
<div class="text-data">我是测试数据24</div>
<nut-backtop @click="handleClick" elId="elId" :distance="100" :bottom="90"
><view></view></nut-backtop
<nut-backtop
@click="handleClick"
:el-id="elId"
:distance="100"
:bottom="90"
>
<nut-backtop @click="handleClick" elId="elId" :distance="200"></nut-backtop>
<view></view>
</nut-backtop>
<nut-backtop
@click="handleClick"
:el-id="elId"
:distance="200"
></nut-backtop>
</div>
</template>
......
......@@ -21,7 +21,7 @@ app.use(BackTop);
### 基本用法
```html
<nut-backtop elId="elId" ></nut-backtop>
<nut-backtop :el-id="elId" ></nut-backtop>
```
### 设置出现位置
......@@ -33,14 +33,9 @@ app.use(BackTop);
### 自定义样式
```html
<nut-backtop @click="handleClick" elId="elId" :distance="100" :bottom="90" ><div></div></nut-backtop>
<nut-backtop @click="handleClick" :el-id="elId" :distance="100" :bottom="90" ><div></div></nut-backtop>
```
### 设置样式
<nut-backtop>
</nut-backtop>
### click事件
```html
......@@ -68,15 +63,17 @@ export default createDemo({
### Prop
| 字段 | 说明 | 类型 | 默认值 |
|-----------------|------------------------------------------------------------------------------------------------|---------|---------|
| elId | 获取监听元素的父级元素 | String | - |
| bottom | 距离页面底部距离 | Number | - |
| right | 距离页面右侧距离 | Number | |
| distance | 页面垂直滚动多高后出现 | Number | - |
| zIndex | 设置组件页面层级 | Number | - |
| 字段 | 说明 | 类型 | 默认值 |
|-----------------|------------------------------------------|---------|---------|
| el-id | 获取监听元素的父级元素 | String | - |
| bottom | 距离页面底部距离 | Number | `20` |
| right | 距离页面右侧距离 | Number | `10` |
| distance | 页面垂直滚动多高后出现 | Number | `200` |
| z-index | 设置组件页面层级 | Number | `10` |
| is-animation | 是否有动画,和duration参数互斥 | Boolean | `true` |
| duration | 设置动画持续时间 | Number | `1000` |
### Event
| 名称 | 说明 | 回调参数 |
|-------|----------|-------------|
| click | 按钮点击时触发事件 | event:Event |
\ No newline at end of file
| click | 按钮点击时触发事件 | event: MouseEvent |
\ No newline at end of file
.nut-backtop {
display: none;
position: fixed;
bottom: 20px;
right: 20px;
z-index: 111;
&.show {
display: block;
width: 40px;
height: 40px;
background: rgba(255, 255, 255, 1);
border: 1px solid rgba(224, 224, 224, 1);
background: $white;
border: 1px solid $backtop-border-color;
border-radius: 50%;
display: flex;
align-items: center;
......
<template>
<div
:class="['nut-backtop', { show: backTop }]"
:style="{
right: styleRight,
bottom: styleBottom,
'z-index': zIndex
}"
@click="click"
>
<div :class="classes" :style="style" @click.stop="click">
<slot>
<nut-icon size="19px" class="nut-backtop-main" name="top"></nut-icon>
</slot>
......@@ -15,121 +7,168 @@
</template>
<script lang="ts">
import { computed, ref, onMounted, onUnmounted } from 'vue';
import {
computed,
onMounted,
onUnmounted,
onActivated,
onDeactivated,
reactive
} from 'vue';
import { createComponent } from '@/utils/create';
const { create } = createComponent('backtop');
const { componentName, create } = createComponent('backtop');
export default create({
props: {
//距离页面底部
bottom: {
type: Number,
default: 20
},
//距离页面右侧
right: {
type: Number,
default: 10
},
///获取容器ID
elId: {
type: String,
default: ''
},
//页面垂直滚动多高后出现
distance: {
type: Number,
default: 200
},
//设置层级
zIndex: {
type: Number,
default: 1111
default: 10
},
isAnimation: {
type: Boolean,
default: true
},
duration: {
type: Number,
default: 1000
}
},
emits: ['click'],
setup(props, { emit }) {
const styleBottom = computed(() => `${props.bottom}px`);
const styleRight = computed(() => `${props.right}px`);
// const styleDistance = computed(() => `${props.distance}px`);
const zIndex = computed(() => `${props.zIndex}px`);
//默认图标不出现
const backTop = ref(false);
const state = reactive({
backTop: false,
scrollTop: 0,
scrollEl: window as HTMLElement | Window,
startTime: 0,
keepAlive: false
});
let scrollEl: Window | HTMLElement = window;
const elId = ref(props.elId);
const classes = computed(() => {
const prefixCls = componentName;
return {
[prefixCls]: true,
show: state.backTop
};
});
const style = computed(() => {
return {
right: `${props.bottom}px`,
bottom: `${props.right}px`,
zIndex: props.zIndex
};
});
function scrollListener() {
//滚动条偏移量
//Window
if (scrollEl instanceof Window) {
const scrollTop =
scrollEl.pageYOffset !== undefined ? scrollEl.pageYOffset : '';
backTop.value = scrollTop >= props.distance;
//DOM
} else if (scrollEl instanceof HTMLElement) {
const scrollTop = scrollEl.scrollTop;
backTop.value = scrollTop >= props.distance;
if (state.scrollEl instanceof Window) {
state.scrollTop = state.scrollEl.pageYOffset;
} else {
state.scrollTop = state.scrollEl.scrollTop;
}
state.backTop = state.scrollTop >= props.distance;
}
//点击按钮返回顶部
function scroll(y = 0) {
if (scrollEl instanceof Window) {
if (state.scrollEl instanceof Window) {
window.scrollTo(0, y);
} else if (scrollEl instanceof HTMLElement) {
scrollEl.scrollTop = y;
} else {
state.scrollEl.scrollTop = y;
}
}
//监听页面滚动事件
function scrollAnimation() {
let cid = requestAniFrame()(function fn() {
var t =
props.duration -
Math.max(0, state.startTime - +new Date() + props.duration);
var y = (t * -state.scrollTop) / props.duration + state.scrollTop;
scroll(y);
cid = requestAniFrame()(fn);
if (t == props.duration || y == 0) {
window.cancelAnimationFrame(cid);
}
});
}
function addEventListener() {
scrollEl.addEventListener('scroll', scrollListener, true);
state.scrollEl.addEventListener('scroll', scrollListener, false);
state.scrollEl.addEventListener('resize', scrollListener, false);
}
//解绑监听页面滚动事件
function removeEventListener() {
scrollEl.removeEventListener('scroll', scrollListener, true);
state.scrollEl.removeEventListener('scroll', scrollListener, false);
state.scrollEl.removeEventListener('resize', scrollListener, false);
}
// function deactivated() {
// keepAlive.value = true;
// removeEventListener();
// }
onUnmounted(() => {
removeEventListener();
});
function initCancelAniFrame() {
window.cancelAnimationFrame = window.webkitCancelAnimationFrame;
}
//点击回到顶部
function click() {
scroll();
emit('click');
function requestAniFrame() {
return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
}
);
}
function init() {
//重新获取容器id
const _scrollEl = document.getElementById(elId.value);
function click(e: MouseEvent) {
state.startTime = +new Date();
props.isAnimation && props.duration > 0 ? scrollAnimation() : scroll();
emit('click', e);
}
if (elId.value && _scrollEl) {
scrollEl = _scrollEl;
_scrollEl.style.scrollBehavior = 'smooth';
function init() {
if (props.elId && document.getElementById(props.elId)) {
state.scrollEl = document.getElementById(props.elId) as
| HTMLElement
| Window;
}
addEventListener();
scrollListener();
initCancelAniFrame();
}
onMounted(() => {
init();
});
onUnmounted(() => {
removeEventListener();
});
onActivated(() => {
if (state.keepAlive) {
state.keepAlive = false;
init();
}
});
onDeactivated(() => {
state.keepAlive = true;
removeEventListener();
});
return {
backTop,
scrollEl,
click,
styleBottom,
styleRight,
zIndex
state,
classes,
style,
click
};
}
});
......
......@@ -145,6 +145,9 @@ $avatar-normal-height: 40px;
$switch-close-bg-color: #ebebeb;
$switch-close--cline-bg-color: #f0f0f0;
//backtop
$backtop-border-color: #e0e0e0;
// calendar
$calendar-primary-color: $primary-color;
$calendar-choose-color: #fef6f6;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册