La solución definitiva para diseñar una barra de desplazamiento

La solución definitiva para diseñar una barra de desplazamiento

I. Introducción

Hace mucho tiempo que no actualizo el artículo, porque no he encontrado buenos materiales, y el trabajo ha sido entregado recientemente, resumí los proyectos de este año y encontré un problema tan interesante para compartir con ustedes;

dos, fondo

En el proyecto, a menudo nos encontramos con la escena de la barra de desplazamiento, que generalmente aparece en una escena de este tipo. Hay un cuadro afuera, y su propiedad css overflowestá configurada en scrollo auto, y su contenido excede el rango de carga del cuadro, luego el en este momento aparecerá la dirección horizontal o las barras de desplazamiento verticales;

Como se muestra en el siguiente código:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>滚动示例</title>
  <style>
    .container {
      width: 300px;
      height: 500px;
      overflow: auto;
      border: 1px solid #eee;
    }
  </style>
</head>

<body>
  <div class="container">
    <ul class="content"></ul>
  </div>


  <script>
    const content = document.querySelector(".content")
    const fragment = document.createElement("fragment")
    new Array(20).fill(true).forEach((item, i) => { // 设计超出外围盒子的承载范围
      const li = document.createElement("li")
      li.innerHTML = `<h1>${'item' + i}</h1>`
      fragment.appendChild(li)
    })
    content.appendChild(fragment)
  </script>
</body>

</html>

复制代码

Resultados como se muestra a continuación:

Efecto Google Chrome

WechatIMG190.png

efecto de navegador de borde

WechatIMG191.png

efecto navegador safari

截屏2022-04-04 下午1.03.11.png

Podemos sentir claramente las diferencias entre los diferentes navegadores, no solo eso, tomamos Google Chrome como ejemplo, a veces podemos pensar que este estilo de barra de desplazamiento es demasiado feo, parece que queremos ir modificando el estilo;

3. Cómo resolver

Para Google Chrome podemos hacer esto:

/* 将以下样式写在全局 */
::-webkit-scrollbar-track {  /* 滚动条的滑轨背景颜色 */ 
  background-color: #b46868; 
 }
::-webkit-scrollbar-thumb { /* 滑块颜色 */ 
  background-color: rgba(0, 0, 0, 0.2); 
 } 
::-webkit-scrollbar-button { /* 滑轨两头的监听按钮颜色 */
  background-color: #7c2929; 
} 
::-webkit-scrollbar-corner {  /* 横向滚动条和纵向滚动条相交处尖角的颜色 */
  background-color: black; 
}
复制代码

Puedes ver los siguientes efectos:

截屏2022-04-04 下午1.41.41.png

Se puede ver que hemos cambiado con éxito el estilo de la barra de desplazamiento del navegador, y debido a que está escrito globalmente, se cambiará el estilo de todas las barras de desplazamiento en el proyecto;

De hecho, a menudo uso esta forma de personalizar los estilos de la barra de desplazamiento en proyectos reales, pero ¿realmente se resolvió el problema? ¿En realidad no?

Debido a que este estilo solo -webkit-admite navegadores con núcleos, ejecute el mismo proyecto en Firefox o navegadores de borde, ¿qué tal el efecto?

WechatIMG191.png

Se puede ver que la barra de desplazamiento ha cambiado a su apariencia original. Si se trata de un proyecto en una escena de pantalla grande, la estética de la pantalla grande se destruirá directamente, ¡así que debemos encontrar una manera de resolver este problema!

Cinco, meditación

Si es un desarrollador experimentado, no nos cuesta pensar que podemos escribirlo para cada navegador css解决方案;

Aquí ordenaré las propiedades CSS expuestas por diferentes navegadores para las barras de desplazamiento;

es decir, navegador

