1.16更新
This commit is contained in:
parent
cf6df28e8c
commit
034744959f
91
components/bangbang-screenShot.vue
Normal file
91
components/bangbang-screenShot.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 当父组件传递的prop属性数据发生变化的时候 ,生成海报图片-->
|
||||
<view :prop="domId" :change:prop="html2canvas.emitData" class="html2canvas">
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { base64ToPath } from '@/utils/image-tools.js';
|
||||
export default {
|
||||
props: {
|
||||
domId: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted:function(){
|
||||
console.log("组件加载完成");
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 接收renderjs发回的数据
|
||||
async receiveRenderData(imgData) {
|
||||
let posterHeight=imgData.height;
|
||||
let posterWidth=imgData.width;
|
||||
let imgPath =await base64ToPath(imgData.imgVal, '.jpeg');
|
||||
this.$emit('renderFinish', {"posterPath":imgPath,"posterHeight":posterHeight,"posterWidth":posterWidth});
|
||||
uni.hideLoading();
|
||||
},
|
||||
showLoading() {
|
||||
uni.showLoading({
|
||||
title: "正在生成导出",
|
||||
icon: "none",
|
||||
mask: true,
|
||||
duration: 3000
|
||||
})
|
||||
},
|
||||
hideLoading() {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<script module="html2canvas" lang="renderjs">
|
||||
import html2canvas from 'html2canvas';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mounted:function(){
|
||||
console.log("视图层渲染完成");
|
||||
},
|
||||
methods: {
|
||||
// 发送数据到逻辑层,下面这里最好是加一个settimeout延迟,因为主界面数据还没加载渲染完成
|
||||
emitData(domId) {
|
||||
this.$ownerInstance.callMethod('showLoading', true);
|
||||
const dom = document.getElementById('poster');
|
||||
console.log("dom",dom);
|
||||
let width= dom.offsetWidth;
|
||||
let height=dom.offsetHeight;
|
||||
let windowHeight= uni.getSystemInfoSync().windowHeight;
|
||||
let windowWidth=uni.getSystemInfoSync().windowWidth;
|
||||
html2canvas(dom, {
|
||||
width:width,
|
||||
height:height,
|
||||
//scale:2.5, // 缩放倍数
|
||||
scrollY: 0, // html2canvas默认绘制视图内的页面,需要把scrollY,scrollX设置为0
|
||||
scrollX: 0,
|
||||
x:0,
|
||||
y:0,
|
||||
windowWidth:windowWidth,
|
||||
windowHeight:windowHeight,
|
||||
useCORS: true, //支持跨域,但好像没什么用
|
||||
}).then((canvas) => {
|
||||
let imgVal= canvas.toDataURL('image/png');
|
||||
this.$ownerInstance.callMethod('receiveRenderData',{imgVal:imgVal,height:height,width:width});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
91
components/bangbang-screenShot/bangbang-screenShot.vue
Normal file
91
components/bangbang-screenShot/bangbang-screenShot.vue
Normal file
@ -0,0 +1,91 @@
|
||||
<template>
|
||||
<view>
|
||||
<!-- 当父组件传递的prop属性数据发生变化的时候 ,生成海报图片-->
|
||||
<view :prop="domId" :change:prop="html2canvas.emitData" class="html2canvas">
|
||||
<slot></slot>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { base64ToPath } from '@/utils/image-tools.js';
|
||||
export default {
|
||||
props: {
|
||||
domId: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
mounted:function(){
|
||||
console.log("组件加载完成");
|
||||
},
|
||||
|
||||
methods: {
|
||||
// 接收renderjs发回的数据
|
||||
async receiveRenderData(imgData) {
|
||||
let posterHeight=imgData.height;
|
||||
let posterWidth=imgData.width;
|
||||
let imgPath =await base64ToPath(imgData.imgVal, '.jpeg');
|
||||
this.$emit('renderFinish', {"posterPath":imgPath,"posterHeight":posterHeight,"posterWidth":posterWidth});
|
||||
uni.hideLoading();
|
||||
},
|
||||
showLoading() {
|
||||
uni.showLoading({
|
||||
title: "正在生成导出",
|
||||
icon: "none",
|
||||
mask: true,
|
||||
duration: 3000
|
||||
})
|
||||
},
|
||||
hideLoading() {
|
||||
uni.hideLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<script module="html2canvas" lang="renderjs">
|
||||
import html2canvas from 'html2canvas';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
},
|
||||
mounted:function(){
|
||||
console.log("视图层渲染完成");
|
||||
},
|
||||
methods: {
|
||||
// 发送数据到逻辑层,下面这里最好是加一个settimeout延迟,因为主界面数据还没加载渲染完成
|
||||
emitData(domId) {
|
||||
this.$ownerInstance.callMethod('showLoading', true);
|
||||
const dom = document.getElementById('poster');
|
||||
console.log("dom",dom);
|
||||
let width= dom.offsetWidth;
|
||||
let height=dom.offsetHeight;
|
||||
let windowHeight= uni.getSystemInfoSync().windowHeight;
|
||||
let windowWidth=uni.getSystemInfoSync().windowWidth;
|
||||
html2canvas(dom, {
|
||||
width:width,
|
||||
height:height,
|
||||
//scale:2.5, // 缩放倍数
|
||||
scrollY: 0, // html2canvas默认绘制视图内的页面,需要把scrollY,scrollX设置为0
|
||||
scrollX: 0,
|
||||
x:0,
|
||||
y:0,
|
||||
windowWidth:windowWidth,
|
||||
windowHeight:windowHeight,
|
||||
useCORS: true, //支持跨域,但好像没什么用
|
||||
}).then((canvas) => {
|
||||
let imgVal= canvas.toDataURL('image/png');
|
||||
this.$ownerInstance.callMethod('receiveRenderData',{imgVal:imgVal,height:height,width:width});
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
</style>
|
||||
@ -12,6 +12,7 @@
|
||||
"@xkit-yx/utils": "^0.7.2",
|
||||
"crypto-js": "^4.2.0",
|
||||
"dayjs": "^1.11.18",
|
||||
"html2canvas": "^1.4.1",
|
||||
"image-tools": "^1.4.0",
|
||||
"js-base64": "^3.7.8",
|
||||
"js-md5": "^0.8.3",
|
||||
|
||||
@ -76,6 +76,7 @@
|
||||
msg: {
|
||||
"price":res.data.amount,
|
||||
"order_id":res.data.order_id,
|
||||
"trade_no":res.data.trade_no,
|
||||
'jifen':res.data.point,
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
<template>
|
||||
<view class="my-code-page">
|
||||
<webview src="https://dev-wx.igandan.com/expert/expertcodeimg?expert_uuid=9UFkll2Xo57km6224XE&fromtype=doctor"></webview>
|
||||
<navBar title="我的二维码" v-if="!jieping"/>
|
||||
<!-- <sp-html2canvas-render :useCORS="true" :allowTaint="true" domId="render-dom" ref="renderRef" @renderOver="renderOver"></sp-html2canvas-render> -->
|
||||
<view class="my-code-page renderDom" id="render-dom" :class="{'active':jieping}">
|
||||
<!-- <webview src="https://dev-wx.igandan.com/expert/expertcodeimg?expert_uuid=9UFkll2Xo57km6224XE&fromtype=doctor"></webview> -->
|
||||
<!-- 顶部导航栏 -->
|
||||
<navBar title="我的二维码" />
|
||||
|
||||
|
||||
<!-- 内容 -->
|
||||
<scroll-view scroll-y class="page-scroll" id="pageContent">
|
||||
@ -59,20 +61,25 @@
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部保存按钮 -->
|
||||
<view class="save-bar">
|
||||
<view class="save-bar" v-if="!jieping">
|
||||
<button class="save-btn" @click="onSave">保存到手机相册</button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup >
|
||||
import { base64ToPath } from 'image-tools'
|
||||
import navBar from '@/components/navBar/navBar.vue'
|
||||
import { onShow } from "@dcloudio/uni-app";
|
||||
import spHtml2canvasRender from '@/uni_modules/sp-html2canvas-render/components/sp-html2canvas-render/sp-html2canvas-render.vue'
|
||||
import { ref } from 'vue';
|
||||
import docUrl from '@/utils/docUrl'
|
||||
import bgImg from "@/static/background.jpg"
|
||||
import viewnkImg from "@/static/arr.png"
|
||||
const userInfo = ref({})
|
||||
const renderRef = ref(null)
|
||||
const jieping = ref(false)
|
||||
const goBack = () => {
|
||||
uni.navigateBack();
|
||||
};
|
||||
@ -97,186 +104,67 @@ const handleSaveError = (err) => {
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onSave = () => {
|
||||
// #ifdef APP-PLUS
|
||||
// 检查是否在 App 端
|
||||
if (typeof plus === 'undefined') {
|
||||
uni.showToast({ title: '当前环境不支持此功能', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示加载提示
|
||||
uni.showLoading({ title: '保存中...' });
|
||||
|
||||
// 添加超时处理
|
||||
let timeoutTimer = setTimeout(() => {
|
||||
uni.hideLoading();
|
||||
uni.showToast({
|
||||
title: '操作超时,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}, 15000); // 15秒超时
|
||||
|
||||
// 获取当前 webview
|
||||
const currentWebview = plus.webview.currentWebview();
|
||||
|
||||
// 使用 draw 方法将页面绘制成图片
|
||||
currentWebview.draw({
|
||||
bitmap: true,
|
||||
success: (bitmap) => {
|
||||
clearTimeout(timeoutTimer);
|
||||
try {
|
||||
// 将 bitmap 转换为 base64
|
||||
const base64 = bitmap.toBase64DataURL('image/png', 1.0);
|
||||
|
||||
// 去除 base64 前缀
|
||||
const base64Data = base64.indexOf(',') > -1 ? base64.split(',')[1] : base64;
|
||||
|
||||
// 生成临时文件路径
|
||||
const fileName = 'mycode_' + Date.now() + '.png';
|
||||
const tempPath = `_doc/${fileName}`;
|
||||
|
||||
// 使用 plus.io 写入文件
|
||||
plus.io.resolveLocalFileSystemURL('_doc', (entry) => {
|
||||
entry.getFile(fileName, { create: true, exclusive: false }, (fileEntry) => {
|
||||
fileEntry.createWriter((writer) => {
|
||||
// base64 转 ArrayBuffer
|
||||
const binaryString = atob(base64Data);
|
||||
const len = binaryString.length;
|
||||
const bytes = new Uint8Array(len);
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
|
||||
writer.onwriteend = () => {
|
||||
// 写入完成,回收 bitmap
|
||||
bitmap.recycle();
|
||||
|
||||
// 转换为本地路径
|
||||
const localPath = plus.io.convertLocalFileSystemURL(fileEntry.fullPath);
|
||||
|
||||
// 保存到相册
|
||||
jieping.value = true //缩小页面比例
|
||||
const that = this
|
||||
setTimeout(()=>{
|
||||
var pages = getCurrentPages(); //获取当前页面信息
|
||||
var page = pages[pages.length - 1];
|
||||
var bitmap = null;
|
||||
var currentWebview = page.$getAppWebview();
|
||||
bitmap = new plus.nativeObj.Bitmap('amway_img');// 将webview内容绘制到Bitmap对象中
|
||||
currentWebview.draw(bitmap, function() {
|
||||
let rand = Math.floor(Math.random() * 10000)
|
||||
let saveUrl = '_doc/' + rand + 'a.jpg'
|
||||
bitmap.save(saveUrl, {}, function(i) {
|
||||
uni.saveImageToPhotosAlbum({
|
||||
filePath: localPath,
|
||||
success: () => {
|
||||
uni.hideLoading();
|
||||
filePath: i.target,
|
||||
success: function() {
|
||||
uni.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
title: '保存图片成功',
|
||||
mask: false,
|
||||
duration: 1500
|
||||
});
|
||||
},
|
||||
fail: (err) => {
|
||||
uni.hideLoading();
|
||||
console.error('保存到相册失败:', err);
|
||||
handleSaveError(err);
|
||||
jieping.value = false //恢复页面大小
|
||||
}
|
||||
});
|
||||
};
|
||||
}, function(e) {
|
||||
console.log('保存图片失败:' + JSON.stringify(e));
|
||||
jieping.value = false //恢复页面大小
|
||||
});
|
||||
}, function(e) {
|
||||
console.log('截屏绘制图片失败:' + JSON.stringify(e));
|
||||
jieping.value = false //恢复页面大小
|
||||
});
|
||||
},100)
|
||||
|
||||
writer.onerror = (err) => {
|
||||
uni.hideLoading();
|
||||
console.error('写入文件失败:', err);
|
||||
bitmap.recycle();
|
||||
uni.showToast({
|
||||
title: '保存失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
};
|
||||
// const onSave = () => {
|
||||
// //jieping.value = true //缩小页面比例
|
||||
// renderRef.value.h2cRenderDom();
|
||||
|
||||
// 创建 Blob 对象并写入
|
||||
try {
|
||||
const blob = new Blob([bytes], { type: 'image/png' });
|
||||
writer.write(blob);
|
||||
} catch (e) {
|
||||
// 如果 Blob 不支持,尝试直接写入 ArrayBuffer
|
||||
try {
|
||||
writer.write(bytes.buffer);
|
||||
} catch (e2) {
|
||||
uni.hideLoading();
|
||||
console.error('写入失败:', e2);
|
||||
bitmap.recycle();
|
||||
uni.showToast({
|
||||
title: '保存失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
// };
|
||||
const renderOver = (e) => {
|
||||
// e为导出截图的base64格式字符串
|
||||
console.log("==== renderOver :", e);
|
||||
base64ToPath(e).then((res) => {
|
||||
console.log("==== path :", res);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, (err) => {
|
||||
clearTimeout(timeoutTimer);
|
||||
uni.hideLoading();
|
||||
console.error('创建写入器失败:', err);
|
||||
bitmap.recycle();
|
||||
uni.showToast({
|
||||
title: '保存失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
});
|
||||
}, (err) => {
|
||||
clearTimeout(timeoutTimer);
|
||||
uni.hideLoading();
|
||||
console.error('获取文件失败:', err);
|
||||
bitmap.recycle();
|
||||
uni.showToast({
|
||||
title: '保存失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
});
|
||||
}, (err) => {
|
||||
clearTimeout(timeoutTimer);
|
||||
uni.hideLoading();
|
||||
console.error('解析文件系统失败:', err);
|
||||
bitmap.recycle();
|
||||
uni.showToast({
|
||||
title: '保存失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
});
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutTimer);
|
||||
uni.hideLoading();
|
||||
console.error('处理失败:', error);
|
||||
if (bitmap && bitmap.recycle) {
|
||||
bitmap.recycle();
|
||||
}
|
||||
uni.showToast({
|
||||
title: '保存失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
clearTimeout(timeoutTimer);
|
||||
uni.hideLoading();
|
||||
console.error('截图失败:', err);
|
||||
uni.showToast({
|
||||
title: '截图失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
});
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-PLUS
|
||||
uni.showToast({ title: '此功能仅支持 App 端', icon: 'none' });
|
||||
// #endif
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.my-code-page {
|
||||
min-height: 100vh;
|
||||
background-color: #0d7dfd;
|
||||
|
||||
.active{
|
||||
transform: scale(0.8);
|
||||
margin-top: -calc(var(--status-bar-height) + 44px);
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
}
|
||||
|
||||
.squrebox{
|
||||
margin:0 30rpx;
|
||||
|
||||
|
||||
@ -292,6 +292,12 @@
|
||||
};
|
||||
|
||||
const goAddPatient = () => {
|
||||
// uni.sendNativeEvent('goExpertQrcodePage', {
|
||||
// msg: "expertQrcodePage"
|
||||
// },ret => {
|
||||
|
||||
// console.log(ret);
|
||||
// })
|
||||
navTo({
|
||||
url: '/pages_app/myCode/myCode'
|
||||
})
|
||||
|
||||
@ -102,5 +102,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
57
uni_modules/sp-html2canvas-render/changelog.md
Normal file
57
uni_modules/sp-html2canvas-render/changelog.md
Normal file
@ -0,0 +1,57 @@
|
||||
## 1.2.3(2024-09-19)
|
||||
1. 更新示例工程
|
||||
## 1.2.2(2024-05-08)
|
||||
1. 修改util.js路径为@/uni_modules/sp-html2canvas-render/utils/index.js
|
||||
## 1.2.1(2024-05-08)
|
||||
1. 更新示例工程
|
||||
## 1.2.0(2024-04-30)
|
||||
1. 示例工程中示例二已更新解决截图模糊的问题,请参考
|
||||
## 1.1.9(2024-04-30)
|
||||
1.更新示例工程
|
||||
## 1.1.8(2024-04-30)
|
||||
1. 优化了报错提示
|
||||
2. domId设为必填
|
||||
## 1.1.7(2024-04-29)
|
||||
1. h2c配置项更新
|
||||
## 1.1.6(2024-03-08)
|
||||
1. 更新示例工程
|
||||
2. 更新文档
|
||||
## 1.1.5(2024-02-29)
|
||||
1. 更新示例工程示例四:横向长截图
|
||||
## 1.1.4(2024-02-27)
|
||||
1. 更新base64ToPath方法,以供需要用临时路径保存文件的小伙伴,见示例一中使用
|
||||
## 1.1.3(2024-02-24)
|
||||
1. 更新示例工程:示例3:动态domid,可动态选择单独导出指定dom
|
||||
## 1.1.2(2024-02-06)
|
||||
1. 更新文档
|
||||
## 1.1.1(2024-02-06)
|
||||
1. 重大更新,详见文档
|
||||
2. 更新示例工程
|
||||
## 1.1.0(2024-02-05)
|
||||
1. 更新文档
|
||||
## 1.0.9(2024-02-05)
|
||||
1. 重要更新:插件更新内置了urlToBase64工具方法,图片报错toDataURL on HTMLCanvasElement或其他问题导致图片无法正常渲染的,可以使用该工具方法将图片路径(支持网络路径和本地相对路径)转换为base64格式
|
||||
## 1.0.8(2024-02-04)
|
||||
1. 更新示例工程
|
||||
## 1.0.7(2024-01-24)
|
||||
1. 更新示例工程延迟渲染示例
|
||||
## 1.0.6(2024-01-16)
|
||||
1. 更新示例工程
|
||||
2. 更新文档
|
||||
## 1.0.5(2024-01-15)
|
||||
1. 更新示例工程
|
||||
## 1.0.4(2023-12-08)
|
||||
1. 更新html2canvas中部分配置
|
||||
2. 重新上传示例工程,还请麻烦用hbuilderx一键导入示例,不要使用zip下载的方式
|
||||
3. 更新文档说明,很多人问toDataURL on HTMLCanvasElement的问题,有的人哪怕直接使用实例工程也会报错,有的人却一切正常,我对此提供了部分解决方式。
|
||||
## 1.0.3(2023-11-29)
|
||||
1.更新示例工程,内联使用方式详见inner页面
|
||||
## 1.0.2(2023-11-27)
|
||||
1.更新示例工程样例
|
||||
## 1.0.1(2023-11-27)
|
||||
1.解决在vue2的ap真机环境下可能出现的报错
|
||||
|
||||
2.更新示例代码,兼容vue2/3写法,支持图片生成样例
|
||||
## 1.0.0(2023-10-20)
|
||||
1. 组件更新,使用方式详见README
|
||||
2. 更新示例项目
|
||||
@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<!-- prop是自定义的数据字段名,要与chang后的保持一致,h2cRender是renderjs的module名称 -->
|
||||
<view class="sp-html2canvas-render" :prop="domId" :change:prop="h2cRender.watchDomId">
|
||||
<slot></slot>
|
||||
<text :prop="expOver" :change:prop="h2cRender.watchExpOver"></text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
// 要渲染dom的id
|
||||
domId: {
|
||||
type: String,
|
||||
default: '',
|
||||
require: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
expOver: 0,
|
||||
// #ifdef VUE2
|
||||
// #ifdef APP
|
||||
// 只有在Vue2的APP真机中需要先声明h2cRender,否则会报错,若未报错建议删除此处代码
|
||||
h2cRender: null
|
||||
// #endif
|
||||
// #endif
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
renderOver(e) {
|
||||
// 监听渲染生成完成
|
||||
this.$emit('renderOver', e)
|
||||
},
|
||||
h2cRenderDom() {
|
||||
// #ifdef H5
|
||||
this.renderDom()
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
// 控制expOver变量改变以触发RenderJs中渲染方法。
|
||||
this.expOver++
|
||||
// 处理你自己的逻辑.....
|
||||
// #endif
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- renderjs目前仅支持内联使用 -->
|
||||
<script module="h2cRender" lang="renderjs">
|
||||
import html2canvas from 'html2canvas';
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
domIdValue: ''
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async renderDom() {
|
||||
// app无法通过传参获取domId,也无法直接获取到script中data或props数据
|
||||
// 必须通过特定的监听方式,与script通信,获取其data
|
||||
try {
|
||||
const el = document.getElementById(this.domIdValue);
|
||||
if(!el) {
|
||||
console.error('dom盒子未加载成功,请先确保dom渲染完成,再检查你的domId是否有误');
|
||||
return
|
||||
}
|
||||
/**
|
||||
* 配置说明
|
||||
* 1. allowTaint:true和useCORS:true都是解决跨域问题的方式(不一定完全能解决跨域),不同的是使用allowTaint会对canvas造成污染,导致无法使用canvas.toDataURL方法
|
||||
* 2. 想要完美解决跨域,还得需要后端服务器设置access-control-allow-origin: *,允许资源跨域访问,前端设置useCORS:true
|
||||
* 2. scale通过放大倍率来调整画质清晰度,但是只调整这一个参数可能不是最优解
|
||||
*/
|
||||
const canvas = await html2canvas(el, {
|
||||
width: el.offsetWidth,
|
||||
height: el.offsetHeight,
|
||||
x: 0,
|
||||
y: 0,
|
||||
logging: true,
|
||||
useCORS: true,
|
||||
// allowTaint: true,
|
||||
// async: false,
|
||||
scale: 2, // 2倍,增强清晰度
|
||||
// foreignObjectRendering: true, // 兼容性问题,慎用
|
||||
});
|
||||
const base64 = canvas.toDataURL('image/png', 1);
|
||||
this.$ownerInstance.callMethod('renderOver', base64);
|
||||
} catch(err) {
|
||||
console.log('==== err :', err.message);
|
||||
}
|
||||
},
|
||||
// 监听方式,与script通信,获取其data
|
||||
watchDomId(newValue, oldValue, ownerInstance, instance) {
|
||||
this.domIdValue = newValue
|
||||
},
|
||||
watchExpOver(newValue, oldValue, ownerInstance, instance) {
|
||||
if(newValue !== 0){
|
||||
// 初始不做监听,避免默认第一次就自动渲染
|
||||
this.renderDom()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.sp-html2canvas-render {
|
||||
position: relative;
|
||||
}
|
||||
</style>
|
||||
86
uni_modules/sp-html2canvas-render/package.json
Normal file
86
uni_modules/sp-html2canvas-render/package.json
Normal file
@ -0,0 +1,86 @@
|
||||
{
|
||||
"id": "sp-html2canvas-render",
|
||||
"displayName": "基于html2canvas和renderjs 指定盒子截图 截屏 截长屏",
|
||||
"version": "1.2.3",
|
||||
"description": "基于html2canvas和renderjs的页面指定盒子截图,截屏,可截长屏,页面生成图片",
|
||||
"keywords": [
|
||||
"截图",
|
||||
"截屏",
|
||||
"截长屏",
|
||||
"生成图片",
|
||||
"html2canvas"
|
||||
],
|
||||
"repository": "",
|
||||
"engines": {
|
||||
"HBuilderX": "^3.8.0"
|
||||
},
|
||||
"dcloudext": {
|
||||
"type": "component-vue",
|
||||
"sale": {
|
||||
"regular": {
|
||||
"price": "0.00"
|
||||
},
|
||||
"sourcecode": {
|
||||
"price": "0.00"
|
||||
}
|
||||
},
|
||||
"contact": {
|
||||
"qq": ""
|
||||
},
|
||||
"declaration": {
|
||||
"ads": "无",
|
||||
"data": "插件不采集任何数据",
|
||||
"permissions": "无"
|
||||
},
|
||||
"npmurl": ""
|
||||
},
|
||||
"uni_modules": {
|
||||
"dependencies": [],
|
||||
"encrypt": [],
|
||||
"platforms": {
|
||||
"cloud": {
|
||||
"tcb": "y",
|
||||
"aliyun": "y",
|
||||
"alipay": "n"
|
||||
},
|
||||
"client": {
|
||||
"Vue": {
|
||||
"vue2": "y",
|
||||
"vue3": "y"
|
||||
},
|
||||
"App": {
|
||||
"app-vue": "y",
|
||||
"app-nvue": "u"
|
||||
},
|
||||
"H5-mobile": {
|
||||
"Safari": "y",
|
||||
"Android Browser": "y",
|
||||
"微信浏览器(Android)": "y",
|
||||
"QQ浏览器(Android)": "y"
|
||||
},
|
||||
"H5-pc": {
|
||||
"Chrome": "y",
|
||||
"IE": "y",
|
||||
"Edge": "y",
|
||||
"Firefox": "y",
|
||||
"Safari": "y"
|
||||
},
|
||||
"小程序": {
|
||||
"微信": "u",
|
||||
"阿里": "u",
|
||||
"百度": "u",
|
||||
"字节跳动": "u",
|
||||
"QQ": "u",
|
||||
"钉钉": "u",
|
||||
"快手": "u",
|
||||
"飞书": "u",
|
||||
"京东": "u"
|
||||
},
|
||||
"快应用": {
|
||||
"华为": "u",
|
||||
"联盟": "u"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
uni_modules/sp-html2canvas-render/readme.md
Normal file
11
uni_modules/sp-html2canvas-render/readme.md
Normal file
@ -0,0 +1,11 @@
|
||||
# sp-html2canvas-render
|
||||
|
||||
### 文档迁移
|
||||
|
||||
> 防止文档失效,提供下列五个地址,内容一致
|
||||
|
||||
- [地址一](https://sonvee.github.io/sv-app-docs/docs-github/src/plugins/sp-html2canvas-render/sp-html2canvas-render.html)
|
||||
- [地址二](https://sv-app-docs.pages.dev/src/plugins/sp-html2canvas-render/sp-html2canvas-render.html)
|
||||
- [地址三](https://sv-app-docs.4everland.app/src/plugins/sp-html2canvas-render/sp-html2canvas-render.html)
|
||||
- [地址四](https://sv-app-docs.vercel.app/src/plugins/sp-html2canvas-render/sp-html2canvas-render.html) (需要梯子)
|
||||
- [地址五](https://static-mp-74bfcbac-6ba6-4f39-8513-8831390ff75a.next.bspapp.com/docs-uni/src/plugins/sp-html2canvas-render/sp-html2canvas-render.html) (有IP限制)
|
||||
255
uni_modules/sp-html2canvas-render/utils/index.js
Normal file
255
uni_modules/sp-html2canvas-render/utils/index.js
Normal file
@ -0,0 +1,255 @@
|
||||
function getLocalFilePath(path) {
|
||||
if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf(
|
||||
'_downloads') === 0) {
|
||||
return path
|
||||
}
|
||||
if (path.indexOf('file://') === 0) {
|
||||
return path
|
||||
}
|
||||
if (path.indexOf('/storage/emulated/0/') === 0) {
|
||||
return path
|
||||
}
|
||||
if (path.indexOf('/') === 0) {
|
||||
let localFilePath = plus.io.convertAbsoluteFileSystem(path)
|
||||
if (localFilePath !== path) {
|
||||
return localFilePath
|
||||
} else {
|
||||
path = path.substr(1)
|
||||
}
|
||||
}
|
||||
return '_www/' + path
|
||||
}
|
||||
|
||||
function dataUrlToBase64(str) {
|
||||
let array = str.split(',')
|
||||
return array[array.length - 1]
|
||||
}
|
||||
|
||||
let index = 0
|
||||
|
||||
function getNewFileId() {
|
||||
return Date.now() + String(index++)
|
||||
}
|
||||
|
||||
function biggerThan(v1, v2) {
|
||||
let v1Array = v1.split('.')
|
||||
let v2Array = v2.split('.')
|
||||
let update = false
|
||||
for (let index = 0; index < v2Array.length; index++) {
|
||||
let diff = v1Array[index] - v2Array[index]
|
||||
if (diff !== 0) {
|
||||
update = diff > 0
|
||||
break
|
||||
}
|
||||
}
|
||||
return update
|
||||
}
|
||||
|
||||
export function pathToBase64(path) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (typeof window === 'object' && 'document' in window) {
|
||||
if (typeof FileReader === 'function') {
|
||||
let xhr = new XMLHttpRequest()
|
||||
xhr.open('GET', path, true)
|
||||
xhr.responseType = 'blob'
|
||||
xhr.onload = function() {
|
||||
if (this.status === 200) {
|
||||
let fileReader = new FileReader()
|
||||
fileReader.onload = function(e) {
|
||||
resolve(e.target.result)
|
||||
}
|
||||
fileReader.onerror = reject
|
||||
fileReader.readAsDataURL(this.response)
|
||||
}
|
||||
}
|
||||
xhr.onerror = reject
|
||||
xhr.send()
|
||||
return
|
||||
}
|
||||
let canvas = document.createElement('canvas')
|
||||
let c2x = canvas.getContext('2d')
|
||||
let img = new Image
|
||||
img.onload = function() {
|
||||
canvas.width = img.width
|
||||
canvas.height = img.height
|
||||
c2x.drawImage(img, 0, 0)
|
||||
resolve(canvas.toDataURL())
|
||||
canvas.height = canvas.width = 0
|
||||
}
|
||||
img.onerror = reject
|
||||
img.src = path
|
||||
return
|
||||
}
|
||||
if (typeof plus === 'object') {
|
||||
plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) {
|
||||
entry.file(function(file) {
|
||||
let fileReader = new plus.io.FileReader()
|
||||
fileReader.onload = function(data) {
|
||||
resolve(data.target.result)
|
||||
}
|
||||
fileReader.onerror = function(error) {
|
||||
reject(error)
|
||||
}
|
||||
fileReader.readAsDataURL(file)
|
||||
}, function(error) {
|
||||
reject(error)
|
||||
})
|
||||
}, function(error) {
|
||||
reject(error)
|
||||
})
|
||||
return
|
||||
}
|
||||
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
|
||||
wx.getFileSystemManager().readFile({
|
||||
filePath: path,
|
||||
encoding: 'base64',
|
||||
success: function(res) {
|
||||
resolve('data:image/png;base64,' + res.data)
|
||||
},
|
||||
fail: function(error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
reject(new Error('not support'))
|
||||
})
|
||||
}
|
||||
|
||||
export function base64ToPath(base64) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (typeof window === 'object' && 'document' in window) {
|
||||
base64 = base64.split(',')
|
||||
let type = base64[0].match(/:(.*?);/)[1]
|
||||
let str = atob(base64[1])
|
||||
let n = str.length
|
||||
let array = new Uint8Array(n)
|
||||
while (n--) {
|
||||
array[n] = str.charCodeAt(n)
|
||||
}
|
||||
return resolve((window.URL || window.webkitURL).createObjectURL(new Blob([array], {
|
||||
type: type
|
||||
})))
|
||||
}
|
||||
let extName = base64.split(',')[0].match(/data\:\S+\/(\S+);/)
|
||||
if (extName) {
|
||||
extName = extName[1]
|
||||
} else {
|
||||
reject(new Error('base64 error'))
|
||||
}
|
||||
let fileName = getNewFileId() + '.' + extName
|
||||
if (typeof plus === 'object') {
|
||||
let basePath = '_doc'
|
||||
let dirPath = 'uniapp_temp'
|
||||
let filePath = basePath + '/' + dirPath + '/' + fileName
|
||||
if (!biggerThan(plus.os.name === 'Android' ? '1.9.9.80627' : '1.9.9.80472', plus.runtime.innerVersion)) {
|
||||
plus.io.resolveLocalFileSystemURL(basePath, function(entry) {
|
||||
entry.getDirectory(dirPath, {
|
||||
create: true,
|
||||
exclusive: false,
|
||||
}, function(entry) {
|
||||
entry.getFile(fileName, {
|
||||
create: true,
|
||||
exclusive: false,
|
||||
}, function(entry) {
|
||||
entry.createWriter(function(writer) {
|
||||
writer.onwrite = function() {
|
||||
resolve(filePath)
|
||||
}
|
||||
writer.onerror = reject
|
||||
writer.seek(0)
|
||||
writer.writeAsBinary(dataUrlToBase64(base64))
|
||||
}, reject)
|
||||
}, reject)
|
||||
}, reject)
|
||||
}, reject)
|
||||
return
|
||||
}
|
||||
let bitmap = new plus.nativeObj.Bitmap(fileName)
|
||||
bitmap.loadBase64Data(base64, function() {
|
||||
bitmap.save(filePath, {}, function() {
|
||||
bitmap.clear()
|
||||
resolve(filePath)
|
||||
}, function(error) {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
}, function(error) {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
return
|
||||
}
|
||||
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
|
||||
let filePath = wx.env.USER_DATA_PATH + '/' + fileName
|
||||
wx.getFileSystemManager().writeFile({
|
||||
filePath: filePath,
|
||||
data: dataUrlToBase64(base64),
|
||||
encoding: 'base64',
|
||||
success: function() {
|
||||
resolve(filePath)
|
||||
},
|
||||
fail: function(error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
reject(new Error('not support'))
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片地址转换为base64格式图片
|
||||
* @param {string} url 图片地址 网络地址 本地相对路径
|
||||
* @param {string} type base64图片类型 默认png
|
||||
*/
|
||||
export function urlToBase64(url, type = 'png') {
|
||||
let promises
|
||||
|
||||
// 网络地址 或者h5端本地相对路径 可使用request方式
|
||||
promises = new Promise((resolve, reject) => {
|
||||
uni.request({
|
||||
url: url,
|
||||
method: 'GET',
|
||||
responseType: 'arraybuffer',
|
||||
success: (res) => {
|
||||
const base64 = `data:image/${type};base64,${uni.arrayBufferToBase64(res.data)}`
|
||||
resolve(base64);
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
// #ifdef APP
|
||||
if (!url.startsWith('http')) {
|
||||
// app真机本地相对路径
|
||||
promises = new Promise((resolve, reject) => {
|
||||
// 使用compressImage获取到安卓本地路径file:///...
|
||||
uni.compressImage({
|
||||
src: url,
|
||||
quality: 100,
|
||||
success: (res) => {
|
||||
const tempUrl = res.tempFilePath
|
||||
plus.io.resolveLocalFileSystemURL(tempUrl, (entry) => {
|
||||
entry.file((e) => {
|
||||
let fileReader = new plus.io.FileReader();
|
||||
fileReader.onload = (r) => {
|
||||
resolve(r.target.result)
|
||||
}
|
||||
fileReader.readAsDataURL(e)
|
||||
})
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
reject(err);
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
// #endif
|
||||
|
||||
return promises
|
||||
}
|
||||
152
utils/image-tools.js
Normal file
152
utils/image-tools.js
Normal file
@ -0,0 +1,152 @@
|
||||
function getLocalFilePath(path) {
|
||||
if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) {
|
||||
return path
|
||||
}
|
||||
if (path.indexOf('file://') === 0) {
|
||||
return path
|
||||
}
|
||||
if (path.indexOf('/storage/emulated/0/') === 0) {
|
||||
return path
|
||||
}
|
||||
if (path.indexOf('/') === 0) {
|
||||
var localFilePath = plus.io.convertAbsoluteFileSystem(path)
|
||||
if (localFilePath !== path) {
|
||||
return localFilePath
|
||||
} else {
|
||||
path = path.substr(1)
|
||||
}
|
||||
}
|
||||
return '_www/' + path
|
||||
}
|
||||
|
||||
export function pathToBase64(path) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (typeof window === 'object' && 'document' in window) {
|
||||
if (typeof FileReader === 'function') {
|
||||
var xhr = new XMLHttpRequest()
|
||||
xhr.open('GET', path, true)
|
||||
xhr.responseType = 'blob'
|
||||
xhr.onload = function() {
|
||||
if (this.status === 200) {
|
||||
let fileReader = new FileReader()
|
||||
fileReader.onload = function(e) {
|
||||
resolve(e.target.result)
|
||||
}
|
||||
fileReader.onerror = reject
|
||||
fileReader.readAsDataURL(this.response)
|
||||
}
|
||||
}
|
||||
xhr.onerror = reject
|
||||
xhr.send()
|
||||
return
|
||||
}
|
||||
var canvas = document.createElement('canvas')
|
||||
var c2x = canvas.getContext('2d')
|
||||
var img = new Image
|
||||
img.onload = function() {
|
||||
canvas.width = img.width
|
||||
canvas.height = img.height
|
||||
c2x.drawImage(img, 0, 0)
|
||||
resolve(canvas.toDataURL())
|
||||
canvas.height = canvas.width = 0
|
||||
}
|
||||
img.onerror = reject
|
||||
img.src = path
|
||||
return
|
||||
}
|
||||
if (typeof plus === 'object') {
|
||||
plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), function(entry) {
|
||||
entry.file(function(file) {
|
||||
var fileReader = new plus.io.FileReader()
|
||||
fileReader.onload = function(data) {
|
||||
resolve(data.target.result)
|
||||
}
|
||||
fileReader.onerror = function(error) {
|
||||
reject(error)
|
||||
}
|
||||
fileReader.readAsDataURL(file)
|
||||
}, function(error) {
|
||||
reject(error)
|
||||
})
|
||||
}, function(error) {
|
||||
reject(error)
|
||||
})
|
||||
return
|
||||
}
|
||||
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
|
||||
wx.getFileSystemManager().readFile({
|
||||
filePath: path,
|
||||
encoding: 'base64',
|
||||
success: function(res) {
|
||||
resolve('data:image/png;base64,' + res.data)
|
||||
},
|
||||
fail: function(error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
reject(new Error('not support'))
|
||||
})
|
||||
}
|
||||
|
||||
export function base64ToPath(base64, extName) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
if (typeof window === 'object' && 'document' in window) {
|
||||
base64 = base64.split(',')
|
||||
var type = base64[0].match(/:(.*?);/)[1]
|
||||
var str = atob(base64[1])
|
||||
var n = str.length
|
||||
var array = new Uint8Array(n)
|
||||
while (n--) {
|
||||
array[n] = str.charCodeAt(n)
|
||||
}
|
||||
return resolve((window.URL || window.webkitURL).createObjectURL(new Blob([array], { type: type })))
|
||||
}
|
||||
var fileName;
|
||||
if (!extName) {
|
||||
extName = base64.match(/data\:\S+\/(\S+);/)
|
||||
if (extName) {
|
||||
extName = extName[1]
|
||||
} else {
|
||||
reject(new Error('base64 error'))
|
||||
}
|
||||
fileName = Date.now() + '.' + extName;
|
||||
} else {
|
||||
fileName = Date.now() + extName;
|
||||
}
|
||||
if (typeof plus === 'object') {
|
||||
var bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now())
|
||||
bitmap.loadBase64Data(base64, function() {
|
||||
var filePath = '_doc/uniapp_temp/' + fileName
|
||||
bitmap.save(filePath, {}, function() {
|
||||
bitmap.clear()
|
||||
resolve(filePath)
|
||||
}, function(error) {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
}, function(error) {
|
||||
bitmap.clear()
|
||||
reject(error)
|
||||
})
|
||||
return
|
||||
}
|
||||
if (typeof wx === 'object' && wx.canIUse('getFileSystemManager')) {
|
||||
var filePath = wx.env.USER_DATA_PATH + '/' + fileName
|
||||
wx.getFileSystemManager().writeFile({
|
||||
filePath: filePath,
|
||||
data: base64.replace(/^data:\S+\/\S+;base64,/, ''),
|
||||
encoding: 'base64',
|
||||
success: function() {
|
||||
resolve(filePath)
|
||||
},
|
||||
fail: function(error) {
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
reject(new Error('not support'))
|
||||
})
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user