vue+element上传图片

news2024/11/7 18:09:29

一、html页面上传图片

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div>
        <input type="file" id="fileInput" />
        <img id="imagePreview" src="" alt="Image Preview" />
    </div>
</body>
</html>
<script>
    const fileInput = document.getElementById('fileInput');
    const imagePreview = document.getElementById('imagePreview');
    
    fileInput.addEventListener('change', (event) => {
      // 获取用户选择的第一个文件
      const file = event.target.files[0]; 
      if (file) {
        const objectURL = URL.createObjectURL(file); // 创建临时 URL
        imagePreview.src = objectURL; // 设置为 img 标签的 src
      }
    });
</script>

 

二、vue选择图片和上传图片

 

1.:auto-upload="false"取消自动上传,点击上传头像按钮上传

2.:on-change文件上传成功时的钩子,(选择图片后,把图片格式转换为base64格式)

3.点击button按钮和upload组件都可以选择图片

4.上传图片(发送请求更新头像,userStore重新更新数据,给用户提示)

<template>
  <PageContainer title="更换头像">
    <el-upload
      ref="uploadRef"
      class="avatar-uploader"
      :auto-upload="false"
      :show-file-list="false"
      :before-upload="beforeAvatarUpload"
      :on-change="onSelectFile"
    >
      <img v-if="imageUrl" :src="imageUrl" class="avatar" />
      <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
    </el-upload>
    <div class="btns">
      <el-button icon="Plus" type="primary" @click="onSelectFn"
        >选择图片</el-button
      >
      <el-button icon="Upload" type="success" @click="onUpdateFn"
        >上传头像</el-button
      >
    </div>
  </PageContainer>
</template>
<script setup>
import { ref } from "vue";
import { ElMessage } from "element-plus";
import { Plus, Upload } from "@element-plus/icons-vue";
import PageContainer from "@/components/PageContainer.vue";
import { updateAvatarApi } from "@/api/user";
import { useUserStore } from "@/store";
//基于store的数据拿到imageUrl的初始值
const userStore = useUserStore();
//图片上传
const imageUrl = ref(userStore.userInfo.user_pic);
const uploadRef = ref();
const beforeAvatarUpload = (rawFile) => {
  if (rawFile.type !== "image/jpeg") {
    ElMessage.error("Avatar picture must be JPG format!");
    return false;
  } else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error("Avatar picture size can not exceed 2MB!");
    return false;
  }
  return true;
};
const onSelectFile = (uploadFile) => {
  //基于fileReader读取图片做预览
  const reader = new FileReader();
  // 将文件读入为Data URL
  reader.readAsDataURL(uploadFile.raw);
  // 获取Base64字符串
  reader.onload = () => {
    imageUrl.value = reader.result;
  };
};
const onSelectFn = () => {
  uploadRef.value.$el.querySelector("input").click();
};
const onUpdateFn = async () => {
  //发送请求更新头像
  await updateAvatarApi(imageUrl.value);
  //userStore重新渲染
  await userStore.getuserInfo();
  //提示用户
  ElMessage.success("修改成功");
};
</script>
<style lang="scss">
.avatar-uploader .avatar {
  width: 178px;
  height: 178px;
  display: block;
}
.avatar-uploader .el-upload {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}
.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
.btns {
  margin-top: 20px;
}
</style>

三、表单中上传图片 

 

1.在表单中使用upload组件

2.URL.createObjectURL 是一个在 JavaScript 中用于创建一个指向 BlobFile 对象的临时 URL 的方法。这种方法非常有用,尤其是在处理文件上传或生成动态内容时,比如图像预览。imageUrl.value = URL.createObjectURL(uploadFile.raw);

  1. 生成临时 URL: 它为 BlobFile 对象生成一个可以在浏览器中使用的 URL。这个 URL 是临时的,仅在页面生命周期内有效。

  2. 文件预览: 在用户选择文件后,可以使用这个 URL 显示图像预览。比如,当用户上传一张图片时,可以生成这个 URL 并将其设置为 <img> 标签的 src 属性。

3.使用 Axios 来获取网络图片并将其转换为 File 对象。以下是具体的实现步骤:

  1. 使用 Axios 请求获取图片的 Blob 数据。
  2. 将 Blob 数据转换为 File 对象。
