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

修改头像

图片上传预览

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('更新失败')
      }
    }
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
首先,你需要在Vue项目中安装vue-router。在安装完成后,你需要在你的Vue项目中创建一个router目录,并且在该目录下创建一个index.js文件,用于定义路由。 在index.js文件中,你需要引入Vuevue-router,然后在Vue中使用vue-router插件。然后,你需要定义每个页面的路由,例如: ```javascript import Vue from 'vue' import VueRouter from 'vue-router' import A from '../components/A.vue' import B from '../components/B.vue' import C from '../components/C.vue' Vue.use(VueRouter) const routes = [ { path: '/a', component: A }, { path: '/b', component: B }, { path: '/c', component: C } ] const router = new VueRouter({ routes }) export default router ``` 在上面的代码中,我们定义了三个组件A、B和C,并将它们分别对应到了不同的路由上。现在,我们需要在Vue实例中使用router,例如: ```javascript import Vue from 'vue' import App from './App.vue' import router from './router' new Vue({ el: '#app', router, render: h => h(App) }) ``` 这样,我们就可以在Vue项目中使用router了。现在,我们需要记录每次路由跳转的记录。为了实现这个功能,我们可以在路由跳转前和路由跳转后分别触发beforeEach和afterEach钩子函数,并在这些函数中记录路由跳转的记录。例如: ```javascript import Vue from 'vue' import VueRouter from 'vue-router' import A from '../components/A.vue' import B from '../components/B.vue' import C from '../components/C.vue' Vue.use(VueRouter) const routes = [ { path: '/a', component: A }, { path: '/b', component: B }, { path: '/c', component: C } ] const router = new VueRouter({ routes }) // 记录路由跳转记录 const routerHistory = [] router.beforeEach((to, from, next) => { routerHistory.push({ from: from.path, to: to.path }) next() }) router.afterEach((to, from) => { routerHistory.push({ from: from.path, to: to.path }) }) export default router ``` 在上面的代码中,我们定义了一个routerHistory数组用于记录路由跳转的记录,并在beforeEach和afterEach钩子函数中分别将from和to的path记录到routerHistory数组中。这样,我们就可以在任何组件中访问routerHistory数组,以查看路由跳转记录。 希望这个简单的实现思路能够帮助你实现你的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不停喝水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值