备战2020

一、window对象与document对象的区别与联系
1、window对象:
概念:是指浏览器打开的窗口。
常见属性:document对象(只读)、location对象、navigator对象(只读)、closed(返回窗口是否关闭 布尔值)、screen系列(screenTop\screenLeft\screenX\screenY)、innerWidth、innerHeight等
常见方法:alert、prompt、blur、focus、print、confirm、scrollTo、moveTo、setTimeout、setInterval、clearTimeout、clearInterval

2、document对象:
概念:载入浏览器的html都会成为一个document对象。(document对象是window对象的一部分,可以在浏览器中window.document展示,由于window是全局变量,所以可以直接打印document)
常用属性:cookie\domain返回当前文档的域名\url\title\lastModified文档最后被修改的日期时间
常用方法:close()\open()\getElementById()\getElementByName\getElementByTagName\write()向文档写html或者js代码

CSS
1、css的盒模型和定位
css盒模型分为:标准盒模型(w3c)和IE盒模型。
区别标准盒模型的width和height是针对content的,IE盒模型的宽高是针对border的。
相同点都具有content\padding\border\margin
切换方法:box-sizing:content-box/border-box
在这里插入图片描述
在这里插入图片描述
2、定位
position:fixed/relative/absolute/static 绝对定位(针对浏览器)/绝对定位(针对不是static的最近的父元素)/相对定位(本身)/默认值(没有定位)
relative和absolute的区别如下
相同点:都是设置定位属性后,通过top、bottom、left、right进行定位操作;可以使用z-index进行层次分级
不同点:a、 relative是针对本身静态位置的定位,absolute是针对距离最近的具有定位属性(不是static)的父元素的位置进行定位,如没有就是针对body的定位
b、相对定位不脱离文档流,绝对定位脱离文档流

3、浮动
产生原因:子元素设置样式float:left/right,父元素的内容不会被撑开导致背景、border、margin无法显示
清除浮动方法:
a、作用于子元素的最后添加一个新元素 clear:both; height:0; line-height:0
b、作用于父元素:overflow:hidden/auto;zoom:1
c、作用于子元素,类似于方法a,使用伪类替代最后一个元素 :after{ clear:both; content:'.'; display: block; width: 0; height:0; visibility:hidden}

4、如何保持浮层水平垂直居中
方法一:定位方法

.parent{
  position: relative;
  width: 200px;
  height:200px;
}
.child{
  position: absolute;
  width: 50px;
  height:50px;
  left: 50%;
  top: 50%;
  transform: transilate(-50%,-50%)
}

方法二:使用margin:0 auto;
方法三:使用vertical-align:middle(平时只能使用在父元素为td或者th中,其他的如div、p元素可以使用display:table-cell激活)

.parent{
  width:200px;
  height:200px;
  display: table-cell;
  vertical-align: middle;
  text-align:center;
  display:table-cell
}
.child{
  display:inline-block //这个保证水平居中
}

5、display的取值和含义
display:none、inline、inline-block、block、flex
a、display:none 对比 visibility:hidden 都是隐藏盒子,前者不占据文档流,后者占据
b、display:inline/block 设置元素为行内元素或者块级元素。inline的内容有多少高度就是多少,水平布局,不能设置宽高;block类似是盒子可以设置宽高,垂直布局,独占一行
c、inline-block 介于两者之间,水平布局但是可以设置宽高
d、display:flex 弹性盒布局模型,其子元素的float、clear、vertical-align失效

提问:给行内元素设置宽高
display:inline-block;position:absolute;float:left / right;后面两行代码自动将行内元素转换成inline-block
6、选择器优先级
!important>内联样式>id选择器>class类选择器=属性选择器=伪类选择器>标签选择器=伪元素选择器>通配符选择器
说明:
a、同一级别比较的是数量,不同级别在数量上没有可比性,数量多不能改变优先级
b、如果优先级相同,后来者居上
c、样式的优先级与选择器的优先级决定,与元素距离目标元素远近无关

7、弹性盒模型
display:flex

vue

一、MVVM的理解

Model:数据模型,用来进行数据处理和业务逻辑处理
view:UI组件,用来将数据用UI 的方式呈现出来
viewModel:监听数据变化和控制视图,将model和view层使用双向数据绑定连接起来,实现两者的自动同步。
优点:可以将更多精力放在业务逻辑上面,不用手动操作dom,不需要关心数据的同步问题

提问:UI中有一个li列表,它是怎么与我们的数据对应的
解答:ul与li都不能使用v-model,可以使用下面方式绑定data中的变量

 <li v-for=“item in list” :key="item">{{item}}</li>

