Skip to content

1.FormData 的使用

FormData 是 JavaScript 的内置对象,用于创建表单数据对象,以便将数据通过 AJAX 或 Fetch API 发送到服务器。

在你提供的代码中,你创建了一个新的 FormData 对象,命名为 FormDatas

以下是一个示例,展示了如何使用 FormData 对象来构建表单数据:就相当于一个对象的作用

js
let FormDatas = new FormData();
FormDatas.append("username", "John");
FormDatas.append("email", "john@example.com");
FormDatas.append("file", fileInput.files[0]);

在上面的示例中,我们首先创建了一个新的 FormData 对象,然后使用 append 方法向表单数据中添加键值对。

  • FormDatas.append('username', 'John'):将键 'username' 和值 'John' 添加到表单数据中。
  • FormDatas.append('email', 'john@example.com'):将键 'email' 和值 'john@example.com' 添加到表单数据中。
  • FormDatas.append('file', fileInput.files[0]):将键 'file' 和文件输入框 fileInput 中选择的第一个文件添加到表单数据中。

你可以根据实际需求添加更多的键值对到 FormData 对象中。

一旦你构建了 FormData 对象,你可以将其作为请求的 body 部分,通过 AJAX 请求 发送到服务器。

请注意,FormData 对象还有其他方法和属性,可以根据需要进行使用,例如 delete()get()getAll() 等方法,以及 has()set()entries() 等属性。你可以参考官方文档或其他资源来深入了解 FormData 的用法和功能。

2.el-upload 实现图片上传

上传图片的三个流程:

1.选择图片

2.调用后端接口进行文件上传,返回文件链接

3.在提交时,将文件链接作为参数调用接口,保存起来,以便下次打开时,文件被记录

模板 1:针对文件列表(多个)

html
<el-form-item label="介绍图片" prop="name" class="imgs-intro">
  <!-- 针对之前上传的图片:去introImages里面替换 -->
  <el-upload
    action="#"
    list-type="picture-card"
    :auto-upload="false"
    :show-file-list="false"
    :on-change="file => changeAlreadyUploadData(file, key)"
    v-for="(item, key) in serviceCenterForm.introImages">
    <!-- 因为这是历史图片,并且是直接用v-for遍历出来的,所以不用展示:show-file-list="false" -->
    <img class="el-upload-list__item-thumbnail" :src="item" alt="" />
  </el-upload>
  <!-- 针对本次上传的图片:去fileList里面删 -->
  <el-upload
    action="#"
    list-type="picture-card"
    :auto-upload="false"
    :on-change="handleSetUploadData2"
    :on-remove="handleRemove"
    v-if="
      serviceCenterForm.introImages &&
        serviceCenterForm.introImages.length < 9
    ">
    <i slot="default" class="el-icon-plus"></i>
  </el-upload>
</el-form-item>
js
// 上传图片,调用后端接口 ——> 直接上传了,此时还没有保存数据
handleSetUploadData2(file) {
  let obj = {
    name: file.name
  };
  let userInfo = localStorage.getItem("userInfo");
  let token = JSON.parse(userInfo).token;
  let FormDatas = new FormData();
  FormDatas.append("file", file.raw);
  let host = window.location.href;
  let BASE_URL = "";
  if (
    host.indexOf("localhost") > -1 ||
    host.indexOf("test") > -1 ||
    host.indexOf("me.classba.cn") > -1
  ) {
    // 测试或开发环境
    BASE_URL = "https://test-agent-crm.myyixue.com";
  } else if (host.indexOf("pre") > -1) {
    // 预发环境
    BASE_URL = `https://agent-crm-pre.songshuai.com`;
  } else {
    BASE_URL = `https://agent-crm.songshuai.com`;
  }
  axios
    .post(`${BASE_URL}/api/base/upload/uploadPicture`, FormDatas, {
      headers: {
        "Content-Type": "multipart/form-data",
        authorization: token
      }
    })
    .then(res => {
      if (res.data.code == 0) {
        console.log(res.data);
        let { fileName, uploadPath } = res.data.data;
        obj["url"] = uploadPath;
        this.fileList.push(obj);
      } else {
        this.$message.error(res.data.message);
      }
    });
},
//根据索引key去serviceCenterForm.introImages里面修改已上传的图片(重新上传,替换原图片)
changeAlreadyUploadData(file, key) {
  console.log(file); //可以正常获取file对象
  console.log(key); //索引
  let url = "";
  let userInfo = localStorage.getItem("userInfo");
  let token = JSON.parse(userInfo).token;
  let FormDatas = new FormData();
  FormDatas.append("file", file.raw);
  let host = window.location.href;
  let BASE_URL = "";
  if (
    host.indexOf("localhost") > -1 ||
    host.indexOf("test") > -1 ||
    host.indexOf("me.classba.cn") > -1
  ) {
    // 测试或开发环境
    BASE_URL = "https://test-agent-crm.myyixue.com";
  } else if (host.indexOf("pre") > -1) {
    // 预发环境
    BASE_URL = `https://agent-crm-pre.songshuai.com`;
  } else {
    BASE_URL = `https://agent-crm.songshuai.com`;
  }
  axios
    .post(`${BASE_URL}/api/base/upload/uploadPicture`, FormDatas, {
      headers: {
        "Content-Type": "multipart/form-data",
        authorization: token
      }
    })
    .then(res => {
      if (res.data.code == 0) {
        console.log(res.data);
        let { fileName, uploadPath } = res.data.data;
        url = uploadPath; //一次也就只有一个url上传成功
        // 替换链接
        let imgsList = this.serviceCenterForm.introImages;
        console.log(imgsList);
        imgsList.map((item, index) => {
          if (key == index) {
            // alert(111);
            imgsList.splice(index, 1, url);
          }
        });
        this.serviceCenterForm.introImages = imgsList;
        console.log(imgsList);
      } else {
        this.$message.error(res.data.message);
      }
    });
},
// 根据图片名name去fileList里面删除图片(删除暂存的文件链接,还没有保存到后端之前)
handleRemove(file) {
  let fileList = this.fileList;
  let name = file.name.split(".")[0];
  fileList.map((item, index) => {
    let itemName = item.name.split(".")[0];
    if (name == itemName) {
      fileList.splice(index, 1);
    }
  });
  this.fileList = fileList;
  console.log(fileList);
},

