欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

前端实战面试汇总(一)

程序员文章站 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会携带参数。

相关标签: 前端面试 前端