最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

vue中el-table實現(xiàn)自動吸頂效果(支持fixed)

 更新時間:2021年09月30日 10:09:40   作者:kaiking_g  
本文主要介紹了vue中el-table實現(xiàn)自動吸頂效果,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

前言

看了很多案例,從簡單的角度,position:sticky,似乎是比較理想的選擇,可是當(dāng)el-table設(shè)置了fixed后,這里的fixed會失效。最后還是采用了js監(jiān)聽滾動的思路實現(xiàn)。

實現(xiàn)思路

  • 表格距離頂部的距離
  • 設(shè)置表格距離頂部多少就吸頂—offsetTop1
  • 獲取滾動條滾動的距離
  • 當(dāng)滾動條滾動 offsetTop1 后,表格就自動吸頂

效果:

使用:

在el-table標(biāo)簽中配置:v-sticky="{ top: 0, parent:'#appMainDom'}",

<el-table 
:data="tableData" style="margin:10px 0;width: 100%;" 
bordermax-height="800"  class="sticky-head" v-sticky="{ top: 0, parent:'#appMainDom' }" >
...
</el-table>

說明

參數(shù)名字 類型 說明
top Number 滾動條距離頂部多少像素,自動吸頂
parent String 滾動的dom元素,內(nèi)部使用querySelector獲取該元素

gitee案例源碼:
https://gitee.com/kaiking_g/test-element-by-vue.git

主要源碼:

/**
 * 思路:
 * 表格距離頂部的距離
 * 設(shè)置表格距離頂部多少就吸頂---offsetTop1
 * 獲取滾動條滾動的距離
 * 當(dāng)滾動條滾動 offsetTop1 后,表格就自動吸頂
 */
import Vue from 'vue'
const tableStickyObj = {}