二、vue双向数据绑定原理

https://www.jianshu.com/p/3e6b89d7d7ad
一句话总结:数据劫持 结合 发布者-订阅者模式(

发布者-订阅者模式:当数据变动时,发布消息给订阅者

observer:监听器,进行数据劫持(Object.defineProperty() 劫持各个属性的getter和setter),如有变化通知订阅者
watcher:订阅者,当有属性变化的通知就执行相应的更新函数,更新视图(消息订阅器Dep来专门收集这些订阅者)
compile:解析器,扫描解析各个节点的指令,将相关指令对应初始化成一个订阅者Watcher,并替换模板数据或者绑定相应的函数

综上所述:
数据劫持和发布者-订阅者模式实现的双向数据绑定。重点是使用了Object.defineProperty()方法劫持数据,参数分别为对象,属性名,属性的特性。打印出对象可以看到属性特性中有set和get函数,对应的setter和getter访问器属性,分别用于设置和获取属性值。每个属性分配一个订阅者集合的管理数组dep订阅器,当获取属性值时触发getter,可以用于在编译时为dep中添加订阅者(watcher自身触发getter)。当input的监听事件发现改变属性值时触发setter,可以用于触发订阅者自身的update方法更新视图。
第一步:
需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter
这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化

第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图

第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。

第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

在这里插入图片描述

详细解说:

observer


数据劫持:使用Object.defineProperty()方法
接受三个参数:目标对象,目标对象的属性,目标对象的属性的特性
返回值:目标对象
对象有两种属性:数据属性和访问器属性,下图为打印出的obj={},get和set对应的函数就是访问器属性,分别用来获取属性和设置属性。
在这里插入图片描述

 const obj={};
 Object.defineProperty(obj,'name',{
      get:function () {    //getter:属性被获取的时候触发
         console.log('obj的name属性被获取了')
              return obj
      } ,
      set:function (newVal) {  //setter:属性被赋值的时候触发,只要数据变化了就会触发该函数,所以更新的方法放在这里
         console.log('obj的name属性重置为'+newVal);
       } });
  obj.name = 'fanym';
  const name = obj.name;
  console.log(name);

运行结果:
obj的name属性重置为fanym
obj的name属性被获取了

实现一个简单的双向数据绑定
效果:
在这里插入图片描述
代码:

 <div>
    <input type="text" id="txt">
    <p id="show"></p>
 </div>
const obj = {}
   Object.defineProperty(obj,'txt',{
         get:function () {
               return obj
          },
         set:function (newVal) {
              document.getElementById('txt').value = newVal;
              document.getElementById('show').innerHTML = newVal;
         }
   });
   document.addEventListener('keyup',function (e) {
         obj.txt = e.target.value
   });

(视图变化–》数据变化) 实现方法:给视图添加一个监听函数
(数据变化–》视图变化) 实现方法:在setter访问器属性中添加更新操作
在这里插入图片描述

监视器observer:
function defineReactive(data, key, val) { //对象、属性名、属性值
    observe(val); // 递归遍历所有子属性
    Object.defineProperty(data, key, {  //监听属性变化
        enumerable: true,  //可枚举
        configurable: true,
        get: function() {
            return val;
        },
        set: function(newVal) {
            val = newVal;
            console.log('属性' + key + '已经被监听了,现在值为:“' + newVal.toString() + '”');
        }
    });
}
 
function observe(data) {  // 递归遍历所有子属性
    if (!data || typeof data !== 'object') {
        return;
    }
    Object.keys(data).forEach(function(key) {
        defineReactive(data, key, data[key]);
    });
};
 
示例:
var library = {
    book1: {
        name: ''
    },
    book2: ''
};
observe(library);
library.book1.name = 'vue权威指南'; // 属性name已经被监听了,现在值为:“vue权威指南”
library.book2 = '没有此书籍';  // 属性book2已经被监听了,现在值为:“没有此书籍”

订阅器Dep负责收集订阅者,然后在属性变化的时候执行对应订阅者的更新函数。改造Observer,植入消息订阅器

function defineReactive(data, key, val) { 
    observe(val); 
    var dep = new Dep();   //构造订阅器
    Object.defineProperty(data, key, {
        enumerable: true,
        configurable: true,
        get: function() {
            if (是否需要添加订阅者) {
                dep.addSub(watcher); // 在这里添加一个订阅者
            }
            return val;
        },
        set: function(newVal) {
            if (val === newVal) {
                return;
            }
            val = newVal;
            console.log('属性' + key + '已经被监听了,现在值为:“' + newVal.toString() + '”');
            dep.notify(); // 如果数据变化,通知所有订阅者
        }
    });
}
 //设置Dep订阅器的构造函数,dep相当于一个容器,使用list包裹所有的订阅者
function Dep () {
    this.subs = [];
}
Dep.prototype = {
    addSub: function(sub) {  //添加订阅者函数
        this.subs.push(sub);
    },
    notify: function() {  //更新函数
        this.subs.forEach(function(sub) {
            sub.update();
        });
    }
};

订阅者watcher:


function Watcher(vm, exp, cb) {
    this.cb = cb;
    this.vm = vm;  //data对象
    this.exp = exp;  //属性
    this.value = this.get();  // 将自己添加到订阅器的操作
}
 
Watcher.prototype = {
    update: function() {
        this.run();
    },
    run: function() {
        var value = this.vm.data[this.exp];
        var oldVal = this.value;
        if (value !== oldVal) {
            this.value = value;
            this.cb.call(this.vm, value, oldVal);
        }
    },
    get: function() {
        Dep.target = this;  // 缓存自己
        var value = this.vm.data[this.exp]  // 强制执行监听器里的get函数
        Dep.target = null;  // 释放自己
        return value;
    }
};
function defineReactive(data, key, val) {
    observe(val); // 递归遍历所有子属性
    var dep = new Dep(); 
    Object.defineProperty(data, key, {
        enumerable: true,
        configurable: true,
        get: function() {
            if (Dep.target) {  // 判断是否需要添加订阅者
                dep.addSub(Dep.target); // 在这里添加一个订阅者
            }
            return val;
        },
        set: function(newVal) {
            if (val === newVal) {
                return;
            }
            val = newVal;
            console.log('属性' + key + '已经被监听了,现在值为:“' + newVal.toString() + '”');
            dep.notify(); // 如果数据变化,通知所有订阅者
        }
    });
}
Dep.target = null;

三、vue的生命周期

8个阶段:创建前后、挂载前后、更新前后、销毁前后
对应的钩子函数:beforeCreate/created,beforeMount/mounted,beforeUpdate/updated,beforeDestroy/destroyed

流程:
1、创建vue实例,new Vue()
2、创建实例的时候,执行init()初始化,首先会调用beforeCreate,this指向vm实例,此时method,data,watch,computed不能使用;添加loading,在加载实例时触发
3、监听data数据,初始化vue内部事件,进行属性和方法的计算
4、实例创建完成后调用created,此时data,computed、watch、methods中的方法都可用, e l 还 不 能 访 问 , el还不能访问, el访refs属性内容为空数组;此处可以进行ajax调用,结束loading事件
5、模板编译:将data对象里面的数据和vue语法写的模板编译成html(查找el挂载元素,如果没有调用this.$mount(el),如果有查找实例内部是否有template属性,如果有直接调用,没有的话调用外部html,否则报错)
6、模板编译完成调用beforeMount
7、render函数执行生成虚拟dom,挂载到真实dom上
8、挂载后调用mounted;处理dom
9、数据变化调用beforeUpdate,经理虚拟dom,更新完成后调用updated
10组件销毁前后调用beforeDestroy、destroyed

提问:
1、初始化组件,执行的钩子函数
beforeCreate/Created/beforeMount/mounted

四、vue原理之渲染函数
vue实例创建之后,开始模板(template中的html)编译成ast(抽象语法树),render函数将ast转换成虚拟dom,并通过Patch渲染到真实dom上
渲染过程中有数据变化时,每个组件对应的watcher订阅层会根据数据依赖触发setter函数来更新视图,采用的是diff算法,根据最小的变动进行更新,这里涉及的就是vue响应式即双向数据绑定

五、Vue的性能优化

六、Vuex
vuex是vue的状态管理,vuex中包含三部分:state、mutations、actions、getter,下面一一说明:
state:一般异步请求的数据放在这里,用于存储数据
mutation:参数1是state,参数2是传递的数据,对数据进行处理并赋值。根据某个actionType更改对应的state中的某个值
action:页面view更改后监听函数触发action,在此处可以进行异步操作,拿到更改的数据,并根据actionType通知mutation进行更改
getters:将所有的数据暴露出来,可以在任何组件进行取用

注意:mapGetters位于computed中,相当于解构赋值,与mapState的区别:源值,直接从state中映射过来的。
mapAction位于methods中,当有更改调用对应的action进行操作,如果没有action可以使用this.$store.commit(‘actionType’,data)通知mutation进行修改state

七、父子组件传值
父传子:在父页面中引用子组件的标签上绑定父组件的属性值,在子组件中的props中可以获取这个属性值

父:<blog-post :title='title' />
子:export default {
  props: {
    title: {
      type: String,
      default: 'hello world'
    }
  }
}

子传父:在子组件中this.$emit(‘方法名’,data),在父组件引用子标签中<child @方法名=‘parent’ />,在parent方法的参数就是传递过来的数据

<!-- 父组件 -->
<template>
    <div class="test">
      <test-com @childFn="parentFn"></test-com>
      <br/> 
      子组件传来的值 : {{message}}
    </div>
</template>

<script>
export default {
    // ...
    data: {
        message: ''
    },
    methods: {
       parentFn(payload) {
        this.message = payload;
      }
    }
}
</script>
<!-- 子组件 -->
<template> 
<div class="testCom">
    <input type="text" v-model="message" />
    <button @click="click">Send</button>
</div>
</template>
<script>
export default {
    // ...
    data() {
        return {
          // 默认
          message: '我是来自子组件的消息'
        }
    },
    methods: {
      click() {
            this.$emit('childFn', this.message);
        }
    }    
}
</script>

js

1、css的line-height:1.5,line-height:150%,line-height:1.5em,line-height:15px的区别
最近子元素行高的1.5倍
100%=1em 150%相当于1.5em
1em=16px

2、闭包

function f1(){
        var n = 123;
        function f2(){    //f2是一个闭包
            alert(n)
        }    
        return f2;
    }

应用:在函数外部可以拿到函数内部的变量,即使函数调用后寿命终结了也可以,
概念:
js链式作用域
子对象会一级一级向上寻找所有父对象的变量,反之不行。
js变量两种作用域?
全局变量、局部变量(函数内):js中函数内部可以读取全局变量,函数外部不能读取函数内部的局部变量。

3、浏览器兼容问题
css样式方面:
(1)内外补丁:*{padding:0,margin:0}
(2)hack的使用:ie6使用下划线_ 和星号 *,ie7使用星号 *
(3)几个img标签放在一起的时候,有些浏览器会有默认的间距:使用float进行布局
(4)块级元素float+横向的margin,margin值会变大:设置display:inline
js方面:
(1)事件绑定:
IE:dom.attachEvent();
其他浏览器:dom.addEventListener();

// 获取浏览器可视窗口的宽度与高度:
var clientWidth = document.documentElement.clientWidth || document.body.clientWidth;
var clientHeight = document.documentElement.clientHeight || document.body.clientHeight;

// 获取事件源元素:
// 备注:event是事件函数的参数。
const event = event || window.event;
const target = event.srcElement || event.target;

// 请注意:下方的处理都默认event已经按照上面的写法兼容过衍生的
// 阻止事件冒泡和浏览器默认行为
event.preventDefault 
	? event.preventDefault()
	: event.returnValue = false; 
// 只阻止事件冒泡
event.stopPropagation 
	? event.stopPropagation(); 
	: event.cancelBubble = true;

// 注册和解除事件监听器的兼容写法
const EventListen = {
   addEvent(ele,fn,str) {
        //通过判断调用的方式兼容IE678
        //判断浏览器是否支持该方法,如果支持那么调用,如果不支持换其他方法
        if(ele.addEventListener){ //火狐谷歌IE9+支持addEventListener
            //直接调用
            ele.addEventListener(str,fn);
        }else if(ele.attachEvent){ //IE678支持attachEvent
            ele.attachEvent("on"+str,fn);
        }else{
            //在addEventListener和attachEvent都不存在的情况下,用此代码
            ele["on"+str] = fn;
        }
    },
    removeEvent (ele,fn,str) {
        if(ele.removeEventListener){
            ele.removeEventListener(str,fn);
        }else if(ele.detachEvent){
            ele.detachEvent("on"+str,fn);
        }else{
            ele["on"+str] = null;
        }
    }
};
EventListen.addEvent(element, function() {}, 'click');

4、事件冒泡和捕获
addEventListener(‘事件名’,“”,false)==三参是false对应的maopao
两种方式来阻止事件冒泡。
方式一:event.stopPropagation();
方式二:return false;
区别:return false 不仅阻止了事件往上冒泡,而且阻止了事件本身。event.stopPropagation() 则只阻止事件往上冒泡,不阻止事件本身。

react

一、

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值