前端实战面试汇总(一)
程序员文章站
2022-04-18 21:55:20
...
一、谈谈标准盒模型和怪异盒模型(IE盒模型)
盒模型分为标准盒模型和怪异盒模型(IE模型)
box-sizing:content-box //标准盒模型
box-sizing:border-box //怪异盒模型
标准盒模型 元素的宽度等于style里的width+margin+padding宽度
标准盒模型:元素的宽度等于style里的width+margin+padding宽度
如下代码 整个宽高就是120px
div{
box-sizing: content-box;
margin: 10px;
width: 100px;
height: 100px;
padding: 10px;
}
怪异盒模型:元素宽度等于style里的width宽度
如下代码 整个宽高就是100px
div{
box-sizing: content-box;
margin: 10px;
width: 100px;
height: 100px;
padding: 10px;
}
二、rem与em的区别
rem是根据根的font-size变化,而em是根据父级的font-size变化
rem:相对于根元素html的font-size,假如html为font-size:12px,那么,在其当中的div设置为font-size:2rem,就是当中的div为24px
em:相对于父元素计算,假如某个p元素为font-size:12px,在它内部有个span标签,设置font-size:2em,那么,这时候的span字体大小为:12*2=24px
三、水平垂直居中的几种方式
1、定位 上下左右0+margin:auto;
2、定位 l50% t50% translate(-50%,-50%)
3、定位 l50% t50% ml:-宽度一半 mt:-高度一半;
4、父元素 line-height:200px font-size:0;
子元素 inline-block vertical-align:middle
5、弹性布局 父 display:flex justify-content:center; align-items:center;
四、谈谈闭包
什么是闭包
函数A 里面包含了 函数B,而 函数B 里面使用了 函数A 的变量,那么 函数B 被称为闭包。
function A() {
var a = 1;
function B() {
console.log(a);
}
return B();
}
闭包的好处
能够实现封装和缓存等
闭包的坏处
就是消耗内存、不正当使用会造成内存溢出的问题
使用闭包的注意点
由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成网页的性能问题,在IE中可能导致内存泄露
解决方法是:在退出函数之前,将不使用的局部变量全部删除
闭包的经典问题
for(var i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
这段代码输出3个3
解析:首先,for 循环是同步代码,先执行三遍 for,i 变成了 3;然后,再执行异步代码 setTimeout,这时候输出的 i,只能是 3 个 3 了
有什么办法输出 0 1 2
使用let
for(let i = 0; i < 3; i++) {
setTimeout(function() {
console.log(i);
}, 1000);
}
在这里,每个 let 和代码块结合起来形成块级作用域,当 setTimeout() 打印时,会寻找最近的块级作用域中的 i,所以依次打印出 0 1 2
使用立即执行函数解决闭包的问题
for(let i = 0; i < 3; i++) {
(function(i){
setTimeout(function() {
console.log(i);
}, 1000);
})(i)
}
五、组件化和模块化
组件化
组件化开发的优点和必要性
增强代码可读性,降低维护成本,达到组件通用性
组件化开发的原则
- 专一
- 可配置性
- 标准性
- 复用性
- 可维护性
模块化
模块化的好处
- 避免变量污染,命名冲突
- 提高代码复用率
- 提高了可维护性
- 方便依赖关系管理
模块化的几种方法
- 函数封装
var myModule = {
var1: 1,
var2: 2,
fn1: function(){
},
fn2: function(){
}
}
- 立即执行函数表达式
var myModule = (function(){
var var1 = 1;
var var2 = 2;
function fn1(){
}
function fn2(){
}
return {
fn1: fn1,
fn2: fn2
};
})();
六、对This对象的理解
this总是指向函数的直接调用者(而非间接调用者)
如果有new关键字,this指向new出来的那个对象
在事件中,this指向触发这个事件的对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window
七、vue生命周期
Vue生命周期总共有几个阶段?
它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后
第一次页面加载会触发哪几个钩子?
第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子
DOM渲染在哪个周期中就已经完成?
DOM 渲染在 mounted 中就已经完成了
每个生命周期适合哪些场景?
生命周期钩子的一些使用方法:
beforecreate : 可以在这加个loading事件,在加载实例时触发
created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用
mounted : 挂载元素,获取到DOM节点
updated : 如果对数据统一处理,在这里写上相应函数
beforeDestroy : 可以做一个确认停止事件的确认框
nextTick : 更新数据后立即操作dom
八、v-show与v-if区别
v-show是css切换,v-if是完整的销毁和重新创建
使用 频繁切换时用v-show,运行时较少改变时用v-if
v-if=‘false’ v-if是条件渲染,当false的时候不会渲染
九、组件之间的传值通信
父组件给子组件传值
使用props,父组件可以使用props向子组件传递数据
父组件vue模板father.vue
<template>
<child :msg="message"></child>
</template>
<script>
import child from './child.vue';
export default {
components: {
child
},
data () {
return {
message: 'father message';
}
}
}
</script>
子组件vue模板child.vue
<template>
<div>{{msg}}</div>
</template>
<script>
export default {
props: {
msg: {
type: String,
required: true
}
}
}
</script>
子组件向父组件通信
父组件向子组件传递事件方法,子组件通过$emit触发事件,回调给父组件
父组件vue模板father.vue
<template>
<child @msgFunc="func"></child>
</template>
<script>
import child from './child.vue';
export default {
components: {
child
},
methods: {
func (msg) {
console.log(msg);
}
}
}
</script>
子组件vue模板child.vue:
<template>
<button @click="handleClick">点我</button>
</template>
<script>
export default {
props: {
msg: {
type: String,
required: true
}
},
methods () {
handleClick () {
//........
this.$emit('msgFunc');
}
}
}
</script>
非父子,兄弟组件之间通信
可以通过实例一个vue实例Bus作为媒介,要相互通信的兄弟组件之中,都引入Bus,然后通过分别调用Bus事件触发和监听来实现通信和参数传递
Bus.js可以是这样:
import Vue from 'vue'
export default new Vue()
在需要通信的组件都引入Bus.js:
<template>
<button @click="toBus">子组件传给兄弟组件</button>
</template>
<script>
import Bus from '../common/js/bus.js'
export default{
methods: {
toBus () {
Bus.$emit('on', '来自兄弟组件')
}
}
}
</script>
另一个组件也import Bus.js 在钩子函数中监听on事件
import Bus from '../common/js/bus.js'
export default {
data() {
return {
message: ''
}
},
mounted() {
Bus.$on('on', (msg) => {
this.message = msg
})
}
}
十、路由传参的几种方式
1、路由配置传参
首先确定自己要传的参数名,将路由配置修改一下,传name,age,sex三个参数:
{
path:'/componentsB/:name/:age/:sex',
name:'componentsB',
component:componentsB
}
在componentsA.vue页面通过this.$router.push配置与之对应的参数:
componentsA.vue
<template>
<div>
<div>我是组件A</div>
<button @click='routerToB1'>方式一跳转到组件B</button>
</div>
</template>
<script>
export default{
data(){
return{
person:{name:'Gene',age:'18',sex:'male'}
}
},
methods: {
routerToB1() {
this.$router.push({
path:`componentsB/${this.person.name}/${this.person.age}/${this.person.sex}`
})
}
},
}
</script>
<style>
</style>
在componentsB.vue页面通过this.$route.params配置与之对应的参数:
componentsB.vue
<template>
<div>
<div>我是组件B</div>
</div>
</template>
<script>
export default{
created(){
this.getRouterData()
},
methods: {
getRouterData(){
const param = this.$route.params
console.log(param)//{name:'Gene',age:'18',sex:'male'}
}
},
}
</script>
<style>
</style>
点击按钮"方式一跳转到组件B",componentsB页面打印出{name:‘Gene’,age:‘18’,sex:‘male’},成功获取到A页面传过来的参数,并且地址栏显示为localhost:8889/#/componentsB/Gene/18/male(端口号根据自己设置的来),表明这种传参方式url会携带参数。
2、params传参
首先将刚才路由配置修改部分还原,在componentsA.vue页面添加按钮"方式二跳转到组件B":
componentsA.vue
<template>
<div>
<div>我是组件A</div>
<button @click='routerToB1'>方式一跳转到组件B</button>
<button @click='routerToB2'>方式二跳转到组件B</button>
</div>
</template>
在methods中添加方法routerToB2,使用路由属性name来确定匹配的路由,使用属性params来传递参数:
componentsA.vue
routerToB2(){
this.$router.push({
name:'componentsB',
params:{
exa:'我是传到组件B的参数'
}
})
},
componentsB.vue保持不变,params传参方式获取参数也是通过this.$route.params,点击A页面新添加的按钮"方式二跳转到组件B",在B页面打印出{exa: “我是传到组件B的参数”},传参成功,地址栏为localhost:8889/#/componentsB,表明这种方式url不会携带参数。
3、query传参
这种方式和params传参方式类似,在componentsA.vue页面继续添加按钮"方式三跳转到组件B":
componentsA.vue
<template>
<div>
<div>我是组件A</div>
<button @click='routerToB1'>方式一跳转到组件B</button>
<button @click='routerToB2'>方式二跳转到组件B</button>
<button @click='routerToB3'>方式三跳转到组件B</button>
</div>
</template>
在methods中添加方法routerToB3,使用路由属性name或者path来确定匹配的路由,使用属性query 来传参:
componentsA.vue
routerToB3(){
this.$router.push({
name:'componentsB',// path:'/componentsB'
query:{
que:'我是通过query传到组件B的参数'
}
})
}
在ccomponentsB.vue页面通过this.$route.query来获取参数:
ccomponentsB.vue
getRouterData(){
const query = this.$route.query
console.log(query)//{que: "我是通过query传到组件B的参数"}
}
查看地址栏为localhost:8889/#/componentsB?que=我是通过query传到组件B的参数,显然这种方式url会携带参数。
上一篇: 模拟Object.creat
下一篇: C语言的介绍2