const __STICKY_TABLE = {
  // 給固定頭設(shè)置樣式
  doFix (dom, top, data) {
    const { uid, domType, isExist } = data
    const uObj = tableStickyObj[uid]
    const curObj = uObj[domType]
    const headerRect = tableStickyObj[uid].headerRect

    if (!isExist) {
      dom.style.position = 'fixed'
      dom.style.zIndex = '2001'
      dom.style.top = top + 'px'
    }
    uObj.tableWrapDom.style.marginTop = headerRect.height + 'px'

    if (domType === 'fixed') {
      dom.style.left = curObj.left + 'px'
    } else if (domType === 'fixedRight') {
      dom.style.left = curObj.left + 1 + 'px'
    }
  },
  // 給固定頭取消樣式
  removeFix (dom, data) {
    const { uid, domType } = data
    // dom.parentNode.style.paddingTop = 0
    const uObj = tableStickyObj[uid]
    const curObj = uObj[domType]
    dom.style.position = 'static'
    dom.style.top = '0'
    dom.style.zIndex = '0'

    uObj.tableWrapDom.style.marginTop = '0'

    if (domType === 'fixed') {
      curObj.dom.style.top = '0'
    } else if (domType === 'fixedRight') {
      curObj.dom.style.top = '0'
    }
  },
  // 給固定頭添加class
  addClass (dom, fixtop, data) {
    fixtop = fixtop || 0
    const isExist = dom.classList.contains('fixed')
    data.isExist = !!isExist
    if (!isExist) { // 若有,就不再添加
      dom.classList.add('fixed')
    }
    this.doFix(dom, fixtop, data)
  },
  // 給固定頭移除class
  removeClass (dom, data) {
    if (dom.classList.contains('fixed')) {
      dom.classList.remove('fixed')
      this.removeFix(dom, data)
    }
  },

  /**
   * 計算某元素距離相對父元素的top距離
   * @param {Nodes} e 某元素
   * @param {String} domId 父元素id
   * @param {Boolean} isParent 是否父元素
   * @returns {Number}
   */
  getPosY (el, domId) {
    let offset = 0
    const pDom = el.offsetParent
    if (pDom != null && '#' + el.id !== domId) {
      offset = el.offsetTop
      offset += this.getPosY(pDom, domId)
    }
    return offset
  },

  // 獲取元素的橫坐標(biāo)(相對于窗口)
  getPosX (e) {
    var offset = e.offsetLeft
    if (e.offsetParent != null) offset += this.getPosX(e.offsetParent)
    return offset
  },
  fixHead (scrollDom, el, uid, binding) {
    this.fixHead1(this, { scrollDom, el, uid, binding })
  },
  // 具體判斷是否固定頭的主函數(shù)
  fixHead1: sticky_throttle((_this, { scrollDom, el, uid, binding }) => {
    const top = binding.value.top
    /**
     * myTop 當(dāng)前元素距離滾動父容器的高度,
     * fixtop 當(dāng)前元素需要設(shè)置的絕對定位的高度
     * parentHeight 滾動父容器的高度
     */
    // 表頭DOM節(jié)點
    const headerWrapDom = el.children[1] // el-table__header-wrapper

    const headerTop = tableStickyObj[uid].headerRect.top
    const scrollTop = scrollDom.scrollTop

    const fixedHeadDom = tableStickyObj[uid].fixed.headerDom
    const fixedHeadRightDom = tableStickyObj[uid].fixedRight.headerDom

    if (scrollTop >= headerTop) {
      const fixtop = top + scrollDom.getBoundingClientRect().top
      // 如果表頭滾動到 父容器頂部了。fixed定位
      _this.addClass(headerWrapDom, fixtop, { domType: 'mainBody', uid })
      fixedHeadDom && _this.addClass(fixedHeadDom, fixtop, { domType: 'fixed', uid })
      fixedHeadRightDom && _this.addClass(fixedHeadRightDom, fixtop, { domType: 'fixedRight', uid })
    } else {
      // 如果表格向上滾動 又滾動到父容器里。取消fixed定位
      _this.removeClass(headerWrapDom, { domType: 'mainBody', uid })
      fixedHeadDom && _this.removeClass(fixedHeadDom, { domType: 'fixed', uid })
      fixedHeadRightDom && _this.removeClass(fixedHeadRightDom, { domType: 'fixedRight', uid })
    }
  }, 100, { eventType: 'fixHead111' }),
  //
  setHeadWidth (data) {
    this.setHeadWidth1(this, data)
  },
  // 設(shè)置頭部固定時表頭外容器的寬度寫死為表格body的寬度
  setHeadWidth1: sticky_debounce((_this, data) => {
    const { el, uid, binding, eventType } = data
    const { scrollDom } = tableStickyObj[uid]
    const headerWrapDom = el.children[1] // el-table__header-wrapper
    const headerH = headerWrapDom.offsetHeight
    const distTop = _this.getPosY(headerWrapDom, binding.value.parent)
    const scrollDistTop = _this.getPosY(scrollDom) // 滾動條距離頂部的距離

    tableStickyObj[uid].headerRect.top = distTop + headerH - scrollDistTop / 3 // 表頭距離頂部的距離 - 表頭自身高度 - 滾動條距離頂部的距離
    tableStickyObj[uid].headerRect.height = headerH
    // tableStickyObj[uid].headerRect.width = tableW

    // debugger
    // fixed left/right header
    // 確保每次刷新,只獲取一次
    // tableStickyObj[uid].fixed.dom = ''
    _this.initFixedWrap({ el, uid, eventType, key: 'fixed', className: 'el-table__fixed', className1: 'el-table__fixed-header-wrapper' })
    _this.initFixedWrap({ el, uid, eventType, key: 'fixedRight', className: 'el-table__fixed-right', className1: 'el-table__fixed-header-wrapper' })

    // debugger
    // 獲取到當(dāng)前表格個表格body的寬度
    const bodyWrapperDom = el.getElementsByClassName('el-table__body-wrapper')[0]
    const width = getComputedStyle(bodyWrapperDom).width
    // 給表格設(shè)置寬度。這里默認(rèn)一個頁面中的多個表格寬度是一樣的。所以直接遍歷賦值,也可以根據(jù)自己需求,單獨設(shè)置
    const tableParent = el.getElementsByClassName('el-table__header-wrapper')
    for (let i = 0; i < tableParent.length; i++) {
      tableParent[i].style.width = width
    }
    // debugger
    _this.fixHead(scrollDom, el, uid, binding) // 判斷頂部是否已吸頂?shù)囊粋€過程
  }),

  initFixedWrap (data) {
    const { key, el, eventType, className, className1, uid } = data
    // 確保每次刷新,只獲取一次
    if (eventType === 'resize' || !tableStickyObj[uid][key].dom) {
      const tableFixedDom = el.getElementsByClassName(className)
      if (tableFixedDom.length) {
        const fixedDom = tableFixedDom[0]
        const arr = fixedDom.getElementsByClassName(className1) //
        const headW = getComputedStyle(fixedDom).width

        tableStickyObj[uid][key].dom = fixedDom
        if (arr.length) {
          const distLeft = this.getPosX(fixedDom) // 距離窗口左側(cè)的距離
          const headDom = arr[0]
          headDom.style.width = headW
          tableStickyObj[uid][key].left = distLeft // 距離窗口左邊像素

          if (key === 'fixedRight') { // right-fixed 的特別之處
            headDom.classList.add('scroll-bar-h0')
            headDom.style.overflow = 'auto'
            headDom.scrollLeft = headDom.scrollWidth
            headDom.style.overflow = 'hidden' // 設(shè)置了滾動到最后,設(shè)置不可滾動
          } else {
            headDom.style.overflow = 'hidden'
          }

          tableStickyObj[uid][key].headerDom = headDom // 取第一個
        }
      }
    }
  },

  // 監(jiān)聽父級的某些變量(父級一定要有才能被監(jiān)聽到)
  watched ({ el, binding, vnode, uid }) {
    // 監(jiān)聽左側(cè)導(dǎo)航欄是否折疊
    vnode.context.$watch('isNavFold', (val) => {
      vnode.context.$nextTick(() => {
        setTimeout(() => {
          // debugger
          this.setHeadWidth({ el, uid, binding, eventType: 'resize' })
        }, 200)
      })
    })
  }

}

