Vue组件封装上传图片和视频的示例代码

Vue组件封装上传图片和视频的示例代码 

首先下载依赖:

cnpm i -S vue-uuid ali-oss

图片和视频字段都是数组类型,保证可以上传多个文件。

UploadImageVideo:

<!--UploadImageVideo 分片上传    -->
<template>
  <div class=\"UploadImageVideo\">
    <el-upload
      action
      :on-change=\"handleChange\"
      :on-remove=\"handleRemove\"
      :limit=\"limitFileNumber\"
      :on-exceed=\"handleExceed\"
      :file-list=\"_fileList\"
      :http-request=\"handleHttpRequest\"
      :before-upload=\"handleBeforeUpload\"
      :multiple=\"isMultiple\"
    >
      <el-button slot=\"trigger\" size=\"small\" type=\"primary\">选择文件</el-button>
      <div slot=\"tip\" class=\"el-upload__tip\">{{ tip }}</div>
    </el-upload>
 
    <el-dialog
      title=\"上传进度\"
      :visible.sync=\"dialogTableVisible\"
      :close-on-click-modal=\"false\"
      :modal-append-to-body=\"false\"
    >
      <el-progress :text-inside=\"true\" :stroke-width=\"26\" :percentage=\"percentage\"></el-progress>
    </el-dialog>
  </div>
</template>
 
