UNPKG

vxe-table-demonic

Version:

一个基于 vue 的 PC 端表单/表格组件,支持增删改查、虚拟列表、虚拟树、懒加载、快捷菜单、数据校验、树形结构、打印导出、表单渲染、数据分页、弹窗、自定义模板、渲染器、JSON 配置式...

440 lines (439 loc) 18.4 kB
import { defineComponent, h, ref, computed, Teleport, onUnmounted, reactive, nextTick, onMounted } from 'vue'; import XEUtils from 'xe-utils'; import GlobalConfig from '../../v-x-e-table/src/conf'; import { useSize } from '../../hooks/size'; import { getAbsolutePos, getEventTargetNode } from '../../tools/dom'; import { getFuncText, getLastZIndex, nextZIndex } from '../../tools/utils'; import { GlobalEvent } from '../../tools/event'; export default defineComponent({ name: 'VxeButton', props: { /** * 按钮类型 */ type: String, className: [String, Function], popupClassName: [String, Function], /** * 按钮尺寸 */ size: { type: String, default: function () { return GlobalConfig.button.size || GlobalConfig.size; } }, /** * 用来标识这一项 */ name: [String, Number], /** * 按钮内容 */ content: String, /** * 固定显示下拉面板的方向 */ placement: String, /** * 按钮状态 */ status: String, /** * 按钮的图标 */ icon: String, /** * 圆角边框 */ round: Boolean, /** * 圆角按钮 */ circle: Boolean, /** * 是否禁用 */ disabled: Boolean, /** * 是否加载中 */ loading: Boolean, /** * 在下拉面板关闭时销毁内容 */ destroyOnClose: Boolean, /** * 是否将弹框容器插入于 body 内 */ transfer: { type: Boolean, default: function () { return GlobalConfig.button.transfer; } }, layer: { type: [HTMLElement, String, Function] } }, emits: [ 'click', 'dropdown-click' ], setup: function (props, context) { var slots = context.slots, emit = context.emit; var xID = XEUtils.uniqueId(); var computeSize = useSize(props); var reactData = reactive({ inited: false, showPanel: false, animatVisible: false, panelIndex: 0, panelStyle: {}, panelPlacement: '' }); var internalData = { showTime: null }; var refElem = ref(); var refButton = ref(); var refBtnPanel = ref(); var refMaps = { refElem: refElem }; var $xebutton = { xID: xID, props: props, context: context, reactData: reactData, internalData: internalData, getRefMaps: function () { return refMaps; } }; var buttonMethods = {}; var computeIsFormBtn = computed(function () { var type = props.type; if (type) { return ['submit', 'reset', 'button'].indexOf(type) > -1; } return false; }); var computeBtnType = computed(function () { var type = props.type; return type && type === 'text' ? type : 'button'; }); var updateZindex = function () { if (reactData.panelIndex < getLastZIndex()) { reactData.panelIndex = nextZIndex(); } }; var updatePlacement = function () { return nextTick().then(function () { var transfer = props.transfer, placement = props.placement, layer = props.layer; var panelIndex = reactData.panelIndex; var targetElem = refButton.value; var panelElem = refBtnPanel.value; if (panelElem && targetElem) { var targetHeight = targetElem.offsetHeight; var targetWidth = targetElem.offsetWidth; var panelHeight = panelElem.offsetHeight; var panelWidth = panelElem.offsetWidth; var marginSize = 5; var panelStyle = { zIndex: panelIndex }; var _a = getAbsolutePos(targetElem), top_1 = _a.top, left = _a.left, boundingTop = _a.boundingTop, boundingBottom = _a.boundingBottom, visibleHeight = _a.visibleHeight, visibleWidth = _a.visibleWidth; var panelPlacement = 'bottom'; if (transfer) { // todo 会员管理页btnTop计算错误 超出视距 var btnLeft = left + targetWidth - panelWidth; var btnTop = top_1 + targetHeight; if (placement === 'top') { panelPlacement = 'top'; btnTop = top_1 - panelHeight; } else if (!placement) { // 如果下面不够放,则向上 if (boundingTop + targetHeight + panelHeight + marginSize > visibleHeight) { panelPlacement = 'top'; btnTop = top_1 - panelHeight; } // 如果上面不够放,则向下(优先) if (btnTop < marginSize) { panelPlacement = 'bottom'; btnTop = top_1 + targetHeight; } } // 如果溢出右边 if (btnLeft + panelWidth + marginSize > visibleWidth) { btnLeft -= btnLeft + panelWidth + marginSize - visibleWidth; } // 如果溢出左边 if (btnLeft < marginSize) { btnLeft = marginSize; } Object.assign(panelStyle, { left: "".concat(btnLeft, "px"), right: 'auto', top: "".concat(btnTop, "px"), minWidth: "".concat(targetWidth, "px") }); } else { var layerEle = layer ? XEUtils.isFunction(layer) ? layer(targetElem) : XEUtils.isString(layer) ? document.querySelector(layer) : layer : undefined; if (placement === 'top') { panelPlacement = 'top'; panelStyle.bottom = "".concat(targetHeight, "px"); } else if (!placement) { if (layerEle) { var _b = layerEle.getBoundingClientRect(), layerBottom = _b.bottom, layerTop = _b.top; // 如果下面不够放,上面够放,则向上 if (boundingBottom + targetHeight + panelHeight > layerBottom && boundingTop - targetHeight - panelHeight > layerTop) { panelPlacement = 'top'; panelStyle.bottom = "".concat(targetHeight, "px"); } } else { // 如果下面不够放,则向上 if (boundingTop + targetHeight + panelHeight > visibleHeight) { // 如果上面不够放,则向下(优先) if (boundingTop - targetHeight - panelHeight > marginSize) { panelPlacement = 'top'; panelStyle.bottom = "".concat(targetHeight, "px"); } } } } } reactData.panelStyle = panelStyle; reactData.panelPlacement = panelPlacement; return nextTick(); } }); }; var clickEvent = function (evnt) { buttonMethods.dispatchEvent('click', { $event: evnt }, evnt); }; var mousedownDropdownEvent = function (evnt) { var isLeftBtn = evnt.button === 0; if (isLeftBtn) { evnt.stopPropagation(); } }; var clickDropdownEvent = function (evnt) { var dropdownElem = evnt.currentTarget; var panelElem = refBtnPanel.value; var _a = getEventTargetNode(evnt, dropdownElem, 'vxe-button'), flag = _a.flag, targetElem = _a.targetElem; if (flag) { if (panelElem) { panelElem.dataset.active = 'N'; } reactData.showPanel = false; setTimeout(function () { if (!panelElem || panelElem.dataset.active !== 'Y') { reactData.animatVisible = false; } }, 350); buttonMethods.dispatchEvent('dropdown-click', { name: targetElem.getAttribute('name'), $event: evnt }, evnt); } }; var mouseenterEvent = function () { var panelElem = refBtnPanel.value; if (panelElem) { panelElem.dataset.active = 'Y'; reactData.animatVisible = true; setTimeout(function () { if (panelElem.dataset.active === 'Y') { reactData.showPanel = true; updateZindex(); updatePlacement(); setTimeout(function () { if (reactData.showPanel) { updatePlacement(); } }, 50); } }, 20); } }; var mouseenterTargetEvent = function () { var panelElem = refBtnPanel.value; if (panelElem) { panelElem.dataset.active = 'Y'; if (!reactData.inited) { reactData.inited = true; } internalData.showTime = setTimeout(function () { if (panelElem.dataset.active === 'Y') { mouseenterEvent(); } else { reactData.animatVisible = false; } }, 250); } }; var closePanel = function () { var panelElem = refBtnPanel.value; clearTimeout(internalData.showTime); if (panelElem) { panelElem.dataset.active = 'N'; setTimeout(function () { if (panelElem.dataset.active !== 'Y') { reactData.showPanel = false; setTimeout(function () { if (panelElem.dataset.active !== 'Y') { reactData.animatVisible = false; } }, 350); } }, 100); } else { reactData.animatVisible = false; reactData.showPanel = false; } }; var mouseleaveEvent = function () { closePanel(); }; var renderContent = function () { var content = props.content, icon = props.icon, loading = props.loading; var contVNs = []; if (loading) { contVNs.push(h('i', { class: ['vxe-button--loading-icon', GlobalConfig.icon.BUTTON_LOADING] })); } else if (slots.icon) { contVNs.push(h('span', { class: 'vxe-button--custom-icon' }, slots.icon({}))); } else if (icon) { contVNs.push(h('i', { class: ['vxe-button--icon', icon] })); } if (slots.default) { contVNs.push(h('span', { class: 'vxe-button--content' }, slots.default({}))); } else if (content) { contVNs.push(h('span', { class: 'vxe-button--content' }, getFuncText(content))); } return contVNs; }; buttonMethods = { dispatchEvent: function (type, params, evnt) { emit(type, Object.assign({ $button: $xebutton, $event: evnt }, params)); }, focus: function () { var btnElem = refButton.value; btnElem.focus(); return nextTick(); }, blur: function () { var btnElem = refButton.value; btnElem.blur(); return nextTick(); } }; Object.assign($xebutton, buttonMethods); onMounted(function () { GlobalEvent.on($xebutton, 'mousewheel', function (evnt) { var panelElem = refBtnPanel.value; if (reactData.showPanel && !getEventTargetNode(evnt, panelElem).flag) { closePanel(); } }); }); onUnmounted(function () { GlobalEvent.off($xebutton, 'mousewheel'); }); var renderVN = function () { var _a, _b, _c, _d; var className = props.className, popupClassName = props.popupClassName, transfer = props.transfer, type = props.type, round = props.round, circle = props.circle, destroyOnClose = props.destroyOnClose, status = props.status, name = props.name, disabled = props.disabled, loading = props.loading; var inited = reactData.inited, showPanel = reactData.showPanel; var isFormBtn = computeIsFormBtn.value; var btnType = computeBtnType.value; var vSize = computeSize.value; if (slots.dropdowns) { return h('div', { ref: refElem, class: ['vxe-button--dropdown', className ? (XEUtils.isFunction(className) ? className({ $button: $xebutton }) : className) : '', (_a = {}, _a["size--".concat(vSize)] = vSize, _a['is--active'] = showPanel, _a)] }, [ h('button', { ref: refButton, class: ['vxe-button', "type--".concat(btnType), (_b = {}, _b["size--".concat(vSize)] = vSize, _b["theme--".concat(status)] = status, _b['is--round'] = round, _b['is--circle'] = circle, _b['is--disabled'] = disabled || loading, _b['is--loading'] = loading, _b)], name: name, type: isFormBtn ? type : 'button', disabled: disabled || loading, onMouseenter: mouseenterTargetEvent, onMouseleave: mouseleaveEvent, onClick: clickEvent }, renderContent().concat([ h('i', { class: "vxe-button--dropdown-arrow ".concat(GlobalConfig.icon.BUTTON_DROPDOWN) }) ])), h(Teleport, { to: 'body', disabled: transfer ? !inited : true }, [ h('div', { ref: refBtnPanel, class: ['vxe-button--dropdown-panel', popupClassName ? (XEUtils.isFunction(popupClassName) ? popupClassName({ $button: $xebutton }) : popupClassName) : '', (_c = {}, _c["size--".concat(vSize)] = vSize, _c['animat--leave'] = reactData.animatVisible, _c['animat--enter'] = showPanel, _c)], placement: reactData.panelPlacement, style: reactData.panelStyle }, inited ? [ h('div', { class: 'vxe-button--dropdown-wrapper', onMousedown: mousedownDropdownEvent, onClick: clickDropdownEvent, onMouseenter: mouseenterEvent, onMouseleave: mouseleaveEvent }, destroyOnClose && !showPanel ? [] : slots.dropdowns({})) ] : []) ]) ]); } return h('button', { ref: refButton, class: ['vxe-button', "type--".concat(btnType), (_d = {}, _d["size--".concat(vSize)] = vSize, _d["theme--".concat(status)] = status, _d['is--round'] = round, _d['is--circle'] = circle, _d['is--disabled'] = disabled || loading, _d['is--loading'] = loading, _d)], name: name, type: isFormBtn ? type : 'button', disabled: disabled || loading, onClick: clickEvent }, renderContent()); }; $xebutton.renderVN = renderVN; return $xebutton; }, render: function () { return this.renderVN(); } });