什么是组件化?
所谓组件化,就是把页面拆分成多个组件,每个组件依赖的 CSS、JS、模板、图片等资源放在一起开发和维护。 因为组件是资源独立的,所以组件在系统内部可复用,组件和组件之间可以嵌套,如果项目比较复杂,可以极大简化代码量,并且对后期的需求变更和维护也更加友好。
好处:增加代码的复用性、灵活性,从而提高开发效率。
技术点:
- 父往子传值
- 子往父传值
- 插槽技术
组件源码:
<template>
<el-dialog :title="upload.title" :visible.sync="visible" width="520px" append-to-body class="uploadFileBox" @close="closed">
<div class="temDownload">
<div class="content">
<div class="frontBox">
<div class="title">下载导入模板</div>
<div class="text">根据模板提示完善内容</div>
</div>
<div class="btnBox">
<el-button @click="handleDownLoadTemp"><i class="el-icon-download"></i>下载模板</el-button>
</div>
</div>
</div>
<el-upload drag ref="upload" class="text-center" :limit="upload.maxCount" :accept="accept" :auto-upload="false" :headers="upload.headers" :action="uploadUrl" :show-file-list="upload.showFileList" :before-upload="beforeUpload" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :on-error="handleError" :on-exceed="handleExceed" :on-change="handleChange" :on-remove="removeFile" :file-list="fileList">
<template v-if="fileList.length == 0">
<i class="el-icon-folder-opened" style="width:50px;height:50px">
<div class="el-upload__text fileName">将文件拖到此处,或<em>点击上传</em></div>
<div class="tips">{{`只能上传${accept}格式文件,且不超过10M`}}</div>
</template>
<template v-if="fileList.length > 0">
<i v-if="!zipType" class="el-icon-document" class="icon" width="50" height="50"></i>
<i v-else class="el-icon-film" class="icon" width="50" height="50"></i>
<div class="fileName">{{files.name}}</div>
<div><a>重新上传</a></div>
</template>
</el-upload>
<div slot="footer" class="dialog-footer">
<el-button @click="visible = false" size="small">取 消</el-button>
<el-button type="primary" @click="submitFileForm" size="small">确 定</el-button>
</div>
</el-dialog>
</template>
<script>
export default {
data() {
return {
visible: false,
zipType: false,//是否是zip包
fileList: [],
files: {},
upload: {
title: '导入',
headers: { Authorization: this.$cookie.get('token') }, //头部
url: process.env.NODE_ENV === "production" ? process.env.VUE_APP_BASE_API : "",//url前缀
showFileList: false,//是否显示文件列表
isUploading: false,
maxCount: 1, //限制个数
},
};
},
props: {
accept: {
type: String,
default: '.xlsx,.xls,.zip'
},
// type: Array,
uploadUrl: {
type: String,
default: ``
},
downloadType: {
type: String,
default: 'materialDefine'
},
value: String
},
methods: {
show() {
this.visible = true;
},
closed() {
this.visible = false
this.onClear()
},
/**
* 下载模板
*/
handleDownLoadTemp() {
this.$confirm('确定下载?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
this.$http({
url: this.$http.SystemAdornUrl(`/file/url?type=${this.downloadType}`),
method: 'get',
params: ''
}).then(({
data
}) => {
if (data && data.code === 200) {
window.open(data.msg);
this.$message({ message: '操作成功', type: 'success', duration: 1000 });
}
});
});
},
/**
* 提交文件
*/
submitFileForm() {
if (this.files) {
this.$refs.upload.submit();
} else {
this.$message.warning('请选择文件')
}
},
/**
* 图片格式校验
*/
beforeUpload(file) {
let _self = this;
/* 新增部分文件格式,用户切换所有文件时做格式限制 */
if (this.accept) {
let acc = this.accept.split(',')
let testmsg = file.name.substring(file.name.lastIndexOf('.'))
const extension = acc.filter(e => e === testmsg)
if (extension.length < 1) {
this.$message({ message: `您上传的文件格式不符合要求!只支持${acc.join(',')}格式的文件`, type: 'error', duration: 1500 })
this.onClear()
return false
}
}
/* 增加限制上传图片大小, 2021.4.14 */
if (file.size > 10 * 1024 * 1024) {
this.$message({
message: '文件大小不能超过10MB',
type: 'error',
duration: 1500
})
this.onClear()
return false;
}
this.loading = this.$loading({
lock: true,
text: 'Loading',
customClass: 'addloading',
background: 'rgba(0, 0, 0, 0.5)'
});
},
// 清除文件
onClear() {
this.files = {}
this.fileList = []
this.$refs.upload.clearFiles();
},
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
this.upload.isUploading = true;
},
// 文件上传成功处理
handleFileSuccess(response, file, fileList) {
this.loading.close();
if (response.code == 200) {
this.visible = false;
this.$emit('ok', response.data)
this.upload.isUploading = false;
this.$refs.upload.clearFiles();
this.$message.success('导入成功')
} else {
this.visible = false;
this.upload.isUploading = false;
this.$refs.upload.clearFiles();
this.$message.error(response.msg)
}
},
/**
* 上传失败
*/
handleError(err, file, fileList) {
this.loading.close();
if (err) {
this.$message({
message: JSON.parse(err.message).message,
type: 'error',
duration: 1500
})
}
},
/**
* 文件超出个数限制时调用
*/
handleExceed(files, fileList) {
this.$set(fileList[0], 'raw', files[0]);
this.$set(fileList[0], 'name', files[0].name);
this.$refs['upload'].clearFiles();//清除文件
this.$refs['upload'].handleStart(files[0]);//选择文件后的赋值方法
},
// 上传 change事件
handleChange(files, fileList) {
let type = files.name.substring(files.name.lastIndexOf('.') + 1)
if (type == 'zip') {
this.zipType = true
} else {
this.zipType = false
}
if (this.accept.indexOf(type) != -1) {
this.files = { ...files }
this.fileList = fileList
} else {
this.$message.warning(`只能上传${this.accept}格式文件`)
this.onClear()
}
},
removeFile(files, fileList) {
this.files = ''
},
},
};
</script>
<style lang="scss" scoped>
.uploadFileBox {
button {
padding: 8px 12px !important;
}
.temDownload {
width: 100%;
height: 88px;
background: #f8f9fd;
border-radius: 4px;
border: 1px solid #d4d9e1;
margin-bottom: 12px;
padding: 20px 24px;
box-sizing: border-box;
.content {
display: flex;
.frontBox {
width: 340px;
}
.title {
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #1d2129;
margin-bottom: 8px;
}
.text {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
}
.icon-mobantubiao {
color: #3e4756 !important;
display: inline-block;
}
}
.btnBox {
::v-deep svg:not(:root) {
padding-top: 2px !important;
}
}
}
.text-center {
width: 100%;
height: 210px;
svg:not(:root) {
margin-top: 52px;
}
.fileName {
height: 22px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #1d2129;
line-height: 22px;
margin-top: 14px;
}
em {
text-decoration: underline;
color: #165dff;
}
a {
text-decoration: underline;
height: 22px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #165dff;
line-height: 22px;
}
.tips {
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #86909c;
margin-top: 6px;
}
}
}
::v-deep .el-upload {
width: 100%;
.el-upload-dragger {
width: 100%;
height: 210px;
background: #f8f9fd;
border-radius: 4px;
border: 1px solid #d4d9e1;
}
}
::v-deep .el-dialog {
height: 438px;
display: flex;
flex-direction: column;
margin: 0 !important;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
.el-dialog__header {
padding: 24px 28px 12px 28px;
}
.el-dialog__body {
padding: 0 28px !important;
}
.el-dialog__footer {
padding: 0 28px 16px 28px;
width: 100%;
position: absolute;
bottom: 0;
right: 0;
}
}
</style>
全局注册:
import Upload from "@/components/upload/upload";
// 全局组件挂载
Vue.component('Upload', Upload)
组件使用:
<el-button @click="onUpload">上传</el-button>
<Upload ref="upLoadRef" :uploadUrl="`${$http.SystemAdornUrl('/file/upload')}`" @ok="handleOk"></Upload>
<script>
methods: {
onUpload(){
this.$refs.upLoadRef.show()
},
handleOk(data){
console.log(data,'dsssssssssss')
},
}
</script>
视图: