前言
在工作中会使用到上传组件,在pc端项目中使用的大多都是element-ui组件或根据需求进行二次封装。在使用后也做了简易版的上传的组件。接下来分析下组件的实现过程。组件样式
在HTML表单中,可以上传文件的唯一控件就是而原始的组件样式太丑了,我们需要给它'改头换面'。
思路:
就是在点击我们设定好的元素上(假身)时,触发input的chang事件从而弹出可以选择本地文件的窗口。实现:
// template
"button__text"
@click="onUploadClick">{{text}}
"file"
class="button__file"
type="file"
@change="onFileChange">
// js
onUploadClick() {
this.$refs.file.click()
}
复制代码
当点击button__text
的元素时,触发上传文件click事件,相当于我们点击'假身'的时候也点击了上传按钮
。具体也可以查看这篇文章。经过上面代码之后,我们给原始的按钮也是改头换面了。
获取本地文件信息
本地文件在点击上传按钮->选择文件后就会在的change事件中得到。
// 获取File引用:
onFileChange(event) {
const file = event.target.files[0]
if (file === undefined) {
return
}
}
复制代码
一般在这个阶段,我们就可以对文件格式大小做限制。
文件上传的整体流程
使用阿里云对象存储服务(oss)存储过程如下图:
- 用户调用接口请求上传的Policy Policy的作用是网站开发者用来
限制
网站用户上传的规则。 - 服务器返回Policy和Signature 在 HTTP 请求中增加 Authorization(授权)的 Head 来包含签名 信息,表明这个消息已被授权。
- 上传数据至oss
上传文件至oss核心步骤
在此函数之前已经拿到oss上传的Policy,signature,bucket(存储空间)在ossParam对象下传入,localfile为本地的文件信息,filehashkey是一个随机的三位数作为hash值的一部分,后面三个是回调函数。由于上传过程中处理的情况较为繁琐只对整体的思路和操作进行分析。
function doUploadFileToOss(
localfile,
ossParam,
filehashkey,
success,
progress,
fail
){
// ajax 发送的参数需要格式化,FormData对象用以将数据编译成键值对,以便用XMLHttpRequest来发送数据
const formatParams = new FormData()
// 调用它的append()方法来添加字段
for (let key in ossParams) {
formatParams.append(key, ossParams[key])
}
formatParams.append('file', localfile)
const ajax = new XMLHttpRequest()
// 绑定事件来监听上传进度 progressEvent上传进度的信息 loaded属性表示已上传的多少,total属性表示文件总的大小
ajax.upload.onprogress = function(progressEvent) {
if (progressEvent.type === 'progress') {
// 计算进度
const percent = Math.round(
(progressEvent.loaded / progressEvent.total) * 100,
2
)
// 执行传入的进度回调函数
progress && progress(percent)
}
}
// 创建http请求参数 (提交方式,提交的地址)
ajax.open('POST', bucket)
ajax.send(formatParams)
}
复制代码
element ui样式
代码可查看 此处css样式和html代码比较长,建议查看该文件。效果实现用到的知识点如下:
元素作为多个元素/组件的过渡效果。使用方法可查看官方文档- 文件名颜色,进度条和关闭按钮的过渡效果使用css的 transition和hover属性
- 复制链接功能实现代码如下
// template
"input"
class="upload__copy"
type="text"
:value="copyFile">
// js
onFileCopyClick(index) {
this.copyFile = this.fileList[index].filePath
this.$refs.input.focus()
setTimeout(() => {
// 判断是否能执行复制
const canCopy = document.execCommand('copy')
if (canCopy) {
// 获取input框的值
this.$refs.input.select()
// 执行复制功能
document.execCommand('copy')
this.$message({
message: '复制链接成功',
type: 'success'
})
}
}, 200)
}
复制代码
思路:
当点击文件名时,将对应图片路径赋值给input(作用:用来装当前值,可以执行document.execCommand命令),ocument.execCommand 用于操纵可编辑区域的内容
,并且将input聚焦
执行点击复制的功能。
多种样式的切换
饿了么官方组件中提供多种上传组件样式,其源码设计的设计思路以及jsx等方法使复用度比较高,代码简洁。但是目前个人水平受限,关于多个样式的上传组件目前采用动态组件的方式
import button from './button.vue'
const componentList = [button]
export default componentList
复制代码
在main.js中注册组件
import componentList from './components/upload/component.js'
componentList.forEach(component => {
Vue.component(component.name, component)
})
复制代码
在页面使用组件 实现多个组件样式的切换
"uploadButton">
data() {
return {
uploadButton: 'uploadButton'
}
复制代码
参考
廖雪峰
vue
完整代码