1、解释一下CSS的盒子模型? ☆
答:1)盒模型: 内容(content)、填充(padding)、边界(margin)、 边框(border)
2)有两种, IE 盒子模型、标准 W3C 盒子模型;IE的content部分包含了 border 和 padding;
image2、CSS水平垂直居中 ☆☆☆
方法一:
绝对定位方法:不确定当前div的宽度和高度,采用 transform: translate(-50%,-50%); 当前div的父级添加相对定位(position: relative;)
图片展示:
img代码如下:
div{
background:red;
position: absolute;
left:50%;
top:50%;
transform: translate(-50%, -50%);
}
方法二:
绝对定位方法:确定了当前div的宽度,margin值为当前div宽度一半的负值
图片展示: 如方法一的图片展示
代码如下:
div{
width:600px;
height: 600px;
background:red;
position: absolute;
left:50%;
top:50%;
margin-left:-300px;
margin-top:-300px;
}
方法三:
绝对定位方法:绝对定位下top left right bottom 都设置0
图片展示: 如方法一的图片展示
代码如下:
div.child{
width: 600px;
height: 600px;
background: red;
position:absolute;
left:0;
top: 0;
bottom: 0;
right: 0;
margin: auto;
}
方法四:
flex布局方法:当前div的父级添加flex css样式
展示图如下:
img代码如下:
.box{
height:800px;
-webkit-display:flex;
display:flex;
-webkit-align-items:center;
align-items:center;
-webkit-justify-content:center;
justify-content:center;
border:1px solid #ccc;
}
div.child{
width:600px;
height:600px;
background-color:red;
}
方法五:
table-cell实现水平垂直居中: table-cell middle center组合使用
展示图如下:
img代码如下:
.table-cell {
display: table-cell;
vertical-align: middle;
text-align: center;
width: 240px;
height: 180px;
border:1px solid #666;
}
方法六:
绝对定位:calc() 函数动态计算实现水平垂直居中
展示图如下:
img代码如下:
.calc{
position: relative;
border: 1px solid #ccc;
width: 400px;
height: 160px;
}
.calc .child{
position: absolute;
width: 200px;
height: 50px;
left:-webkit-calc((400px - 200px)/2);
top:-webkit-calc((160px - 50px)/2);
left:-moz-calc((400px - 200px)/2);
top:-moz-calc((160px - 50px)/2);
left:calc((400px - 200px)/2);
top:calc((160px - 50px)/2);
}
3、CSS 如何取消浮动
答:https://www.cnblogs.com/wush-1215/p/10623243.html
4、CSS flex布局(问:解释什么是flex)
答:Flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。
布局的传统解决方案,基于盒状模型,依赖display属性+ position属性+ float属性。它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现。
简单的分为容器属性和元素属性
容器的属性:
· flex-direction:决定主轴的方向(即子item的排列方法)
.box {
flex-direction: row | row-reverse | column | column-reverse;
}
· flex-wrap:决定换行规则
.box{
flex-wrap: nowrap | wrap | wrap-reverse;
}
· flex-flow:
.box {
flex-flow: <flex-direction> || <flex-wrap>;
}
· justify-content:对其方式,水平主轴对齐方式
· align-items:对齐方式,竖直轴线方向
项目的属性(元素的属性):
· order属性:定义项目的排列顺序,顺序越小,排列越靠前,默认为0
· flex-grow属性:定义项目的放大比例,即使存在空间,也不会放大
· flex-shrink属性:定义了项目的缩小比例,当空间不足的情况下会等比例的缩小,如果定义个item的flow-shrink为0,则为不缩小
· flex-basis属性:定义了在分配多余的空间,项目占据的空间。
· flex:是flex-grow和flex-shrink、flex-basis的简写,默认值为0 1 auto。
· align-self:允许单个项目与其他项目不一样的对齐方式,可以覆盖align-items,默认属性为auto,表示继承父元素的align-items
比如说,用flex实现圣杯布局
<!-- DOM结构 -->
<div id="container">
<div id="center"></div>
<div id="left"></div>
<div id="right"></div>
</div>
#container {
display: flex;
}
#center {
flex: 1;
}
#left {
flex: 0 0 200px;
order: -1;
}
#right {
flex: 0 0 150px;
}
注:https://www.runoob.com/cssref/css3-pr-flex.html
5、变量提升
答:
注:https://www.jianshu.com/p/864b0003d7a9?tdsourcetag=s_pcqq_aiomsg
https://blog.csdn.net/weixin_44022064/article/details/103821052
6、闭包 ☆☆
答:
(1)什么是闭包:
闭包是指有权访问另外一个函数作用域中的变量的函数。
闭包就是函数的局部变量集合,只是这些局部变量在函数返回后会继续存在。闭包就是就是函数的“堆栈”在函数返回后并不释放,我们也可以理解为这些函数堆栈并不在栈上分配而是在堆上分配。当在一个函数内定义另外一个函数就会产生闭包。
(2)为什么要用:
匿名自执行函数:我们知道所有的变量,如果不加上var关键字,则默认的会添加到全局对象的属性上去,这样的临时变量加入全局对象有很多坏处,比如:别的函数可能误用这些变量;造成全局对象过于庞大,影响访问速度(因为变量的取值是需要从原型链上遍历的)。除了每次使用变量都是用var关键字外,我们在实际情况下经常遇到这样一种情况,即有的函数只需要执行一次,其内部变量无需维护,可以用闭包。
结果缓存:我们开发中会碰到很多情况,设想我们有一个处理过程很耗时的函数对象,每次调用都会花费很长时间,那么我们就需要将计算出来的值存储起来,当调用这个函数的时候,首先在缓存中查找,如果找不到,则进行计算,然后更新缓存并返回值,如果找到了,直接返回查找到的值即可。闭包正是可以做到这一点,因为它不会释放外部的引用,从而函数内部的值可以得以保留。
function f1(){
var n = 999;
nAdd = function(){
n+=1
}
function f2(){
alert(n)
}
return f2
}
var result = f1();
result();
nAdd();
result();
7、原型链
答:原型本身也是一个对象,这个对象就是Object的实例,所以原型也可以调用到Object的原型,这样就组成了一个链式结构,这个就是原型链。
注:https://www.cnblogs.com/shuiyi/p/5305435.html
8、Event Loop(介绍node中的事件循环) ☆☆
答:链接:https://www.nowcoder.com/questionTerminal/6c17f460e32d4baeaf66c20223354f97
来源:牛客网
Event Loop:
1.遇到sciprt之后开始第一个宏任务
2.执行过程中遇到异步请求,会将其压入任务队列,交由异步事件引擎处理
3.执行完宏任务后,检测是否存在微任务,有的话会先执行微任务
4.执行第二个宏任务
new Promise((resolve, reject) => {
console.log(1)
}).then(_ => {
console.log(2)
})
setTimeout(_ => {
console.log(3)
}, 300)
执行顺序: 1 -> 2->3
promise属于微任务, setTimeout属于宏任务
注:https://segmentfault.com/a/1190000012925872?utm_source=tag-newest
9、promise
答:promise表示一个异步操作的最终结果,与之交互的方式主要是then方法,该方法主要注册了二个回调函数,用于接收promise的最终结果和不能执行的原因。
promise的状态主要有三种:等待、执行、拒绝
1、等待pending 等待进入执行或拒绝状态
2、执行 resolve不能进入其他状态,有一个不可变的最终结果
3、拒绝rejected 不能进入其他状态,有一个不可变的拒绝原因
10、$nextTick ☆☆
答:因为vue是异步更新的,$nextTick用来知道什么时候DOM更新完成。
当修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值,
你需要使用$nextTick这个回调,让修改后的data值渲染更新到dom元素之后在获取,才能成功。
11、vue的双向绑定原理 ☆☆☆☆☆
答:vue 双向数据绑定是通过 数据劫持 结合 发布订阅模式的方式来实现的, 也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变;
核心:关于VUE双向数据绑定,其核心是 Object.defineProperty()方法。
https://www.cnblogs.com/sweeeper/p/10829887.html
12、vue生命周期(考察生命周期某个阶段做了什么) ☆☆
答:每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做 生命周期钩子 的函数,这给了用户在不同阶段添加自己的代码的机会。(ps:生命周期钩子就是生命周期函数)例如,如果要通过某些插件操作DOM节点,如想在页面渲染完后弹出广告窗, 那我们最早可在mounted 中进行。
注:vue的生命周期是:vue实例从创建到摧毁,也就是开始创建、初始化数据、编译模板、挂载DOM → 渲染、更新 → 渲染、卸载等一系列过程。
13、vue-router 有哪几种导航钩子 ☆☆☆
答:三种,
第一种:是全局导航钩子:router.beforeEach(to,from,next),作用:跳转前进行判断拦截。
第二种:组件内的钩子
第三种:单独路由独享组件
参考地址:https://www.cnblogs.com/goloving/p/9211295.html
14、 await和async与promise区别 ☆
注:https://www.jianshu.com/p/463280af23ef
15、vue和angular区别 ☆
注:https://www.imooc.com/article/71832?block_id=tuijian_wz
16、ES6新特性 ☆☆
类
模块化
箭头函数
函数参数默认值
模板字符串
解构赋值
延展操作符(展开操作符)
对象属性简写
Promise
Let与Const
17、有没有用过Directive指令 ☆☆
https://cn.vuejs.org/v2/guide/custom-directive.html
18、vue-router路由的两种模式 ☆☆☆
答:
1、hash模式:vue-router默认hash模式,
使用URL的hash来模拟一个完整的URL,于是当URL改变时,页面不会重新加载。
2、history模式:这种模式充分利用history.pushState API来完成URL跳转而无需重新加载页面。
//设置mode属性,设置路由模式
const router = new VueRouter({
mode:'history',
routes:[..]
})
19、vue如何优化首屏加载 ☆☆
20、vue性能优化
21、js 实现sleep函数
https://blog.csdn.net/qq_36711388/article/details/89787637
22、module.export、exports、export default、export有什么区别
https://www.cnblogs.com/little-baby/p/12783006.html
23、如何设计前端灰度发布
https://www.jianshu.com/p/1329b38ef5d4
24、每页返回10000条数据,如何优化前端渲染和交互体验
1、异步加载
2、碎片化
注:可能会问到滚动条的问题
https://blog.csdn.net/weixin_34116110/article/details/87946321
☆☆
25、移动端300ms延迟以及点击穿透 ☆☆
1、禁用缩放
<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
2、改变视口宽度
<meta name="viewport" content="width=device-width" />
3、touch-action
设置 touch-action 属性,该设置会禁用掉该元素上的浏览器代理的任何默认行为,包括缩放,移动,拖拽等.它把所有的触摸类型的交互事件都禁止掉了,导致页面也不能滚动.感觉在稍微复杂点的实际开发中,应该不会这么设置吧.
html {
touch-action: none;
}
4、引用fastclick库
参考地址:https://juejin.im/post/6854573211317698568
26、面试官:我这样this.xxx[xxx] = xxx,在data里添加一个数据,vue能不能侦测到?为什么?(有类似的问题) ☆☆
答:不能,在new Vue()初始化的时候,在实例的data初始化的数据,才能被侦测到;因为在生命周期beforeCreate到create钩子之间会进行将data中的数据进去双向绑定的侦测;实例初始化完之后再添加的数据,无办法完成侦测初始化
27、JS防抖与节流(性能优化) ☆☆
防抖:动作停止后的时间超过设定的时间时执行一次函数。注意:这里的动作停止表示你停止了触发这个函数,从这个时间点开始计算,当间隔时间等于你设定时间,才会执行里面的回调函数。如果你一直在触发这个函数并且两次触发间隔小于设定时间,则函数一直不会执行。
简单实现:
function debance(fn, delay) {
let timer = null;
return () => {
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn();
}, delay);
};
}
window.addEventListener(
"scroll",
debance(() => {
console.log(111);
}, 1000) );
防抖应用场景:
- search搜索联想,用户在不断输入值时,用防抖来节约请求资源
- window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
节流:一定时间内执行的操作只执行一次,也就是说即预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期。
简单实现:
//方法一:设置一个标志
function throttle(fn, delay) {
let flag = true;
return () => {
if (!flag) return;
flag = false;
timer = setTimeout(() => {
fn();
flag = true; }, delay);
};
}
//方法二:使用时间戳
function throttle(fn, delay) {
let startTime=new Date()
return () => {
let endTime=new Date()
if (endTime-startTime>=delay){
fn()
startTime=endTime
}else{
return
}
};
}
window.addEventListener(
"scroll",
throttle(() => {
console.log(111);
}, 1000)
);
节流应用场景:
- 鼠标不断点击触发,mousedown(单位时间内只触发一次)
- 监听滚动事件,比如是否滑到底部自动加载更多(懒加载)
28、get和post区别,哪个容易造成跨域问题,怎么解决跨域 ☆
GET请求会被浏览器主动cache,而POST不会,除非手动设置
get把请求的参数放在url上,即HTTP协议头上 post把参数放在HTTP的包体内
Get 方式传输的数据量非常小,一般限制在 2 KB 左右,但是执行效率却比 >Post 方法好;而 Post 方式传递的数据量相对较大,它是等待服务器来读取数>据,不过也有字节限制(实际上IIS4中最大量为80KB,IIS5中为100KB),这是为>了避免对服务器用大量数据进行恶意攻击
GET请求只能进行url编码,而POST支持多种编码方式
GET产生的URL地址可以加入书签,而POST不可以
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息
29、前端安全 ☆☆
一、XSS攻击(跨站脚本攻击)
防御:
1、转义字符
2、白名单
二、CSRF(跨站请求伪造)
防御:
1、增加token在请求中放入攻击者不能伪造的信息
2、通过Referer识别
3、网站重要操作增加验证码
30、强缓存和协商缓存 ☆
31、获取当前页面中所有HTML tag的名字,以数组形式输出,不包含重复的标签
const getTagNameNum = () => {
return new Set([...document.querySelectorAll('*')].map(el => el.tagName)).size
}
参考地址:https://blog.csdn.net/weixin_30386713/article/details/98829121
31、Vue模板编译过程
首先会先将模版通过解析器,解析成AST(抽象语法树),然后再通过优化器,遍历AST树,将里面的所有静态节点找出来,并打上标志,这样可以避免在数据更新进行重新生成新的Vnode的时候做一些无用的功夫,和diff算法对比时进行一些无用的对比,因为静态节点这辈子是什么样就是什么样的了,不会变化。接着,代码生成器会将这颗AST编译成代码字符串,这段字符串会别Vdom里面的createElement函数调用,最后生成Vnode。
32、computed和watch
33、说下v-if跟v-show区别
34、组件中的data为什么是一个函数
答:一个组件被复用多次的话,也就会创建多个实例。本质上,这些实例用的都是同一个构造函数。如果data是对象的话,对象属于引用类型,会影响到所有的实例。所以为了保证组件不同的实例之间data不冲突,data必须是一个函数。
35、说一下v-model的原理
答:v-model本质就是一个语法糖,可以看成是value + input方法的语法糖。 可以通过model属性的prop和event属性来进行自定义。原生的v-model,会根据标签的不同生成不同的事件和属性。
36、Vue中组件生命周期调用顺序说一下
答:组件的调用顺序都是先父后子,渲染完成的顺序是先子后父。
组件的销毁操作是先父后子,销毁完成的顺序是先子后父。
加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount- >子mounted->父mounted
子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程
父 beforeUpdate -> 父 updated
销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
37、SSR了解吗 ☆ ☆
答:SSR也就是服务端渲染,也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成,然后再把html直接返回给客户端。
SSR有着更好的SEO、并且首屏加载速度更快等优点。不过它也有一些缺点,比如我们的开发条件会受到限制,服务器端渲染只支持beforeCreate和created两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于Node.js的运行环境。还有就是服务器会有更大的负载需求。
38、Vue-router跳转和location.href有什么区别 ☆ ☆
答:使用location.href='/url'来跳转,简单方便,但是刷新了页面;
使用history.pushState('/url'),无刷新页面,静态跳转;
引进router,然后使用router.push('/url')来跳转,使用了diff算法,实现了按需加载,减少了dom的消耗。
其实使用router跳转和使用history.pushState()没什么差别的,因为vue-router就是用了history.pushState(),尤其是在history模式下。
39、params和query的区别 ☆ ☆
答:用法:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.$route.query.name和this.$route.params.name。
url地址显示:query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
注意点:query刷新不会丢失query里面的数据
params刷新 会 丢失 params里面的数据。
40、vue-router 是什么?它有哪些组件
答:vue用来写路由一个插件。router-link、router-view
参开地址:https://juejin.im/post/6844903945530245133
41、怎么定义 vue-router 的动态路由? 怎么获取传过来的值?
答:在router目录下的index.js文件中,对path属性加上/:id。 使用router对象的params.id。
42、Promise.all 和 Promise.race
Promise.all是支持链式调用的,本质上就是返回了一个Promise实例,通过resolve和reject来改变实例状态。
Promise.myAll = function(promiseArr) {
return new Promise((resolve, reject) => {
const ans = [];
let index = 0;
for (let i = 0; i < promiseArr.length; i++) {
promiseArr[i]
.then(res => {
ans[i] = res;
index++;
if (index === promiseArr.length) {
resolve(ans);
}
})
.catch(err => reject(err));
}
})
}
Promise.race = function(promiseArr) {
return new Promise((resolve, reject) => {
promiseArr.forEach(p => {
// 如果不是Promise实例需要转化为Promise实例
Promise.resolve(p).then(
val => resolve(val),
err => reject(err),
)
})
})
}
网友评论