vue中父子组件通过props和update:实现双向绑定(el-upload)

例子:
这里的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>```

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值