info
This commit is contained in:
@@ -0,0 +1,199 @@
|
||||
import './image-uploading.css'
|
||||
|
||||
export default function (Quill) {
|
||||
// const Delta = Quill.import('delta')
|
||||
|
||||
class ImageExtend {
|
||||
constructor(quill, config) {
|
||||
this.quill = quill
|
||||
this.config = config
|
||||
|
||||
// 通过监听内容变化判断是否上传图片
|
||||
quill.on(Quill.events.TEXT_CHANGE, (delta) => {
|
||||
const imageElements = quill.container.querySelectorAll('img[data-local]:not(.uploading)')
|
||||
|
||||
imageElements.forEach(element => {
|
||||
if (element.classList.contains('uploaded')) {
|
||||
element.removeAttribute('data-local')
|
||||
element.classList.remove('uploaded')
|
||||
if(element.classList.length <= 0) {
|
||||
element.removeAttribute('class')
|
||||
}
|
||||
} else {
|
||||
this.uploader(element)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 插入粘贴的文件图片
|
||||
quill.root.addEventListener('paste', (e) => {
|
||||
|
||||
const files = Array.from(e.clipboardData.files || []);
|
||||
|
||||
if (files.length > 0) {
|
||||
e.preventDefault();
|
||||
setTimeout(() => {
|
||||
this.insertFileImage(files[0])
|
||||
}, 0)
|
||||
}
|
||||
}, false)
|
||||
|
||||
// 插入粘贴的网络图片
|
||||
quill.clipboard.addMatcher('IMG', function (node, delta) {
|
||||
if (!delta.ops[0].attributes) {
|
||||
delta.ops[0].attributes = {}
|
||||
}
|
||||
|
||||
delta.ops[0].attributes['data-local'] = node.src
|
||||
|
||||
delta.ops[0].attributes = Object.keys(delta.ops[0].attributes).reduce((attributes, key) => {
|
||||
if (['data-local', 'alt'].includes(key)) {
|
||||
attributes[key] = delta.ops[0].attributes[key]
|
||||
}
|
||||
|
||||
return attributes
|
||||
}, {})
|
||||
return delta
|
||||
});
|
||||
}
|
||||
|
||||
async uploader(element) {
|
||||
// 标记元素正在上传
|
||||
element.classList.add('uploading')
|
||||
|
||||
// 检查是否配置了上传方法
|
||||
if (typeof this.config.uploadHandler !== 'function') {
|
||||
console.warn('没有配置图片上传方法,移除图片:' + element.src)
|
||||
Quill.find(element).deleteAt(0)
|
||||
return
|
||||
}
|
||||
|
||||
const imageFile = await this.convertImageFile(element.src)
|
||||
|
||||
// 构建上传元素
|
||||
const uploadNode = this.getUploadNode(element.src)
|
||||
// 获取位置
|
||||
const parent = this.quill.root.parentNode
|
||||
|
||||
setTimeout(() => {
|
||||
|
||||
const elementRect = element.getBoundingClientRect()
|
||||
const containerRect = parent.getBoundingClientRect()
|
||||
|
||||
uploadNode.style.left = `${elementRect.left - containerRect.left - 1 + parent.scrollLeft}px`
|
||||
uploadNode.style.top = `${elementRect.top - containerRect.top + parent.scrollTop}px`
|
||||
uploadNode.style.width = `${elementRect.width}px`
|
||||
uploadNode.style.height = `${elementRect.height}px`
|
||||
|
||||
// 渲染到element上
|
||||
parent.appendChild(uploadNode)
|
||||
}, 100)
|
||||
|
||||
// 上传图片 展示进度
|
||||
Promise.resolve({
|
||||
then: (resolve, reject) => {
|
||||
try {
|
||||
const handler = this.config.uploadHandler(imageFile, element)
|
||||
resolve(handler)
|
||||
} catch (e) {
|
||||
reject(e)
|
||||
}
|
||||
}
|
||||
}).then((url) => {
|
||||
const customData = (element.getAttribute('data-custom') || '').split('&').filter(item => item).reduce((res, item) => {
|
||||
const [key, value] = item.split('=')
|
||||
res[key] = value
|
||||
return res
|
||||
}, {})
|
||||
|
||||
customData.source = url
|
||||
|
||||
element.src = url
|
||||
element.removeAttribute('data-local')
|
||||
element.classList.remove('uploading')
|
||||
element.setAttribute('data-custom', Object.keys(customData).map(key => `${key}=${customData[key]}`).join('&'))
|
||||
|
||||
parent.removeChild(uploadNode)
|
||||
}).catch((e) => {
|
||||
parent.removeChild(uploadNode)
|
||||
console.error(e)
|
||||
})
|
||||
}
|
||||
|
||||
async convertImageFile(imageUrl) {
|
||||
const result = {
|
||||
blob: imageUrl,
|
||||
ext: 'jpg',
|
||||
size: 0,
|
||||
}
|
||||
|
||||
// if (!/^blob:/.test(imageUrl)) {
|
||||
const image = await fetch(imageUrl)
|
||||
const blob = await image.blob()
|
||||
const mimeType = this.getBlobImageMimeType(blob, imageUrl)
|
||||
const ext = mimeType.replace('image/', '')
|
||||
const filename = `image.${ext}`
|
||||
const file = new File([blob], filename, {type: mimeType})
|
||||
|
||||
result.blob = this.file2blob(file)
|
||||
result.ext = ext
|
||||
result.size = file.size
|
||||
// }
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
getBlobImageMimeType(blob, imageUrl) {
|
||||
if (blob.type) {
|
||||
return blob.type
|
||||
}
|
||||
if (imageUrl.match(/data:(image\/\w+);base64/)) {
|
||||
return imageUrl.match(/data:(image\/\w+);base64/)[1].toLowerCase()
|
||||
}
|
||||
return 'image/jpeg'
|
||||
}
|
||||
|
||||
getUploadNode(imageUrl) {
|
||||
const div = document.createElement('div')
|
||||
const img = document.createElement('img')
|
||||
|
||||
img.src = imageUrl
|
||||
img.setAttribute('οndragstart', 'return false')
|
||||
div.appendChild(img)
|
||||
|
||||
div.classList.add('image-uploading')
|
||||
|
||||
return div
|
||||
}
|
||||
|
||||
file2blob(file) {
|
||||
let url
|
||||
if (window.createObjectURL !== undefined) {
|
||||
url = window.createObjectURL(file);
|
||||
} else if (window.URL !== undefined) {
|
||||
url = window.URL.createObjectURL(file);
|
||||
} else if (window.webkitURL !== undefined) {
|
||||
url = window.webkitURL.createObjectURL(file);
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
insertFileImage(file) {
|
||||
const range = this.quill.getSelection(true)
|
||||
const url = this.file2blob(file)
|
||||
if (range.index > 0 && this.quill.getText(range.index - 1, 1) !== '\n') {
|
||||
this.quill.insertText(range.index, '\n', Quill.sources.SILENT)
|
||||
range.index += 1
|
||||
}
|
||||
this.quill.insertEmbed(range.index, 'image', url, Quill.sources.SILENT)
|
||||
this.quill.formatText(range.index, 1, 'data-local', url, Quill.sources.SILENT)
|
||||
this.quill.insertText(range.index + 1, '\n', Quill.sources.SILENT)
|
||||
this.quill.setSelection(range.index + 2, Quill.sources.SILENT)
|
||||
this.quill.scrollIntoView()
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
'modules/ImageExtend': ImageExtend
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user