公共知识点
前端面试和工作中遇到的常见问题
React和Vue 异同
vue:双向绑定,不完全的MVVM(因为vue能$ref操作dom)
react:单项绑定(一般用hooks),MVVM中的第二个V(View环节)
for 和 for in 和 for of 区别
- for in遍历对象,返回的是对象的key;遍历数组/字符串(字符串也可以当成数组)返回的是数组的下标
- for of 只能遍历的是数组、遍历数组对象,返回单个对象;遍历数组元素/字符串,返回单个元素
for of不能遍历对象
ES6提出的语句,在可迭代对象(Array(数组),Map(字典),Set(集合),String(字符串),
TypedArray(一组构造函数),arguments(类似数组的全局对象)) - 速度对比:
for 循环在遍历值为 let 时快于 while 快于 forEach
for in 循环速度是最慢的
for of 比 for in快点但是没有for循环快 - 结论
for 循环常用且效率会高一些
for in 用来循环对象,因为循环出来的是对象的key,用key直接操作对象
for of 用来循环数组,循环出来的是value,元素值。不能循环对象
各有各的用处
数组及对象 值处理(对比,排序)
- 排序:
const sortedColumnData = columnData.sort((a, b) => b - a);
a-b就是升序,b-a就是降序
JavaScript的Array.sort()方法使用的是快速排序(Quick Sort)算法,它的平均时间复杂度是 O(n log n)。快速排序是一种高效的排序算法,通过分治的思想将数组分解为较小的子数组,然后对子数组进行排序并合并,以达到整体排序的目的。
然而,需要注意的是,Array.sort()方法的具体实现可能因浏览器或JavaScript引擎的不同而有所差异。在某些情况下,它可能会使用其他排序算法,如归并排序(Merge Sort)或插入排序(Insertion Sort),以优化特定情况下的性能。
- 判断:
(一个数组对象里面的某一个对象是否有包含某一个值)
const containsString = [{name:1,value:1},{name:2,value:2},{name:3,value:3}].some(obj =>
Object.values(obj).some(
value => typeof value === "string" && value.includes(1)
)
);
//返回的是true或者false
前端工程化(webpack)
WebPack可以看做是模块打包机:它做的事情是,分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其转换和打包为合适的格式供浏览器使用。
-
模块化开发:Webpack 支持使用模块化的开发方式,可以将代码拆分成多个模块,提高代码的复用性和维护性。
-
资源打包和优化:Webpack 可以将项目中的各种资源进行打包和优化,例如将多个 JavaScript 文件合并成一个文件,将 CSS 进行提取和压缩,处理图片和字体等。
-
代码转换和编译:Webpack 支持使用不同的 loader 对不同类型的文件进行处理,例如将 ES6/ES7 代码转换为 ES5,将 SCSS 转换为 CSS,对 TypeScript 进行编译等。
-
开发环境优化:Webpack 提供了开发服务器(DevServer)和热模块替换(Hot Module Replacement)等功能,可以实现实时预览、自动刷新和模块热更新,提高开发效率。
-
构建和部署:Webpack 可以通过配置多个不同的构建环境(如开发环境、生产环境),将项目打包成可部署的静态资源,减小文件体积,优化加载速度
闭包
原型,原型链,作用域
new运算符
Promise Async/Await
nextTick/setTimeOut
有两种方法,一种是JavaScript的setTimeOut方法,一种是this.$nextTick(function(){})
方法。
两种的区别是setTimeOut
可以设置时间后再进行渲染,this.$nextTick(function(){})
可以在vue组件自动渲染后调用。
setTimeOut
//在3000毫秒后跳出弹窗
setTimeout("alert('123123123213')", 3000 )
this.$nextTick(function(){})
//在页面dom渲染完成后弹出弹窗
this.$nextTick(function () {
this.$refs.message.success('渲染完成')
})
插槽
最常见的el-table插槽
<el-table-column
fixed="left"
prop="date"
label="产业分类"
align="center"
width="120"
>
<template slot-scope="scope">
<div>
<img src="../../assets/images/tableColList1.png" alt="" />
<span>{{ scope.row.province }}</span>
</div>
</template>
</el-table-column>
服务端/客户端渲染
React/Vue视图刷新问题
eventBus
直接上代码 粘就完事了
- utils工具类 命名bus.js 最好放在components或者utils目录下
import Vue from "vue";
const bus = new Vue();
export default bus;
- 加入到mian方法中(我用的是vue2)
import Bus from "./utils/bus";
Vue.prototype.$bus = Bus;
- 使用方法
//发消息
let _this = this;
_this.$bus.$emit("areaChangs", [参数1, 数据2]);
//收消息
let _this = this;
this.$bus.$on("areaChangs", function(data) {
//这个是匿名函数哦,不饿能直接用this
_this.data= data;
});
大屏适配解决方案
1. rem开发
方案1:整体适配
使用px2rem,自动实现px对rem的转换
npm install px2rem-loader --save-dev
在vue2下新增一个配置文件postcss.config.js
const autoprefixer = require("autoprefixer");
const pxtorem = require("postcss-pxtorem");
module.exports = () => ({
plugins: [
autoprefixer(),
pxtorem({
rootValue: 192.0,
propList: ["*"],
mediaQuery: false,
unitPrecision: 3
})
// // autoprefixer 自动补齐 CSS3 前缀,适配不同浏览器
// require('autoprefixer')({
// overrideBrowserslist: [
// "last 10 versions", // 所有主流浏览器最近10版本用
// ],
// }),
// require('postcss-pxtorem')({
// rootValue: 192.0, //设计稿元素尺寸/10,这里设计稿宽度为1920
// propList: ["*"], //是一个存储哪些将被转换的属性列表,这里设置为['*']全部,假设需要仅对边框进行设置,可以写['*', '!border*']
// unitPrecision: 3, //保留rem小数点多少位
// selectorBlackList: ['el-input', 'el-step', 'no-'],//则是一个对css选择器进行过滤的数组,比如你设置为['el-'],那所有el-类名里面有关px的样式将不被转换,这里也支持正则写法。
// replace: true,
// mediaQuery: false, //媒体查询( @media screen 之类的)中不生效
// // minPixelValue: 3, //px小于3的不会被转换
// })
]
});
方案2:单页适配(门户首页,单个大屏)
//首先设置单页的fontsize大小,根据1920适配
document.documentElement.style.fontSize = document.documentElement.clientWidth / 1920 + 'px';
//然后把css文件中相关与px的内容全部改为rem就可以了
//这个方法可以解决背景图会自动拉伸的情况可以写算法动态写死背景图的宽高
2. 强制分辨率缩放(Bom始终保持一个分辨率,使用控制transform)
控制浏览器的显示,一直保持着1k,2k,4k的屏幕大小,问题是对于每个不同的分辨率都需要开发一套样式文件
控制屏幕的缩放比,当bom层面的分辨率发生变化transform:scale
也跟着变化
//vue2.x
mounted() {
let _this = this;
_this.setRem();
window.onresize = function() {
_this.setRem();
};
},
methods: {
setRem() {
// if (!window.frameElement) {
// 当前页面屏幕分辨率相对于 1920宽的缩放比例,可根据自己需要修改
let w = document.documentElement.clientWidth,
h = document.documentElement.clientHeight;
const scale = w / h > 1920 / 1080 ? h / 1080 : w / 1920;
document.querySelector("#mapbox").style.transform = `scale(${scale})`; 控制屏幕的缩放比
document.querySelector("#mapbox").style[
"transform-origin"
] = `center center`;
// } else {
// $("#app").addClass("iframBox");
// }
},
}
//注意 上面代码是只控制倒了1k的分辨率下,如果需要适配其他的分辨率就需要判断其他的宽度
let w = document.documentElement.clientWidth,
h = document.documentElement.clientHeight,
if (nameList.includes(name) && w > 6000) {
scale = w / h > 6880 / 2000 ? h / 2000 : w / 6880;
} else if (nameList.includes(name) && w > 3800) {
scale = w / h > 3840 / 1290 ? h / 1290 : w / 3840;
} else {
scale = w / h > 1920 / 1080 ? h / 1080 : w / 1920;
}
//整个页面需要限制宽和高
width: 1920px;
height: 1080px;
3. 百分比布局
用的很少,平时只是控制单页的适配问题
动画使用和基本配置
动画
.bodersLine {
animation-name: likes; // 动画名称
animation-duration: 1.5s; // 动画完成时间
animation-timing-function: linear; // 动画执行方式,linear:匀速;ease:先慢再快后慢;ease-in:由慢速开始;ease-out:由慢速结束;ease-in-out:由慢速开始和结束;
animation-delay: 0s; // 动画延迟时间
animation-iteration-count: infinite; // 动画播放次数,infinite:一直播放
// animation-direction: alternate; // 动画在奇数次(1、3、5...)正向播放,在偶数次(2、4、6...)反向播放。
}
@keyframes likes {
0% {
transform: translateY(0px)
}
25% {
transform: translateY(5px)
}
50% {
transform: translateY(10px)
}
75% {
transform:translateY(15px)
}
100% {
transform: translateY(0px)
}
}
项目开发公用样式及功能
1滚动条样式修改
/**设置关于el-table的滚动条*/
//滚动条长宽
::v-deep .el-table__body-wrapper::-webkit-scrollbar {
width: 3px;
height: 3px;
}
//滚动条样式
::v-deep .el-table__body-wrapper::-webkit-scrollbar-thumb {
border-radius: 0px;
background-color: rgba(0, 138, 255, 1);
}
//滚动条悬浮
::v-deep .el-table__body-wrapper::-webkit-scrollbar-thumb:hover {
background-color: rgba(0, 138, 255, 1);
}
//滚动条背景
::v-deep .el-table__body-wrapper::-webkit-scrollbar-track {
background-color: rgba(77, 178, 255, 0.38);
border-radius: 0px;
}
//滚动条交合处
::v-deep .el-table__body-wrapper::-webkit-scrollbar-corner {
// display: none;
background-color: rgba(77, 178, 255, 0.38);
}
2. el-table样式整体修改,
- 去掉自有的边框,合并单元格
//html代码
<div
class="city-content"
v-loading="loading"
element-loading-background="rgba(24, 41, 88, 0)"
>
<el-table :data="tableData" style="width: 98%" max-height="250">
<el-table-column
prop="date"
label="日期"
align="center"
width="120"
>
</el-table-column>
<el-table-column label="配送信息" align="center">
<el-table-column
prop="name"
label="姓名"
width="190"
align="center"
>
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="190"
align="center"
>
</el-table-column>
</el-table-column>
<el-table-column label="配送信息" align="center">
<el-table-column
prop="name"
label="姓名"
width="190"
align="center"
>
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="190"
align="center"
>
</el-table-column>
</el-table-column>
<el-table-column label="配送信息" align="center">
<el-table-column
prop="name"
label="姓名"
width="190"
align="center"
>
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="190"
align="center"
>
</el-table-column>
</el-table-column>
<el-table-column label="配送信息" align="center">
<el-table-column
prop="name"
label="姓名"
width="190"
align="center"
>
</el-table-column>
<el-table-column
prop="name"
label="姓名"
width="190"
align="center"
>
</el-table-column>
</el-table-column>
</el-table>
</div>
//css样式
.city-content {
::v-deep .el-table th,
::v-deep .el-table tr,
::v-deep .el-table td {
background-color: transparent !important;
border: 0; //去除表格
}
/*去除底边框*/
::v-deep.el-table td.el-table__cell {
border: 0;
}
/* 表格内背景颜色 */
::v-deep .el-table thead {
background: rgba(11, 87, 252, 0.38);
box-shadow: inset 0 0 20px rgba(11, 87, 252, 1);
}
::v-deep.el-table th.el-table__cell.is-leaf {
border: 0;
}
::v-deep .el-table--border th.gutter:last-of-type {
border-bottom-width: 0px;
}
::v-deep .no-border.el-table__header-wrapper {
border: 0;
}
::v-deep .no-border.el-table__body-wrapper {
border: 0;
}
::v-deep .el-table::before {
background: none;
}
::v-deep .el-table::after {
background: none;
}
::v-deep .el-table--border,
.el-table--group {
border: 0;
}
// ::v-deep td,
// th {
// border: 1px solid rgba(141, 149, 165, 0.4);
// }
::v-deep thead {
font-size: 16px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #ffffff;
tr:nth-child(1) {
th:nth-child(1) {
border-right: 1px solid rgba(141, 149, 165, 0.4);
}
}
tr:nth-child(1) {
th {
border-bottom: 1px solid rgba(141, 149, 165, 0.4);
border-right: 1px solid rgba(141, 149, 165, 0.4);
}
th:nth-child(1) {
border-bottom: 0;
}
}
tr:nth-child(2) {
th:nth-child(2n) {
border-right: 1px solid rgba(141, 149, 165, 0.4);
}
}
tr {
th {
border-right: 0;
}
}
}
::v-deep .el-table__row {
font-size: 16px;
font-family: Microsoft YaHei;
font-weight: 400;
color: #ffffff;
td {
border-top: 0;
border-bottom: 0;
}
td:nth-child(2n + 1) {
border-right: 1px solid rgba(141, 149, 165, 0.4);
}
// td:last-of-type {
// border-right: 0;
// }
}
}
页面元素全屏组件vue-fullscreen
- npm install vue-fullscreen
- main.js引入
import VueFullscreen from ‘vue-fullscreen’
Vue.use(VueFullscreen) - 使用
//html
<template>
<fullscreen
:page-only="true"
v-model="fullscreen"
:exit-on-click-wrapper="false"
fullscreen-class="big-view bg-white"
>
<div>放大的内容</div>
<el-button @click="toggle"
>{{ fullscreen ? "退出" : "进入" }}全屏</el-button
>
</fullscreen>
</template>
//js
export default {
data() {
return {
fullscreen: false,
BomHeights :350,//因为需要设置el-table的最大高度
}
},
methods: {
toggle() {
this.fullscreen = !this.fullscreen;
this.BomHeights = this.fullscreen ? window.innerHeight - 50 : 350;
},
},
}
//css
.big-view {
z-index: 999;
}
监听页面窗口大小变化
监听并给元素设置宽度
window.onresize = function() {
_this.BomHeights = _this.fullscreen ? window.innerHeight - 50 : 350;
};
npm操作
npm 安装插件:npm install xxxx;
npm安装插件并写入package.json的"dependencies"中:npm install xxx --save
npm全局安装插件:npm install -g xxxx ;
npm删除插件 :
npm删除插件:npm uninstall xxx(同时删除package.json的"dependencies"的记录)
npm全局删除插件:npm uninstall -g xxxx
el组件遇到的问题
- 获取el-select选中的label值
//也是用$ref,需要注意的是双向绑定问题,注意视图第一次刷新是没有的
this.$refs.cylflSelect.selected.label
- 获取el-cascader选中的label值
//使用 $ref
let arr = this.$refs["cascaderHandle"].getCheckedNodes()[0].pathLabels;
this.CitysName = arr.toString();
文件流下载
import axios from "axios";
axios({
url: `接口?token=${getToken()}`,
method: "POST",
responseType: "blob" // 设置响应类型为二进制流
}).then(response => {
const url = window.URL.createObjectURL(new Blob([response.data]));
const link = document.createElement("a");
link.href = url;
link.setAttribute("download", "文件名.csv"); // 设置下载文件名
document.body.appendChild(link);
link.click();
});
doc文件下载并预览
//第二种方案,实现较为简单,但只支持.docx .xlsx .pptx 格式的文件预览
const pptxFile = '***/file.pptx';//必须是域名
const viewerUrl = `https://view.officeapps.live.com/op/view.aspxsrc=${encodeURIComponent(pptxFile)}`;
window.open(viewerUrl, '_blank');