/** * 移动端工具函数 */ /** * 检测是否为移动设备 */ export function isMobile() { return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || window.innerWidth < 768 } /** * 检测是否为iOS设备 */ export function isIOS() { return /iPad|iPhone|iPod/.test(navigator.userAgent) } /** * 检测是否为Android设备 */ export function isAndroid() { return /Android/.test(navigator.userAgent) } /** * 获取设备类型 */ export function getDeviceType() { if (isMobile()) { if (isIOS()) return 'ios' if (isAndroid()) return 'android' return 'mobile' } return 'desktop' } /** * 设置移动端视口 */ export function setMobileViewport() { if (isMobile()) { const viewport = document.querySelector('meta[name="viewport"]') if (viewport) { viewport.setAttribute('content', 'width=device-width, initial-scale=1, maximum-scale=5, minimum-scale=1, user-scalable=yes, viewport-fit=cover') } } } /** * 防止iOS双击缩放 */ export function preventDoubleTapZoom() { if (isIOS()) { let lastTouchEnd = 0 document.addEventListener('touchend', (event) => { const now = Date.now() if (now - lastTouchEnd <= 300) { event.preventDefault() } lastTouchEnd = now }, false) } } /** * 优化移动端滚动 */ export function optimizeMobileScroll() { if (isMobile()) { // 添加平滑滚动 document.documentElement.style.scrollBehavior = 'smooth' // 优化触摸滚动 const style = document.createElement('style') style.textContent = ` * { -webkit-overflow-scrolling: touch; } ` document.head.appendChild(style) } } /** * 设置安全区域适配(iOS刘海屏) */ export function setSafeArea() { if (isIOS()) { const style = document.createElement('style') style.textContent = ` .safe-area-top { padding-top: env(safe-area-inset-top); } .safe-area-bottom { padding-bottom: env(safe-area-inset-bottom); } .safe-area-left { padding-left: env(safe-area-inset-left); } .safe-area-right { padding-right: env(safe-area-inset-right); } ` document.head.appendChild(style) } } /** * 移动端初始化 */ export function initMobile() { setMobileViewport() preventDoubleTapZoom() optimizeMobileScroll() setSafeArea() } /** * 格式化移动端表格数据为卡片数据 */ export function formatTableToCards(tableData, columns) { return tableData.map(row => { const card = {} columns.forEach(column => { if (column.visible !== false) { const value = column.prop ? getNestedValue(row, column.prop) : '' card[column.prop || column.key] = { label: column.label, value: column.formatter ? column.formatter(row, column, value) : value, type: column.type || 'text' } } }) return { ...row, _cardData: card } }) } /** * 获取嵌套对象值 */ function getNestedValue(obj, path) { return path.split('.').reduce((o, p) => o && o[p], obj) } /** * 移动端表格列配置 */ export function getMobileTableColumns(columns) { return columns .filter(col => col.visible !== false) .map(col => ({ ...col, label: col.label || col.prop, prop: col.prop || col.key })) } /** * 防抖函数 */ export function debounce(func, wait) { let timeout return function executedFunction(...args) { const later = () => { clearTimeout(timeout) func(...args) } clearTimeout(timeout) timeout = setTimeout(later, wait) } } /** * 节流函数 */ export function throttle(func, limit) { let inThrottle return function(...args) { if (!inThrottle) { func.apply(this, args) inThrottle = true setTimeout(() => inThrottle = false, limit) } } } /** * 移动端图片懒加载 */ export function lazyLoadImages() { if ('IntersectionObserver' in window) { const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target img.src = img.dataset.src img.classList.remove('lazy') imageObserver.unobserve(img) } }) }) document.querySelectorAll('img.lazy').forEach(img => { imageObserver.observe(img) }) } } export default { isMobile, isIOS, isAndroid, getDeviceType, setMobileViewport, preventDoubleTapZoom, optimizeMobileScroll, setSafeArea, initMobile, formatTableToCards, getMobileTableColumns, debounce, throttle, lazyLoadImages }