腾讯云对象储存功能的使用详解, 巨翔!!!

349 阅读6分钟

图片存储方案介绍

目标

了解主流的图片存储方案

两种常见方案

方案一:存到自己公司购买的服务器上

优点:好控制

缺点:成本高由于图片都存放到自己的服务器上,占据空间很大

方案二:存到三方云服务器(阿里云,七牛云,腾讯云)

各种云有专门的为图片存储提供的云服务器,我们自己的服务器只存储图片地址即可

image-20210521225849514.png

腾讯云cos申请配置

目标

使用现成的腾讯云服务创建一个免费的云存储。

官网:cloud.tencent.com/

创建账号并实名认证

在腾讯云中创建帐号并实名认证

image-20210424202734409.png

开通对象存储

image-20210424200430967.png

02.png

(实名认证,视频校验,居住地址,......)

创建存储桶

03.png

04.png

设置cors规则

在存储桶列表中,选中存储桶

image-20210402111641088.png

在左侧的菜单中选安全管理

因为我们是在测试上传,全部容许上传即可,真正的生产环境需要单独配置具体的域名和操作方法

05.png

配置云API秘钥

服务器属于个人的,需要一定的权限才能自由上传图片,这个负责权限验证的其实就是秘钥。拥有秘钥是进行上传的基础条件。

image-20211024162352571.png

秘钥配置

06.png API密钥管理

image-20211024162454910.png 安全性提示

实际工作中,秘钥属于敏感信息,不能直接放到前端存储,容易产生安全问题,更好的做法是把秘钥交给后端管理,前端通过调用接口先获取秘钥,有了秘钥之后再进行上传操作

以上我们就完成了,所有的准备工作~

图片上传组件-封装组件-基本思路

目标

封装一个组件,用来把图片上传到cos中。

思路

组件有两个功能:

  1. 展示图片(初始显示图片)
  2. 修改图片

image-20210701150341246.png

图片上传组件-封装组件-upload二次封装

目标

基于elementUI的upload组件封装一个通用的上传组件供业务组件使用

需求理解

前端主动发起图片上传使用的是三方的腾讯云上传接口,前端得到一个已经上传完毕的图片地址,然后把这个地址当成一个接口字段 传给我们自己的后端服务

详情页

12.png

新建公共上传组件

我们的上传功能是基于element上传组件的二次开发,先准备好我们需要的elementUI上传组件,根据我们具体的业务需求选取一个合适的样例代码

src/components/UploadImg

<template>
  <div>
    <el-upload
      class="avatar-uploader"
      action="#"
      :show-file-list="false"
      :on-success="handleAvatarSuccess"
      :before-upload="beforeAvatarUpload"
      :http-request="upload"
    >
      <img v-if="imageUrl" :src="imageUrl" class="avatar">
      <i v-else class="el-icon-plus avatar-uploader-icon" />
    </el-upload>
  </div>
</template>

<script>
export default {
  data() {
    return {
      imageUrl: ''
    }
  },
  methods: {
    upload(file) {
      console.log(file)
    },
    handleAvatarSuccess(res, file) {
      this.imageUrl = URL.createObjectURL(file.raw)
    },
    beforeAvatarUpload(file) {
      const isPNG = file.type === 'image/png'
      const isLt2M = file.size / 1024 / 1024 < 2
      if (!isPNG) {
        this.$message.error('上传头像图片只能是 PNG 格式!')
      }
      if (!isLt2M) {
        this.$message.error('上传头像图片大小不能超过 2MB!')
      }
      return isPNG && isLt2M
    }
  }
}
</script>

<style>
.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  line-height: 178px;
  text-align: center;
}
.avatar {
  width: 178px;
  height: 178px;
  display: block;
}
</style>

预览,在首页模块进行组件预览显示

自定义上传配置

关键属性::http-request="upload" action="#"

使用自定义行为覆盖默认上传,注意一旦设置自定义上传行为之后,所有的上传操作都需要自己实现,比如数据处理,上传成功之后的后续操作,on-success钩子函数也不会继续触发

