HTML&CSS
【1】简述Chrome盒模型与IE盒模型的区别(掌握)
每个元素在页面中占位大小 = content + padding + margin + border
Chrome盒模型内容大小等于content大小;
IE盒模型内容大小等于content + padding + border的总和
【2】BFC(掌握)
BFC全称”Block Formatting Context”
, 中文为“块级格式化上下文
”。
流体特性:块状水平元素,如div元素(下同),在默认情况下(非浮动、绝对定位等),水平方向会自动填满外部的容器;
BFC元素特性表现原则就是,内部子元素不会影响外部的元素
。
【3】什么是弹性布局?(掌握)
解决某元素中“子元素
”的布局方式,为布局提供最大的灵活性。
设为 flex
布局以后,子元素的 float、clear
和vertical-align
属性将失效!!!
display:flex
; 属性align-self
定义子元素的位置
【4】html5有哪些新特性?(掌握)
- (1)
Canvas绘图
- (2)
SVG绘图
- (3)
地理定位
- (4)
Web Worker
- (5)
Web Storage
- (6)
Web Socket
【5】CSS3有哪些新特性(掌握)
border-radius 圆角
box-shadow 阴影
text-shadow 文字阴影
gradient 线性渐变
transform 旋转、缩放、移动或倾斜
scale 缩放
translate 位移
媒体查询 多栏布局 多背景
【6】如何让一个盒子在页面垂直水平居中(掌握)
方法一:已知宽高
div{
position: absolute;
left: 0;
right: 0;
bottom: 0;
top: 0;
margin: auto;
}
方法二:未知宽高
div{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
【7】前端性能优化方案(掌握)
1、减少DOM操作
2、部署前,图片压缩,代码压缩
3、优化js代码结构,减少冗余代码
4、减少http请求,合理设置HTTP缓存
5、使用内容分发cdn加速
6、静态资源缓存
7、图片延迟加载
【8】介绍一下你对浏览器内核的理解?(掌握)
主要分成两部分:渲染引擎(layout engineer或Rendering Engine)
和JS引擎
。
渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。
JS引擎则:解析和执行javascript来实现网页的动态效果。最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。
【9】如何实现响应式布局
1、响应式布局方法一:媒体查询
使用@media媒体查询可以针对不同的媒体类型定义不同的样式,特别是响应式页面,可以针对不同屏幕的大小,编写多套样式,从而达到自适应的效果
2、响应式布局方法二:rem
rem单位是相对于字体大小的html元素,也称为根元素。 默认情况下,html元素的font-size为16px。所以此时1rem = 16px。
3、响应式布局方法三:百分比%
比如当浏览器的宽度或者高度发生变化时,通过百分比单位,通过百分比单位可以使得浏览器中的组件的宽和高随着浏览器的变化而变化,从而实现响应式的效果
4、响应式布局方法四:vw/vh
css3中引入了一个新的单位vw/vh,与视图窗口有关,vw表示相对于视图窗口的宽度,vh表示相对于视图窗口高度。 任意层级元素,在使用vw单位的情况下,1vw都等于视图宽度的百分之一。
与百分比布局很相似,但更好用。
5、响应式布局方法五:flex弹性布局
弹性布局是一种十分方便的,只需要依赖于CSS样式的实现响应式布局的方式,也是最多用到的一种实现响应式的方法。
【10】安卓和ios的适配问题
1.margin在IOS中失效
在页面中元素使用margin值,在某些IOS设备下会出现失效的情况,而安卓机则正常显示,此问题暂无直接的解决方案,当前使用空DIV控制间距。
2.fixed定位问题
整个页面的fixed定位,在ios下下拉会触发下拉事件,但是没有动画效果。Android就能正常运行
flex中使用 绝对定位,ios出现严重错位,导致父级元素也会变成绝对定位,Android能达到理想效果
总而言之 尽量不用fixed
3.absolute定位问题
①使用absolute定位,并且宽带设置了100% 并且设置了padding就会导致屏幕宽度溢出,出现页面左右可以移动的bug,
模拟器上是没有问题,但是真机上是有这个问题的。这个问题让我调试并痛苦了许久
②使用absolute并且当前元素是flex容器这种情况在Ios下面布局不会起到左右,会出现所有元素转换成了absloute并且文字错位
③总而言之 尽量不用 absolute
- word-spacing在button中的问题
有时候在使用大按钮的时候两个字中间希望有段间距,但是目前没有找到能使用的占位符,所以使用了的word-spacing加空格 这个方法来设置文字的间距,
但是在iPhone6s 上两个字中间一个空格的时候整体会向右偏,必须设置两个空格。
5.相同代码存在效果差异
在真机测试或者模拟器测试,总汇出现各种样式上的差异,造成原因比较多,因为不同的手机呈现的效果或者它本身采用的技术均存在差异,
最终呈现的效果有时候就会出现较大的差别。但是这些差别一般都是在可以接受的范围。
【11】css画三角形,n种方法
1、使用 border 绘制三角形
2、使用 linear-gradient 绘制三角形
3、使用 conic-gradient 绘制三角形
4、transform: rotate 配合 overflow: hidden 绘制三角形
5、使用 clip-path 绘制三角形
6、利用字符绘制三角形
JavaScript
【1】console.log(0.1 + 0.2) (掌握)
0.1+0.2的结果不是0.3,而是0.3000000000000000004,JS中两个数字相加时是以二进制形式进行的,当十进制小数的二进制表示的有限数字超过52位时,在JS里是不能精确储存的,这个时候就存在舍入误差。
【2】事件冒泡和事件捕获到底有何区别?(掌握)
1.事件冒泡:从下至上。当给父子元素的同一事件绑定方法的时候,触发子元素身上的事件,执行完毕之后,也会触发父级元素相同的事件。
注意: addEventListener中有三个属性,第三个属性是布尔值。false为事件冒泡,true为事件捕获
2.事件捕获:从上至下到指定元素。当触发子元素身上的事件时,先触发父元素,然后在传递给子元素
【3】JS数据类型(掌握)
在ES5的时候,我们认知的数据类型确实是 6种:Number、String、Boolean、undefined、object、Null。
ES6 中新增了一种 Symbol
【4】简述javascript原型、原型链?有什么特点(掌握)
原型:每一个构造函数都有一个prototype属性指向一个对象,这个对象就是构造函数实例的原型
原型链:每一个实例都有一个__proto__属性执行原型对象,来获取原型对象上的属性和方法,原型对象也有一个__proto
属性指向另外一个原型对象,以此类推,直到原型链的最终端null为止,这个串成链的过程就是原型链
特点:实现继承 一个对象可以拿到另一个对象上的属性和方法
构造函数都有一个prototype属性指向原型对象
原型对象都有一个consttuctor属性指向构造函数
构造函数new实例化实例对象
实例对象上有__proto属性指向原型
【5】谈谈this对象的理解,call()、apply()和bind()的区别(掌握)
1.普通函数 window
2.构造函数 实例对象
3.回调函数 大部分指向window
4.事件处理程序 事件源
5.对象的方法 当前对象
6.箭头函数 上局作用域中的this指向
call和apply的区别在于传入参数的不同; 第一个参数都是,指定函数体内this的指向;
第二个参数开始不同,apply是传入带下标的集合,数组或者类数组,apply把它传给函数作为参数,call从第二个开始传入的参数是不固定的,都会传给函数作为参数。
call比apply的性能要好,平常可以多用call。call传入参数的格式正是内部所需要的格式
bind是增加一个新的this指向,并向这个新的this指向里传参
【6】什么是闭包?为什么要用它?(掌握)
1)什么是闭包
函数执行后返回结果是一个内部函数,并被外部变量所引用,如果内部函数持有被执行函数作用域的变量,即形成了闭包。
【7】简述js继承的方式(掌握)
- 混入式继承:把父类的所有方法都拷贝到子类上
- 原型式继承:只继承父类原型上的属性和方法
- 原型链继承:继承父类构造函数里边的属性和方法,也继承父类原型上的属性和方法 缺点–不能向父类传参数
- 借用构造函数继承:可以父类传递参数 缺点–继承不了父类原型对象的方法
- 组合继承:借用构造函数继承+原型链继承
【8】深拷贝和浅拷贝的区别(掌握)
浅拷贝(shallowCopy)
只是增加了一个指针指向已存在的内存地址,
深拷贝(deepCopy)
是增加了一个指针并且申请了一个新的内存,使这个增加的指针指向这个新的内存.
浅复制
:仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。
深复制
:在计算机中开辟一块新的内存地址用于存放复制的对象。
【9】如何实现深拷贝(掌握)
常用:使用JSON.parse(JSON.stringify(obj))
原理是把一个对象序列化成为一个JSON字符串,将对象的内容转换成字符串的形式再保存在磁盘上,再用JSON.parse()反序列化将JSON字符串变成一个新的对象
缺点是: 会忽略undefined、symbol、funciton
实现:递归+判断类型
【10】javascript 的垃圾回收机制讲一下(掌握)
定义:指一块被分配的内存既不能使用,又不能回收,直到浏览器进程结束。JavaScript 在创建对象(对象、字符串等)时会为它们分配内存,不再使用对时会“自动”释放内存,这个过程称为垃圾收集。
内存生命周期中的每一个阶段:
分配内存 — 内存是由操作系统分配的,它允许您的程序使用它。在低级语言(例如 C 语言)中,这是一个开发人员需要自己处理的显式执行的操作。然而,在高级语言中,系统会自动为你分配内在。 使用内存 — 这是程序实际使用之前分配的内存,在代码中使用分配的变量时,就会发生读和写操作。 释放内存 — 释放所有不再使用的内存,使之成为自由内存,并可以被重利用。与分配内存操作一样,这一操作在低级语言中也是需要显式地执行。
四种常见的内存泄漏:全局变量,未清除的定时器,闭包,以及 dom 的引用
- 全局变量 不用 var 声明的变量,相当于挂载到 window 对象上。如:b=1; 解决:使用严格模式
- 被遗忘的定时器和回调函数
- 闭包
- 没有清理的 DOM 元素引用
【11】介绍下 promise 的特性、优缺点(掌握)
1、Promise有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败),异步操作嵌套异步操作可以使用
2、Promise对象接受一个回调函数作为参数, 该回调函数接受两个参数,分别是成功时的回调resolve和失败时的回调reject;另外resolve的参数除了正常值以外, 还可能是一个Promise对象的实例;reject的参数通常是一个Error对象的实例。
3、then方法返回一个新的Promise实例,并接收两个参数onResolved(fulfilled状态的回调);onRejected(rejected状态的回调,该参数可选)
4、catch方法返回一个新的Promise实例
2)Promise优点
①统一异步 API
②Promise 和事件相比较, Promise 更适合处理一次性的结果
③Promise 解决了回调地狱的问题,
④Promise 带来的额外好处是包含了更好的错误处理方式(包含了异常处理),并且写起来很轻松(因为可以重用一些同步的工具,比如 Array.prototype.map() )
3)Promise缺点
1、无法取消Promise,一旦新建它就会立即执行,无法中途取消。
2、如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
3、当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
4、Promise 真正执行回调的时候,定义 Promise 那部分实际上已经走完了,所以 Promise 的报错堆栈上下文不太友好
【12】请描述一下 cookies,sessionStorage 和 localStorage 的区别?
- cookie是浏览器自动携带在请求里发送给服务端去验证的
sessionStorage和localStorage不会自动携带
- cookie体积相对sessionStorage localStorage小
- 后端可以设置cookie之后,前端修改不了的;
- cookie可以设置过期时间
- cookie是用来做状态保持的,因为http请求时无状态的
- cookie是用户第一次访问服务器服务器颁发给浏览器的,第二次请求就会携带
- sessionStorage 存储在内存中 关闭浏览器数据会消失
- localStorage 关闭浏览器数据不会消失 需要手动去清除
【13】简述同源策略与跨域(掌握)
同源策略是一种约定,它是浏览器最核心的也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能会受到影响。
当协议,主机,和端口号有一个不同时,就是跨域。
【14】跨域解决方案(掌握)
1、(后端)服务器配置CORS(跨域资源共享)
2) (后端)node.js或nginx,反向代理,把跨域改造成同域
3)(前端)将JSON升级成JSONP,在JSON的基础上,利用script 标签可以跨域的特性,加上头设置
【15】浏览器的事件循环(掌握)
【16】什么是防抖和节流?有什么区别?如何实现?(掌握)
/** 防抖:
* 应用场景:当用户进行了某个行为(例如点击)之后。不希望每次行为都会触发方法,而是行为做出后,一段时间内没有再次重复行为,
* 才给用户响应
* 实现原理 : 每次触发事件时设置一个延时调用方法,并且取消之前的延时调用方法。(每次触发事件时都取消之前的延时调用方法)
* @params fun 传入的防抖函数(callback) delay 等待时间
* */
const debounce = (fun, delay = 500) => {
let timer = null //设定一个定时器
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => {
fun.apply(this, args)
}, delay)
}
}
/** 节流
* 应用场景:用户进行高频事件触发(滚动),但在限制在n秒内只会执行一次。
* 实现原理: 每次触发时间的时候,判断当前是否存在等待执行的延时函数
* @params fun 传入的防抖函数(callback) delay 等待时间
* */
const throttle = (fun, delay = 1000) => {
let flag = true;
return function (...args) {
if (!flag) return;
flag = false
setTimeout(() => {
fun.apply(this, args)
flag = true
}, delay)
}
}
【17】宏观任务和微观任务
宏任务
(macro)task(又称之为宏任务),可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。
微任务
microtask(又称为微任务),可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。
ES6
【1】ES6新特性
1,promise异步编排
2.let关键字
3.const
4.数组解构
5.对象解构
6.模板字符串
7.数组扁平化
8.箭头函数
9.rest操作符
10.拓展运算符(…)
11.class extends.
12.symbol(新的数据类型)
13.async+await
14.forin(遍历对象)
【2】5个字符串函数和5个数组函数
字符串函数
1、gets函数
2、puts函数
3、strcat函数
4、strlen函数
5、strlwr函数
一、数组操作的基本函数
数组的键名和值
array_values($arr);获得数组的值
array_keys($arr);获得数组的键名
array_flip($arr);数组中的值与键名互换(如果有重复前面的会被后面的覆盖)
in_array(“apple”,$arr);在数组中检索apple
array_search(“apple”,$arr);在数组中检索apple ,如果存在返回键名
array_key_exists(“apple”,$arr);检索给定的键名是否存在数组中
isset($arr[apple]):检索给定的键名是否存在数组中
数组的内部指针
current($arr);返回数组中的当前单元
pos($arr);返回数组中的当前单元
key($arr);返回数组中当前单元的键名
prev($arr);将数组中的内部指针倒回一位
next($arr);将数组中的内部指针向前移动一位
end($arr);将数组中的内部指针指向最后一个单元
reset($arr;将数组中的内部指针指向第一个单元
each($arr);将返回数组当前元素的一个键名/值的构造数组,并使数组指针向前移动一位
list( k e y , key, key,value)=each($arr);获得数组当前元素的键名和值
【3】get和post的区别
1、get和post在HTTP中都代表着请求数据,其中get请求相对来说更简单、快速,效率高些
2、get相对post安全性低
3、get有缓存,post没有
4、get体积小,post可以无限大
5、get的url参数可见,post不可见
6、get只接受ASCII字符的参数数据类型,post没有限制
7、get请求参数会保留历史记录,post中参数不会保留
8、get会被浏览器主动catch,post不会,需要手动设置
9、get在浏览器回退时无害,post会再次提交请求
(请求方式:get,post.put,delete.opions.head)
【4】Promise构造函数是同步执行还是异步执行,那么 then 方法呢?
promise构造函数是同步执行的,then方法是异步执行的
【5】说一下你知道的常用的HTTP状态码
1开头的状态码(信息类)
2开头的状态码(成功类) 例如:200请求成功
3开头的状态码(重定向) 例如:307临时跳转,临时从不同的url响应请求
4开头的状态码(客户端错误) 例如:404服务器找不到请求页面
5开头的状态码(服务器错误) 例如:500服务器内部错误
小程序
【1】小程序登录流程
- wx.login获取临时登录凭证code
- 发送code给后端,后端通过code,appid,appsecret调用微信接口,返回openid和session-key;
- 后端通过openid和session-key生成token返回给前端
- 前端把后端返回的token缓存起来
【2】静默登录和非静默登录
【3】小程序生命周期
- onLaunch() 用户首次打开小程序触发(全局只触发一次)
- onShow() 小程序初始化完成后触发,小程序从后台进入前台也会触发
- onHide() 小程序从前台进入后台触发
- onError() 小程序发生脚本错误或者API调用失败时触发
【4】小程序常用API
wx.downloadFile下载文件
wx.request() 请求数据
wx.relaunch({}) 关闭所有页面,打开到应用内的某个页面
wx.switchTab({}) 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
wx.getUserProfile 获取用户信息。
wx.navigateTo({url:url}) 保留当前页面,跳转到应用内的某个页面。
wx.navigateBack 关闭当前页面,返回上一页面或多级页面。
wx.redirectTo({}) 关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。
【5】小程序解决时间的冒泡
解决方案:将绑定事件的bindtap改为catchtap
【6】什么是openid
1.openID是什么
openID是微信平台推出的,每个用户在每个公众号的用户标志
openID目前是由28位加密过后的字符串组成
【7】小程序包超过2M怎么处理
一、分包
1、配置manifest.json
2、在pages.json里面配置
3、新建分包目录
4、查看
二、图片上传至服务器
把图片都放到服务器上,访问服务器地址
三、先发行再打包
React
【1】结合你的经验谈谈,react 和 vue区别 (不光要搜索的官方区别,还要结合自己的经验谈谈)
【2】React类式组件的生命周期 废弃的不用说 说了更牛逼
1、组件挂载
/** 组件 挂载 时生命周期函数 **/
componentWillMount() {组件即将挂载}
// 一般在这个生命周期函数进行ajax请求
componentDidMount() {组件 挂载 完成}
/** 组件 更新 时生命周期函数 **/
2、组件更新
componentWillReceiveProps() {}
shouldComponentUpdate() {}
componentWillUpdate() {}
componentDidUpdate() {}
3、组件卸载
/** 组件 卸载 时生命周期函数 **/
componentWillUnmount() {}
【3】useState 是同步还是异步的?
setState和useState是看起来像异步的同步,因为react的合并机制,多次调用不会立即更新,setState是合并state,useState是执行最后一次,延迟执行但本身还在一个事件循环,如果脱离react事件,如原生事件或者setTimeout/promise.then里执行setState和useState,就会得到同步代码。
【4】函数式组件和类式组件的区别
-
语法上的区别:
函数式组件是一个纯函数,它是需要接受props参数并且返回一个React元素就可以了。 类组件是需要继承React.Component,而且class组件需要创建render并且返回React元素, 语法上来讲更复杂。
-
调用方式
函数式组件可以直接调用,返回一个新的React元素;
类组件在调用时是需要创建一个实例的,然后通过调用实例里的render方法来返回一个React元素。 -
状态管理(state)
函数式组件没有状态管理,类组件有状态管理。 -
使用场景
类组件没有具体的要求。
函数式组件一般是用在大型项目中来分割大组件(函数式组件不用创建实例,所有更高效),
一般情况下能用函数式组件就不用类组件,提升效率。
【5】说说你常用的Hook , 什么是Hook , 你了解过Hook吗
Hook(钩子)是一种特殊的消息处理机制,它可以监视系统或者进程中的各种事件消息,截获发往目标窗口的消息并进行处理。
1、 useState
2、useEffect
3、useContext:使函数组件可以具有和Class组件中的contextType属性(使可以通过this.context访问值)一样的功能。
4、useReducer 可以看做useState的复合版
5、useMemo:接受两个参数useMemo(()=>{ 立刻执行函数体,*返回一个值 },依赖) 返回一个值 作用:缓存值,依赖为空的话,这个函数体永远就执行一次
【6】 react 组件传值 父子 多层父子 兄弟
父子组件常用的传值方法是当父组件给子组件传值时通过props,
子组件向父组件传值通过回调函数来传值。
跨级组件常用的传值方法是props一层一层的传,或者使用context对象,将父组件设置为生产者而子组件都设置对应的contextType即可。
非嵌套关系组件传值的方法是使用共同的父级组件进行props传值,或者通过context传值,
【7】 受控组件和 不受控组件
受控组件 自己写双向绑定 组件 获取值 值直接绑定给data数据了 <input onchange= value={}>
不受控组件 没有绑定的 获取dom 获取值
【8】 什么是jsx? 和 html的区别
\JSX是一种JavaScript的语法扩展,全称JavaScript XML,运用于React架构中,其格式比较像是模版语言,但事实上完全是在JavaScript内部实现的。元素是构成React应用的最小单位,JSX就是用来声明React当中的元素,React使用JSX来描述用户界面,能让我们可以在JS中写html标记语言。
1、JSX中,添加行内onClick事件,不同于HTML行内事件,jsx中的原理是使用事件代理的方式,进行添加的事件。原因如下:
(1)jsx中,既可以给dom元素,又可以给react组件进行添加事件。
注意: react中区分dom元素和react组件的方式是根据首字母的大小写判定的。
(2)jsx中,通过onClick挂载的每一个函数都可以控制在单个组件中,不会污染全局。
(3)jsx中,无论给多少个组件进行事件挂载,都是通过事件委托,给一个dom元素进行事件挂载的,效率高
(4)在react的生命周期中,当unmount时,会清除所有的相关事件,避免了内存泄露。
(5)在jsx中,也可以定义样式。见例子。
2、HTML中,添加行内onclick事件,不推荐,原因如下
(1)onclick事件是在全局环境下执行的,污染全局
(2)直接给很多dom元素添加onclick事件,影响网页性能。
(3)对于使用onclick的dom元素进行动态删除时,需要及时删除掉dom元素的事件,否则如果直接删除dom,容易造成内存泄露。
【9】 结合你的经验 , 谈谈 什么是 typescript
Typescript 是一个强类型的 JavaScript 超集,支持ES6语法,支持面向对象编程的概念,如类、接口、继承、泛型等。Typescript并不直接在浏览器上运行,需要编译器编译成纯Javascript来运行。
Vue
【1】能说下 vue-router 中常用的路由模式实现原理吗
hash 模式
1.location.hash 的值实际就是 URL 中#后面的东西 它的特点在于:hash 虽然出现 URL 中,但不会被包含在 HTTP 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
2.可以为 hash 的改变添加监听事件每一次改变 .(window.location.hash),都会在浏览器的访问历史中增加一个记录利用 hash 的以上特点,就可以来实现前端路由“更新视图但不重新请求页面”的功能了
兼容性好但是不美观
history 模式
利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。
这两个方法有个共同的特点:当调用他们修改浏览器历史记录栈后,虽然当前 URL 改变了,但浏览器不会刷新页面,这就为单页应用前端路由“更新视图但不重新请求页面”提供了基础。
虽然美观,但是刷新会出现 404 需要后端进行配置
【2】vue常用的修饰符?
.prevent: 阻止事件默认行为;
.stop: 阻止单击事件冒泡;
.self: 当事件发生在该元素本身而不是子元素的时候会触发;
.capture: 事件侦听,事件发生的时候会调用;
.once:事件只触发一次
【3】vue中v-if与v-show的区别以及使用场景
- 1.手段:v-if是通过控制dom节点的存在与否来控制元素的显隐;v-show是通过设置DOM元素的display样式,block为显示,none为隐藏;
- 2.编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换;
- 3.编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译; v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;
- 4.性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗;
使用场景
基于以上区别,因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
【4】v-if和v-for为什么避免一起用
v-if和v-for一起使用,v-for的优先级要高于v-if,先循环再控制显示隐藏,带来性能方面的浪费(每次渲染都会先循环再进行条件判断)
- 为了过滤一个列表中的项目(比如
v-for = "user in users" v-if = "user.isActive"
)。在这种情况下,请将users
替换为一个计算属性(比如activeUsers
),让其返回过滤后的列表。 - 为了避免渲染本应该被隐藏的列表(比如
v-for = "user in users" v-if = "shouldShowUsers"
)。这种情况下,请将v-if
移动至容器元素上(比如ul
,ol
)。
【5】使用过 Vue SSR 吗?说说 SSR
SSR 也就是服务端渲染,也就是将 Vue 在客户端把标签渲染成 HTML 的工作放在服务端完成,然后再把 html 直接返回给客户端。
优点:
SSR 有着更好的 SEO、并且首屏加载速度更快
缺点: 开发条件会受到限制,服务器端渲染只支持 beforeCreate 和 created 两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于 Node.js 的运行环境。
服务器会有更大的负载需求
【6】你都做过哪些 Vue 的性能优化
- 对象层级不要过深,否则性能就会差
- 不需要响应式的数据不要放到 data 中(可以用 Object.freeze() 冻结数据)
- v-if 和 v-show 区分使用场景
- computed 和 watch 区分使用场景
- v-for 遍历必须加 key,key 最好是 id 值,且避免同时使用 v-if
- 大数据列表和表格性能优化-虚拟列表/虚拟表格
- 防止内部泄漏,组件销毁后把全局变量和事件销毁
- 图片懒加载
- 路由懒加载
- 第三方插件的按需引入
- 适当采用 keep-alive 缓存组件
- 防抖、节流运用
- 服务端渲染 SSR or 预渲染
【7】keep-alive 使用场景和原理
keep-alive 是 Vue 内置的一个组件,可以实现组件缓存,当组件切换时不会对当前组件进行卸载。
- 常用的两个属性 include/exclude,允许组件有条件的进行缓存。
- 两个生命周期 activated/deactivated,用来得知当前组件是否处于活跃状态。
- keep-alive 的中还运用了 LRU(最近最少使用) 算法,选择最近最久未使用的组件予以淘汰
【8】Vue.set 方法原理
了解 Vue 响应式原理的同学都知道在两种情况下修改数据 Vue 是不会触发视图更新的
1.在实例创建之后添加新的属性到实例上(给响应式对象新增属性)
2.直接更改数组下标来修改数组的值
Vue.set 或者说是$set 原理如下
因为响应式数据 我们给对象和数组本身都增加了__ob__属性,代表的是 Observer 实例。当给对象新增不存在的属性 首先会把新的属性进行响应式跟踪 然后会触发对象__ob__的 dep 收集到的 watcher 去更新,当修改数组索引时我们调用数组本身的 splice 方法去更新数组
【9】多层父子组件通讯
有时候需要通讯的组件不是直接的父子组件,而是祖父和孙子,嵌套的层级比较多的情况下,需要传递的事件和属性比较多,会导致代码混乱,这个时候就需要用到Vue提供的更高阶方法:provide/inject
【10】父子组件通讯方式有哪些?
- 父组件 --> 子组件 : 自定义属性 props
- 子组件 --> 父组件 : 自定义事件 $emit
- EventBus
- Vuex
- v-model
v-model的方式:
- 父组件通过v-model绑定一个变量传给子组件
- 子组件通过props{value:{type:数据类型,defauult:默认值}} 接收
- 子组件通过$emit(‘input’,传给父组件绑定变量的值) 去改变父组件中v-model绑定的变量
【11】没有任何关系的组件传值
1.EventBus:
事件总线,使用
e
m
i
t
发送
,
使用
emit发送,使用
emit发送,使用on接收,可以较好的实现兄弟组件之间的数据通讯
2.再套一层,通过父组件;
3.vuex;
【12】简述Vue的生命周期
- beforeCreate() 创建前
created() 创建后 - beforeMount() 挂载前
mounted() 挂载后 - beforeUpdate() 更新前
updated() 更新后 - beforeDestory() 销毁前
destoryed() 销毁后
【13】Vue实现数据双向绑定的原理
采用数据劫持监听(Observer)结合订阅者(Watcher)的方式,通过 Object.defineProperty()来劫持属性中的setter和getter,监听到数据变化时发布消息给订阅者,触发相应监听回调
vue数据双向绑定,整合Observer,Watcher,Compile三者,通过Observer监听model数据变化,通过Compile解析指令,利用Watcher搭起二者之间的通信桥梁,
达到数据变化=>视图更新=>model变更双向绑定 的效果
视图变化影响数据----添加一个监听事件
数据变化影响视图----object.defineProperty()
【14】Vuex刷新页面数据丢失怎么解决?
方法一: 将vuex中的数据直接保存到浏览器缓存中(sessionStorage,localStorage,cookie)
方法二: 页面刷新时,再次请求远程数据,使之动态更新vuex数据
方法三: 在页面刷新前将vuex数据保存到sessionStorage中
//因为vuex数据是响应式的,一个位置改内容其他位置立马生效
【15】简单讲述vuex
vuex是专门为vue.js提供的一种状态管理模式,它采用的是集中式储存和管理所有组件的状态和数据,方便使用。
//5种属性:
- state (si de te) 数据
- getters (gai de si) 类似计算属性
- mutations (mu 忒神死)修改数据,同步,使用commit
- actions (啊 克神似)异步操作数据,使用dispatch
- module (眸丢死)模块化管理
【16】Vue 组件 data 为什么必须是函数
函数的好处就是每一次组件复用之后都会产生一个全新的data. 组件与组件之间各自维护自己的数据, 互不干扰
【17】nextTick 是做什么的
动态数据变化后,DOM还未及时更新的问题,用nextTick可以获取数据更新后最新的DOM变化(在created里面操作DOM)
注意: 数据更新和DOM更新是异步的
dom更新之后自动执行,可以在更新之后获取dom
【18】$route
和 $router
的区别
$router
为 VueRouter
实例,想要导航到不同 URL
,则使用 $router.push
方法
$route
为当前 router
跳转对象里面可以获取 name
、 path
、 query
、 params
等
【19】Virtual DOM(虚拟DOM)是什么?
Virtual DOM 其实就是一棵以 JavaScript 对象( VNode 节点)作为基础的树,用对象属性来描述节点,实际上它只是一层对真实 DOM 的抽象。最终可以通过一系列操作使这棵树映射到真实的DOM上
【20】为何需要Virtual DOM?
具备跨平台的优势
由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,所以使它具有了跨平台的能力,比如说浏览器平台、Weex、Node 等。
操作原生DOM慢,js运行效率高。
我们可以将DOM对比操作放在JS层,提高效率。 因为DOM操作的执行速度远不如Javascript的运算速度快,因此,把大量的DOM操作搬运到Javascript中,运用patching算法来计算出真正需要更新的节点,最大限度地减少DOM操作,从而显著提高性能。
Virtual DOM 本质上就是在 JS 和 DOM 之间做了一个缓存。
可以类比 CPU 和硬盘,既然硬盘这么慢,我们就在它们之间加个缓存:既然 DOM 这么慢,我们就在它们 JS 和 DOM 之间加个缓存。CPU(JS)只操作内存(Virtual DOM),最后的时候再把变更写入硬盘(DOM)
提升渲染性能
Virtual DOM的优势不在于单次的操作,而是在大量、频繁的数据更新下,能够对视图进行合理、高效的更新。
【21】Virtual DOM的diff算法
Virtual DOM因为是纯粹的JS对象,所以操作它会很高效,但是Virtual DOM的变更最终会转换成DOM操作,为了实现高效的DOM操作,一套高效的虚拟DOM diff算法显得很有必要。
diff算法包括一下几个步骤:
- 1.用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中
- 2当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较(diff),记录两棵树差异
-3 把2所记录的差异应用到步骤1所构建的真正的DOM树上(patch),视图就更新了
diff算法是通过同层的树节点进行比较而非对树进行逐层搜索遍历的方式,所以时间复杂度只有O(n),是一种相当高效的算法。
【22】修改第三方库的样式
/deep/`
【23】Computed和Watch
Computed
本质是一个具备缓存的watcher,依赖的属性发生变化就会更新视图。 适用于计算比较消耗性能的计算场景。当表达式过于复杂时,在模板中放入过多逻辑会让模板难以维护,
可以将复杂的逻辑放入计算属性中处理。
Watch
没有缓存性,更多的是观察的作用,可以监听某些数据执行回调。当我们需要深度监听对象中的属性时,可以打开deep:true
选项,这样便会对对象中的每一项进行监听。
这样会带来性能问题,优化的话可以使用字符串形式
监听。
【24】Vuex和Redux区别
redux是一个范用的库,可以单独使用。而vuex是专门用来配合vue使用的。
Vuex触发方式有两种commit同步和dispatch异步;redux同步和异步都使用dispatch;
Vuex和state统一存放,方便理解;reduxstate依赖所有reducer的初始值;
Vuex有getter,目的是快捷得到state;redux没有这层
Redux使用的是不可变数据,而Vuex的数据是可变的。Redux每次都是用新的state替换旧的state,而Vuex是直接修改;
【25】vue双向数据绑定时效
1、如果data里面只定义了对象,对象里面的键值没有,getter/setter函数无法监听到数据变化,会导致此现象发生
解决办法为调用vue的set函数,设置需要绑定的键值:
2、如果数据层次太多,例如数组包对象,对象包数组,多层嵌套,会出现v-if调用失效,页面不重新渲染问题;
解决办法为在数据处理完成之后调用$forceUpdate()发放:
前端 iOS 和 Android 的兼容问题
JavaScript兼容
一、javascript 兼容
1、iOS 日期的兼容
ios 下 new Date('2020-03-11 00:00:00')
不生效,需要对日期进行 date.replace(/-/g, '/')
处理
2、iOS 的 beforeunload 事件的兼容
ios 下 beforeunload
事件废弃了,需要使用 pagehide
事件替代。
3、Android 和 iOS 下,表单的 input 事件和 change 事件
ios11之后,有些情况使用 input 事件 ios 自带的输入法,当选择拼音输入时会自动输入多个字符,这是因为有时 ios 对 input 事件不兼容导致的,使用 change 事件即可解决这个问题。
CSS兼容
二、css 兼容
1、Android 下 line-height 和 height 的兼容
对于一般PC浏览器以及iOS设备的浏览器表现就是我们想要的居中效果,但是大部分 Android 设备的浏览器文字都会稍微向上偏离。
结合行高、对齐的关系 和 伪元素,可以给当前元素添加以下样式来尝试解决该问题:
2、Android 下,margin-top 失效
给其父元素添加 padding-top
,代替该元素的 margin-top
。
3、Android 下页面出现横向滚动条,iOS 正常
给该元素设置:
overflow-x: hidden;
4、Android 下给页面设置 fixed 固定定位无效,iOS 正常
Android 下给页面设置 fixed 固定定位无效,iOS 正常
给该元素设置:
position: fixed;
left: 0;
top: 0;
5、iOS 中字体加粗无效 Android 正常
这是我遇到的一个问题,当时去掉 font-family
就好了。13、13、iOS 下拉页面时,自定义的头部导航栏消失了
因为,iOS 自带的回弹特效不会触发 scroll 事件,也就导致 scrollTop 的值为 undefined。需要做一个兼容:默认是 0 就好了——let scrollTop = e.target.scrollTop || 0
。
HTML兼容
- 三、html 兼容
- 1、iOS 下,会将数字当成电话号码,导致变色