canUseDom
function canUseDom() {return !!(typeof window !== 'undefined' && window.document && window.document.createElement);}
isStyleNameSupport 浏览器是否支持该样式名称
document.documentElement.style可以访问到的就是支持的
const isStyleNameSupport = (styleName: string | string[]): boolean => {if (canUseDom() && window.document.documentElement) {const styleNameList = Array.isArray(styleName) ? styleName : [styleName];const { documentElement } = window.document;return styleNameList.some(name => name in documentElement.style);}return false;};
isStyleValueSupport 浏览器是否支持该样式值
const isStyleValueSupport = (styleName: string, value: any) => {if (!isStyleNameSupport(styleName)) {return false;}const ele = document.createElement('div');const origin = ele.style[styleName];ele.style[styleName] = value;return ele.style[styleName] !== origin;};
isStyleSupport = isStyleNameSupport & isStyleValueSupport
isStyleNameSupport & isStyleValueSupport都支持就行
getScrollBarSize 计算当前浏览器显示滚动条后占用宽度
// 创建内外两个boxconst inner = document.createElement('div');inner.style.width = '100%';inner.style.height = '200px';const outer = document.createElement('div');const outerStyle = outer.style;// 给外层设定样式 不能影响到正常内容显示 所以不可见 不能遮挡原有事件区域 所以事件透传// 绝对定位 overflow=hidden 外部高度大于内部高度 触发滚动条outerStyle.position = 'absolute';outerStyle.top = '0';outerStyle.left = '0';outerStyle.pointerEvents = 'none';outerStyle.visibility = 'hidden';outerStyle.width = '200px';outerStyle.height = '150px';outerStyle.overflow = 'hidden';outer.appendChild(inner);document.body.appendChild(outer);// 完全包裹的宽度 offsetWidth 没有滚动条的宽度const widthContained = inner.offsetWidth;// 带有滚动条的宽度outer.style.overflow = 'scroll';let widthScroll = inner.offsetWidth;// 如果有滚动条时两者都能相等 说明offsetWidth不能用来确定滚动条宽度// 用box的clientWidth来作为外宽 clientWidth计算box内宽度 不包括滚动条宽度if (widthContained === widthScroll) {widthScroll = outer.clientWidth;}// 移除冗余domdocument.body.removeChild(outer);// 内部非滚动条状态时的offsetWidth - 有滚动条时的宽度 = 滚动条占用宽度cached = widthContained - widthScroll;
ScrollLocker 锁定当前页面不可滚动 在modal弹窗时候可选背景页是否固定
思路:
- overflow: hidden;
- 上锁的时候新旧样式叠加覆盖旧样式 记录旧样式样式表
- 注意计算当前滚动条宽度
- 保证不会闪屏
- 多个的时候不会重复处理
- 解锁后需要还原 所以在设置locker样式的时候 需要记住旧样式 解锁的时候把整个样式用旧样式覆盖回去
// 新旧样式累加oldStyle = setStyle({width: scrollBarSize !== 0 ? `calc(100% - ${scrollBarSize}px)` : undefined,overflow: 'hidden',overflowX: 'hidden',overflowY: 'hidden',},{element: container,},),// 恢复setStyle(cacheStyle.get(container), { element: container });
raf
封装了一个请求requestAnimationFrame请求和取消请求的工具
为什么需要这么些工具
某些情况下是跳脱于react体系的,比方说element.style.height = 90
