fix: 手机保存图片使用 navigator.share 直接保存到相册
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 5s
Test / build-check (push) Successful in 4s
PR Preview / test (pull_request) Successful in 4s
PR Preview / deploy-preview (pull_request) Successful in 15s
Test / e2e-test (push) Failing after 52s
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 5s
Test / build-check (push) Successful in 4s
PR Preview / test (pull_request) Successful in 4s
PR Preview / deploy-preview (pull_request) Successful in 15s
Test / e2e-test (push) Failing after 52s
- 新增 composables/useSaveImage.js
- saveImageFromUrl: data URL → 手机分享/桌面下载
- captureAndSave: DOM元素 → html2canvas → 保存
- saveCanvasImage: canvas → 保存
- RecipeDetailOverlay: saveImage 改用 saveImageFromUrl
- OilReference: saveModalImage 改用 captureAndSave
- 手机端调用 navigator.share({files}) 弹出系统分享面板
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
76
frontend/src/composables/useSaveImage.js
Normal file
76
frontend/src/composables/useSaveImage.js
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* Save image — on mobile use native share (save to photos),
|
||||
* on desktop trigger download.
|
||||
*/
|
||||
|
||||
const isMobile = () => /iPhone|iPad|iPod|Android/i.test(navigator.userAgent)
|
||||
|
||||
/**
|
||||
* Save a data URL or blob as image.
|
||||
* Mobile: navigator.share → save to photos
|
||||
* Desktop: download link
|
||||
*/
|
||||
export async function saveImageFromUrl(dataUrl, filename) {
|
||||
if (isMobile() && navigator.canShare) {
|
||||
try {
|
||||
const res = await fetch(dataUrl)
|
||||
const blob = await res.blob()
|
||||
const file = new File([blob], filename + '.png', { type: 'image/png' })
|
||||
if (navigator.canShare({ files: [file] })) {
|
||||
await navigator.share({ files: [file] })
|
||||
return true
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
// Desktop fallback
|
||||
const a = document.createElement('a')
|
||||
a.href = dataUrl
|
||||
a.download = filename + '.png'
|
||||
a.click()
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Capture a DOM element as image and save it.
|
||||
*/
|
||||
export async function captureAndSave(element, filename) {
|
||||
const { default: html2canvas } = await import('html2canvas')
|
||||
// Hide buttons during capture
|
||||
const buttons = element.querySelectorAll('button')
|
||||
buttons.forEach(b => b.style.display = 'none')
|
||||
try {
|
||||
const canvas = await html2canvas(element, {
|
||||
scale: 2,
|
||||
backgroundColor: '#ffffff',
|
||||
useCORS: true,
|
||||
})
|
||||
buttons.forEach(b => b.style.display = '')
|
||||
return saveCanvasImage(canvas, filename)
|
||||
} catch {
|
||||
buttons.forEach(b => b.style.display = '')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a canvas element as image.
|
||||
*/
|
||||
export async function saveCanvasImage(canvas, filename) {
|
||||
if (isMobile() && navigator.canShare) {
|
||||
try {
|
||||
const blob = await new Promise(r => canvas.toBlob(r, 'image/png'))
|
||||
const file = new File([blob], filename + '.png', { type: 'image/png' })
|
||||
if (navigator.canShare({ files: [file] })) {
|
||||
await navigator.share({ files: [file] })
|
||||
return true
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
// Desktop fallback
|
||||
const url = canvas.toDataURL('image/png')
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = filename + '.png'
|
||||
a.click()
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user