<template>
  <el-drawer v-model="drawerVisible" direction="rtl">
    <template #header>
      <h4>{{ formModel.id ? "编辑文章" : "添加文章" }}</h4>
    </template>
    <template #default>
      <el-form :model="formModel" :rules="rules" ref="formRef">
        <el-form-item label="文章标题" prop="title">
          <el-input v-model="formModel.title"></el-input>
        </el-form-item>
        <el-form-item label="文章分类" props="cate_id">
          <ChannelSelect
            v-model:modelValue="formModel.cate_id"
            width="100%"
          ></ChannelSelect>
        </el-form-item>
        <el-form-item label="文章封面" prop="cover_img">
          <el-upload
            class="avatar-uploader"
            :auto-upload="false"
            :show-file-list="false"
            :before-upload="beforeAvatarUpload"
            :on-change="onSelectFile"
          >
            <img v-if="imageUrl" :src="imageUrl" class="avatar" />
            <el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
          </el-upload>
        </el-form-item>
        <el-form-item label="文章内容" prop="content">
          <div class="editor">
            <QuillEditor
              ref="editorRef"
              v-model:content="formModel.content"
              theme="snow"
              contentType="html"
            />
          </div>
        </el-form-item>
        <el-form-item label=" ">
          <div>
            <el-button type="primary" @click="onPublisg('已发布')"
              >发布</el-button
            >
            <el-button @click="onPublisg('草稿')">草稿</el-button>
          </div>
        </el-form-item>
      </el-form>
    </template>
  </el-drawer>
