1.FormData 的使用
FormData
是 JavaScript 的内置对象,用于创建表单数据对象,以便将数据通过 AJAX 或 Fetch API 发送到服务器。
在你提供的代码中,你创建了一个新的 FormData
对象,命名为 FormDatas
。
以下是一个示例,展示了如何使用 FormData
对象来构建表单数据:就相当于一个对象的作用
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:针对文件列表(多个)
<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>
// 上传图片,调用后端接口 ——> 直接上传了,此时还没有保存数据
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:针对单个文件或者图片
<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>
// 上传二维码,调用后端接口
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
绑定到一个数组对象,你可以实现以下功能:
- 显示上传文件列表:将
file-list
绑定到一个数组后,el-upload
组件会自动在界面上展示已上传的文件列表,包括文件名、大小、上传进度等信息。 - 删除已上传文件:通过修改绑定的
file-list
数组,你可以实现删除已上传的文件。当你在file-list
数组中移除某个文件对象时,el-upload
组件会相应地更新界面上的文件列表。 - 预览已上传文件:你可以通过绑定的
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-word
的 word-break
属性为 break-all
,当单词超出容器宽度时,会自动进行换行。
请注意,word-break: break-all
会在单词内部的任意位置进行换行,这可能会导致单词变得难以阅读。因此,在实际应用中,建议结合使用 overflow-wrap
或 word-wrap
属性,以更好地处理长单词的换行情况。
例如,你可以添加 overflow-wrap: break-word
,让单词在空格或连字符处换行,同时允许单词内部任意位置的换行:
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
:to="/case/detail/111?campusId=222"
路由配置:主要是配置 params 的,而 query 是直接?跟在后面就可以了!
/case/detail/:caseId
接收参数:
this.caseId = this.$route.params.caseId || 0;
this.campusId = this.$route.query.campusId || 0;
还有常用的就是 props,但是相对更加高级了!
5.js 里面可以连续相等,连续赋值
this.divLineBottom = this.inSchoolScoreTopHeight =
Math.round((moduleData?.inSchoolScore * 100) / moduleData?.totalScore) + "%";
6.基本的常用操作
let a = this.viewType == 3 ? "" : this.viewType; //三元运算符
let str = "111"; //字符串转数字的三种基本方法
let a = parseFloat(str);
let b = parseInt(str);
let c = Number(str);
p {
text-indent: 2em;
}
7.json.cn 网站
传参的时候一定要看好 json 结构,json.cn 网站要用起来,否则会造成后端不必要的麻烦
8.transform-origin 会改变原内容的位置
即使 transform:scale(1),也会影响原来的样式
所以要设置:style 默认为空“”
<div class="detail" :style="scaleStyle"></div>
let scaleStyle = ""; //默认情况下
if (this.isPreview == 1) {
this.scaleStyle = { transform: `scale(0.6)`, "transform-origin": "top" };
// this.scaleNum = 0.6;
}
9.js 对象列表的字段组成新列表
如果你有一个对象组成的列表,想要从中提取出特定字段组成一个新的列表,你可以使用 JavaScript 的map
函数。
// 原始对象列表
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 代表不同规则下的升序和降序
箭头最好还是用图片,不要直接用文字 ▲,不够美观
<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>