圖片粘貼上傳场晶,大家基本都司空見慣了诗轻,不足為奇。(本文只是水記一下扳炬,有空深挖細耕)
某日產(chǎn)品大大發(fā)話:
- 某:“這個沖賬憑證上傳恨樟,能加個圖片粘貼上傳功能嗎?”
- 我(凡事一句):“為什么缩多?”
- 某:“理由是:用戶覺得,截個屏 > 保存到本地 > 選擇這個文件上傳衬吆,太麻煩逊抡。直接截圖上傳,省事冒嫡〉埔ィ”
- 我(無力反駁):“哦,我試試峻呛」家ぃ”
由于用的 iView,先去扒扒有沒有 API 提供牙勘。文檔沒有所禀,圍觀源碼,欸恭金,居然寫了這么一段代碼褂策,upload.vue#L7:
...
@paste="handlePaste"
...
...
handlePaste (e) {
if (this.paste) {
this.uploadFiles(e.clipboardData.files);
}
}
...
但是斤寂,為什么凡事都有個但是?人家還沒發(fā)布 releases...
這種類似的功能罗侯,網(wǎng)上搜羅也一大堆溪猿。哎呦喂蒂培,挺簡單的护戳,監(jiān)聽 paste
事件垂睬,獲取 event 里面的內容就行了。擼起袖子就是干钳枕,照著源碼畫葫蘆赏壹。
分分鐘就搞定了,圖片也能上傳昔瞧。然鵝菩佑,為什么可粘貼區(qū)域這么詭異...
看來 iView 那個也是個半成品稍坯,我還是扶墻好了
開始去 MDN 看 paste ,結果寥寥幾字混巧,沒什么參考性勤揩。
梅西表示,我現(xiàn)在慌的一匹...
順著摸到 W3 的 clipboard-event-paste:
...
The paste action has no effect in a non-editable context, but the paste event fires regardless.
...
表示并沒怎么看懂這段英文...
所以缠犀,大致意思是,不可編輯的元素辨液,無效滔迈?加個屬性試試:
<div contenteditable="true" @paste="pasteHandler" ></div>
嗯被辑,現(xiàn)在敬惦,只有點擊這個 div
才會觸發(fā)這個 paste
事件。
但是宏怔,但是畴椰,同時也帶來了用戶可以隨意輸入斜脂、編輯、粘貼任何內容的問題......
我的內心玷或,時而堅強销斟,時而奔潰...
然后蚂踊,我想了個搓的方式:
- 字體設置為 0
- 子元素 display: none
- 子元素字體大小為 0
.paste {
overflow: hidden;
height: 140px;
font-size: 0;
line-height: 140px;
text-align: center;
border: 1px dashed #dddee1;
background-color: #fff;
/deep/ * {
display: none !important;
font-size: 0 !important;
}
&:after {
display: inline-block;
font-size: 12px;
content: "點擊,粘貼圖片上傳";
}
}
這種方式棱诱,就是不顯示給你看涝动,倒是非常不優(yōu)雅的解決了。
不過本身這種交互方式靡菇,就感覺怪怪的:
- 點擊一個區(qū)域
- Ctrl + V 粘貼圖片
- 上傳
暫且這樣吧米愿,目前木有想到更好的方式。
待我發(fā)了個測試版后较鼓,發(fā)現(xiàn) FireFox 4.x 不支持博烂。
經(jīng)測測試,paste 事件有響應畜伐。但是 event 里面谆级,files 為空,啊哈哈哈...
偶然發(fā)現(xiàn)脚仔,其實舆绎,瀏覽器插入富文本到里面了:
再回想到 W3 的 clipboard-event-paste:
...
If the cursor is in an editable context, the paste action will insert clipboard data in the most suitable format (if any) supported for the given context.
...
再讀一遍 ...in the most suitable format ...
怎么辦呢吕朵?
- 獲取 img 元素
- 讀取 base64
- base64 轉 Blob
- Blob 轉 File
- 上傳
base64toBlob (base64Data) {
let byteString
if (base64Data.split(',')[0].indexOf('base64') >= 0) {
byteString = atob(base64Data.split(',')[1])
} else {
byteString = unescape(base64Data.split(',')[1])
}
const mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0]
const ia = new Uint8Array(byteString.length)
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i)
}
return new Blob([ia], {type:mimeString})
},
hackForFireFox () {
// 等待 dom 更新
this.$nextTick(() => {
const $img = this.$refs.paste.querySelector('img')
if (!$img) {
return
}
const base64Data = $img.getAttribute('src')
const blob = this.base64toBlob(base64Data)
const file = new File([blob], 'image.png')
this.$refs.paste.innerHTML = '' // 清空上傳的圖片
this.$refs.upload.uploadFiles([file])
})
},
// 粘貼事件處理
pasteHandler (e) {
// 如果配置了運行粘貼上傳
if (this.paste) {
// 高版本瀏覽器努溃,能直接拿到 files
// 我司不考慮 IE,故未兼容處理
if (e.clipboardData.files.length > 0) {
this.$refs.upload.uploadFiles(e.clipboardData.files)
} else {
// 否則沦疾,嘗試讀取富文本
this.hackForFireFox()
}
}
}
總結
不是很好的解決方式第队,踩了幾個坑,算是個思路吧忆畅。后面有新想法尸执,再補上如失。
其實,我的內心岖常,是不接受這種方式的...
—— 2018/07/31 By Vinci竭鞍, Partly Cloudy.