例子:
这里的prop是fileList
在子组件里,将fileList赋值给showFileList
并watch showFileList值的变化, emit(‘update:(属性名)’, (传递数据))
emit('update:fileList', state.showFileList)
......
const stopWatchShowFileList = watch(
() => state.showFileList,
() => {
emit('update:fileList', state.showFileList)
},
{ deep: true }
)
onMounted(() => {
state.showFileList = props.fileList.map((file) => {
file.url = file.id ? `${window.$config.imgURL}${file.id}` : file.url
return file
})
emit('change-upload-loading')
})
onBeforeUnmount(() => {
// stopWatchFileList()
stopWatchShowFileList()
})
详细代码:
父组件
<el-form-item
class="hidden-lg-only hidden-md-only hidden-xl-only"
label="产品图片"
prop="productImageList"
style="margin-top: 10px"
>
<template v-if="!formDisabled">
<el-icon v-show="uploadLoading" class="is-loading">
<vab-icon icon="loader-5-fill" />
</el-icon>
<upload
v-model:file-list="form.fileList"
:can-video="false"
@change-upload-loading="changeUploadLoading"
@fetch-data="fetchData"
/>
</template>
<imageList
v-else-if="formDisabled && form.fileList.length"
:key="form.id"
ref="imageListRef"
align="left"
:file-list="form.fileList"
:size="100"
:video-icon-size="50"
:wrap="true"
/>
<div v-else-if="formDisabled && !form.fileList.length">暂无图片</div>
</el-form-item>
子组件
<template>
<div>
<el-upload
v-model:file-list="showFileList"
:accept="accept"
:auto-upload="false"
list-type="picture-card"
:multiple="true"
:on-change="onFileChange"
>
<template #file="{ file }">
<div>
<!-- todo study -->
<el-image
v-if="matchType(file.name || file.fileName)"
alt=""
class="el-upload-list__item-thumbnail"
fit="fill"
:src="file.url"
>
<template #error>
<div class="image-slot">
<vab-icon icon="file-damage-line" />
</div>
</template>
</el-image>
<video
v-if="!matchType(file.name || file.fileName)"
class="el-upload-list__item-thumbnail"
controls="controls"
:src="file.url"
>
您的浏览器不支持视频播放
</video>
<span class="el-upload-list__item-status-label">
<vab-icon icon="check-fill" style="color: #fff" />
</span>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="
handlePictureCardPreview(
file,
matchType(file.name || file.fileName)
)
"
>
<vab-icon icon="zoom-in-line" />
</span>
<span
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<vab-icon icon="delete-bin-line" />
</span>
</span>
</div>
</template>
<vab-icon icon="add-line" />
</el-upload>
<el-image-viewer
v-if="dialogVisible"
v-bind="$attrs"
hide-on-click-modal
:url-list="[dialogImageUrl]"
@close="dialogVisible = false"
/>
<!-- 用于编辑时显示单个视频文件的 -->
<MediaViewer
v-if="showViewer"
:hide-on-click-modal="true"
:initial-index="0"
:single-video="true"
:url-list="videoFileList"
:z-index="2018"
@close="closeViewer"
/>
</div>
</template>
<script>
// Api
import { doDelete as doDeleteFile } from '@/api/files'
// Components
import { ElImageViewer } from 'element-plus' //自定义函数组件无法使用全局组件,需要单独引入
import MediaViewer from '@/components/mediaViewer'
export default defineComponent({
name: 'Edit',
components: {
ElImageViewer,
MediaViewer,
},
props: {
fileList: {
type: Array,
default: () => [],
},
canVideo: {
type: Boolean,
default: false,
},
},
emits: [
'fetch-data',
'change-upload-loading',
'delFile',
'update:fileList',
],
setup(props, { emit }) {
const $baseMessage = inject('$baseMessage')
const $baseConfirm = inject('$baseConfirm')
const state = reactive({
// 上传的文件类型
showFileList: [],
srcList: [],
showViewer: false,
videoFileList: [],
// 预览图片
dialogVisible: false,
dialogImageUrl: '',
isShow: true,
})
const accept = computed(() => {
return props.canVideo
? '.jpg, .jpeg,.png,.mp4,.ogg,.flv,.avi,.wmv,.rmvb'
: '.jpg, .jpeg,.png'
})
const handleRemove = (uploadFile) => {
// 判断是之前的图片还是新图片
if (uploadFile.raw) {
// 新图片
// 从showFileList中筛选掉
state.showFileList = state.showFileList.filter(
(ele) => ele.uid !== uploadFile.uid
)
} else {
// 旧图片 请求接口
$baseConfirm('你确定要删除当前项吗', null, async () => {
try {
const { msg } = await doDeleteFile(uploadFile.id)
$baseMessage(msg, 'success')
emit('fetch-data')
// 从showFileList中筛选掉
state.showFileList = state.showFileList.filter(
(ele) => ele.id !== uploadFile.id
)
} catch (err) {
console.log(err)
}
})
}
}
const onFileChange = async (file) => {
if (file.status !== 'ready') return
}
const handlePictureCardPreview = (uploadFile, isImage) => {
if (isImage) {
state.dialogImageUrl = uploadFile.url
state.dialogVisible = true
return
}
state.showViewer = true
state.videoFileList = [uploadFile.url]
// state.index = 0
}
//图片视频匹配
const matchType = (name) => {
//后缀获取
let suffic = ''
//获取类型结果
let result = ''
try {
let fileArr = name.split('.')
suffic = fileArr[fileArr.length - 1]
} catch (error) {
suffic = ''
}
//图片格式
var imgList = ['png', 'jpg', 'jpeg', 'bmp', 'gif']
//进行图片匹配
result = imgList.some((item) => {
return item === suffic
})
if (result) {
result = 'image'
return result
}
}
const closeViewer = () => {
state.showViewer = false
}
const stopWatchShowFileList = watch(
() => state.showFileList,
() => {
emit('update:fileList', state.showFileList)
},
{ deep: true }
)
onMounted(() => {
state.showFileList = props.fileList.map((file) => {
file.url = file.id ? `${window.$config.imgURL}${file.id}` : file.url
return file
})
emit('change-upload-loading')
})
onBeforeUnmount(() => {
// stopWatchFileList()
stopWatchShowFileList()
})
return {
...toRefs(state),
accept,
handleRemove,
handlePictureCardPreview,
onFileChange,
closeViewer,
matchType,
}
},
})
</script>```