惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News and Events Feed by Topic
D
Docker
云风的 BLOG
云风的 BLOG
F
Fortinet All Blogs
F
Full Disclosure
H
Hackread – Cybersecurity News, Data Breaches, AI and More
P
Proofpoint News Feed
Microsoft Azure Blog
Microsoft Azure Blog
WordPress大学
WordPress大学
The GitHub Blog
The GitHub Blog
L
LangChain Blog
H
Help Net Security
B
Blog
T
Tailwind CSS Blog
V
V2EX
博客园_首页
阮一峰的网络日志
阮一峰的网络日志
人人都是产品经理
人人都是产品经理
The Cloudflare Blog
Recent Announcements
Recent Announcements
aimingoo的专栏
aimingoo的专栏
美团技术团队
A
About on SuperTechFans
C
Cybersecurity and Infrastructure Security Agency CISA
K
Kaspersky official blog
I
InfoQ
Project Zero
Project Zero
I
Intezer
Google DeepMind News
Google DeepMind News
博客园 - 【当耐特】
Hugging Face - Blog
Hugging Face - Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
Threat Research - Cisco Blogs
Last Week in AI
Last Week in AI
C
Cyber Attacks, Cyber Crime and Cyber Security
G
GRAHAM CLULEY
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
AWS News Blog
AWS News Blog
Spread Privacy
Spread Privacy
S
Securelist
Recorded Future
Recorded Future
D
Darknet – Hacking Tools, Hacker News & Cyber Security
博客园 - 叶小钗
S
Security Affairs
Blog — PlanetScale
Blog — PlanetScale
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
罗磊的独立博客
The Hacker News
The Hacker News

博客园 - abcByme

边框渐变、字体渐变 列表进度处理 路由保存参数还在当前页 菜单右侧竖条 登录记住密码浏览器默认样式修改 a-table 子级异步加载 动态效果 是否第一次打开 vue3 拖动弹窗 vue3 表格下拉刷新 vue3 下拉刷新 平均分布从左到右 从上到下 js 数据平均分配 喊话器功能 获取完整的文件路径地址 vue3 词云 树形多选 多表单验证 复选框单选
头像图片上传和裁切
abcByme · 2025-03-27 · via 博客园 - abcByme

<script setup>

import { message } from 'ant-design-vue'

import Cropper from 'cropperjs'

import { upload } from '@/api/workOrder/hotService'

const props = defineProps({

  modelValue: String,

})

const emit = defineEmits(['update:modelValue', 'submit'])

const modelValue = useVModel(props, 'modelValue', emit)

const [visible, toggle] = useToggle(false)

const imgRef = ref()

const previewRef = ref()

const fileRef = ref()

const cropper = ref()

function init() {

  cropper.value = new Cropper(unrefElement(imgRef), {

    aspectRatio: 1,

    dragMode: 'move',

    preview: unrefElement(previewRef),

    restore: false,

    center: false,

    highlight: false,

    cropBoxMovable: true,

    toggleDragModeOnDblclick: true,

  })

}

function getImageBase64(e) {

  const file = e.target.files[0]

  if (!file) return

  const reader = new FileReader()

  reader.readAsDataURL(file)

  reader.onload = () => {

    if (!cropper.value) init()

    cropper.value.replace(reader.result)

  }

}

function submit() {

  const file = cropper.value?.getCroppedCanvas()?.toDataURL()

  if (!file) {

    message.info('请选择图片')

    return

  }

  if (file.length > 250 * 1024) {

    message.warning('选择的区域太大,超过了250K。请缩小选择区域!')

    return

  }

  modelValue.value = file

  let newfile = base64ToFile(file, '头像')

  const formData = new window.FormData()

  formData.append('files', newfile)

  upload(formData).then((res) => {

    if (res?.code == 200) {

      message.success('上传成功')

      if (res.data && res.data !== null && res.data.length) {

        emit('submit', res.data)

      }

    }

  })

  toggle(false)

}

function base64ToFile(dataurl, filename) {

  let arr = dataurl.split(','),

    mime = arr[0].match(/:(.*?);/)[1],

    bstr = atob(arr[1]),

    n = bstr.length,

    u8arr = new Uint8Array(n)

  while (n--) {

    u8arr[n] = bstr.charCodeAt(n)

  }

  return new File([u8arr], filename, { type: mime })

}

function upload1() {

  fileRef.value?.click()

}

function reset() {

  cropper.value?.reset()

}

function remove() {

  cropper.value?.destroy()

  cropper.value = null

}

function zoomIn() {

  cropper.value?.zoom(0.1)

}

function zoomOut() {

  cropper.value?.zoom(-0.1)

}

</script>

<template>

  <div>

    <div class="btn">

      <a-button @click="toggle()">本地上传</a-button>

    </div>

    <a-modal

      v-model:visible="visible"

      title="修改头像"

      width="640px"

      :closable="false"

      :maskClosable="false"

      @ok="submit()"

    >

      <div class="flex justify-between">

        <div class="w-96 border border-solid border-gray-300">

          <img ref="imgRef" />

        </div>

        <div class="flex flex-col items-center space-y-2.5">

          <div

            ref="previewRef"

            class="w-44 h-44 border border-solid border-gray-300 overflow-hidden"

          />

          <a-space>

            <a-button-group>

              <input

                ref="fileRef"

                type="file"

                accept="image/png, image/jpeg, image/gif, image/jpg"

                class="hidden"

                @change="getImageBase64"

              />

              <a-button type="primary" @click="upload1()">

                <template #icon>

                  <UploadOutlined />

                </template>

              </a-button>

              <a-button type="primary" @click="reset()">

                <template #icon>

                  <SyncOutlined />

                </template>

              </a-button>

              <a-button type="primary" @click="remove()">

                <template #icon>

                  <DeleteOutlined />

                </template>

              </a-button>

            </a-button-group>

            <a-button-group>

              <a-button type="primary" @click="zoomIn()">

                <template #icon>

                  <ZoomInOutlined />

                </template>

              </a-button>

              <a-button type="primary" @click="zoomOut()">

                <template #icon>

                  <ZoomOutOutlined />

                </template>

              </a-button>

            </a-button-group>

          </a-space>

        </div>

      </div>

    </a-modal>

  </div>

</template>

<style scoped>

@import 'cropperjs';

img {

  display: block;

  max-width: 100%;

}

.btn {

  margin-top: 10px;

}

</style>