1、当我们点击按钮的时候动态给 data 增加的成员是否是响应式数据,如果不是的话,如果把新增成员设置成响应式数据,它的内部原理是什么。
let vm = new Vue({
el: '#el'
data: {
o: 'object',
dog: {}
},
method: {
clickHandler () {
// 该 name 属性是否是响应式的
this.dog.name = 'Trump'
}
}
})
首先该 name 属性不是响应式数据的。
1、因为vue2.x内部是使用Object.defineProperty()的getter和setter方法来进行数据监听,然而新增的属性name并没有getter 和setter方法,所以数据不是响应式
要想设置成响应式也比较容易
方法1:预留一个坑位类似于以下代码:
let vm = new Vue({
el: '#el'
data: {
o: 'object',
dog: {
name:''
}
},
method: {
clickHandler () {
// 该 name 属性是否是响应式的
this.dog.name = 'Trump'
}
}
})
原因:初始化的时候已经存在的属性,vue中会使用Object.defineProperty()方法对其进行监听,所以该属性有getter 和setter方法,所以数据就是响应式的
方法2:
vue官网给出一种解决的思路调用Vue.set()就可以实现数据的响应式
调用方法:Vue.set( target, key, value )
- target:要更改的数据源(可以是对象或者数组)
- key:要更改的具体数据
- value :重新赋的值
let vm = new Vue({
el: '#app',
data: {
msg: 'object',
dog: {}
},
method: {
clickHandler() {
// 该 name 属性是否是响应式的
this.$set(this.data.dog, name, 'Trump')
}
}
})
2、请简述 Diff 算法的执行过程
-
diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。
-
在采取diff算法比较新旧节点的时候,比较只会在同层级进行, 不会跨层级比较。
-
数据发生改变时,set方法会让调用Dep.notify通知所有订阅者Watcher,订阅者就会调用patch给真实的DOM打补丁
说明:
patch 函数接收两个参数 oldVnode 和 Vnode,它们分别代表新的节点和之前的旧节点。这个patch函数会比较 oldVnode 和 vnode 是否是相同的, 即函数 sameVnode(oldVnode, vnode), 根据这个函数的返回结果分如下两种情况
- true:执行 patchVnode
- false:用 vnode 替换 oldVnode
patchVnode 函数做的工作
1.找到对应的真实 dom,称为 el
2.判断 vnode 和 oldVnode 是否指向同一个对象。
如果是,那么直接 return(结束)。
3.判断他们都有文本节点并且不相等,那么将 el 的文本节点设置为 vnode 的文本节点。
4.判断 oldVnode 有子节点而 vnode 没有,则删除 el 的子节点。
5.判断 oldVnode 没有子节点而 vnode 有,则将 vnode 的子节点真实化之后添加到 el
6.判断两者都有子节点,则执行 updateChildren 函数比较子节点。
vue-router 中常用的 hash 和 history 路由模式实现原理
- hash:路由的哈希(锚点)模式其实是利用了window可以监听onhashchange事件,也就是说你的url中的哈希值(#后面的值)如果有变化,前端是可以做到监听并做一些响应(做点事情),这么一来,即使前端并没有发起http请求也能够找到对应页面的代码块进行按需加载
- hash可以通过window.location.hash读取
- history模式:是利用pushState||replaceState(+服务端)以及popState事件的监听到状态变更
-
pushState:浏览器不会向服务端请求数据,直接改变url地址,可以类似的理解为变相版的hash;但不像hash一样,浏览器会记录pushState的历史记录,可以使用浏览器的前进、后退功能作用
-
replaceState:不同于pushState,replaceState仅仅是修改了对应的历史记录