1.Vue生命周期理解
生命周期钩子的this 上下文指向调用它的Vue 实例。
(1)在beforeCreated和created钩子函数之间的生命周期
初始化事件,进行初始化事件、数据观测,在created的时候数据已经跟data属性进行绑定(放在data中的属性值改变时,视图也会改变),此时没有el。
在beforeCreated阶段,Vue实例的挂载元素$el和数据对象data都为undefined,还未初始化。在created阶段,Vue实例的数据对象data有了,$el还没有。
(2) created钩子函数和beforeMount间的生命周期
首先会判断对象是否有el选项,如果有就继续往下编译,如果没有就停止编译,整个生命周期结束,直到等到该Vue实例调用vm.$mount(el)(el就是挂载的dom结点)
(ajax请求等请求数据的操作)
如果Vue实例中template参数选项,则将其作为模板编译成render函数,如果没有template参数选项,则将外部html作为模板编译,template优先级要高于外部html优先级。
优先级:render函数>template模板>外部html
(3)beforeMount和mounted间的生命周期
给Vue实例对象添加$el成员,替换掉挂载的DOM元素
在beforemount阶段,Vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。
(4)mounted
在mounted之前h1中还是通过{{message}}进行占位的,因为此时还有挂载到页面上,还是JavaScript中的虚拟DOM形式存在的。在mounted之后可以看到h1中的内容发生了变化。在mounted阶段,Vue实例挂载完成,data.message成功渲染。
(5)beforeupdate和updated钩子函数间的生命周期
当Vue发现数据发生改变,会触发对应组件的重新渲染,先后调用beforeupdate和updated钩子函数
(6)beforedestroy和destroyed钩子函数间的生命周期
beforeDestroy钩子函数在实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed钩子函数在Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。
2.mvvm框架解析之双向绑定
view——>viewModel——>Model
<—— <——
视图(DOM) 通讯(观察者) 数据(JavaScript对象)
在 MVVM 框架中,View(视图) 和 Model(数据) 是不可以直接通讯的,在它们之间存在着 ViewModel 这个中间介充当着观察者的角色。当用户操作 View(视图),ViewModel 感知到变化,然后通知 Model 发生相应改变;反之当 Model(数据) 发生改变,ViewModel 也能感知到变化,使 View 作出相应更新。视图转换成模型,通过DOM事件监听;模型转换成视图,通过事件绑定。这个一来一回的过程就是我们所熟知的双向绑定。
a、Observer实现对MVVM自身model数据劫持,监听数据的属性变更,并在变动时进行notify
b、Compile实现指令解析,初始化视图,并订阅数据变化,绑定好更新函数
c、Watcher一方面接收Observer通过dep传递过来的数据变化,一方面通知Compile进行view update
2.Vue实现双向绑定的做法 发布者订阅者模式
VUE通过Object.defineProperty()来劫持对象属性的setter和getter操作
Observer 数据监听器,把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用Object.defineProperty()方法把这些属性全部转成setter、getter方法。当data中的某个属性被访问时,则会调用getter方法,当data中的属性被改变时,则会调用setter方法。
Compile指令解析器,它的作用对每个元素节点的指令进行解析,替换模板数据,并绑定对应的更新函数,初始化相应的订阅。
Watcher 订阅者,作为连接 Observer 和 Compile 的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数。Dep 消息订阅器,内部维护了一个数组,用来收集订阅者(Watcher),数据变动触发notify 函数,再调用订阅者的 update 方法。
从下图中可以看出,当执行 new Vue() 时,Vue 就进入了初始化阶段,一方面Vue 会遍历 data 选项中的属性,并用 Object.defineProperty 将它们转为 getter/setter,实现数据变化监听功能;另一方面,Vue 的指令编译器Compile 对元素节点的指令进行解析,初始化视图,并订阅Watcher 来更新视图, 此时Wather 会将自己添加到消息订阅器中(Dep),初始化完毕。当数据发生变化时,Observer 中的 setter 方法被触发,setter 会立即调用Dep.notify(),Dep 开始遍历所有的订阅者,并调用订阅者的 update 方法,订阅者收到通知后对视图进行相应的更新。因为VUE使用Object.defineProperty方法来做数据绑定,而这个方法又无法通过兼容性处理,所以Vue 不支持 IE8 以及更低版本浏览器。
双向绑定步骤:
(1)实现一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
(2)实现一个订阅者Watcher,可以收到属性的变化通知并执行相应的函数,从而更新视图。
(3)实现一个解析器Compile,可以扫描和解析每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅器。
3.vue组件通信
方式一:
父组件A通过props的方式向子组件B传递,B to A 通过在 B 组件中 $emit, A 组件中 v-on 的方式实现。
父传子:
父组件中<users v-bind:users="users"></users>//前者自定义名称便于子组件调用,后者要传递数据名
子组件中props:{
users:{ //这个就是父组件中子标签自定义名字
type:Array,
required:true
}
}
子传父:
子组件中 <h1 @click="changeTitle">{{title}}</h1>//绑定一个点击事件
methods:{
changeTitle() {
this.$emit("titleChanged","子向父组件传值");//自定义事件 传递值“子向父组件传值”
}
}
父组件
<app-header v-on:titleChanged="updateTitle" ></app-header>
methods:{
updateTitle(e){ //声明这个函数
this.title = e;
}
}
方式二:
通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现任何组件间的通信,包括父子、兄弟和跨级。
var event=new vue();
event.$emit(事件名,数据);
event.$on(事件名,data=>{});
方式三:
vuex
vuex原理:
Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。
方式四
$attrs/$listeners
$attrs与$listeners 是两个对象,$attrs 里存放的是父组件中绑定的非 Props 属性,$listeners里存放的是父组件中绑定的非原生事件。
方法五:provide/inject
主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
方法六 $parent/$children和ref
缺点:无法在跨级或兄弟间通信
ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
$parent / $children:访问父 / 子实例
常用的场景
父子通信:
父向子传递数据是通过 props,子向父是通过 events($emit);通过父链 / 子链也可以通信($parent / $children);ref 也可以访问组件实例;provide / inject API;$attrs/$listeners
兄弟通信:
Bus;Vuex
跨级通信:
Bus;Vuex;provide / inject API、$attrs/$listeners
3.vue实例
Vue只能有一个根节点
5.Vue原生指令
v-text
v-bind :
v-on @
v-html
v-show 是否显示
v-if v-else-if v-else
v-for :key
v-model一般用在input上面 v-model.number 数值类型 v-model.trim 省略空格 v-model.lazy
v-pre 不会解析语句
v-once 数据绑定内容只执行一次,节省性能开销,静态数据不需要更新
6.computed.watch
computed计算属性,用于获取值,尽量不要修改原来的值
watch用于监听数据变化,如果对象的属性变化时,加deep:true,可以监听到。刚开始不会调用watch,因为没有数据变化,加immediate:true就会调用watch。
7.组件
prop中的数据不要修改
data返回函数
extend继承组件
vue组件的高级属性:
插槽:作用域插槽slot-scope
8.render: function
9.vue-router
<router-view />显示路由信息
配置vue-router时,mode:history;可以取消路径中的#号
base:'/base/' 路径中的基路径
scrollBehavior(to,from,savedPosition)
路由配置包括:
path
props:true //会把path后面的参数当做props传给
component
name给路由命名
meta:
children嵌套路由
<transition name='fade'>
<router-view />
</transition>
再添加fade样式,就有路由切换的fade效果
导航守卫:全局导航守卫(index.js中定义),路由定义内的导航守卫,组件内导航守卫
action与mutation区别:action异步 mutation同步
模块:命名空间namespaced
热更替
10.Vue原理
Vue的核心定位并不是一个框架,设计上也没有完全遵循MVVM模式,可以看到在图中只有State和View两部分, Vue的核心功能强调的是状态到界面的映射,对于代码的结构组织并不重视, 所以单纯只使用其核心功能时,它并不是一个框架,而更像一个视图模板引擎,这也是为什么Vue开发者把其命名成读音类似于view的原因。Vue的核心的功能,是一个视图模板引擎,但这不是说Vue就不能成为一个框架,Vue的所有部件,在声明式渲染(视图模板引擎)的基础上,我们可以通过添加组件系统、客户端路由、大规模状态管理来构建一个完整的框架。更重要的是,这些功能相互独立,你可以在核心功能的基础上任意选用其他的部件,不一定要全部整合在一起。可以看到,所说的“渐进式”,其实就是Vue的使用方式,同时也体现了Vue的设计的理念.
11Vue2.0与Vue3.0的区别
双向绑定的实现方式不同,Vue2.0通过Object.defineproperty中的set实现数据劫持,但是有一个弊端无法监听到数组内部的数据变化,Vue3.0通过Proxy对象来实现数据的劫持,相比于Object.defineproperty可以检测到数组内部数据的变化