hookehuyr

fix(SharePoster): 修复首次生成海报时封面空白问题

移除生成中的提示注释,调整海报图片圆角样式
添加首次生成标志位,连续生成两次规避空白问题
修改离屏克隆背景为透明,避免白色背景影响视觉效果
......@@ -14,12 +14,12 @@
</div>
<!-- 生成中提示 -->
<div v-if="is_generating" class="text-center text-gray-500 text-sm mb-2">正在生成海报...</div>
<!-- <div v-if="is_generating" class="text-center text-gray-500 text-sm mb-2">正在生成海报...</div> -->
<!-- 海报区域:直接使用 Canvas 合成的图片,支持长按保存 -->
<!-- 当已生成海报图时,容器不再应用卡片边框与阴影,避免双重边框视觉效果;降级展示仍保留卡片样式 -->
<div :class="poster_img_src ? 'PosterCard mx-auto' : 'PosterCard bg-white rounded-xl overflow-hidden border border-gray-200 mx-auto'" ref="card_ref">
<img v-if="poster_img_src" :src="poster_img_src" alt="分享海报" class="w-full h-auto object-contain block" />
<img v-if="poster_img_src" :src="poster_img_src" alt="分享海报" class="w-full h-auto object-contain block rounded-xl overflow-hidden" />
<!-- 生成失败或尚未生成时的降级展示(可长按截图保存) -->
<div v-else>
<!-- 上部封面图 -->
......@@ -163,6 +163,11 @@ const card_ref = ref(null)
* @description 是否处于海报生成中状态,用于在弹窗内展示“正在生成海报...”提示。
*/
const is_generating = ref(false)
/**
* @var {import('vue').Ref<boolean>} has_generated_once
* @description 是否已在本组件生命周期内完成过生成;用于控制首次打开时执行两次生成以规避首屏封面空白问题。
*/
const has_generated_once = ref(false)
/** 标题/副标题/介绍 */
const title_text = computed(() => props.course?.title || '课程')
......@@ -347,7 +352,6 @@ async function compose_poster() {
const data_url = await toPng(clone, {
pixelRatio: pixel_ratio,
cacheBust: true,
backgroundColor: '#ffffff',
imagePlaceholder: placeholder,
fetchRequestInit: { mode: 'cors', cache: 'no-cache', credentials: 'omit' },
// 避免外层 margin 影响截图结果
......@@ -368,6 +372,27 @@ async function compose_poster() {
}
/**
* @function generate_on_open
* @description 弹窗首次打开时,连续生成两次;后续打开只生成一次。
* @returns {Promise<void>}
*/
async function generate_on_open() {
try {
if (!has_generated_once.value) {
await compose_poster()
// 短暂等待,确保图片与布局稳定后再次生成,规避首次封面空白
await new Promise(r => setTimeout(r, 120))
await compose_poster()
has_generated_once.value = true
} else {
await compose_poster()
}
} catch (_) {
// 忽略异常,compose_poster 已包含错误提示
}
}
/**
* @function create_offscreen_clone
* @description 创建一个离屏的卡片克隆用于稳定截图,避免受弹窗动画与布局影响。
* @param {HTMLElement} node 原始容器节点
......@@ -388,7 +413,7 @@ function create_offscreen_clone(node) {
overflow: 'hidden',
opacity: '0',
pointerEvents: 'none',
background: '#ffffff',
background: 'transparent',
zIndex: '-1000'
})
// 克隆节点样式校正,避免动画、阴影、滤镜干扰
......@@ -398,7 +423,9 @@ function create_offscreen_clone(node) {
margin: '0',
transform: 'none',
filter: 'none',
boxShadow: 'none'
boxShadow: 'none',
borderRadius: '16px',
overflow: 'hidden'
})
wrapper.appendChild(clone)
document.body.appendChild(wrapper)
......@@ -414,7 +441,7 @@ watch(show_proxy, (opened) => {
if (opened) {
if (is_generating.value) return
poster_img_src.value = ''
nextTick(() => compose_poster())
nextTick(() => generate_on_open())
}
})
......