<template>
  <div>
    <!--
      show-file-list: 是否显示上传的文件列表

      action: '#' 用来指定文件要上传的地址,由于我们需要定制上传动作
             这里设为#
      :http-request:自定义上传行为(重点)

      on-success: 上传成功之后的回调
      before-upload: 上传之前的检查
    -->
    <el-upload
      class="avatar-uploader"
      action="#"
      :show-file-list="false"
      :before-upload="beforeAvatarUpload"
      :http-request="upload"
    >
      <img v-if="imageUrl" :src="imageUrl" class="avatar">
      <i v-else class="el-icon-plus avatar-uploader-icon" />
    </el-upload>
  </div>
</template>
<script>
  export default {
      methods:{
         upload(params){
             console.log(params)
         }
      }
  }
</script>

全局注册

src/components/index.js

// 全局注册组件
// 省略其他....
+ import UploadImg from '@/components/UploadImg'

// 1.定义插件(拓展Vue的功能)
const MyPlugin = {
  install(Vue) {
    // 省略其他....
 +   Vue.component(UploadImg.name, UploadImg)

  }
}
export default MyPlugin

测试使用

主页中测试(其他页面也可以)

图片上传组件-封装组件-上传图片到腾讯云

前置基础:

1.在云服务器上的准备:申请cos服务器,配置密钥,设置cors访问

2.在代码层面的准备:

​ (1) 下载一个官方提供的操作cos服务的包(cos-js-sdk-v5)

​ (2) 用自己的密钥去实例化cos

​ (3) 具体做上传

目标

用前边注册的对象存储功能,将图片上传到腾讯云,根据cos的上传API实现上传功能

腾讯云文档地址

安装依赖

在项目中安装依赖

npm i cos-js-sdk-v5 --save

实例化cos对象

src/components/UploadImg

// 下面的代码是固定写法
const COS = require('cos-js-sdk-v5')
// 填写自己腾讯云cos中的key和id (密钥)
const cos = new COS({
  SecretId: 'xxx', // 身份识别ID
  SecretKey: 'xxx' // 身份秘钥
})

上边用到的SecretId和SecretKey在这里找到:

image-20210424204204400.png

使用cos对象完成上传

主要是用cos.putObjectapi来完成上传功能,代码如下:

upload(res) {
  if (res.file) {
    // 执行上传操作
    cos.putObject({
      Bucket: 'xxxxxx', /* 存储桶 */
      Region: 'xxxx', /* 存储桶所在地域,必须字段 */
      Key: res.file.name, /* 文件名 */
      StorageClass: 'STANDARD', // 上传模式, 标准模式
      Body: res.file // 上传文件对象
    }, (err, data) => {
      console.log(err || data)
      // 上传成功之后
      if (data.statusCode === 200) {
        this.imageUrl = `https:${data.Location}`
      }
    })
  }
}

上边的Bucket和Region在这里可以找到

image-20210424204852144.png

图片上传组件-封装组件-补充上传进度条

目标

给出用户更好的上传体验,显示当前上传进度

思路

  1. 在上传时,cos支持配置onProgress回调,在这个回调函数中可以拿到当前上传的进度。
