vue框架下整合perfect-scrollbar

卫烨烁
2023-12-01

更详细教程见:https://www.npmjs.com/package/perfect-scrollbar

目标

  1. 使用简单命令在Vue项目中便捷调用perfect-scrollbar
  2. element ui 的 elTable 也能简单调用perfect-scrollbar

安装

npm install perfect-scrollbar --save
npm install classlist-polyfill --save

引入

在src/directive文件下,创建perfect-scrollbar文件夹,perfect-scrollbar文件夹里面创建index.js和scrollBar.js文件。
index.js

import scrollBar from './scrollBar'

const install = function(Vue) {
  Vue.directive('scrollBar', scrollBar)
}

if (window.Vue) {
  window['scrollBar'] = scrollBar
  Vue.use(install); // eslint-disable-line
}

scrollBar.install = install
export default scrollBar

scrollBar.js

// classList的垫片
import 'classlist-polyfill'
// 插件的包
import PerfectScrollbar from 'perfect-scrollbar'
// 对应的css
import 'perfect-scrollbar/css/perfect-scrollbar.css'

/**
 * @description 自动判断该更新PerfectScrollbar还是创建它
 * @param {HTMLElement} el - 必填。dom元素
 */
const el_scrollBar = (el) => {
  // 在元素上加点私货,名字随便取,确保不会和已有属性重复即可,我取名叫做_ps_
  if (el._ps_ instanceof PerfectScrollbar) {
    el._ps_.update()
  } else {
    // el上挂一份属性
    el._ps_ = new PerfectScrollbar(el, { suppressScrollX: true })
  }
}

export default {
  // 使用inserted钩子函数(初次创建dom)获取使用自定义指令处的dom
  inserted(el, binding, vnode) {
    // 判断其样式是否存在position 并且position为"fixed", "absolute"或"relative"
    // 如果不符合条件,抛个错误。当然你也可以抛个警告然顺便给其position自动加上"relative"
    // 为什么要这么做呢,因为PerfectScrollbar实现原理就是对dom注入两个div,一个是x轴一个是y轴,他们两的position都是absolute。
    // 对css稍有常识的人都知道,absolute是相对于所有父节点里设置了position属性的最近的一个节点来定位的,为了能够正确定位,我们要给其设置position属性
    const { arg } = binding;
    if(arg === "elTable"){ // "elTable" 可以换成任何你喜欢的标记
        el = el.querySelector(".el-table__body-wrapper");
        if(!el){
            return console.warn("未发现className为el-table__body-wrapper的dom");
        }
    }
    const rules = ['fixed', 'absolute', 'relative']
    if (!rules.includes(window.getComputedStyle(el, null).position)) {
      console.error(`perfect-scrollbar所在的容器的position属性必须是以下之一:${rules.join('、')}`)
    }
    // el上挂一份属性
    el_scrollBar(el)
  },
  // 更新dom的时候
  componentUpdated(el, binding, vnode, oldVnode) {
    const { arg } = binding;
    if (arg === "elTable") { // "elTable" 可以换成任何你喜欢的标记
      el = el.querySelector(".el-table__body-wrapper");
      if(!el){
          return console.warn("未发现className为el-table__body-wrapper的dom");
      }
    }
    try {
      // vnode.context其实就是vue实例,这里其实无需实例也直接用Vue的静态方法
      // 故而也可以写成Vue.nextTick
      vnode.context.$nextTick(
        () => {
          el_scrollBar(el)
        }
      )
    } catch (error) {
      console.error(error)
      el_scrollBar(el)
    }
  },
  // 解绑
  unbind(el, binding, vnode, oldVnode) {
    if (el._ps_ instanceof PerfectScrollbar) {
      el._ps_.destroy()
    }
  }
}

在全局样式文件中加入

.el-table__body-wrapper{
	position: relative;
}

在main.js文件中引入perfect-scrollbar组件
main.js

//滚动条
import scrollBar from '@/directive/perfect-scrollbar/index.js'

Vue.directive('scrollBar', scrollBar);

至此,引入完成

通过v-scrollBar直接在容器上使用,或在Element UI的el-table标签中使用v-scrollBar:elTable(可以配合el-table标签的height属性一起使用)。另外,该容器必须具有position样式,所以在加入v-scrollBar的容器上需要加入position:relative;(或其他)。

注意

以上方法引入,锁定了x轴,不出现滚动条。存在特殊情况时可以单独创建滚动条。

example.vue

<template>
	<div class="scroll-box"><div>
</template>

<script>
	import PerfectScrollbar from 'perfect-scrollbar';
	data() {
		return {
			ps: undefined
		}
	},
	mounted() {
      this.initScrollbar();
    },
	beforeDestroy(){
      this.ps.destroy();
    },
    methods:{
		initScrollbar(){
    		this.$nextTick(() => {
        	this.ps = new PerfectScrollbar('.scroll-box', {
						suppressScrollX: true //其他参数详见https://www.npmjs.com/package/perfect-scrollbar
					});
        	});
    	},
	}
</script>
<style lang="scss" scoped>
	.scroll-box{
		position:relative;
	}
</style>
 类似资料: