table-sticky.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /* 组件需要提供parent字段,指定表格的className(字符串) */
  2. const rafThrottle = fn => {
  3. let locked = false
  4. return function (...args) {
  5. if (locked) return
  6. locked = true
  7. window.requestAnimationFrame(_ => {
  8. fn.apply(this, args)
  9. locked = false
  10. })
  11. }
  12. }
  13. export default {
  14. mounted() {
  15. this.containerDom = document.getElementsByClassName('main-container')
  16. this.clearListener()
  17. let timer = setTimeout(() => {
  18. this.initFixedHeader()
  19. clearTimeout(timer)
  20. }, 300)
  21. window.addEventListener('resize', this.resizeChange)
  22. },
  23. deactivated() {
  24. this.clearListener()
  25. },
  26. beforeDestroy() {
  27. this.clearListener()
  28. //取消监听窗口大小
  29. window.removeEventListener('resize', this.resizeChange)
  30. },
  31. activated() {
  32. this.initFixedHeader()
  33. this.updateFixedRight()
  34. window.addEventListener('resize', this.resizeChange)
  35. let timer
  36. timer = setTimeout(() => {
  37. let container = this.containerDom
  38. if (container[0].scrollTop > 0) {
  39. container[0].scrollTop = container[0].scrollTop + 2
  40. }
  41. clearTimeout(timer)
  42. }, 1000)
  43. },
  44. methods: {
  45. reset() {
  46. this.clearFixedStyle()
  47. },
  48. // 窗口大小变化时,初始化
  49. resizeChange() {
  50. this.headerDragend()
  51. let timer = setTimeout(() => {
  52. this.initFixedHeader()
  53. clearTimeout(timer)
  54. }, 300)
  55. },
  56. async initFixedHeader() {
  57. if (this.parent) {
  58. // console.log('启动监听,页面:', this.parent)
  59. this.parentDom = document.getElementsByClassName(this.parent)
  60. if (this.parentDom && this.parentDom.length !== 0) {
  61. this.tableWidth = this.parentDom[0].querySelector('.el-table__header-wrapper').getBoundingClientRect().width
  62. this.setScrollXWidth()
  63. this.tableDom = this.parentDom[0].getElementsByClassName('el-table__header-wrapper')
  64. this.scrollDom = document.querySelector('.main-container')
  65. this.scrollDom.addEventListener('scroll', this.scrollEvent)
  66. }
  67. }
  68. },
  69. // 清空监听事件
  70. clearListener() {
  71. if (this.scrollDom) {
  72. this.scrollDom.removeEventListener('scroll', this.scrollEvent)
  73. window.removeEventListener('resize', this.resizeChange)
  74. this.clearFixedStyle()
  75. // console.log('卸载监听,页面:', this.parent)
  76. this.timerList.forEach(key => {
  77. clearTimeout(key)
  78. })
  79. }
  80. },
  81. // 更新右侧固定栏
  82. updateFixedRight() {
  83. let { fixedRightHeaderDom, dom } = this.getFixedDom()
  84. if (dom.classList.contains('fixed')) {
  85. let timer = setTimeout(() => {
  86. this.setFixedStyle({
  87. dom: fixedRightHeaderDom,
  88. left: this.fixedRightDom[0].getBoundingClientRect().left + 'px',
  89. width: getComputedStyle(this.fixedRightDom[0]).width,
  90. scrollLeft: fixedRightHeaderDom.scrollWidth
  91. })
  92. clearTimeout(timer)
  93. }, 100)
  94. }
  95. },
  96. async headerDragend() {
  97. await this.updateWidth()
  98. await this.updateFixedRight()
  99. this.setScrollXWidth()
  100. // await this.updateHeaderHeight()
  101. },
  102. setScrollXWidth() {
  103. let timer = setTimeout(() => {
  104. if (!this.parentDom) this.parentDom = document.getElementsByClassName(this.parent)
  105. if (this.parentDom.length == 0) return
  106. let dom = this.parentDom[0].querySelector('.el-table__header')
  107. this.tableWidth = this.parentDom[0].querySelector('.el-table__body-wrapper').getBoundingClientRect().width
  108. this.tableDom[0].style.width = this.tableWidth + 'px'
  109. this.updateHeaderHeight()
  110. this.headerWidth = dom.style.width
  111. clearTimeout(timer)
  112. }, 200)
  113. },
  114. // 更新表格宽度,(拖拽改变宽度时使用)
  115. updateWidth() {
  116. if (!this.parentDom) this.parentDom = document.getElementsByClassName(this.parent)
  117. const bodyWrapperDom = this.parentDom[0].getElementsByClassName('el-table__body-wrapper')[0]
  118. const width = getComputedStyle(bodyWrapperDom).width //表格宽度
  119. // 给表格设置宽度。
  120. const tableParent = this.tableDom
  121. for (let i = 0; i < tableParent.length; i++) {
  122. tableParent[i].style.width = width
  123. }
  124. },
  125. getFixedDom() {
  126. let fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox
  127. let dom = this.tableDom[0]
  128. if (this.fixedLeftDom && this.fixedLeftDom[0]) {
  129. let lefarr = this.fixedLeftDom[0].children
  130. fixedLeftHeaderDom = lefarr[0]
  131. fixedLeftBox = lefarr[1]
  132. }
  133. if (this.fixedRightDom && this.fixedRightDom[0]) {
  134. let rightarr = this.fixedRightDom[0].children
  135. fixedRightHeaderDom = rightarr[0]
  136. fixedRightBox = rightarr[1]
  137. }
  138. return { fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox, dom }
  139. },
  140. // 更新表头高度,表头高度有可能改变
  141. updateHeaderHeight() {
  142. this.$nextTick(() => {
  143. this.tableDom = this.parentDom[0].getElementsByClassName('el-table__header-wrapper')
  144. let obj = this.tableDom[0].getBoundingClientRect()
  145. if (obj.height != this.tablexy.height) {
  146. this.tablexy.height = obj.height
  147. let { dom } = this.getFixedDom()
  148. if (dom.classList.contains('fixed')) {
  149. let timer = setTimeout(() => {
  150. this.parentDom[0].getElementsByClassName('el-table__fixed-body-wrapper')[0].style.top = 0
  151. let container = this.containerDom
  152. if (container && container[0]) {
  153. container[0].scrollTop = container[0].scrollTop + 3
  154. }
  155. clearTimeout(timer)
  156. }, 100)
  157. }
  158. }
  159. })
  160. },
  161. // 获取表格属性
  162. getTableXy() {
  163. this.tablexy = this.tableDom[0].getBoundingClientRect()
  164. this.tablexy.height = this.tableDom[0].offsetHeight
  165. return this.tablexy
  166. },
  167. getDom() {
  168. if (!this.parentDom) {
  169. this.parentDom = document.getElementsByClassName(this.parent)
  170. }
  171. },
  172. //滚动事件
  173. scrollEvent: rafThrottle(async function (e) {
  174. this.getDom()
  175. this.tableDom = this.parentDom[0].getElementsByClassName('el-table__header-wrapper')
  176. if (this.tablexy.top == 0 || !this.tablexy.height || !this.tablexy.top) {
  177. await this.getTableXy()
  178. }
  179. this.fixedRightDom = this.parentDom[0].getElementsByClassName('el-table__fixed-right')
  180. this.fixedLeftDom = this.parentDom[0].getElementsByClassName('el-table__fixed')
  181. let { height, top, left } = this.tablexy
  182. let scrollTop = e.target.scrollTop
  183. let { fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox, dom } = this.getFixedDom()
  184. if (scrollTop >= height / 2 + top) {
  185. // 存在右侧固定表头
  186. if (fixedRightHeaderDom) {
  187. this.setFixedStyle({
  188. dom: fixedRightHeaderDom,
  189. left: this.fixedRightDom[0].getBoundingClientRect().left + 'px',
  190. width: getComputedStyle(this.fixedRightDom[0]).width,
  191. scrollLeft: fixedRightHeaderDom.scrollWidth
  192. })
  193. fixedRightBox.style.top = 83 + 'px'
  194. }
  195. // 左侧固定
  196. if (fixedLeftHeaderDom) {
  197. this.setFixedStyle({
  198. dom: fixedLeftHeaderDom,
  199. left: left + 'px',
  200. width: getComputedStyle(this.fixedLeftDom[0]).width,
  201. scrollLeft: 0
  202. })
  203. fixedLeftBox.style.top = 83 + 'px'
  204. }
  205. dom.classList.add('fixed') //加一个固定标识
  206. this.updateWidth()
  207. dom.style.position = 'fixed'
  208. dom.style.zIndex = '2000'
  209. dom.style.top = 83 + 'px'
  210. dom.style.overflow = 'hidden'
  211. } else {
  212. this.clearFixedStyle()
  213. }
  214. }),
  215. //设置固定
  216. setFixedStyle(data) {
  217. let { dom, scrollLeft, width, left } = data
  218. dom.style.zIndex = '2000'
  219. dom.style.position = 'fixed'
  220. dom.style.top = 83 + 'px'
  221. dom.scrollLeft = scrollLeft
  222. dom.style.width = width
  223. dom.style.overflow = 'hidden'
  224. dom.style.left = left
  225. },
  226. // 清除header固定
  227. clearFixedStyle() {
  228. if (!this.tableDom) return
  229. let { height, left } = this.tablexy
  230. let { dom, fixedRightHeaderDom, fixedRightBox, fixedLeftHeaderDom, fixedLeftBox } = this.getFixedDom()
  231. if (dom.classList.contains('fixed')) {
  232. if (fixedRightHeaderDom) {
  233. fixedRightBox.style.top = height + 'px'
  234. fixedRightHeaderDom.removeAttribute('style')
  235. }
  236. if (fixedLeftHeaderDom) {
  237. fixedLeftHeaderDom.style.zIndex = '0'
  238. fixedLeftHeaderDom.style.position = 'static'
  239. fixedLeftHeaderDom.style.top = 0 + 'px'
  240. fixedLeftHeaderDom.style.left = left + 'px'
  241. fixedLeftBox.style.top = getComputedStyle(dom).height
  242. }
  243. dom.classList.remove('fixed')
  244. dom.style.position = 'static'
  245. dom.style.top = '0'
  246. dom.style.zIndex = '0'
  247. }
  248. }
  249. },
  250. watch: {
  251. __opened() {
  252. this.$nextTick(() => {
  253. this.setScrollXWidth()
  254. })
  255. }
  256. },
  257. data() {
  258. return {
  259. tablexy: {}, //表格的左边宽度信息
  260. fixedRightDom: null, //右侧
  261. fixedLeftDom: null, //左侧栏固定
  262. scrollDom: null, //滚动的dom
  263. parentDom: null, //表格的父元素dom
  264. tableWidth: 0,
  265. timerList: [],
  266. tableDom: null,
  267. containerDom: null
  268. }
  269. }
  270. }