@tencentcloud/chat-uikit-uniapp
Version:
TUIKit 是基于 IM SDK 实现的一套 UI 组件,其包含会话、聊天、群组、个人资料等功能,基于这些精心设计的 UI 组件,您可以快速构建优雅的、可靠的、可扩展的 Chat 应用。
157 lines (135 loc) • 4.49 kB
text/typescript
import { isIOS } from '@tencentcloud/universal-api';
const ua = navigator.userAgent;
function getScrollTypeByPlatform() {
if (isIOS) {
if (/Safari\//.test(ua) || /IOS 11_[0-3]\D/.test(ua)) {
// Safari IOS 11.0-11.3 exclude(`scrollTop`/`scrolIntoView` not working)
return 0;
}
// IOS: use `scrollTop`
return 1;
}
// Android: use `scrollIntoView`
return 2;
}
function createKeyboardHeightObserver(callback: (height: number) => void) {
const initialViewportHeight = window.innerHeight;
let lastKeyboardHeight = 0;
if (window.visualViewport) {
const handleViewportChange = () => {
const currentViewportHeight = window.visualViewport!.height;
const keyboardHeight = initialViewportHeight - currentViewportHeight;
if (Math.abs(keyboardHeight - lastKeyboardHeight) > 10) {
lastKeyboardHeight = keyboardHeight;
callback(keyboardHeight > 0 ? keyboardHeight : 0);
}
};
window.visualViewport.addEventListener('resize', handleViewportChange);
return () => {
window.visualViewport?.removeEventListener('resize', handleViewportChange);
};
}
const handleWindowResize = () => {
const currentHeight = window.innerHeight;
const keyboardHeight = initialViewportHeight - currentHeight;
if (Math.abs(keyboardHeight - lastKeyboardHeight) > 10) {
lastKeyboardHeight = keyboardHeight;
callback(keyboardHeight > 0 ? keyboardHeight : 0);
}
};
window.addEventListener('resize', handleWindowResize);
return () => {
window.removeEventListener('resize', handleWindowResize);
};
}
function adjustPageHeight(keyboardHeight: number) {
const possibleContainers = [
document.getElementById('app'),
document.querySelector('.app'),
document.querySelector('[data-app]'),
document.body,
];
const container = possibleContainers.find(el => el !== null) as HTMLElement;
if (!container) return;
if (keyboardHeight > 0) {
container.style.paddingBottom = '';
container.style.transition = '';
const timer = setTimeout(() => {
const activeElement = document.activeElement as HTMLElement;
if (activeElement && activeElement.scrollIntoView) {
const elementRect = activeElement.getBoundingClientRect();
const currentViewportHeight = window.visualViewport ? window.visualViewport.height : window.innerHeight;
if (elementRect.bottom > currentViewportHeight - 50) {
activeElement.scrollIntoView({
behavior: 'smooth',
block: 'end',
inline: 'nearest',
});
}
}
clearTimeout(timer);
}, 100);
} else {
container.style.paddingBottom = '';
const timer = setTimeout(() => {
container.style.transition = '';
clearTimeout(timer);
}, 250);
}
}
export default function riseInput(input: HTMLElement, target?: HTMLElement) {
const scrollType = getScrollTypeByPlatform();
let scrollTimer: ReturnType<typeof setTimeout>;
let keyboardObserver: (() => void) | null = null;
if (!target) {
// eslint-disable-next-line no-param-reassign
target = input;
}
const scrollIntoView = () => {
if (scrollType === 0) return;
if (scrollType === 1) {
document.body.scrollTop = document.body.scrollHeight;
} else {
target?.scrollIntoView(false);
}
};
if (isIOS) {
keyboardObserver = createKeyboardHeightObserver((keyboardHeight) => {
adjustPageHeight(keyboardHeight);
if (keyboardHeight > 0 && document.activeElement === input) {
const timer = setTimeout(() => {
input.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'nearest',
});
clearTimeout(timer);
}, 200);
}
});
}
input.addEventListener('focus', () => {
const timer = setTimeout(() => {
scrollIntoView();
clearTimeout(timer);
}, 300);
scrollTimer = setTimeout(scrollIntoView, 1000);
});
input.addEventListener('blur', () => {
clearTimeout(scrollTimer);
// Handle IOS issues about keyboard is hidden but page not refreshed
if (scrollType && isIOS) {
const timer = setTimeout(() => {
if (!keyboardObserver) {
document.body.scrollIntoView();
adjustPageHeight(0);
}
clearTimeout(timer);
}, 300);
}
});
return () => {
clearTimeout(scrollTimer);
keyboardObserver?.();
};
}