常见前端面试题答案汇总
1.css的居中方式
1.1 内联元素水平居中
利用 text-align: center 可以实现在块级元素内部的内联元素水平居中.此方法对内联元素(inline), 内联块(inline-block), 内联表(inline-table), inline-flex元素水平居中都有效.
代码如下:
center-text{
Text-aling:center;
}
1.2 块级元素水平居中
通过把固定宽度块级元素的margin-left和margin-right设成auto,就可以使块级元素水平居中.
核心代码:
center-block{
margin: 0 auto;
}
1.3 多块级元素水平居中
1.3.1 利用inline-block
如果一行中有两个或两个以上的块级元素,通过设置块级元素的显示类型为inline-block和父容器的text-align属性从而使多块级元素水平居中.
核心代码:
.container {
text-align: center;
}
.inline-block {
display: inline-block;
}
1.3.2 利用display: flex
利用弹性布局(flex),实现水平居中,其中justify-content 用于设置弹性盒子元素在主轴(横轴)方向上的对齐方式,本例中设置子元素水平居中显示.
核心代码:
flex-center {
display: flex;
justify-content: center;
}
2 垂直居中
2.1 单行内联(inline-)元素垂直居中
通过设置内联元素的高度(height)和行高(line-height)相等,从而使元素垂直居中.
核心代码:
#v-box {
height: 120px;
line-height: 120px;
}
2.2 多行元素垂直居中
2.2.1 利用表布局(table)
利用表布局的vertical-align: middle可以实现子元素的垂直居中.
核心代码:
.center-table {
display: table;
}
.v-cell {
display: table-cell;
vertical-align: middle;
}
2.2.2 利用flex布局(flex)
利用flex布局实现垂直居中,其中flex-direction: column定义主轴方向为纵向.因为flex布局是CSS3中定义,在较老的浏览器存在兼容性问题.
核心代码:
.center-flex {
display: flex;
flex-direction: column;
justify-content: center;
}
2.2.3 利用“精灵元素”
利用“精灵元素”(ghost element)技术实现垂直居中,即在父容器内放一个100%高度的伪元素,让文本和伪元素垂直对齐,从而达到垂直居中的目的。
核心代码:
.ghost-center {
position: relative;
}
.ghost-center::before {
content: " ";
display: inline-block;
height: 100%;
width: 1%;
vertical-align: middle;
}
.ghost-center p {
display: inline-block;
vertical-align: middle;
width: 20rem;
}
2.3 块级元素垂直居中
2.3.1 固定高度的块级元素
我们知道居中元素的高度和宽度,垂直居中问题就很简单.通过绝对定位元素距离顶部50%,并设置margin-top向上偏移元素高度的一半,就可以实现垂直居中了.
核心代码:
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
height: 100px;
margin-top: -50px;
}
2.3.2 未知高度的块级元素
当垂直居中的元素的高度和宽度未知时,我们可以借助CSS3中的transform属性向Y轴反向偏移50%的方法实现垂直居中.但是部分浏览器存在兼容性的问题.
核心代码:
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
transform: translateY(-50%);
}
3 水平垂直居中
3.1 固定宽高元素水平垂直居中
通过margin平移元素整体宽度的一半,使元素水平垂直居中.
核心代码:
.parent {
position: relative;
}
.child {
width: 300px;
height: 100px;
padding: 20px;
position: absolute;
top: 50%;
left: 50%;
margin: -70px 0 0 -170px;
}
3.2 未知宽高元素水平垂直居中
利用2D变换,在水平和垂直两个方向都向反向平移宽高的一半,从而使元素水平垂直居中.
核心代码:
.parent {
position: relative;
}
.child {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
3.3 利用flex布局
利用flex布局,其中justify-content 用于设置或检索弹性盒子元素在主轴(横轴)方向上的对齐方式;而align-items属性定义flex子项在flex容器的当前行的侧轴(纵轴)方向上的对齐方式.
核心代码:
.parent {
display: flex;
justify-content: center;
align-items: center;
}
3.4 利用grid布局
利用grid实现水平垂直居中,兼容性较差,不推荐.
核心代码:
.parent {
height: 140px;
display: grid;
}
.child {
margin: auto;
}
3.5 屏幕上水平垂直居中
屏幕上水平垂直居中十分常用,常规的登录及注册页面都需要用到,要保证较好的兼容性,还需要用到表布局.
核心代码:
.outer {
display: table;
position: absolute;
height: 100%;
width: 100%;
}
.middle {
display: table-cell;
vertical-align: middle;
}
.inner {
margin-left: auto;
margin-right: auto;
width: 400px;
}
2.px,em,rem,%
== 1.px(像素)
px单位的名称为像素,它是一个固定大小的单元,像素的计算是针对(电脑/手机)屏幕的,一个像素(1px)就是(电脑/手机)屏幕上的一个点,即屏幕分辨率的最小分割。由于它是固定大小的单位,单独用它来设计的网页,如果适应大屏幕(电脑),在小屏幕(手机)上就会很不友好,做不到自适应的效果。
2.em(相对长度单位)
em单位用的也比较多,特别是国外;em单位的名称为相对长度单位,它是用来设置文本的字体尺寸的,相对于父级元素对象内文本的字体尺寸;如果没有人为设置当前对象内文本的字体尺寸,那么它相对的是浏览器默认的字体尺寸(16px)。
3.rem(css3新增的相对长度单位)
rem是css3新增的一个相对长度单位,它的出现是为了解决em的缺点,em可以说是相对于父级元素的字体大小,当父级元素字体大小改变时,又得重新计算。rem出现就可以解决这样的问题,rem只相对于根目录,即HTML元素。所以只要在html标签上设置字体大小,文档中的字体大小都会以此为参照标准,一般用于自适应布局。
4.%(百分比)
%也很常见,它和em差不多一样,都是相对于父级元素。但%可以在很多属性中使用,比如:width、height、font-size等。而em是用来设置字体大小(font-size)的单位,width、height等属性是没有em单位的。
px、em、rem和%的区别与总结:
1.px是固定长度单位,不随其它元素的变化而变化;
2.em和%是相对于父级元素的单位,会随父级元素的属性(font-size或其它属性)变化而变化;
3.rem是相对于根目录(HTML元素)的,所有它会随HTML元素的属性(font-size)变化而变化;
4.px和%用的比较广泛一些,可以充当更多属性的单位,而em和rem是字体大小的单位,用于充当font-size属性的单位
5.一般来说:1em = 1rem = 100% = 16 px ==
3.display的值和作用
4.路由跳转的方式
1.router-link
1.不带参数
<router-link :to="{name:'home'}">
<router-link :to="{path:'/home'}">`
//name,path都行, 建议用name
// 注意:router-link中链接如果是’/‘开始就是从根路由开始,如果开始不带’/’,则从当前路由开始。
2.带参数
<router-link :to="{name:'home', params: {id:1}}">
// params传参数 (类似post)
// 路由配置 path: “/home/:id” 或者 path: “/home:id”
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
// html 取参
r
o
u
t
e
.
p
a
r
a
m
s
.
i
d
/
/
s
c
r
i
p
t
取
参
t
h
i
s
.
route.params.id // script 取参 this.
route.params.id//script取参this.route.params.id
<router-link :to="{name:'home', query: {id:1}}">
// query传参数 (类似get,url后面会显示参数)
// 路由可不配置
// html 取参
r
o
u
t
e
.
q
u
e
r
y
.
i
d
/
/
s
c
r
i
p
t
取
参
t
h
i
s
.
route.query.id // script 取参 this.
route.query.id//script取参this.route.query.id
2. this.
r
o
u
t
e
r
.
p
u
s
h
(
)
(
函
数
里
面
调
用
)
1.
不
带
参
数
t
h
i
s
.
router.push() (函数里面调用) 1.不带参数 this.
router.push()(函数里面调用)1.不带参数this.router.push(’/home’)
this.
r
o
u
t
e
r
.
p
u
s
h
(
n
a
m
e
:
′
h
o
m
e
′
)
t
h
i
s
.
router.push({name:'home'}) this.
router.push(name:′home′)this.router.push({path:’/home’})
2.query传参
this.
r
o
u
t
e
r
.
p
u
s
h
(
n
a
m
e
:
′
h
o
m
e
′
,
q
u
e
r
y
:
i
d
:
′
1
′
)
t
h
i
s
.
router.push({name:'home',query: {id:'1'}}) this.
router.push(name:′home′,query:id:′1′)this.router.push({path:’/home’,query: {id:‘1’}})
// html 取参
r
o
u
t
e
.
q
u
e
r
y
.
i
d
/
/
s
c
r
i
p
t
取
参
t
h
i
s
.
route.query.id // script 取参 this.
route.query.id//script取参this.route.query.id
3. params传参
this.$router.push({name:‘home’,params: {id:‘1’}}) // 只能用 name
// 路由配置 path: “/home/:id” 或者 path: “/home:id” ,
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
// html 取参
r
o
u
t
e
.
p
a
r
a
m
s
.
i
d
/
/
s
c
r
i
p
t
取
参
t
h
i
s
.
route.params.id // script 取参 this.
route.params.id//script取参this.route.params.id
4. query和params区别
query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传, 密码之类还是用params刷新页面id还在
params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失
3. this.
r
o
u
t
e
r
.
r
e
p
l
a
c
e
(
)
(
用
法
同
上
,
p
u
s
h
)
4.
t
h
i
s
.
router.replace() (用法同上,push) 4. this.
router.replace()(用法同上,push)4.this.router.go(n) ()
this.
r
o
u
t
e
r
.
g
o
(
n
)
向
前
或
者
向
后
跳
转
n
个
页
面
,
n
可
为
正
整
数
或
负
整
数
p
s
:
区
别
t
h
i
s
.
router.go(n) 向前或者向后跳转n个页面,n可为正整数或负整数 ps : 区别 this.
router.go(n)向前或者向后跳转n个页面,n可为正整数或负整数ps:区别this.router.push
跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面
this.
r
o
u
t
e
r
.
r
e
p
l
a
c
e
跳
转
到
指
定
u
r
l
路
径
,
但
是
h
i
s
t
o
r
y
栈
中
不
会
有
记
录
,
点
击
返
回
会
跳
转
到
上
上
个
页
面
(
就
是
直
接
替
换
了
当
前
页
面
)
t
h
i
s
.
router.replace 跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面) this.
router.replace跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面(就是直接替换了当前页面)this.router.go(n)
向前或者向后跳转n个页面,n可为正整数或负整数
5.vue生命周期的理解
6.数组去重
1.利用ES6 Set去重(ES6中最常用)
function unique (arr) {
return Array.from(new Set(arr))
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]
不考虑兼容性,这种去重的方法代码最少。这种方法还无法去掉“{}”空对象,后面的高阶方法会添加去掉重复“{}”的方法。
2.利用for嵌套for,然后splice去重(ES5中最常用)
function unique(arr){
for(var i=0; i<arr.length; i++){
for(var j=i+1; j<arr.length; j++){
if(arr[i]==arr[j]){ //第一个等同于第二个,splice方法删除第二个
arr.splice(j,1);
j--;
}
}
}
return arr;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", 15, false, undefined, NaN, NaN, "NaN", "a", {…}, {…}] //NaN和{}没有去重,两个null直接消失了
3.利用indexOf去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array .indexOf(arr[i]) === -1) {
array .push(arr[i])
}
}
return array;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
// [1, "true", true, 15, false, undefined, null, NaN, NaN, "NaN", 0, "a", {…},{…}] //NaN、{}没有去重
新建一个空的结果数组,for 循环原数组,判断结果数组是否存在当前元素,如果有相同的值则跳过,不相同则push进数组。(个人认为对于初学者来讲这是目前最易懂的方法)
4.利用sort()
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return;
}
arr = arr.sort()
var arrry= [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i-1]) {
arrry.push(arr[i]);
}
}
return arrry;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
// [0, 1, 15, "NaN", NaN, NaN, {…}, {…}, "a", false, null, true, "true", undefined] //NaN、{}没有去重
利用sort()排序方法,然后根据排序后的结果进行遍历及相邻元素比对。
5.利用对象的属性不能相同的特点进行去重
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var arrry= [];
var obj = {};
for (var i = 0; i < arr.length; i++) {
if (!obj[arr[i]]) {
arrry.push(arr[i])
obj[arr[i]] = 1
} else {
obj[arr[i]]++
}
}
return arrry;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", 15, false, undefined, null, NaN, 0, "a", {…}] //两个true直接去掉了,NaN和{}去重
6.利用includes
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array =[];
for(var i = 0; i < arr.length; i++) {
if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值
array.push(arr[i]);
}
}
return array
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}] //{}没有去重
7.利用hasOwnProperty
function unique(arr) {
var obj = {};
return arr.filter(function(item, index, arr){
return obj.hasOwnProperty(typeof item + item) ? false : (obj[typeof item + item] = true)
})
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}] //所有的都去重了
利用hasOwnProperty 判断是否存在对象属性
8.利用filter
function unique(arr) {
return arr.filter(function(item, index, arr) {
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
return arr.indexOf(item, 0) === index;
});
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, "NaN", 0, "a", {…}, {…}]
9.利用递归去重
function unique(arr) {
var array= arr;
var len = array.length;
array.sort(function(a,b){ //排序后更加方便去重
return a - b;
})
function loop(index){
if(index >= 1){
if(array[index] === array[index-1]){
array.splice(index,1);
}
loop(index - 1); //递归loop,然后数组去重
}
}
loop(len-1);
return array;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]
10.利用Map数据结构去重
function arrayNonRepeatfy(arr) {
let map = new Map();
let array = new Array(); // 数组用于返回结果
for (let i = 0; i < arr.length; i++) {
if(map .has(arr[i])) { // 如果有该key值
map .set(arr[i], true);
} else {
map .set(arr[i], false); // 如果没有该key值
array .push(arr[i]);
}
}
return array ;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "a", "true", true, 15, false, 1, {…}, null, NaN, NaN, "NaN", 0, "a", {…}, undefined]
创建一个空Map数据结构,遍历需要去重的数组,把数组的每一个元素作为key存到Map中。由于Map中不会出现相同的key值,所以最终得到的就是去重后的结果。
11.利用reduce+includes
function unique(arr){
return arr.reduce((prev,cur) => prev.includes(cur) ? prev : [...prev,cur],[]);
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr));
// [1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {…}, {…}]
12.[…new Set(arr)]
[...new Set(arr)] //代码就是这么少----(其实,严格来说并不算是一种,相对于第一种方法来说只是简化了代码)