vue3 html2canvas:^1.0.0-rc.4(目前来说相对稳定的版本)
- 直接上代码吧
<template>
<van-popup
v-model:show="visibles"
position="bottom"
:style="{
'background-color': 'transparent',
width: '100%',
height: '100vh',
'box-sizing': 'border-box',
}"
:overlay-style="{
backgroundColor: 'rgba(0, 0, 0, 0.5)',
}"
ref="pup"
@open="onOpen"
@close="onClose"
@opened="onOpened"
@closed="onClosed"
@click="onClosed"
teleport="body"
>
<!-- 海报主体内容 -->
<div class="haipbox" ref="PosterHtml" v-show="!flag" @click.stop="() => {}">
<img class="b1" src="@assets/images/readIndex/hpimg1.jpg" alt="" />
<div class="b2">
<div class="basePop2">
<img class="bg6" src="@assets/images/readIndex/sb1.jpg" />
<!-- 信件部分 -->
<div class="mesBox">
<img class="tag tag1" src="@assets/images/readIndex/tag1.png" />
<div class="info">
<div class="touxiangimg">
<img class="atvar" :src="Items?.atvar" />
</div>
<div class="rbox">
<div class="name">{{ Items.name }}</div>
<div class="desc">{{ Items.desc }}</div>
</div>
</div>
<!-- 信的内容 -->
<div v-if="Items.message.length > 0" class="mes-content">
<div v-for="(pm, px) in Items.message" class="mesp" :key="px">
{{ pm }}
</div>
</div>
<div v-else class="mes-content">
<div class="mesp">{{ Items.famousword }}</div>
</div>
</div>
<!-- 书籍部分 -->
<div v-if="Items.bookList.length > 0" class="bookdesc-box">
<img class="tag tag2" src="@assets/images/readIndex/tag2.png" />
<van-image
class="bookimg"
alt=""
:src="Items.bookList[Idx].bookiamge"
>
<template v-slot:loading>
<van-loading type="spinner" size="20" />
</template>
</van-image>
<div class="rt-box">
<div class="bookname">{{ Items.bookList[Idx].bookname }}</div>
<div class="author">
<div class="tag3">作者</div>
{{ Items.bookList[Idx].author }}
</div>
<div class="tags">推荐理由</div>
<div class="descs">
{{ Items.bookList[Idx].recomends }}
</div>
</div>
</div>
</div>
<div class="hb-bottom">
<img src="@assets/images/readIndex/bg7.jpg" />
</div>
</div>
</div>
<!-- 绘制的海报图片,绘制前先隐藏 -->
<div v-show="flag" class="img-box" @click.stop="() => {}">
<img class="postImg" :src="posterImg" alt="" />
</div>
<div class="closebtn" @click="onClosed"></div>
</van-popup>
</template>
<script lang="ts">
import { defineComponent, nextTick, reactive, ref, toRefs, watch } from 'vue'
import html2canvas from 'html2canvas'
export default defineComponent({
props: {
visible: {
type: Boolean,
required: true,
default: false,
},
},
setup(_props, { emit }) {
const visibles = ref(_props.visible)
const PosterHtml = ref(null) as any
const pup = ref(null) as any
watch(
() => _props.visible,
n => {
visibles.value = n
if (!n) {
data.posterImg = ''
data.flag = false
}
if (n) {
nextTick(() => {
// 每次打开还原回顶部
pup.value.popupRef.value.scrollTop = 0
})
}
},
)
watch(
() => _props.Item,
n => {
Items.value = n
},
)
const onOpen = () => {
emit('open')
}
const onClose = () => {
emit('close')
}
const onOpened = () => {
emit('opened')
}
const onClosed = () => {
emit('closed')
}
const data = reactive({
posterImg: '', // 最终生成的海报图片
flag: false,
posterUrl: '', // upc返回的
})
// 保存图片
const saveImage = () => {}
/**
* 海报生成
* */
const createPoster = () => {
// 生成海报
const domObj = PosterHtml.value
// 清晰度关键 像素比
const dpi = DPR()
console.log(dpi)
html2canvas(domObj, {
useCORS: true, // 是否允许图片跨域
allowTaint: true,
scrollY: 0,
scrollX: 0,
logging: false, // 日志
width: domObj.offsetWidth, // 图片宽度
height: domObj.offsetHeight,
scale: dpi,
backgroundColor: 'transparent',
}).then(async canvas => {
Toast('生成海报成功~')
// 在微信里,可长按保存或转发
data.posterImg = canvas.toDataURL('image/jpeg')
// flag:生成后展示图片
data.flag = true
emit('showHp')
if (
isApp.value ||
navigator.userAgent.indexOf('UCBrowser') > -1 ||
navigator.userAgent.toLowerCase().toString().indexOf('qqbrowser') > -1
) {
const hbData = data.posterImg.split(',')
try {
const params = {
data: hbData[1],
// keepSrc: 'yes',
// readExif: 'no',
}
const res = (await startComentRepos.uploadQuickStream(
params,
)) as any
const resJson = JSON.parse(res)
console.log('文件', resJson)
data.posterUrl = resJson.files[0].url
console.log('posterUrl', data.posterUrl)
} catch (error) {
console.error(error)
}
// uc兼容
if (
navigator.userAgent.indexOf('UCBrowser') > -1 ||
navigator.userAgent.toLowerCase().toString().indexOf('qqbrowser') >
-1
) {
data.posterImg = data.posterUrl
}
}
// console.log('海报生成成功===>', data.posterImg)
})
}
// 获取像素比
const DPR = () => {
// 获取设备dpi
if (window.devicePixelRatio && window.devicePixelRatio > 1) {
return window.devicePixelRatio * 2
}
// 直接返回高像素比
return 8
}
const productHaibao = () => {
nextTick(() => {
Toast.loading({
duration: 0,
message: '海报生成中...',
forbidClick: true,
})
setTimeout(() => {
createPoster()
}, 600)
})
}
return {
pup,
productHaibao,
visibles,
DPR,
onOpen,
onClose,
onOpened,
onClosed,
saveImage,
PosterHtml,
createPoster,
...toRefs(data),
}
},
})
</script>
- 看看效果吧
- 附带几个坑点修复方案
- html-canvas生成海报参考这个地址:blog.csdn.net/qq_41227106…
- 文字下划线bug:修改源码搜索underline===>Math.round(text.bounds.top + baseline) 变成 Math.round(text.bounds.top + baseline + 2)