我的情境是這樣的
我的畫面上
有固定的3個component區塊
顯示著3種不太一樣的畫面
例如:
<component1 id="show1" :list="list1"></component1>
<component2 id="show2" :list="list2"></component1>
<component3 id="show3" :list="list3"></component1>
<button>列印</button>
3個component有屬於自己要塞的內容(list1.2.3)
這3個內容會由另一個比較複雜的陣列分析出來
暫定叫做dataList = [{...}, {...}]
內容大概長這樣
dataList = [
{
type:...,
list:...,
},
{
type:...,
list:...,
}
...
...
]
接下來的重點是
執行javascript跑dataList的forEach
然後判斷相關的參數來分別將資料丟到對應的list1.2.3
並將相關區塊的畫面個別轉成base64
好讓我最後可以統一印出來
例如:
let base64List = [];
let elementId = "";
let printList = [];
dataList.forEach(function(datas) {
/*執行一些資料判斷*/
if (datas.type = /*執行一些資料判斷*/) {
elementId = "show1";
this.list1 = data.list;
} else if (datas.type = /*執行一些資料判斷*/) {
elementId = "show2";
this.list2 = data.list;
} else if (datas.type = /*執行一些資料判斷*/) {
elementId = "show3";
this.list3 = data.list;
}
if (elementId !== "") {
html2Canvas(document.getElementById(elementId), {
allowTaint: true,
useCORS: true,
onclone: function (clonedDoc) {
clonedDoc.getElementById(elementId).style.visibility = 'visible';
}
}).then(function (canvas) {
let base64String = canvas.toDataURL('image/png', 1.0);
base64List.push(base64String.replace(/^data:.*?;base64,/, ""));
}).catch((error) => {
alert(error);
});
}
})
printList.push({
baseList: base64List
})
console.log(printList)
上面的例子最後的printList看似多餘的
是因為我想說簡單敘述問題
事實上外面還有一層迴圈
實際上的printList長這樣
printList = [
{
ip: 192.....110,
baseList: [
"base64",
"base64",
...
...
]
},
{
ip: 192.....111,
baseList: [
"base64",
"base64",
...
...
]
},
...
...
]
功能目的是要讓個別的資料在不同的印表機列印
我的問題在畫面轉base64那一大段
他的執行順序會forEach跑完才開始跑html2Canvas這段的then
怪的是
我本以為資料會不完整
沒想到
printList在forEach跑完後成功建立了
後面執行的html2Canvas卻持續對base64List這個變數進行更新
雖然最後所有的base64List都塞在printList的第一個元素裡
不知道有沒有人有遇過類似的問題
是否有解法
js 的執行順序本來就是先把目前的部份執行完後才跑去執行非同步的程式 (你說的 then
的部份,它那邊回傳的是一個 Promise),不知道你有沒有用過 async/await ,有的話你可以試著這樣:
for (const data of dataList) {
this.list = data // 設定資料的部份
await Vue.nextTick() // 等待 Vue 更新畫面
const canvas = await html2canvas(...) // 取得截圖
}
nextTick
的使用可以去看 Vue 的文件
沒用過 async/await 要用 then
的話也是可以,只是比較麻煩:
dataList.reduce((prev, data) => {
return prev.then(() => {
this.list = data
return Vue.nextTick()
}).then(() => {
return html2canvas(...)
}).then((canvas) => {
// ... 取得 base64
})
}, Promise.resolve())