@Secretmm
2023-02-06T02:03:44.000000Z
字数 6585
阅读 704
p6必备
https://juejin.cn/post/6844904084374290446
https://juejin.im/post/5d5ffad2518825258a772fa8
一句话:用类似“setState
”的方式显式的发布数据变化,触发视图更改。
简述:存在一个发布数据变化的发布者。数据绑定视图的操作就是 【订阅者】向这个发布者订阅相应的数据变化,当数据需要发生改变时,需要开发者显式调用类似setState
这样的方法【vue中用的是数据劫持的方式】发布数据变化,然后在数据被改变的同时,发布者就会向对应的数据订阅者——比如绑定的视图/虚拟DOM
——发布数据变化,相应更改视图。
理解版:
【子组件】发布者:1.监听所有数据的数据变化;
【父组件】订阅者:2.向发布者订阅需要的数据变化【数据变化了,发布者就会告诉它】;
联系【当数据发生变化的时候,发布者怎么告诉订阅者呢】:订阅者在订阅数据变化的时候,把数据变化时应当执行的方法传递【这个传递可以存在一个管道】给发布者;开发者显式调用类似setState
这样的方法时使发布者监听到数据变化,发布者调用订阅者事先传递的方法【这就叫做告诉订阅者数据变化了】
一句话:通过脏值检测的方式比对数据是否有变更,来决定是否更新视图。
简述:每当可能有变量发生变化需要检查时,比如用户输入、点击、XHR
响应、setTimeout
到时等,就将所有变量的旧值跟新值进行比较,不相等就说明检测到变化,将变更的数据发送到视图,更新页面展现。
一句话:通过Object.defineProperty()
来劫持各个数据属性的setter
,getter
,在数据变动时触发对应视图改变。
简述:通过Object.defineProperty()
来劫持需要监听的各个数据属性的setter
,getter
。数据被改变执行相应的setter时,获得数据变化情况,执行相应操作改变对应的视图。
核心是使用了Object.defineProperty
方法,通过观察者模式实现数据响应,执行render
,生成vnode
【virtual dom
的节点】,再将虚拟dom
应用到视图中;
Object.defineProperty
在对象中定义属性或者修改属性,通过存取描述符get
和set
关键字,提供给属性getter
和setter
方法
1个数据1个
Dep
,多个watcher
Observer类: 劫持数据对象,通过defineProperty
增加getter
/setter
方法,然后在getter
中收集依赖;在setter
通知更新;
收集依赖:在Dep
的subs
里放一个Watcher
实例,【subs
是一个Watcher
实例组成的数组(已有去重)】
通知更新:调用Dep
实例的notify
方法,【notify
方法:把该实例的subs
中的所有watcher
的update
方法调用一遍】;
Watcher类:Watcher
实例初始化时通过读取被监听属性的值来调用get
方法,触发依赖收集【即把自己放进Dep
的subs
中,见上】;提供update
方法【执行响应数据的操作】【update
方法里面是:执行里面回调函数(something
(eg: compile
)在初始化Watcher
实例时传进来的回调函数[谁初始化该watcher
谁传])】
Dep类:用subs
来集中存放某一数据属性的Watcher
实例;用notify
方法统一调用所有Watcher
中的update
方法
compile指令解析器: 编译模板【对每个元素节点的指令进行扫描和解析,根据指令模板替换初始数据】;为模板中绑定的数据初始化对应的Watcher
实例,并给它提供回调函数;
1、虚拟dom是框架封装dom操作的一种方式;
2、便于声明式的书写界面,进行函数式UI编程;
3、提高组件的抽象能力;
4、虚拟dom+diff可以将多次dom操作合并,在某些场合提高性能;
5、利于在无dom场景下渲染,如ssr、跨平台移植框架
https://juejin.im/post/5d5ffad2518825258a772fa8
defineProperty
缺陷:
1.无法监听数组变化
2.只能劫持对象的属性【不能监听对象本身】
proxy
简述:
它在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写
优势:
1.可以直接监听对象本身,而非属性;
2.可以直接监听数组的变化;
3.Proxy
有多达13种拦截方法,不限于apply
、ownKeys
、deleteProperty
、has
等等是Object.defineProperty
不具备的。
4.Proxy
返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty
只能遍历对象属性直接修改。
5.Proxy
作为新标准将受到浏览器厂商重点持续的性能优化,有性能红利
参考链接
https://juejin.im/post/59f2845e6fb9a0451a759e85
https://juejin.im/post/5acd0c8a6fb9a028da7cdfaf
m:数据层
v:视图层
vm:视图模型层
数据操纵视图,数据视图双向绑定。
重写push
、pop
、shift
、unshift
、splice
、sort
、reverse
这七个数组方法
bind
:只调用一次,指令第一次绑定到元素时调用;
unbind
:只调用一次,指令与元素解绑时调用;
inserted
:被绑定元素插入父节点时调用;
update
:所在组件的VNode更新时调用;
componentUpdated
:指令所在组件的 VNode 及其子 VNode 全部更新后调用;
el
:指令所绑定的元素,可以用来直接操作 DOM。
binding
:一个对象,包含以下属性:
name
:指令名,不包括 v- 前缀。
value
:指令的绑定值,例如:v-my-directive="1 + 1"
中,绑定值为2
。
oldValue
:指令绑定的前一个值,仅在update
和componentUpdated
钩子中可用。无论值是否改变都可用。
expression
:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
arg
:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
modifiers
:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
vnode
:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
oldVnode
:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
创建前后、挂载前后、更新前后、销毁前后、【动态组件 激活后activated
、移除后deactivated
】
生命周期钩子 | 组件状态 | 最佳实践 |
---|---|---|
beforeCreate | 实例初始化之后【this 指向创建的实例,不能访问到data 、computed 、watch 、methods 上的方法和数据】 |
常用于初始化非响应式变量 |
created | 实例创建完成之后,可访问data 、computed 、watch 、methods 上的方法和数据,未挂载到DOM ,不能访问到$el 属性,$ref 属性内容为空数组 |
常用于简单的ajax 请求,页面的初始化 |
beforeMount | template 被找到并已经被编译成render 函数之后 |
|
mounted | $el 创建完成之后【还未挂载完成(挂载可能完成了,dom 渲染到界面不保证已经完成),所以要用nextTick 】 |
常用于获取VNode 信息和操作,ajax 请求 |
beforeUpdate | 响应式数据已经更新,虚拟DOM还未重新渲染 | 适合在更新之前访问现有的DOM ,比如手动移除已添加的事件监听器 |
updated | 虚拟 DOM 重新渲染之后,组件DOM已经更新 | |
beforeDestroy | 实例还未销毁,完全可用,this可访问 | 常用于销毁定时器、解绑全局事件、销毁插件对象等操作 |
destroyed | 解除绑定之后,销毁子组件以及事件监听器之后 |
1.仅当子组件完成挂载后,父组件才会挂载
2.当子组件完成挂载后,父组件会主动执行一次beforeUpdate
/updated
钩子函数(仅首次)
3.父子组件在data
变化中是分别监控的,但是在更新props
中的数据是关联的(可实践)
4.销毁父组件时,先将子组件销毁后才会销毁父组件
结合 Vue
的异步组件和Webpack
的代码分割功能。在router
项的组件用import
函数引入,而不是直接引入。
eg:
//动态地加载模块。调用 import()之处,被作为分离的模块起点,意思是,被请求的模块和它引用的所有子模块,会分离到一个单独的 chunk 中。
//Router文件中【webpack不用管】
const Foo = () => import(/* webpackChunkName: "other" */ './Foo.vue') //返回一个promise
//router配置项不作修改
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
vue-router
默认 hash
模式; hash
发生改变时【即切换路由时】,页面不会自动刷新;
前端:1.mode
改为history
;【开发环境也是直接/
,而不是#/
】;2.配置一个404页面【不是必须,地址改变,浏览器会向后台请求,会发生刷新,后端针对所有的地址,都返回一个页面文件,不存在的地址需要前端处理】【后端处理404有地址配置,也有文件夹配置】
const router = new VueRouter({
mode: 'history',
routes: [...]
})
后端要做到所有路由地址都响应同一个页面文件,再把这个同一份页面文件返回回来
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '*', component: NotFoundComponent }
]
})
beforeRouteLeave
。beforeEach
守卫。beforeRouteUpdate
守卫 (2.2+)。beforeEnter
。beforeRouteEnter
。beforeResolve
守卫 (2.5+)。afterEach
钩子。DOM
更新。beforeRouteEnter
守卫中传给 next
的回调函数。
beforeRouteUpdate
: 举例来说,对于一个带有动态参数的路径/foo/:id
,在/foo/1
和/foo/2
之间跳转的时候,由于会渲染同样的Foo
组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。可以访问组件实例this
还可以自定义合并策略哦
Vue.config.optionMergeStrategies.myOption = function (toVal, fromVal) {
// 返回合并后的值
}
1.mixin的钩子函数优先执行【同名钩子函数,合并为一个数组,都会被调用】
2.数据对象(data里的值)在内部会进行递归合并,并在发生冲突时以组件数据优先。
3.值为对象的选项,例如 methods
、components``directives
,将被合并为同一个对象。两个对象键名字冲突时,取组件对象的键值对。
后两个:因为组件是minxin的子类,数据方法冲突,相当于重写
eg:
//1.钩子函数,mixin优先执行
var mixin = {
created: function () {
console.log('混入对象的钩子被调用')
}
}
new Vue({
mixins: [mixin],
created: function () {
console.log('组件钩子被调用')
}
})
// => "混入对象的钩子被调用"
// => "组件钩子被调用"
//2.数据冲突,组件优先
var mixin = {
data: function () {
return {
message: 'hello',
foo: 'abc'
}
}
}
new Vue({
mixins: [mixin],
data: function () {
return {
message: 'goodbye',
bar: 'def'
}
},
created: function () {
console.log(this.$data)
// => { message: "goodbye", foo: "abc", bar: "def" }
}
})
//3.对象键名冲突,组件优先
var mixin = {
methods: {
foo: function () {
console.log('foo')
},
conflicting: function () {
console.log('from mixin')
}
}
}
var vm = new Vue({
mixins: [mixin],
methods: {
bar: function () {
console.log('bar')
},
conflicting: function () {
console.log('from self')
}
}
})
vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"
nextTick
可以在DOM
更新后执行一个回调,问题在于vue
如何检测到DOM
更新完毕,
html5
有一个新属性:MutationObserver
,用于监听dom
修改事件,能够监听到节点的属性,文字内容、子节点的改动,vue
如果检测到浏览器支持MutationObserver
,则创建一个文本节点,监听这个文本节点的改动事件,以此来触发nextTickHandler
(也就是DOM更新完毕回调)的执行;利用js的事件循环机制,手动修改文本节点属性,确保文本节点更新时,其他dom节点已经更新完毕。 浏览器不支持时,则用settimeout
(fn,0)来替代;
https://juejin.cn/post/6844904084374290446
https://juejin.im/post/6844903922453200904
constructor
: 构造函数:初始化state
,给自定义方法绑定this
;
getDerivedStateFromProps
: 静态方法,从props
中获取state
;
render
:纯函数,返回需要渲染的东西;
componentDidMount
:组件挂载之后使用,
单向数据流,双向数据流