vxe-table-demonic
Version:
一个基于 vue 的 PC 端表单/表格组件,支持增删改查、虚拟列表、虚拟树、懒加载、快捷菜单、数据校验、树形结构、打印导出、表单渲染、数据分页、弹窗、自定义模板、渲染器、JSON 配置式...
440 lines (439 loc) • 18.4 kB
JavaScript
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();
}
});