模板 2:针对单个文件或者图片

html
<el-upload
  class="avatar-uploader"
  action="#"
  :show-file-list="false"
  :on-change="handleSetUploadData">
  <img
    v-if="serviceCenterForm.qCodeImage"
    :src="serviceCenterForm.qCodeImage"
    class="avatar-qcode" />
  <i v-else class="el-icon-plus avatar-uploader-icon"></i>
</el-upload>
js
// 上传二维码,调用后端接口
handleSetUploadData(file) {
  let userInfo = localStorage.getItem("userInfo");
  let token = JSON.parse(userInfo).token;
  let FormDatas = new FormData();
  FormDatas.append("file", file.raw);
  let host = window.location.href;
  let BASE_URL = "";
  if (
    host.indexOf("localhost") > -1 ||
    host.indexOf("test") > -1 ||
    host.indexOf("me.classba.cn") > -1
  ) {
    // 测试或开发环境
    BASE_URL = "https://test-agent-crm.myyixue.com";
  } else if (host.indexOf("pre") > -1) {
    // 预发环境
    BASE_URL = `https://agent-crm-pre.songshuai.com`;
  } else {
    BASE_URL = `https://agent-crm.songshuai.com`;
  }
  axios
    .post(`${BASE_URL}/api/base/upload/uploadPicture`, FormDatas, {
      headers: {
        "Content-Type": "multipart/form-data",
        authorization: token
      }
    })
    .then(res => {
      if (res.data.code == 0) {
        let { fileName, uploadPath } = res.data.data;
        this.serviceCenterForm.qCodeImage = uploadPath;
      } else {
        this.$message.error(res.data.message);
      }
    });
},

注意:

on-remove 等回调函数,:show-file-list="true",:file-list="fileList"都只对本次新上传的管用,之前上传的不行!

并且:show-file-list="true",:file-list="fileList" 一般是不要的

:file-list 属性的介绍

在 Element UI 的 el-upload 组件中,file-list 属性用于指定一个绑定的数组,用于展示上传文件的列表。通过将 file-list 绑定到一个数组对象,你可以实现以下功能:

  1. 显示上传文件列表:将 file-list 绑定到一个数组后,el-upload 组件会自动在界面上展示已上传的文件列表,包括文件名、大小、上传进度等信息。
  2. 删除已上传文件:通过修改绑定的 file-list 数组,你可以实现删除已上传的文件。当你在 file-list 数组中移除某个文件对象时,el-upload 组件会相应地更新界面上的文件列表。
  3. 预览已上传文件:你可以通过绑定的 file-list 数组中的文件对象,实现预览已上传的文件。通常,el-upload 组件会提供一个预览功能,允许你点击文件列表中的某个文件,以弹出预览窗口显示文件内容。

总之,file-list 属性是 el-upload 组件用于展示已上传文件列表的关键属性。通过绑定一个数组对象到 file-list,你可以方便地管理和显示上传文件的信息,并实现文件的删除和预览功能。

2.on-change 回调实现自定义传参

正常写法是:on-change="changeAlreadyUploadData",changeAlreadyUploadData(file) {}

如果我们想传 key,直接这样的话:on-change="changeAlreadyUploadData(key)"

那么 changeAlreadyUploadData(file, key) {} 这边的 file 会是 key,而 key 会是 undefined,所以我们可以把回调进行封装

可以将 on-change 的回调进行封装,因为回调的默认参数就是 file,我们将它再传给函数,:on-change="file => changeAlreadyUploadData(file, key)",这样 changeAlreadyUploadData(file, key) {} 可以正常接收到 file 和 key

3.文本超出宽度范围自动换行的实现

通过设置 .long-wordword-break 属性为 break-all,当单词超出容器宽度时,会自动进行换行。

