vue.js
是采用数据劫持结合发布者-订阅者的模式的方法,通过Object.defineProperty()
来劫持各个属性的Getter、setter
,在数据变动时发送消息给订阅者。它实现的整个流程是先为每个vue
属性用Object.defineProperty()
实现数据劫持,为每个属性分配一个订阅者集合的管理数组dep;然后在编译的时候在该属性的数组dep
中添加订阅者
,v-model
就会添加一个订阅者
,接着用input
举例,为input
添加监听事件,修改值就会为这个属性赋值,触发这个属性的set方法
,在set方法
内通知订阅者数组dep
,订阅者数组
循环调用各个订阅者
的update方法
更新视图。然后就实现了数据的双向绑定。
先将img
标签的src
链接设为同一张图片(比如空白图片),然后给img
标签设置自定义属性(比如 data-src
),然后将真正的图片地址存储在data-src
中,当JS监听到该图片元素进入可视窗口时,将自定义属性中的地址存储到src
属性中。达到懒加载的效果。
这样做能防止页面一次性向服务器发送大量请求,导致服务器响应慢,页面卡顿崩溃等。
2.1判断元素是否在可视区域内
元素距离顶部高度(elOffsetTop
) >= dom滚动高度(docScrollTop
)
并且元素距离顶部高度(elOffsetTop
) < (dom滚动高度 + 视窗高度)
虚拟 DOM就是一个JavaScript
的一个对象。对复杂的文档DOM结构,提供一种方便的工具,进行最小化的DOM操作。
其实就是用js来模拟DOM中的节点,就是传说中的虚拟DOM。
diff
的过程就是调用名为patch
的函数,比较新旧节点,一边比较一边给真实的DOM打补丁
首先第一点就是vue2和vue3双向数据绑定原理发生了改变
vue2
的双向数据绑定是利用ES5 的一个 API Object.definePropert()
对数据进行劫持 结合 发布订阅模式的方式来实现的。
vue3
中使用了 es6
的 ProxyAPI
对数据代理。
第二就是vue2默认进行懒观察(lazy observation)。
在 2.x
版本里,不管数据多大,都会在一开始就为其创建观察者。当数据很大时,这可能会在页面载入时造成明显的性能压力。3.x
版本,只会对「被用于渲染初始可见部分的数据」创建观察者,而且 3.x
的观察者更高效。
三就是重写了虚拟 DOM
随着虚拟 DOM 重写,减少 运行时(runtime)开销。重写将包括更有效的代码来创建虚拟节点
四是他们的项目目录结构
vue-cli2.0
与3.0
在目录结构方面,有明显的不同
vue-cli3.0
移除了配置文件目录
,config
和 build
文件夹 同时移除了 static
静态文件夹,新增了 public
文件夹,打开层级目录还会发现, index.html
移动到 public
中
五就是vue3性能的提升
更小巧,更快速;支持摇树优化;支持 分段 (Fragments) 和跨组件渲染;支持自定义渲染器
我最常用的有三种,
第一种是父传子:主要通过 props 来实现的
父传子是通过import
引入子组件,在components
中注册 在父 组件标签上用v-bind
绑定要传递的数据,子组件通过props
接收 并明确传递属性的数据类型
第二种:子传父:主要通过$emit 来实现
子传父通过提交一个$emit
方法,这个方法接收两个参数,第一个是要派发的事件,第二个参数是要传递的参数,然后在组件标签上自定义事件接收这个提交的方法,然后在methods
中定义
第三种:兄弟传值
兄弟传值有两种方法:
首先创建一个空的vue
实例BUS
第一种方法通过BUS.$emit(‘事件名’)
传到空的vue
实例中
第二种方法通过BUS.$on(‘事件名’,(参数)=>{挂载从子1传来的数据})
来接收
第四种:vuex
6.1 vuex的流程
Vuex怎么请求异步数据
1.首先在state中创建变量
2.然后在action中调用封装好的axios请求,异步接收数据,commit提交给mutations
Mutations中改变state中的状态,将从action中获取到的值赋值给state
页面通过mapAction
异步提交事件到action
。action
通过commit
把对应参数同步提交到mutation
,mutation
会修改state
中对应的值。最后通过getter
把对应值跑出去,在页面的计算属性中,通过mapGetter
来动态获取state
中的值
6.2 vuex有五种状态和属性
第一种是State
State
就是存放数据的地方,类似一个仓库 , 特性就是当mutation
修改了state
的数据的时候,他会动态的去修改所有的调用这个变量的所有组件里面的值( 若是store
中的数据发生改变,依赖这个数据的组件也会发生更新 )
第二种是Getters
getters
用来获取数据,mapgetter
经常在计算属性中被使用
第三种就是mutations
他是 唯一更改store
中状态的方法,且必须是同步函数。
第四种是action
他 用于提交 mutation
,而不是直接变更状态,可以包含任意异步操作。
最后一种是moduled
他是store
的子模块,为了开发大型项目,方便状态管理而使用的。
他可以将单一的 Store
拆分为多个 store
并同时保存在单一的状态树中。
vuex的优势
优点:解决了非父子组件的通信,减少了ajax请求次数,有些可以直接从state中获取
缺点:刷新浏览器,vuex中的state会重新变为初始状态,解决办法是vuex-along,得配合计算属性和sessionstorage来实现
vue
中 key
的作用需要使⽤key
来给每个节点做⼀个唯⼀标识,Diff
算法就可以正确的识别此节 点。 作⽤主要是为了⾼效的更新虚拟DOM
。
vue
中的组件中的 data
为什么是 data
函数因为一个组件是可以共享的,但他们的data
是私有的,所以每个组件都要return
一个新的data
对象,返回一个唯一的对象。
Data是一个函数时,每个组件实例都有自己的作用域,每个实例相互独立,不会相互影响
vue
中nextTick
作用nextTick
是在下次DOM
更新循环结束之后执行延迟回调,
在修改数据之后使用nextTick
,就可以在回调中获取更新后的 DOM
.
vue
组件封装我用vue
开发的所有项目,都是采用组件化的思想开发的。一般我在搭建项目的时候,会创建一个views
目录和一个commen
目录和一个feature
目录,views
目录中放页面级的组件,commen
中放公共组件(如:head
(公共头组件),foot(公共底部组件)等),feature
目录内放功能组件(如:swiper
(轮播功能组件),tabbar
(切换功能组件)、list
(上拉加载更多功能组件))
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性低等问题。
使用Vue.extend
方法创建一个组件,然后使用Vue.component
方法注册组件。但是我们一般用脚手架开发项目,每个 .vue单文件就是一个组件。在另一组件import
导入,并在components
中注册,子组件需要数据,可以在props
中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit
方法。
Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、销毁等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,就是生命周期。
总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
创建前/后: 在beforeCreated阶段,vue实例的挂载元素el还没有。在created阶段,vue实例的数据对象data有了,el还没有.
载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。
更新前/后:当data变化时,会触发beforeUpdate和updated方法。
销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在
生命周期中有多个事件钩子,让我们在控制整个 vue 实例的过程时更容易形成好的逻辑
页面第一次加载会触发 beforeCreate、created、beforeMount、mounted
DOM渲染在mounted周期中就已经完成
闭包是用来解决全局变量私有化的,也可以说成局部变量全局化。
闭包是一种保护私有变量的机制,在函数执行时形成私有的作用域,保护里面的私有变量不受外界干扰。
就是当一个函数的返回值是另外一个函数,而返回的那个函数如果调用了其父函数的内部变量,且返回的那个函数在外部被执行,就产生了闭包 。
他的特点就是
函数嵌套函数
内部函数可以直接访问外部函数的内部变量或参数
变量或参数不会被垃圾回收机制回收( GC 项目使用的闭包越多占用的内存越大,要滞空)
闭包的优点是
变量常驻内存 避免全局变量的污染 他有私有成员存在
闭包的缺点就是
常驻内存 增加内存的使用量 使用不当会造成内存泄漏
他可以通过闭包制作计数器 封装私有属性方法 还可以作为一个回调函数 还可以用作函数节流防抖
CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充,和实际内容
。 他分为两种类型 IE盒子模型
和标准W3C盒子模型
,两种盒模型的主要区别就是标准盒模型的宽高是值内容的宽高
,而IE盒模型的宽高是值内容的宽高+填充+边框
;在css中通过box-sizing
设置盒模型; box-sizing:content-box
就是用来设置标准盒模型
; box-sizing:border-box
则用来设置IE盒模型
js
的所有对象中都包含了一个[proto]
内部属性,这个属性所对应的就是自身的原型
。JavaScript
的函数对象,除了原型[proto]
之外,还有prototype
属性,当函数对象作为构造函数创建实例时,该prototype
属性值将被作为实例对象的原型[proto
];原型链
就是当一个对象调用自身不存在的属性或方法时,就会去自己 [proto
] 关联的前辈 prototype
对象上去找,如果没找到,就会去该 prototype
原型 [proto
] 关联的前辈 prototype
去找。依次类推,直到找到属性方法或 undefined
为止。从而形成了所谓的“原型链”。
promise
Promise
对象是CommonJS
工作组提出的一种规范,目的是为异步编程提供统一接口。每一个异步任务返回一个Promise
对象,该对象有一个then
方法,允许指定回调函数。
一个promise
可能有三种状态:等待(pending)
、已完成(resolved,又称fulfilled)
、已拒绝(rejected)
。
promise
必须实现then
方法(可以说,then
就是promise
的核心),而且then
必须返回一个promise
,同一个promise
的then
可以调用多次,并且回调的执行顺序跟它们被定义时的顺序一致。
then
方法接受两个参数,第一个参数是成功
时的回调,在promise
由“等待”态转换到“完成
”态时调用,另一个是失败
时的回调,在promise
由“等待”态转换到“拒绝
”态时调用。同时,then
可以接受另一个promise
传入,也接受类then
的对象或方法
(总的来说,Promise是一个让开发者更合理、更规范地用于处理异步操作的对象。它有三种状态:初始化(pending),操作成功(fulfilled),操作异常(rejected)。使用实例方法:then()和catch()用于绑定处理程序,还有all()和race()方法。)
async
/await
async
/await
其实是Promise
的语法糖,它能实现的效果都能用then链
来实现,它是为优化then链
而开发出来的。从字面上来看,async
是“异步”的简写,await
译为等待,所以我们很好理解async
声明function
是异步的,await
等待某个操作完成。当然语法上强制规定await
只能出现在asnyc
函数中
forEach()
用来遍历数组,没有返回值。
而some()
大多使用场景是找到符合条件的元素,迭代效率高,返回值是布尔。
CSS有具体以下几个缺点:
语法不够强大,比如无法嵌套书写,导致模块化开发中需要书写很多重复的选择器;
没有变量和合理的样式复用机制,使得逻辑上相关的属性值必须以字面量的形式重复输出,导致难以维护。
这就导致了我们在工作中无端增加了许多工作量。而使用CSS预处理器,提供 CSS 缺失的样式层复用机制、减少冗余代码,提高样式代码的可维护性。大大提高了我们的开发效率。
但是,CSS预处理器也不是万金油,CSS的好处在于简便、随时随地被使用和调试。预编译CSS步骤的加入&