前端面试套餐
css:说说flexbox(弹性盒布局模型)
Flexible Box
简称flex
,意为"弹性布局",可以简便,完整,响应式地实现各种页面布局
采用Flex布局的元素,称为flex
容器container
它的所有子元素自动成为容器成员,成为flex
项目item
属性
关于flex常用的属性,我们可以划分为容器属性和容器成员属性
容器属性
- flex-direction
决定主轴的方向(即项目的排列方向)
.container {
flex-direction: row | row-reverse | column | column-reverse;
}
- row(默认值):主轴水平方向,起点在左端
- row-reverse:主轴水平方向,起点在右端
- column:主轴垂直方向,起点在上沿
- column-reverse:主轴垂直方向,起点在下沿
- flex-wrap
弹性元素永远沿主轴排列,那么如果主轴排不下,通过flex-wrap
决定容器内项目是否可换行
.container {
flex-wrap: nowrap | wrap | wrap-reverse;
}
- nowrap(默认值):不换行
- wrap:换行,第一行在上方
- wrap-reverse:换行,第一行在下方
默认情况是不换行,但这里也不会任由元素直接溢出容器,会涉及到元素的弹性伸缩
- flex-flow
是flex-direction
属性和flex-wrap
属性的简写形式,默认值为row nowrap
- justify-content
定义了项目在主轴上的对齐方式
.box {
justify-content: flex-start | flex-end | center | space-between | space-around;
}
- flex-start(默认值):左对齐
- flex-end:右对齐
- center:居中
- space-between:两端对齐,项目之间的间隔都相等
- space-around:两个项目两侧间隔相等
- align-items
定义项目在交叉轴上如何对齐
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
- flex-start:交叉轴的起点对齐
- flex-end:交叉轴的终点对齐
- center:交叉轴的中点对齐
- baseline:项目的第一行文字的基线对齐
- stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度
- align-content
定义了多根轴线的对齐方式。如果项目只有一根轴线,该属性不起作用
.box {
align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}
- flex-start:与交叉轴的起点对齐
- flex-end:与交叉轴的终点对齐
- center:与交叉轴的中点对齐
- space-between:与交叉轴两端对齐,轴线之间的间隔平均分布
- space-around:每根轴线两侧的间隔都相等。所以,轴线之间的间隔比轴线与边框的间隔大一倍
- stretch(默认值):轴线占满整个交叉轴
成员属性
- order
定义项目的排列顺序。数值越小,排列越靠前,默认为0
- flex-grow
上面讲到当容器设为flex-wrap:nowrap;
不换行的时候,容器宽度有不够分的情况,弹性元素会根据flex-grow
来决定
定义项目的放大比例(容器宽度>元素总宽度 时如何伸展)
默认为0,即如果存在剩余空间,也不放大
如果所有项目的flex-grow属性为xn,那么这个item占比xn/xn的求和
- flex-shrink
定义了项目的缩小比例(容器宽度<元素总宽度时如何收缩,默认为1,即如果空间不足,该项目将缩小)
所有项目的flex-shrink
属性都为1,当空间不足时,都将等比例缩小
如果一个项目的flex-shrink
属性为0,其他项目都为1,则空间不足时,前者不缩小
- flex-basis
设置的是元素在主轴上的初始尺寸,所谓的初始尺寸就是元素在flex-grow
和flex-shrink
生效前的尺寸
浏览器根据这个属性,计算主轴是否有多余空间,默认值为auto,即项目的本来大小,如设置了width
则元素尺寸由width/height
决定(主轴方向),没有设置则由内容决定
- flex
flex属性是flex-grow, flex-shrink 和 flex-basis
的简写,默认值为0 1 auto,也是比较难懂的一个复合属性
- align-self
允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items
属性
默认值为auto
,表示继承父元素的align-items
属性,如果没有父元素,则等同于stretch
javascript:解释下什么是事件代理?应用场景?
事件代理,通俗来讲,就是把一个元素响应事件(click,keydown…)的函数委托到另一个元素
前面讲到,事件流都会经过三个阶段:捕获阶段->目标阶段->冒泡阶段,而事件委托就是在冒泡阶段完成
事件委托,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素
当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件上,然后再外层元素上去执行函数
应用场景
如果我们有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候响应一个事件
<ul id="list">
<li>item 1</li>
<li>item 2</li>
<li>item 3</li>
......
<li>item n</li>
</ul>
如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的
这时候就可以事件委托,把点击事件绑定在父级元素ul
上面,然后执行事件的时候再去匹配目标元素
// 给父层元素绑定事件
document.getElementById('list').addEventListener('click', function (e) {
// 兼容性处理
var event = e || window.event;
var target = event.target || event.srcElement;
// 判断是否匹配目标元素
if (target.nodeName.toLocaleLowerCase === 'li') {
console.log('the content is: ', target.innerHTML);
}
});
事件委托两大优点:
- 减少整个页面所需的内存,提升整体性能
- 动态绑定,减少重复工作
vue:给对象添加新属性界面不刷新?
直接添加属性的问题
我们从一个例子开始
定义一个p标签,通过v-for指令进行遍历
然后给button标签绑定点击事件,我们预期点击按钮时,数据新增一个属性,界面也新增一行
<p v-for="(value,key) in item" :key="key">
{{ value }}
</p>
<button @click="addProperty">动态添加新属性</button>
实例化一个vue实例,定义data属性和methods方法
const app = new Vue({
el:"#app",
data:()=>{
item:{
oldProperty:"旧属性"
}
},
methods:{
addProperty(){
this.items.newProperty = "新属性" // 为items添加新属性
console.log(this.items) // 输出带有newProperty的items
}
}
})
点击按钮,发现结果不及预期,数据虽然更新了(console打印出了新属性),但页面并没有更新
原理分析
vue2
是通过Object.defineProperty
实现数据响应式
const obj = {}
Object.defineProperty(obj, 'foo', {
get() {
console.log(`get foo:${val}`);
return val
},
set(newVal) {
if (newVal !== val) {
console.log(`set foo:${newVal}`);
val = newVal
}
}
})
}
当我们访问foo属性或者设置foo值的时候都能够触发setter与getter
但是我们为obj添加新属性的时候,却无法触发事件属性的拦截
原因是一开始obj的foo属性被设成了响应式数据,而bar是后面新增的属性,并没有通过Object.defineProperty
设置成响应式数据
解决方案
vue不允许在已经创建的实例上动态添加新的响应式属性
若想实现数据与试图同步更新,可采取下面三种解决方案
- Vue.set()
- Object.assign() 合并对象
- $forcecUpdated() 强制重新渲染
这里省略了源码部分,分析起来很是复杂啊!
PS:vue3
是通过proxy
实现数据响应式的,直接动态添加新属性仍可惜实现数据响应式