Vue移动端系列 => [10] 编辑用户头像

338 阅读1分钟

修改头像

图片上传预览

1、准备file类型输入框,并通过点击头像触发上传

<input type="file" hidden ref="inputFile">
    <!-- 导航栏 -->
    <van-nav-bar
    class="page-nav-bar"
    title="个人信息"
    left-arrow @click-left="$router.back()" />
    <!-- /导航栏 -->
    <van-cell title="头像" is-link @click="$refs.inputFile.click()">
      <van-image
        class="avatar"
        fit="cover"
        round
        :src="user.photo"
      />
    </van-cell>

2、给input定义change事件

3、获取上传文件信息

inputChange () {
      // 获取文件对象
      const file = this.$refs.inputFile.files[0]
      // 获取blob数据
      const imgUrl = window.URL.createObjectURL(file)
      console.log(imgUrl)
    }

图片上传预览功能处理

1、定义显示弹层

<!-- 编辑头像弹层 -->
    <van-popup
    v-model="isShowUpdateAvatar"
    style="height: 100%"
    position="bottom">
      hello
    </van-popup>
    <!-- 编辑头像弹层 -->
inputChange () {
    // 获取上传文件
    const file = this.$refs.inputFile.files[0]
    const data = window.URL.createObjectURL(file)
    console.log(data)
    this.isShowUpdateAvatar = true
}

2、定义更新图片组件

3、引用、注册、使用

import updateAvatar from './components/update-avatar.vue'
components: {
    updateName,
    updateGender,
    updateBirthdy,
    updateAvatar
}
<!-- 编辑头像弹层 -->
    <van-popup
    v-model="isShowUpdateAvatar"
    style="height: 100%"
    position="bottom">
      <update-avatar : />
    </van-popup>
    <!-- 编辑头像弹层 -->

4、将图片保存到data中并传递给update-avatar组件

inputChange () {
    // 获取上传文件
    const file = this.$refs.inputFile.files[0]
    this.img = window.URL.createObjectURL(file)
    this.isShowUpdateAvatar = true
    this.$refs.inputFile.value = ''
}
<!-- 编辑头像弹层 -->
    <van-popup
    v-model="isShowUpdateAvatar"
    style="height: 100%"
    position="bottom">
      <update-avatar :img="img" />
    </van-popup>
    <!-- 编辑头像弹层 -->

5、update-avatar组件接收并使用

<template>
    <div>
      <img :src="img" />
    </div>
</template>

<script>
export default {
  props: {
    img: {
      type: [String, Object],
      retuired: true
    }
  }
}
</script>

<style scoped lang='less'>

</style>

图片上传预览样式处理

1、结构

<div class="update-avatar">
    <img :src="img" />
    <div class="toolbar">
      <span>取消</span>
      <span>完成</span>
    </div>
  </div>

2、css

.update-avatar {
  background: #000;
  width: 100%;
  height: 100%;
  .toolbar {
    position: fixed;
    bottom: 10px;
    width: 100%;
    display: flex;
    justify-content: space-between;
    font-size: 28px;
    color: #fff;
    padding: 0 15px;
    box-sizing: border-box;
  }
}

3、点击取消

<span @click="$emit('close')">取消</span>
<!-- 编辑头像弹层 -->
<van-popup
           v-model="isShowUpdateAvatar"
           style="height: 100%"
           position="bottom">
    <update-avatar @close="isShowUpdateAvatar = false" :img="img" />
</van-popup>
<!-- 编辑头像弹层 -->

头像裁切

方式一:结合服务器的图片上传预览

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A4NmRZqJ-1605272238940)(F:/课程/课程项目/vue/vue-mobile/vue移动端笔记/assets/1567067894388.png)]

方式二:纯客户端实现上传图片预览

方案一:结合服务端的图片裁切上传流程

方案二:纯客户端的图片裁切上传流程