/**
 * 節(jié)流函數(shù): 指定時間間隔內(nèi)只會執(zhí)行一次任務(wù)
 * @param {function} fn
 * @param {Number} interval
 */
function sticky_throttle (fn, interval = 300) {
  let canRun = true
  return function () {
    if (!canRun) return
    canRun = false
    setTimeout(() => {
      fn.apply(this, arguments)
      canRun = true
    }, interval)
  }
}

/**
 * 防抖: 指定時間間隔內(nèi)只會執(zhí)行一次任務(wù),并且該時間段內(nèi)再觸發(fā),都會重新計算時間。(函數(shù)防抖的非立即執(zhí)行版)
 * 在頻繁觸發(fā)某些事件,導(dǎo)致大量的計算或者非常消耗資源的操作的時候,防抖可以強(qiáng)制在一段連續(xù)的時間內(nèi)只執(zhí)行一次
 * */
function sticky_debounce (fn, delay, config) {
  const _delay = delay || 200
  config = config || {}
  // const _this = this // 該this指向common.js
  return function () {
    const th = this // 該this指向?qū)嵗?
    const args = arguments
    // debounceNum++
    // let str = `, label: ${th && th.listItem && th.listItem.label}`
    if (fn.timer) {
      clearTimeout(fn.timer)
      fn.timer = null
    } else {
      // fn.debounceNum = debounceNum
    }
    fn.timer = setTimeout(function () {
      // str = `, label: ${th && th.listItem && th.listItem.label}`
      fn.timer = null
      fn.apply(th, args)
    }, _delay)
  }
}

// 全局注冊 自定義事件
Vue.directive('sticky', {
  // 當(dāng)被綁定的元素插入到 DOM 中時……
  inserted (el, binding, vnode) {
    // 獲取當(dāng)前vueComponent的ID。作為存放各種監(jiān)聽事件的key
    const uid = vnode.componentInstance._uid
    // 獲取當(dāng)前滾動的容器是什么。如果是document滾動。則可默認(rèn)不傳入parent參數(shù)
    const scrollDom = document.querySelector(binding.value.parent) || document.body // TODO:得考慮沒有 binding.value.parent 的情況,重新登錄直接進(jìn)到內(nèi)頁會出現(xiàn)

    if (!tableStickyObj[uid]) {
      tableStickyObj[uid] = {
        uid,
        fixFunObj: {}, // 用于存放滾動容器的監(jiān)聽scroll事件
        setWidthFunObj: {}, // 用于存放頁面resize后重新計算head寬度事件
        autoMoveFunObj: {}, // 用戶存放如果是DOM元素內(nèi)局部滾動時,document滾動時,fix布局的表頭也需要跟著document一起向上滾動
        scrollDomRect: {},
        headerRect: { top: 0, left: 0 },
        fixed: {}, // 表格左浮動
        fixedRight: {}, // 表格右浮動
        // binding,
        // el,
        tableWrapDom: el.getElementsByClassName('el-table__body-wrapper')[0],
        scrollDom
      }
    }

    __STICKY_TABLE.watched({ el, binding, vnode, uid }) // 監(jiān)聽父級的某些變量

    // 當(dāng)window resize時 重新計算設(shè)置表頭寬度,并將監(jiān)聽函數(shù)存入 監(jiān)聽函數(shù)對象中,方便移除監(jiān)聽事件
    window.addEventListener('resize', (tableStickyObj[uid].setWidthFunObj = () => {
      __STICKY_TABLE.setHeadWidth({ el, uid, binding, eventType: 'resize' }) // 首先設(shè)置表頭寬度
    })
    )

    // 給滾動容器加scroll監(jiān)聽事件。并將監(jiān)聽函數(shù)存入 監(jiān)聽函數(shù)對象中,方便移除監(jiān)聽事件
    scrollDom.addEventListener('scroll', (tableStickyObj[uid].fixFunObj = (e) => {
      __STICKY_TABLE.fixHead(scrollDom, el, uid, binding)
    }))
  },
  // component 更新后。重新計算表頭寬度
  componentUpdated (el, binding, vnode) {
    const uid = vnode.componentInstance._uid
    __STICKY_TABLE.setHeadWidth({ el, uid, binding, eventType: 'componentUpdated' })
  },
  // 節(jié)點取消綁定時 移除各項監(jiān)聽事件。
  unbind (el, binding, vnode) {
    const uid = vnode.componentInstance._uid
    window.removeEventListener('resize', tableStickyObj[uid].setWidthFunObj)
    const scrollDom = document.querySelector(binding.value.parent) || document
    scrollDom.removeEventListener('scroll', tableStickyObj[uid].fixFunObj)
    if (binding.value.parent) {
      document.removeEventListener('scroll', tableStickyObj[uid].autoMoveFunObj)
    }
  }
})

