js 笔记总结
盒子塌陷的原因?解决方式
原因: 1. 浮动导致的塌陷,浮动会脱落标准流
2. 嵌套的两个盒子,子盒子设置margin-top会导致父盒子一下下移
解决方法:第一种情况 1 清除浮动; 2 给父盒子加高度;
3 给父元素添加overflow:hidden
第二种情况 1 给父元素加上边框; 2 给父元素添加overflow:hidden
不定宽高的 div 水平垂直居中
答: 1、使用定位和translate来实现
div{
position:absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
2、使用flex来实现
div {
display: flex;
justify-content:center; //子元素水平居中
align-items:center; //子元素垂直居中
}
3、使用定位和margin来实现
#box {
width: 100px;
height: 100px;
position: relative;
}
#content {
width: 50px;
height: 50px;
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
}
css 写一个三角形
答: div {
width: 0px;
height: 0px;
border: 30px solid transparent;
border-left-color: rgb(233, 42, 191)
}
不设置宽高,设置边框中一个边框大小及颜色,其他三边框为透明色
css 选择器的优先级
答: !important>行内样式>id选择器>类/属性/伪类选择器>伪元素/标签选择器>通配符选择器*
px、em 和 rem 的区别
答: px 是固定单位,
em 是相对单位,相当于当前文字的大小,如果没有就找父元素
rem 也是相对单位,相对于html的fontsize的大小
rem 布局的原理
答:rem是css的相对单位,rem缩放是相对根元素字体大小.
rem布局的本质是等比缩放,一般是基于宽度。
rem会配合媒体查询(或js动态获取屏幕宽度)来一起使用,来实现屏幕的适配。
什么是重绘和重排
答:
重排: 当DOM元素影响了元素的几何属性(例如宽和高),浏览器需要重新计算元素的几何属性,同样其它元素的几何属性也会和位置也会因此受到影响。浏览器会使渲染树中受到影响的部分失效,并重新构造渲染树。这个过程称为“重排”。
重绘: 完成重排后,浏览器会重新绘制受影响的部分到屏幕上中,该过程称为“重绘”。
当我们改变DOM的大小,增加删除都会导致重排,当给DOM元素改变颜色的时候,会导致重绘,重排一定会重绘,重绘不会重排。重排会影响性能,所以我们尽快能的减少重排的操作
flex 常用的容器属性
答:
1. flex-direction: 设置容器中的主轴方向
2. flex-wrap: 项目在主轴方向上是否换行显示
3. justify-content: 设置容器中的项目在主轴上的对齐方式
4. align-items: 单行项目在侧轴上的排列方式
5. align-content: 多行项目侧轴上的对齐方式
6. flex-flow: 是flex-direction和flex-wrap的合写, 默认值为row nowrap
如何设置比 12px 更小的字体
p {
font-size:12px;
-webkit-transform:scale(0.8);
}
H5 新增了那些特性
答:
1. 语义化标签: header nav section article aside footer
2. 多媒体标签: video audio
3. 表单控件: number search email tel date file time url
4. 本地离线存储 localStorage 长期存储数据,改变浏览器数据不会丢失
sessionStorage 浏览器关闭数据会丢失
5. 自定义属性 data-*
6. 画布 Canvas
7. 拖拽释放 (Drap and Drap) API ondrop
8. 新的技术文本 webworker
9. 地理位置 (Geolocation) API
C3 新增了那些特性
答:
1. 圆角 border-radius
2. 盒子模型 box-sizing
3. 阴影 box-shadow 盒子阴影 text-shadow 文字阴影
4. 过渡 transition
5. 2D转换transform translate(平移) scale(缩放) skew(斜切) rotate(旋转) transform-origin 控制转换中心点
6. 3D转换 perspective(透视距) transform-style(3D控件效果)
7. 渐变 linear-gradient radial-gradient
8. 弹性布局 flex
9. 媒体查询 @media screen and () {...}
10. 边框图片 border-image
11. 自定义动画 @keyframes animation
12. 颜色 新增RGBA HSLA模式
13. 背景 background-size background-origin background-clip
js 的数据类型有哪些
答: 简单数据类型: number string boolean undefined null
复制数据类型: object function array
typeof 返回的数据类型
答: number string boolean undefined object function
特殊情况:
typeof null -->object
typeof array -->object
typeof typeof 任何类型 -->string
返回 false 的情况有哪些
答: 0 "" null false NaN undefined 不成立的表达式
对 this 的理解
答: this是个关键字,它的指向和函数的调用方式有关
1. 函数调用模式, this指向window
2. 构造函数调用模式, this指向新创建的实例对象
3. 方法调用模式, this指向调用方法的对象
4. 上下文调用模式, call和apply方法中, this指向方法内的第一个参数
bind方法中, bind创建的新函数的this绑定为bind方法中新的函数
5. 在事件处理函数中,this指向触发事件的当前元素
6. 定时器中,this指向window
7. 箭头函数中没有this指向问题,它的this和外层作用域的this保持一致
8. 匿名函数中的this总是指向window
new 操作符做了什么
答: 1. 创建一个新对象
2. 函数内部的this指向这个对象
3. 执行函数体
4. 自动返回这个函数
==和===的区别
答:== 表示是相等,只比较内容
=== 表示是全等,不仅比较内容,也比较类型
null 和 undefined 的区别
答:null 表示空值 没有获取到。typeof null 返回"object"
undefined 表示未定义,声明没有值。typeof undefined 返回"undefined"
localStorage、sessionStorage 和 cookie 的区别
答: 共同点: 都可以用来存储数据。
区别:
1. 请求不同:
cookie 数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。
sessionStorage 和 localStorage不会自动把数据发给服务器,仅在本地保存。
2. 存储大小限制也不同:
cookie 数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。
sessionStorage 和 localStorage虽然也有存储大小的限制,但比cookie大得多,sessionStorage和localStorage约5M 。
3. 数据有效期不同:
sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;
localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;
cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
js 的运行机制是什么
答:js是单线程执行的,页面加载时,会自上而下执行主线程上的同步任务,当主线程代码执行完毕时,才开始执行在任务队列中的异步任务。具体如下
1.所有同步任务都在主线程上执行,形成一个执行栈。
2.主线程之外,还存在一个"任务队列(eventloop队列或者消息队列)"。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
3.一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。哪些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
4.主线程不断重复上面的第三步。
怎么理解面向对象
答:1、面向对象是一种软件开发的思想和面向过程是相对应的,就是把程序看作一个对象,将属性和方法封装其中,以提高代码的灵活性、复用性、可扩展性。
2、面向对象有三大特性:封装、继承、多态。
封装:把相关的信息(无论数据或方法)存储在对象中的能力
继承:由另一个类(或多个类)得来类的属性和方法的能力
多态:编写能以多种方法运行的函数或方法的能力
3、js中对象是一个无序的数据集合或者也可以说是属性和方法的集合,可以动态的添加属性可方法。
4、js是基于对象,但是也使用了嵌入了面向对象的思想,可以实现继承和封装,这样也可以提供代码的灵活性和复用性。
那些情况会得到伪数组
1、参数 arguments,
2、DOM 对象列表(比如通过 document.getElementsByTags 得到的列表)、childNodes也是伪数组
3、jQuery 对象(比如 $("div"))
let、const、var 的区别
1、var声明变量存在提升(提升当前作用域最顶端),let和const是不存在变量提升的情况
2、var没有块级作用,let和const存在块级作用域
3、var允许重复声明,let和const在同一作用域不允许重复声明
4、var和let声明变量可以修改,const是常量不能改变
怎么理解事件循环机制
1、JavaScript 是一门单线程语言.单线程可能会出现阻塞的情况,所js分了同步任务和异步任务。
2、同步和异步任务分别进入不同的执行环境,同步的进入主线程,即主执行栈,异步的进入 Event Queue(事件队列) 。主线程内的任务执行完毕为空,会去 Event Queue 读取对应的任务,推入主线程执行。 上述过程的不断重复就是我们说的 Event Loop (事件循环)。
什么是作用域链
1、作用域:分全局作用域和局部作用域
2、在访问一个变量时,首先在当前作用域中找,如果找不到再到外层作用域中找,这样一层一层的查找,就形成了作用域链。
for in 和 for of 的区别
1、for…in是遍历数组、对象的key下标
2、for…of是遍历数组的value属性
例如:
let arr = ["a","b"];
1)for (let key in arr) {
console.log(key); //0 1
}
2)for (let value of arr) {
console.log(value); //a b
}
值类型和引用类型的区别
1、值类型
1)基本类型数据是值类型
2)保存与复制的是值本身
3)使用typeof检测数据的类型
2、引用类型
1)保存与复制的是指向对象的一个指针
2)使用instanceof检测数据类型
3)使用 new() 方法构造出的对象是引用型
什么是深拷贝什么是浅拷贝
答: 浅拷贝: 拷贝对象的一层属性,如果对象里面还有对象,拷贝的是地址, 两者之间修改会有影响,适用于对象里面属性的值是简单数据类型的.
深拷贝: 拷贝对象的多层属性,如果对象里面还有对象,会继续拷贝,使用递归去实现.
如何实现深拷贝和浅拷贝
答: 浅拷贝: var obj = {
class: "UI",
age: 20,
love: "eat",
};
function getObj(obj) {
var newObj = {};
for (var k in obj) {
newObj[k] = obj[k];
}
return newObj;
}
var obj2 = getObj(obj);
console.log(obj2);
深拷贝: var obj = {
class: "前端",
age: 26,
love: {
friuts: "apple",
meat: "beef",
},
};
function getObj(obj) {
var newObj = {};
for (var k in obj) {
/* if (typeof obj[k] == 'object') {
newObj[k] = getObj(obj[k])
} else {
newObj[k] = obj[k]
} */
newObj[k] = typeof obj[k] == "object" ? getObj(obj[k]) : obj[k];
}
return newObj;
}
var obj2 = getObj(obj);
console.log(obj2);
对闭包的理解?并能举出闭包的例子
答: 闭包 函数和声明该函数的词法环境的组合(两个嵌套关系的函数,内部函数可以访问外部函数定义的变量)
闭包的优点:1、形成私有空间,避免全局变量的污染
2、持久化内存,保存数据
闭包的缺点:1、持久化内存,导致内存泄露
解决:1、尽快避免函数的嵌套,以及变量的引用
2、执行完的变量,可以赋值null,让垃圾回收机制,进行回收释放内存(当不在引用的变量,垃圾回收机制就会回收)
例: 点击li获取当前下标
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>
var lis = document.querySelectorAll('li')
for (var i = 0; i < lis.length; i++) {
(function (j) {
lis[j].onclick = function () {
console.log(j)
}
})(i)
}
什么是原型和原型链
答: 原型: 函数都有prototype属性,这个属性的值是个对象,称之为原型
原型链: 对象都有__proto__属性,这个属性指向它的原型对象,原型对象也是对象,也有__proto__属性,指向原型对象的原型对象,这样一层一层形成的链式结构称为原型链.
call、apply 和 bind 的区别
答: 1. call和apply方法都可以调用函数,方法内的第一个参数可以修改this的指向
2. call方法可以有多个参数,除了第一个参数,其他参数作为实参传递给函数
apply方法最多有2个参数,第二个参数是个数组或伪数组,数组里面的每一项作为实参传递给函数
3. bind方法不能调用函数,它会创建一个副本函数,并且绑定新函数的this指向bind返回的新的函数
es6-es10 新增常用方法
答:
es6:
1、let、const
2、解构赋值 let { a, b } = { a: 1, b: 2 }
3、箭头函数 ()=>{}
4、字符串模板 ``
5、扩展运算符 ...arr
6、数组方法:map、filter、some等等
7、类:class关键字
8、promise 主要用于异步计算
9、函数参数默认值 fn(a = 1) {}
10、对象属性简写 let a = 1; let obj = {a}
11、模块化:import--引入、exprot default--导出
es7:
1、includes()方法,用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回true,否则返回false。
es8:
1、async/await
es9:
1、Promise.finally() 允许你指定最终的逻辑
es10:
1、数组Array的flat()和flatmap()
flat:方法最基本的作用就是数组降维
var arr1 = [1, 2, [3, 4]];
arr1.flat();
// [1, 2, 3, 4]
var arr3 = [1, 2, [3, 4, [5, 6]]];
arr3.flat(2);
// [1, 2, 3, 4, 5, 6]
//使用 Infinity 作为深度,展开任意深度的嵌套数组
arr3.flat(Infinity);
// [1, 2, 3, 4, 5, 6]
flatmap:方法首先使用映射函数映射(遍历)每个元素,然后将结果压缩成一个新数组
怎么理解函数的防抖和节流
答:
1、定义:
防抖: 就是指触发事件后在n秒内函数只能执行一次,如果在n秒内又触发了事件,则会重新计算函数执行时间。
例如:设定1000毫秒执行,当你触发事件了,他会1000毫秒后执行,但是在还剩500毫秒的时候你又触发了事件,那就会重新开始1000毫秒之后再执行
节流: 就是指连续触发事件但是在设定的一段时间内中只执行一次函数。
例如:设定1000毫秒执行,那你在1000毫秒触发在多次,也只在1000毫秒后执行一次
2、防抖和节流的实现:
<body>
<input type="text" class="ipt" />
<script>
var timerId = null
document.querySelector('.ipt').onkeyup = function () {
// 防抖
if (timerId !== null) {
clearTimeout(timerId)
}
timerId = setTimeout(() => {
console.log('我是防抖')
}, 1000)
}
document.querySelector('.ipt').onkeyup = function () {
// 节流
console.log(2)
if (timerId !== null) {
return
}
timerId = setTimeout(() => {
console.log('我是节流')
timerId = null
}, 1000)
}
</script>
</body>
异步函数有哪些
JavaScript 中常见的异步函数有:定时器,事件和 ajax 等
伪数组有哪些
1、参数 arguments,
2、DOM 对象列表(比如通过 document.getElementsByTags 得到的列表)、childNodes也是伪数组
3、jQuery 对象(比如 $("div"))
真数组和伪数组的区别
伪数组:
1、拥有length属性
2、不具有数组的方法
3、伪数组是一个Object,真数组是Array
4、伪数组的长度不可变,真数组的长度是可变的
伪数组怎么转真数组
1、let newArr = Array.protype.slice.call(伪数组)
2、let newArr = Array.from(伪数组),ES6的新语法
3、let newArr = [...伪数组],使用扩展运算符,也是ES6的语法
数组如何进行降维(扁平化)
1、利用Array.some方法判断数组中是否还存在数组,es6展开运算符连接数组
let arr = [1,2,[3,4]]
while (arr.some(item => Array.isArray(item))) {
arr = [].concat(...arr);
}
2、使用数组的concat方法
let arr = [1,2,[3,4]]
let result = []
result = Array.prototype.concat.apply([], arr)
3、 使用数组的concat方法和扩展运算符
var arr = [1,2,[3,4]]
var result = []
result = [].concat(...arr)
4、es6中的flat函数也可以实现数组的扁平化
let arr = [1,2,['a','b',['中','文',[1,2,3,[11,21,31]]]],3];
let result = arr.flat( Infinity )
注意:flat方法的infinity属性,可以实现多层数组的降维
ajax 笔记总结
什么是事件流
答: 事件流是指事件传播的顺序, (由事件捕获) => (目标事件) => 事件冒泡;
如何阻止冒泡和默认行为
答: 阻止冒泡和捕获 e.stopPropagation()
阻止默认行为 e.preventDefault() return false
注意:addEventListener注册的事件,在高浏览器版本中,return false将没有效果,必须要用事件对象
原生注册事件的方式有哪些?区别是什么
答: 注册方式
1. on + 事件名称
2. addEventListener
区别:
1. 使用on注册事件,同一个元素只能注册一个同类型事件,否则会覆盖。
2. addEventListener可以注册同一事件多次,不会被覆盖。
http 和 https 的区别
答:
1.https协议需要到CA申请证书,一般免费证书较少,因而需要一定费用。
2.http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl/tls加密传输协议。
3.http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4.http的连接很简单,是无状态的;HTTPS协议是由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
get 和 post 的区别
答: get
1. 在url后面拼接参数,只能以文本的形式传递数据
2. 传递的数据量小,4KB左右
3. 安全性低, 会将数据显示在地址栏
4. 速度快,通常用于安全性要求不高的请求
5. 会缓存数据
post
1. 安全性比较高
2. 传递数据量大,请求对数据长度没有要求
3. 请求不会被缓存,也不会保留在浏览器历史记录里
项目中常遇到的状态码有哪些
答: 200 请求成功, 2开头的异步表示请求成功
304 请求被允许,但请求内容没有改变, 3开头的一般请求完成
400 请求格式错误, 4开头的一般表示请求错误
404 请求的资源(网页)不存在,
500 内部服务器错误, 5开头的一般都是指服务器错误
jsonp 的原理?以及优缺点
答: 原理: 利用script标签的src属性具有天然可跨域的特性,由服务端返回一个预先定义好的Javascript函数的调用,并且将服务器数据以该函数参数的形式响应给浏览器.
优点: 完美解决在测试或者开发中获取不同域下的数据,用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
缺点:Jsonp只支持get请求而不支持post 请求,也即是说如果想传给后台一个json 格式的数据,此时问题就来了, 浏览器会报一个http状态码41错误,告诉你请求格式不正确.
Json 字符串和 json 对象怎么相互转换
答: JSON对象转JSON字符串: json.stringify(对象)
JSON字符串转JSON对象: json.parse(字符串)
什么是同源策略?怎么解决跨域问题
答: 同源策略: 同源策略是浏览器的一种安全策略, 所谓同源是指域名、协议、端口完全相同,不同源则跨域。
解决跨域的方法:
1. 通过jsonp跨域
2. 跨域资源共享(CORS Access-Control-Allow-Origin: http://api.bob.com)
3. nginx代理跨域
怎么理解同步和异步
1、javascript是单线程。单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。于是就有一个概念——任务队列。
2、所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行。
你对 WebSocket 了解哪些
答: WebSocket 是HTML5一种新的协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在TCP之上,同HTTP一样通过TCP来传输数据,但是它和HTTP最大不同是:
1. WebSocket是一种双向通信协议,在建立连接后,WebSocket服务器和Browser/Client Agent都能主动的向对方发送或接收数据,就像Socket一样;
2. WebSocket需要类似TCP的客户端和服务器端通过握手连接连接成功后才能相互通信。
在地址栏输入网址,到数据返回的过程是什么?
答: 1. 输入url地址后,首先进行DNS解析,将相应的域名解析为IP地址。
2. 根据IP地址去寻找相应的服务器。
3. 与服务器进行TCP的三次握手,建立连接。
4. 客户端发送请求,找到相应的资源库。
5. 客户端拿到数据,进行相应的渲染。
原生 ajax 请求的步骤
答:1.创建异步对象 var xhr = new HTMLHttpRequest()
2.设置请求行 xhr.open()
3.设置请求头 xhr.setRequestHeader()
get请求没有请求头
post请求多一个关键头信息
Content-type: application/x-www-form-urlencoded
4.设置请求体 xhr.send get请求没有请求体,参数为null
5.监视异步对象的状态变化 xhr.onreadystatechange(){}
怎么理解三次握手
字段 含义
URG 紧急指针是否有效。为1,表示某一位需要被优先处理
ACK 确认号是否有效,一般置为1。
PSH 提示接收端应用程序立即从TCP缓冲区把数据读走。
RST 对方要求重新建立连接,复位。
SYN 请求建立连接,并在其序列号的字段进行序列号的初始值设定。建立连接,设置为1
FIN 希望断开连接。
1、三次握手
第一次握手:建立连接时,客户端发送syn包到服务器,等待服务器确认。
第二次握手:服务器收到syn包,必须确认客户的SYN,同时自己也发送一个SYN包(syn=y)到客户端
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK,此包发送完毕,客户端和服务器进入(TCP连接成功)状态,完成三次握手
(通俗:主机1告诉主机2,我可以向你请求数据吗。主机2告诉主机1,可以请求数据。主机1告诉主机2,那我来请求数据了,请求完成,实现三次握手)
怎么理解四次挥手
1、四次挥手
第一次分手:主机1(可以使客户端,也可以是服务器端)向主机2发送一个FIN报文段;此时,主机1进入FIN_WAIT_1状态;这表示主机1没有数据要发送给主机2了。
第二次分手:主机2收到了主机1发送的FIN报文段,向主机1回一个ACK报文段,主机1进入FIN_WAIT_2状态;主机2告诉主机1,我“同意”你的关闭请求。
第三次分手:主机2向主机1发送FIN报文段,请求关闭连接,同时主机2进入LAST_ACK状态。
第四次分手:主机1收到主机2发送的FIN报文段,向主机2发送ACK报文段,然后主机1进入TIME_WAIT状态;主机2收到主机1的ACK报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。
(通俗:主机1告诉主机2,我没有数据要发送了,希望断开连接。主机2接到请求后说,同意断开。主机2告诉主机1可以关闭连接了。主机1接到可以关闭的指令后,关闭连接,四次挥手完成)
vue 笔记总结
怎么理解 mvvm 这种设计模式
Model–View–ViewModel (MVVM) 是一个软件架构设计模式,是一种简化用户界面的事件驱动编程方式。
MVVM
M Model 模型 指的是数据层
V View 视图 指的是用户页面
VM ViewModel 视图模型
视图模型是MVVM模式的核心,它是连接view和model的桥梁,MVVM实现了view和model的自动同步,当model的属性改变时,我们不用自己手动操作DOM元素,来改变view的显示,反之亦然,我们称之为数据的双向绑定。
v-if 和 v-show 的区别,使用场景区别
v-if和v-show看起来似乎差不多,当条件不成立时,其所对应的标签元素都不可见,但是这两个选项是有区别的:
1、v-if在条件切换时,会对标签进行适当的创建和销毁,而v-show则仅在初始化时加载一次,因此v-if的开销相对来说会比v-show大。
2、v-if是惰性的,只有当条件为真时才会真正渲染标签;如果初始条件不为真,则v-if不会去渲染标签。v-show则无论初始条件是否成立,都会渲染标签,它仅仅做的只是简单的CSS(display)切换。
3、 v-if适用于不需要频繁切换元素显示和隐藏的情况
v-show适用于需要频繁切换元素的显示和隐藏的场景。
vue 事件修饰符和按键修饰符有哪些
事件修饰符:
.prevent 阻止事件默认行为
.stop 阻止事件冒泡
.capture 设置事件捕获机制
.self 只有点击元素自身才能触发事件
.once 事件只触发一次
按键修饰符:
.tab
.enter
.esc
.space
.delete(捕获"删除"和"空格"键)
.up
.down
.left
.right
v-model 修饰符有哪些
.trim 去除首尾空格
.lazy 只在输入框失去焦点或按回车键时更新内容,不是实时更新
.number 将数据转换成number类型(原本是字符串类型)
v-for 中为什么要加 key,原理是什么
作用:
1.key的作用主要是为了高效的更新虚拟DOM,提高渲染性能。
2.key属性可以避免数据混乱的情况出现。
原理:
1.vue实现了一套虚拟DOM,使我们可以不直接操作DOM元素只操作数据,就可以重新渲染页面,而隐藏在背后的原理是高效的Diff算法
2.当页面数据发生变化时,Diff算法只会比较同一层级的节点;
3.如果节点类型不同,直接干掉前面的节点,再创建并插入新的节点,不会再比较这个节点后面的子节点;
如果节点类型相同,则会重新设置该节点属性,从而实现节点更新
4.使用key给每个节点做一个唯一标识,Diff算法就可以正确失败此节点,"就地更新"找到正确的位置插入新的节点。
v-for 和 v-if 的优先级
v-for优先级高于v-if
如果同时出现v-for和v-if,无论判断条件是否成立,都会执行一遍v-for循环,这样浪费性能,所以要尽可能的避免两者一起使用。
插槽(solt)
1、什么是插槽
1.1 插槽(Slot)是Vue提出来的一个概念,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。
1.2 插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制
2、插槽使用
2.1 默认插槽 在子组件中写入slot,slot所在的位置就是父组件要显示的内容
2.2 具名插槽 在子组件中定义了三个slot标签,其中有两个分别添加了name属性header和footer
在父组件中使用template并写入对应的slot名字来指定该内容在子组件中现实的位置
2.3 作用域插槽 在子组件的slot标签上绑定需要的值
<slot :data="user"></slot>
在父组件上使用slot-scope=“user”来接收子组件传过来的值
组件中的 data 为什么是函数,new Vue 实例里,data 可以直接是一个对象
1、组件是用来复用的,组件中的data写成一个函数,数据以函数返回值形式定义,函数有独立的作用域,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
2、而单纯的写成对象形式,由于对象是引用类型,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。
3、因为new vue里面的代码是不存在复用的情况,所以可以写成对象形式
vue 中怎么给 data 动态添加数据,为什么要这样写
答: 1.官方文档定义:如果在vue实例创建之后添加新的属性到实例上,她不会触发视图更新。
2.原因:受现代JavaScript的限制,vue不能检测到对象属性的添加或删除。由于vue会在初始化实例是对属性执行getter/setter转换过程(使用Object.defineProperty进行数据的劫持)。所以属性必须在data对象上存在才能让vue转换它,这样才能让它是响应的。
方法:1.this.$set(对象名,属性,值)或 Vue.set(对象名,属性,值)
2.Object.assign(target,source)添加多个属性
例如:
const target = {a:1, b:2}
const source = {b:4, d:5}
const returnedTarget = Object.assign(target,source)
console.log(returnedTarget); //{ a: 1, b: 4, c: 5 }
computed 和 watch 的区别是什么
计算属性computed:
1、支持缓存,只有依赖数据发生改变,才会重新进行计算
2、不支持异步,当computed内有异步操作时无效,无法监听数据的变化
3、如果computed需要对数据修改,需要写get和set两个方法,当数据变化时,调用set方法。
4、computed擅长处理的场景:一个数据受多个数据影响,例如购物车计算总价
侦听属性watch:
1、不支持缓存,数据变,直接会触发相应的操作;
2、watch支持异步;监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
3、immediate:组件加载立即触发回调函数执行
4、deep:true的意思就是深入监听,任何修改obj里面任何一个属性都会触发这个监听器里的 handler方法来处理逻辑
5、watch擅长处理的场景:一个数据影响多个数据,例如搜索框
组件化和模块化的区别
1、组件相当于库,把一些能在项目里或者不同类型项目中可复用的代码进行工具性的封装。
2、模块相应于业务逻辑模块,把同一类型项目里的功能逻辑进行进行需求性的封装。
怎么理解 vue 中的虚拟 DOM
原理:
用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象;
diff 算法 — 比较两棵虚拟 DOM 树的差异;
pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
好处:
1、性能优化
2、无需手动操作DOM
3、可以跨平台,服务端渲染等
怎么理解 vue 的生命周期
vue的生命周期:vue实例从创建到销毁的全过程,这个过程可以分为3个阶段
第一阶段:初始化阶段 创建vue实例,准备数据,准备模板,渲染视图
第二阶段:数据更新阶段 当数据变化时,会进行新旧DOM的对比,对比出差异的部分,进行差异化更新。
第三阶段:实例销毁阶段 当vm.$destroy()被调用,vue实例就会被销毁,释放相关资源,此时再更新数据,视图不会再变化。
vue 钩子函数有哪些,有哪些使用的场景
1、各阶段包含钩子: beforeCreate 在data数据注入到vm实例之前,此时vm身上没有数据 created 在data数据注入到vm实例之前,此时vm身上有数据 beforeMount 生成的结构替换视图之前,此时DOM还没更新 mounted 生成的结构替换视图之前,此时DOM已经更新完成 beforeUpdate 数据变化了,dom更新之前 updated 数据变化了,dom更新之后 activated 被keep-alive缓存的组件激活时调用 deactivated 被keep-alive缓存的组件停用时调用 beforeDestroy 实例销毁,是否资源之前 destroyed 实例销毁,是否资源之后 这些钩子函数会在vue的生命周期的不同阶段,自动被vue调用2、常用的钩子函数使用场景: beforeCreate 做loading的一些渲染 created 结束loading, 发送数据的请求,拿数据 mounted 可以对dom进行操作 updated 监视数据的更新 beforeDestroy 销毁非vue资源,防止内存泄漏,例如清除定时器 activated 当我们运用了组件缓存时,如果想每次切换都发送一次请求的话,需要把请求函数写在activated中,而写在created或mounted中其只会在首次加载该组件的时候起作用。
Vue 的父组件和子组件生命周期钩子函数执行顺序
1、Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分: 1)加载渲染过程 父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted 2)子组件更新过程 父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated 3)父组件更新过程 父 beforeUpdate -> 父 updated 4)销毁过程 父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
vue 组件传值的方式
1、父传子
通过props传递
父组件: <child :list = 'list' />
子组件: props['list'],接收数据,接受之后使用和data中定义数据使用方式一样
2、子传父
在父组件中给子组件绑定一个自定义的事件,子组件通过$emit()触发该事件并传值。
父组件: <child @receive = 'getData' />
getData(value){value就是接收的值}
子组件: this.$emit('receive',value)
3、兄弟组件传值
通过中央通信 let bus = new Vue()
A组件:methods :{
sendData(){
bus.$emit('getData',value)
} 发送
B组件:created(){
bus.$on(‘getData’,(value)=>{value就是接收的数据})
} 进行数据接收
$nextTick 是什么?原理是什么?使用的场景
背景:
1、简单来说,Vue 在修改数据后,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。
定义:
2、在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。nextTick(),是将回调函数延迟在下一次dom更新数据后调用,简单的理解是:当数据更新了,在dom中渲染后,自动执行该函数。
原理
3、vue用异步队列的方式来控制DOM更新和nextTick回调先后执行。
简单来说,nextTick是做了promise加上setTimeout的封装,利用事件换行机制,来确保当nextTick出现时,都是在我们所有操作DOM更新之后的。
场景:
4.1 点击获取元素宽度
4.2 使用swiper插件通过 ajax 请求图片后的滑动问题
4.3 点击按钮显示原本以 v-show = false 隐藏起来的输入框,并获取焦点
vue 是如何获取 DOM
1、先给标签设置一个ref值,再通过this.$refs.domName获取,这个操作要在mounted阶段进行。2、例如:<template> <div ref="test"></div></template>mounted(){ const dom = this.$refs.test }
v-on 可以监听多个方法吗
可以例如:<input type="text" v-on="{ input:onInput,focus:onFocus }">
谈谈你对 keep-alive 的了解
1、keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染2、一般结合路由和动态组件一起使用,用于缓存组件3、对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated4、提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;例如:<keep-alive include="a"> <component> <!-- name 为 a 的组件将被缓存! --> </component></keep-alive><keep-alive exclude="a"> <component> <!-- 除了 name 为 a 的组件都将被缓存! --> </component></keep-alive>
谈谈你对 slot 的了解
1、什么是插槽 1.1 插槽(Slot)是Vue提出来的一个概念,正如名字一样,插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。 1.2 插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制 2、插槽使用 2.1 默认插槽 在子组件中写入slot,slot所在的位置就是父组件要显示的内容 2.2 具名插槽 在子组件中定义了三个slot标签,其中有两个分别添加了name属性header和footer 在父组件中使用template并写入对应的slot名字来指定该内容在子组件中现实的位置 2.3 作用域插槽 在子组件的slot标签上绑定需要的值<slot :data="user"></slot> 在父组件上使用slot-scope=“user”来接收子组件传过来的值
vue 中动态组件如何使用
1、在某个中使用 is 特性来切换不同的组件: <component :is="TabComponent"></component> TabComponent:已注册组件的名字
v-model 的原理是什么
1、v-model主要提供了两个功能,view层输入值影响data的属性值,属性值发生改变会更新层的数值变化.2、v-model指令的实现: 3.1 v-bind:绑定响应式数据 3.2 触发input事件并传递数据 (核心和重点)3、其底层原理就是(双向数据绑定原理): 3.1 一方面modal层通过defineProperty来劫持每个属性,一旦监听到变化通过相关的页面元素更新。 3.2 另一方面通过编译模板文件,为控件的v-model绑定input事件,从而页面输入能实时更新相关data属性值。
vue 响应式的原理
1、原理:
Vue 的响应式原理是核心是通过 ES5 的 Object.defindeProperty 进行数据劫持,然后利用 get 和 set 方法进行获取和设置,data 中声明的属性都被添加到了get和set中,当读取 data 中的数据时自动调用 get 方法,当修改 data 中的数据时,自动调用 set 方法,检测到数据的变化,会通知观察者 Wacher,观察者 Wacher自动触发重新render 当前组件(子组件不会重新渲染),生成新的虚拟 DOM 树,Vue 框架会遍历并对比新虚拟 DOM 树和旧虚拟 DOM 树中每个节点的差别,并记录下来,最后,加载操作,将所有记录的不同点,局部修改到真实 DOM 树上。
2、底层代码实现:
let data = {
name: "lis",
age: 20,
sex: "男"
}
// vue2.0实现 使用Object.defineProperty进行数据劫持
for(let key in data){
let temp = data[key]
Object.defineProperty(data, data[key], {
get(){
return temp
},
set(value){
temp = value
}
})
}
// vue3.0实现 使用Proxy 进行数据的代理
let newData = new Proxy(data, {
get(target, key){
return target[key]
},
set(target, key, value){
target[key] = value
}
})
vue2.0 和 vue3.0 响应式的区别
1、Object.defineProperty
1) 用于监听对象的数据变化
2) 无法监听数组变化(下标,长度)
3) 只能劫持对象的自身属性,动态添加的劫持不到
2、Proxy
1) proxy返回的是一个新对象, 可以通过操作返回的新的对象达到目的
2)可以监听到数组变化,也可以监听到动态添加的数据
router 和 route 的区别
1、$router对象 1)$router对象是全局路由的实例,是router构造方法的实例 2)$router对象上的方法有:push()、go()、replace()2、$route对象 1)$route对象表示当前的路由信息,包含了当前 URL 解析得到的信息。包含当前的路径,参数,query对象等 2)$route对象上的属性有:path、params、query、hash等等
路由传参的方式和区别
答: 1、方式:params 和 query2、区别:1)params用的是name,传递的参数在地址栏不会显示,类似于post 2)query用的是path,传递的参数会在地址栏显示出来,类似于get 3、举例说明: 1)params 传参 传: this.$router.push({ name: 'particulars', params: { id: id } }) 接:this.$route.params.id 2)query传参 传:this.$router.push({ path: '/particulars', query: { id: id } }) 接:this.$route.query.id
Vue 模版编译原理知道吗,能简单说一下吗
1、简单说,Vue的编译过程就是将template转化为render函数的过程。2、首先解析模版,生成AST语法树(一种用JavaScript对象的形式来描述整个模板)。 使用大量的正则表达式对模板进行解析,遇到标签、文本的时候都会执行对应的钩子进行相关处理。3、Vue的数据是响应式的,但其实模板中并不是所有的数据都是响应式的。有一些数据首次渲染后就不会再变化,对应的DOM也不会变化。那么优化过程就是深度遍历AST树,按照相关条件对树节点进行标记。这些被标记的节点(静态节点)我们就可以跳过对它们的比对,对运行时的模板起到很大的优化作用。4、编译的最后一步是将优化后的AST树转换为可执行的代码。
SSR 了解吗
1、SSR也就是服务端渲染,也就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成,然后再把html直接返回给客户端。2、SSR有着更好的SEO、并且首屏加载速度更快等优点。不过它也有一些缺点,比如我们的开发条件会受到限制,服务器端渲染只支持beforeCreate和created两个钩子,当我们需要一些外部扩展库时需要特殊处理,服务端渲染应用程序也需要处于Node.js的运行环境。还有就是服务器的压力比较大。
你都做过哪些 Vue 的性能优化
1、v-if和v-for不能连用2、页面采用keep-alive缓存组件3、合理使用v-if和v-show4、key保证唯一5、使用路由懒加载、异步组件、组件封装6、防抖、节流7、第三方模块按需导入8、图片懒加载9、精灵图的使用10、代码压缩
Vue-router 路由有哪些模式
一般有两种模式: 1、hash 模式:后面的 hash 值的变化,浏览器既不会向服务器发出请求,浏览器也不会刷新,每次 hash 值的变化会触发 hashchange 事件。 2、history 模式:利用了 HTML5 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器的历史记录栈,在当前已有的 back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改时,虽然改变了当前的 URL,但浏览器不会立即向后端发送请求。
Vuex 是什么?有哪几种属性?
1、Vuex 是专为Vue设计的状态管理工具,采用集中式储存管理 Vue 中所有组件的状态。
2、属性
(1)state属性:基本数据
(2)getters属性:从 state 中派生出的数据
(3)mutation属性:更新 store 中数据的唯一途径,其接收一个以 state 为第一参数的回调函数
(4)action 属性:提交 mutation 以更改 state,其中可以包含异步操作,数据请求
(5)module 属性:用于将 store分割成不同的模块。
axios 封装请求拦截器和响应拦截器
interceptors:【ɪntərˈsɛptərz】
1、项目中会在utils文件中,封装一个request.js文件
2、通过axios.create()配置baseURL,并得到一个request实例
3、通过request.interceptors.request.use来配置请求拦截
4、通过request.interceptors.response.use来配置响应拦截
webpack 在项目中的常见配置
1、 配置兼容编译ES6转成ES5
用babel来编译,npm i babel-core babel-loader babel-preset-env babel-polyfill babel-plugin-transform-runtime --save-dev
2、配置跨域代理服务
用proxy进行代理,在devServer里面配置,proxy:{'/api':{target:代理的地址}}
3、配置打包路径
publicPath:'/'
4、配置打包出去文件
outputDir: 'dist'
5、配置执行环境变量
启动的端口 const port = process.env.port || process.env.npm_config_port || 9528
vue 怎么实现强制刷新组件
第一.使用this.$forceUpdate强制重新渲染 <template> <button @click="reload()">刷新当前组件</button> </template> <script> export default { name: 'comp', methods: { reload() { this.$forceUpdate() } } } </script>第二.使用v-if指令<template> <comp v-if="update"></comp> <button @click="reload()">刷新comp组件</button></template><script>import comp from '@/views/comp.vue'export default { name: 'parentComp', data() { return { update: true } }, methods: { reload() { // 移除组件 this.update = false // 在组件移除后,重新渲染组件 // this.$nextTick可实现在DOM 状态更新后,执行传入的方法。 this.$nextTick(() => { this.update = true }) } }}</script>
在使用计算属性的时,函数名和 data 数据源中的数据可以同名吗?
不可以 在初始化vm的过程,因为不管是计算属性还是data还是props 都会被挂载在vm实例上,会把data覆盖了,因此 这三个都不能同名
vue 中 data 的属性可以和 methods 中的方法同名吗?
不可以
vue源码中的 initData() 方法会取出 methods 中的方法进行判断,如果有重复的就会报错
你知道 style 加 scoped 属性的用途和原理吗
用途:防止全局同名CSS污染
原理:在标签加上v-data-something属性,再在选择器时加上对应[v-data-something],即CSS带属性选择器,以此完成类似作用域的选择方式.
scoped会在元素上添加唯一的属性(data-v-x形式),css编译后也会加上属性选择器,从而达到限制作用域的目的。
如何在子组件中访问父组件的实例
Vue中子组件调用父组件的方法,这里有三种方法提供参考:
1:直接在子组件中通过this.$parent.event来调用父组件的方法
2:在子组件里用$emit向父组件触发一个事件,父组件监听这个事件
3:父组件把方法传入子组件中,在子组件里直接调用这个方法
watch 的属性用箭头函数定义结果会怎么样
不应该使用箭头函数来定义 watch :
例如:
watch: {
a: () => { // 这里不应该用箭头函数
console.log(this);
this.sum = this.a + this.b;
}
})。
理由是箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向 Vue 实例,
this.a 将是 undefined。
注意:methods里面定义的方法也不要用箭头函数
怎么解决 vue 打包后静态资源图片失效的问题
在vue-cli 需要在根目录下建一个vue.config.js 在里面配置publicPath即可
默认值为/,更改为./就好了
怎么解决 vue 动态设置 img 的 src 不生效的问题
因为动态添加src被当做静态资源处理了,没有进行编译,所以要加上require。
<img :src="require('@/assets/images/xxx.png')" />
EventBus 注册在全局上时,路由切换时会重复触发事件,如何解决呢
原因:因为我们的事件是全局的,它并不会随着组件的销毁而自动注销,需要我们手动调用注销方法来注销。
解决:我们可以在组件的 beforeDestroy ,或 destroy 生命周期中执行注销方法,手动注销事件
你认为 vue 的核心是什么
组件化;
双向数据绑定;
在.vue 文件中 style 是必须的吗?那 script 是必须的吗
在.vue 文件中,template是必须的,而script与style都不是必须的。都没有的话那就是一个静态网页
说说 vue 的优缺点
优点:
1.数据驱动
2.组件化
3.轻量级
4.SPA(单页面)
5.版本3.0的界面化管理工具比较好使
6.vue易入门
7.中文社区强大,入门简单,提升也有很多的参考资料。
缺点:
1.不支持IE8及以下浏览器
2.吃内存(每个组件都会实例化一个Vue实例,实例的属性和方法很多)
3.定义在data里面的对象,实例化时,都会递归的遍历转成响应式数据,然而有的响应式数据我们并不会用到,造成性能上的浪费
库和框架的区别
答: 库 本质上是一个函数的集合,每一次调用函数,实现一个特定的功能,使用库的时候,把库当成工具使用,需要自己控制代码的执行逻辑。
框架 是一套完整的解决方案,使用框架的时候,框架实现了大部分的功能,我们只需要按照框架的规则书写代码即可,使用框架开发比库开发效率更高,更容易维护。
MVC 和 MVVM 的区别
答: MVVM
M Model 模型 指的是数据层
V View 视图 指的是用户页面
VM ViewModel 视图模型
视图模型是MVVM模式的核心,它是连接view和model的桥梁,MVVM实现了view和model的自动同步,当model的属性改变时,我们不用自己手动操作DOM元素,来改变view的显示,反之亦然,我们称之为数据的双向绑定。
MVC
M Model 模型 指的是数据层
V View 视图 指的是用户页面
C controller 控制器 指的是页面业务逻辑
view传送指令到controller,controller完成业务逻辑后,要求model改变状态,model将新的数据发送给view,用户得到反馈。所有通信都是单向的。
自己实现一个 v-model 的效果
答:
<input type="text">
<script>
// vue2.0
let data = {
msg: 'hello vue'
}
let input = document.querySelector('input')
input.value = data.msg
input.addEventListener('input', function () {
data.msg = this.value
})
let temp = data.msg
Object.defineProperty(data, 'msg', {
get() {
return temp
},
set(value) {
input.value = value
return (temp = value)
}
})
// vue3.0
let data = {
msg: 'hello vue'
}
let input = document.querySelector('input')
input.value = data.msg
input.addEventListener('input', function () {
obj.msg = this.value
})
const obj = new Proxy(data, {
get(target, key) {
return target[key]
},
set(target, key, value) {
target[key] = value
input.value = value
}
})
</script>
Object.defineProperty 和 proxy 的区别
1、Object.defineProperty 用于监听对象的数据变化
缺点:
1)无法监听数组变化
2)只能劫持对象的属性,属性值也是对象那么需要深度遍历
2、proxy 可以理解为 在被劫持的对象之前 加了一层拦截
proxy返回的是一个新对象, 可以通过操作返回的新的对象达到目的
总结:
当使用 defineProperty 时,我们修改原来的 obj 对象就可以触发拦截
而使用 proxy,就必须修改代理对象,即 Proxy 的实例才可以触发拦截
vue-loader 是做什么的
答: 概念:vue-loader是基于webpack的一个loader,解析和转换.vue文件。提取出其中的逻辑代码script,样式代码style,以及HTML模板template,再分别把他们交给对应的loader去处理。
用途:js可以写es6、style样式可以是less或scss等
vue 中怎么操作 dom
答: 要在mounted中使用,在执行mounted的时候,vue已经渲染了dom节点,可以获取dom节点。
方法:
1)在标签中添加ref="name"
2)在方法中用this.$refs.name拿到这个元素,
导航钩子有几种(导航守卫)具体怎么用的
答: 分类:
1、全局守卫: router.beforeEach
2、全局解析守卫: router.beforeResolve
3、全局后置钩子: router.afterEach
4、路由独享的守卫: beforeEnter
5、组件内的守卫: beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave
使用:
1、全局守卫: router.beforeEach
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
2、全局解析守卫: router.beforeResolve
可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是:在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
3、全局后置钩子: router.afterEach
router.afterEach((to, from) => {
// ...
})
4、路由独享的守卫: beforeEnter
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
5、组件内的守卫: beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不能获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
什么是 promise,特点是什么
首先,它是一个对象,也就是说与其他JavaScript对象的用法,没有什么两样;其次,它起到代理作用(proxy),充当异步操作与回调函数之间的中介。它使得异步操作具备同步操作的效果,使得程序具备正常的同步运行的流程,回调函数不必再一层层嵌套。
简单说,它的思想是,每一个异步任务立刻返回一个Promise对象,由于是立刻返回,所以可以采用同步操作的流程。这个Promises对象有一个then方法,允许指定回调函数,在异步任务完成后调用。
特点:
1、Promise对象只有三种状态。
异步操作“未完成”(pending)
异步操作“已完成”(resolved,又称fulfilled)
异步操作“失败”(rejected)
异步操作成功,Promise对象传回一个值,状态变为resolved。
异步操作失败,Promise对象抛出一个错误,状态变为rejected。
2、promise的回调是同步的,then是异步的
3、可以链式调用
promise 的方法有哪些,能说明其作用
原型上的方法:
1、Promise.prototype.then()
1)作用是为 Promise 实例添加状态改变时的回调函数。接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。其中,第二个函数是可选的,不一定要提供。
2)返回的是另一个Promise对象,后面还可以接着调用then方法。
2、Promise.prototype.catch()
1)用于指定发生错误时的回调函数。
2)返回的也是一个 Promise 对象,因此还可以接着调用then方法
3、Promise.prototype.finally()
1)finally方法用于指定不管 Promise 对象最后状态如何,都会执行的回调函数。
2)finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。
自身API:
1、Promise.resolve()
1)不带参数传递 — 返回一个新的状态为resolve的promise对象
2)参数是一个 Promise 实例— 返回 当前的promise实例
2、Promise.reject()
1)返回的是一个值
2)返回的值会传递到下一个then的resolve方法参数中
3、Promise.all()
1)并行执行异步操作的能力
2)所有异步操作执行完后才执行回调
4、Promise.race()
1)那个结果返回来的快就是,那个结果,不管结果是成功还是失败
async 和 await 是干什么的
async和await可以说是异步终极解决方案了。
1、async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成。
2、await 只能出现在 async 函数中。
3、async 函数返回的是一个 Promise 对象,后面可以用then方法。
缺点:因为await将异步代码改造成了同步代码,如果多个异步代码都使用了await会导致性能上的降低。
什么是宏任务和微任务,执行顺序是什么
1、宏任务一般是:包括整体代码script,setTimeout,setInterval。
2、微任务:Promise(then、catch、finally),process.nextTick(node.js)。
3、先执行主代码块,然后执行微任务,最后在执行宏任务(异步)
webpack 的作用是什么
webpack是一个打包器(bundler),它能将多个js文件打包成一个文件(其实不止能打包js文件,也能打包其他类型的文件,比如css文件,json文件等)
webpack 打包的流程是什么
Webpack首先会把配置参数和命令行的参数及默认参数合并,并初始化需要使用的插件和配置插件等执行环境所需要的参数;初始化完成后会调用Compiler的run来真正启动webpack编译构建过程,webpack的构建流程包括compile、make、build、seal、emit阶段,执行完这些阶段就完成了构建过程.
大概阶段:1、初始化参数(加载插件和处理入口等)
2、编译阶段(读取文件-编译模块-分析模块依赖关系)
3、文件输出(渲染源码-执行文件输出-全部完成)
页面通信的方式有哪些
1. 通过url拼接地址
2. H5本地存储
如何清除浏览器的缓存
答: 当我们请求的地址相同的时候,浏览器为了提高性能,会把相同地址的数据进行缓存。如果服务端的数据发生改变,客户端也不会更新,那就需要清除缓存
解决:在url后面加时间戳
例如:https://www.baidu.com?time=New Date()
token 的作用是什么
答: token是服务端生成的“令牌”,来标识不同身份的
1. 防止表单重复提交
2.判断用户是否登录
列举 echarts 常用的配置项,说明含义
答: 图表标题 title
图例 legend
值域 dataRange
提示框 tooltip
区域缩放控制器 dataZoom
网格 grid
类目轴 categoryAxis
值型坐标轴默认参数 valueAxis
柱形图默认参数 bar
折线图默认参数 line
散点图默认参数 scatter
饼图默认参数 pie
默认标志图形类型列表 symbolList
可计算特性配置, 孤岛, 提示颜色 calculable
git 如何管理一个项目
答: 1、git init初始化git仓库(新项目才有这一步)
2、git clone将远程仓库的项目资料下载下来
3、git checkout -b dev (dev 为本地分支名)
4、git add .将工作区文件存在暂存区
4、git commit -m ""从暂存区存到仓储区
5、git checkout master切到master分支
6、git merge dev 合并分支,合并后要将分支删除
7、使用git push将其上传到远程仓库
8、第二上班,先pull一下,更新最新代码
项目问题
token 问题
Vue项目中实现token验证大致思路如下:
1、第一次登录的时候,前端调后端的登陆接口,发送用户名和密码
2、后端收到请求,验证用户名和密码,验证成功,就给前端返回一个token
3、前端拿到token,将token存储到localStorage/cookie 和vuex中,并跳转路由页面
4、前端每次跳转路由,就判断 localStroage/cookie 中有无 token ,没有就跳转到登录页面,有则跳转到对应路由页面
5、每次调后端接口,都要在请求头中加token
token 过期
Lazyload 图片懒加载
先将img标签中的src链接设置为空,将真正的图片链接放在自定义属性(data-src),当js监听到图片元素进入到可视窗口的时候,将自定义属性中的地址存储到src中,达到懒加载的效果。
如果滚动的大小和屏幕高度之和大于元素到顶部的距离,设置一个定时器,制造懒加载的延迟加载的效果,也就是说,当我们滑动滚动条,看见图片的时候,就让它加载出来
less 和 sass 区别
定义变量的符号不同:less使用@,sass使用$,
变量的作用域不同:less在全局定义就作用在全局,在代码块中定义就作用于整个代码块,而sass只作用于全局
编译环境不同:less在开发者环境编译,sass在服务器环境下编译
响应式布局
响应式布局指的是同一页面在不同屏幕尺寸下有不同的布局
1.pc端响应式布局:是指屏幕大小缩放时样式发生相应改变。运用媒体查询@media来设置。
2.移动端响应式布局:是指根据移动端不同设备实现页面正常显示的方案。运用以下三种方案布局:a. 百分比布局。b. flex布局。c. rem布局
visibility,opacity 和 display:none 的区别
1. display:none
该方式让元素隐藏时,隐藏的元素不占空间,隐藏后将改变html原有样式。
2. visibility:hidden
该方式让元素隐藏时,隐藏的元素还是占用原有位置,隐藏后不将改变html原有样式。但,如果该元素的子元素使用了visibility:visible的话,改子元素将不被隐藏。
3. opacity:0
该方式让元素隐藏时,隐藏的元素还是占用原有位置,隐藏后不将改变html原有样式。但,隐藏的元素所对应的事件,仍然可以触发。
简单用 node.js 搭建本地服务器
安装框架之前先把NPM镜像改成淘宝镜像,在文件夹打开命令行窗口执行命令:npm config set registry https://registry.npm.taobao.org
然后全局安装express命令安装工具 输入命令: npm install -g express-generator
再安装express框架 输入命令: npm install -g express
安装成功后就可以使用express框架构建项目了
如输入命令: express myStudy -e 创建项目, 再cd 进入该目录,输入命令:npm install 安装组件 ,最后执行命令:npm start 启动项目
http 状态码
2xx:成功 这类状态代码表明服务器成功地接受了客户端请求。
201 已创建。
203 非权威性信息。
205 重置内容。
3xx:重定向 客户端浏览器必须采取更多操作来实现请求。
302 对象已移动。
307 临时重定向。
4xx:客户端错误 发生错误,客户端似乎有问题
400 错误的请求。
401 访问被拒绝。
403 服务器拒绝请求
404 服务器找不到请求的网页。
5xx:服务器错误 服务器由于遇到错误而不能完成该请求。
501 页眉值指定了未实现的配置。
503 目前服务器无法使用,一般是因为服务器超载或停止维护。
505 HTTP 版本不受支持。
前端加密的集中方法
第一种:base64方法
第二种:MD5加密方式 非对称加密 不能解密
首先引入相关js,对要加密的内容直接加密,直接使用MD5方法对内容进行加密
第三种加密RSA用公钥私钥加密解密
先引入相关配置文件,前端在向后台发起登录请求之前,先请求后台获取公钥的方法,通过公钥对相关内容加密,接下来就是用加密后的内容请求后台。
双 token 如何让用户无感刷新权限
一般后台返回的会有两个token,一个登陆用的taoken,一个用来刷新的taoken,刷新用关灯token过期时间会设置的比较长,通过判断用户活跃度来刷新token,如果一直没登录,就直接让客户登录,如果是登录期间过期了就直接使用刷新taoken后台获取新的token
树形控件 使用
引入el-tree 然后发送请求获得数据,如果后台给的数据不是直接可以用的,通过比较一级部门的id和二级部门的pid之类的利用递归来处理数据
Echarts 如何使用的?
安装模块,页面上准备具有宽高的放置表的DOM容器,通过echarts.init生成一个实例并利用setOption生成简单图表
APP 中如何兼容 ios 系统和安卓系统(刘海屏和水滴屏如何适应)
//CSS3新特性viewport-fit 属性
<meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
// 竖屏底下的查询
@media screen and (orientation: portrait) {
body {
/* 防止页面被刘海遮住 */
padding-top: constant(safe-area-inset-top);
//以防万一写一个你本身适配其他手机的
padding-top:0px;
}
}
/* 横屏底下的查询 */
@media screen and (orientation: landscape) {
body {
/* IOS 11支持*/
padding-right: constant(safe-area-inset-right);
padding-left: constant(safe-area-inset-left);
padding-bottom: constant(safe-area-inset-bottom);//为底下圆弧的高度 34px
/*IOS 11.2版本版本支持*/
padding-right: env(safe-area-inset-right);
padding-left: env(safe-area-inset-left);
padding-bottom: env(safe-area-inset-bottom);
//以防万一写一个你本身适配其他手机的
padding-right:0px;
padding-left:0px;
padding-bottom:0px;
}
}
//如果用header和footer请单独定义
什么情况下使用箭头函数,什么情况下必须用 function
在事件处理程序 和作为构造函数时,不能使用箭头函数,箭头函数内没有arguments(实参列表),没有this指向,不需要这些的时候可以直接用箭头函数
小程序的分享功能如何实现
//微信小程序分享功能的实现方法有两种:
//第一种
在page.js中实现onShareAppMessage,便可在小程序右上角选择分享该页面
onShareAppMessage: function () {
return {
title: '弹出分享时显示的分享标题',
desc: '分享页面的内容',
path: '/page/user?id=123' // 路径,传递参数到指定页面。
}
}
//第二种
//自定义按钮实现分享,在page中添加一个带有open-type='share'的button标签(<button open-type='share'><\/button>)
如何配置路由
安装路由,导入路由,注册路由,创建路由规则,创建路由实例并挂载规则,挂载路由实例,并在页面中放置路由出口
APP 中 1px 的边框如何处理?
使用border-image实现;使用background-image实现;(优点:可以设置单条、多条表框。缺点:更换颜色和样式麻烦,某些设备上会模糊)
使用box-shadow模拟边框(优点:代码少,兼容性好。缺点:边框有阴影,颜色变浅。)
webpack 如何进行打包的
1、初始化环境
yarn init
2、安装依赖包
yarn add webpack webpack-cli -D
3、配置script
scripts: {
"build": "webpack"
}
4、新建目录src,建立导入导出文件
5、运行打包命令
yarn build
跨域的解决方案
jsonp(只支持get方式的请求) 反向代理(配置proxy节点) cors
APP 如何同步 pc 端和移动端的数据
1、利用import()异步引入组件实现按需引入
2、使用CDN引入第三方依赖
3、利用SplitChunks插件提取公共js代码和分割js代码
防抖和节流是什么?
防抖,就是指触发事件后在 一定时间内只能执行一次,如果在这个时间内又触发了事件,则会重新计算函数执行时间。
节流,就是指连续触发事件但是在一定时间内最多只执行一次函数
//防抖一般用于input框
let timer = null
clearTimeout(timer)
timer = setTimeout(()=>{
发送请求(业务逻辑代码)
},1000)
1、定义一个延时任务,在延迟任务之前再清除这个任务,那么只要在这个约定的时间内一直触发这个时间就会重新计算事件,直到我超出事件后没有再次触发该事件,那么就会发出请求
//节流 timer 是定时器的id 是个数字 布尔值是true
let timer = false
if (!timer) return
timer = setTimeout(()=>{
业务逻辑
重置timer=fase
},50)
适合事件触发频率特别高的时候,可以减少代码的执行率
APP 的发布方式,发布工具
APICloud 可以同时生成一套 ios 和安卓的原生模块
轮询技术?
轮询是在特定的的时间间隔(如每 1 秒),由浏览器对服务器发出 HTTP request,然后由服务器返回最新的数据给客户端的浏览器,轮询最开始出现时为了解决服务端压力过大,当前端一次并发多个请求的时候,可以轮流依次给到不同的服务器(这三台服务器的数据和接口都是一样的)。
项目打包后图片加载失败,怎么处理?
检查下基地址,静态资源路径等,找出问题后重新打包。
RBAC 是什么?
基于角色的权限控制,通过给不同的用户分配不同的权限,控制其访问的页面,当权限增加时,能访问的页面也对应的增加。
RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联。简单地说,一个用户拥有若干角色,每一个角色拥有若干权限。这样,就形成“用户-角色-权限”的授权模型。在这种模型中,用户与角色之间,角色与权限之间一般都是多对多的关系。
无感注册,无感刷新如何实现?
无感刷新一般后台返回的会有两个 token,一个登陆用的 token,一个用来刷新的 token,刷新用 token 过期时间会设置的比较长,通过判断用户活跃度来刷新 token,如果一直没登录,就直接让客户登录,如果是登录期间过期了就直接使用刷新 taoken 后台获取新的 token
如何实现同一旗下的 app 登录其中一个,其他 app 也同时可以访问?
单点登录 SSO(Single Sign On),解决如何产生和存储的信任,再就是其他系统如何验证这个信任的有效性
第一种方式:以 Cookie 作为凭证媒介
最简单的单点登录实现方式,是使用 cookie 作为媒介,存放用户凭证。 用户登录父应用之后,应用返回一个加密的 cookie,当用户访问子应用的时候,携带上这个 cookie,授权应用解密 cookie 并进行校验,校验通过则登录当前用户。(不安全,不能解决跨域实现免登录)
第二种方式:通过页面重定向的方式
是通过父应用和子应用来回重定向中进行通信,实现信息的安全传递。 父应用提供一个 GET 方式的登录接口,用户通过子应用重定向连接的方式访问这个接口,如果用户还没有登录,则返回一个的登录页面,用户输入账号密码进行登录。如果用户已经登录了,则生成加密的 Token,并且重定向到子应用提供的验证 Token 的接口,通过解密和校验之后,子应用登录当前用户
第三种方式:使用独立登录系统
大型应用会把授权的逻辑与用户信息的相关逻辑独立成一个应用,称为用户中心。 用户中心不处理业务逻辑,只是处理用户信息的管理以及授权给第三方应用。第三方应用需要登录的时候,则把用户的登录请求转发给用户中心进行处理,处理完毕返回凭证,第三方应用验证凭证,通过后就登录用户。
Echarts 如何联动两个表?
图表实现联动的关键代码 echarts.connect([myChart1, myChart2])
响应式和自适应的区别
1.自适应布局通过检测视口分辨率,来判断当前访问的设备,响应式布局针对不同客户端在客户端做代码处理。
2.自适应要开发多套界面,响应式只要开发一套界面。
3.自适应适配是在一定范围,响应式布局是一套页面全部适应。
电商网站如何实现订单的唯一性?
可以使用一个唯一的流水号 ID,用来标识是不是同一个请求或者交易,先将这个 ID 保存到一个流水表里面,并且流水表中将这个 ID 设置为UNIQUE KEY
,如果插入出现冲突了,则说明这个创建订单的请求已经处理过了,直接返回之前的操作结果。
(幂等性):用在接口上就可以理解为:同一个接口,多次发出同一个请求,必须保证操作只执行一次。 调用接口发生异常并且重复尝试时,总是会造成系统所无法承受的损失,所以必须阻止这种现象的发生。 比如下面这些情况,如果没有实现接口幂等性会有很严重的后果: 支付接口,重复支付会导致多次扣钱 订单接口,同一个订单可能会多次创建
A 和 B 两个非父子组件,A 中 input 框里的值如何传给 B?
EventBus 建立一个 js 文件,只做事件发布和监听,A 和 B 组件都需要导入这个 js 文件,A 组件通过$emit发布一个事件,并携带input框的值,B组件通过$on 订阅事件,并接收参数。
或者直接存到 vuex 中
过滤器怎么写?
全局的:
Vue.filter("capitalize", function (value) {
if (!value) return "";
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1);
});
// 参数一 过滤器名字 参数二 函数,value 是使用这个过滤器的dom元素 参数二的函数必须有一个返回值
局部过滤器:
filters: {
formatDate(val,str){
return moment(val).format(str)
}
}
自定义指令?
全局:
Vue.directive("focus", {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 使用这个指令的元素元素
el.focus();
},
});
局部指令:
directives: {
color: {
// 指令的定义
inserted: function (el,binding) {
el.style.color=binding.value
}
}
}
手机端如何调出键盘?
在 Android 上,只要不是用户触发的事件都无法触发。一个 label,两个 input,既然隐藏了搜索组件的 input1。新建另一个隐藏的 input2。点击 label–>input2 聚焦–>键盘起–>input1.focus()
ios 上,touchstart 事件时,直接 focus 到 input 上。
btn.addEventListener('touchstart', function(evt){if(isIos){ evt.preventDefault(); evt.stopPropagation(); input.focus() }//必须阻止默认行为,也不能冒泡,而且click事件是不行的。click有延迟,用户触摸屏幕,无法及时的focus。preventDefault和stopPropagation也是为了防止焦点到其他的元素上。
vuex 里 modules 使用场景
在项目开发过程中,随着项目逐渐增大,数据关联复杂度逐渐加大, 多人协同开发,人员变动等。 我们会遇到 vuex 数据更新时,执行某个 action 导致同名/未预测到的关联数据发生了变化。
vue 基本思想之一便是数据驱动, vuex 更是专门的数据状态关联库。 导致数据错误结果可想而知......
使用vuex module 命名空间概念则可以很好的解决这个问题!!!
vuex 流程
对vuex的简单理解
每一个 Vuex 应用的核心就是 store,里面又包括:
(1)state(数据):用来存放数据源,就是公共状态;
(2)getters(数据加工):有的时候需要对数据源进行加工,返回需要的数据;
(3)actions(事件):要执行的操作,可以进行同步或者异步事件
(4)mutations(执行):操作结束之后,actions通过commit更新state数据源
(5)modules:使用单一状态树,致使应用的全部状态集中到一个很大的对象,所以把每个模块的局部状态分装使每一个模块拥有本身的 state、mutation、action、getters、甚至是嵌套子模块;
vuex的工作流程就是:
(1)通过dispatch去提交一个actions,
(2)actions接收到这个事件之后,在actions中可以执行一些异步|同步操作,根据不同的情况去分发给不同的mutations,
(3)actions通过commit去触发mutations,
(4)mutations去更新state数据,state更新之后,就会通知vue进行渲染
1.在vue组件里面,通过dispatch来触发actions提交修改数据的操作。
2.然后再通过actions的commit来触发mutations来修改数据。
3.mutations接收到commit的请求,就会自动通过Mutate来修改state(数据中心里面的数据状态)里面的数据。
4.最后由store触发每一个调用它的组件的更新
Vuex 的严格模式是什么
在严格模式下,无论何时发生了状态变更且不是由 mutation函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
在Vuex.Store 构造器选项中开启,如下
const store = new Vuex.Store({
strict:true,
})
vue-router 命名视图
有时候想同时(同级)展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar(侧导航) 和 main(主内容) 两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。
数组去重
一、双层循环(暴力方法)
二、indexOf和includes
三、排序去重
四、filter
五、键值对(key-value)
六、ES6(set 和 map)
set方法
var arr = [1, 2, 1, '1', '2'];
function unique(array) {
return [...new Set(array)];
}
console.log(unique(arr)); // [ 1, 2, '1', '2' ]
map方法
function unique (arr) {
const newMap = new Map()
return arr.filter((a) => !newMap.has(a) && newMap.set(a, 1));
}
事件冒泡和事件委托
js中事件冒泡我们知道,子元素身上的事件会冒泡到父元素身上。
事件代理就是,把原本需要绑定在子元素的响应事件(click、keydown......)委托给父元素,让父元素担当事件监听的职务。
事件委托的优点:
1.可以大量节省内存占用,减少事件注册,比如在ul上代理所有li的click事件就非常棒
2.可以实现当新增子对象时无需再次对其绑定(动态绑定事件)
flex 布局是什么,有哪些属性?flex:1 是什么意思?
- 是什么
Flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。
任何一个容器都可以指定为 Flex 布局。
行内元素也可以使用 Flex 布局。
Webkit 内核的浏览器,必须加上-webkit 前缀。
注意,设为 Flex 布局以后,子元素的 float、clear 和 vertical-align 属性将失效。
- Flex 的属性
以下 6 个属性设置在容器上。
- flex-direction
flex-direction 属性决定主轴的方向(即项目的排列方向)。
.box {
flex-direction: row | row-reverse | column | column-reverse;
}
row(默认值):主轴为水平方向,起点在左端。
row-reverse:主轴为水平方向,起点在右端。
column:主轴为垂直方向,起点在上沿,自上而下。
column-reverse:主轴为垂直方向,起点在下沿,自下而上。
- flex-wrap
默认情况下,项目都排在一条线(又称"轴线")上。flex-wrap 属性定义,如果一条轴线排不下,应该如何换行。
.box{
flex-wrap: nowrap | wrap | wrap-reverse;
}
nowrap(默认):不换行,宽度自动压缩。
wrap:换行,第一行在上方。
wrap-reverse:换行,第一行在下方。
- flex-flow
flex-flow 属性是 flex-direction 属性和 flex-wrap 属性的简写形式,默认值为 row nowrap。
.box {
flex-flow: <flex-direction> || <flex-wrap>;
}
.box{
flex-flow:row||nowrap;
}
- justify-content
justify-content 属性定义了项目在主轴上(即横向)的对齐方式。
flex-start(默认值):左对齐
flex-end:右对齐
center: 居中
space-between:两端对齐,组件之间的间隔都相等。
space-around:距边界两侧的间隔相等,元素之间的间隔比项目与边框的间隔大一倍。
- align-items
align-items 属性定义项目在交叉轴上(即纵向,垂直)如何对齐。
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
flex-start:交叉轴的起点(顶部)对齐。
flex-end:交叉轴的终点(底部)对齐。
center:交叉轴的中点(中间)对齐。
baseline: 项目的第一行文字的基线(即根据内容对齐,不再根据容器)对齐。
stretch(默认值):如果项目未设置高度或设为 auto,将占满整个容器的高度。
- align-content
align-items 属性定义项目在交叉轴上(即纵向,垂直)如何对齐。
.box {
align-items: flex-start | flex-end | center | baseline | stretch;
}
flex-start:交叉轴的起点(顶部)对齐。
flex-end:交叉轴的终点(底部)对齐。
center:交叉轴的中点(中间)对齐。
baseline: 项目的第一行文字的基线(即根据内容对齐,不再根据容器)对齐。
stretch(默认值):如果项目未设置高度或设为 auto,将占满整个容器的高度。
- flex:1 是什么意思?
flex:1即为flex-grow:1,经常用作自适应布局,将父容器的display:flex,侧边栏大小固定后,将内容区flex:1,内容区则会自动放大占满剩余空间。
position 有哪些属性?
(1)、static
可以认为静态的,默认元素都是静态的定位,对象遵循常规流。此时4个定位偏移属性不会被应用,也就是使用left,right,bottom,top将不会生效。
(2)、relative
相对定位,对象遵循常规流,并且参照自身在常规流中的位置通过top,right,bottom,left这4个定位偏移属性进行偏移时不会影响常规流中的任何元素。
(3)、absolute
a、绝对定位,对象脱离常规流,此时偏移属性参照的是离自身最近的定位祖先元素,如果没有定位的祖先元素,则一直回溯到body元素。盒子的偏移位置不影响常规流中的任何元素,其margin不与其他任何margin折叠。
b、元素定位参考的是离自身最近的定位祖先元素,要满足两个条件,第一个是自己的祖先元素,可以是父元素也可以是父元素的父元素,一直找,如果没有则选择body为对照对象。第二个条件是要求祖先元素必须定位,通俗说就是position的属性值为非static都行。
(4)、fixed
固定定位,与absolute一致,但偏移定位是以窗口为参考。当出现滚动条时,对象不会随着滚动。
(5)、center
与absolute一致,但偏移定位是以定位祖先元素的中心点为参考。盒子在其包含容器垂直水平居中。(CSS3)
(6)、page
与absolute一致。元素在分页媒体或者区域块内,元素的包含块始终是初始包含块,否则取决于每个absolute模式。(CSS3)
(7)、sticky
对象在常态时遵循常规流。它就像是relative和fixed的合体,当在屏幕中时按常规流排版,当卷动到屏幕外时则表现如fixed。
页面布局,左右固定中间自适应怎么实现?
1.使用自身浮动法:
自身浮动法的原理就是对左右分别使用float:left和float:right,float使左右两个元素脱离文档流,中间元素正常在正常文档流中。对中间文档流使用margin指定左右外边距进行定位。
该布局法的不足是三个元素的顺序,middle一定要放在最后,middle占据文档流位置,所以一定要放在最后,左右两个元素位置没有关系。当浏览器窗口很小的时候,右边元素会被挤到下一行。
2.使用绝对定位法:
绝对定位法原理是将左右两边使用absolute定位,因为绝对定位使其脱离文档流,后面的middle会自然流动到他们上面,然后使用margin属性,留出左右元素的宽度,既可以使中间元素自适应屏幕宽度。
该法布局的好处,三个div顺序可以任意改变。但是因为是绝对定位,如果页面上还有其他内容,top的值需要小心处理。
3.使用flex布局:
设置一个父div,添加样式display:flex。中间div设置flex-grow:1,(等同代码中设置flex:1。flex是grow、shrink、basis的简写)但是盒模型默认紧紧挨着,可以使用margin控制外边距。middle一定在中间,否则需要order属性来调整。
通过项目属性flex-grow设置middle的放大比例,将空余的空间用middle来填充,使三个项目排满一整行;默认为0,也就是对剩余空间不做处理。通过项目属性flex-basis 设置left和right的固定宽度。
不定宽高的 div 水平垂直居中?
方法一:
CSS3(实现简单,缺点是兼容性不好)
display: flex;
justify-content:center; //子元素水平居中
align-items:center; //子元素垂直居中
方法二:
运用margin:auto进行垂直居中
margin的值设置为auto,可以让我们对剩余空间进行分配!我们知道,块级元素设置为margin:0 auto;可以左右居中显示!那有没有办法让margin设置为margin:auto之后,上下左右都居中呢?上下左右都居中,就可以实现我们的垂直居中了!
答案是有的,只要我们让上下有足够的空间,就可以让margin的auto来分配上下空间。
我们可以利用定位的方式,让margin上下左右都有足够的空间!那么就可以用margin:auto来实现垂直居中了!
key 值有什么作用?不加 key 会有什么影响?会在哪个生命周期会用到 key?
作用:key属性能够提升性能(主要作用于数据更新时)。
不加 key 会有什么影响:可能会导致数据渲染错乱
会在哪个生命周期会用到 key:beforeUpdate
vue 八大生命周期钩子函数
beforeCreate: vue实例初始化之前调用(vue实例中的el,data,data中的message都为undefined)
created: vue实例初始化之后调用(
el还是undefined,而数据已经与data中的属性进行绑定(放在data中属性当值发生改变的同时,视图也会发生变化),在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取)
beforeMount: 挂载到DOM树之前调用(载入前(完成了data和el数据初始化),但是页面中的内容还是vue中的占位符,data中的message信息没有被挂在到Bom节点中,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取)
mounted: 挂载到DOM树之后调用(载入后html已经渲染(ajax请求可以放在这个函数中),把vue实例中的data里的message挂载到BOM节点中去)
beforeUpdate: 数据更新之前调用 (更新前状态(view层的数据变化前,不是data中的数据改变前),重新渲染之前触发,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染)
updated:数据更新之后调用 (数据已经更改完成,dom也重新render完成)
beforeDestroy: vue实例销毁之前调用(销毁前执行($destroy方法被调用的时候就会执行),一般在这里善后:清除计时器、清除非指令绑定的事件等等…’)
destroyed:vue实例销毁之后调用(销毁后 (Dom元素存在,只是不再受vue控制),卸载watcher,事件监听,子组件)
- 生命周期总结
beforecreate : 可以在这加个loading事件
created :在这结束loading,还做一些初始数据的获取,实现函数自执行
mounted : 在这发起后端请求,拿回数据,配合路由钩子做一些事情
beforeDestroy: 你确认删除XX吗?
destroyed :当前组件已被删除,清空相关内容
vue v-model 实现原理?
实现原理:
1、v-bind绑定响应数据
2、触发input事件并传递数据
vue created 到 beforeMount 的过程?
首先会判断vue实例中有没有el选项,如果有的话则进行下面的编译,但是如果没有el选项,则停止生命周期,直到vue实例上调用vm.$mount(el)。
如果有el,再判断是否有template参数,如果有,则把其当作模板编译成render函数,如果没有,则把外部的html作为模板编译。template中的模板优先级高于outer HTML模板。
在vue对象中还有一个render函数,它是以createElement作为参数,然后做渲染操作,而且我们可以直接嵌入JSX.
综合排名优先级:render函数选项 > template选项 > outer HTML.
vue 父子组件加载顺序?组件通信有哪些?
- vue 父子组件加载顺序
首先加载父组件 : beforeCreate ,created ,beforeMount, mounted,beforeUpdate(四次)
然后是 子组件1 : beforeCreate ,created ,beforeMount ,
然后是 子组件2 : beforeCreate ,created ,beforeMount ,
然后是 子组件1 : mounted,
然后是 子组件2 : mounted,
然后是 父组件 : updated (四次 ),
最后 父组件 再次 加载一次 beforeUpdate,updated
- 组件间通信的分类
组件间通信的分类可以分成以下
父子组件之间的通信
兄弟组件之间的通信
祖孙与后代组件之间的通信
非关系组件间之间的通信
- 组件间通信的方案
整理vue中8种常规的通信方案
通过 props 传递
通过 $emit 触发自定义事件
使用 ref
EventBus
$parent 或 $root
attrs 与 listeners
Provide 与 Inject
Vuex
Git 提交代码错误怎么撤回?怎么合并冲突?
- Git 提交代码错误怎么撤回
1.输入git log 查看所有提交的版本,找出对应的版本号码
2.回退到指定版本
git reset --hard 版本号码
3. 推送代码
git push origin master -f
- 合并冲突
1.先通过开发工具找出冲突
2.解决冲突
3. 推送代码
vue v-if 和 v-show 区别?
- v-if 和 v-show 区别
1.共同点
v-if 和 v-show 都可以动态地显示隐藏DOM元素
2. 区别
(1)手段不同:
v-if 是动态的向DOM树内添加或者删除DOM元素;
v-show 是通过设置DOM元素的display样式属性控制显隐;
(2)性能消耗不同:
v-if 有更高的切换消耗;
v-show 有更高的初始渲染消耗;
(3)使用场景不同:
v-if 适合运营条件不大可能改变;
v-show 适合频繁切换。
webpack 执行顺序打包流程,从哪里收集参数?依赖关系怎么走?
promise 有哪些方法?
宏任务和微任务有哪些?异步操作和同步操作有哪些?
(macro)task,可以理解是每次执行栈执行的代码就是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行)。
- 宏任务包含
script(整体代码)
setTimeout
setInterval
I/O
UI交互事件
postMessage
MessageChannel
setImmediate(Node.js 环境)
微任务
microtask,可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前task任务后,下一个task之前,在渲染之前。
所以它的响应速度相比setTimeout(setTimeout是task)会更快,因为无需等渲染。也就是说,在某一个macrotask执行完后,就会将在它执行期间产生的所有microtask都执行完毕(在渲染前)。
微任务包含:
Promise.then
Object.observe
MutaionObserver
process.nextTick(Node.js 环境)
四分之一圆用 css 怎么实现?
保持宽高和圆角值相同
div {
width: 100px;
height: 100px;
background-color: pink;
border-radius: 100px 0 0 0;
/*四个值分别对应 左上、右上、右下、左下 */
}
computed 和 watch 的区别是什么?
计算属性computed :
1. 支持缓存,只有依赖数据发生改变,才会重新进行计算
2. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
3.computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
4. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
侦听属性watch:
1. 不支持缓存,数据变,直接会触发相应的操作;
2.watch支持异步;
3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
4. 当一个属性发生变化时,需要执行对应的操作;一对多;
5. 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
immediate:组件加载立即触发回调函数执行,
deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
判断数据类型的方法有哪些?
1.typeof
console.log(
typeof 123, //"number"
typeof 'dsfsf', //"string"
typeof false, //"boolean"
typeof [1,2,3], //"object"
typeof {a:1,b:2,c:3}, //"object"
typeof function(){console.log('aaa');}, //"function"
typeof undefined, //"undefined"
typeof null, //"object"
typeof new Date(), //"object"
typeof /^[a-zA-Z]{5,20}$/, //"object"
typeof new Error() //"object"
);
Array,Object,null,Date,RegExp,Error这几个类型都被typeof判断为object,所以如果想要判断这几种类型,就不能使用typeof了。
Number,String,Boolean,Function,undefined,如果想判断这几种类型,那就可以使用typeof。
2. instanceof
instanceof运算符需要指定一个构造函数,或者说指定一个特定的类型,它用来判断这个构造函数的原型是否在给定对象的原型链上。
console.log(
123 instanceof Number, //false
'dsfsf' instanceof String, //false
false instanceof Boolean, //false
[1,2,3] instanceof Array, //true
{a:1,b:2,c:3} instanceof Object, //true
function(){console.log('aaa');} instanceof Function, //true
undefined instanceof Object, //false
null instanceof Object, //false
new Date() instanceof Date, //true
/^[a-zA-Z]{5,20}$/ instanceof RegExp, //true
new Error() instanceof Error //true
)
3.constructor
constructor是prototype对象上的属性,指向构造函数。根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的。
typeof 判断类型返回什么?
less 和 sass 区别?
一、概念
1、Less:
是一种动态样式语言. 对CSS赋予了动态语言的特性,如变量、继承、运算、函数。
Less 既可以在客户端上运行 (支持IE 6+, Webkit, Firefox),也可在服务端运行。
2、Sass:
是一种动态样式语言,Sass语法属于缩排语法,
比css比多出好些功能(如变量、嵌套、运算,混入(Mixin)、继承、颜色处理,函数等),更容易阅读。
二、less和sass的相同之处
Less和Sass在语法上有些共性,比如下面这些:
1、混入(Mixins)——class中的class;
2、参数混入——可以传递参数的class,就像函数一样;
3、嵌套规则——Class中嵌套class,从而减少重复的代码;
4、运算——CSS中用上数学;
5、颜色功能——可以编辑颜色;
6、名字空间(namespace)——分组样式,从而可以被调用;
7、作用域——局部修改样式;
8、JavaScript 赋值——在CSS中使用JavaScript表达式赋值。
三、less和sass的区别
Less和Sass的主要不同就是他们的实现方式。
Less是基于JavaScript,是在客户端处理的。
Sass是基于Ruby的,是在服务器端处理的。
关于变量在Less和Sass中的唯一区别就是Less用@,Sass用$。
闭包?
闭包函数:声明在一个函数中的函数,叫做闭包函数。
闭包:内部函数总是可以访问其所在的外部函数中声明的参数和变量,即使在其外部函数被返回(寿命终结)了之后。
2、特点
让外部访问函数内部变量成为可能;
局部变量会常驻在内存中;
可以避免使用全局变量,防止全局变量污染;
过度使用 会造成内存泄漏(有一块内存空间被长期占用,而不被释放)
var,let 和 const 区别?
一、var声明的变量会挂载在window上,而let和const声明的变量不会
二、var声明变量存在变量提升,let和const不存在变量提升
三、let和const声明形成块作用域
四、同一作用域下let和const不能声明同名变量,而var可以
五、暂存死区
六、const
1、一旦声明必须赋值,不能使用null占位。
2、声明后不能再修改
3、如果声明的是复合类型数据,可以修改其属性
vue2 和 vue3 区别?
1. 数据双向绑定方面
vue2 的双向数据绑定是利用ES5 的一个 API ,Object.definePropert()对数据进行劫持 结合 发布订阅模式的方式来实现的。
vue3 中使用了 es6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每一个对象都包一层 Proxy,通过 Proxy 监听属性的变化,从而实现对数据的监控。
2. Vue 3 的 Template 支持多个根标签,Vue 2 不支持
3. slot具名插槽的使用
vue2中的用法:父组件使用slot=插槽名
vue3中子组件用法不变,父组件需要使用v-slot:插槽名
Echarts ?
Echarts:ECharts 是一个使用 JavaScript 实现的开源可视化库,涵盖各行业图表,满足各种需求。
数组去重?
一、利用ES6 Set去重(ES6中最常用)
function unique (arr) {
return Array.from(new Set(arr))
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
//[1, "true", true, 15, false, undefined, null, NaN, "NaN", 0, "a", {}, {}]
二、[...new Set(arr)]
[...new Set(arr)]
//代码就是这么少----(其实,严格来说并不算是一种,相对于第一种方法来说只是简化了代码)
数组方法和遍历方法?
数组遍历方法
1.for循环
2.foreach循环
3. map循环
4.forof遍历
5.filter遍历
6.every遍历
7.some遍历
8.reduce求和
数组方法
1 arr.push():从后面添加元素,返回值为添加完后的数组的长度
2 arr.pop():从后面删除元素,只能是一个,返回值是删除的元素
3 arr.shift():从前面删除元素,只能删除一个 返回值是删除的元素
4 arr.unshift():从前面添加元素, 返回值是添加完后的数组的长度
5 arr.splice(i,n):删除从i(索引值)开始之后的那个元素。返回值是删除的元素
6 arr.concat():连接两个数组 返回值为连接后的新数组
7 str.split():将字符串转化为数组
8 arr.sort():将数组进行排序,返回值是排好的数组,默认是按照最左边的数字进行排序,不是按照数字大小排序的。
9 arr.reverse():将数组反转,返回值是反转后的数组
10 arr.slice(start,end):切去索引值start到索引值end的数组,不包含end索引的值,返回值是切出来的数组