/* IE 浏览器 */
.scrollbar{
    /*三角箭头的颜色*/
    scrollbar-arrow-color: #fff;
    /*滚动条滑块按钮的颜色*/
    scrollbar-face-color: #0099dd;
    /*滚动条整体颜色*/
    scrollbar-highlight-color: #0099dd;
    /*滚动条阴影*/
    scrollbar-shadow-color: #0099dd;
    /*滚动条轨道颜色*/
    scrollbar-track-color: #0066ff;
    /*滚动条3d亮色阴影边框的外观颜色——左边和上边的阴影色*/
    scrollbar-3dlight-color:#0099dd;
    /*滚动条3d暗色阴影边框的外观颜色——右边和下边的阴影色*/
    scrollbar-darkshadow-color: #0099dd;
    /*滚动条基准颜色*/
    scrollbar-base-color: #0099dd;
}

复制代码

Tanto Google Chrome como Safari son -webkit-内核iguales .

/* 谷歌浏览器和safari浏览器 */
::-webkit-scrollbar-track {  /* 滚动条的滑轨背景颜色 */ 
  background-color: #b46868; 
 }
::-webkit-scrollbar-thumb { /* 滑块颜色 */ 
  background-color: rgba(0, 0, 0, 0.2); 
 } 
::-webkit-scrollbar-button { /* 滑轨两头的监听按钮颜色 */
  background-color: #7c2929; 
} 
::-webkit-scrollbar-corner {  /* 横向滚动条和纵向滚动条相交处尖角的颜色 */
  background-color: black; 
}
复制代码

El autor no ha encontrado una solución para el navegador Firefox por el momento, se dice que el navegador Firefox actual no proporciona tales propiedades css para que los desarrolladores las modifiquen;

对于大部分应用似乎可以通过这种全量css的方法去解决;但是为了用户体验,我们还是希望能够有更好的解决方案;

我并不推荐以上做法的原因是因为滚动条样式在某些浏览器上用户是可以自定义修改的;此外css的方式还是不确定性因素太多,为了保证滚动条在多类浏览器下的统一性,我们还是需要一种稳定、统一、易于维护的方式;

六、绞尽脑汁

在探索的过程中,我在element-ui上找到了思路,我发现element左侧菜单栏的滚动条,无论在什么浏览器下,都能够很好的保持一致性,并且UI样式,交互都很好看;基于此,我点进去看了一下;

截屏2022-04-04 下午2.16.36.png

才发现原来element-ui并非用的浏览器内置的滚动条,而是自己实现了一个滚动条;

确实有一下几点好处:

第一:稳定,无论在任何情况下都可以保持UI的一致性,因为将对内置的滚动条样式的控制,转换为对普通div元素的样式控制,可以保证其更稳定的样式一致性

第二:可控性更强,因为css样式都是自己设计,交互也是自己设计的,无论拓展新的交互都更加容易

第三:更方便维护,对于滚动条,我们很容易想到可以将其封装成一个组件;

当然有优点就有一定的缺点,根据目前我的了解,这种方式依然无法完全依赖于css实现,因此js的消耗代价是其致命弱点

既然element-ui有这样的实现,我想他肯定有这样的组件呀,我只要使用就好了,但是,遗憾的是我并没有在element-ui找到类似的组件实现,因此我想,那就自己实现一个;综合考虑,我选择先封装一个基于vue2的scrollbar的解决方案(因为element-ui就是基于vue2的哈);

七、实现组件

这个组件的目录结构思路如下

|-- scrollbar
|   |-- index.js
|   |-- helper
|   |   |-- calc.js
|   |   |-- event.js
|   |   |-- index.js
|   |-- src
|       |-- index.vue

复制代码

截屏2022-04-04 下午2.51.23.png

其实整个内容还是比较简单的,但是我想分享几个写的过程中,我觉得对大家有帮助的点;

1.如何实现

为了尽可能的利用浏览器滚动的原生特性,我选择将浏览器内置的滚动条,隐藏起来(遮盖住);将我们自己写的滚动条样式暴露在外部;

如下图所示

截屏2022-04-04 下午3.10.50.png

以下将可视区域称为 scrollbox 、实际内容为 contentbox 、滚动条为 scrollbar、

他们应该具备以下关系:

