本地数据库IndexedDB - 学员管理系统之上传头像(三)

         IndexedDB是浏览器提供的本地数据库,它可以被网页脚本创建和操作。IndexedDB允许存储大量数据,提供查找接口,还能建立索引。这些都是LocalStorage或Cookie不具备的。就数据库类型而言,IndexedDB不属于关系型数据库(不支持SQL查询语句),更接近NoSQL数据库。

        在前面两篇中,讲解了系统登录和列表的增删改查功能;有些人可能还希望上传头像,这里我们可以将获取的图片转成base64图像或Blob二进制进行保存,因IndexedDB中不仅可以保存文本或Object对象数据,也可以存储二进制数据,所以这为我们实现上传功能,技术上提供可行性支持。

实现后的效果图如下:

         我们在学员列表中实现下头像上传功能,会做两处修改:一是列表页添加头像展示,二是在新增或编辑弹框中添加上传头像功能。这里没作弹框上传要求,如果没有上传头像,列表中则显示暂无头像。

        这里之前讲过的内容,就不再详细叙述了,只将需要调整位置挑选出来,进行讲解。如果未看过之前章节,对整个系统还不了解的朋友,可以翻看前几篇,地址如下:

本地数据库IndexedDB - 学员管理系统之登录(一)_觉醒法师的博客-CSDN博客

本地数据库IndexedDB - 学员管理系统之列表管理(二)_觉醒法师的博客-CSDN博客

一、base64图像存储

        首先我们先将上传图片转换成base64图像来实现上传功能,不管是Base64还是Blob二进制方式,其实实行方式都比较简单。

1.1 列表添加头像展示

这里我们在列表中,添加avatar头像显示列,并判断用户头像是否存在,不存在显示”暂无头像“字样。打开pages/student/index.vue,添加html代码如下:

<div class="table-wrap">
    <el-table
      @selection-change="selectionChange"
      :data="tableList"
      style="width: 100%">
      <el-table-column type="selection" label="选择" width="50"> </el-table-column>
      <el-table-column prop="avatar" label="头像" width="80">
        <template slot-scope="scope">
          <img :src="scope.row.avatar" alt="" class="avatar" v-if="scope.row.avatar" />
          <span v-else class="avatar-empty">暂无头像</span>
        </template>
      </el-table-column>
      
      ...

    </el-table>

    <div class="right-box">
      <el-pagination
        background
        layout="prev, pager, next"
        @current-change="currentChange"
        :current-page="page"
        :page-size="pageSize"
        :total="pageTotal">
      </el-pagination>
    </div>
  </div>

打开pages/student/index.scss样式文件,添加样式代码如下:

.right-box{
  text-align: right;
  padding-top: 15px;
}

.avatar{
  width: 50px;
  height: 50px;
  border-radius: 50px;
  object-fit: cover;
  overflow: hidden;
}

.avatar-empty{
  display: block;
  width: 50px;
  height: 50px;
  overflow: hidden;
  border-radius: 50px;
  font-size: 12px;
  color: #ccc;
  text-align: center;
  padding: 10px;
  box-sizing: border-box;
  line-height: 14px;
  border: 1px solid #ccc;
}

列表页面的js部分代码无修改,所以这边不需要做任何操作。

1.2 新增或编辑弹框

       事先在工具类src/utils/utils/js中添加fileToBase64()函数,代码如下:

/**
 * file 转 base64
 */
export const fileToBase64 = file => {
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader();
    fileReader.onload = (e) => {
      resolve(e.target.result);
    };

    fileReader.readAsDataURL(file);
    fileReader.onerror = () => {
      reject(new Error('fileToBase64 error'));
    };
  });
}

1.3 添加头像上传功能

打开components/studentDialog/index.vue,增加element的el-upload组件,由于这里不是上传到服务器,而是本地存储,所以action这块置空即可。html代码如下:

<template>
  <el-dialog :title="uid!=0?'编辑':'新增'" :visible="visible" @close="closeEvent" width="420px" class="dialog-wrap">

    <el-form :model="form" :rules="rules"  status-icon ref="ruleForm">
      <el-form-item label="头像" :label-width="formLabelWidth">
        <el-upload
          action=""
          class="avatar-uploader"
          :show-file-list="false"
          :before-upload="beforeAvatarUpload">
          <img v-if="imageUrl" :src="imageUrl" class="avatar">
          <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
      </el-form-item>
      
      ...

    </el-form>

    <div slot="footer" class="dialog-footer">
      <el-button size="small" @click="closeEvent">取 消</el-button>
      <el-button size="small" type="primary" @click="submitForm">保 存</el-button>
    </div>

  </el-dialog>
</template>

将utils工具包里引入fileToBase64()函数;data中定义imageUrl变量;methods中定义beforeAvatarUpload()函数用来接收上传参数,并转换为base64图像赋值给imageUrl变量;在methods中的getParams()增加avatar字段,在保存时将imageUrl值赋上即可;如果为编辑状态时,在updateStudentInfo()执行时,获取详情数据须判断avatar字段是否有值,如果存在需要重新赋值给imageUrl。 js代码如下:

