UNPKG

vxe-table

Version:

一个基于 vue 的 PC 端表格组件,支持增删改查、虚拟滚动、懒加载、快捷菜单、数据校验、树形结构、打印导出、表单渲染、数据分页、虚拟列表、模态窗口、自定义模板、渲染器、贼灵活的配置项、扩展接口等...

207 lines (196 loc) 6.92 kB
import XEUtils from 'xe-utils/ctor' import UtilTools from './utils' const { getRowid } = UtilTools const browse = XEUtils.browse() const htmlElem = browse.isDoc ? document.querySelector('html') : 0 const bodyElem = browse.isDoc ? document.body : 0 const reClsMap = {} function getClsRE (cls) { if (!reClsMap[cls]) { reClsMap[cls] = new RegExp(`(?:^|\\s)${cls}(?!\\S)`, 'g') } return reClsMap[cls] } function getNodeOffset (elem, container, rest) { if (elem) { const parentElem = elem.parentNode rest.top += elem.offsetTop rest.left += elem.offsetLeft if (parentElem && parentElem !== htmlElem && parentElem !== bodyElem) { rest.top -= parentElem.scrollTop rest.left -= parentElem.scrollLeft } if (container && (elem === container || elem.offsetParent === container) ? 0 : elem.offsetParent) { return getNodeOffset(elem.offsetParent, container, rest) } } return rest } function isScale (val) { return val && /^\d+%$/.test(val) } function hasClass (elem, cls) { return elem && elem.className && elem.className.match && elem.className.match(getClsRE(cls)) } function removeClass (elem, cls) { if (elem && hasClass(elem, cls)) { elem.className = elem.className.replace(getClsRE(cls), '') } } function getDomNode () { const documentElement = document.documentElement const bodyElem = document.body return { scrollTop: documentElement.scrollTop || bodyElem.scrollTop, scrollLeft: documentElement.scrollLeft || bodyElem.scrollLeft, visibleHeight: documentElement.clientHeight || bodyElem.clientHeight, visibleWidth: documentElement.clientWidth || bodyElem.clientWidth } } export const DomTools = { browse, isPx (val) { return val && /^\d+(px)?$/.test(val) }, isScale, hasClass, removeClass, addClass (elem, cls) { if (elem && !hasClass(elem, cls)) { removeClass(elem, cls) elem.className = `${elem.className} ${cls}` } }, updateCellTitle (overflowElem, column) { const content = column.type === 'html' ? overflowElem.innerText : overflowElem.textContent if (overflowElem.getAttribute('title') !== content) { overflowElem.setAttribute('title', content) } }, rowToVisible ($xetable, row) { const bodyElem = $xetable.$refs.tableBody.$el const trElem = bodyElem.querySelector(`[data-rowid="${getRowid($xetable, row)}"]`) if (trElem) { const bodyHeight = bodyElem.clientHeight const bodySrcollTop = bodyElem.scrollTop const trOffsetTop = trElem.offsetTop + (trElem.offsetParent ? trElem.offsetParent.offsetTop : 0) const trHeight = trElem.clientHeight // 检测行是否在可视区中 if (trOffsetTop < bodySrcollTop || trOffsetTop > bodySrcollTop + bodyHeight) { // 向上定位 return $xetable.scrollTo(null, trOffsetTop) } else if (trOffsetTop + trHeight >= bodyHeight + bodySrcollTop) { // 向下定位 return $xetable.scrollTo(null, bodySrcollTop + trHeight) } } else { // 如果是虚拟渲染跨行滚动 if ($xetable.scrollYLoad) { return $xetable.scrollTo(null, ($xetable.afterFullData.indexOf(row) - 1) * $xetable.scrollYStore.rowHeight) } } return Promise.resolve() }, colToVisible ($xetable, column) { const bodyElem = $xetable.$refs.tableBody.$el const tdElem = bodyElem.querySelector(`.${column.id}`) if (tdElem) { const bodyWidth = bodyElem.clientWidth const bodySrcollLeft = bodyElem.scrollLeft const tdOffsetLeft = tdElem.offsetLeft + (tdElem.offsetParent ? tdElem.offsetParent.offsetLeft : 0) const tdWidth = tdElem.clientWidth // 检测行是否在可视区中 if (tdOffsetLeft < bodySrcollLeft || tdOffsetLeft > bodySrcollLeft + bodyWidth) { // 向左定位 return $xetable.scrollTo(tdOffsetLeft) } else if (tdOffsetLeft + tdWidth >= bodyWidth + bodySrcollLeft) { // 向右定位 return $xetable.scrollTo(bodySrcollLeft + tdWidth) } } else { // 如果是虚拟渲染跨行滚动 if ($xetable.scrollXLoad) { const visibleColumn = $xetable.visibleColumn let scrollLeft = 0 for (let index = 0; index < visibleColumn.length; index++) { if (visibleColumn[index] === column) { break } scrollLeft += visibleColumn[index].renderWidth } return $xetable.scrollTo(scrollLeft) } } return Promise.resolve() }, getDomNode, /** * 检查触发源是否属于目标节点 */ getEventTargetNode (evnt, container, queryCls, queryMethod) { let targetElem let target = evnt.target while (target && target.nodeType && target !== document) { if (queryCls && hasClass(target, queryCls) && (!queryMethod || queryMethod(target))) { targetElem = target } else if (target === container) { return { flag: queryCls ? !!targetElem : true, container, targetElem: targetElem } } target = target.parentNode } return { flag: false } }, /** * 获取元素相对于 document 的位置 */ getOffsetPos (elem, container) { return getNodeOffset(elem, container, { left: 0, top: 0 }) }, getAbsolutePos (elem) { const bounding = elem.getBoundingClientRect() const boundingTop = bounding.top const boundingLeft = bounding.left const { scrollTop, scrollLeft, visibleHeight, visibleWidth } = getDomNode() return { boundingTop, top: scrollTop + boundingTop, boundingLeft, left: scrollLeft + boundingLeft, visibleHeight, visibleWidth } }, toView (elem) { const scrollIntoViewIfNeeded = 'scrollIntoViewIfNeeded' const scrollIntoView = 'scrollIntoView' if (elem) { if (elem[scrollIntoViewIfNeeded]) { elem[scrollIntoViewIfNeeded]() } else if (elem[scrollIntoView]) { elem[scrollIntoView]() } } }, triggerEvent (targetElem, type) { let evnt if (typeof Event === 'function') { evnt = new Event(type) } else { evnt = document.createEvent('Event') evnt.initEvent(type, true, true) } targetElem.dispatchEvent(evnt) }, calcHeight ($xetable, key) { const val = $xetable[key] let num = 0 if (val) { if (val === 'auto') { num = $xetable.parentHeight } else { const excludeHeight = $xetable.getExcludeHeight() if (isScale(val)) { num = Math.floor((XEUtils.toInteger(val) || 1) / 100 * $xetable.parentHeight) } else { num = XEUtils.toNumber(val) } num = Math.max(40, num - excludeHeight) } } return num } } export default DomTools