前端面试套餐
css:如何实现两栏布局,右侧自适应?三栏布局中间自适应呢?
在日常布局中,无论是两栏布局还是三栏布局,使用的频率都非常高
两栏布局
两栏布局实现效果就是讲页面分割成左右宽度不等的两列,宽度较小的列设置iwei固定宽度,剩余宽度由另一列撑满(列较小的为次要布局容器,宽度较大的为主要布局)
BFC+float
- 使用float左浮左边栏
- 右边模块使用margin-left撑出内容块做内容展示
- 为父级元素添加BFC,防止下方元素飞到上方内容
<style>
.box{
overflow: hidden; 添加BFC
}
.left {
float: left;
width: 200px;
background-color: gray;
height: 400px;
}
.right {
margin-left: 210px;
background-color: lightgray;
height: 200px;
}
</style>
<div class="box">
<div class="left">左边</div>
<div class="right">右边</div>
</div>
flex弹性布局
<!--
* @Author: 41
* @Date: 2021-12-07 09:37:47
* @LastEditors: 41
* @LastEditTime: 2021-12-07 09:40:35
* @Description:
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box{
display: flex;
/* align-items: flex-start */
}
.left{
width: 200px;
height: 500px;
background-color: gray;
}
.right{
flex: 1;
margin-left: 10px;
background-color: black;
}
</style>
</head>
<body>
<div class="box">
<div class="left">左边</div>
<div class="right">右边</div>
</div>
</body>
</html>
flex可以说是最好的方案了,代码少,使用简单
注意的是,flex容器的一个默认属性值:align-items: stretch;
这个属性导致了列等高的效果。为了让两个盒子高度自动,需要设置: align-items: flex-start;
注意,这里的 flex:1;=== flex-grow:1;flex-shrink:1;flex-basis:0%
三栏布局
三栏布局按照左中右的顺序进行排序,通常中间列最宽,左右两列次之
实现三栏布局中间自适应的布局方式有:
- 两边使用float,中间使用margin
- 两边使用absolute,中间使用margin
- 两边使用float和负margin
- display:table实现
- flex实现
- grid网格布局
两边使用float,中间使用margin
- 两边固定宽度,中间宽度自适应
- 利用中间元素的margin值控制两边的间距
- 宽度小于左右部分宽度之和时,右侧部分会被挤下去
<!--
* @Author: 41
* @Date: 2021-12-07 09:57:56
* @LastEditors: 41
* @LastEditTime: 2021-12-07 10:14:10
* @Description:
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.wrap {
background: #eee;
overflow: hidden;
padding: 20px;
height: 200px;
}
.left {
width: 200px;
height: 200px;
float: left;
background: coral;
}
.right {
width: 120px;
height: 200px;
float: right;
background: lightblue;
}
.middle {
margin-left: 220px;
height: 200px;
background: lightpink;
margin-right: 140px;
}
</style>
</head>
<body>
<div class="wrap">
<div class="left">左侧</div>
<div class="right">右侧</div>
<div class="middle">中间</div>
</div>
</body>
</html>
缺陷:
- 主题内容最后加载
- 右边在主题内容之前,如果是响应式设计,不能简单的换行展示
两边使用absolute,中间使用margin
基于绝对定位的三栏布局:注意绝对定位的元素脱离文档流,相对于最近的已经定位的祖先元素进行定位。无需考虑html中结构的顺序。
- 左右两边使用绝对定位,固定在两侧
- 中间占满一行,但通过margin和左右两边留出10px的间隔
<!--
* @Author: 41
* @Date: 2021-12-07 10:33:42
* @LastEditors: 41
* @LastEditTime: 2021-12-07 10:43:28
* @Description:
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
position: relative;
}
.left,
.right,
.main {
height: 200px;
line-height: 200px;
text-align: center;
}
.left {
position: absolute;
top: 0;
left: 0;
width: 100px;
background: green;
}
.right {
position: absolute;
top: 0;
right: 0;
width: 100px;
background: green;
}
.main {
margin: 0 110px;
background: black;
color: white;
}
</style>
</head>
<body>
<div class="container">
<div class="left">左边固定宽度</div>
<div class="right">右边固定宽度</div>
<div class="main">中间自适应</div>
</div>
</body>
</html>
两边使用float和负margin
实现过程:
- 中间使用双层标签,外层浮动,以便左中右能在同一行展示
- 左边通过使用负margin-left:-100%,相当于中间的宽度,所以向上偏移到左侧
- 右边通过使用负margin-left:-100px,相当于自身宽度,所以向上偏移到最右侧
缺点:
- 增加了.main-wrapper一层,结构变复杂
- 使用负margin,调试相对麻烦
<!--
* @Author: 41
* @Date: 2021-12-07 10:51:28
* @LastEditors: 41
* @LastEditTime: 2021-12-07 10:58:40
* @Description:
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.left,
.right,
.main {
height: 200px;
line-height: 200px;
text-align: center;
}
.main-wrapper {
float: left;
width: 100%;
}
.main {
margin: 0 110px;
background: black;
color: white;
}
.left,
.right {
float: left;
width: 100px;
margin-left: -100%;
background: green;
}
.right {
margin-left: -100px; /* 同自身宽度 */
}
</style>
</head>
<body>
<div class="main-wrapper">
<div class="main">中间自适应</div>
</div>
<div class="left">左边固定宽度</div>
<div class="right">右边固定宽度</div>
</body>
</html>
display:table实现
<table>
标签用于展示行列数据,不适合用于布局。但是可以使用
display:table
来实现布局的效果
实现原理:
- 外层通过display:table设置为表格,设置
table-layout:fixed
表示列宽自身宽度决定,而不是自动计算 - 内层的左中右通过display:table-cell设置为表格单元
- 左右设置固定宽度,中间设置width:100% 填充剩下的宽度
<!--
* @Author: 41
* @Date: 2021-12-07 11:02:36
* @LastEditors: 41
* @LastEditTime: 2021-12-07 11:07:24
* @Description:
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
height: 200px;
line-height: 200px;
text-align: center;
display: table;
table-layout: fixed;
width: 100%;
}
.left,
.right,
.main {
display: table-cell;
}
.left,
.right {
width: 100px;
background: green;
}
.main {
background: black;
color: white;
width: 100%;
}
</style>
</head>
<body>
<div class="container">
<div class="left">左边固定宽度</div>
<div class="main">中间自适应</div>
<div class="right">右边固定宽度</div>
</div>
</body>
</html>
flex实现
实现过程:
- 容器设置为display:flex;
- 盒内元素两端对齐,将中间元素设置为100%宽度,或者设为flex:1,即可填充空白
- 盒内元素的高度撑开容器的高度
优点:
- 结构简单直观
- 可以结果flex的其他功能实现更多效果,例如使用order属性调整显示顺序,让主题内容优先加载,但展示在中间
<!--
* @Author: 41
* @Date: 2021-12-07 11:24:58
* @LastEditors: 41
* @LastEditTime: 2021-12-07 11:38:11
* @Description:
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.wrap {
display: flex;
justify-content: space-between;
}
.left,
.right,
.middle {
height: 100px;
}
.left {
width: 200px;
background: coral;
}
.right {
width: 120px;
background: lightblue;
}
.middle {
background: #555;
width: 100%;
margin: 0 20px;
}
</style>
</head>
<body>
<div class="wrap">
<div class="left">左侧</div>
<div class="middle">中间</div>
<div class="right">右侧</div>
</div>
</body>
</html>
grid网格布局
和flex布局类似
<!--
* @Author: 41
* @Date: 2021-12-07 11:40:48
* @LastEditors: 41
* @LastEditTime: 2021-12-07 11:42:01
* @Description:
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.wrap {
display: grid;
width: 100%;
grid-template-columns: 100px auto 100px;
}
.left,
.right,
.middle {
height: 100px;
}
.left {
background: coral;
}
.right {
background: lightblue;
}
.middle {
margin: 0 20px;
background: #555;
}
</style>
</head>
<body>
<div class="wrap">
<div class="left">左侧</div>
<div class="middle">中间</div>
<div class="right">右侧</div>
</div>
</body>
</html>
js:说说你对Javascript中this对象的理解
函数的this
关键字在JavaScript中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别
在绝大多数情况下,函数的调用方式决定了this
的值(运行时绑定)
this
关键字是函数运行时自动生成的一个内部对象,只能在函数内部使用,总指向调用它的对象
改变this指针
apply(),call(),bind()是函数的一个方法,作用是改变函数的调用对象。它的第一个参数就表示改变后的调用这个函数的对象。因此,这时this指的是第一个参数。
这个在后面的博客会细说
箭头函数
在 ES6 的语法中还提供了箭头函语法,让我们在代码书写时就能确定 this 的指向(编译时绑定)
- 绑定事件监听要小心
const button = document.getElementById('mngb');
button.addEventListener('click', ()=> {
console.log(this === window) // true
this.innerHTML = 'clicked button'
})
上述可以看到,我们其实是想要this为点击的button,但此时this指向了window
- 原型上添加方法,this指针指向
window
Cat.prototype.sayName = () => {
console.log(this === window) //true
return this.name
}
const cat = new Cat('mm');
cat.sayName()
我们应该避免上面的情况,同样的,箭头函数不能作为构造函数
优先级
这里不细说了
new绑定优先级 > 显示绑定优先级 > 隐式绑定优先级 > 默认绑定优先级
ES6:你是怎么理解ES6中的Decorator的?使用场景?
Decorator,即装饰器,从名字上很容易让我们联想到装饰着模式
简单来讲,装饰着模式就是一种不再改变原类和使用继承的情况下,动态地扩展对象功能地设计理论。
ES6中Decorator功能意识如此,其本质也不是什么高大上的结构,就是一个普通的函数,用于扩展类属性和类方法
- 这里定义一个士兵,这时候它什么装备都没有
class soldier{
}
- 定义一个得到AK装备的函数,即装饰器
function strong(target){
target.AK = true
}
- 使用该装饰器对士兵进行增强
@strong
class soldier{
}
- 这时候士兵就有武器了
soldier.AK // true
上述代码虽然简单,但也能够清晰看到使用了Decorator两大优点:
- 代码可读性变强了,装饰器命名相当于一个注释
- 在不改变原有代码情况下,对原来功能进行扩展
用法
- 类的装饰
当对类本身进行装饰的时候,能够接受一个参数,即类本身
将装饰器行为进行分解如下
@decorator
class A {}
// 等同于
class A {}
A = decorator(A) || A;
下面@testable就是一个装饰器,target就是传入的类,即MyTestableClass,实现了为类添加静态属性
@testable
class MyTestableClass {
// ...
}
function testable(target) {
target.isTestable = true;
}
MyTestableClass.isTestable // true
如果想要传递参数,可以在装饰器外层再封装一层函数
function testable(isTestable) {
return function(target) {
target.isTestable = isTestable;
}
}
@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true
@testable(false)
class MyClass {}
MyClass.isTestable // false
- 类属性的装饰
当对类属性进行装饰的时候,能够接受三个参数: - 类的原型对象
- 需要装饰的属性名
- 装饰属性名的描述对象
- 首先定义一个
readonly
装饰器
function readonly(target, name, descriptor){
descriptor.writable = false; // 将可写属性设为false
return descriptor;
}
- 使用
readonly
装饰类的name
方法
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}
- 相当于以下调用
readonly(Person.prototype, 'name', descriptor);
如果一个方法有多个装饰器,就像洋葱一样,线从外到内进入,再由内到外执行
function dec(id){
console.log('evaluated', id);
return (target, property, descriptor) =>console.log('executed', id);
}
class Example {
@dec(1)
@dec(2)
method(){}
}
// evaluated 1
// evaluated 2
// executed 2
// executed 1
外层装饰器@dec(1)
线进入,但是内层装饰器@dec(2)
先执行
使用场景
- 使用react-redux的时候
class MyReactComponent extends React.Component {}
export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);
@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
- mixins写成装饰器
function mixins(...list) {
return function (target) {
Object.assign(target.prototype, ...list);
};
}
// 使用
const Foo = {
foo() { console.log('foo') }
};
@mixins(Foo)
class MyClass {}
let obj = new MyClass();
obj.foo() // "foo"
vue:为什么data属性是一个函数而不是一个对象?
- 根实例对象data可以是对象也可以是函数(根实例是单例),不会产生数据污染情况
- 组件实例对象data必须为函数,目的是为了防止多个组件实例对象之间共用一个data,产生数据污染。采用函数的形式,initData时会将其作为工厂函数都会返回全新data对象