1.为避免安装依赖过慢或者丢包务必使用淘宝镜像
npm install -g cnpm --registry=registry.npm.taobao.org
之后就可以愉快地使用cnpm命令啦
2.项目中使用sass时由于版本过高导致的报错
1.先删掉整个node_moudules文件夹
2.删除package.json中sass和sass-loader相关配置项
3.按照下面的要求重新安装sass和loader
node-v 16.11.1及以上版本: npm install sass-loader@10.2.0 node-sass@6.0.1 --save-dev
node-v 16.11.1 以下版本: npm install sass-loader@7.3.1 node-sass@4.14.1 --save-dev
node版本与sass版本对应关系:
3.大屏项目自适应使用transform(scale)
data(){
return {
designUI:{
width:1920,
height:1080
}
}
},
created(){
this.setScale();
window.onresize=()=>this.setScale();
},
methods: {
setScale(){
let ratioX = window.innerWidth / this.designUI.width;
let ratioY = window.innerHeight / this.designUI.height;
let style = document.body.style;
style.transform="scale(" + ratioX + "," + ratioY + ")";
style.transformOrigin="left top";
style.backgroundSize="100% 100%";
style.overflow='hidden';
}
}
后续:由于对body进行了缩放,导致elment-ui中与tooltip相关的提示信息都出现了位置偏移,究其原因,在tooltip出现时,是在body内部末尾追加元素,其定位方式其实是相对于body的宽高的,想要使其能够正常显示,就要使body保持正常缩放比例,因此可以将原本加在body上的缩放样式转移到其下一层根元素document.getElementById("app")中,同样达到了自适应的效果,但又不会影响到tooltip气泡位置。注意,此时要将生命周期created改成mounted。
4.使用液晶字体
注意:引入字体文件后如果启动项目报错提示.TTF文件解析失败,则需要安装url-loader
如果安装url-loader后重启项目依然失败,可以检查下是build/webpack.base.conf.js文件中module-rules中是否只匹配解析了ttf,我们只需要把TTF加上就行
5.使用天地图
参考文档:zhuanlan.zhihu.com/p/121701936
注意:请一定保证在页面dom元素挂在完成后(即mounted生命周期中)进行地图初始化,如果非要在created中初始化,请配合$nectTick使用
5.一堆index.vue文件导致断点总是进入错误的位置
参考文档:www.freesion.com/article/446…
6.环境变量
开发环境:config/dev.env.js
生产环境:config/prod.env.js
7.前端配置跨域代理
按照以往的开发经验,前端处理跨域一般是在vue.config.js中通过代理服务器proxy实现,我如法炮制之后发现请求接口总是404(前提:postman测试接口是正常的),把百度翻烂之后终于发现问题所在,老项目是用vue-cli2创建的,配置代理可以在vue.config.js中,但是我的新项目是vue-cli3创建的,要配置跨域代理必须在根路径下的config/index.js中实现,配置项和vue-cli2的方式是一样的,相当于换了个地方而已,也就是说,vue.config.js已经完全没用啦。
vue-cli2老项目,在vue.config.js中配置代理解决跨域:
vue-cli3新项目,在config/index.js中配置代理解决跨域:
参考文档:t.zoukankan.com/EnSnail-p-8…
8.js中动态引入并加载图片
你如果天真的以为
<img :src="imgSrc"> this.imgSrc='../images/logo.png'
这样的代码能让你正常渲染图片的话就大错特错了,必须使用require才行 this.imgSrc=require('../images/logo.png')
9.新项目托管到git
参考文档:Git新建仓库首次提交
10.添加闪烁动画
.span{
-webkit-animation: twinkling 1s infinite ease-in-out;
animation: twinkling 1s infinite ease-in-out;
}
@-webkit-keyframes twinkling{
0%{
opacity: 0.5;
}
100%{
opacity: 1;
}
}
@keyframes twinkling{
0%{
opacity: 0.5;
}
100%{
opacity: 1;
}
}
11.vscode设置保存时自动格式化代码,自动缩进对齐
1.文件–首选项–设置 或者vscode左下角齿轮–设置
2.搜索框搜索emmet.include ,点击在settings.json中编辑
3.在打开的settings.json中添加这两行代码
"editor.formatOnType": true,
"editor.formatOnSave": true,
参考文档:blog.csdn.net/qq_43657442…
12.好用的vscode扩展程序
13.将后台返回的文件流格式的图片进行转化并显示
getImg() {
axios
.get(url, {
responseType: "arraybuffer"
})
.then(res => {
return (
"data:image/png;base64," +
btoa(
new Uint8Array(res.data).reduce(
(data, byte) => data + String.fromCharCode(byte),
""
)
)
);
})
.then(data => {
this.imgSrc = data;
})
.catch(ex => {
console.error(ex);
});
}
14.下载后台返回的文件流格式Excel
export function exportExcel() {
return request({
url: `/dna/watersampledata/export`,
method: "get",
responseType: "blob"
})
}
clickExport() {
exportExcel().then(res => {
const blob = res.data;
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onload = e => {
const a = document.createElement("a");
a.download = `数据.xls`;
a.href = e.target.result;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
};
});
}
15.对于Element UI 下拉框和级联选择器位置错乱问题
- 对于el-select来说添加 :popper-append-to-body = “false” 即可
- 对于el-cascader来说添加 :append-to-body=“false” 即可
16.记录一次犯蠢
平时自己用ES6对象简写用的很爽,但是当用到一些组件库时看到对象简写经常会反应不过来,以为是什么不可随意改变的高级用法,这不,使用天地图创建地图标注是乍一看就被唬到了,小小犯蠢
当时想要创建多个自定义标注图片,类似icon icon1 icon2这种的,然后在创建Marker时根据条件使用不同图片,就发现只有叫icon的能被渲染,其他都渲染失败,当时还在纳闷,明明是自己定义的变量,为啥改个名字就不能用了呢?后来检查代码才突然灵光乍现,麻蛋,识别不了除icon之外的名字因为天地图内置方法new Marker中规定了必须以icon为key,{icon}这种方式其实是触发了ES6的对象简写,完整写法应该是{icon:icon},即{icon:icon1},而后面的icon1才是我们在前文自定义的变量名字,随便怎么改都行
总结:当时用框架或者库时,看到一些貌似高级的语法千万不要被唬住了
17.关于Content-Type
Content-Type分类
application/x-www-form-urlencoded
HTTP会将请求参数用key1=val1&key2=val2的方式进行组织,并放到请求实体里面,注意如果是中文或特殊字符如"/"、","、“:" 等会自动进行URL转码。不支持文件,一般用于表单提交(传参显示在Form Data中)。
multipart/form-data与application/x-www-form-urlencoded不同,这是一个多部分多媒体类型。首先生成了一个 boundary 用于分割不同的字段,在请求实体里每个参数以------boundary开始,然后是附加信息和参数名,然后是空行,最后是参数内容。多个参数将会有多个boundary块。如果参数是文件会有特别的文件域。最后以------boundary–为结束标识。multipart/form-data支持文件上传的格式,一般需要上传文件的表单则用该类型(传参显示在payload中)。
application/jsonJSON 是一种轻量级的数据格式,以“键-值”对的方式组织的数据。这个使用这个类型,需要参数本身就是json格式的数据,参数会被直接放到请求实体里,不进行任何处理。服务端/客户端会按json格式解析数据(传参显示在payload中)。
application/xml 和 text/xml与application/json类似,这里用的是xml格式的数据,text/xml的话,将忽略xml数据里的编码格式
Content-Type使用
request 的Content-Type
一般我们在开发的过程中需要注意客户端发送请求(Request)时的Content-Type设置,特别是使用ajax的时候,如果设置得不准确,很有可能导致请求失败。比如在spring中,如果接口使用了@RequestBody,spring强大的自动解析功能,会将请求实体的内容自动转换为Bean,但前提是请求的Content-Type必须设置为application/json,否正就会返回415错误。(注:415 错误是 Unsupported media type,即不支持的媒体类型。)
建议:如果是一个restful接口(json格式),一般将Content-Type设置为application/json; charset=UTF-8;
如果是文件上传,一般Content-Type设置为multipart/form-data
如果普通表单提交,一般Content-Type设置为application/x-www-form-urlencoded
response的Content-Type
服务端响应(Response)的Content-Type最好也保持准确,虽然一般web开发中,前端解析响应的数据不会根据Content-Type,并且服务端一般能自动设置准确的Content-Type,但是如果乱设置某些情况下可能会有问题,比如导出文件,打开图片等。如果在spring项目里使用@ResponseBody,spring会将响应的Content-Type设置为application/json;charset=UTF-8;,可能会导致文件无法导出,需要注意下。
response的Content-Type设置建议:
一般情况下不需要显示设置; 如果是文件导出,Content-Type 设置为 multipart/form-data,并且添加一个Content-Disposition设置为attachment;fileName=文件.后缀。 注:Content-Disposition是Content-Type的扩展,告诉浏览器弹窗下载框,而不是直接在浏览器里展示文件。因为一般浏览器对于它能够处理的文件类型,如txt,pdf 等,它都是直接打开展示,而不是弹窗下载框。
HTTP请求中 request payload 和 formData 区别?
FormData和Payload是浏览器传输给接口的两种格式,这两种方式浏览器是通过Content-Type来进行区分的(了解Content-Type),如果是 application/x-www-form-urlencoded的话,则为formdata方式,如果是application/json或multipart/form-data的话,则为 request payload的方式。 参考:www.cnblogs.com/kaibindirve…
18.el-upload+xlsx实现前端上传并解析excel
安装xlsx依赖:npm install xlsx
引入XLSX: import XLSX from "xlsx";
html中文件上传组件
<el-upload
action=""
accept=".xls, .xlsx"
:on-change="importFile"
:http-request="uploadRequest"
:show-file-list="false"
:multiple="false"
:limit="1"
class="uploader">
<span class="btn">数据录入</span>
</el-upload>
js中methods部分
文件上传完成后的处理
importFile(file) {
this.file2Xce(file)
.then(res => {
if (res && res.length > 0) {
// 解析出来的json数据格式如:[{sheetName: sheet1, sheet: sheetData }]
//默认只处理第一个页签的数据
if (res[0] && res[0].sheet && res[0].sheet.length) {
let datas = res[0].sheet;
this.tableData = this.handleXlsData(datas, this.tableCols);
}
}
})
.catch(() => {
this.loading = false;
});
},
解析excel文件的核心代码
/**
* 解析excel文件核心代码
* @param {Object} file
*/
file2Xce(file) {
return new Promise(function(resolve, reject) {
const reader = new FileReader();
reader.onload = function(e) {
const data = e.target.result;
this.wb = XLSX.read(data, {
type: "binary"
});
const result = [];
this.wb.SheetNames.forEach(sheetName => {
result.push({
sheetName: sheetName,
sheet: XLSX.utils.sheet_to_json(this.wb.Sheets[sheetName])
});
});
resolve(result);
};
reader.readAsBinaryString(file.raw);
});
},
将直接解析出来的excel文件内容处理成适合自己表格使用的数据格式
/**
* 解析excel文件数据为表格数据
* @param {Array} data
* @param {Array} tableCols
*/
handleXlsData(data,tableCols) {
let result=[];
//循环遍历每一条数据
data.forEach(it => {
let temObj = {};
//循环遍历每条数据的每个属性,并对其进行转化
for (let k in it) {
if (k.includes('日期')) {
it[k]=this.formatDate(it[k],'-')
}
let colName = tableCols.filter(i => i.label === k)[0].prop;
temObj[colName] = it[k];
}
result.push(temObj)
})
return result
},
由于直接解析出来的excel表格数据一般都以表头文字(中文)作为key,比如:
这不符合我们实际开发中的习惯,所以需要对其进行相应转化处理,变成这种:
这里我是直接使用了循环遍历生成表格时所使用的表格列配置信息,其实主要就是表格列名和前端渲染时的列字段的对应关系,自己可以灵活配置,我这边大概配置如下:
另外,在使用xlsx插件来读取excel时,会将2018/10/16这种数据自动装换成48264.12584511这种样子,所以需要自己手动再转换回来(参考:www.cnblogs.com/cazj/p/1094…
/**
* @param {Number} numb是传过来的整数数字
* @param {String} format是之间间隔的符号
*/
formatDate(numb, format) {
const time = new Date((numb - 1) * 24 * 3600000 + 1)
time.setYear(time.getFullYear() - 70)
const year = time.getFullYear() + ''
const month = time.getMonth() + 1 + ''
const date = time.getDate() - 1 + ''
if (format && format.length === 1) {
return year + format + month + format + date
}
return year + (month < 10 ? '0' + month : month) + (date < 10 ? '0' + date : date)
},
备注:vue2项目中如果安装完xlsx依赖发现报错 “export ‘default‘ (imported as ‘XLSX‘) was not found in ‘xlsx‘,有可能是版本不兼容问题,可以通过npm install xlsx@XXX.XXX --save安装特定版本的插件来解决。建议版本:"xlsx": "^0.16.0"
扩展1:纯前端实现下载当前表格为excel
前置条件:安装插件 npm install --save xlsx file-saver
import XLSX from 'xlsx'
import FileSaver from 'file-saver'
exportExcel() {
var wb = XLSX.utils.table_to_book(
document.querySelector("#tableId")
);
var wbout = XLSX.write(wb, {
bookType: "xlsx",
bookSST: true,
type: "array"
});
try {
FileSaver.saveAs(
new Blob([wbout], { type: "application/octet-stream" }),
this.title+".xlsx"
);
} catch (e) {
if (typeof console !== "undefined") console.log(e, wbout);
}
return wbout;
}
参考文档:www.jianshu.com/p/a65122b9d…
注意,如果表格中有固定列,会导致生成重复表格数据
解决思路:先移除固定列Dom,然后再追加
实现代码如下:
exportExcel() {
// 解决生成重复数据-因为使用fixed属性 注意你的fixed是left还是right
var fix = document.querySelector("#daochu2 .el-table__fixed-right");
var wb;
// 判断要导出的节点中是否有fixed的表格,如果有,转换excel时先将该dom移除,然后append回去
if (fix) {
/* 从表生成工作簿对象 */
wb = XLSX.utils.table_to_book(
document.querySelector("#table").removeChild(fix),
{ raw: true }
);
document.querySelector("#table").appendChild(fix);
} else {
wb = XLSX.utils.table_to_book(document.querySelector("#table"), {
raw: true,
});
}
/* 获取二进制字符串作为输出 */
var wbout = XLSX.write(wb, {
bookType: "xlsx",
bookSST: true,
type: "array",
});
try {
FileSaver.saveAs(
new Blob([wbout], { type: "application/octet-stream" }),
// 设置导出文件名称
"统计核算.xlsx"
);
} catch (e) {
if (typeof console !== "undefined") console.log(e, wbout);
}
return wbout;
}
参考文档:www.jianshu.com/p/f6a03c734…
扩展2:纯前端实现将json数据转换为excel数据并下载
import XLSX from 'xlsx';
const export=()=>{
let head = ['商品','售价','颜色']
let data = [
['裙子','¥500','红色'],
['衬衫','¥300','白色'],
['裤子','¥200','黑色'],
['皮鞋','¥800','黑色'],
];
data = data.map(e => Object.values(e))
data.unshift(head)
let filename = "表格名字.xlsx";
let ws_name = "SheetJS";
let wb = XLSX.utils.book_new();
let ws = XLSX.utils.aoa_to_sheet(data);
XLSX.utils.book_append_sheet(wb, ws, ws_name);
XLSX.writeFile(wb, filename);
}
参考文档:cloud.tencent.com/developer/a…
19.Echarts折线图配置项
chartsOption: {
tooltip: {
trigger: "axis",
backgroundColor: "rgba(22,42,209,1)",
borderColor: "#28a6d8",
textStyle: {
color: "#fff",
align: "left"
},
formatter: params => {
let { value, axisValue } = params[0];
let html = `<span>数值:${value.toFixed(2)}</span><br/>
<span>时间:${axisValue}</span>`;
return html;
}
},
grid: {
top: 10,
left: 50,
right: 40,
bottom: 10,
containLabel: true
},
xAxis: {
type: "category",
boundaryGap: false,
data: [],
//x轴
axisLine: {
show: true,
lineStyle: {
color: "#3d5bff"
}
},
//x轴上刻度文字
axisLabel: {
textStyle: {
color: "#8ea0ff",
fontSize: 16
},
//显示间隔
interval: (index, value) => {
return this.intervals[index].count;
},
formatter: function(value, index) {
return value.split(" ")[0];
}
//rotate: 30
}
},
yAxis: {
type: "value",
//y轴
axisLine: {
show: true,
lineStyle: {
color: "#3d5bff"
}
},
//y轴上刻度文字
axisLabel: {
textStyle: {
color: "#8ea0ff",
fontSize: 16
}
},
//横向网格线(诶嘿,想不到吧,横向网格线样式的设置居然是在yAxis中呢O(∩_∩)O)
splitLine: {
lineStyle: {
color: ["#0a2395"]
}
}
},
series: [
{
type: "line",
smooth: true,
//折线图拐点使用自定义图标
symbol: () => {
let circleIcon = require("@/assets/images/peiqi.png");
return `image://${circleIcon}`;
},
symbolSize: 20, //折线图拐点大小
itemStyle: {
normal: {
lineStyle: {
width: 2,
type: "dashed"
}
}
},
data: []
}
],
color: [], //折线颜色
//缩放及滚动条
dataZoom: [
{
type: "inside",
xAxisIndex: [0, 1],
start: 0,
end: 100
},
{
show: false,
xAxisIndex: [0, 1],
type: "slider",
top: "75%",
start: 0,
end: 100
}
]
}
20.element固定列+固定高度后,滚动到底部错位
项目中自定义了滚动条样式,设置的宽高不一样。
解决方法:将宽高设置成一样
::-webkit-scrollbar{
width: 13px;
height: 13px;
background-color: #01064b;
}
参考文档:blog.csdn.net/a1983029606…
21.Git不识别文件大小写
git默认配置为忽略大小写,因此无法正确检测大小写的更改
解决方法:运行git config core.ignorecase false,关闭git忽略大小写配置,即可检测到大小写名称更改
22.闪烁动画
.warning {
background: url("~@/assets/images/home/map_marker_warning.png");
position: relative;
&::before {
background: inherit;
content: "";
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: -2;
animation: twinkling 0.3s ease-in-out infinite; //使用闪烁动画
}
}
//定义闪烁动画
@keyframes twinkling {
0% {
opacity: 0.2;
filter: alpha(opacity=20);
transform: scale(1);
}
50% {
opacity: 1;
filter: alpha(opacity=100);
transform: scale(1.12);
}
100% {
opacity: 0.2;
filter: alpha(opacity=20);
transform: scale(1);
}
}
23.el-table篇
1.el-table表格固定列之后下方边缘出现白线
解决方案:
.el-table__fixed-right::before, .el-table__fixed::before {
background-color: transparent;
}
参考文档:blog.csdn.net/DDD4V/artic…
2.el-table表格XY方向都滚动时右下角出现的白色小方块
::-webkit-scrollbar-corner{
background: transparent;
}
3.el-table鼠标悬停时高亮背景颜色的修改,添加fixed后固定列高亮颜色不生效
.el-table__body .el-table__row.hover-row td{
background-color: #00b8ff !important;
}
参考文档:blog.csdn.net/zeng092210/…
24.对document.getElementsByClassName使用forEach报错
获取的元素与报错内容:
报错原因分析:document.getElementsByClassName获取到的内容不是严格意义上的数组,而是一个HTMLColletion集合,并且是只读的
解决方案:使用Array.prototype.forEach.call(els,el=>{})代替els.forEach
25.截取页面内容并下载为图片
安装依赖:npm install html2canvas
let wrapper = this.$refs.domWrapper;
html2canvas(wrapper,{这里可以写很多配置项,可以缺省}).then(canvas => {
let dataURL = canvas.toDataURL("image/png");
if (dataURL !== "") {
let blob = this.dataURLToBlob(canvas.toDataURL("image/png"));
let a = document.createElement("a");
a.style.display = "none";
a.setAttribute("href", URL.createObjectURL(blob));
a.setAttribute("download", this.dlgInfo.com + ".png");
document.body.appendChild(a);
a.click();
URL.revokeObjectURL(blob);
document.body.removeChild(a);
}
});
25.截取页面内容并下载为PDF
前置工作:
1.npm i html2canvas
2.npm i jspdf
代码:
import html2canvas from "html2canvas";
import JsPDF from 'jspdf';
方法:
getPdf(title, html) {
html2canvas(html, {
allowTaint: false,
taintTest: false,
logging: false,
useCORS: true,
dpi: window.devicePixelRatio * 4, // 将分辨率提高到特定的DPI 提高四倍
scale: 4, // 按比例增加分辨率
}).then(canvas => {
var pdf = new JsPDF('p', 'mm', 'a4'); // A4纸,纵向
var ctx = canvas.getContext('2d');
var a4w = 190; var a4h = 277; // A4大小,210mm x 297mm,四边各保留10mm的边距,显示区域190x277
var imgHeight = Math.floor(a4h * canvas.width / a4w); // 按A4显示比例换算一页图像的像素高度
var renderedHeight = 0;
while (renderedHeight < canvas.height) {
var page = document.createElement("canvas");
page.width = canvas.width;
page.height = Math.min(imgHeight, canvas.height - renderedHeight);// 可能内容不足一页
// 用getImageData剪裁指定区域,并画到前面创建的canvas对象中
page.getContext('2d').putImageData(ctx.getImageData(0, renderedHeight, canvas.width, Math.min(imgHeight, canvas.height - renderedHeight)), 0, 0);
pdf.addImage(page.toDataURL('image/jpeg', 1.0), 'JPEG', 10, 10, a4w, Math.min(a4h, a4w * page.height / page.width)); // 添加图像到页面,保留10mm边距
renderedHeight += imgHeight;
if (renderedHeight < canvas.height) {
pdf.addPage();// 如果后面还有内容,添加一个空页
}
}
// 保存文件
pdf.save(title + '.pdf');
});
}
调用:
getPdf('我的PDF文件', this.$refs.pdfContainer);