项目使用的是vue框架,需要一个markdown的编辑框,就在npm上找了一下,发现simplemde挺不错的,由于我比较懒,就顺便在npm又搜了一下,找到了vue-simplemde这个 package ,那就开始使用它吧。
但是这个 vue-simplemde 不支持图片拖拽上传、粘贴上传,也不能说是因为这个 vue-simplemde ,因为 vue-simplemde 只是对 simplemde 的基础上封装成一个Vue插件。所以最后还是由于 simplemde 没有提供相关的功能,但是为了用户体验考虑,这个功能时必要的,除非不使用markdown编辑器。而去使用富文本编辑器,那样的话,项目很多的代码都要进行更改。所以就在网上查了文章,及在github上查了一些代码。下面将进行分析
拖拽
拖拽的API核心是 drop 这个事件,就是当我们从桌面拖动一个文件到浏览器里时,松开的时候,而触发的事件名。
我们都知道,你随便拖动一个图片到浏览器里,会直接打开这个图片,这是因为浏览器默认你拖动文件到浏览器里时,将打开这个文件,所以,我们需要阻止原生的操作。
我们现在先写一段代码,让其屏蔽掉默认事件
window.addEventListener("drop", e => {
e = e || event
if (e.target.className === 'CodeMirror-scroll') { // 如果进入到编辑器的话,将阻止默认事件
e.preventDefault()
}
}, false)
CodeMirror-scroll 这个Class就是 simplemde 编辑框的Class名称。
现在我们拖拽文件到这个编辑框,然后松掉,不会出现任何反应。如果在编辑框之外的地方,还是会继续触发默认事件。
下面就是获取 simplemde 方法,给他 drop 事件处理方法。
// 假设页面一共有三个编辑窗口,所以需要循环监听事件
[ this.$refs.simplemde1,
this.$refs.simplemde2,
this.$refs.simplemde3
].map(({simplemde}) => {
simplemde.codemirror.on('drop', (editor, e) => {
if (!(e.dataTransfer && e.dataTransfer.files)) {
// 弹窗说明,此浏览器不支持此操作
return
}
let dataList = e.dataTransfer.files
let imageFiles = [] // 要上传的文件实例数组
// 循环,是因为可能会同时拖动几个图片文件
for (let i = 0; i < dataList.length; i++) {
// 如果不是图片,则弹窗警告 仅支持拖拽图片文件
if (dataList[i].type.indexOf('image') === -1) {
// 下面的continue,作用是,如果用户同时拖动2个图片和一个文档,那么文档不给于上传,图片照常上传。
continue
}
imageFiles.push(dataList[i]) // 先把当前的文件push进数组里,等for循环结束之后,统一上传。
}
// uploadImagesFile方法是上传图片的方法
// simplemde.codemirror的作用是用于区分当前的图片上传是处于哪个编辑框
this.uploadImagesFile(simplemde.codemirror, imageFiles)
// 因为已经有了下面这段代码,所以上面的屏蔽默认事件代码就不用写了
e.preventDefault()
})
})
诈一看,代码好像有点多,那是因为注释的原因,下面是没有注释的代码。你可以根据下面的代码,有自己的见解和理解:
[ this.$refs.simplemde1,
this.$refs.simplemde2,
this.$refs.simplemde3
].map(({simplemde}) => {
simplemde.codemirror.on('drop', (editor, e) => {
if (!(e.dataTransfer && e.dataTransfer.files)) {
return
}
let dataList = e.dataTransfer.files
let imageFiles = []
for (let i = 0; i < dataList.length; i++) {
if (dataList[i].type.indexOf('image') === -1) {
continue
}
imageFiles.push(dataList[i])
}
this.uploadImagesFile(simplemde.codemirror, imageFiles)
e.preventDefault()
})
})
粘贴
粘贴的API是 paste 方法,这个不像上面一样,粘贴不需要禁止默认事件,因为我们可以看到,你复制一个图片,到浏览器里按下 ctrl+v 的时候,是不会发生任何变化的,所以没用必要禁止默认事件。
下面是代码:
simplemde.codemirror.on('paste', (editor, e) => { // 粘贴图片的触发函数
if (!(e.clipboardData && e.clipboardData.items)) {
// 弹窗说明,此浏览器不支持此操作
return
}
try {
let dataList = e.clipboardData.items
if (dataList[0].kind === 'file' && dataList[0].getAsFile().type.indexOf('image') !== -1) {
this.uploadImagesFile(simplemde.codemirror, [dataList[0].getAsFile()])
}
} catch (e) {
// 弹窗说明,只能粘贴图片
}
})
之所以这里写上 try...catch 方法,是因为如果你粘贴的时候,如果是一个文件, items 将是空的,而在下面的if循环里,使用 dataList[0].kind 。也就是 e.clipboardData.items[0].kind 。当 item 为空时,还去访问一个不存的 kind 属性时,就会报错了。所以这里需要使用 try...catch 方法进行判断。
dataList[0].getAsFile().type.indexOf('image') !== -1 这个句话是判断,粘贴的东西确认是图片,而不是其他东西。
if 里的上传图片,不一样的地方是 [dataList[0].getAsFile()] ,因为为了统一格式,方便 uploadImagesFile 函数进行处理,我加上了 [] ,使之成为数组。 dataList[0].getAsFile() 就是获取文件实例了。
上传
上传就有一点麻烦了:
uploadImagesFile (simplemde, files) {
// 把每个文件实例使用FormData进行包装一下,然后返回一个数组
let params = files.map(file => {
let param = new FormData()
param.append('file', file, file.name)
return param
})
let makeRequest = params => {
return this.$http.post('/Api/upload', params)
}
let requests = params.map(makeRequest)
this.$http.spread = callback => {
return arr => {
return callback.apply(null, arr)
}
}
// 服务端返回的格式是{state: Boolean, data: String}
// state为false时,data就是返回的错误信息
// state为true时,data是图片上传后url地址,这个地址是针对网站的绝对路径。如下:
// /static/upload/2cfd6a50-3d30-11e8-b351-0d25ce9162a3.png
Promise.all(requests)
.then(this.$http.spread((...resps) => {
for (let i = 0; i < resps.length; i++) {
let {state, data} = resps[i].data
if (!state) {
// 弹窗显示data的错误信息
continue
}
let url = `` // 拼接成markdown语法
let content = simplemde.getValue()
simplemde.setValue(content + url + '\n') // 和编辑框之前的内容进行拼接
}
}))
}
因为我是把 axiox 封装成vue插件来使用,这样会导致, this.$http 是实例化后的,而不是他本身。 axios 维护者说的解决方案是,重新引入 axios 包,来使用。但是我觉得没有必要。 axios.all 内部是 Promise.all 。 axios.spread 实现代码比较少,就直接拿过来,重新赋值给 axios 就好了
所以上面有段代码是
Promise.all(requests)
.then(this.$http.spread((...resps) => {
// code
})
把这段代码翻译一下就是
axios.all(requests)
.then(axios.spread((...resps) => {
// code
})
关于这个问题,请看下官方的解释:axios-all-is-not-a-function-inside-vue-component 。也可以看下 axios 的代码: axios.js#L45-L48
这个问题,暂时就不深究了,我们回到刚刚的话题上。
上面我说到当state为true时,data是文件相对于网站的绝对路径,如: /static/upload/2cfd6a50-3d30-11e8-b351-0d25ce9162a3.png
如果我们需要进行拼接一下,所以就有了  这段代码进行拼接。最后的两行是获取指的获取之前的内容,然后在追加url地址。
免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
RTX 5090要首发 性能要翻倍!三星展示GDDR7显存
三星在GTC上展示了专为下一代游戏GPU设计的GDDR7内存。
首次推出的GDDR7内存模块密度为16GB,每个模块容量为2GB。其速度预设为32 Gbps(PAM3),但也可以降至28 Gbps,以提高产量和初始阶段的整体性能和成本效益。
据三星表示,GDDR7内存的能效将提高20%,同时工作电压仅为1.1V,低于标准的1.2V。通过采用更新的封装材料和优化的电路设计,使得在高速运行时的发热量降低,GDDR7的热阻比GDDR6降低了70%。
更新日志
- 小骆驼-《草原狼2(蓝光CD)》[原抓WAV+CUE]
- 群星《欢迎来到我身边 电影原声专辑》[320K/MP3][105.02MB]
- 群星《欢迎来到我身边 电影原声专辑》[FLAC/分轨][480.9MB]
- 雷婷《梦里蓝天HQⅡ》 2023头版限量编号低速原抓[WAV+CUE][463M]
- 群星《2024好听新歌42》AI调整音效【WAV分轨】
- 王思雨-《思念陪着鸿雁飞》WAV
- 王思雨《喜马拉雅HQ》头版限量编号[WAV+CUE]
- 李健《无时无刻》[WAV+CUE][590M]
- 陈奕迅《酝酿》[WAV分轨][502M]
- 卓依婷《化蝶》2CD[WAV+CUE][1.1G]
- 群星《吉他王(黑胶CD)》[WAV+CUE]
- 齐秦《穿乐(穿越)》[WAV+CUE]
- 发烧珍品《数位CD音响测试-动向效果(九)》【WAV+CUE】
- 邝美云《邝美云精装歌集》[DSF][1.6G]
- 吕方《爱一回伤一回》[WAV+CUE][454M]