This commit is contained in:
Leo
2026-01-05 18:32:29 +08:00
parent 1a4e56bfed
commit a3291f7a31
22 changed files with 3180 additions and 23 deletions

230
src/utils/mobile.js Normal file
View File

@@ -0,0 +1,230 @@
/**
* 移动端工具函数
*/
/**
* 检测是否为移动设备
*/
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
}