el-upload实现可替换、删除、预览的图片上传
<template>
<div>
<UploadImage sendUrl='' :limit="1" :size="size" :gifSize="gifSize" v-model="images"></UploadImage>
</div>
</template>
<script>
import Vue from 'vue'
import UploadImage from './UploadImage.vue'
export default {
components: {
UploadImage
},
data(){
retun {
images:'',
size: 400 * 1024,
ifSize: 1 * 1024 * 1024,
// images:[]
}
}
}
</script>
UploadImage.vue
组件:<template>
<div class="uploadFileMain" :style="{'--height':`${height}px`,'--width':`${width}px`}">
<div v-for="(item,index) in fileList" :key="index" class="upload-list" :class="[limit==1?'upload-lis1':'']">
<div v-if="switchIndex==index && showProgress" v-loading="true" class="loadingView" element-loading-background="rgba(0, 0, 0, 0.8)" />
<img :id="`${idName}_image_${index}`" class="el-upload-listImg" :src="item.url" alt="">
<span class="el-actions">
<span
class="el-upload-icon"
@click="handlePictureCardPreview(index,item.url)"
>
<i class="el-icon-zoom-in" />
</span>
<span
class="el-upload-icon"
@click="switchFn(index)"
>
<i class="el-icon-sort" style="transform: rotate(90deg);" />
</span>
<span
class="el-upload-icon"
@click="delRemove(index)"
>
<i class="el-icon-delete" />
</span>
</span>
</div>
<el-upload
v-show="!limit || fileList.length<limit"
:ref="`${idName}_upload`"
:show-file-list="false"
:multiple="multiple"
:limit="limit?limit+1:limit"
:action="sendUrl"
list-type="picture-card"
:headers="{Authorization: $utils.getToken()}"
:accept="acceptArray.length>0?acceptArray.map(n=>this.acceptType[n]).join(',') :'*'"
:file-list="fileList"
:before-upload="beforeUpload"
:on-progress="progressFn"
:on-success="uploadSuccess"
>
<div v-if="switchIndex==-1 && showProgress" v-loading="true" :style="{'height':`${height}px`,'width':`${width}px`}" class="loadingView" element-loading-background="rgba(0, 0, 0, 0.8)" />
<div v-else class="uploadClick" :id="`${idName}_uploadClick`" slot="trigger" @click="changeIndex(-1)">
<i class="el-icon-plus" />
</div>
</el-upload>
</div>
</template>
<script>
import Vue from 'vue'
export default {
props: {
sendUrl: {
type: String,
default: ''
},
value: {
type: [Array, String],
default: ''
},
width: {
type: [Number, String],
default: 80
},
height: {
type: [Number, String],
default: 80
},
multiple: {
type: Boolean,
default: true
},
limit: {
type: Number,
default: null
// default: 4
},
// 大小限制:10 * 1024 * 1024 = 10MB
size: {
type: Number,
default: -1
},
// 限制类型,按照acceptType数组里面来
acceptArray: {
type: Array,
default: () => {
return ['png', 'jpg', 'jpeg', 'gif']
}
},
gifSize: {
type: Number,
default: -1
}
},
data() {
return {
acceptType: {
'doc': 'application/msword',
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'xls': 'application/vnd.ms-excel',
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'pdf': 'application/pdf',
'csv': '.csv',
'txt': 'text/plain',
'image': 'image/*',
'png': 'image/png',
'gif': 'image/gif',
'jpg': 'image/jpg',
'jpeg': 'image/jpeg'
},
idName: `${Math.random().toString(36).slice(-8)}_${new Date().getTime()}`,
switchIndex: -1,
fileList: [],
dataArray: {
1: [],
2: []
},
showProgress: false
}
},
watch: {
value: {
handler(value) {
if (Array.isArray(value)) {
this.fileList = value.filter(n => n != '').map(n => {
return {
url: n
}
})
} else {
this.fileList = value.split(',').filter(n => n != '').map(n => {
return {
url: n
}
})
}
},
deep: true,
immediate: true
},
fileList: {
handler(value) {
if (value.length > 0) {
this.toFileImg(value)
}
},
deep: true,
immediate: true
},
dataArray: {
handler(value) {
// 1 和 2 相等表示这次上传成功的数量相同,会添加到数组里面
if (value[1].length != 0 && value[2].length != 0 && value[1].length == value[2].length) {
value[2].forEach(e => {
// 有更换就变化
if (this.switchIndex != -1) {
this.fileList.splice(this.switchIndex, 1, {
status: 'success',
url: e.data
})
} else {
// 没有更好追加
this.fileList.push({
status: 'success',
url: e.data
})
}
})
setTimeout(() => {
this.showProgress = false
this.switchIndex = -1
}, 300)
this.dataArray = {
1: [],
2: []
}
}
},
deep: true
}
},
methods: {
async lookImageViewer(url, list) {
let listImg = list
const thisIndex = list.indexOf(url)
const firstArray = list.slice(thisIndex, list.length)
const twoArray = list.slice(0, thisIndex)
listImg = [...firstArray, ...twoArray]
// this.$viewerApi({ images: listImg })//v-viewer组件
const id = 'MyElImageViewer_' + new Date().getTime() + '_' + parseInt(Math.random() * 1000)
// 引用组件(找到Elementui中image-viewer的位置)
const ElImageViewer = (await import('element-ui/packages/image/src/image-viewer')).default
const MyElImageViewer = Vue.component('MyElImageViewer', ElImageViewer)
const MyElImageViewerNew = new MyElImageViewer({
propsData: {
urlList: listImg,
onClose: () => {
// 删除组件
compDOm.$destroy()
document.body.removeChild(document.getElementById(id))
}
}
})
const DOM = document.createElement('div')
DOM.setAttribute('id', id)
DOM.setAttribute('class', 'imageSwipeViewer_Show')
document.body.appendChild(DOM)
// 挂载组件
const compDOm = MyElImageViewerNew.$mount(DOM.appendChild(document.createElement('template')))
compDOm.$nextTick(() => {
const showDom = document.getElementById(id)
showDom.querySelector('.el-icon-circle-close').style = 'font-size:38px;color:#fff'
})
},
filterSize(size) {
const pow1024 = (num) => {
return Math.pow(1024, num)
}
if (!size) return ''
if (size < pow1024(1)) return size + ' B'
if (size < pow1024(2)) return (size / pow1024(1)).toFixed(0) + ' KB'
if (size < pow1024(3)) return (size / pow1024(2)).toFixed(0) + ' MB'
if (size < pow1024(4)) return (size / pow1024(3)).toFixed(0) + ' GB'
return (size / pow1024(4)).toFixed(2) + ' TB'
},
// 上传之前放到1
beforeUpload(e) {
const fileSize = e.size
if (this.gifSize > 0) {
if (e.type.indexOf('gif') != -1 && fileSize > this.gifSize) {
this.$message.error(`gif最大上传${this.filterSize(this.gifSize)}`)
return false
}
} else {
if (this.size > 0 && fileSize > this.size) {
this.$message.error(`最大上传${this.filterSize(this.size)}`)
return false
}
}
this.dataArray[1].push({
status: 'uploading',
...e
})
return true
},
// 通过 slot="trigger" ,区分模拟点击,表示这次时人为点击的
changeIndex(index) {
if (index == -1) {
this.switchIndex = -1
}
},
progressFn(e) {
this.showProgress = true
},
// 更换图片,模拟点击
switchFn(index) {
document.getElementById(`${this.idName}_uploadClick`).click(this.switchIndex)
setTimeout(() => {
this.switchIndex = index
}, 0)
},
// 查看图片
handlePictureCardPreview(index, url) {
this.lookImageViewer(url, [url])
},
// 成功后放到2
uploadSuccess(e) {
this.dataArray[2].push({
...e
})
},
// 传递图片
toFileImg(value) {
if (Array.isArray(this.value)) {
this.$emit('input', value.map(n => n.url))
} else {
this.$emit('input', value.map(n => n.url).join(','))
}
},
delRemove(index) {
this.fileList.splice(index, 1)
if (this.fileList.length == 0) {
this.toFileImg(this.fileList)
}
}
}
}
</script>
<style lang="scss" scoped>
::v-deep .el-upload--picture-card{
width: var(--width);
display:flex;
justify-content:center;
align-items:center;
height: var(--height);
}
.uploadClick{
width: var(--width);
display:flex;
justify-content:center;
align-items:center;
height: var(--height);
}
::v-deep .el-upload-list--picture-card .el-upload-list__item{
width: var(--width);
display:flex;
align-items:center;
height: var(--height);
transition: none !important;
}
::v-deep .el-upload-list__item .el-icon-check{
position: absolute;
margin-top: 0px;
top: 10px;
right: 14px;
}
::v-deep .el-loading-spinner{
width: 100%;
height: 100%;
top: 0;
margin-top: 0;
display: flex;
align-items: center;
justify-content: center;
}
::v-deep .el-upload-list,::v-deep .el-upload-list--picture-card{
//display: none;
}
.uploadFileMain{
display: flex;
flex-wrap: wrap;
.upload-list{
flex-shrink:0;
width: var(--width);
border:1px solid #0000005d;
box-sizing: border-box;
height: var(--height);
margin-right: 20px;
margin-bottom: 10px;
&.upload-lis1{
margin-bottom: 0px;
}
overflow: hidden;
border-radius: 8px;
position: relative;
.el-actions{
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
align-items: center;
justify-content: center;
display: none;
.el-upload-icon{
margin: 5px;
i{
color: #ffffff;
cursor: pointer;
}
}
}
&:hover{
.el-actions{
display: flex;
}
}
}
.el-upload-listImg{
width: 100%;
height: 100%;
object-fit: contain;
}
}
.loadingView{
width: 100%;
height: 100%;
}
</style>
往返缓存(BFCache)
BFCache是一种浏览器优化,可实现即时前进和后退载入页面。它改善了用户的浏览体验,尤其是那些网络或设备速度较慢的用户。
*我们可以通过这个方法判断当前页面是不是返回的页面*
在APP站内嵌套h5页面,判断进入拨号页返回情况:
我们需要通过visibilitychange
通过在点击时修改一个状态值,回来时和上面的方法进行判断
const isClick=false // 是否点击了离开页面按钮
const isShowPop=false // 是否显示弹窗
document.addEventListener('visibilitychange', () => {
if (document.visibilityState == "visible") {
if (isClick) {
isShowPop = true
}
isClick = false
} else {}
})
如果是在浏览器里面,判断进入拨号页(三方客服链接)返回情况:
在浏览器里面如果是离开了页面还是可以通过visibilitychange
判断,但是跳转的是三方客服链接,那我我们回到页面,页面是会重新刷新的,我们需要知道是否返回了,就需要通过performance.getEntriesByType('navigation')[0].type
同时通过在点击时修改一个状态值,回来时和上面的方法进行判断
const isClick=false // 是否点击了离开页面按钮
const isShowPop=false // 是否显示弹窗
const pageshowFn=(event)=> {
const navigationType = performance.getEntriesByType('navigation')[0].type
const {persisted = null} = event
if (persisted || navigationType == 'back_forward') {
isShowPop = true
isClick = false
}
}
window.removeEventListener('pageshow', pageshowFn)
window.addEventListener('pageshow', pageshowFn)
// 页面初次进入需要调用
pageshowFn({})