携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第2天,点击查看活动详情 >>>
Composition API
Mixin的合并规则(当Minxin对象的选项和组件对象中的选项发生了冲突时)
分不同情况进行处理
(1)如果是data函数的返回值对象
返回值对象默认情况会进行合并,如果data返回值对象的属性发生了冲突,那么会保留自身组件的数据
(2)如果是生命周期钩子函数
生命周期的钩子函数会被合并到数组中,都会被调用
(3)值为对象的选项,如:methods/components/directives,将会被合并为同一个对象
比如都有methods选项,并且都定义了方法,那么他们都会生效,但是如果对象的key相同,那么会取组件对象的键值对
vue2中,我们编写的是一个optionsApI,optionsAPI的一大特点就是在对应的属性中编写对应的功能模块,但是这种代码存在一个很大的弊端,一些功能都分散在其他的地方,不好便于理解代码。
setup函数的参数
(注意:在setup函数里面不能使用this)
它主要有两个参数,props、context
props,父组件传递过来属性
context ,上下文,它里面包括三个属性
attrs:所有的非prop的attribute
slots:父组件传过来的插槽
emit:等到发射事件的时候,就可以拿到emit了(因为我们不能用到this,所以需要用到context.emit)
setup函数的返回值
setup的返回值可以在模板template中被使用
也就是说我们可以通过setup的返回值来替代data选项
setup函数的响应API
this并没有只想组件实例,在setup调用之前,data/computed/methods等都没有解析,所以无法在setup中获取this
API:
reactive(相对比较麻烦)
ref API (reference 引用的意思)
ref会返回一个可变的响应式对象,该对象作为一个响应式的引用维护着它内部的值,这就是ref名称的来源,它内部的值是在ref的value属性中被维护的
REF的自动解包
(1)ref的解包只能是浅层解包
(2)当如果最外层包裹是一个reactive可响应式对象,那么内容的ref可以解包
认识readonly
我们通过reactive或者ref可以获取到一个响应式的对象,但是某些情况在我们传入给其他地方(组件)的这个响应式对象,希望在另外一个地方被使用,但是不能被修改,这时候如何防止这种情况的出现呢?
vue3为我们提供了readonly方法
readonly会返回原生对象的只读代理(也就是它依然是一个proxy,这是一个Proxy的set方法被劫持,并且不能对其修改)
Reactive判断的API
isProxy 检查对象是否是由 reactive 或 readonly创建的proxy
isReactive
检查对象是否由reactive创建的响应式代理 但如果该代理是readonly建的 但包裹了由reactive创建的另一个代理,它也会返回true
isReadonly 检查对象是否由readonly创建的只读代理
toRow 返回reactive或readonly代理的原始对象(不建议保留对原始对象的持久引用,谨慎使用)
shallowReactive(浅层的reactive)
创建一个响应式代理,它跟踪其自身property的响应式,但不执行嵌套对象的深层响应式转换
shallowReadonly(浅层的readonly)
创建一个proxy,使自身的property为只读,但不执行嵌套对象的深度只读转换(深层还是可读、可写的)
toRefs 将reactive对象中的所有属性都转成ref,建立连接
toRef 对其中一个属性进行转换ref,建立连接
ref其他的API
unref:如果我们想要获取一个ref引用中的value,那么也可以通过unref方法,如果参数是一个ref,则返回内部值,否则返回参数本身,这是 val = isRef(val) ? val.value : val 的语法糖函数
isref:判断值是否是一个ref对象
shallowRef:创建一个浅层的ref对象
triggerRrf:强制进行刷新
customRef:创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制
它需要一个工厂函数,该函数接收track和trigger函数作为参数,并且应该返回一个带有get和set的对象
watchEffect 和 watch API
watchEffect 自动收集响应式的依赖
watchEffect清除副作用
比如在开发中我们需要在侦听函数中执行网络请求,但是在网络请求还没有达到的时候,我们停止了侦听器,或者侦听器侦听函数被再次执行了,那么上一次的网络请求就应该被取消掉,这个时候我们就可以清除上一次的副作用
在我们给watchEffect传入的函数被回调时,其实可以获取到一个参数:onInvaliadte,当 副作用即将重新执行 或 侦听器被停止 时会执行该函数传入的回调函数,我们可以在传入的回调函数中,执行一些清除工作
调整watchEffect的执行时机
我们可以设置副作用函数的执行时机
watch的使用
watch的api完全等于组件watch选项的property
watch需要侦听特定的数据源,并在回调函数中执行副作用,默认情况下它是惰性的,只有当侦听的源变化才会执行回调
生命周期钩子
在原来的基础上加上on 然后在setup里面使用
render函数
当你真的需要js的完全编程的能力,这时你可以使用渲染函数,它比模板更接近编译器
vue在生成真实的DOM之前,会将我们的节点转换成VNode,而VNode组合在一起形成一颗树结构,就是虚拟DOM
事实上,我们之前编写的template中的HTML最终也是渲染成对应的VNode,那么,如果你想充分的利用js的编程能力,我们可以自己来编写createVNode函数,生成对应的VNode
这个时候,我们可以使用 h() 函数
h() 函数是一个用于创建vnode的一个函数
其实更准确的命名是createVNode(),但是为了简便在vue将值简化为h()函数
第一个参数 标签的名字
第二个参数 对象 与我们将在模板中使用的attribute/prop和事件相对应
第三个参数 子代VNODE
注意事项:
如果没有Props,那么通常可以将children作为第二个参数传入
如果会产生歧义,可以将null作为第二个参数输入,将children作为第三个参数传入
JSX
一般封装组件库的时候会用到 类react代码
自定义指令
vue允许我们来自定义自己的指令,通常在某些情况下,你需要对DOM元素进行底层操作,这个时候就会用到自定义指令
自定义指令分为两种:
(1)自定义局部指令:组件通过directives选项,只能在当前组件中使用
(2)自定义全局指令:app的directive方法,可以在任意组件中使用
指令的生命周期: 一个指令定义的对象,vue提供了如下的几个钩子函数:
created:在绑定元素的attribute或事件监听 器被应用之前调用
beforeMount:当指令第一次绑定到元素并且在挂在父组件之前调用
mounted:在绑定元素的父组件被挂载后调用
beforeUpdate:在更新包含组件的VNode之前调用
updated:在包含组件的VNode及其子组件的VNode更新之后使用
beforeUnmounted:在卸载绑定元素的父组件之前调用
unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次
指令生命周期里面的参有el bindings VNode preVNode,比较常用的是el和bindings,bindings里面可以获取用户在使用自定义标签时的修饰符和传过来的值
Teleport
在组件化开发中,封装一个组件A,在另外一个组件B中使用,那么A中的template的元素就会被挂在到组件B中的template中的某个位置中,最终我们的应用程序会形成一颗Dom树结构
但是在一些开发情况中,我们希望组件不是挂载在这个组件树上的,可能是移动到vue app 之外的其他位置上,这时候就可以通过teleport来完成
teleport是vue3提供的内置组件,它有两个属性
to : 指定将其中的内容移动到的目标元素 可以使用选择器
disabled: 是否禁用teleport的功能
Vue插件
通常我们向vue全局添加一些功能时,会采用插件的模式,它有两种编写方式
对象类型 :一个对象,但是必须包含一个install的函数,该函数会在安装插件时执行
函数类型:一个function,这个函数会在安装插件时自动执行
插件可以完成的功能没有限制,比如下面的几种都是可以的: (1)添加全局方法或者property,例如globalProperties
(2)添加全局资源:指令/过滤器、过渡等
首先编写插件
在全局用app使用
之后就可以在组件内使用全局的插件了,类似vuex这种插件都是类似的实现方式
VUE的源码
三大核心系统:
compiler模块:编译模板系统
runtime模块:render模块,真正渲染的模块
reactivity模块:响应式系统