<script>
import { uuid } from \"vue-uuid\";
const OSS = require(\"ali-oss\");
 
export default {
  name: \"\",
  components: {},
  props: {
    region: {
      type: String,
      default: \"oss-cn-chengdu\"
    },
    accessKeyId: {
      type: String,
      default: \"xxx\"
    },
    accessKeySecret: {
      type: String,
      default: \"xxx\"
    },
    //存储位置
    bucket: {
      type: String,
      required: true
    },
    currentUrls: {
      type: Array,
      default: () => [],
      required: true
    },
    //限制上传文件数量
    limitFileNumber: {
      type: Number,
      default: 1
    },
    //是否支持多选
    isMultiple: {
      type: Boolean,
      default: false
    },
    //文件格式
    fileType: {
      type: String,
      default: \"\"
    },
    //提示
    tip: {
      type: String
    }
  },
  data() {
    return {
      client: new OSS({
        region: this.region,
        accessKeyId: this.accessKeyId,
        accessKeySecret: this.accessKeySecret,
        bucket: this.bucket
      }),
      percentage: 0,
      dialogTableVisible: false,
      fileList: []
    };
  },
  computed: {
    //注意:计算属性里面慎用console.log()来打印,因为有可能打印的变量是依赖某个属性而出现该计算属性重复调用!!!!!!
    _fileList() {
      const arr = [];
      //一定要this.currentUrls判断一下是否非空,否则要报错
      if (this.currentUrls.length !== 0) {
        for (const item of this.currentUrls) {
          let { pathname } = new URL(item);
          arr.push({ name: decodeURIComponent(pathname), url: item });
        }
      }
 
      this.fileList = arr; //这行代码很重要!!
      return arr;
    }
  },
  created() {},
  mounted() {},
  methods: {
    handleChange(file, fileList) {
      this.fileList = fileList;
    },
    handleRemove(file, fileList) {
      this.fileList = fileList;
    },
    handleExceed(files, fileList) {
      this.$message.warning(
        `当前限制选择 ${this.limitFileNumber} 个文件,本次选择了 ${
          files.length
        } 个文件,共选择了 ${files.length + fileList.length} 个文件`
      );
    },
 
    //注意:为了让自定义上传handleHttpRequest生效,需满足:
    // 1、设置:auto-upload=\'true\'或者不写这个属性,因为它默认为true  2、设置action=\'#\'或者直接写action
    handleHttpRequest(file) {
      //虽然没有内容,但是这个函数不能少!
    },
    //注意:自定义上传handleHttpRequest必须要生效,才会触发before-upload钩子函数
    handleBeforeUpload(file) {
      if (this.fileType == \"image\") {
        let { type, size, name } = file;
        let isJPEG = type === \"image/jpeg\";
        let isJPG = type === \"image/jpg\";
        let isPNG = type === \"image/png\";
        let isLt5M = size / 1024 / 1024 < 5;
        if (!isJPEG && !isJPG && !isPNG) {
          this.$message.error(\"上传图片只能是 JPEG/JPG/PNG  格式!\");
          return false;
        }
        if (!isLt5M) {
          this.$message.error(\"单张图片大小不能超过 5MB!\");
          return false;
        }
      }
      if (this.fileType == \"video\") {
        let { type, size, name } = file;
        let isMP4 = type === \"video/mp4\";
        let isLt50M = size / 1024 / 1024 < 50;
        if (!isMP4) {
          this.$message.error(\"上传视频只能是 MP4  格式!\");
          return false;
        }
        if (!isLt50M) {
          this.$message.error(\"单个视频大小不能超过 50MB!\");
          return false;
        }
      }
    },
    // 分片上传数据,可展示进度条。上传重命名后的文件到alioss, 并返回单个文件url字符串。可支持中文文件名
    async UploadImageVideo(filename, file) {
      let newFileName =
        filename.split(\".\")[0] + \"-\" + uuid.v1() + \".\" + filename.split(\".\")[1];
      let that = this;
      that.dialogTableVisible = true;
 
      let {
        res: { requestUrls }
      } = await this.client.multipartUpload(newFileName, file, {
        progress: function(p, checkpoint) {
          that.percentage = parseFloat((p * 100).toFixed(2));
        }
      });
      if (that.percentage == 100) {
        that.dialogTableVisible = false;
      }
      let { origin, pathname } = new URL(requestUrls[0]);
      return origin + decodeURIComponent(pathname);
    },
    //批量上传文件。返回成功上传的url数组
    async addFiles() {
      let urls = [];
      if (this.fileList.length !== 0) {
        for (const item of this.fileList) {
          let { name, raw } = item;
          let pathname = await this.UploadImageVideo(name, raw);
          urls.push(pathname);
        }
      }
      return urls;
    },
    //更新文件数据。上传新数据到服务器,并删除服务器中的旧数据,返回更新后的url数组
    async UpdateFiles() {
      let arr_newUploaded = []; //新上传的图片url。
      let arr_original = []; //原有的图片url。不用删除
      let arr_delete = []; //需要删除的图片url。
      if (this.fileList.length !== 0) {
        for (const { raw, name, url } of this.fileList) {
          //注意:这里一定要判断raw是否存在。存在,则表示是新上传的;不存在,则表示是原有的
          if (raw) {
            let pathname = await this.UploadImageVideo(name, raw);
            arr_newUploaded.push(pathname);
          }
          if (this.currentUrls.includes(url)) {
            arr_original.push(url);
          }
        }
      }
 
      for (const element of this.currentUrls) {
        if (!arr_original.includes(element)) {
          arr_delete.push(element);
        }
      }
      await this.deleteMultiFiles(arr_delete);
 
      return [...arr_original, ...arr_newUploaded];
    },
    //批量删除服务器中的文件。参数:待删除到服务器文件url数组。
    async deleteMultiFiles(urls = []) {
      let arr_pathname = [];
      if (urls.length !== 0) {
        for (const item of urls) {
          //不要用let url=require(\"url\");url.parse();已失效。要用new URL()
          let { pathname } = new URL(item);
          // decodeURIComponent()函数将中文乱码转为中文
          arr_pathname.push(decodeURIComponent(pathname));
        }
        //删除服务器中的图片
        await this.client.deleteMulti(arr_pathname);
      }
    }
  },
  watch: {}
};
</script>
 
<style lang=\"scss\" scoped>
.UploadImageVideo {
  /*去除upload组件过渡效果*/
  ::v-deep .el-upload-list__item {
    transition: none !important;
  }
}
</style>

使用:

<UploadImageVideo
  ref=\"ref_UploadImageVideo\"
  bucket=\"xxx\"
  :currentUrls=\"formData.imgurl\"
  :limitFileNumber=\"3\"
  tip=\"1、最多上传3张照片; 2、上传图片只能是 JPEG/JPG/PNG 格式; 3、单张图片大小不能超过 5MB!\"
  fileType=\"image\"
  :isMultiple=\"true\"
></UploadImageVideo>

fileType可选。默认不写,表示图片、视频都可上传。fileType=\”image\”表示只能上传图片。fileType=\”video\”表示只能上传视频
bucket必选。
isMultiple可选。默认为false
currentUrls必选。当前目前已有的文件服务器url数组。通常新增文件时,传入的currentUrls为空数组[];更新文件时,传入到currentUrls为非空数组
tip可选。提示内容

提供的方法:(当前组件中所有的上传都是批量上传,且为分片上传,以展示上传进度条)

    UpdateFiles()。更新文件数据。上传新数据到服务器,并删除服务器中的旧数据,返回更新后的url数组
    addFiles()。批量上传文件。返回成功上传的url数组
    deleteMultiFiles(urls = [])。批量删除服务器中的文件。参数:待删除到服务器文件url数组。
    UploadImageVideo(filename, file)。分片上传数据,可展示进度条。上传重命名后的文件到alioss, 并返回单个文件url字符串。可支持中文文件名

调用组件中的方法:例如可通过 let urls = await this.$refs[\”ref_UploadImageVideo\”].addFiles();调用批量上传图片或视频的方法

例1:

Vue组件封装上传图片和视频的示例代码Vue组件封装上传图片和视频的示例代码 Vue组件封装上传图片和视频的示例代码 

<!--userManage-->
<template>
  <div class=\"userManage\">
    <el-card>
      <div style=\"margin-bottom: 10px\">
        <el-input
          v-model=\"searchName\"
          clearable
          placeholder=\"输入用户名称搜索\"
          style=\"width: 200px; margin-right: 10px\"
        />
        <el-button
          sizi=\"mini\"
          type=\"success\"
          icon=\"el-icon-search\"
          @click=\"searchUser(searchName)\"
        >搜索</el-button>
        <el-button
          sizi=\"mini\"
          type=\"warning\"
          icon=\"el-icon-refresh-left\"
          @click=\"searchName = \'\'\"
        >重置</el-button>
        <el-button sizi=\"mini\" @click=\"handleAdd()\" type=\"primary\" icon=\"el-icon-plus\">新增</el-button>
        <el-button @click=\"getUserList()\" sizi=\"mini\" icon=\"el-icon-refresh\" style=\"float: right\">刷新</el-button>
      </div>
      <el-table :data=\"tableData\" border v-loading=\"isLoading\">
        <el-table-column label=\"用户名\" prop=\"username\" align=\"center\" width=\"150px\"></el-table-column>
        <el-table-column label=\"密码\" prop=\"password\" align=\"center\"></el-table-column>
        <el-table-column label=\"图片\" align=\"center\">
          <template slot-scope=\"scope\">
            <div
              style=\"
                display: flex;
                justify-content: space-around;
                flex-flow: row wrap;
              \"
            >
              <el-image
                style=\"width: 50px; height: 50px\"
                v-for=\"(item, index) in scope.row.imgurl\"
                :key=\"index\"
                :src=\"item\"
                :preview-src-list=\"scope.row.imgurl\"
              ></el-image>
              <!-- <a :href=\"scope.row.imgurl\" rel=\"external nofollow\"  target=\"_blank\">{{scope.row.imgurl}}</a> -->
            </div>
          </template>
        </el-table-column>
        <el-table-column label=\"操作\" align=\"center\">
          <template slot-scope=\"scope\">
            <el-button size=\"mini\" @click=\"showEditDialog(scope.row)\">
              <i class=\"el-icon-edit\" /> 编辑
            </el-button>
            <el-button size=\"mini\" type=\"danger\" @click=\"handleDelete(scope.row)\">
              <i class=\"el-icon-delete\" /> 删除
            </el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
    <UserManageDialog :dialog=\"dialog\" :formData=\"formData\" @addUser=\"addUser\" @editUser=\"editUser\"></UserManageDialog>
  </div>
</template>
 
<script>
import UserManageDialog from \"./userManageDialog.vue\";
import { client_alioss, deleteMultiFiles } from \"@/utils/alioss.js\";
 
import {
  addUser,
  getUserList,
  editUser,
  deleteUser,
  searchUser
} from \"@/api/userManage/index\";
export default {
  name: \"userManage\",
  components: { UserManageDialog },
  data() {
    return {
      searchName: \"\",
      isLoading: false,
      dialog: {
        show: false,
        title: \"\"
      },
      formData: {},
      tableData: [
        {
          _id: \"\",
          username: \"admin\",
          password: \"123\",
          imgurl: []
        }
      ],
      currentImgs: []
    };
  },
  props: {},
  created() {},
  mounted() {
    this.getUserList();
  },
  computed: {},
  methods: {
    //获取用户列表
    async getUserList() {
      this.isLoading = true;
      let { data } = await getUserList();
      this.tableData = data.data;
      this.isLoading = false;
    },
 
    //打开新增用户窗口
    handleAdd() {
      this.dialog = {
        show: true,
        title: \"新增用户\",
        option: \"add\"
      };
      this.formData = {
        username: \"\",
        password: \"\",
        imgurl: []
      };
    },
    //打开编辑用户窗口
    showEditDialog(row) {
      this.currentImgs = row.imgurl;
 
      this.dialog = {
        show: true,
        title: \"编辑用户\",
        option: \"edit\"
      };
      this.formData = {
        _id: row._id,
        username: row.username,
        password: row.password,
        imgurl: row.imgurl
      };
    },
    //新增用户
    async addUser(urls) {
      this.formData.imgurl = urls;
 
      await addUser(this.formData);
      this.dialog.show = false;
      this.$notify({
        title: \"成功\",
        message: \"新增用户成功!\",
        type: \"success\"
      });
      this.getUserList();
    },
    //编辑用户
    async editUser(urls) {
      this.formData.imgurl = urls;
 
      await editUser(this.formData, this.formData._id); //更新数据库,尤其是图片url
 
      this.dialog.show = false;
      this.$notify({
        title: \"成功\",
        message: \"编辑用户成功!\",
        type: \"success\"
      });
      this.getUserList();
    },
    //删除用户
    handleDelete({ _id }) {
      this.$confirm(\"此操作将永久删除该文件, 是否继续?\", \"提示\", {
        confirmButtonText: \"确定\",
        cancelButtonText: \"取消\",
        type: \"warning\"
      })
        .then(async () => {
          this.$message({
            type: \"success\",
            message: \"删除成功!\",
            showClose: true
          });
          let {
            data: { imgurl }
          } = await deleteUser(_id);
 
          //删除服务器中的文件。传入待删除的url数组
          await deleteMultiFiles(imgurl);
 
          this.getUserList();
        })
        .catch(() => {
          this.$message({
            type: \"info\",
            message: \"已取消删除\",
            showClose: true
          });
        });
    },
    //根据用户名查询
    async searchUser(searchName) {
      this.isLoading = true;
      let { data } = await searchUser({
        searchName
      });
      this.tableData = data.data;
      this.isLoading = false;
    }
  },
  watch: {}
};
</script>
 
<style lang=\"scss\" scoped>
.userManage {
}
</style>

 Vue组件封装上传图片和视频的示例代码

<!--userManageDialog   -->
<template>
  <div class=\"userManageDialog\">
    <el-dialog :title=\"dialog.title\" width=\"45%\" :visible.sync=\"dialog.show\" v-if=\"dialog.show\">
      <el-form ref=\"ref_form_userManage\" :model=\"formData\" :rules=\"rules\" label-width=\"100px\">
        <el-form-item label=\"用户名\" prop=\"username\">
          <el-input v-model=\"formData.username\" autocomplete=\"off\" style=\"width: 90%\"></el-input>
        </el-form-item>
        <el-form-item label=\"密码\" prop=\"password\">
          <el-input v-model=\"formData.password\" autocomplete=\"off\" style=\"width: 90%\"></el-input>
        </el-form-item>
        <el-form-item label=\"图片\" prop=\"imgurl\">
          <!-- fileType属性不写的话,表示图片、视频都可上传。fileType=\"image\"表示只能上传图片。fileType=\"video\"表示只能上传视频 -->
          <UploadImageVideo
            ref=\"ref_UploadImageVideo\"
            bucket=\"bucket-lijiang-test\"
            :currentUrls=\"formData.imgurl\"
            :limitFileNumber=\"3\"
            tip=\"1、最多上传3张照片; 2、上传图片只能是 JPEG/JPG/PNG 格式; 3、单张图片大小不能超过 5MB!\"
            fileType=\"image\"
            :isMultiple=\"true\"
          ></UploadImageVideo>
        </el-form-item>
      </el-form>
      <div slot=\"footer\" class=\"dialog-footer\">
        <el-button @click=\"dialog.show = false\">取 消</el-button>
        <el-button
          v-if=\"dialog.option == \'add\'\"
          @click=\"addUser(\'ref_form_userManage\')\"
          type=\"primary\"
        >确 定</el-button>
        <el-button
          v-if=\"dialog.option == \'edit\'\"
          @click=\"editUser(\'ref_form_userManage\')\"
          type=\"primary\"
        >确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>
 
<script>
import UploadImageVideo from \"@/components/UploadImageVideo\";
 
export default {
  name: \"userManageDialog\",
  components: { UploadImageVideo },
  props: [\"dialog\", \"formData\"],
  data() {
    return {
      fileList: [],
      rules: {
        username: [
          { required: true, message: \"请输入用户名称\", trigger: \"blur\" }
        ]
      }
    };
  },
  created() {},
  mounted() {},
  computed: {},
  methods: {
    addUser(formName) {
      this.$refs[formName].validate(async valid => {
        if (valid) {
          let urls = await this.$refs[\"ref_UploadImageVideo\"].addFiles();
          this.$emit(\"addUser\", urls);
        } else {
          console.log(\"error submit!!\");
          return false;
        }
      });
    },
    editUser(formName) {
      this.$refs[formName].validate(async valid => {
        if (valid) {
          let urls = await this.$refs[\"ref_UploadImageVideo\"].UpdateFiles();
 
          this.$emit(\"editUser\", urls);
        } else {
          console.log(\"error submit!!\");
          return false;
        }
      });
    }
  },
  watch: {}
};
</script>
<style lang=\"scss\" scoped>
</style>

 Vue组件封装上传图片和视频的示例代码

import { uuid } from \'vue-uuid\';
const OSS = require(\"ali-oss\");
 
let client = new OSS({
    region: \"oss-cn-chengdu\",
    accessKeyId: \"LTAI5tQPHvixV8aakp1vg8Jr\",
    accessKeySecret: \"xYyToToPe8UFQMdt4hpTUS4PNxzl9S\",
    bucket: \"bucket-lijiang-test\",
 
});
 
export const client_alioss = client;
 
 
//删除文件数组
export async function deleteMultiFiles(urls = []) {
    let arr_pathname = [];
    if (urls.length !== 0) {
        for (const item of urls) {
            //不要用let url=require(\"url\");url.parse();已失效。要用new URL()
            let { pathname } = new URL(item);
            // decodeURIComponent()函数将中文乱码转为中文
            arr_pathname.push(decodeURIComponent(pathname));
        }
        await client.deleteMulti(arr_pathname);
    }
}

 Vue组件封装上传图片和视频的示例代码

import request from \'@/utils/request\'
//  获取用户列表
export function getUserList() {
    return request({
        url: \'/api/userManage\',
        method: \'get\'
    })
}
 
//  新增用户
export function addUser(data) {
    return request({
        url: \'/api/userManage\',
        method: \'post\',
        data
    })
}
 
//  编辑用户
export function editUser(data, _id) {
    return request({
        url: `/api/userManage/${_id}`,
        method: \'put\',
        data
    })
}
 
//  删除用户
export function deleteUser(_id) {
    return request({
        url: `/api/userManage/${_id}`,
        method: \'delete\'
    })
}
 
//  根据关键字查询
export function searchUser(data) {
    return request({
        url: `/api/userManage/search`,
        method: \'get\',
        params: data
    })
}

Vue组件封装上传图片和视频的示例代码  

const router = require(\'koa-router\')()
 
const User = require(\"../models/User\"); //引入模块模型
router.prefix(\'/userManage\')
 
//获取用户列表
router.get(\'/\', async (ctx, next) => {
    let data = await User.find({})
    ctx.body = {
        code: 200,
        message: \"请求成功\",
        data,
    }
})
//新增用户
router.post(\'/\', async (ctx, next) => {
    let { username, password, imgurl } = ctx.request.body;
    await User.create({ username, password, imgurl })
    ctx.body = { code: 200, message: \"新增成功\" }
})
//编辑用户
router.put(\'/:_id\', async (ctx, next) => {
    let { username, password, imgurl } = ctx.request.body;
    let { _id } = ctx.params
 
    await User.findByIdAndUpdate(_id, { username, password, imgurl })
    ctx.body = { code: 200, message: \"编辑成功\" }
})
//删除用户
router.delete(\'/:_id\', async (ctx, next) => {
    let { _id } = ctx.params;
    let { imgurl } = await User.findByIdAndDelete(_id)
    ctx.body = { code: 200, message: \"删除成功\", imgurl }
 
})
 
//根据关键字查询用户。模糊查询
 
router.get(\'/search\', async (ctx, next) => {
    let { searchName } = ctx.request.query;
 
    let data = await User.find({ username: { $regex: searchName } })
    ctx.body = { code: 200, message: \"查询成功\", data }
})
module.exports = router
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容