feat(P01): 迁移 Taro 小程序项目代码
- 迁移前端源码 (src/) - 迁移后端服务 (server/) - 迁移配置文件 (package.json, tsconfig.json 等) - 更新需求概要文档 - 更新架构设计文档 - 更新接口定义文档 - 更新环境配置文档 - 创建测试目录结构和配置 项目技术栈: - Taro 4.1.9 (跨端框架) - React 18 - TypeScript - NestJS (后端) - Tailwind CSS 4 - shadcn/ui 组件库
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import Taro from '@tarojs/taro'
|
||||
import { canUseDOM, isH5 } from './platform'
|
||||
|
||||
export type Rect = { left: number; top: number; width: number; height: number }
|
||||
|
||||
const toNumber = (v: unknown) => {
|
||||
if (typeof v === 'number') return v
|
||||
if (typeof v === 'string') {
|
||||
const n = parseFloat(v)
|
||||
return Number.isFinite(n) ? n : 0
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
const normalizeRect = (r: Record<string, unknown> | DOMRect | null | undefined): Rect | null => {
|
||||
if (!r) return null
|
||||
if ('left' in r && 'top' in r && 'width' in r && 'height' in r) {
|
||||
return {
|
||||
left: toNumber(r.left),
|
||||
top: toNumber(r.top),
|
||||
width: toNumber(r.width),
|
||||
height: toNumber(r.height),
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export const getViewport = () => {
|
||||
if (isH5() && canUseDOM()) {
|
||||
return { width: window.innerWidth, height: window.innerHeight }
|
||||
}
|
||||
try {
|
||||
const info = Taro.getSystemInfoSync()
|
||||
return {
|
||||
width: toNumber(info.windowWidth),
|
||||
height: toNumber(info.windowHeight),
|
||||
}
|
||||
} catch {
|
||||
return { width: 375, height: 667 }
|
||||
}
|
||||
}
|
||||
|
||||
const getRectH5 = (id: string): Rect | null => {
|
||||
if (!isH5() || !canUseDOM()) return null
|
||||
const el = document.getElementById(id)
|
||||
if (!el) return null
|
||||
const r = el.getBoundingClientRect()
|
||||
return normalizeRect(r)
|
||||
}
|
||||
|
||||
export const getRectById = (id: string): Promise<Rect | null> => {
|
||||
const h5Rect = getRectH5(id)
|
||||
if (h5Rect) return Promise.resolve(h5Rect)
|
||||
return new Promise(resolve => {
|
||||
const query = Taro.createSelectorQuery()
|
||||
query
|
||||
.select(`#${id}`)
|
||||
.boundingClientRect(res => {
|
||||
const rect = Array.isArray(res) ? res[0] : res
|
||||
if (rect && 'left' in rect) {
|
||||
resolve(normalizeRect(rect))
|
||||
} else {
|
||||
resolve(null)
|
||||
}
|
||||
})
|
||||
.exec()
|
||||
})
|
||||
}
|
||||
|
||||
export const computePosition = (params: {
|
||||
triggerRect: Rect
|
||||
contentRect: Rect
|
||||
align: 'start' | 'center' | 'end'
|
||||
side: 'top' | 'bottom' | 'left' | 'right'
|
||||
sideOffset: number
|
||||
}) => {
|
||||
const { triggerRect, contentRect, align, side, sideOffset } = params
|
||||
const { width: vw, height: vh } = getViewport()
|
||||
const margin = 8
|
||||
|
||||
const crossStart =
|
||||
side === 'left' || side === 'right' ? triggerRect.top : triggerRect.left
|
||||
const crossSize =
|
||||
side === 'left' || side === 'right'
|
||||
? triggerRect.height
|
||||
: triggerRect.width
|
||||
const contentCrossSize =
|
||||
side === 'left' || side === 'right'
|
||||
? contentRect.height
|
||||
: contentRect.width
|
||||
|
||||
const cross = (() => {
|
||||
if (align === 'start') return crossStart
|
||||
if (align === 'end') return crossStart + crossSize - contentCrossSize
|
||||
return crossStart + crossSize / 2 - contentCrossSize / 2
|
||||
})()
|
||||
|
||||
let left = 0
|
||||
let top = 0
|
||||
|
||||
if (side === 'bottom' || side === 'top') {
|
||||
left = cross
|
||||
top =
|
||||
side === 'bottom'
|
||||
? triggerRect.top + triggerRect.height + sideOffset
|
||||
: triggerRect.top - contentRect.height - sideOffset
|
||||
} else {
|
||||
top = cross
|
||||
left =
|
||||
side === 'right'
|
||||
? triggerRect.left + triggerRect.width + sideOffset
|
||||
: triggerRect.left - contentRect.width - sideOffset
|
||||
}
|
||||
|
||||
const maxLeft = Math.max(margin, vw - contentRect.width - margin)
|
||||
const maxTop = Math.max(margin, vh - contentRect.height - margin)
|
||||
|
||||
left = Math.min(Math.max(left, margin), maxLeft)
|
||||
top = Math.min(Math.max(top, margin), maxTop)
|
||||
|
||||
return { left, top }
|
||||
}
|
||||
Reference in New Issue
Block a user