请注意,word-break: break-all 会在单词内部的任意位置进行换行,这可能会导致单词变得难以阅读。因此,在实际应用中,建议结合使用 overflow-wrapword-wrap 属性,以更好地处理长单词的换行情况。

例如,你可以添加 overflow-wrap: break-word,让单词在空格或连字符处换行,同时允许单词内部任意位置的换行:

css
cssCopy code.long-word {
  word-break: break-all;
  overflow-wrap: break-word;
}

这样,当单词超出容器宽度时,会在空格或连字符处进行换行,如果没有空格或连字符,则在单词内部任意位置进行换行。这样可以更好地保持单词的可读性。

注意

一般数字是必须要有换行的,文字则会默认根据 div 的固定宽度自动换行

4.路由的有关问题

1.vue-router 中传参数量一定要够,才能正确找到路由,即便传的参数都是没用的

例如:

localhost:8080/case/detail/861747617141362688/0/0/0/0/2/0

2.常用的两种传参

路由跳转:params 和 query

js
:to="/case/detail/111?campusId=222"

路由配置:主要是配置 params 的,而 query 是直接?跟在后面就可以了!

js
/case/detail/:caseId

接收参数:

js
this.caseId = this.$route.params.caseId || 0;
this.campusId = this.$route.query.campusId || 0;

还有常用的就是 props,但是相对更加高级了!

5.js 里面可以连续相等,连续赋值

js
this.divLineBottom = this.inSchoolScoreTopHeight =
  Math.round((moduleData?.inSchoolScore * 100) / moduleData?.totalScore) + "%";

6.基本的常用操作

js
let a = this.viewType == 3 ? "" : this.viewType; //三元运算符
js
let str = "111"; //字符串转数字的三种基本方法
let a = parseFloat(str);
let b = parseInt(str);
let c = Number(str);
css
p {
  text-indent: 2em;
}

7.json.cn 网站

传参的时候一定要看好 json 结构,json.cn 网站要用起来,否则会造成后端不必要的麻烦

8.transform-origin 会改变原内容的位置

即使 transform:scale(1),也会影响原来的样式

所以要设置:style 默认为空“”

html
<div class="detail" :style="scaleStyle"></div>
js
let scaleStyle = ""; //默认情况下
if (this.isPreview == 1) {
  this.scaleStyle = { transform: `scale(0.6)`, "transform-origin": "top" };
  // this.scaleNum = 0.6;
}

9.js 对象列表的字段组成新列表

如果你有一个对象组成的列表,想要从中提取出特定字段组成一个新的列表,你可以使用 JavaScript 的map函数。

js
// 原始对象列表
var people = [
  { name: "Alice", age: 25 },
  { name: "Bob", age: 30 },
  { name: "Charlie", age: 35 },
];

// 提取名字字段组成新列表
var names = people.map(function (person) {
  return person.name;
});

console.log(names); // 输出: ['Alice', 'Bob', 'Charlie']

10.实现排序规则选择器

orderByType 代表根据不同的进行排序,viewCountSort 和 buyCountSort 代表不同规则下的升序和降序

箭头最好还是用图片,不要直接用文字 ▲,不够美观

html
<section>
  <div @click="selectSubject">
    {{ subjectName }}
    <span><img src="../../assets/images/case/triangle/bottom-grey.png" /></span>
  </div>
  <div @click="selectCity">
    {{ areaName }}
    <span><img src="../../assets/images/case/triangle/bottom-grey.png" /></span>
  </div>
  <p @click="buyCountSortClick">
    购买量
    <!-- <span :class="[orderByType === 1 ? 'orderBy' : '']"> -->
    <span v-if="orderByType === 1">
      <!-- <b :class="[!buyCountSort ? 'selected' : 'noSelected']">▲</b>
        <b :class="[buyCountSort ? 'selected' : 'noSelected']">▼</b> -->
      <b v-if="!buyCountSort"
        ><img src="../../assets/images/case/triangle/top-blue.png"
      /></b>
      <b v-if="buyCountSort"
        ><img src="../../assets/images/case/triangle/bottom-blue.png"
      /></b>
    </span>
    <span v-else>
      <b><img src="../../assets/images/case/triangle/both-white.png" /></b
    ></span>
  </p>

  <p @click="viewCountSortClick">
    浏览量
    <!-- <span :class="[orderByType === 2 ? 'orderBy' : '']"> -->
    <span v-if="orderByType === 2">
      <!-- <b :class="[!viewCountSort ? 'selected' : 'noSelected']">▲</b>
        <b :class="[viewCountSort ? 'selected' : 'noSelected']">▼</b> -->
      <b v-if="!viewCountSort"
        ><img src="../../assets/images/case/triangle/top-blue.png"
      /></b>
      <b v-if="viewCountSort"
        ><img src="../../assets/images/case/triangle/bottom-blue.png"
      /></b>
    </span>
    <span v-else>
      <b><img src="../../assets/images/case/triangle/both-white.png" /></b
    ></span>
  </p>
</section>