1.行元素,块元素的区别
块元素:h1~h6、p、div、ol、ul、li等,其中div是最典型的块元素
- 比较霸道,独占一行
- 可以设置宽度、高度、内边距和外边距
- 宽度默认是容器(父级元素宽度)的100%
- 是一个容器及盒子,里面可以放行内或块级元素
行元素:a、i、strong、b、em、ins、del、s、u、span等,其中span标签时最典型的行内元素,有的地方也称为内联元素。
- 相邻行内元素在同一行上,一行可以显示多个
- 宽和高直接设置是无效的
- 默认宽度就是它本身内容的宽度
- 行内元素只能容纳文本或其它行内元素
浏览器还有默认的天生 inline-block 元素(拥有内在尺寸,可设置高宽,
但不会自动换行),有哪些?
答案:
<input> 、<img> 、<button> 、<texterea> 、<label>。
2.说说你了解的居中布局方式
1.水平居中:
1.元素为⾏内元素,设置⽗元素 text-align:center; 块级元素: margin: 0 auto
2.如果元素宽度固定,可以设置左右 margin 为 auto ;
3.如果元素为绝对定位,设置⽗元素 position 为 relative ,元素设 left:0;right:0;margin:auto;
4.使⽤ flex-box 布局,指定 justify-content 属性为center
5.display 设置为 tabel-cell
2.垂直居中:
1.将显示⽅式设置为表格, display:table-cell ,同时设置 vertial-align:middle
2.使⽤ flex 布局,设置为 align-item:center
3.绝对定位中设置 bottom:0,top:0 ,并设置 margin:auto
4.绝对定位中固定⾼度时设置 top:50%,margin-top 值为⾼度⼀半的负值
5.⽂本垂直居中设置 line-height 为 height 值
3.css盒模型的理解
有两种, IE 盒⼦模型、 W3C 盒⼦模型;
盒模型: 内容(content)、填充( padding )、边界( margin )、 边框( border );
区 别: IE 的content 部分把 border 和 padding 计算了进去;
4.px和rem的区别
px
像素,相对长度单位,是相对于显示器屏幕分辨率而言的。
em
em,相对长度,em的大小是根据父元素的font-size大小变化的,如果父元素没有的话,会向上追溯。任意浏览器的默认字体高都是16px。所有未经调整的浏览器都符合: 1em=16px。
rem
rem,相对长度,rem是基于html字体中font-size的大小而做改变。浏览器默认字体大小是16px,1rem=16px。
em和rem的区别
浏览器根据谁来转化成px值,em 是基于使用他们的元素(父元素)的字体大小,rem 单位基于 html 元素的字体大小。
5.display和visible的区别
联系:它们都能让元素不可⻅
区别:
display:none ;会让元素完全从渲染树中消失,渲染的时候不占据任何空间; visibility: hidden ;不会让元素从渲染树消失,渲染师元素继续占据空间,只是内 容不可⻅
display: none ;是⾮继承属性,⼦孙节点消失由于元素从渲染树消失造成,通过修改 ⼦孙节点属性⽆法显示 ;visibility: hidden; 是继承属性,⼦孙节点消失由于继承 了 hidden ,通过设置 visibility: visible; 可以让⼦孙节点显式
修改常规流中元素的 display 通常会造成⽂档重排。修改 visibility 属性只会造成 本元素的重绘。(然后会问到重排和重绘的问题,可惜我没搭到点子上)
读屏器不会读取 display: none ;元素内容;会读取 visibility: hidden; 元素内容
CSS 都有哪些选择器
派生选择器(用 HTML 标签申明)
id 选择器(用 DOM 的 ID 申明)
类选择器(用一个样式类名申明)
属性选择器(用 DOM 的属性申明,属于 CSS2,IE6 不支持,不常用,不知道就算了) 除了前 3 种基本选择器,还有一些扩展选择器,包括
后代选择器(利用空格间隔,比如 div .a{ })
群组选择器(利用逗号间隔,比如 p,div,#a{ })
CSS选择器的优先级是怎么样定义的?
基本原则:
一般而言,选择器越特殊,它的优先级越高。也就是选择器指向的越准确,它的优先级就越高。 复杂的计算方法:
用 1 表示派生选择器的优先级
用 10 表示类选择器的优先级
用 100 标示 ID 选择器的优先级
div.test1 .span var 优先级 1+10 +10 +1
span#xxx .songs li 优先级 1+100 + 10 + 1
#xxx li 优先级 100 +1
6.闭包的理解
闭包就是能够读取其他函数内部变量的函数
闭包是指有权访问另⼀个函数作⽤域中变量的函数,创建闭包的最常⻅的⽅式就是在⼀个 函数内创建另⼀个函数,通过另⼀个函数访问这个函数的局部变量,利⽤闭包可以突破作⽤ 链域 闭包的特性:
函数内再嵌套函数
内部函数可以引⽤外层的参数和变量
参数和变量不会被垃圾回收机制回收
说说你对闭包的理解
使⽤闭包主要是为了设计私有的⽅法和变量。闭包的优点是可以避免全局变量的污染,缺 点是闭包会常驻内存,会增⼤内存使⽤量,使⽤不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产⽣作⽤域的概念
闭包 的最⼤⽤处有两个,⼀个是可以读取函数内部的变量,另⼀个就是让这些变量始终保 持在内存中
闭包的另⼀个⽤处,是封装对象的私有属性和私有⽅法
好处:能够实现封装和缓存等;
坏处:就是消耗内存、不正当使⽤会造成内存溢出的问题
7.==和===的区别
前者会自动转换类型
后者不会
1==”1”
null==undefined
===先判断左右两边的数据类型,如果数据类型不一致,直接返回 false 之后才会进行两边值的判断
8.浅拷贝和深拷贝的区别,怎么实现
深拷贝 & 浅拷贝
- 浅拷贝:仅仅是复制了引用,彼此之间的操作会互相影响
- 深拷贝:在堆中重新分配内存,不同的地址,相同的值,互不影响
总的来说,深浅拷贝的主要区别就是:复制的是引用还是复制的是实例
浅拷贝
- Array.prototype.slice()
let a = [1, 2, 3, 4];
let b = a.slice();
console.log(a === b); // -> false
a[0] = 5;
console.log(a); // -> [5, 2, 3, 4]
console.log(b); // -> [1, 2, 3, 4]
复制代码
- Array.prototype.concat()
let a = [1, 2, 3, 4];
let b = a.concat();
console.log(a === b); // -> false
a[0] = 5;
console.log(a); // -> [5, 2, 3, 4]
console.log(b); // -> [1, 2, 3, 4]
复制代码
看起来Array的slice(),concat()似乎是深拷贝,再接着看就知道它们究竟是深拷贝还是浅拷贝:
let a = [[1, 2], 3, 4];
let b = a.slice();
console.log(a === b); // -> false
a[0][0] = 0;
console.log(a); // -> [[0, 2], 3, 4]
console.log(b); // -> [[0, 2], 3, 4]
Array的slice和concat方法并不是真正的深拷贝,对于Array的第一层的元素是深拷贝,而Array的第二层 slice和concat方法是复制引用。所以,Array的slice和concat方法都是浅拷贝。
深拷贝
- JSON.parse()和JSON.stringify()
- JSON.stringify():把一个js对象序列化为一个JSON字符串
- JSON.parse():把JSON字符串反序列化为一个js对象
let obj = {
name: 'leeper',
age: 20,
friend: {
name: 'lee',
age: 19
}
};
let copyObj = JSON.parse(JSON.stringify(obj));
obj.name = 'Sandman';
obj.friend.name = 'Jerry';
console.log(obj);
// -> {name: "Sandman", age: 20, friend: {age: 19,name: 'Jerry'}}
console.log(copyObj);
// -> {name: "leeper", age: 20, friend: {age: 19,name: 'lee'}}
综上,JSON.parse()和JSON.stringify()是完全的深拷贝。
- 动手实现深拷贝 利用递归来实现对对象或数组的深拷贝。递归思路:对属性中所有引用类型的值进行遍历,直到是基本类型值为止。
function deepCopy(obj) {
if (!obj && typeof obj !== 'object') {
throw new Error('error arguments');
}
// const targetObj = obj.constructor === Array ? [] : {};
const targetObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
//只对对象自有属性进行拷贝
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === 'object') {
targetObj[key] = deepCopy(obj[key]);
} else {
targetObj[key] = obj[key];
}
}
}
return targetObj;
}
9.vue生命周期
每个Vue实例在创建时都会经过一系列的初始化过程,vue的生命周期钩子,就是说在达到某一阶段或条件时去触发的函数,目的就是为了完成一些动作或者事件
create阶段:vue实例被创建beforeCreate: 创建前,此时data和methods中的数据都还没有初始化created: 创建完毕,data中有值,未挂载mount阶段: vue实例被挂载到真实DOM节点beforeMount:可以发起服务端请求,去数据mounted: 此时可以操作Domupdate阶段:当vue实例里面的data数据变化时,触发组件的重新渲染beforeUpdateupdateddestroy阶段:vue实例被销毁beforeDestroy:实例被销毁前,此时可以手动销毁一些方法destroyed链接:juejin.cn/post/698942…
10.v-if和v-show的区别
1. 在原理方面的区别
v-show指令:元素始终被渲染到HTML,它只是简单的伪元素设置css的style属性,当不满足条件的元素被设置style=“display:none”的样,是通过修改元素的的CSS属性(display)来决定实现显示还是隐藏v-if指令:满足条件是会渲染到html中,不满足条件时是不会渲染到html中的,是通过操纵dom元素来进行切换显示
2. 在使用应用场景方面的区别
v-if需要操作dom元素,有更高的切换消耗.v-show只是修改元素的的CSS属性有更高的初始渲染消耗。- 如果需要非常频繁的切换,建议使用
v-show较好,如果在运行时条件很少改变,则使用v-if较好
11.vue组件间通信方式
vue组件的通信
父传子
通过props传递
父组件: <child value = '传递的数据' />
子组件: props['value'],接收数据,接受之后使用和data中定义数据使用方式一样
复制代码
子传父
在父组件中给子组件绑定一个自定义的事件,子组件通过$emit()触发该事件并传值。
父组件: <child @receive = 'receive' />
子组件: this.$emit('receive','传递的数据')
复制代码
兄弟组件传值
- 通过中央通信 let bus = new Vue()
A:methods :{ 函数{bus.$emit(‘自定义事件名’,数据)} 发送
B:created (){bus.$on(‘A发送过来的自定义事件名’,函数)} 进行数据接收
- 通过vuex
12.v-for中key的作用
key的作用主要是为了更高效的对比虚拟DOM中每个节点是否是相同节点;Vue在patch过程中判断两个节点是否是相同节点,key是一个必要条件,渲染一组列表时,key往往是唯一标识,所以如果不定义key的话,Vue只能认为比较的两个节点是同一个,哪怕它们实际上不是,这导致了频繁更新元素,使得整个patch过程比较低效,影响性能;- 从源码中可以知道,Vue判断两个节点是否相同时主要判断两者的key和元素类型等,因此如果不设置key,它的值就是
undefined,则可能永 远认为这是两个相同的节点,只能去做更新操作,这造成了大量的dom更新操作,明显是不可取的。
13.说说vuex的理解
Vuex 是一个专为 Vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能。
-
state 唯一数据源,Vue 实例中的 data 遵循相同的规则
-
getters 可以认为是 store 的计算属性,就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。Getter 会暴露为 store.getters 对象,你可以以属性的形式访问这些值.
-
mutation 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,非常类似于事件,通过store.commit 方法触发
-
action Action 类似于 mutation,不同在于Action 提交的是 mutation,而不是直接变更状态,Action 可以包含任意异步操作
-
module 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。 链接:juejin.cn/post/685003…