</template>
<script setup>
import { ref, nextTick } from "vue";
import ChannelSelect from "@/view/article/component/ChannelSelect.vue";
import {
  addArticlePublishApi,
  getArticleInfoApi,
  editArticleInfoApi,
} from "@/api/article.js";
import { QuillEditor } from "@vueup/vue-quill";
import "@vueup/vue-quill/dist/vue-quill.snow.css";
import { ElMessage } from "element-plus";
import { baseURL } from "@/utils/request";
const drawerVisible = ref(false);
const emit = defineEmits(["success"]);
const deaultFormModel = {
  title: "",
  cate_id: "",
  cover_img: "",
  content: "",
  state: "",
};
const formModel = ref({ ...deaultFormModel });
const formRef = ref();
const editorRef = ref();
const open = async (row) => {
  drawerVisible.value = true;
  if (row.id) {
    const res = await getArticleInfoApi(row.id);
    formModel.value = res.data.data;
    console.log(res);
    imageUrl.value = `${baseURL}${res.data.data.cover_img}`;
    //提交给后台需要的格式是file格式对象,需要将网络图片地址转为file对象,将 File 对象赋值给表单模型
    const file = await convertImageUrlToFile(
      imageUrl,
      formModel.value.cover_img
    );
    formModel.value.cover_img = file;
  } else {
    formModel.value = { ...deaultFormModel };
    console.log("editorRef.value", editorRef.value);
    imageUrl.value = "";
    await nextTick(() => {
      editorRef.value.setHTML("");
    });
  }
};
defineExpose({ open });
//图片上传
const imageUrl = ref("");
const beforeAvatarUpload = (rawFile) => {
  if (rawFile.type !== "image/jpeg") {
    ElMessage.error("Avatar picture must be JPG format!");
    return false;
  } else if (rawFile.size / 1024 / 1024 > 2) {
    ElMessage.error("Avatar picture size can not exceed 2MB!");
    return false;
  }
  return true;
};
const onSelectFile = (uploadFile) => {
  imageUrl.value = URL.createObjectURL(uploadFile.raw);
  formModel.value.cover_img = uploadFile.raw;
};
const onPublisg = async (state) => {
  formModel.value.state = state;
  const fd = new FormData();
  for (let key in formModel.value) {
    fd.append(key, formModel.value[key]);
  }
  if (formModel.value.id) {
    await editArticleInfoApi(fd);
    ElMessage.success("修改成功");
    drawerVisible.value = false;
    emit("success", "emit");
  } else {
    await addArticlePublishApi(fd);
    ElMessage.success("添加成功");
    drawerVisible.value = false;
    console.log("drawerVisible.value", drawerVisible.value);
    emit("success", "add");
  }
};
const convertImageUrlToFile = async (imageUrl, fileName = "image.jpg") => {
  // 使用 Axios 获取图片
  const response = await axios.get(imageUrl, {
    responseType: "blob", // 设置响应类型为 blob
  });
  // 创建 File 对象
  const file = new File([response.data], fileName, {
    type: response.data.type,
  });
  return file;
};
</script>
<style lang="scss" scoped>
.avatar-uploader .avatar {
  width: 178px;
  height: 178px;
  display: block;
}
.avatar-uploader .el-upload {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
  border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
.editor {
  width: 100%;
  .ql-editor {
    min-height: 200px !important;
  }
}
</style>

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2229556.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

22_快速diff算法

目录 处理相同的前置元素和后置元素处理相同的前置元素和后置元素-挂载处理相同的前置元素和后置元素-卸载判断是否需要进行 DOM 移动操作如何移动元素 处理相同的前置元素和后置元素 快速 diff 算法是需要经过预处理的&#xff0c;什么是预处理呢&#xff1f;我们来看一下下面…

Redis-事务、锁

文章目录 数据库的事务、锁介绍数据库的锁数据库的事务 Redis的事务介绍Redis的事务操作例子Redis的锁介绍1. 加锁2. 释放锁乐观锁和悲观锁悲观锁&#xff08;Pessimistic Locking&#xff09;乐观锁&#xff08;Optimistic Locking&#xff09;Redis中的锁机制 3. Redlock算法…

微服务基础拆分实践(第一篇)

目录 前言 一、认识微服务 1.1 单体架构 VS 微服务架构 1.2 微服务的集大成者&#xff1a;SpringCloud 1.3 微服务拆分原则 1.4 微服务拆分方式 二、微服务拆分入门步骤 &#xff1a;以拆分商品模块为例 三、服务注册订阅与远程调用&#xff1a;以拆分购物车为例 3.1 …

【NOIP普及组】 过河卒

【NOIP普及组】 过河卒 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 如图&#xff0c;A 点有一个过河卒&#xff0c;需要走到目标 B 点。卒行走规则&#xff1a;可以向下、或者向右。同时在棋盘上的任一点有一个对方的马&#xff08;如上…

功能强大视频编辑软件 Movavi Video Editor Plus 2024 v24.2.0 中文特别版

Movavi Video Editor Plus中文修改版是一款功能强大的视频制作编辑软件&#xff0c;使用能够帮助用户快速从录制的素材中制作成一个精美的电影&#xff0c;支持进行视频剪辑&#xff0c;支持添加背影、音乐和各种音乐&#xff0c;软件使用简单&#xff0c;无需任何的经验和专业…

linux基本指令之文件操作

前言 这次博客的主要目的就是要解决如何快速查看或查找文件&#xff0c;以及讲解文件的一些属性。本次博客还是以基本指令为主来理解linux对文件的操作。 linux下输入输出流的理解 在linux中&#xff0c;我们要对文件进行输入输出时&#xff0c;一般会怎么做呢? 可以通过pr…

JavaEE初阶---网络原理值TCP篇(三)

文章目录 1.延时应答机制2.捎带应答3.面向字节流---粘包问题3.1问题引入3.2解决方法 4.异常情况的处理5.TCP的心跳机制6.TCP/UDP的对比 1.延时应答机制 例如我们的这个剩余空间大小10kb,如果我们直接返回ack,这个发送方的窗口大小只能是10kb&#xff0c;但是如果我们进行延时&…

慢sql优化和Explain解析

要想程序跑的快&#xff0c;sql优化不可懈怠&#xff01;今日来总结一下常用的慢sql的分析和优化的方法。 1、慢sql的执行分析&#xff1a; 大家都知道分析一个sql语句执行效率的方法是用explain关键词&#xff1a; 举例&#xff1a;sql:select * from test where bussiness_…

Java后端面试内容总结

先讲项目背景&#xff0c;再讲技术栈模块划分&#xff0c; 讲业务的时候可以先讲一般再特殊 为什么用这个&#xff0c;好处是什么&#xff0c;应用场景 Debug发现问题/日志发现问题. QPS TPS 项目单元测试&#xff0c;代码的变更覆盖率达到80%&#xff0c;项目的复用性高…

【10月】新款3DMAX插件排行榜

根据近期的行业动态和插件发布情况&#xff0c;整理并推荐一些在10月或近期内受到关注的3DMAX新款插件。 1. MaxToCAD插件 功能特点&#xff1a;允许用户将3D MAX中的三维模型快速转换为CAD软件可识别的二维平面图&#xff0c;适用于需要将3D设计导出为施工图或平面图的设计师…

【数据结构与算法】第7课—数据结构之队列

文章目录 1. 队列1.1 什么是队列1.2 队列的结构1.3 队列初始化1.4 队列入栈1.5 出队列1.6 查找队列有效元素个数1.7 取队头和队尾数据1.8 销毁链表 2. 用两个队列实现栈3. 用两个栈实现队列4. 循环队列 1. 队列 注&#xff1a;文中Queue是队列&#xff0c;Quene是错误写法 1.1 …

window快捷键:window + v 打开剪切板历史记录 / 非常实用

一、剪切板历史记录功能介绍 1.1、window v 打开剪切板历史记录 / 文字、图片都可记录 1.2、window v 最近使用 1.3、window v 表情符号 1.4、window v GIF 1.5、window v 颜文字 1.6、window v 符号 二、欢迎交流指正

手机功耗异常大数据看板建设

一、背景 基于《软件绿色联盟应用体验标准—功耗标准》监控软硬件资源功耗异常类别与趋势 上述为手机功耗问题的前世今生及我们应该在哪些维度建立功耗的埋点监控支持分析​ 二、目标 手机端侧建立alarm\wakelock\wakeup\gps\bt\cpu\sensor\netTriffic等功耗相关的使用次数和时…

多彩电子显示屏

在仓储管理的广阔舞台上&#xff0c;一款名为“仓库46代”的创新标签悄然登场&#xff0c;它不仅是技术的飞跃&#xff0c;更是智慧仓储的新篇章。这款标签&#xff0c;以其独特的515.6x260x29mm身材&#xff0c;优雅地融入了繁忙的仓库环境&#xff0c;其沉稳的黑色外观&#…

sklearn|机器学习:决策树(一)

文章目录 sklearn&#xff5c;机器学习&#xff1a;决策树&#xff08;一&#xff09;&#xff08;一&#xff09;概述&#xff08;二&#xff09;实战1. 环境配置2. sklearn 中的决策树&#xff08;1&#xff09;模块 sklearn.tree&#xff08;2&#xff09;sklearn 基本建模流…

服务器Linux系统网络重启失败 Restarting network (via systemctl):......

网络重启时报错&#xff1a; Linux 网络服务重启失败可能由网络配置工具冲突或配置错误引起。 冲突问题&#xff1a;在 Linux 中&#xff0c;network 和 NetworkManager 这两个工具可能会冲突&#xff0c;禁用 NetworkManager 可以尝试解决该问题。 先停止服务 systemctl s…

域控操作二十四:主域故障辅域接替

模拟环境&#xff1a;上海DC1故障无法开机&#xff0c;导致只有一个DNS的电脑无法上网&#xff08;实际可以添加DC2但是为了实验就不说了&#xff09; FSMO还在DC1上 使用powershell把角色迁移到DC2 ntdsutil roles connections connect to server DC2SHA.whbk.cn quitSeize …

边缘AI计算技术应用-实训解决方案

一、解决方案架构 1.1 来自产业的项目 实训项目全部是基于产业的商业化项目&#xff0c;经过角色拆解、任务拆解、代码拆解、部署流程拆解等过程&#xff0c;讲其标准化为教师可以带领学生完成的实训内容&#xff0c;真正帮助学生接触产业前沿技术和工作内容&#xff0c;提升就…

贪心算法习题其二【力扣】【算法学习day.18】

前言 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&am…

【Axure原型分享】颜色选择器——填充颜色

今天和大家分享颜色选择器——填充颜色的原型模板&#xff0c;点击颜色区域可以弹出颜色选择器&#xff0c;点击可以选择对应颜色&#xff0c;颜色区域会变色我们选择的颜色&#xff0c;具体效果可以观看下方视频或者打开预览地址体验。 【原型效果】 【Axure高保真原型】颜色…