思路:生成微信小程序码的时候,微信服务器返回的是图片二进制数据流,因此我们现在服务端将二进制流转换为base64进制数据流,然后返回给前端。前端将请求到的base64进制流转换进行下载。
这样可以有效避免需要通过访问图片url造成的跨域等等的一些列问题。
后端代码
这里以微信小程序码为例。其中$binary是二进制数据,$base64String为64位数据信息,其余代码根据自己需求书写
/**
* 生成学校小程序码的base64位数据流
* @return \sf\ViewModel\JsonModel
*/
public function schcodeAction()
{
$wx = new WeiXin(true);
$scene = POST::Int('sch_id'); // 参数获取,自己根据自己的写
$wxAppPage = SchoolInfo::$shareCodePage; // 自己根据自己的写
$binary = $wx->getAppShareQR($scene, $wxAppPage); // 请求微信服务器返回的二进制流数据,请求接口自己写
$base64String = 'data:' . getimagesizefromstring($binary)['mime'] . ';base64,' . chunk_split(base64_encode($binary)); // 关键::此处为二进制流转换为base64位
return $this->GetFailJSONModel(['info'=>$base64String]); // 数据返回,自己写
}
前端代码
html在这里就不进行书写了,理解万岁,点击事件触发download(),然后 this.codeData是请求回来的图片数据流
// 下载图片
download() {
downloadFile(this.detailInfo.sch_name ? this.detailInfo.sch_name : '二维码', this.codeData)
}
以下为封装代码,可以放在工具文件中,然后进行引入使用
/**
* base64图片下载
* @param {*} fileName 下载后的文件名称
* @param {*} content 内容
*/
export const downloadFile = (fileName, content) => {
const aLink = document.createElement('a')
const blob = base64ToBlob(content) // new Blob([content]);
const evt = document.createEvent('HTMLEvents')
evt.initEvent('click', true, true)// initEvent 不加后两个参数在FF下会报错 事件类型,是否冒泡,是否阻止浏览器的默认行为
aLink.download = fileName
aLink.href = URL.createObjectURL(blob)
aLink.click()
}
/**
* base64转blob
* @param {*} code base64位码
*/
const base64ToBlob = (code) => {
const parts = code.split(';base64,')
const contentType = parts[0].split(':')[1]
const raw = window.atob(parts[1])
const rawLength = raw.length
const uInt8Array = new Uint8Array(rawLength)
for (let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i)
}
return new Blob([uInt8Array], { type: contentType })
}