viewMode: 1,
dragMode: 'move',
aspectRatio: 1,
autoCropArea: 1,
cropBoxMovable: false,
cropBoxResizable: false,
background: false,
movable: true

使用cropperjs

1、安装cropperjs

npm install cropperjs

2、引入css、js

import 'cropperjs/dist/cropper.css'
import Cropper from 'cropperjs'

3、在mounted中初始化

const image = this.$refs.img
const cropper = new Cropper(image, {
    aspectRatio: 16 / 9,
    crop (event) {
        console.log(event.detail.x)
        console.log(event.detail.y)
        console.log(event.detail.width)
        console.log(event.detail.height)
        console.log(event.detail.rotate)
        console.log(event.detail.scaleX)
        console.log(event.detail.scaleY)
    }
})
console.log(cropper)

配置cropperjs

const cropper = new Cropper(image, {
    viewMode: 1, // 只能在裁剪的图片范围内移动
    dragMode: 'move', // 画布和图片都可以移动
    aspectRatio: 1, // 裁剪区默认正方形
    autoCropArea: 1, // 自动调整裁剪图片
    cropBoxMovable: false, // 禁止裁剪区移动
    cropBoxResizable: false, // 禁止裁剪区缩放
    background: false // 关闭默认背景
})

裁切的两种方式- 服务端

获取参数

1、获取cropper实例

this.cropper = new Cropper(image, {
      viewMode: 1, // 只能在裁剪的图片范围内移动
      dragMode: 'move', // 画布和图片都可以移动
      aspectRatio: 1, // 裁剪区默认正方形
      autoCropArea: 1, // 自动调整裁剪图片
      cropBoxMovable: false, // 禁止裁剪区移动
      cropBoxResizable: false, // 禁止裁剪区缩放
      background: false // 关闭默认背景
    })

2、给确定注册点击事件,在事件函数中获取参数

<span @click="confirm">完成</span>
confirm () {
    console.log(this.cropper.getData())
}

客户端方式

confirm () {
      // console.log(this.cropper.getData())
      this.cropper.getCroppedCanvas().toBlob(blob => {
        console.log(blob)
      })
    }

实现裁剪图片提交

1、封装更新头像api

/**
 * 更新头像
 */
export const updateUserAvatar = data => {
  return request({
    method: 'PATCH',
    url: '/app/v1_0/user/photo',
    data
  })
}

2、引入方法并调用

import { updateUserAvatar } from '@/api/user.js'
confirm () {
      this.cropper.getCroppedCanvas().toBlob(async blob => {
        // 创建formData数据
        const formData = new FormData()
        formData.append('photo', blob)
        const res = await updateUserAvatar(formData)
        console.log(res)
      })
    }

3、关闭弹层、更新视图

this.cropper.getCroppedCanvas().toBlob(async blob => {
        const formData = new FormData()
        formData.append('photo', blob)
        const { data } = await updateUserAvatar(formData)
        // 关闭弹层,更新视图
        this.$emit('close')
        this.$emit('update-avatar', data.data.photo)
      })
<update-avatar
      @update-avatar="user.photo = $event"
      @close="isShowUpdateAvatar = false"
      :img="img" />

4、利用v-if重置数据

<update-avatar
      v-if="isShowUpdateAvatar"
      @update-avatar="user.photo = $event"
      @close="isShowUpdateAvatar = false"
      :img="img" />

5、优化loading效果

async updateAvatar (blob) {
      this.$toast.loading({
        message: '保存中...',
        forbidClick: true,
        loadingType: 'spinner',
        duration: 0
      })
      try {
        const formData = new FormData()
        formData.append('photo', blob)
        const { data } = await updateUserAvatar(formData)
        // 关闭弹层,更新视图
        this.$emit('close')
        this.$emit('update-avatar', data.data.photo)
        this.$toast('更新成功')
      } catch (err) {
        this.$toast('更新失败')
      }
    }