這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 界面無滾動條 滾動條的優化也有很多種,比如隨便再網上搜索美化瀏覽器滾動條樣式,就會出現些用css去美化滾動條的方案。 那種更好呢? 沒有更好只有更合適 像預設的滾動條的話,他能讓你方便摁著往下滑動(他比較寬)特別省勁,不用擔心美化過後變細 ...
這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
界面無滾動條
滾動條的優化也有很多種,比如隨便再網上搜索美化瀏覽器滾動條樣式
,就會出現些用css
去美化滾動條的方案。
那種更好呢?
沒有更好只有更合適
- 像預設的滾動條的話,他能讓你方便摁著往下滑動(他比較寬)特別省勁,不用擔心美化過後變細摁不到問題。
- 美化後的滾動條樣式啊更貼合網站主題,讓用戶體驗更好。
- 無滾動條(滑鼠放上去後出現)這種更適合像一個頁面好多個塊,每個塊的話還很多內容(都有滾動條)。如果像這種都預設都出現滾動條的話,也太不美觀了。
那咱們就從無滾動條展開說說!!!
無滾動條設計
比如像
element ui
組件內像input
的自定義模塊數據過多的時候出現的下拉框內的滾動條,如下圖:
在element-ui
裡面它其實是有內部組件el-scrollbar在的。那麼它是怎麼實現無滾動條呢?
如下圖咱們先把:hover
勾選上讓滾動條一直處於顯示得狀態。然後咱們再分析他的實現。
當我把樣式稍微修改下,咱們再觀察下圖:
這麼看是不是就很明白了 他其實用margin
值把整個容器擴大了點然後溢出隱藏,其實滾動條還在就是給界面上看不到了而已。
然後它自己用dom
畫了個滾動條,如下圖:
經過上面分析,咱們已經很清楚得瞭解到一個無滾動條是從那個方面實現得了。
- 使用
margin
值把滾動條給溢出隱藏掉。- 使用
div
自己畫了一個滾動條。方便咱們隱藏、顯示、更改樣式等。
無滾動條實現
那咱們再從細節上拆分下具體實現要考慮那些點:
- 需要計算滾動條得寬度用來
margin
擴大得距離(每個界面上得滾動條得寬度是不一樣得)。 - 需要計算畫的
div
滾動條得高度(這個內容多少會影響滾動條的高度)。 - 需要根據滾動條去
transform: translateY(19.3916%);
移動咱們自己畫的div
滾動條的。 - 需要根據摁著畫的
div
滾動條,去實際更改需要滾動的高度。 - 需要點擊滾動軸的柱子支持跳到目標的滾動位置;
一 計算界面原本滾動條的寬度
計算下界面上原本滾動條的寬度如下:
let scrollBarWidth; export default function() { if (scrollBarWidth !== undefined) return scrollBarWidth; const outer = document.createElement('div'); outer.className = 'el-scrollbar__wrap'; outer.style.visibility = 'hidden'; outer.style.width = '100px'; outer.style.position = 'absolute'; outer.style.top = '-9999px'; document.body.appendChild(outer); const widthNoScroll = outer.offsetWidth; outer.style.overflow = 'scroll'; const inner = document.createElement('div'); inner.style.width = '100%'; outer.appendChild(inner); const widthWithScroll = inner.offsetWidth; outer.parentNode.removeChild(outer); scrollBarWidth = widthNoScroll - widthWithScroll; return scrollBarWidth; };
先創建了一個
div
, 設置成scroll
, 然後再在裡面嵌套一個沒有滾動條的div
設置寬度100%
, 獲取到兩者的offsetWidth
, 相減獲取到scrollBarWidth
。賦值給scrollBarWidth
是惰性載入的優化,只需要計算一次就可以了。 具體展現如下圖:
二 計算畫的滾動條的高度height
計算下畫的
div
滾動條的高度height
。是用當前容器的內部高度 / 容器整個滾動條的高度 * 100計算出百分比;
比如:
const warp = this.$refs.wrap; // 或者使用documnet獲取容器 const heightPercentage = (wrap.clientHeight * 100 / wrap.scrollHeight); // height const widthPercentage = (wrap.clientWidth * 100 / wrap.scrollWidth); // width
解析: 如當前容器高
30px
,內容撐起來總共高100px
,那麼滾動條的高度就是當前容器的30%
;
三 計算滾動條需要移動的值
計算畫的
div
需要滾動條的高度moveY
是, 獲取當前容器滾動的scrollTop
/ 當前容器內部高度 * 100:
演算法一:
解析 使用
transform: translateY(0%);
是移動的是自己本身的百分比那麼(容器滾動的scrollTop
/ 當前容器內部高度 * 100)演算法如下:
const warp = this.$refs.wrap; // 或者使用documnet獲取容器 this.moveY = ((wrap.scrollTop * 100) / wrap.clientHeight); this.moveX = ((wrap.scrollLeft * 100) / wrap.clientWidth);
演算法二:
解析:使用定位
top
值,這個比較好理解滾動條的滾動 / 容器的滾動總高度 * 100得到百分比,如下:
const warp = this.$refs.wrap; // 或者使用documnet獲取容器 this.moveY = ((wrap.scrollTop * 100) / wrap.scrollHeight); this.moveX = ((wrap.scrollLeft * 100) / wrap.scrollWidth);
把計算出來的
moveY
、moveX
的方法 綁定給scroll
滾動事件就可以了。
四 摁著畫的div
滾動條 經行拖動
滾動條都是支持拖著上下左右移動的,那咱們也要支持下:
- 獲取當前滾動條的高度或者寬度可以使用
getBoundingClientRect()
如下圖: - 獲取拖著移動的距離 就是再滑鼠摁下先計一個當前的
x1、y1
監聽move
的x2、y2
相減就是拖動的距離了。 - 獲取到拖動的距離後轉成
transform || top
值。
一個簡單的拖動組件如下:
<template> <div ref="draggableRef" class="draggable" :style="style" > <slot /> </div> </template> <script> export default { name: 'DraggableComponent', props: { initialValue: { type: Object, required: false, default: () => ({ x: 0, y: 0 }), }, }, data() { return { currentValue: { x: 0, y: 0 }, isDragging: false, startX: 0, startY: 0, diffX: 0, diffY: 0, }; }, computed: { style() { return `left: ${this.currentValue.x + this.diffX}px; top: ${this.currentValue.y + this.diffY}px`; }, }, watch: { initialValue: { handler(val) { this.currentValue = val; }, immediate: true, }, }, mounted() { this.$nextTick(() => { const { draggableRef } = this.$refs; if (draggableRef) { draggableRef.addEventListener('mousedown', this.startDrag); document.addEventListener('mousemove', this.moveDrag); document.addEventListener('mouseup', this.endDrag); } }); }, beforeDestroy() { const { draggableRef } = this.$refs; draggableRef.removeEventListener('mousedown', this.startDrag); document.removeEventListener('mousemove', this.moveDrag); document.removeEventListener('mouseup', this.endDrag); }, methods: { startDrag({ clientX: x1, clientY: y1 }) { this.isDragging = true; document.onselectstart = () => false; this.startX = x1; this.startY = y1; }, moveDrag({ clientX: x2, clientY: y2 }) { if (this.isDragging) { this.diffX = x2 - this.startX; this.diffY = y2 - this.startY; } }, endDrag() { this.isDragging = false; document.onselectstart = () => true; this.currentValue.x += this.diffX; this.currentValue.y += this.diffY; this.diffX = 0; this.diffY = 0; }, }, }; </script> <style> .draggable { position: fixed; z-index: 9; } </style>
咱們需要獲取到畫的滾動條的高度,然後根據拖動的距離算出來
transform: translateY(0%);
或者top
值;
如上面拖動組件 拖動部分代碼就不在重覆了 咱們直接用diffX、diffY、lastX、lastY
來用了。
diffX、diffY
是拖動差的值lastX、lastY
是上一次也就是未拖動前的值translateY || top
演算法一(transform)
const thumb = document.querySelector('el-scrollbar__thumb'); // element ui el-scrollbar 的滾動條 const { height: thumbHeight } = thumb?.getBoundingClientRect() || {}; const diffY = 10; const lastY = '300'; // transform: translateY(300%);` const moveY = (diffY / thumbHeight) + lastY;演算法二(top)
const thumb = document.querySelector('el-scrollbar__thumb'); // element ui el-scrollbar 的滾動條 const { height: thumbHeight } = thumb?.getBoundingClientRect() || {}; const diffY = 10; const lastY = 30; // top: 30%` const moveY = (diffY / wrap.scrollWidth * 100) + lastY;
五 點擊滾動軸使滾動條跳轉到該位置
- getBoundingClientRect 的 top 是獲取到距離瀏覽器頂部的距離。 寫一個點擊事件如下
function clickTrackHandler(event) { const wrap = this.$refs.wrap; // 1. 減去clientX 正好能獲取到需要滾動到的位置 const offset = Math.abs(e.target.getBoundingClientRect().top - e.clientX); // 2. 利用offset 的到畫的滾動條的實際位置 兩種演算法transform || top const thumb = document.querySelector('el-scrollbar__thumb'); // element ui el-scrollbar 的滾動條 const { height: thumbHeight } = thumb?.getBoundingClientRect() || {}; const translateY = offset / height * 100; // transform const top = offset / wrap.scrollHeight * 100; // top // 3、計算實際需要滾動的高度 使界面滾動到該位置。兩種演算法transform(scrollTop2) || top(scrollTop1) const scrollTop1 = top * wrap.scrollHeight; // top const scrollTop2 = translateY * wrap.clientHeight; // transform }