@vxe-ui/core 4.4.31 → 4.4.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/all.esm.js +263 -3
- package/es/index.esm.js +3 -0
- package/es/src/base-utils.js +15 -0
- package/es/src/core.js +1 -1
- package/es/src/dom-utils.js +56 -0
- package/es/src/log.js +1 -1
- package/es/src/popper-utils.js +188 -0
- package/lib/index.common.js +13 -0
- package/lib/index.umd.js +269 -2
- package/lib/index.umd.min.js +1 -1
- package/lib/src/base-utils.js +15 -0
- package/lib/src/base-utils.min.js +1 -1
- package/lib/src/core.js +1 -1
- package/lib/src/core.min.js +1 -1
- package/lib/src/dom-utils.js +56 -0
- package/lib/src/dom-utils.min.js +1 -1
- package/lib/src/log.js +1 -1
- package/lib/src/log.min.js +1 -1
- package/lib/src/popper-utils.js +198 -0
- package/lib/src/popper-utils.min.js +1 -0
- package/package.json +1 -1
- package/packages/index.ts +3 -0
- package/packages/src/base-utils.ts +15 -0
- package/packages/src/dom-utils.ts +60 -0
- package/packages/src/popper-utils.ts +194 -0
- package/types/core/base-utils.d.ts +18 -0
- package/types/core/dom-utils.d.ts +28 -0
- package/types/core/index.d.ts +7 -0
- package/types/core/popper-utils.d.ts +44 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.popperUtils = void 0;
|
|
7
|
+
var _xeUtils = _interopRequireDefault(require("xe-utils"));
|
|
8
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
/**
|
|
10
|
+
* 获取包裹容器的元素
|
|
11
|
+
*/
|
|
12
|
+
function getWrapperElement(panelElem) {
|
|
13
|
+
if (!panelElem) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
const bodyEl = document.body;
|
|
17
|
+
const parentEl = panelElem.parentElement;
|
|
18
|
+
return (parentEl === bodyEl ? document.documentElement : parentEl) || null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 获取插入到指定容器的元素或字符串
|
|
22
|
+
*/
|
|
23
|
+
function getAppendSelector(appendTo) {
|
|
24
|
+
const selectElem = appendTo && _xeUtils.default.isFunction(appendTo) ? appendTo({}) : appendTo;
|
|
25
|
+
return selectElem || 'body';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 获取插入到指定容器的元素
|
|
29
|
+
*/
|
|
30
|
+
function getAppendElement(appendTo) {
|
|
31
|
+
const selectElem = getAppendSelector(appendTo);
|
|
32
|
+
if (_xeUtils.default.isString(selectElem)) {
|
|
33
|
+
return document.querySelector(selectElem) || document.body;
|
|
34
|
+
}
|
|
35
|
+
return selectElem;
|
|
36
|
+
}
|
|
37
|
+
const popperUtils = exports.popperUtils = {
|
|
38
|
+
/**
|
|
39
|
+
* 更新位置
|
|
40
|
+
*/
|
|
41
|
+
updatePlacement(targetElem, panelElem, options) {
|
|
42
|
+
const {
|
|
43
|
+
defaultTop,
|
|
44
|
+
defaultLeft,
|
|
45
|
+
placement,
|
|
46
|
+
defaultPlacement,
|
|
47
|
+
appendTo,
|
|
48
|
+
teleportTo,
|
|
49
|
+
marginSize,
|
|
50
|
+
isMinWidth
|
|
51
|
+
} = Object.assign({
|
|
52
|
+
appendTo: '',
|
|
53
|
+
teleportTo: false,
|
|
54
|
+
marginSize: 18,
|
|
55
|
+
isMinWidth: true
|
|
56
|
+
}, options);
|
|
57
|
+
let panelPlacement = 'bottom';
|
|
58
|
+
let top = '';
|
|
59
|
+
let bottom = '';
|
|
60
|
+
let left = 0;
|
|
61
|
+
let minWidth = '';
|
|
62
|
+
let arrowLeft = '';
|
|
63
|
+
const stys = {};
|
|
64
|
+
if (panelElem && targetElem) {
|
|
65
|
+
const bodyEl = document.body;
|
|
66
|
+
const parentWrapperEl = getWrapperElement(teleportTo ? getAppendElement(appendTo) : panelElem);
|
|
67
|
+
if (parentWrapperEl) {
|
|
68
|
+
const targetWidth = targetElem.offsetWidth;
|
|
69
|
+
const targetHeight = targetElem.offsetHeight;
|
|
70
|
+
const panelWidth = panelElem.offsetWidth;
|
|
71
|
+
const panelHeight = panelElem.offsetHeight;
|
|
72
|
+
const parentWrapperRect = parentWrapperEl.getBoundingClientRect();
|
|
73
|
+
const panelRect = panelElem.getBoundingClientRect();
|
|
74
|
+
const targetRect = targetElem.getBoundingClientRect();
|
|
75
|
+
const visibleHeight = bodyEl.clientHeight;
|
|
76
|
+
const visibleWidth = bodyEl.clientWidth;
|
|
77
|
+
const parentWrapperScrollLeft = parentWrapperEl.scrollLeft;
|
|
78
|
+
const parentWrapperScrollTop = parentWrapperEl.scrollTop;
|
|
79
|
+
const parentWrapperOffsetLeft = parentWrapperRect.left;
|
|
80
|
+
const parentWrapperOffsetTop = parentWrapperRect.top;
|
|
81
|
+
const targetLeft = targetRect.left;
|
|
82
|
+
const targetTop = targetRect.top;
|
|
83
|
+
minWidth = targetElem.offsetWidth;
|
|
84
|
+
if (teleportTo) {
|
|
85
|
+
left = (defaultLeft || targetLeft - (panelWidth - targetWidth) / 2) - parentWrapperScrollLeft;
|
|
86
|
+
top = (defaultTop || targetTop + targetHeight) - parentWrapperScrollTop;
|
|
87
|
+
if (placement === 'top') {
|
|
88
|
+
panelPlacement = 'top';
|
|
89
|
+
top = targetTop - panelHeight;
|
|
90
|
+
} else if (!placement) {
|
|
91
|
+
if (defaultPlacement === 'top') {
|
|
92
|
+
panelPlacement = 'top';
|
|
93
|
+
if (!defaultTop) {
|
|
94
|
+
top = targetTop - panelHeight;
|
|
95
|
+
}
|
|
96
|
+
// 如果上面不够放,则向下
|
|
97
|
+
if (top < marginSize) {
|
|
98
|
+
panelPlacement = 'bottom';
|
|
99
|
+
top = targetTop + targetHeight;
|
|
100
|
+
}
|
|
101
|
+
// 如果下面不够放,则向上(优先)
|
|
102
|
+
if (top + panelHeight + marginSize > visibleHeight) {
|
|
103
|
+
panelPlacement = 'top';
|
|
104
|
+
top = targetTop - panelHeight;
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
// 如果下面不够放,则向上
|
|
108
|
+
if (top + panelHeight + marginSize > visibleHeight) {
|
|
109
|
+
panelPlacement = 'top';
|
|
110
|
+
top = targetTop - panelHeight;
|
|
111
|
+
}
|
|
112
|
+
// 如果上面不够放,则向下(优先)
|
|
113
|
+
if (top < marginSize) {
|
|
114
|
+
panelPlacement = 'bottom';
|
|
115
|
+
top = targetTop + targetHeight;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
// 如果溢出右边
|
|
120
|
+
if (left + panelWidth + marginSize > visibleWidth) {
|
|
121
|
+
left -= left + panelWidth + marginSize - visibleWidth;
|
|
122
|
+
}
|
|
123
|
+
// 如果溢出左边
|
|
124
|
+
if (left < marginSize) {
|
|
125
|
+
left = marginSize;
|
|
126
|
+
}
|
|
127
|
+
// 偏移
|
|
128
|
+
top -= parentWrapperOffsetTop;
|
|
129
|
+
left -= parentWrapperOffsetLeft;
|
|
130
|
+
} else {
|
|
131
|
+
if (placement === 'top') {
|
|
132
|
+
panelPlacement = 'top';
|
|
133
|
+
bottom = targetHeight;
|
|
134
|
+
} else if (!placement) {
|
|
135
|
+
// 如果下面不够放,则向上
|
|
136
|
+
top = targetHeight;
|
|
137
|
+
if (targetTop + targetHeight + panelHeight + marginSize > visibleHeight) {
|
|
138
|
+
// 如果上面不够放,则向下(优先)
|
|
139
|
+
if (targetTop - targetHeight - panelHeight > marginSize) {
|
|
140
|
+
panelPlacement = 'top';
|
|
141
|
+
top = '';
|
|
142
|
+
bottom = targetHeight;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// 是否超出右侧
|
|
147
|
+
if (panelRect.left + panelRect.width + marginSize > visibleWidth) {
|
|
148
|
+
left = -(panelRect.left + panelRect.width + marginSize - visibleWidth);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (_xeUtils.default.isNumber(top)) {
|
|
152
|
+
stys.top = top + 'px';
|
|
153
|
+
}
|
|
154
|
+
if (_xeUtils.default.isNumber(bottom)) {
|
|
155
|
+
stys.bottom = bottom + 'px';
|
|
156
|
+
}
|
|
157
|
+
if (_xeUtils.default.isNumber(left)) {
|
|
158
|
+
stys.left = left + 'px';
|
|
159
|
+
}
|
|
160
|
+
if (isMinWidth && _xeUtils.default.isNumber(minWidth)) {
|
|
161
|
+
stys.minWidth = minWidth + 'px';
|
|
162
|
+
}
|
|
163
|
+
// 箭头
|
|
164
|
+
if (left === targetLeft) {
|
|
165
|
+
if (targetWidth <= panelWidth) {
|
|
166
|
+
arrowLeft = targetWidth / 2;
|
|
167
|
+
}
|
|
168
|
+
} else if (left < targetLeft) {
|
|
169
|
+
if (left + panelWidth > targetLeft + targetWidth) {
|
|
170
|
+
arrowLeft = targetLeft - left + targetWidth / 2;
|
|
171
|
+
} else {
|
|
172
|
+
arrowLeft = targetLeft - left + (panelWidth - (targetLeft - left)) / 2;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
top: top || 0,
|
|
179
|
+
bottom: bottom || 0,
|
|
180
|
+
left: left || 0,
|
|
181
|
+
arrowLeft: arrowLeft || 0,
|
|
182
|
+
style: stys,
|
|
183
|
+
placement: panelPlacement
|
|
184
|
+
};
|
|
185
|
+
},
|
|
186
|
+
/**
|
|
187
|
+
* 获取包裹容器的元素
|
|
188
|
+
*/
|
|
189
|
+
getWrapperElement,
|
|
190
|
+
/**
|
|
191
|
+
* 获取插入到指定容器的元素或字符串
|
|
192
|
+
*/
|
|
193
|
+
getAppendSelector,
|
|
194
|
+
/**
|
|
195
|
+
* 获取插入到指定容器的元素
|
|
196
|
+
*/
|
|
197
|
+
getAppendElement
|
|
198
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Object.defineProperty(exports,"__esModule",{value:!0}),exports.popperUtils=void 0;var _xeUtils=_interopRequireDefault(require("xe-utils"));function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}function getWrapperElement(e){var t;return e&&(t=document.body,(e=e.parentElement)===t?document.documentElement:e)||null}function getAppendSelector(e){return(e&&_xeUtils.default.isFunction(e)?e({}):e)||"body"}function getAppendElement(e){e=getAppendSelector(e);return _xeUtils.default.isString(e)?document.querySelector(e)||document.body:e}let popperUtils=exports.popperUtils={updatePlacement(e,t,o){var{defaultTop:o,defaultLeft:l,placement:n,defaultPlacement:p,appendTo:i,teleportTo:r,marginSize:d,isMinWidth:u}=Object.assign({appendTo:"",teleportTo:!1,marginSize:18,isMinWidth:!0},o);let f="bottom",a="",s="",m=0;var c="";let g="";var b,x,_,h,W,E,U,A,S,v,y,T={};return t&&e&&(E=document.body,i=getWrapperElement(r?getAppendElement(i):t))&&(b=e.offsetWidth,x=e.offsetHeight,_=t.offsetWidth,h=t.offsetHeight,S=i.getBoundingClientRect(),t=t.getBoundingClientRect(),y=e.getBoundingClientRect(),W=E.clientHeight,E=E.clientWidth,U=i.scrollLeft,i=i.scrollTop,A=S.left,S=S.top,v=y.left,y=y.top,c=e.offsetWidth,r?(m=(l||v-(_-b)/2)-U,a=(o||y+x)-i,"top"===n?(f="top",a=y-h):n||("top"===p?(f="top",(a=o?a:y-h)<d&&(f="bottom",a=y+x),a+h+d>W&&(f="top",a=y-h)):(a+h+d>W&&(f="top",a=y-h),a<d&&(f="bottom",a=y+x))),m+_+d>E&&(m-=m+_+d-E),m<d&&(m=d),a-=S,m-=A):("top"===n?(f="top",s=x):n||W<y+(a=x)+h+d&&d<y-x-h&&(f="top",a="",s=x),t.left+t.width+d>E&&(m=-(t.left+t.width+d-E))),_xeUtils.default.isNumber(a)&&(T.top=a+"px"),_xeUtils.default.isNumber(s)&&(T.bottom=s+"px"),_xeUtils.default.isNumber(m)&&(T.left=m+"px"),u&&_xeUtils.default.isNumber(c)&&(T.minWidth=c+"px"),m===v?b<=_&&(g=b/2):m<v&&(g=m+_>v+b?v-m+b/2:v-m+(_-(v-m))/2)),{top:a||0,bottom:s||0,left:m||0,arrowLeft:g||0,style:T,placement:f}},getWrapperElement:getWrapperElement,getAppendSelector:getAppendSelector,getAppendElement:getAppendElement};
|
package/package.json
CHANGED
package/packages/index.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { permission } from './src/permission'
|
|
|
18
18
|
import { baseUtils } from './src/base-utils'
|
|
19
19
|
import { domUtils } from './src/dom-utils'
|
|
20
20
|
import { scrollbarUtils } from './src/scrollbar-utils'
|
|
21
|
+
import { popperUtils } from './src/popper-utils'
|
|
21
22
|
import { log } from './src/log'
|
|
22
23
|
import { hooks } from './src/hooks'
|
|
23
24
|
import { useFns } from './src/useFns'
|
|
@@ -111,6 +112,7 @@ export const VxeUI = Object.assign(VxeCore, {
|
|
|
111
112
|
baseUtils,
|
|
112
113
|
domUtils,
|
|
113
114
|
scrollbarUtils,
|
|
115
|
+
popperUtils,
|
|
114
116
|
|
|
115
117
|
globalStore,
|
|
116
118
|
|
|
@@ -149,6 +151,7 @@ export * from './src/permission'
|
|
|
149
151
|
export * from './src/base-utils'
|
|
150
152
|
export * from './src/dom-utils'
|
|
151
153
|
export * from './src/scrollbar-utils'
|
|
154
|
+
export * from './src/popper-utils'
|
|
152
155
|
|
|
153
156
|
export * from './src/dataStore'
|
|
154
157
|
|
|
@@ -24,5 +24,20 @@ export const baseUtils: VxeBaseUtils = {
|
|
|
24
24
|
*/
|
|
25
25
|
getDefVal (value, defVal) {
|
|
26
26
|
return XEUtils.eqNull(value) ? defVal : value
|
|
27
|
+
},
|
|
28
|
+
/**
|
|
29
|
+
* 判断是否启用
|
|
30
|
+
*/
|
|
31
|
+
isEnabled (conf: any) {
|
|
32
|
+
return !!(conf && conf.enabled !== false)
|
|
33
|
+
},
|
|
34
|
+
/**
|
|
35
|
+
* 用于开关类型的配置项
|
|
36
|
+
* 局部启用规则:conf={}
|
|
37
|
+
* 局部禁用规则:conf={enabled:false}
|
|
38
|
+
* 全局默认启用规则:conf.enabled=true
|
|
39
|
+
*/
|
|
40
|
+
hasEnableConf (conf, opts) {
|
|
41
|
+
return !!(opts && (conf ? opts.enabled !== false : opts.enabled))
|
|
27
42
|
}
|
|
28
43
|
}
|
|
@@ -3,7 +3,67 @@ import XEUtils from 'xe-utils'
|
|
|
3
3
|
|
|
4
4
|
import { VxeDomUtils } from '../../types'
|
|
5
5
|
|
|
6
|
+
const reClsMap: { [key: string]: any } = {}
|
|
7
|
+
|
|
8
|
+
function getClsRE (cls: any) {
|
|
9
|
+
if (!reClsMap[cls]) {
|
|
10
|
+
reClsMap[cls] = new RegExp(`(?:^|\\s)${cls}(?!\\S)`, 'g')
|
|
11
|
+
}
|
|
12
|
+
return reClsMap[cls]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 判断元素是否包含 class
|
|
17
|
+
*/
|
|
18
|
+
function hasClass (elem: any, cls: any) {
|
|
19
|
+
if (elem) {
|
|
20
|
+
if (elem.classList) {
|
|
21
|
+
return elem.classList.contains(cls)
|
|
22
|
+
}
|
|
23
|
+
return !!(elem.className && elem.className.match && elem.className.match(getClsRE(cls)))
|
|
24
|
+
}
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 给元素删除 class
|
|
30
|
+
*/
|
|
31
|
+
function removeClass (elem: any, cls: any) {
|
|
32
|
+
if (elem && hasClass(elem, cls)) {
|
|
33
|
+
elem.className = elem.className.replace(getClsRE(cls), '')
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
6
37
|
export const domUtils: VxeDomUtils = {
|
|
38
|
+
/**
|
|
39
|
+
* 判断是否像素px单位 '100px' | 100
|
|
40
|
+
*/
|
|
41
|
+
isPx (val: any) {
|
|
42
|
+
return val && /^\d+(\.\d+)?(px)?$/.test(val)
|
|
43
|
+
},
|
|
44
|
+
/**
|
|
45
|
+
* 判断是否百分比%单位 '100%'
|
|
46
|
+
*/
|
|
47
|
+
isScale (val: any) {
|
|
48
|
+
return val && /^\d+(\.\d+)?%$/.test(val)
|
|
49
|
+
},
|
|
50
|
+
/**
|
|
51
|
+
* 判断元素是否包含 class
|
|
52
|
+
*/
|
|
53
|
+
hasClass,
|
|
54
|
+
/**
|
|
55
|
+
* 给元素删除 class
|
|
56
|
+
*/
|
|
57
|
+
removeClass,
|
|
58
|
+
/**
|
|
59
|
+
* 给元素增加 class
|
|
60
|
+
*/
|
|
61
|
+
addClass (elem: any, cls: string) {
|
|
62
|
+
if (elem && !hasClass(elem, cls)) {
|
|
63
|
+
removeClass(elem, cls)
|
|
64
|
+
elem.className = elem.className + ' ' + cls
|
|
65
|
+
}
|
|
66
|
+
},
|
|
7
67
|
/**
|
|
8
68
|
* 生成 className
|
|
9
69
|
*/
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import XEUtils from 'xe-utils'
|
|
2
|
+
|
|
3
|
+
import type { VxePopperUtils, VxePopperOptions } from '../../types'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 获取包裹容器的元素
|
|
7
|
+
*/
|
|
8
|
+
function getWrapperElement (panelElem: HTMLElement | null | undefined) {
|
|
9
|
+
if (!panelElem) {
|
|
10
|
+
return null
|
|
11
|
+
}
|
|
12
|
+
const bodyEl = document.body
|
|
13
|
+
const parentEl = panelElem.parentElement
|
|
14
|
+
return (parentEl === bodyEl ? document.documentElement : parentEl) || null
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* 获取插入到指定容器的元素或字符串
|
|
19
|
+
*/
|
|
20
|
+
function getAppendSelector (appendTo: string | HTMLElement | ((params: any) => string | HTMLElement) | undefined) {
|
|
21
|
+
const selectElem = appendTo && XEUtils.isFunction(appendTo) ? appendTo({}) : appendTo
|
|
22
|
+
return selectElem || 'body'
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 获取插入到指定容器的元素
|
|
27
|
+
*/
|
|
28
|
+
function getAppendElement (appendTo: string | HTMLElement | ((params: any) => string | HTMLElement) | undefined) {
|
|
29
|
+
const selectElem = getAppendSelector(appendTo)
|
|
30
|
+
if (XEUtils.isString(selectElem)) {
|
|
31
|
+
return document.querySelector<HTMLElement>(selectElem) || document.body
|
|
32
|
+
}
|
|
33
|
+
return selectElem
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const popperUtils: VxePopperUtils = {
|
|
37
|
+
/**
|
|
38
|
+
* 更新位置
|
|
39
|
+
*/
|
|
40
|
+
updatePlacement (targetElem: HTMLElement | null | undefined, panelElem: HTMLElement | null | undefined, options: VxePopperOptions) {
|
|
41
|
+
const { defaultTop, defaultLeft, placement, defaultPlacement, appendTo, teleportTo, marginSize, isMinWidth } = Object.assign({
|
|
42
|
+
appendTo: '',
|
|
43
|
+
teleportTo: false,
|
|
44
|
+
marginSize: 18,
|
|
45
|
+
isMinWidth: true
|
|
46
|
+
}, options)
|
|
47
|
+
let panelPlacement: 'top' | 'bottom' = 'bottom'
|
|
48
|
+
let top: number | '' = ''
|
|
49
|
+
let bottom: number | '' = ''
|
|
50
|
+
let left = 0
|
|
51
|
+
let minWidth: number | '' = ''
|
|
52
|
+
let arrowLeft: number | '' = ''
|
|
53
|
+
const stys: Record<string, string> = {}
|
|
54
|
+
if (panelElem && targetElem) {
|
|
55
|
+
const bodyEl = document.body
|
|
56
|
+
const parentWrapperEl = getWrapperElement(teleportTo ? getAppendElement(appendTo) : panelElem)
|
|
57
|
+
if (parentWrapperEl) {
|
|
58
|
+
const targetWidth = targetElem.offsetWidth
|
|
59
|
+
const targetHeight = targetElem.offsetHeight
|
|
60
|
+
const panelWidth = panelElem.offsetWidth
|
|
61
|
+
const panelHeight = panelElem.offsetHeight
|
|
62
|
+
|
|
63
|
+
const parentWrapperRect = parentWrapperEl.getBoundingClientRect()
|
|
64
|
+
const panelRect = panelElem.getBoundingClientRect()
|
|
65
|
+
const targetRect = targetElem.getBoundingClientRect()
|
|
66
|
+
const visibleHeight = bodyEl.clientHeight
|
|
67
|
+
const visibleWidth = bodyEl.clientWidth
|
|
68
|
+
|
|
69
|
+
const parentWrapperScrollLeft = parentWrapperEl.scrollLeft
|
|
70
|
+
const parentWrapperScrollTop = parentWrapperEl.scrollTop
|
|
71
|
+
const parentWrapperOffsetLeft = parentWrapperRect.left
|
|
72
|
+
const parentWrapperOffsetTop = parentWrapperRect.top
|
|
73
|
+
const targetLeft = targetRect.left
|
|
74
|
+
const targetTop = targetRect.top
|
|
75
|
+
|
|
76
|
+
minWidth = targetElem.offsetWidth
|
|
77
|
+
|
|
78
|
+
if (teleportTo) {
|
|
79
|
+
left = (defaultLeft || (targetLeft - (panelWidth - targetWidth) / 2)) - parentWrapperScrollLeft
|
|
80
|
+
top = (defaultTop || (targetTop + targetHeight)) - parentWrapperScrollTop
|
|
81
|
+
if (placement === 'top') {
|
|
82
|
+
panelPlacement = 'top'
|
|
83
|
+
top = targetTop - panelHeight
|
|
84
|
+
} else if (!placement) {
|
|
85
|
+
if (defaultPlacement === 'top') {
|
|
86
|
+
panelPlacement = 'top'
|
|
87
|
+
if (!defaultTop) {
|
|
88
|
+
top = targetTop - panelHeight
|
|
89
|
+
}
|
|
90
|
+
// 如果上面不够放,则向下
|
|
91
|
+
if (top < marginSize) {
|
|
92
|
+
panelPlacement = 'bottom'
|
|
93
|
+
top = targetTop + targetHeight
|
|
94
|
+
}
|
|
95
|
+
// 如果下面不够放,则向上(优先)
|
|
96
|
+
if (top + panelHeight + marginSize > visibleHeight) {
|
|
97
|
+
panelPlacement = 'top'
|
|
98
|
+
top = targetTop - panelHeight
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
// 如果下面不够放,则向上
|
|
102
|
+
if (top + panelHeight + marginSize > visibleHeight) {
|
|
103
|
+
panelPlacement = 'top'
|
|
104
|
+
top = targetTop - panelHeight
|
|
105
|
+
}
|
|
106
|
+
// 如果上面不够放,则向下(优先)
|
|
107
|
+
if (top < marginSize) {
|
|
108
|
+
panelPlacement = 'bottom'
|
|
109
|
+
top = targetTop + targetHeight
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// 如果溢出右边
|
|
114
|
+
if (left + panelWidth + marginSize > visibleWidth) {
|
|
115
|
+
left -= left + panelWidth + marginSize - visibleWidth
|
|
116
|
+
}
|
|
117
|
+
// 如果溢出左边
|
|
118
|
+
if (left < marginSize) {
|
|
119
|
+
left = marginSize
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 偏移
|
|
123
|
+
top -= parentWrapperOffsetTop
|
|
124
|
+
left -= parentWrapperOffsetLeft
|
|
125
|
+
} else {
|
|
126
|
+
if (placement === 'top') {
|
|
127
|
+
panelPlacement = 'top'
|
|
128
|
+
bottom = targetHeight
|
|
129
|
+
} else if (!placement) {
|
|
130
|
+
// 如果下面不够放,则向上
|
|
131
|
+
top = targetHeight
|
|
132
|
+
if (targetTop + targetHeight + panelHeight + marginSize > visibleHeight) {
|
|
133
|
+
// 如果上面不够放,则向下(优先)
|
|
134
|
+
if (targetTop - targetHeight - panelHeight > marginSize) {
|
|
135
|
+
panelPlacement = 'top'
|
|
136
|
+
top = ''
|
|
137
|
+
bottom = targetHeight
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// 是否超出右侧
|
|
142
|
+
if (panelRect.left + panelRect.width + marginSize > visibleWidth) {
|
|
143
|
+
left = -(panelRect.left + panelRect.width + marginSize - visibleWidth)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (XEUtils.isNumber(top)) {
|
|
147
|
+
stys.top = top + 'px'
|
|
148
|
+
}
|
|
149
|
+
if (XEUtils.isNumber(bottom)) {
|
|
150
|
+
stys.bottom = bottom + 'px'
|
|
151
|
+
}
|
|
152
|
+
if (XEUtils.isNumber(left)) {
|
|
153
|
+
stys.left = left + 'px'
|
|
154
|
+
}
|
|
155
|
+
if (isMinWidth && XEUtils.isNumber(minWidth)) {
|
|
156
|
+
stys.minWidth = minWidth + 'px'
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 箭头
|
|
160
|
+
if (left === targetLeft) {
|
|
161
|
+
if (targetWidth <= panelWidth) {
|
|
162
|
+
arrowLeft = targetWidth / 2
|
|
163
|
+
}
|
|
164
|
+
} else if (left < targetLeft) {
|
|
165
|
+
if (left + panelWidth > targetLeft + targetWidth) {
|
|
166
|
+
arrowLeft = (targetLeft - left) + targetWidth / 2
|
|
167
|
+
} else {
|
|
168
|
+
arrowLeft = (targetLeft - left) + (panelWidth - (targetLeft - left)) / 2
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
top: top || 0,
|
|
175
|
+
bottom: bottom || 0,
|
|
176
|
+
left: left || 0,
|
|
177
|
+
arrowLeft: arrowLeft || 0,
|
|
178
|
+
style: stys,
|
|
179
|
+
placement: panelPlacement
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
/**
|
|
183
|
+
* 获取包裹容器的元素
|
|
184
|
+
*/
|
|
185
|
+
getWrapperElement,
|
|
186
|
+
/**
|
|
187
|
+
* 获取插入到指定容器的元素或字符串
|
|
188
|
+
*/
|
|
189
|
+
getAppendSelector,
|
|
190
|
+
/**
|
|
191
|
+
* 获取插入到指定容器的元素
|
|
192
|
+
*/
|
|
193
|
+
getAppendElement
|
|
194
|
+
}
|
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
type Nullish = null | undefined
|
|
3
3
|
export type VxeBaseEmptyValue = '' | Nullish
|
|
4
4
|
|
|
5
|
+
interface EnableConfOptions {
|
|
6
|
+
enabled?: boolean
|
|
7
|
+
}
|
|
8
|
+
|
|
5
9
|
export interface VxeBaseUtils {
|
|
6
10
|
/**
|
|
7
11
|
* 转成字符串
|
|
@@ -19,4 +23,18 @@ export interface VxeBaseUtils {
|
|
|
19
23
|
* @param defVal
|
|
20
24
|
*/
|
|
21
25
|
getDefVal<T = any, D = any>(value: T, defVal: D): T | D
|
|
26
|
+
/**
|
|
27
|
+
* 判断配置项是否启用
|
|
28
|
+
* @param conf
|
|
29
|
+
*/
|
|
30
|
+
isEnabled(conf: EnableConfOptions): boolean
|
|
31
|
+
/**
|
|
32
|
+
* 用于判断开关类型的配置项
|
|
33
|
+
* 局部启用规则:conf={}
|
|
34
|
+
* 局部禁用规则:conf={enabled:false}
|
|
35
|
+
* 全局默认启用规则:conf.enabled=true
|
|
36
|
+
* @param conf
|
|
37
|
+
* @param opts
|
|
38
|
+
*/
|
|
39
|
+
hasEnableConf(conf: EnableConfOptions, opts: EnableConfOptions): boolean
|
|
22
40
|
}
|
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
|
|
2
2
|
export interface VxeDomUtils {
|
|
3
|
+
/**
|
|
4
|
+
* 判断是否像素px单位 '100px' | 100
|
|
5
|
+
* @param val
|
|
6
|
+
*/
|
|
7
|
+
isPx(val: any): boolean
|
|
8
|
+
/**
|
|
9
|
+
* 判断是否百分比%单位 '100%'
|
|
10
|
+
* @param val
|
|
11
|
+
*/
|
|
12
|
+
isScale(val: any): boolean
|
|
13
|
+
/**
|
|
14
|
+
* 判断元素是否包含 class
|
|
15
|
+
* @param elem
|
|
16
|
+
* @param cls
|
|
17
|
+
*/
|
|
18
|
+
hasClass(elem: HTMLElement, cls: string): boolean
|
|
19
|
+
/**
|
|
20
|
+
* 给元素删除 class
|
|
21
|
+
* @param elem
|
|
22
|
+
* @param cls
|
|
23
|
+
*/
|
|
24
|
+
removeClass(elem: HTMLElement, cls: string): void
|
|
25
|
+
/**
|
|
26
|
+
* 给元素增加 class
|
|
27
|
+
* @param elem
|
|
28
|
+
* @param cls
|
|
29
|
+
*/
|
|
30
|
+
addClass(elem: HTMLElement, cls: string): void
|
|
3
31
|
/**
|
|
4
32
|
* 生成 className
|
|
5
33
|
* @param staticClassNames
|
package/types/core/index.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ import { VxeGlobalPermission } from './permission'
|
|
|
17
17
|
import { VxeBaseUtils } from './base-utils'
|
|
18
18
|
import { VxeDomUtils } from './dom-utils'
|
|
19
19
|
import { VxeScrollbarUtils } from './scrollbar-utils'
|
|
20
|
+
import { VxePopperUtils } from './popper-utils'
|
|
20
21
|
import { VxeGlobalComponentMethod, VxeGlobalGetComponentMethod, VxeGlobalHasComponentMethod } from './components'
|
|
21
22
|
import { VxeGlobalUseFns } from './useFn'
|
|
22
23
|
import { VxeGlobalHooks } from './hooks'
|
|
@@ -76,6 +77,7 @@ export const permission: VxeGlobalPermission
|
|
|
76
77
|
export const baseUtils: VxeBaseUtils
|
|
77
78
|
export const domUtils: VxeDomUtils
|
|
78
79
|
export const scrollbarUtils: VxeScrollbarUtils
|
|
80
|
+
export const popperUtils: VxePopperUtils
|
|
79
81
|
|
|
80
82
|
export const globalEvents: VxeGlobalEvents
|
|
81
83
|
|
|
@@ -223,6 +225,10 @@ export interface VxeUIExport {
|
|
|
223
225
|
* 滚动条工具函数
|
|
224
226
|
*/
|
|
225
227
|
scrollbarUtils: VxeScrollbarUtils
|
|
228
|
+
/**
|
|
229
|
+
* 弹出元素定位工具函数
|
|
230
|
+
*/
|
|
231
|
+
popperUtils: VxePopperUtils
|
|
226
232
|
|
|
227
233
|
/**
|
|
228
234
|
* 全局事件管理
|
|
@@ -309,6 +315,7 @@ export * from './permission'
|
|
|
309
315
|
export * from './base-utils'
|
|
310
316
|
export * from './dom-utils'
|
|
311
317
|
export * from './scrollbar-utils'
|
|
318
|
+
export * from './popper-utils'
|
|
312
319
|
|
|
313
320
|
export * from './log'
|
|
314
321
|
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface VxePopperOptions {
|
|
2
|
+
defaultTop?: number
|
|
3
|
+
defaultLeft?: number
|
|
4
|
+
placement?: '' | 'top' | 'bottom' | null
|
|
5
|
+
defaultPlacement?: '' | 'top' | 'bottom' | null
|
|
6
|
+
appendTo?: string | HTMLElement | ((params: any) => string | HTMLElement)
|
|
7
|
+
teleportTo?: boolean
|
|
8
|
+
marginSize?: number
|
|
9
|
+
isMinWidth?: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface VxePopperPlacementResult {
|
|
13
|
+
top: number
|
|
14
|
+
bottom: number
|
|
15
|
+
left: number
|
|
16
|
+
arrowLeft: number
|
|
17
|
+
style: Record<string, string>
|
|
18
|
+
placement: 'top' | 'bottom'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface VxePopperUtils {
|
|
22
|
+
/**
|
|
23
|
+
* 更新位置
|
|
24
|
+
* @param targetElem
|
|
25
|
+
* @param panelElem
|
|
26
|
+
* @param options
|
|
27
|
+
*/
|
|
28
|
+
updatePlacement (targetElem: HTMLElement | null | undefined, panelElem: HTMLElement | null | undefined, options: VxePopperOptions): VxePopperPlacementResult
|
|
29
|
+
/**
|
|
30
|
+
* 获取包裹容器的元素
|
|
31
|
+
* @param panelElem
|
|
32
|
+
*/
|
|
33
|
+
getWrapperElement (panelElem: HTMLElement | null | undefined): HTMLElement | null
|
|
34
|
+
/**
|
|
35
|
+
* 获取插入到指定容器的元素或字符串
|
|
36
|
+
* @param appendTo
|
|
37
|
+
*/
|
|
38
|
+
getAppendSelector (appendTo: string | HTMLElement | ((params: any) => string | HTMLElement) | undefined): HTMLElement | string
|
|
39
|
+
/**
|
|
40
|
+
* 获取插入到指定容器的元素
|
|
41
|
+
* @param appendTo
|
|
42
|
+
*/
|
|
43
|
+
getAppendElement (appendTo: string | HTMLElement | ((params: any) => string | HTMLElement) | undefined): HTMLElement | null
|
|
44
|
+
}
|