css部分
1.css盒模型
box-sizing: content-box(W3C盒模型,又名标准盒模型):元素的宽高大小表现为内容的大小。
box-sizing: border-box(IE盒模型,又名怪异盒模型):元素的宽高表现为内容 + 内边距 + 边框的大小。
2.清除浮动的几种方式
- 在浮动元素后面添加 clear:both 的空 div 元素
<div class="container">
<div class="left"></div>
<div class="right"></div>
<div style="clear:both"></div>
</div>
- 给父元素添加 overflow:hidden 或者 auto 样式,触发BFC。
<div class="container">
<div class="left"></div>
<div class="right"></div>
</div>
.container{
width: 300px;
background-color: #aaa;
overflow:hidden;
zoom:1; /*IE6*/
}
- 使用伪元素,也是在元素末尾添加一个点并带有 clear: both 属性的元素实现的。
<div class="container clearfix">
<div class="left"></div>
<div class="right"></div>
</div>
.clearfix:after{
content: ".";
height: 0;
clear: both;
display: block;
visibility: hidden;
}
推荐使用第三种方法,不会在页面新增div,文档结构更加清晰。
3.移动端1px解决方案
- 伪元素+scale
<style>
.box{
width: 100%;
height: 1px;
margin: 20px 0;
position: relative;
}
.box::after{
content: '';
position: absolute;
bottom: 0;
width: 100%;
height: 1px;
transform: scaleY(0.5);
transform-origin: 0 0;
background: red;
}
</style>
<div class="box"></div>
- border-image
div{
border-width: 1px 0px;
-webkit-border-image: url(border.png) 2 0 stretch;
border-image: url(border.png) 2 0 stretch;
}
4.两边宽度固定中间自适应的三栏布局
- 圣杯布局
<style>
body{
min-width: 550px;
}
#container{
padding-left: 200px;
padding-right: 150px;
}
#container .column{
float: left;
}
#center{
width: 100%;
}
#left{
width: 200px;
margin-left: -100%;
position: relative;
right: 200px;
}
#right{
width: 150px;
margin-right: -150px;
}
</style>
<div id="container">
<div id="center" class="column">center</div>
<div id="left" class="column">left</div>
<div id="right" class="column">right</div>
</div>
- 双飞翼布局
<style>
body {
min-width: 500px;
}
#container {
width: 100%;
}
.column {
float: left;
}
#center {
margin-left: 200px;
margin-right: 150px;
}
#left {
width: 200px;
margin-left: -100%;
}
#right {
width: 150px;
margin-left: -150px;
}
</style>
<div id="container" class="column">
<div id="center">center</div>
</div>
<div id="left" class="column">left</div>
<div id="right" class="column">right</div>
5.不定宽高的元素怎么水平垂直居中
1.最简单的flex布局,外层容器加上如下样式即可
display:-webkit-flex;
justify-content:center; /*水平居中*/
align-items:center; /*垂直居中*/
2.利用table-cell
外层容器:
display:table-cell;
text-align:center;
vertical-align:middle;
内层元素
display:inline-block;
vertical-align:middle;
3.CSS3 transform
外层容器:
position:relative
内层元素
transform: translate(-50%,-50%);
position: absolute;
top: 50%;
left: 50%;
6.左边固定宽度,右边自适应怎么布局?
1.使用flex
.outbox {
width: 100%;
height: 100%;
display: flex;
}
.left {
width: 100px;
height: 100%;
background: red;
}
.right {
flex: 0 0 0 100px;
width: 100%;
height: 100%;
background: green;
}
2.使用定位
.outbox {
width: 100%;
height: 100%;
position: relative;
}
.left {
width: 100px;
height: 100%;
background: red;
}
.right {
height: 100%;
position: absolute;
top:0;
right: 0;
left: 100px;
background: green;
}
7.元素隐藏的几种方法,有啥区别
- opacity=0,该元素隐藏起来了,但不会改变页面布局,并且,如果该元素已经绑定一些事件,如click事件,那么点击该区域,也能触发点击事件的
- visibility=hidden,该元素隐藏起来了,但不会改变页面布局,但是不会触发该元素已经绑定的事件
- display=none,把元素隐藏起来,并且会改变页面布局,可以理解成在页面中把该元素删除掉一样。
- 使用定位 定位数值写的特别大 让飞出页面外 比如:left:-9999px;
- z-index=-1置于其他元素下面
js部分
1.js中基本的数据类型有几种
七种。分别是number、string、boolean、undefined、null、symbol(es6)、bigint(es10)-任 意精度整数
判断数据类型的方法
1)typeof:返回一个表示数据类型的字符串
优点:能够快速区分基本数据类型 缺点:不能将Object、Array和Null区分,都返回object
typeof Symbol();//symbol 有效
typeof '';//string 有效
typeof 1;//number 有效
typeof true;//boolean 有效
typeof undefined;//undefined 有效
typeof new Function();// function 有效
typeof null;//object 无效
typeof [];//object 无效
typeof {};//object无效
typeof new Date();//object 无效
typeof new RegExp();//object 无效
2)instanceof:只适用于对象、不能检测基本类型
instanceof 是用来判断A是否为B的实例,表达式为:A instanceof B,如果A是B的实例,则返回true,否则返回false。instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性,但它不能检测null 和 undefined
优点:能够区分Array、Object和Function,适合用于判断自定义的类实例对象 缺点:Number,Boolean,String基本数据类型不能判断
2 instanceof Number; // false
true instanceof Boolean; // false
'str' instanceof String; // false
[] instanceof Array; // true
function(){} instanceof Function; // true
{} instanceof Object; // true
new Date() instanceof Date; //true
new RegExp() instanceof RegExp; //true
null instanceof Null //报错
undefined instanceof undefined //报错
- Object.prototype.toString.call() 是最准确最常用的方式
Object.prototype.toString.call().slice(8,-1); 得到准确的类型
优点:精准判断数据类型 缺点:写法繁琐不容易记,推荐进行封装后使用
Object.prototype.toString.call('');// [object String]
Object.prototype.toString.call(1);// [object Number]
Object.prototype.toString.call(true);// [object Boolean]
Object.prototype.toString.call(undefined);// [object Undefined]
Object.prototype.toString.call(null);// [object Null]
Object.prototype.toString.call(new Function());// [object Function]
Object.prototype.toString.call(new Date());// [object Date]
Object.prototype.toString.call([]);// [object Array]
Object.prototype.toString.call(new RegExp());// [object RegExp]
Object.prototype.toString.call(new Error());// [object Error]
- constructor
constructor作用和instanceof非常相似。但constructor检测 Object与instanceof不一样,还可以处理基本数据类型的检测。不过函数的 constructor 是不稳定的,这个主要体现在把类的原型进行重写,在重写的过程中很有可能出现把之前的constructor给覆盖了,这样检测出来的结果就是不准确的。
''.constructor === String;//true
[].constructor === Array;//true
2. 变量声明
函数声明优先于变量声明
变量提升只提升函数声明,并不提升函数表达式,所以函数声明可以放在任何地方被调用,函数表达式要在定义后进行使用。
var a;
function a(){}
console.log(typeof a); //function
或许有人是认为函数声明在后面的原因,那么调换一下位置。
function a(){}
var a;
console.log(typeof a); //function
调换位置后变量a的类型还是function,这时候声明变量a的语句没有起作用,被函数声明覆盖了。因此函数声明优先于变量的声明。
但是如果我们在声明的同时给a进行赋值。
function a(){}
var a='xyf';
console.log(typeof a); //string
我们将其调换一下位置再次进行验证。
var a='xyf';
function a(){}
console.log(typeof a); //string
可以看到,给变量a进行赋值后,不管变量a在哪,其类型变为字符串类型,上面两段代码相当于如下代码:
function a(){}
var a;
a='xyf';
console.log(typeof a); //string
3.==和===区别
- ==, 两边值类型不同的时候,要先进行类型转换,再比较
- ===,不做类型转换,类型不同的一定不等。
==类型转换过程:
1)如果类型不同,进行类型转换
2)判断比较的是否是 null 或者是 undefined, 如果是, 返回 true .
3)判断两者类型是否为 string 和 number, 如果是, 将字符串转换成 number
4)判断其中一方是否为 boolean, 如果是, 将 boolean 转为 number 再进行判断
5)判断其中一方是否为 object 且另一方为 string、number 或者 symbol , 如果是, 将 object 转为原始类型再进行判断
4.js中浮点数精度问题(0.1+0.2!=0.3怎么处理)
最近在做项目的时候,涉及到商品价格的计算,经常会出现计算出现精度问题。
toFixed奇葩问题
在遇到浮点数运算后出现的精度问题时,刚开始我是使用toFixed(2)来解决的。但是在chrome下测试结果不太令人满意:
1.35.toFixed(1) // 1.4 正确
1.335.toFixed(2) // 1.33 错误
1.3335.toFixed(3) // 1.333 错误
1.33335.toFixed(4) // 1.3334 正确
1.333335.toFixed(5) // 1.33333 错误
1.3333335.toFixed(6) // 1.333333 错误
使用IETester在IE下面测试的结果却是正确的。
把需要计算的数字升级(乘以10的n次幂)成计算机能够精确识别的整数,等计算完成后再进行降级(除以10的n次幂),即:
(0.1*10 + 0.2*10)/10 == 0.3 //true
5.深拷贝、浅拷贝
参考链接:www.cnblogs.com/echolun/p/7…
深拷贝的实现方法
- 使用递归去复制所有层级属性
function deepClone(obj) {
let result;
if (typeof obj == 'object') {
result = isArray(obj) ? [] : {}
for (let i in obj) {
//isObject(obj[i]) ? deepClone(obj[i]) : obj[i]
//多谢"朝歌在掘金"指出,多维数组会有问题
result[i] = isObject(obj[i])||isArray(obj[i])?deepClone(obj[i]):obj[i]
}
} else {
result = obj
}
return result
}
function isObject(obj) {
return Object.prototype.toString.call(obj) == "[object Object]"
}
function isArray(obj) {
return Object.prototype.toString.call(obj) == "[object Array]"
}
- JSON对象的parse和stringify
- JQ的extend方法
$.extend( [deep ], target, object1 [, objectN ] )
deep表示是否深拷贝,为true为深拷贝,为false,则为浅拷贝
target Object类型 目标对象,其他对象的成员属性将被附加到该对象上。
object1 objectN可选。 Object类型 第一个以及第N个被合并的对象。
- 热门的函数库lodash,也有提供_.cloneDeep用来做深拷贝
不完全拷贝(只能拷贝一级属性、二级属性没拷贝成功)的方法
- slice() 针对数组
- concat() 针对数组
浅拷贝方法:
object.assign() 针对对象
6.给ul下面的li加上点击事件,点击哪个li,就显示那个li的innerHTML
考点:事件委托
var oUl=document.getElementById("ul-test");
oUl.addEventListener("click",function(ev){
var ev=ev||window.event;
var target=ev.target||ev.srcElement;
//如果点击的最底层是li元素
if(target.tagName.toLowerCase()==='li'){
alert(target.innerHTML)
}
})
如果是将事件绑定在每一个li标签上,会有什么问题?
var oUl=document.getElementById("ul-test");
var oLi=oUl.getElementsByTagName("li");
for(var i=0,len=oLi.length;i<len;i++){
oLi[i].addEventListener("click",function(){
alert(this.innerHTML)
})
}
1.for循环,循环的是li,10个li就循环10次,绑定10次事件,100个就循环了100次,绑定100次事件!
2.如果li不是本来就在页面上的,是未来元素,是页面加载了,再通过js动态加载进来了,上面的写法是无效的,点击li是没有反应的!
7.比如有一个需求,往ul里面添加10个li,如下代码
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<ul id="ul-test">
</ul>
</body>
<script type="text/javascript">
var oUl=document.getElementById("ul-test");
for(var i=0;i<10;i++){
var oLi=document.createElement('li');
oLi.innerHTML=i;
oUl.appendChild(oLi);
}
</script>
</html>
问题:这里相当于操作了10次DOM,有什么方案,减少DOM的操作次数?
- innerHtml
var oUl=document.getElementById("ul-test");
//定义临时变量
var _html='';
for(var i=0;i<10;i++){
//保存临时变量
_html+='<li>'+i+'</li>'
}
//添加元素
oUl.innerHTML=_html;
- 文档碎片
var oUl=document.getElementById("ul-test"),
_frag = document.createDocumentFragment();
for(var i=0;i<10;i++){
var oLi=document.createElement('li');
oLi.innerHTML=i;
//把元素添加进文档碎片
_frag.appendChild(oLi);
}
//把文档碎片添加进元素
oUl.appendChild(_frag);
8.跨域
什么是跨域:浏览器有同源策略,不允许ajax访问其他域的接口。协议、域名、端口有一个不同就算跨域
但是有三个标签允许跨域 link script img
怎么解决跨域:
- jsonp:即json+padding,动态创建script标签,利用script标签的src属性可以获取任何域下的js脚本,通过这个特性(也可以说漏洞),服务器端不在返回json格式,而是返回一段调用某个函数的js代码,在src中进行了调用,这样实现了跨域.
<script>
window.callback= function (data) {
//这里是跨域得到的信息
console.log(data)
}
</script>
<script src="xxx.js"></script>
//以上将返回格式为callback({x:100,y:100})
<script>
function createJs(sUrl){
var oScript = document.createElement('script');
oScript.type = 'text/javascript';
oScript.src = sUrl;
document.getElementsByTagName('head')[0].appendChild(oScript);
}
createJs('jsonp.js');
function box(json){alert(json.name);}
box({'name': 'test'});
</script>
参考链接🔗:blog.csdn.net/hansexplora…
- webpack设置代理 proxyTable属性
- 服务器代理
9.this的指向问题
箭头函数:指向函数所在的作用域:注意理解作用域,只有函数的{}构成作用域,对象的{}以及 if(){}都不构成作用域;
10.继承的几种方式
如何理解原型跟原型链??
1)原型链继承:让新实例的原型等于父类的实例。可以继承构造函数里面的属性和方法 也可以继承原型链上面的属性和方法
特点:实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:
- 新实例无法向父类构造函数传参。
- 继承单一。
- 所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)
缺点1代码举例:
function Person(name){
this.name = name;
this.run = function(){
alert(this.name+'在运动');
}
}
Person.prototype.age = 10;
Person.prototype.work = function(){
alert(this.name+'在工作');
}
//web类继承Person类 原型链继承模式
function Web(name){}
Web.prototype = new Person();
var w = new Web('李四');//实例化子类的时候没办法给父类传承
w.run();//undefined在运动
w.work();//undefined在工作
缺点3代码举例:
function Person() {
this.name = '张三';
this.colors = ['red','blue'];
this.run = function () {
console.log(this.name + '在运动');
}
}
Person.prototype.work = function () {
console.log(this.name + '在工作');
};
//web类继承Person类 原型链继承模式
function Web() {}
Web.prototype = new Person();
var w = new Web();
var w1 = new Web();
w.colors.push('yellow');//一个实例修改了原型属性,另一个实例的原型属性也会被修改!
w.run();//张三在运动
w.work();//张三在工作
console.log(w.colors);//['red','blue','yellow']
w1.run();//张三在运动
w1.work();//张三在工作
console.log(w1.colors);//['red','blue','yellow']
console.log(Web instanceof Person);//true
2)构造函数继承:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制),可以继承构造函数里面的属性和方法,但是没法继承原型链上面的属性和方法
特点:
- 只继承了父类构造函数的属性,没有继承父类原型的属性。
- 解决了原型链继承缺点1、2、3。
- 可以继承多个构造函数属性(call多个)。
- 在子实例中可向父实例传参。
缺点:
- 只能继承父类构造函数的属性。
- 无法实现构造函数的复用。(每次用每次都要重新调用)
- 每个新实例都有父类构造函数的副本,臃肿。
function Person(name) {
this.name = name;
this.colors = ['red','blue'];
this.run = function () {
console.log(this.name + '在运动');
}
}
Person.prototype.work = function () {
console.log(this.name + '在工作');
};
//web类继承Person类 构造函数继承模式
function Web(name) {
Person.call(this, name);
}
var w = new Web('张三');
var w1 = new Web('李四');
w.colors.push('yellow');
w.run();//张三在运动
w.work();//报错 构造函数继承没法继承原型链上面的属性和方法
console.log(w.colors);//['red','blue','yellow']
w1.run();//李四在运动
w1.work();//报错 构造函数继承没法继承原型链上面的属性和方法
console.log(w1.colors);//['red','blue']
console.log(w instanceof Person); //false
3)组合继承:常用,组合原型链继承和借用构造函数继承
特点:
- 使用原型链实现对原型方法的继承,而通过借用构造函数来实现对实例属性的继承。
- 可以继承父类原型上的属性,可以传参,可复用。
- 每个新实例引入的构造函数属性是私有的
缺点:调用了两次父类构造函数,一次是在创建子类型原型的时候,另一次是在子类型构造函数内部,(消耗内存),子类的构造函数会代替原型上的那个父类构造函数。
function Person(name) {
this.name = name;
this.colors = ['red','blue'];
this.run = function () {
console.log(this.name + '在运动');
}
}
Person.prototype.work = function () {
console.log(this.name + '在工作');
};
//web类继承Person类 组合继承模式
function Web(name) {
Person.call(this, name); //第二次调用 Person() 子类的构造函数会代替原型上的那个父类构造函数。
}
Web.prototype = new Person(); //第一次调用 Person()
var w = new Web('张三');
var w1 = new Web('李四');
w.colors.push('yellow');
w.run();//张三在运动
w.work();//张三在工作
console.log(w.colors);//['red','blue','yellow']
w1.run();//李四在运动
w1.work();//李四在工作
console.log(w1.colors);//['red','blue']
4)原型式继承:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:
- 所有实例都会继承原型上的属性。包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样。
- 无法实现复用。(新实例属性都是后面添加的)
function createObj(o) {
function F() {}
F.prototype = o;
return new F();
}
var person = {
name: '111',
friend: ['aaa', 'bbb']
};
var person1 = createObj(person);
person1.name = '222';
person1.friend.push('ccc');
console.log(person1.name); //222
console.log(person1.friend); //['aaa','bbb','ccc']
var person2 = createObj(person);
person2.name = '333';
console.log(person2.name); //333
console.log(person2.friend); //['aaa','bbb','ccc']
console.log(person.name); //111
console.log(person.friend); //['aaa','bbb','ccc']
5)寄生式继承:寄生继承的思想是创建一个用于封装继承过程的函数,该函数在内部以某种方式来增强对象。最后返回对象。可以理解为在原型式继承的基础上新增一些函数或属性
缺点:没用到原型,无法复用。
function createObj(o) {
function F() {}
F.prototype = o;
return new F();
}
var person = {
name: '111',
friend: ['aaa', 'bbb']
};
var person1 = createObj(person);
console.log(person1.name); //111
function createOb(o) {
var newObj = createObj(o);
newObj.sayName = function () {// 增强对象
console.log(this.name);
};
return newObj// 指定对象
}
var person2 = createOb(person1);
person2.sayName();//111
6)寄生组合继承:(常用)子类构造函数复制父类的自身属性和方法,子类原型只接收父类的原型属性和方法。
所谓寄生组合继承,即通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。
其背后的基本思路是:不必为了指定子类型的原型而调用超类型的构造函数,我们所需要的无非就是超类型的原型的一个副本而已。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给予类型的原型。
优点: 这种方式的高效率体现它只调用了一次Parent构造函数,并且因此避免了再Parent.prototype上面创建不必要的,多余的属性。普遍认为寄生组合式继承是引用类型最理想的继承方式
function Parent(name) {
this.name = name;
this.colors = ['red','blue'];
this.run = function () {
console.log(this.name + '在运动');
}
}
Parent.prototype.work = function () {
console.log(this.name + '在工作');
};
//web类继承Person类 原型链继承模式
function Child(name) {
Parent.call(this, name);
}
function createObj(o) {
function F() {}
F.prototype = o;
return new F();
}
// Child.prototype = new Parent(); // 这里换成下面
function prototype(child,parent) {
var prototype = createObj(parent.prototype);
prototype.constructor = child;
child.prototype = prototype
}
prototype(Child,Parent);
var child = new Child('张三');
console.log(child.name); //张三
11.函数节流、函数防抖
函数防抖:如果一个事件被频繁触发多次,并且触发的时间间隔过短,则防抖函数可以使得对应的事件处理函数只执行最后触发的一次。函数防抖可以把多个顺序的调用合并成一次。
function debounce(fn, delay, scope) {
let timer = null;
// 返回函数对debounce作用域形成闭包
return function () {
// setTimeout()中用到函数环境总是window,故需要当前环境的副本;
let context = scope || this, args = arguments;
// 如果事件被触发,清除timer并重新开始计时
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(context, args);
}, delay);
}
}
函数节流:如果一个事件被频繁触发多次,节流函数可以按照固定频率去执行对应的事件处理方法。函数节流保证一个事件一定时间内只执行一次。
# 利用时间戳简单实现(先执行目标函数,后等待规定的时间段;)
function throttle(fn, threshold, scope) {
let timer;
let prev = 0;
return function () {
let context = scope || this, args = arguments;
let now = Date.now();
if (now - prev > threshold) {
fn.apply(context, args);
prev = now;
}
}
}
# 利用定时器简单实现(先等待够规定时间,再执行)
function throttle2(fn, threshold, scope) {
let timer;
return function () {
let context = scope || this, args = arguments;
if (!timer) {
timer = setTimeout(function () {
fn.apply(context, args);
timer = null;
}, threshold);
}
}
}
# 二者结合(实现一次触发,两次执行(先立即执行,结尾也有执行))
function throttle(fn, cycle) {
let start = Date.now();
let now;
let timer;
return function () {
now = Date.now();
clearTimeout(timer);
if (now - start >= cycle) {
fn.apply(this, arguments);
start = now;
} else {
timer = setTimeout(() => {
fn.apply(this, arguments);
}, cycle);
}
}
}
vue部分
1.delete和Vue.delete删除数组的区别
delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。 Vue.delete直接删除了数组 改变了数组的键值。
var a=[1,2,3,4]
var b=[1,2,3,4]
delete a[1]
console.log(a) //[1,empty,3,4]
this.$delete(b,1)
console.log(b) //[1,3,4]
2.vue组件间通信六种方式
参考链接🔗: mp.weixin.qq.com/s/xAsGUGOl0…
-
props /
emit给父组件发送消息,实际上就是子组件把自己的数据发送到父组件。
-
on
这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案vuex。
3). vuex
4). listeners
listeners 是两个对象,
listeners里存放的是父组件中绑定的非原生事件。
5). provide/inject
Vue2.2.0新增API,这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。一言而蔽之:祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的
6). children & ref
ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
children:访问父 / 子实例
不过,这两种方法的弊端是,无法在跨级或兄弟间通信。
#####常见使用场景可以分为三类:
父子通信: 父向子传递数据是通过 props,子向父是通过 events( emit);通过父链 / 子链也可以通信( parent / children);ref 也可以访问组件实例;provide / inject API; attrs/listeners
兄弟通信: Bus;Vuex
跨级通信: Bus;Vuex;provide / inject API、 attrs/listeners
3.对vue生命周期的理解?
参考链接🔗: segmentfault.com/a/119000001…
总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
创建前/后: 在beforeCreated阶段,vue实例的挂载元素el还没有。
载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:当data变化时,会触发beforeUpdate和updated方法。
销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
其他部分
1.浅谈网站性能之前端性能优化
参考链接🔗: segmentfault.com/a/119000000…
1)减少 HTTP 请求数量
- CSS Sprites : 将多张图片合并成一张图片达到减少 HTTP 请求的一种解决方案,可以通过 CSS background 属性来访问图片内容。
- 合并 CSS 和 JS 文件:现在前端有很多工程化打包工具,如:grunt、gulp、webpack等。为了减少 HTTP 请求数量,可以通过这些工具再发布前将多个 CSS 或者 多个 JS 合并成一个文件。
- 采用 lazyLoad:俗称懒加载,可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容。这样就控制了网页资源一次性请求数量。
2)控制资源文件加载优先级
主要文件放在 head 内部,次要文件放在 body 底部。一般情况下都是 CSS 在头部,JS 在底部。
3)利用浏览器缓存
4)使用CDN
5)减少重排(Reflow):如果需要在 DOM 操作时添加样式,尽量使用 增加 class 属性,而不是通过 style 操作样式。
6)减少 DOM 操作
7)图标使用 IconFont 替换