<script>
  import { toggleStudentInfo, loadStudentById, gradeAllList, getClassByKey } from '@/api'
  import { formatDate, fileToBase64 } from '@/utils/utils'
  export default {
    props: {
      //学员ID
      uid: {
        type: Number,
        default: () => 0
      },
      visible: {
        type: Boolean,
        default: () => false
      }
    },
    data(){
      return {
        //用户头像
        imageUrl: '',
        formLabelWidth: '80px',
  
        //...
      }
    },
    watch: {
      uid(){
        if(this.uid!=0){
          this.updateStudentInfo();
        }
      }
    },
    created() {
      this.updateGradeInfo();
    },
    methods: {
      /**
       * 上传用户头像
       * @param {Object} file
       */
      beforeAvatarUpload(file) {
        const isJPG = file.type === 'image/jpeg' || file.type === 'image/png';
        const isLt2M = file.size / 1024 / 1024 < 2;

        if (!isJPG) {
          this.$message.error('上传头像图片只能是 JPG 或 PNG 格式!');
        }
        if (!isLt2M) {
          this.$message.error('上传头像图片大小不能超过 2MB!');
        }
        fileToBase64(file).then(res => {
          this.imageUrl = res;
        })
        return isJPG && isLt2M;
      },
      
      //...

      /**
       * 获取班级
       */
      updateStudentInfo(){
        loadStudentById(this.uid).then(res => {
          if(res.code==1){
            let data = res.data,
                tmpData = {
                  name: res.data['name'],
                  registration: res.data['registration'],
                  phone: res.data['phone'],
                  address: res.data['address'],
                  birthday: res.data['birthday']
                };

            if(data['gid']){
              tmpData['gid'] = data.gid;
            }
            if(data['cid']){
              tmpData['cid'] = data.cid;
            }
            this.form = tmpData;

            if(data['avatar']){
              this.imageUrl = data.avatar;
            }

            if(data['gid']){
              this.updateClassInfo();
            }
          }
        }).catch(e => {
          console.error(e);
        })
      },
      /**
       * 获取保存数据
       */
      getParams(){
        let { name, registration,  phone, address, birthday, gid, cid } = this.form;
        return {
          name, registration, phone, address, birthday, gid, cid,
          avatar: this.imageUrl
        }
      },
      
      //...
    }
  }
</script>

此时通过新增或修改进行头像编辑后,列表上就可以展现对应头像了,如下图:

二、Blob二进制存储

        通过二进制存储上传图片,只需在base64基本上进行几处修改即可,大家也可根据实际需求对比,哪种方式适合自己业务需要即可。

2.1 定义存储file文件变量

        首先需要在data中添加uploadFile变量,用于存储Blob二进制文件流,代码如下:

 export default {

    //...

    data(){
      return {
        //用户头像
        imageUrl: '',
        //存储二进制流Blob
        uploadFile: "",
    
        //...

      }
    }
  }

2.2 beforeAvatarUpload()函数修改

        接下来,我们需要对上传功能函数beforeAvatarUpload()内部进行调用,代码如下:

fileToBase64(file).then(res => {
    this.imageUrl = res;
})

// 将上部分代码,替换为下面内容即可

this.uploadFile = new Blob([file]);
this.imageUrl = URL.createObjectURL(this.uploadFile);

2.3 getParams()函数修改

        将之前赋值的imageUrl修改为uploadFile即可,代码如下:

getParams(){
    let { name, registration,  phone, address, birthday, gid, cid } = this.form;
    return {
        name, registration, phone, address, birthday, gid, cid,
        avatar: this.uploadFile
    }
},

2.4 updateStudentInfo()函数修改

        由于Blob二进制无法直接显示,所以在编辑时候需要将获取的avatar通过URL.createObjectURL(Blob)进行转换下,代码如下:

if(data['avatar']){
    this.imageUrl = URL.createObjectURL(data.avatar);
}

        此时,我们可以进行新增或编辑学员头像修改了,现在保存到数据库中的avatar中则Blob二进制数据了,如下图所示:

注:如果之前是按照base64图像存储的,需通过编辑功能,将所有avatar值转成Blob二进制后,再进行修改列表数据,否则拿到的base64将无法转成正常的URL对象。

        由于列表页还未将Blob二进制流转成可显示的URL对象,现在列表效果如下:

 2.5 列表页修改

        列表页我们只需要将updateList()函数执行后,内部获取的avatar值转换成可显示的URL对象即可,代码如下:

methods: { 

   //...

   updateList(){
      getStudentPageList(this.keyword, {
        page: this.page,
        pageSize: this.pageSize
      }).then(res => {
        if(res.code==1){
          this.pageTotal = res.data['total'];
          this.tableList = res.data['list'].map(item => {
            item['createtime'] = formatDate(item.createtime);
            item['updatetime'] = formatDate(item.updatetime);

            //将Blob二进制转成可显示的URL对象
            if(item['avatar']){
              item.avatar = URL.createObjectURL(item.avatar);
            }
            return item;
          });
        }
      }).catch(e => {
        console.error(e);
      })
    },

    //...

}

现在列表效果如下:

猜你喜欢

转载自blog.csdn.net/jiciqiang/article/details/127685455