到此這篇關(guān)于vue中el-table實現(xiàn)自動吸頂效果(支持fixed)的文章就介紹到這了,更多相關(guān)el-table 自動吸頂內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • vue頁面params傳值的坑及解決

    vue頁面params傳值的坑及解決

    這篇文章主要介紹了vue頁面params傳值的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-05-05
  • VUEX?使用?mutations的兩種方式

    VUEX?使用?mutations的兩種方式

    這篇文章主要介紹了VUEX?使用?mutations的兩種方式,實現(xiàn)方式就是利用vuex中的mutations,在mutations中定義一個方法,這個方法就是把點擊的index(也就是每個列表的唯一標(biāo)識),傳給state中的當(dāng)前標(biāo)識,需要的朋友可以參考下
    2023-01-01
  • Element-ui之ElScrollBar組件滾動條的使用方法

    Element-ui之ElScrollBar組件滾動條的使用方法

    這篇文章主要介紹了Element-ui之ElScrollBar組件滾動條的使用方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • Vue項目報錯:Uncaught?SyntaxError:?Unexpected?token?'<'的解決方法

    Vue項目報錯:Uncaught?SyntaxError:?Unexpected?token?'<&a

    最近在做vue項目時,需要引入一個第三方的js文件,在index.html中通過以下方式引入JS文件編譯后就報了這個問題,這篇文章主要給大家介紹了關(guān)于Vue項目報錯:Uncaught?SyntaxError:?Unexpected?token?'<'的解決方法,需要的朋友可以參考下
    2022-08-08
  • element-plus報錯ResizeObserver?loop?limit?exceeded解決辦法

    element-plus報錯ResizeObserver?loop?limit?exceeded解決辦法

    這篇文章主要給大家介紹了關(guān)于element-plus報錯ResizeObserver?loop?limit?exceeded的解決辦法,文中通過代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • 解決vue打包后vendor.js文件過大問題

    解決vue打包后vendor.js文件過大問題

    這篇文章主要介紹了解決vue打包后vendor.js文件過大問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-07-07
  • 搭建vue開發(fā)環(huán)境

    搭建vue開發(fā)環(huán)境

    這篇文章主要介紹了搭建vue開發(fā)環(huán)境的方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下
    2018-07-07
  • Vue項目pdf(base64)轉(zhuǎn)圖片遇到的問題及解決方法

    Vue項目pdf(base64)轉(zhuǎn)圖片遇到的問題及解決方法

    這篇文章主要介紹了Vue項目pdf(base64)轉(zhuǎn)圖片遇到的問題及解決方法,需要的朋友可以參考下
    2018-10-10
  • 關(guān)于element中對el-input 自定義驗證規(guī)則

    關(guān)于element中對el-input 自定義驗證規(guī)則

    這篇文章主要介紹了關(guān)于element中對el-input 自定義驗證規(guī)則,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • 詳解win7 cmd執(zhí)行vue不是內(nèi)部命令的解決方法

    詳解win7 cmd執(zhí)行vue不是內(nèi)部命令的解決方法

    這篇文章主要介紹了詳解win7 cmd執(zhí)行vue不是內(nèi)部命令的解決方法的相關(guān)資料,這里提供了解決問題的詳細(xì)步驟,具有一定的參考價值,需要的朋友可以參考下
    2017-07-07

最新評論

临武县| 阿拉善左旗| 巍山| 井陉县| 确山县| 孝义市| 富阳市| 高要市| 卓尼县| 西宁市| 日喀则市| 大庆市| 固始县| 庐江县| 平和县| 衢州市| 双辽市| 长子县| 通河县| 印江| 浦东新区| 南靖县| 文登市| 莱西市| 乌苏市| 东明县| 定陶县| 科技| 隆尧县| 新田县| 翼城县| 武胜县| 葫芦岛市| 温宿县| 东方市| 夹江县| 红桥区| 监利县| 金山区| 兴义市| 麻阳|