前段時間有給大家分享兩個svelte3.x系列元件。今天繼續分享一個最新寫的svelte3-scrollbar
虛擬美化系統滾動條元件。
svelte-layer:一款svelte3.x輕量級PC端彈窗元件
svelte-popup:一款svelte3.x移動端彈層元件
svelte-scrollbar 一款輕量級網頁自定義美化系統滾動條元件。支援原生滾動條、自動隱藏、垂直+水平滾動、自定義滾動條大小/顏色/間隙
等功能。
在lib目錄下新建一個Scrollbar元件。
引入元件
在需要用到滾動條功能的頁面引入外掛。
import Scrollbar from '$lib/Scrollbar'
快速呼叫
通過如下方式呼叫,即可快速生成一個虛擬化滾動條。
<!-- //原生滾動條 -->
<Scrollbar native>
<div>自定義內容資訊。</div>
</Scrollbar>
<!-- //自動隱藏 -->
<Scrollbar autohide={true}>
<div>自定義內容資訊。</div>
</Scrollbar>
<!-- //水平滾動(支援滾輪滑動) -->
<Scrollbar mousewheel>
<div>自定義內容資訊。</div>
</Scrollbar>
<!-- //自定義高度/最大高度 -->
<Scrollbar height="200" maxHeight="350">
<div>自定義內容資訊。</div>
</Scrollbar>
<!-- //自定義大小/間隙/顏色 -->
<Scrollbar size="10px" gap="5" color="#09f">
<div>自定義內容資訊。</div>
</Scrollbar>
引數配置
svelte-scrollbar支援如下引數配置。
<script>
// 是否開啟原生滾動條
export let native = false
// 是否自動隱藏滾動條
export let autohide = false
// 滾動條尺寸
export let size = undefined
// 滾動條顏色
export let color = ''
// 滾動條層疊
export let zIndex = null
// 滾動條區域高度
export let height = undefined
// 滾動條區域最大高度
export let maxHeight = undefined
// 滾動條間隙
export let gap = 0
// 是否開啟水平滾輪滾動控制
export let mousewheel = false
...
</script>
模板及邏輯部分
<div class="vui__scrollbar" bind:this={el} on:mouseenter={handleMouseEnter} on:mouseleave={handleMouseLeave}>
<div class="vscroll__wrap" class:hidenative={!bool(native)} bind:this={wrap} on:scroll={handleScroll} on:mousewheel={handleMouseWheel} style="{wrapStyle}">
<slot />
</div>
<div class="vscroll__bar vertical" class:ishide={!data.isShowBar} on:mousedown={e => handleClickTrack(e, 0)} >
<div class="vscroll__thumb" bind:this={barY} style="background: {color}; height: {data.barHeight}px; width: {addUnit(size)}" on:mousedown={e => handleDragThumb(e, 0)}></div>
</div>
<div class="vscroll__bar horizontal" class:ishide={!data.isShowBar} on:mousedown={e => handleClickTrack(e, 1)}>
<div class="vscroll__thumb" bind:this={barX} style="background: {color}; width: {data.barWidth}px; height: {addUnit(size)}" on:mousedown={e => handleDragThumb(e, 1)}></div>
</div>
</div>
<script>
/**
* @Desc svelte3虛擬滾動條元件svelte-scrollbar
* @Time andy by 2022-05
* @About Q:282310962 wx:xy190310
*/
// ...
import { onMount, afterUpdate, createEventDispatcher, tick } from 'svelte'
const dispatch = createEventDispatcher()
import util from './util'
$: data = {
// 滾動條寬度
barWidth: 0,
// 滾動條高度
barHeight: 0,
// 滾動條水平偏移率
ratioX: 1,
// 滾動條垂直偏移率
ratioY: 1,
// 滑鼠是否按住滾動條
isTaped: false,
// 滑鼠是否懸停於滾動區域
isHover: false,
// 顯示滾動條
isShowBar: !bool(autohide)
}
const bool = (boolean) => JSON.parse(boolean) ? true : false
const addUnit = (val) => val ? parseInt(val) + 'px' : null
let observeTimer = null
let c = {}
// 滾動條物件
let el
let wrap
let barX
let barY
$: wrapStyle = `height: ${addUnit(height)}; max-height: ${addUnit(maxHeight)}`
$: GAP = addUnit(gap)
onMount(() => {
console.log('監聽滾動條開啟...')
updated()
let observer = new MutationObserver(mutation => {
updated()
})
observer.observe(wrap, {
attributes: true,
childList: true,
subtree: true,
attributeFilter: [
'style', 'class'
]
})
window.addEventListener('resize', util.throttle(updated))
return () => {
observer.disconnect()
window.removeEventListener('resize', updated)
console.log('監聽滾動條關閉...')
}
})
afterUpdate(() => {
// console.log('監聽dom更新...')
})
// 滑鼠滑入
function handleMouseEnter() {
data.isHover = true
data.isShowBar = true
updated()
}
// 滑鼠滑出
function handleMouseLeave() {
data.isHover = false
if(!data.isTaped && bool(autohide)) {
data.isShowBar = false
}
}
// 拖動滾動條
function handleDragThumb(e, index) {
// ...
}
// 點選滾動條插槽
function handleClickTrack(e, index) {
if(index == 0) {
wrap.scrollTop = (Math.abs(e.target.getBoundingClientRect().top - e.clientY) - barY.offsetHeight / 2) * data.ratioY
barY.style.transform = `translateY(${wrap.scrollTop / data.ratioY}px)`
}else {
wrap.scrollLeft = (Math.abs(e.target.getBoundingClientRect().left - e.clientX) - barX.offsetWidth / 2) * data.ratioX
barX.style.transform = `translateX(${wrap.scrollLeft / data.ratioX}px)`
}
}
// 更新滾動區
async function updated() {
// ...
}
// 滑鼠滾動事件
function handleScroll(e) {
let target = e.target
let status
if(target.scrollTop == 0) {
status = 'top' // 滾動至頂部
}else if(target.scrollTop + target.offsetHeight >= target.scrollHeight) {
status = 'bottom' // 滾動至底部
}
/**
* 父元件呼叫 const { target, status, scrollTop, scrollLeft } = e.detail
*/
dispatch('scroll', {
target, // 滾動物件
status, // 滾動狀態(記錄滾動位置)
scrollTop: target.scrollTop,
scrollLeft: target.scrollLeft
})
updated()
}
// 控制滾輪水平滾動
function handleMouseWheel(e) {
if(!bool(mousewheel)) return
e.preventDefault()
if(wrap.scrollWidth > wrap.offsetWidth) {
wrap.scrollLeft += e.deltaY
}
}
// 滾動到一組特定座標
export async function scrollTo(arg1, arg2) {
await tick()
if(typeof arg1 == 'object') {
wrap.scrollTo(arg1)
}else if(!isNaN(arg1) && !isNaN(arg2)) {
wrap.scrollTo(arg1, arg2)
}
}
// 設定滾動條到頂部的距離
export async function setScrollTop(value) {
await tick()
wrap.scrollTop = value == 'top' ? 0 : value == 'bottom' ? wrap.scrollHeight : parseInt(value)
barY.style.transform = `translateY(${wrap.scrollTop / data.ratioY}px)`
}
// 設定滾動條到左邊的距離
export async function setScrollLeft(value) {
await tick()
wrap.scrollLeft = value == 'left' ? 0 : value == 'right' ? wrap.scrollWidth : parseInt(value)
barX.style.transform = `translateX(${wrap.scrollLeft / data.ratioX}px)`
}
</script>
<style>
@import 'Scrollbar.scss';
</style>
另外還支援動態監聽scroll事件。
<Scrollbar on:scroll={handleScroll}>
<div>自定義內容資訊。</div>
</Scrollbar>
<script>
// 監聽滾動事件
function handleScroll(e) {
const { target, status, scrollTop, scrollLeft } = e.detail
scrollTopVal = scrollTop
scrollLeftVal = scrollLeft
// 判斷滾動狀態(方法1)
/*if(scrollTop == 0) {
scrollStatus = '滾動至頂部'
}else if(scrollTop + target.offsetHeight >= target.scrollHeight) {
scrollStatus = '滾動底部'
}else {
scrollStatus = '滾動中'
}*/
// // 判斷滾動狀態(方法2)
if(status == 'top') {
scrollStatus = '滾動至頂部'
}else if(status == 'bottom') {
scrollStatus = '滾動底部'
}else {
scrollStatus = '滾動中'
}
}
</script>
OK,以上就是svelte.js自定義系統美化滾動條元件的分享。後續還會分享一個svelte桌面端例項專案。
最後附上一個svelte3聊天實戰專案
svelte-chat基於svelte3.x仿微信APP聊天專案
目前svelte.js穩定性還可以,生態也逐步完善,期待更多的開發小夥伴一起參與進來。