概述
vue深入响应式原理
数据模型–》 vm中 的data选项
状态管理
什么叫做状态?什么叫做状态管理?
我们使用一个数据去管理视图中的一个部分, 那么这条数据就叫做状态, 这种管理模式就叫做状态管理
Object.defineProperty( obj, obj.attr , descriptor )
* 存储器:
* get函数 设置了当前对象的初始值
* get函数 要求必须要有返回值
*
* set函数 修改了当前对象的key的值
* set函数 set( val,old ) val 代表当前的值 , old 表示上一次改变时的值
Object.defineProperty(obj,'name',{
//存储器
get(){
//要求必须有返回值
return 'hello'
},
set(value){ //value就是修改后的对象的key的value
console.log('set')
console.log('====================================');
console.log(value);
console.log('====================================');
document.querySelector('#app').innerHTML = value
}
- 非响应式情况
- 在vm模型的data外定义的属性, 就是非响应式属性, 非响应式属性, 属性值更新, 视图不会更新
- 非响应式属性如何变成响应式属性
- 思维: 将非响应式属性合并到响应式属性身上
- 解决: 利用了Vue提供的 Vue.set/this.$set(vm.dataattr,prop,value)
- Vue.set(vm.someObj,prop,value)
- this.$set(vm.someObj,prop,value)
- Vue.set底层原生是什么?
- Object.assign(目标对象,对象1, 对象2,对象3)
- 如果要求非相应数据进行相应, 需要将非相应的属性合并到data中
- 如果是在Vue中去合并的话 使用 this.$set( vm.someobj , prop , value )
- 如果实在Vue外部合并的话 使用 Vue.set( vm.someobj , prop , value )
总结:
1.
什么是深入响应式原理?
*
深入响应式原理是利用了数据劫持和订阅发布的模式, 当数据模型发生改变的时候,
*
视图就会响应的进行更新, 那么深入响应式原理是利用es5的Object.defineProperty中getter/setter来进行数据的劫持的
*
Vue通过watcher将data中的属性全部使用Object.definePropery变成getter和setter,当属性值发生
改变的时候, 就会触发, 然后wather就会触发, 告诉视图(V)进行重新渲染
名称解释:
数据劫持:
Object.defineProperty中的getter/setter , 然后在执行watcher
订阅发布:事件(自定义事件)
订阅: 事件的声明
vm.$on
发布: 事件的触发
vm.$emit
vue双向数据绑定原理
v-model 双向数据绑定
1. 效果
数据改 , 视图更
视图改, 数据更
2. 实现
使用v-model实现
3. 缺点
v-model默认绑定value属性, 所以v-model只能在表单使用
4. 原理
1. 为什么数据能直接在视图显示
v-model默认绑定了DOM对象的value属性, 当它初次绑定的时候,
就会触发getter,watcher就会触发, watcher通知Vue生成新的VDOM树,
再通过render函数进行渲染,生成真实DOM
2. 为什么视图修改数据就会修改
当视图修改是, 意味着DOM的value属性值改变,就会触发setter,watcher监听机制就会执行
watcher通知Vue生成新的VDOM树,再通过render函数进行渲染,生成真实DOM
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:
第一步:需要 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter?
这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
第二步:compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
第三步:Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
1、在自身实例化时往属性订阅器(dep)里面添加自己
2、自身必须有一个update()方法
3、待属性变动dep.notice()通知时,能调用自身的 update() 方法,并触发Compile中绑定的回调,则功成身退。
第四步:MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
- axios fetch 数据请求
watch 监听
- 作用:
用来监听数据的变换, 当数据模型 (data选项 M)发生改变时, watch就会触发 - 使用
两种用法:
1. key的value值是一个函数
new Vue({
watch: {
key(value,oldvalue){}
}
})
```
2. key的value值是一个对象
```javascript
new Vue({
watch: {
key: {
deep: true/false 深入监听,
handler(value,oldvalue){}
// 监听的处理函数
}
}
})
```
用法:
```javascript
new Vue({
el: '#app',
data: {
msg: 'hello vue.js'
},
watch: {
msg(){
alert('数据改变了')
}
}
})
watch中的key指的就是data选项中key
对比 watch computed methods
methods : 用于时间
watch : 1.异步操作
2. 开销较大
computed : 1. 有逻辑 2. 要像变量一样使用
mixins
组件即实例, 实例即组件
1. 概念:
mixins; 混合 ,将
根实例或是组件中的配置项 抽离出来, 单独管理
2. 类型
A:局部混入
var mixin = {
methods: {
sum(){
alert( 10*10 )
}
},
}
new Vue({
el: '#app',
data: {},
watch: {},
mixins: [mixin],
computed: {}
})
注意:
1. 即使分离出去, 我们的配置项中也可以继续写分离出去的配置
2. 如果说分离出去中的内容有冲突, 以组件中的配置项为准
3. 配置项中的方法执行时是最优先的
B: 全局混入
注意: 全局混入慎用(不建议你使用)
理由:全局混入会影响所有的组件(实例)
Vue.mixin({
watch: {},
methods: {
yes():{
alert(123);
}
}
})
axios与fetch(原生的方法)
1.get方法
A: 无参数
axios.get(url).then(res=>console.log(res).catch(error=>conosle.log(error))
B: 有参数
axios({
url: 'http://xxx',
method: 'get' //默认就是get,这个可以省略,
params: {
key: value
}
})
2.post
注意: axios中post请求如果你直接使用npmjs.com官网文档, 会有坑
解决步骤:
1. 先设置请求头
2. 实例化 URLSearchParams的构造器函数得到params对象
3. 使用params对象身上的append方法进行数据的传参
4. new URLserachParams对象有一个toString()方法可以将对象转换为类似a=1&b=2的形式
// 统一设置请求头
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
let params = new URLSearchParams()
// params.append(key,value)
params.append('a',1)
params.append('b',2)
axios({
url: 'http://localhost/post.php',
method: 'post',
data: params,
headers: {
//单个请求设置请求头
'Content-Type': "application/x-www-form-urlencoded"
}
})
.then(res => {
console.log( res )
})
.catch( error => {
if( error ){
throw error
}
})
Fetch
https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch#进行_fetch_请求
https://blog.csdn.net/hefeng6500/article/details/81456975
列表渲染中的key的作用
给VDOM添加标记
如果没有key会产生的问题:
VDOM是惰性的, 它有一个原则, 这个原则叫做’就地复用’ , 它认为我的第一个就是红色的, 删除了第二个之后, 第二个就变成了第一个, 它印象中第一个是红的, 所以就我们认为的第二个变成红的了
解决: 使用key属性
使用:
<li v-for = " (item,index) in list " :key = "item.id">
注意:
1. 优先使用数据中能够识别的, 比如 : id
2. 最差在用 index
虚拟DOM和diff算法
-
虚拟DOM 是什么?
虚拟DOM是利用 了js的对象的Object的对象模型来模拟真实DOM, 那么它的结构是一个树形结构
2. diff算法
diff算法是用来比较两个或是多个文件, 返回值是文件的不同点diff算法是同级比较的
diff思维也是来自后端
diff算法的比较思维
比较后会出现四种情况:
1、此节点是否被移除 -> 添加新的节点
2、属性是否被改变 -> 旧属性改为新属性
3、文本内容被改变-> 旧内容改为新内容
4、节点要被整个替换 -> 结构完全不相同 移除整个替换- 整个VDOM的使用流程(Vue)
- 创建VDOM树
- 利用render函数渲染页面
- 数据改变,生成新的vDOM
- 通过diff算法比较 新 旧 两个VDOM , 将不同的地方进行修改, 相同的地方就地复用 , 最后在通过render函数渲染页面
//用js实现的一个简单的redner函数封装
<script>
var vdom = {
vnode: {
tag: 'div',
attr: {
idName: '#app'
},
content: [
{
tag: 'header',
content: [
'头部'
]
},
{
tag: 'section',
content: [
'内容'
]
},
{
tag: 'footer',
content: [
'底部',
]
}
]
}
}
function render (parentNode){
//父节点的元素类型和属性
var parent = document.createElement(parentNode.tag);
parent.id = parentNode.attr.idName;
//添加到body中
document.body.appendChild(parent);
// 保存所有文本
var content = vdom.vnode.content;
//循环遍历生成标签
content.forEach((ele,i)=>{
var vno = document.createElement(ele.tag);
ele.content.forEach((ele)=>{
var vtext = document.createTextNode(ele);
vno.appendChild(vtext);
})
parent.appendChild(vno);
})
}
render(vdom.vnode);
</script>
最后
以上就是朴素盼望为你收集整理的Vue的底层原理的全部内容,希望文章能够帮你解决Vue的底层原理所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复