cos.putObject({
      // 省略其他...
      onProgress: (progressData) => {
        console.log(JSON.stringify(progressData))
      }
    }
  1. 进度条: 现成的组件:el-progress

添加布局

补充进度条组件:el-progress

<el-upload
  class="avatar-uploader"
  action="#"
  :show-file-list="false"
  :before-upload="beforeAvatarUpload"
  :http-request="upload"
>
  <img v-if="imageUrl" :src="imageUrl" class="avatar">
  <i v-else class="el-icon-plus avatar-uploader-icon" />
+ <el-progress type="circle" :percentage="25" class="progress" />
</el-upload>

<style>
.progress {
  position: absolute;
  display: flex;
  top: 50%;
  left: 50%;
  transform: translate(-50%,-50%);
  background: #fff;
}
</style>

实现功能

补充数据项:

data () {
  return {
    // ...
    percent: 0, // 上传进度
    showProgress: false // 是否展示进度条
  }
}

核心逻辑:在onProgress钩子函数里动态修改负责显示进度的percent属性即可

更新数据项值

upload(params) {
  if (params.file) {
    // 显示进度条
+    this.showProgress = true
    // 执行上传操作
    cos.putObject({
      Bucket: 'chaichai-1305124340', /* 存储桶 */
      Region: 'ap-beijing', /* 存储桶所在地域,必须字段 */
      Key: params.file.name, /* 文件名 */
      StorageClass: 'STANDARD', // 上传模式, 标准模式
      Body: params.file, // 上传文件对象
      onProgress: (progressData) => {
        console.log(JSON.stringify(progressData))
+        this.percent = progressData.percent * 100
      }
    }, (err, data) => {
        // 隐藏进度条
+       this.showProgress = false
        console.log(err || data)
        if (data.statusCode === 200) {
           this.imageUrl = `https:${data.Location}`
        }
    })
  }
}

视图

<el-progress v-if="showProgress" :percentage="percent" />

用户详情页中使用上传组件-v-model

目标

我们希望达成的目标是:在upload-img上可以使用v-model做双向绑定。如下:

<el-form-item label="员工头像">
  <!-- <img :src="userInfo.staffPhoto"> -->
  <!-- 放置上传图片 -->
  <upload-img v-model="imageUrl" />
</el-form-item>

upload-img: 自定义的组件, v-model:双向绑定。

复习v-model

v-model是一个语法糖。

<com v-model="imageUrl" />

上面的写法等价于:

<com :value="imageUrl" @input="val=>imageUrl=val" />
1. 给子组件内部传一个名为value的属性,属性值就是绑定的数据项
2. 在子组件监听一个名为input的事件,回调函数是:将收到的参数值保存到数据项中

image-20210427085159254.png

代码

父组件

v-model绑定值

<upload-img v-model="userInfo.staffPhoto" />

子组件(图片上传组件)

  1. 定义props value来接收父组件传入的图片地址
  2. 直接用value来显示图片(把原来 imageUrl删除了)
  3. 在上传成功之后,this.$emit('input', 新地址), 抛给父组件,达到更新父组件中v-model绑定数据项
<template>
  <!--
      show-file-list: 是否显示上传的文件列表

      action: '#' 用来指定文件要上传的地址,由于我们需要定制上传动作
      (我们要上传到腾讯云cos)
             这里设为#
      :http-request:自定义上传行为(重点)

      on-success: 上传成功之后的回调
      before-upload: 上传之前的检查
      :on-success="handleAvatarSuccess"
      :on-success="handleAvatarSuccess"
      :before-upload="beforeAvatarUpload"
    -->
  <el-upload
    class="avatar-uploader"
    action="#"
    :http-request="upload"

    :show-file-list="false"
  >
+    <img v-if="value" :src="value" class="avatar">
    <i v-else class="el-icon-plus avatar-uploader-icon" />
    <el-progress
      v-if="isShow"
      :percentage="percentage"
      class="progress"
    />
  </el-upload>

</template>


<script>
// 下面的代码是固定写法
const COS = require('cos-js-sdk-v5')
// 填写自己腾讯云cos中的key和id (密钥)
const cos = new COS({
  SecretId: 'AKIDEI7fxzkFTXLtBD**********', // 身份识别ID  这俩填你们自己的
  SecretKey: '91cx0nJabLo1yf5D5**************' // 身份秘钥
})
export default {
  name: 'UploadImg',
+  props: {
    // 从父组件传递过来的v-model对应的值
    value: { type: String, default: '' }
  },
  data() {
    return {
      // imageUrl: '',
      percentage: 0, // 上传进度
      isShow: false // 进度条是否可见
    }
  },
  methods: {
    upload(res) {
      console.log('当前要上传的文件是', res.file)
      if (res.file) {
        // 执行上传操作
        this.isShow = true // 进度条可见
        cos.putObject({
          Bucket: 'tj03-1258898967', /* 存储桶 */
          Region: 'ap-nanjing', /* 存储桶所在地域,必须字段 */
          Key: res.file.name, /* 文件名 */
          StorageClass: 'STANDARD', // 上传模式, 标准模式
          Body: res.file, // 上传文件对象
          onProgress: (progressData) => {
            console.log('上传文件进度.....', JSON.stringify(progressData))
            this.percentage = progressData.percent * 100
          }
        }, (err, data) => {
          this.isShow = false // 进度条不可见
          console.log(err || data)
          // 上传成功之后
          if (data.statusCode === 200) {
            const urlImg = `https://${data.Location}`
+           this.$emit('input', urlImg)
          }
        })
      }
    }
}
</script>

小结

图片上传组件整个工作过程

image-20210703120810411.png

全天小结

  1. excel 导出
    1. 用xlsx库,把excel文件的内容读出来到浏览器的内存中。
    2. 数据格式化(后端要求的数据格式与直接读入的内容格式不同)
    3. 调用后端接口
  2. 员工详情页
  3. 把图片上传到腾讯云COS (云cloudy 对象 Object S 存储store )
    1. 账号申请,认证
    2. 购买COS服务
    3. 建立存储桶,设置CORS,生成API秘钥,用它提供的API做文件上传
  4. 图片上传组件封装
    1. element-ui: el-upload组件, el-progress组件
    2. v-model

image-20210703084039580.png

在员工列表中显示头像

目标

在表格中显示员工头像

思路

通过自定义列,将图片显示在表格中

操作

在employee.vue中的table上补充一列

<el-table-column label="头像">
  <template slot-scope="scope">
      <img :src="scope.row.staffPhoto" />
  </template>
</el-table-column>

此时可能部分图片无法正常显示(原因是图片本身地址有误,或者就是没有设置图片)

封装全局图片组件

目标

封装全局图片组件,实现两个效果:

  1. 没有src属性时,有一个默认图片
  2. 统一样式

基本思路

用户如何使用?

image-20210522122117511.png

可以在el-image的基础之上,做进一步开发。

创建组件

在src/components目录下创建组件。

具体目录结构如下

|-components
					|-ImageHolder
												|-index.vue  # 组件本身
												|-head.jpg   # 默认头像,当没有图像需要显示时,使用这张图

代码

src\components\ImageHolder\index.vue

<template>
<!-- el-image组件 :https://element.eleme.io/#/zh-CN/component/image -->
  <el-image :src="src" class="img-container">
   <!-- error插槽:设置如果出错,要显示的内容 -->
    <template #error>
      <!-- 静态资源就近维护:把head.jpg这张图放在这个组件的目录下 -->
      <img src="./head.jpg" alt="">
    </template>
  </el-image>
</template>

<script>
export default {
  // 定义如何从父组件中接收数据
  props: {
    src: {
      type: String,
      default: ''
    }
  }
}
</script>


<style scoped lang="scss">
// 样式穿透, 有三种写法:
// 1. >>>       在less中使用
// 2. /deep/    在less中使用
// 3. ::v-deep  在scss中使用
.img-container {
  border-radius: 50%;
  ::v-deep img{
    width: 100px;
    height: 100px;
  }
}
</style>

全局注册

src/components/index.js中注册全局组件

// 定义全局组件PageTools
// 省略其它...
+ import ImageHolder from '@/components/ImageHolder/index.vue'
const MyPlugin = {
  install: function(Vue) {
    // 省略其它...
+   Vue.component('ImageHolder', ImageHolder)
  }
}

export default MyPlugin

在业务组件中使用

src\views\employees\employees.vue中,用上面定义的组件来显示员工图像

<el-table-column label="头像">
  <template slot-scope="scope">
		<image-holder :src="scope.row.staffPhoto" />
  </template>
</el-table-column>

src就是传递给子组件的prop。