feat:初版实现基础功能,返回顶部,固定按钮,自定义内容,特定容器内部显示
This commit is contained in:
		
							parent
							
								
									eb296766f8
								
							
						
					
					
						commit
						91ccfc58bb
					
				
							
								
								
									
										170
									
								
								example/docs/zh-CN/components/backtop.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								example/docs/zh-CN/components/backtop.md
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,170 @@
 | 
			
		||||
::: title 基础使用
 | 
			
		||||
 | 
			
		||||
###### 回到顶部组件的默认样式,通过滑动来查看页面右下角的按钮。
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
::: demo
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <Lay-backtop target=".layui-body"></Lay-backtop>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { ref } from 'vue'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  setup() {
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
:::title 自定义
 | 
			
		||||
 | 
			
		||||
###### 回到顶部组件可自定义样式,限制宽高:50px \* 50px,<code>showHeight = 0</code> 将始终显示,<code>disabled</code> 属性可以禁用返回顶部效果。查看页面右下角的圆形按钮。
 | 
			
		||||
 | 
			
		||||
::: demo
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <Lay-backtop target=".layui-body" :showHeight="0" :bottom="100"  @click="handlerClick" disabled style="background-color:#FFFFFF">
 | 
			
		||||
    <div style="
 | 
			
		||||
        width:50px;
 | 
			
		||||
        height:50px;
 | 
			
		||||
        background-color: #5FB878;
 | 
			
		||||
        color: #FFFFFF;
 | 
			
		||||
        text-align: center;
 | 
			
		||||
        border-radius:50%">
 | 
			
		||||
        <lay-icon type="layui-icon-dialogue" size="30px"></lay-icon>
 | 
			
		||||
    </div>
 | 
			
		||||
  </Lay-backtop>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { ref } from 'vue'
 | 
			
		||||
import { layer } from "../../../../src/index.ts"
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  setup() {
 | 
			
		||||
    const handlerClick = () => {
 | 
			
		||||
      layer.confirm("layui-vue 1.0.0 已经发布");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      handlerClick,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
::: title 滚动容器
 | 
			
		||||
 | 
			
		||||
###### 通过设置 <code>target</code> 和 <code>position="absolute"</code>参数 ,可对特定容器进行返回顶部操作
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
::: demo
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
<!-- 需要用一个 div 包裹滚动容器和 Lay-backtop 组件 -->
 | 
			
		||||
<div style="width:700px; height:300px;">
 | 
			
		||||
  <div id="scrollContainer" style="overflow-y:auto; overflow-x:auto; width:700px; height:300px;">
 | 
			
		||||
    <p v-for="(n,index) in 50" :key="n" style="height:40px;border-bottom:0.5px solid #5FB878;margin-bottom:10px;line-height:40px">
 | 
			
		||||
      {{index + ".  layui-vue , 基 于 vue 3.0 的 桌 面 端 组 件 库 , layui 的 另 一 种 呈 现 方 式"}}
 | 
			
		||||
    </p>
 | 
			
		||||
  </div>
 | 
			
		||||
  <Lay-backtop target="#scrollContainer" :showHeight="100" :bottom="30" position="absolute"></Lay-backtop>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { ref } from 'vue'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  setup() {
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
::: title 结合 tooltip 组件使用
 | 
			
		||||
 | 
			
		||||
###### 可以和 lay-tooltip 组件搭配使用
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
::: demo
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
<!-- 需要用一个 div 包裹滚动容器和 Lay-backtop 组件 -->
 | 
			
		||||
<div style="width:700px; height:300px;">
 | 
			
		||||
  <div id="scrollContainer2" style="overflow-y:auto; overflow-x:auto; width:700px; height:300px;">
 | 
			
		||||
    <p v-for="(n,index) in 50" :key="n" style="height:40px;border-bottom:0.5px solid #5FB878;margin-bottom:10px;line-height:40px">
 | 
			
		||||
      {{index + ".  layui-vue , 基 于 vue 3.0 的 桌 面 端 组 件 库 , layui 的 另 一 种 呈 现 方 式"}}
 | 
			
		||||
    </p>
 | 
			
		||||
  </div>
 | 
			
		||||
  <lay-tooltip content="backtop" position="left">
 | 
			
		||||
    <Lay-backtop target="#scrollContainer2" :showHeight="100" :bottom="30" position="absolute" style="border-radius: 50%;background-color: #5FB878;"></Lay-backtop>
 | 
			
		||||
  </lay-tooltip>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { ref } from 'vue'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  setup() {
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
::: title 属性
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
::: table
 | 
			
		||||
 | 
			
		||||
| 属性       | 说明                                                 | 类型    | 可选值                   |
 | 
			
		||||
| ---------- | --------------------------------------------------- | ------- | ------------------------ |
 | 
			
		||||
| target     | 可选,触发滚动的对象                                | string  | 元素选择器 \| window(默认) |
 | 
			
		||||
| showHeight | 可选,滚动高度达到该值后显示回到顶部按钮             | number  | 200(默认)                |
 | 
			
		||||
| position   | 可选,定位方式,特定容器内部需设置为 absolute        | string  | absolute \| fixed(默认)  |
 | 
			
		||||
| right      | 可选,按钮距离页面右边距,单位 px                   | number  | 30(默认)                 |
 | 
			
		||||
| bottom     | 可选,按钮距离页面底部位置,单位 px                 | number  | 40(默认)                 |
 | 
			
		||||
| bgcolor    | 可选,背景颜色                                     | string  | \#9F9F9F(默认)           |
 | 
			
		||||
| disabled   | 可选,禁用点击返回顶部                             | boolean | true \| false(默认)      |
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
::: title 事件
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
::: table
 | 
			
		||||
 | 
			
		||||
| 事件名 | 说明                      | 回调参数 |
 | 
			
		||||
| ------ | ------------------------- | -------- |
 | 
			
		||||
| click  | 点击回到顶部按钮的回调函数 | event    |
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
::: title 插槽
 | 
			
		||||
:::
 | 
			
		||||
 | 
			
		||||
::: table
 | 
			
		||||
 | 
			
		||||
| 插槽名 | 说明              |
 | 
			
		||||
| ------ | ------------------ |
 | 
			
		||||
| —      | 自定义内容 |
 | 
			
		||||
 | 
			
		||||
:::
 | 
			
		||||
@ -327,6 +327,11 @@ export default {
 | 
			
		||||
        title: '文字提示',
 | 
			
		||||
        subTitle: 'tooltip',
 | 
			
		||||
        path: '/zh-CN/components/tooltip',
 | 
			
		||||
      }, {
 | 
			
		||||
        id: 42,
 | 
			
		||||
        title: '返回顶部',
 | 
			
		||||
        subTitle: 'backtop',
 | 
			
		||||
        path: '/zh-CN/components/backtop',
 | 
			
		||||
      },
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -299,6 +299,10 @@ const zhCN = [
 | 
			
		||||
            path: '/zh-CN/components/msg',
 | 
			
		||||
            component: () => import('../../docs/zh-CN/components/msg.md'),
 | 
			
		||||
            meta: { title: '信息' },
 | 
			
		||||
          },{
 | 
			
		||||
            path: '/zh-CN/components/backtop',
 | 
			
		||||
            component: () => import('../../docs/zh-CN/components/backtop.md'),
 | 
			
		||||
            meta: { title: '返回顶部' },
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
 | 
			
		||||
@ -158,6 +158,12 @@ export default {
 | 
			
		||||
            subTitle: 'dropdown',
 | 
			
		||||
            path: '/zh-CN/components/dropdown',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            id: 42,
 | 
			
		||||
            title: '返回顶部',
 | 
			
		||||
            subTitle: 'backtop',
 | 
			
		||||
            path: '/zh-CN/components/backtop',
 | 
			
		||||
          },
 | 
			
		||||
        ],
 | 
			
		||||
      },
 | 
			
		||||
      {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								src/module/backTop/index.less
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/module/backTop/index.less
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
			
		||||
/** backtop **/
 | 
			
		||||
.lay-backtop {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  right: 15px;
 | 
			
		||||
  bottom: 15px;
 | 
			
		||||
  z-index: 999999;
 | 
			
		||||
  width: 50px;
 | 
			
		||||
  height: 50px;
 | 
			
		||||
  line-height: 50px;
 | 
			
		||||
  margin-bottom: 1px;
 | 
			
		||||
  text-align: center;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  font-size: 40px;
 | 
			
		||||
  background-color: #9f9f9f;
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  border-radius: 2px;
 | 
			
		||||
  opacity: 0.95;
 | 
			
		||||
  :hover {
 | 
			
		||||
    opacity: 0.85;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,14 +1,119 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <ul class="layui-fixbar">
 | 
			
		||||
    <li class="layui-icon layui-fixbar-top" style="display: list-item"></li>
 | 
			
		||||
  </ul>
 | 
			
		||||
  <div
 | 
			
		||||
    v-show="visible"
 | 
			
		||||
    ref="backtopRef"
 | 
			
		||||
    class="lay-backtop"
 | 
			
		||||
    :style="{
 | 
			
		||||
      right: `${props.right}px`,
 | 
			
		||||
      bottom: `${props.bottom}px`,
 | 
			
		||||
      backgroundColor: `${props.bgcolor}`
 | 
			
		||||
    }"
 | 
			
		||||
    @click.stop="handleClick"
 | 
			
		||||
  >
 | 
			
		||||
    <slot>
 | 
			
		||||
      <lay-icon type="layui-icon-top" size="40px"></lay-icon>
 | 
			
		||||
    </slot>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
export default {
 | 
			
		||||
    name: "LayBacktop"
 | 
			
		||||
}
 | 
			
		||||
  name: 'LayBacktop',
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<script lang="ts" setup>
 | 
			
		||||
import { defineProps, defineEmits, ref, shallowRef, withDefaults, computed, onMounted, } from 'vue';
 | 
			
		||||
import layIcon from '../icon/index';
 | 
			
		||||
import './index.less';
 | 
			
		||||
 | 
			
		||||
export interface LayBacktopProps {
 | 
			
		||||
  target?: string; // 触发滚动的对象
 | 
			
		||||
  showHeight?: number;
 | 
			
		||||
  position?: 'fixed' | 'absolute';  // 定位方式,显示在特定容器内部需要设置为 absolute
 | 
			
		||||
  right?: number;
 | 
			
		||||
  bottom?: number;
 | 
			
		||||
  bgcolor?: string;
 | 
			
		||||
  disabled?: boolean; // 禁用返回顶部
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const props = withDefaults(defineProps<LayBacktopProps>(), {
 | 
			
		||||
  target: 'window',
 | 
			
		||||
  showHeight: 200,
 | 
			
		||||
  position: 'fixed',
 | 
			
		||||
  right: 30,
 | 
			
		||||
  bottom: 40,
 | 
			
		||||
  bgcolor: '#9F9F9F',
 | 
			
		||||
  disabled: false,
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const emit = defineEmits(['click']);
 | 
			
		||||
 | 
			
		||||
let visible = ref(props.showHeight === 0);
 | 
			
		||||
const backtopRef = ref<HTMLElement | null>(null);
 | 
			
		||||
const scrollTarget = shallowRef<Window | HTMLElement | undefined>(undefined);
 | 
			
		||||
 | 
			
		||||
const scrollToTop = () => {
 | 
			
		||||
  if (!scrollTarget.value) return;
 | 
			
		||||
  if (scrollTarget.value instanceof Window) {
 | 
			
		||||
    window.scrollTo({
 | 
			
		||||
      top: 0,
 | 
			
		||||
      left: 0,
 | 
			
		||||
      behavior: 'smooth' //smooth(平滑滚动),instant(瞬间滚动),默认instant
 | 
			
		||||
    });
 | 
			
		||||
  } else {
 | 
			
		||||
    // FIXME 初版待改进
 | 
			
		||||
    let step = scrollTarget.value.scrollTop / 4;
 | 
			
		||||
    if (scrollTarget.value.scrollTop > 0) {
 | 
			
		||||
      scrollTarget.value.scrollTop -= Math.max(step, 10);
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        scrollToTop();
 | 
			
		||||
      }, 1000 / 60);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const handleScroll = () => {
 | 
			
		||||
  if (!scrollTarget.value) return;
 | 
			
		||||
  const scrollTop = scrollTarget.value instanceof Window ? window.pageYOffset : scrollTarget.value.scrollTop;
 | 
			
		||||
  visible.value = scrollTop >= props.showHeight;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const handleClick = (event: MouseEvent) => {
 | 
			
		||||
  if (!props.disabled) {
 | 
			
		||||
    scrollToTop()
 | 
			
		||||
  };
 | 
			
		||||
  emit('click', event);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 获取滚动目标元素
 | 
			
		||||
const getScrollTarget = () => {
 | 
			
		||||
  if (props.target === 'window') {
 | 
			
		||||
    return window || document.documentElement || document.body;
 | 
			
		||||
  } else {
 | 
			
		||||
    const targetElement = document.querySelector<HTMLElement>(props.target);
 | 
			
		||||
    if (!targetElement) throw new Error(`target is not existed: ${props.target}`);
 | 
			
		||||
    // 特定容器内部显示
 | 
			
		||||
    if (props.position === 'absolute') {
 | 
			
		||||
      if (!targetElement.parentElement) throw new Error(`target parent element is not existed: ${props.target}`);
 | 
			
		||||
      targetElement.parentElement.style.position = 'relative';
 | 
			
		||||
      console.log(backtopRef.value);
 | 
			
		||||
      if (!backtopRef.value) throw new Error(`target ref is null: ${props.target}`);
 | 
			
		||||
      backtopRef.value.style.position = props.position;
 | 
			
		||||
    }
 | 
			
		||||
    return targetElement;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
  let timer: any = undefined;
 | 
			
		||||
  scrollTarget.value = getScrollTarget();
 | 
			
		||||
  // FIXME 节流待改进
 | 
			
		||||
  scrollTarget.value.addEventListener('scroll', () => {
 | 
			
		||||
    clearTimeout(timer);
 | 
			
		||||
    timer = setTimeout(() => {
 | 
			
		||||
      handleScroll();
 | 
			
		||||
    }, 100);
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user