提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
随着Vue3的逐渐进入市场,让我们跟随着官网逐渐了解Vue2的基础吧
Vue2的特点
- 声明式(响应式)
- MVVM框架(M数据层<- ->VM虚拟DOM层<->V视图层)
- 组件化(支持自定义组件)
- 丰富的指令(DOM的抽象化)
- 基于选项(data,computed,methods,watch)
DOM与Vue2开发思想的区别
- DOM开发思想:在交互事件中改变事件,使用DO选择器直接对节点进行DOM方法,改变视图
- Vue2开发思想:在交互事件中改变事件,在data选项中声明一个合适的变量,通过这个声明式变量去改变,视图进行自动更新
指令
作用
用于视图节点上动态绑定变量,就是DOM功能的抽象,也是DOM操作
全部指令
- 文本指令(v-text,v-html,{{}},v-cloak,v-once)
- 动态属性指令(v-bind)可以换为:,属性有(style,class,value,title)
- 动态事件指令(v-on)可以换为@,事件修饰符(.enter,.stop,.prevent)
- 表单指令v-model,事件修饰符(.trim,.number,.lazy)
- 列表渲染指令(v-for)
- 条件渲染指令(v-if,v-else-if,v-else,v-show)
- 其他指令(v-pre,v-slot可以用#替换)
computed计算属性
作用
定义计算属性方法,在方法体中进行声明式变量的若干计算
优点
- 当指令的表达式复杂,可用computed进行优化,提升视图模板中代码的可读性,可维护性
- 进行缓存一个复杂的计算,避免组件更新时产生没有必要的性能损耗
- 计算属性默认是一个函数,表示get功能,为了支持set,要把计算属性写成对象结构xxx:{get,set}
watch监听器(侦听器)
作用
用于监听一个变量的变化,再做另外一件事
特点
当侦听器监听数据类型为引用数据类型时,只能监听一层,因为监听的越深,Vue在背后需要做的事情越多,对Vue来说是一种性能损耗,所以一般不要对一个引用数据类型监听,如果要监听可以针对某一节监听,具体方法为obj.key方法,如’info.child.age’(){}
响应式原理
在vue组件被创建时,在生命周期的第一阶段(创建阶段beforeCreate,created),Vue使用Object.defineProperty()对data选项进行遍历劫持,并且添加get/set钩子,在生命周期第二阶段(挂载阶段beforeMount,mounted),指令第一次与声明式变量touch时,发生了依赖收集,再调用当前组件的watcher第一次更新DOM,DOM视图显现,当声明式变量发生改变时,Vue进行re-render,通知watcher更新DOM,这就是响应式
重要概念
- 劫持:使用Object.defineProperty()对data选项进行遍历并且添加getter,setter钩子
- touch:当指令第一次与声明式变量绑定时,第一次触发声明式变量的get钩子
- 依赖收集:第一次touch时,把当前声明式变量的更新方法添加到dep依赖数组中
- watcher:跟声明式变量对应的DOM方法
- re-render:当声明式变量被set时,Vue通知Watcher更新DOM
组件基础
组件是HTML的扩展,使用粒度较小的HTML元素封装成粒度更大的标签(Vue组件),自定义组件技术是MVVM框架中最重要的技术之一,可以实现快速开发,代码复用,提升维护性
自定义组件
组件可以理解为一组选项构成的一个集合,封装组件时,可以使用到大多数的Vue选项属性比如data、template、methods
- 对组件来讲,最重要的选项为template,它用于指定组件的视图结构,在视图结构中你可以使用任意指令
- 对子组件来讲,可以通过props选项接收父组件传递过来的自定义属性,在组件内部用this访问
- 同样可以使用this.$emit(‘自定义事件’,数据)触发父组件给的自定义事件,并且回传数据给父组件
组件注册
- 全局注册:Vue.component(‘xx-yy’, ‘原材料选项’) 全局注册的组件,一次注册,在任何其它组件中都可以使用。
- 局部注册:components: { ‘xx-yy’: ‘原材料选项’ } 局部注册的组件,只能在当前组件作用域中使用。
注意:注册组件时,组件名称名称必须由多个单词用中划线连接。
关于组件间关系与通信
- 约定:在MVVM框架,当我们谈论“组件”这个概念时,通常指是自定义组件。当在A组件的视图结构中使用到了B组件,这就形成了组件关系(父子组件),那么A就是B组件的父组件,B就是A的子组件。
- 通信:在Vue中,所谓“通信”就是组件之间的数据交互。父组件向子组件通信,使用自定义属性,在子组件使用props接收;子组件向父组件通信,使用自定义事件,在子组件中使用 this.$emit(‘自定义事件’, ‘数据’) 回传数据。
组件化的三大技术
- 自定义属性
<qf-score :num='num'></qf-score>
- 自定义事件
<qf-score @change=''></qf-score>
- 自定义插槽
<qf-score> <div #default></div> </qf-score>
深入学习v-model指令
- 在组件中,v-model=‘num’ == :value=‘num’ + @input=‘num=$event’
- 在input中,对text,textarea 文本表单,v-model= :value + @input
- 在input选择框中,checkbox和radio选择框,v-model=:checked + @change
- 在input中下拉列表框中,select下拉框,v-model= :value +@change
生命周期
生命周期11个钩子
- 创建阶段:beforeCreate,Created
- 挂载阶段:beforeMount,Mounted
- 更改阶段:beforeUpdate,updated
- 销毁阶段:beforeDestroy,deatoryed
- 与动态组件有关的两个特殊的钩子:activated(激活)、deactivated(休眠)
- 与组件异常捕获有关的钩子:errorCaptured
生命周期流程
-
beforeCreate
- 声明methods方法,声明生命周期钩子
-
created (可调接口)
- 注入(injections)provide数据
- 进行响应式劫持、把data上数据遍历后放到this上
-
beforeMount
- 通过el/$mount/template找视图模板
- 把template视图模板编译成render()(render方法是用于创建虚拟DOM的)
-
mounted (调接口、开定时器、建立websocket长连接、echarts图表实例化、DOM/BOM操作)
- 创建**
$el
挂载节点,或者$mount
**挂载 - 调用render()方法第一次生成虚拟DOM(Vnode是对真实视图结构的一种数据描述)
- Vue开始编译工作,循环递归,指令和声明式变量进行touch,依赖收集、通知Watcher第一次完成DOM渲染
- 创建**
-
beforeUpdate
- 网页显示,当各种事件交互触发data变化时触发
-
updated 在某些场景下,可以模拟出watch/$nextTick()的功能
- 再次调用render()方法生成新的虚拟DOM(现在就有了两个虚拟DOM)
- 执行patch运算(diff运算)找到两个虚拟DOM之间的最小差异(脏节点集合),通过一个队列进行异步更新
-
beforeDestory 清除定时器、消除缓存
- 当调用**
$destory()
或者切换路由($route)**,即将进入销毁阶段
- 当调用**
-
destoryed
- 移除当前组件的Watcher(DOM将无法再更新了)
- 拆卸掉所有的子组件
- 移除事件监听器(watch等等)
Vue中内置组件
一共就5个内置组件分别为
- slot
- keep-alive
- component
- transition
- transition-group
keep-alive动态组件
作用
被keep-alive所包裹的组件不会被**‘销毁**’,你可以理解成是对组件的一种缓存
产生的生命周期钩子
被keep-alive所包裹的组件都会自动创建两个生命周期钩子:
- activated 激活,当切换到被包裹的组件时就会出现一次激活钩子
- deactivated 休眠,当切换走,被包裹的组件时就会出现一次休眠钩子
注意:
两组生命周期钩子的区别和使用场景:activated(执行多次)-mounted(执行一次),deactivated(执行多次)-beforeDestory(执行一次)
唯二的属性
- include 只包含 包含在incude数组中的组件不会‘destory’
- exclude 只不包含 不包含在exclude数组中的组件不会’destory’
component
作用
有种v-if的感觉,根据指定条件渲染目标组件,它的is属性等于哪个组件,就显示哪个组件
场景
它经常配合keep-alive一起使用
transition过渡动画
作用
是Vue内置的一种动画方式,可以很方便地为元素显示隐藏或者组件切换添加动画,本质是一种提升用户体验的优化
用法
把过渡动画抽象成两个过程(Enter进入动画、Leave离开动画),配合6个钩子使用。利用xx做例子
- xx-enter
- xx-enter-active
- xx-enter-to
- xx-leave
- xx-leave-active
- xx-leave-to
注意:
Vue过渡动画的终点是不会保留的,就相当于动画结束后元素的样式决定与class/style样式,在定义动画时,注意xx-enter-to和xx-leave这两个类名,最好配合UI的样式定义
使用第三方css动画库
如animate.css
- 官网:https://animate.style/
- 用法:安装或引入第三方css动画库,使用enter-active-class指定进入动画,使用leave-active-class指定离开动画
对多个元素执行动画时
- 要给每个元素都加上唯一的key(key值不能重复),否则动画不生效
- 使用mode指定多个元素显示与隐藏的先后顺序,通常mode='out-in’(离开动画先执行,再执行进入动画)
transition-group
作用
一般用于给列表添加分组动画,可参照Vue官网
混入
作用
用于向组件中混入可复用的选项(data,methods,生命周期钩子)
- 全局混入:使用Vue.mixin({选项}),进行全局混入。所有组件都拥有了这些被混入的选项
- 局部混入:使用**mixins:[{},{}]**选项进行局部混入,只有当前组件才有这些被混入的选项
注意:
当一个组件同时有全局混入、局部混入、自有选项时,他们的优先级为
自有选项 > 局部混入 > 全局混入
结论:无论是全局混入还是局部混入,都解决的是选项复用问题
关于混入
- 注意:工作中尽量不要使用全局混入,偶尔会用到局部混入
- 缺点:当混入用得多了,选项就会变的‘来历不明’,代码不宜维护
过滤器
作用
用于数据处理
- 全局过滤器:使用Vue.filter(‘名称’,val=>{return newVal}) 定义,在任何组件中都可以直接使用
- 局部过滤器:使用**filters:{}**定义,只能在当前组件中使用
注意1:
过滤器只能用在**{{}}和v-bind**中,不支持其他指令
注意2:
过滤器还可以链式调用,像这样**{{num | f1 | f2}}**,过滤器是有顺序的
自定义指令
作用:
在项目中有一些常用的DOM功能要复用时,建议封装成指令,这就是自定义指令,进行DOM功能的一种抽象封装
- 全局指令:使用Vue.directive(‘指令名’,fn/{})定义全局指令,在任何组件中都能使用
- 局部指令:使用**directives:{}**定义局部指令,只能在当前组件中使用
插件封装
作用
是一种更加高级的代码复用技术,可以以插件的方式为我们提供可复用的组件、混入、指令、过滤器、原型链API
说明
在Vue生态中,除了Vue本身,其他所有与Vue相关的第三方包,都是插件,都得以插件的方式进行集成
注意:
以公司真实项目、优秀开源项目,你只要发现里面有好用的组件和指令,都可以搬到自己的review中,以便未来复用
封装Vue插件方法
- const Plugin={install(val){}}
- const Plugin=function(Vue){}
- 导入插件,Vue.use(Plugin)
两个重要的API
Vue.nextTick()/this.$nextTick()
事实:
set操作,代码确实是同步的,但是set行为是异步的;set操作修改声明变量,触发re-render生成新的虚拟DOM,进一步执行diff运算,找到脏节点集合,交给Vue背后的更新队列去执行循环更新DOM
作用:
这么描述一个场景,我们set操作data(更新DOM),你希望访问这个DOM的最新状态时,使用this.$nextTick(handler)
什么是nextTick,怎么用?
- 在更新队列中每一个更新任务都是一个更新单元,nextTick表示下一个更新单元(更新周期)
- 在某种程度(场景)上,可以使用updated()来代替;原则上建议使用nextTick(),因为nextTick只在局部,updated是全局的
this.$forceUpdate()
事实:
Vue响应式是有缺陷的,在Vue应用中,如果声明式变量是引用数据类型时,当进行set操作这些复杂的引用数据类型时,视图会出现不更新的情况
解决方案:
set操作完成后,立即调用**this.$forceUpdate()
强调更新**(强制re-render),
但,有时候this.$forceUpdate()
也无法解决上述问题,这个时候我们对set操作的变量进行一次深拷贝还在利用Lodash库中的**_.cloneDepp**()
组件通信
什么是通信
通信是组件或者模块之间的数据交互,多重通信就形成了数据流,数据流管理的优劣决定了产品能否上线,通常数据流(通信)越混乱,代码越难维护
Vue中常见的通信方案
- 父子组件通信:父传子使用自定义属性(props),子传父使用自定义事件($emit())。
- 状态提升:当兄弟组件之间需要共享数据时,我们通常的做法是把这个数据定义它们的共同的父组件中,再通过自定义属性实现数据共享。
- provide/inject:这是在组件树中,自上而下的一种数据通信方案,也就是说只能父级组件中向后代组件传递。需要注意的是,当provide提供动态数据(声明式变量)时,动态数据发生变化,后代组件们不会自动更新。这是为什么呢?你自己从生命周期流程的角度去思考。
- ref通信:ref是Vue内置的一个属性,每一个HTML元素或组件都有这个属性;ref作用在HTML元素上得到DOM实例,ref作用在组件上得到组件实例。使用ref访问组件实例,进一步可以访问组件中的数据和方法。(说明:ref是一种快速的DOM的访问方式,当然ref也可作用在组件上得到组件实例。这些ref得到的DOM实例或组件实例,使用this.$refs来访问它们。ref尽量少用,除非某些难搞的需求。)
- 插槽通信:借助组件实现从子组件向父组件传递数据,借助
this.$slots
访问父组件中的插槽实例。(在自定义组件中使用this.$slots访问父组件给的插槽实例;在父组件插槽中使用**#default=‘scoped’**访问子组件回传的数据。这种通信在组件库中、工作中,非常常见!) $parent/$children
:借助 p a r e n t / parent/ parent/children可以实现,在任一组件中访问组件树中的其它任意组件实例,可以做到在组件中随意穿梭。( p a r e n t 表示的是当前组件的父组件实例, parent表示的是当前组件的父组件实例, parent表示的是当前组件的父组件实例,children表示的是当前组件的子组件们。)$attrs/$listeners
:借助$attrs
可访问父组件传递过来的自定义属性(除了class和style外),借助$listenrs
可以访问父组件给的自定义事件。在某些场景下,$attrs/$listeners
可以替代props/$emit()这种通用的通信方案- 事件总线:借助于Vue内置的事件系统(
$on/$emit/$off/$once
)实现“订阅-发布”式的通信,这种通信方式是一种与组件层级无关的“一对多”的通信。(工作中很少用,一些特殊的Vue项目才用得到事件总线。) - Vuex通信:这是Vue架构中终极的通信方案,也是Vue架构中用的最多的一种通信方案。
总结
根据Vue2官网所示,并且进行简单概括了一些,可能也属于精华吧,就这么多了,还有很多认为不太重要的就没有做记录。学习Vue2最好还是随着官网学习,让我们加油吧!!