vue自定义组件封装_vue组件的双向绑定实现

2022-11-09 13:14:45 浏览数 (3)

大家好,又见面了,我是你们的朋友全栈君。

封装组件的v-model

再看组件的时候,不如elementui等等,我们时常看到它们的组件都是直接通过v-model双向绑定的,而不是通过我们常用的属性(prop)传递过去,子组件修改通过$emit,或者通过vuex等等来返回父组件,这样的方法也不是说不行,但是总感觉没有elementui那样的写法高级。所以我们也来简单的封装一个看起来高级一点点的组件。 简单的借用elementui的组件做一个二开

代码语言:javascript复制
<template>
<div class="image-video-upload">
<div v-if="imageUrl" class="upload-success">
<custom-image :src="imageUrl" class="result-image" :style="imageStyle" />
<i v-if="!disabled" class="el-icon-circle-close" @click="handleRemove" />
</div>
<el-upload
v-show="!imageUrl"
ref="uploader"
class="uploader"
:action="action"
:disabled="disabled"
:headers="headers"
:accept="accept"
:show-file-list="false"
:on-success="handlerSuccess"
:on-error="handlerError"
:before-upload="beforeUploadHandler"
:style="imageStyle"
:on-progress="handleProcess"
:data="uploadData"
>
<el-progress v-if="uploading" type="circle" :percentage="percentage" :width="80" />
<i v-else class="el-icon-plus" />
</el-upload>
<div class="el-upload__tip" v-html="tip" />
</div>
</template>
代码语言:javascript复制
export default { 

name: 'UploadImage',
components: { 

CustomImage
},
props: { 

//v-model直接使用value
value: { 

type: String,
default: ''
},
bucket: { 

type: String,
default: 'knight-dev'
},
tip: { 

type: String,
default: ''
},
// 控制图片样式(长宽等)
imageStyle: { 

type: String,
default: 'width: 200px;height: 100px;'
},
accept: { 

type: String,
default: '.jpg,.jpeg,.png,.gif,.bmp,.JPG,.JPEG,.PBG,.GIF,.BMP'
},
width: { 

type: Number,
default: 0
},
height: { 

type: Number,
default: 0
},
// 图片尺寸验证类型
validType: { 

type: Number,
default: 0 // 0:比列验证,1:实际大小验证
},
// 图片尺寸验证
valid: { 

type: Number,
default: 0 // 0: 不验证,不提示 1:验证提示,不停止上传 2: 验证提示,停止上传
},
// 图片大小验证,单位M
imageSize: { 

type: Number,
default: 3
},
disabled: { 

type: Boolean,
default: false
}
},
data() { 

return { 

uploading: false,
percentage: 0,
imageUrl: this.value ? downloadUrl   '/'   this.value : '',
action: uploadUrl
}
},
computed: { 

uploadData() { 

return { 
 bucket: this.bucket }
},
headers() { 

const header = { 
}
const { 
 access_token,  login_name } = this.$store.getters.authInfo
header['Authorization'] = 'Bearer '   access_token
return header
}
},
watch: { 

value(value) { 

this.imageUrl = value ? downloadUrl   '/'   value : ''
}
},
methods: { 

handleProcess(event, file, fileList) { 

this.percentage =  file.percentage.toFixed(0)
},
beforeUploadHandler(file) { 

this.uploading = true
this.percentage = 0
const fileSize = file.size / 1024 / 1024
if (fileSize > this.imageSize) { 

this.uploading = false
this.$message.error(`图片文件大小不能超过 ${ 
this.imageSize}MB!`)
return false
} else if (this.valid == 0 || this.width == 0 || this.height == 0) { 

return true
}
return new Promise((resolve, reject) => { 

this.filetoDataURL(file, url => { 

this.dataURLtoImage(url, img => { 

const { 
 width, height } = this
let validTemp = true
let str = ''
if (this.validType == 0) { 

validTemp =
(width / height).toFixed(2) ==
(img.width / img.height).toFixed(2)
str = '比例'
} else { 

validTemp = width == img.width && height == img.height
str = '宽高'
}
if (!validTemp) { 

this.$message.error(`图片${ 
str}不符合建议要求!`)
if (this.valid == 2) { 

this.uploading = false
return reject()
}
}
resolve()
})
})
})
},
handlerSuccess(res) { 

if (res.code == 200) { 

const imageUrl = res.data.fileName[0]
this.uploading = false
this.setValue(imageUrl)
}
},
handlerError() { 

this.uploading = false
},
setValue(imageUrl) { 

this.imageUrl = imageUrl
//返回值直接使用$emit('input','value')即可
this.$emit('input', imageUrl)
},
handleRemove() { 

this.setValue('')
}
}
}
代码语言:javascript复制
.image-video-upload { 

display: flex; .uploader, .result-image { 

display: flex;
font-size: 28px;
color: #8c939d;
text-align: center;
background-color: #fbfdff;
border: 1px dashed #c0ccda;
border-radius: 6px;
cursor: pointer;
}
.result-image { 

border: 1px solid #c0ccda;
}
.uploader{ 

&:hover { 

border-color: #409eff;
color: #409eff;
}
::v-deep { 

.el-upload{ 

width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center; &:focus{ 

border-color: #fbfdff;
color: #8c939d;
}
&:hover{ 

border-color: #409eff;
color: #409eff;
}
}
}
}
.el-upload__tip { 

flex: 1;
line-height: 21px;
display: flex;
align-items: center;
margin-left: 20px;
margin-top: 0;
}
.upload-success { 

position: relative;
border-radius: 6px;
overflow: hidden; &:hover { 

.icon-success { 

display: none;
}
.remove-wrapper { 

display: flex;
}
}
.el-icon-circle-close{ 

position: absolute;
top: 0;
right: 0;
font-size: 20px;
color: #F56C6C;
}
}
.remove-wrapper { 

display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.5);
}
.icon-success { 

position: absolute;
right: -15px;
top: -6px;
width: 40px;
height: 24px;
// line-height: 24px;
text-align: center;
background: #13ce66;
-webkit-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 1pc 1px rgba(0, 0, 0, 0.2); .el-icon-check { 

color: #ffffff;
-webkit-transform: rotate(-45deg);
transform: rotate(-45deg);
}
}
.el-icon-delete { 

font-size: 20px;
color: #fff;
cursor: pointer;
}
}

这样使用的时候就可以直接引入组件使用了,绑定的值也是可以通过v-midel双向了

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/190462.html原文链接:https://javaforall.cn

1 人点赞