大家好,欢迎来到IT知识分享网。
今天给大家分享一个最新开发的Vue3自定义模拟滚动条组件v3scroll。
V3Scroll 基于vue3.0开发的轻量级PC端虚拟滚动条组件。支持是否自动隐藏、自定义大小、颜色及层叠等功能。
开发灵感来自于之前的vue2版自定义滚动条组件。借鉴了ElementPlus滚动条设计。
vue2.x自定义桌面端滚动条组件
v3scroll同样支持垂直/水平滚动条。并且在功能效果上和之前vue2版保持一致。
通过简单的<v3-scroll></v3-scroll>裹住内容块,即可快速生成一个精致的仿原生滚动条。
引入组件
在main.js中整体引入组件。
import { createApp } from 'vue' import App from './App.vue' import './index.css' // 引入滚动条组件v3scroll import V3Scroll from './components/v3scroll' createApp(App).use(V3Scroll).mount('#app')
快速使用
<v3-scroll :native="true"> <img src="https://cn.vuejs.org/images/logo.png" style="max-width:100%;" /> <p>这里是内容信息!这里是内容信息!这里是内容信息!这里是内容信息!</p> </v3-scroll>
<v3-scroll size="12px"> <img src="https://cn.vuejs.org/images/logo.png" style="height:180px" /> <img src="https://cn.vuejs.org/images/logo.png" style="height:180px" /> <p>这里是内容信息!这里是内容信息!这里是内容信息!这里是内容信息!</p> </v3-scroll>
编码实现
- 参数配置
props: { // 是否显示原生滚动条 native: Boolean, // 是否自动隐藏滚动条 autohide: Boolean, // 滚动条尺寸 size: { type: [Number, String], default: '' }, // 滚动条颜色 color: String, // 滚动条层级 zIndex: null },
- v3scroll组件模板
<template> <div class="vui__scrollbar" ref="ref__box" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave" v-resize="handleResize"> <div :class="['vscroll__wrap', {native: native}]" ref="ref__wrap" @scroll="handleScroll"> <div class="vscroll__view" v-resize="handleResize"> <slot /> </div> </div> <!-- //滚动条 --> <div :class="['vscroll__bar vertical', {ishide: !isShow}]" @mousedown="handleClickTrack($event, 0)"> <div class="vscroll__thumb" ref="ref__barY" @mousedown="handleDragThumb($event, 0)"></div> </div> <div :class="['vscroll__bar horizontal', {ishide: !isShow}]" @mousedown="handleClickTrack($event, 1)"> <div class="vscroll__thumb" ref="ref__barX" @mousedown="handleDragThumb($event, 1)"></div> </div> </div> </template>
- v3scroll逻辑处理
<script> import { onMounted, ref, reactive, toRefs, nextTick } from 'vue' export default { props: { // ... }, /** * Vue3.x写法 */ // 监听DOM尺寸变化 directives: { 'resize': { beforeMount: function(el, binding) { let width = '', height = ''; function get() { const elStyle = el.currentStyle ? el.currentStyle : document.defaultView.getComputedStyle(el, null); if (width !== elStyle.width || height !== elStyle.height) {binding.value({width, height}); } width = elStyle.width; height = elStyle.height; } el.__vueReize__ = setInterval(get, 16) }, unmounted: function(el) {clearInterval(el.__vueReize__)} } }, setup(props, context) { const ref__box = ref(null) const ref__wrap = ref(null) const ref__barX = ref(null) const ref__barY = ref(null) const data = reactive({ barWidth: 0, barHeight: 0, ratioX: 1, ratioY: 1, isTaped: false, isHover: false, isShow: !props.autohide, }) // 鼠标滑入 const handleMouseEnter = () => { data.isHover = true data.isShow = true updated() } // 鼠标滑出 const handleMouseLeave = () => { data.isHover = false if(!data.isTaped && props.autohide) { data.isShow = false } } // 拖动滚动条 const handleDragThumb = (e, index) => { const elWrap = ref__wrap.value const elBarX = ref__barX.value const elBarY = ref__barY.value data.isTaped = true let c = {} // 阻止默认事件 domUtils.isIE() ? (e.returnValue = false, e.cancelBubble = true) : (e.stopPropagation(), e.preventDefault()) document.onselectstart = () => false if(index == 0) { c.dragY = true c.clientY = e.clientY }else { c.dragX = true c.clientX = e.clientX } // ... } // 点击滚动槽 const handleClickTrack = (e, index) => { // ... } // 更新滚动区 const updated = () => { if(props.native) return const elBox = ref__box.value const elWrap = ref__wrap.value const elBarX = ref__barX.value const elBarY = ref__barY.value let barSize = domUtils.getScrollBarSize() // 垂直滚动条 if(elWrap.scrollHeight > elWrap.offsetHeight) { data.barHeight = elBox.offsetHeight **2 / elWrap.scrollHeight data.ratioY = (elWrap.scrollHeight - elBox.offsetHeight) / (elBox.offsetHeight - data.barHeight) elBarY.style.transform = `translateY(${elWrap.scrollTop / data.ratioY}px)` }else { data.barHeight = 0 elBarY.style.transform = '' elWrap.style.marginRight = '' } // 水平滚动条 // ... } // 滚动区元素/DOM尺寸改变 const handleResize = () => { updated() } // 鼠标滚动 const handleScroll = (e) => { context.emit('scroll', e) updated() } const scrollTo = (dir) => { const elWrap = ref__wrap.value const elBarY = ref__barY.value nextTick(() => { elWrap.scrollTop = (dir == 'top') ? 0 : (dir == 'bottom') ? elWrap.scrollHeight : parseInt(dir) elBarY.style.transform = `translateY(${elWrap.scrollTop / data.ratioY}px)` }) } return { ...toRefs(data), ref__box, ref__wrap, ref__barX, ref__barY, handleMouseEnter, handleMouseLeave, handleDragThumb, handleClickTrack, updated, handleResize, handleScroll, scrollTo, } } } </script>
<v3-scroll @scroll="handleScroll"> <p><img src="https://cn.vuejs.org/images/logo.png" style="height:250px;" /></p> <p>这里是内容信息!这里是内容信息!这里是内容信息!这里是内容信息!这里是内容信息!</p> </v3-scroll> setup() { // 监听滚动事件 const handleScroll = (e) => { data.scrollTop = e.target.scrollTop // 判断滚动状态 if(e.target.scrollTop == 0) { data.scrollStatus = '到达顶部' } else if(e.target.scrollTop + e.target.offsetHeight >= e.target.scrollHeight) { data.scrollStatus = '到达底部' }else { data.scrollStatus = '滚动中....' } } // ... }
好了,基于vue3.0实现pc端模拟滚动条就分享到这里。感谢大家的阅读!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/54522.html