指令实战之滚动条自适应指令|周末学习

486 阅读2分钟

这是我参与更文挑战的第6天,活动详情查看:更文挑战

本文已参与周末学习计划,点击查看详情

1. 自适应浏览器宽高

<template>
  <div class="re-size" v-resize="getSize">浏览器窗口宽:{{windowSize.x}},浏览器窗口高:{{windowSize.y}}</div>
</template>

<script>
//import x from ''
export default {
  components: {},
  data() {
    return {
      windowSize: {
        x: 0,
        y: 0
      }
    }
  },
  mounted: function () {
    this.getSize()
  },
  directives: {
    resize: {
      inserted: function (el, binding) {
        var callback = binding.value
        var debounce = 200
        var options = { passive: true }
        var debounceTimeout = null
        var onResize = function () {
          clearTimeout(debounceTimeout)
          debounceTimeout = setTimeout(callback, debounce, options)
        }

        window.addEventListener('resize', onResize, options)

        el._onResize = {
          callback: callback,
          options: options
        }
      },
      unbind: function (el, binding) {
        var callback = el._onResize.callback
        var options = el._onResize.options
        window.removeEventListener('resize', callback, options)
        delete el._onResize
      }
    }
  },
  computed: {},
  methods: {
    getSize: function () {
      this.windowSize = {
        x: window.innerWidth,
        y: window.innerHeight
      }
    }
  }
}
</script>

2.进阶: y滚动条自适应

指令实战.gif

目前遇到的问题就是在使用 el-table 时, table 大概占页面1/3的样子,在浏览器宽高改变且整体布局不能动的情况下,无法自适应高度,所以写了这个指令来使 table 滚动条自适应高度.

指令核心代码

// tableScrollAuto.js
function getHeight(el,binding) {
  // 获取楼上元素块(如类似搜索区域)的dom
  let subTopDom = binding.value.topClass ? document.querySelector(binding.value.topClass) : null
  // 通过getBoundingClientRect获取楼上元素块距离页面顶部的top值
  let subTopTop = subTopDom ? subTopDom.getBoundingClientRect().top : 0
  // 楼下(底部)块的高度值
  let bottomHeight = binding.value.bottomHeight ? binding.value.bottomHeight : 0
  // el距离顶部的top值
  let elTop = el.getBoundingClientRect().top
  // 获取el与楼上的高度距离
  let topToMain = elTop -  subTopTop
  // 获取最终要减掉的高度值
  let sub = topToMain + bottomHeight
  // 获取父盒子的选择器,默认body
  let boxClass = binding.value.boxClass ? binding.value.boxClass : 'body'
  // 父盒子的总高度
  let boxHeight =  document.querySelector(boxClass).getBoundingClientRect().height
  // 总高度减去sub值,拿到了el的最终高度
  let height = (boxHeight - sub).toFixed(1) + 'px'
  return height
}
export const tableScrollAuto = {
  bind: function(el,binding) {
    // 初始化设置高度
    let height = getHeight(el,binding)
    el.style['overflow'] =  'auto'
    el.style['max-height'] =  height
  },
  inserted: function(el,binding) {
    // 设置防抖时间,防抖函数,通过监听resize来设置盒子高度
    let debounce = 200
    let debounceTime = null
    let onScrollAuto = function() {
      clearTimeout(debounceTime)
      debounceTime = setTimeout(() => {
        let height = getHeight(el,binding)
        el.style['overflow'] =  'auto'
        el.style['max-height'] =  height
      }, debounce);
    }
    // 方便销毁
    el._onScrollAuto = onScrollAuto
    window.addEventListener('resize',onScrollAuto)
  },
  unbind: function(el,binding) {
    // 移除监听
    window.removeEventListener('resize', el._onScrollAuto)
    console.log(el._onScrollAuto);
    delete el._onScrollAuto
    console.log('已经移出监听~');
  }
}

模板文件

<template>
  <div class="re-size">
    <div class="header"></div>
    <el-table :data="tableData" v-table-auto.a="{topCLass: '.header',bottomHeight: 30}">
      <el-table-column prop="date" label="日期" width="180"></el-table-column>
      <el-table-column prop="name" label="姓名" width="180"></el-table-column>
      <el-table-column prop="address" label="地址"></el-table-column>
    </el-table>
    <div class="footer"></div>
  </div>
</template>

<script>
//import x from ''
import { tableData } from './mock' // ele官网table demo 的数据
import { tableScrollAuto } from '@/directives/table-auto.js'
export default {
  components: {},
  data() {
    return {
      tableData: tableData
    }
  },
  directives: {
    'table-auto': tableScrollAuto
  },
  computed: {},
  methods: {
  }
}
</script>

<style lang='scss' scoped>
//@import url()
.re-size {
  .header {
    width: 100%;
    height: 110px;
    background: #ccc;
    margin-bottom: 45px;
  }
  .footer {
    width: 100%;
    height: 30px;
    background: #ccc;
    // margin-bottom: 45px;
  }
}
</style>

目前的话,这个指令的不足就是在resize的时候这个滚动条总会有卡顿, 不是防抖的问题, 我说的这个卡顿就是...类似重影, 这个现在没想到什么好的解决方法, 如果有大佬有解决方法的话,希望能指点下~ 但是话说回来, 不可能会有正常使用的用户一直resize浏览器窗口的, 所以...问题不大~

额...忘记写使用方式了,简单写一下~

使用方式

<el-table :data="tableData" v-table-auto="{topCLass: '.header',bottomHeight: 30}">
      <el-table-column prop="date" label="日期" width="180"></el-table-column>
      <el-table-column prop="name" label="姓名" width="180"></el-table-column>
      <el-table-column prop="address" label="地址"></el-table-column>
</el-table>

目前仅接受三个参数,如下:

参数类型描述
topCLassString,选择器字符顶部块的select选择器, 默认无
bottomHeightNumber,高度完整的底部块的高度(包括margin), 默认0
boxClassString,选择器字符父盒子的select选择器, 默认'body'