scrollbar的高度 / scrollbox的高度 = scrollbox的高度 / contentbox的高度

scrollbox的scrollTop / contentbox的高度 = scrollbar的top / scrollbox的高度

遵循以上关系,就能完全模拟真实的滚动效果;

2.事件管理

在书写这个组件的时候,我发现我们经常需要书写类似下面的代码


// 在某个时机
element.addEventListener("事件类型" , ()=>{
  // do something ... 
})

// 在某个时机

element.removeEventListener("事件类型" , 原函数引用)

复制代码

这种事件高频的业务场景,尤其是一个事件的监听是在另一个事件触发的回调里这种情况是,管理事件就显得比较消耗心智了,通常情况话,在写代码时总显的力不从心;这个时候,我们其实可以选择写一个保存应用的类,只管注册,而不管取消,最后统一取消,这样的方式会极大的减少我们的心智负担;我们来看一下;

export class ScrollEvent {
  constructor(el) {
    this.el = el;
    this.events = {}
  }

  listen (type, fn) {
    (this.events[type] || (this.events[type] = [])).push(fn);
    this.el.addEventListener(type, fn, { passive: false })
  }

  remove (type) {
    const callbacks = this.events[type]
    callbacks && callbacks.forEach((fn) => {
      this.el.removeEventListener(type, fn)
    })
  }

  removeAll () {
    Object.keys(this.events).forEach(type => {
      this.remove(type)
    })
  }

  removeThat (type, fn) {
    const callbacks = this.events[type]
    const index = callbacks.indexOf(fn)
    if (index === -1) {
      return false
    }
    this.el.removeElementListener(type, callbacks[index])
    return true
  }
}

复制代码

每一个ScrollEvent实例都代表一个DOM元素,所监听的所有事件,管理在自己的events中;

这个时候哪怕是通过

scrollevent.listen("事件类型" , ()=>{
  // to do something..
})
复制代码

这样的函数字面量的方式去进行的注册函数,我们在取消的时候,也只用这样写就好了;

scrollevent.remove("原事件类型")
复制代码

根本就不用去管需是否需要将函数具名的问题;

八、发布组件

通过一顿操作,我将这个组件发布在了npm上,具体如何发布,我推荐看这篇文章

所以使用的时候可以这样使用

npm i story-scrollbar -S
复制代码

然后在全局中注册一下

// 目前还在完善当中,详情请关注npm的readme哈
import SScrollbar from "story-scrollbar/index"
Vue.use(SScrollbar)
复制代码

在组件中可以这样使用

<template>
  <div>
    <h1>原始滚动条</h1>
    <div class="container">
      <ul>
        <li v-for="item in 100" :key="item">item {{item}}</li>
      </ul>
    </div>
    <h1>组件滚动条</h1>
    <SScrollbar class="scroll">
      <ul>
        <li v-for="item in 100" :key="item">item {{item}}</li>
      </ul>
    </SScrollbar>
  </div>
</template>

<script>

export default {
  data () {
    return {}
  }
}
</script>

<style scoped>
.container {
  width: 300px;
  height: 300px;
  border: 1px solid #333;
  overflow: auto;
}

.scroll {
  width: 300px;
  height: 300px;
  border: 1px solid #333;
}
</style>
复制代码

效果如下

屏幕录制2022-04-04 下午11.47.16.gif

因为我这个是mac系统,所以体现的不是很明显,如果是windows系统,那么就可以明显的看到差异了,并且无论在任何浏览器上面,滚动条的样式都还是表现的比较稳定的,并且提供了定义滚动条样式的style供开发者自定义;

下面贴上git地址:如果觉得不错,还希望给个star哈;多谢啦;也欢迎提交issues;

https://github.com/sonxiaopeng/story-scrollbar.git
复制代码

本文首发时间:2022年04月05日,后续将不断完善和更新;

九、参考资料

火狐浏览器
element-ui
自动生成目录

Supongo que te gusta

Origin juejin.im/post/7082786038816440333
Recomendado
Clasificación