Vue编译时声明周期的执行顺序
Vue中父子组件渲染顺序(同步引入子组件:import Son from ‘@/components/son’ )
父子组件编译时的生命周期执行顺序
这里修改data数据时也修改了dom,如过知识通过按钮对数据进行++操作,那么没有修改dom,也就不会调用beforeupdate和updated生命周期
1.beforeUpdate()是针对视图层的,只有页面中渲染的数据发生改变或者渲染,才会触发这个生命周期函数
2.updated()中修改数据(在视图层进行了展示)是会触发beforeUpdate()的
修改父组件的视图数据
修该子组件的视图数据
Vue中父子组件渲染顺序(异步引入子组件:const Son = () => import(‘@/components/son’) )
组件的通讯方式有哪些
父子组件通信
1.父组件使用自定义属性向子组件传递数据(单向数据流),子组件使用props接受父组件传递过来的数据
2.子组件使用事件向父组件传递数据:$emit('事件名','传递的数据'...)
3.父组件使用v-model语法糖向子组件通信(双向绑定,子组件可以修改):相当于父组件使用了自定义属性value,子组件使用$emit('input','xxx')用父组件传递数据
4.sync修饰符:父传子没什么变化,子传父不需要使用事件接受(双向绑定,类似v-model,不过自定义属性名和变量名相同) $emit('update:属性名',‘传递的数据’)
父组件向后代组件通信
依赖注入(传递的对象是响应式的数据,传入的其他格式的数据是非响应式的)
(provide和inject)
非父子组件通信
使用事件总线(创建事件总线之后,使用$emit发送,使用$on接收)
Vuex
Vuex的属性和方法
// 3. 创建 store 实例对象
const store = new Vuex.Store({/* 这里配置Vuex *///state属性的值是一个对象,用来存储全局共享的数据strict: true, //开启vue严格模式,不允许在组件中直接修改state数据state: {//在组件中通过 $store.state.属性名调用age: 20,username: 'zhangsan'},mutations:{ //放同步方法,用来更新state中的数据//组件中通过 $store.commit(‘方法名’,参数值)调用updateAge(state,newVal){//第一个参数是固定的,表示实例中的state对象//第二个参数及后续参数,需要调用时传递过来}},actions:{ //放异步方法,actions不能直接修改state数据,可以通过调用mutations中的方法修改state数据
//组件中通过$store.dispatch(‘方法名’,参数值)
update(store,newval){
//第一个参数store是固定的,表示当前的store对象,通过它可以很方便的mutations中的方法
//第二个参数及后续参数,需要调用时传递过来
store.commit('方法名',val)
}
}getters:{//getter是vuex中的计算属性,但是不支持set修改
//组件中通过$store.getters.方法名 调用
isAllDone(state){
//第一个参数state是固定的,表示前面的state对象,通过它可以很方便的找到state中的属性
return xxx
}
}})
可以通过Vuex 提供了 mapState、mapGetters、mapMutations、mapActions 四个方法,使用他们,也可以在组件中直接使用Vuex。
还有使用模块化思想
为什么不能直接修改state的值
因为state是实时更新的,假如可以直接修改state,当你异步对state进行操作时,还没执行完,这时候如果state已经在其他地方被修改了,这样就会导致程序存在问题了。mutations无法进行异步操作,所以state要同步操作,通过mutations的方式限制了不允许异步。
Vue2的双向数据绑定原理
通过数据劫持实现数据的响应式更新,通过发布-订阅模式(Watcher)实现数据和视图之间的双向绑定。当数据发生变化时,会通知订阅者更新视图,保持数据和视图的同步。这种机制使得Vue能够实现高效的数据绑定和视图更新,提高开发效率和用户体验。
步骤
1.数据劫持(Object.defineProperty):创建实例时,Vue通过Object.defineProperty方法对data对象的属性进行劫持,当访问或修改属性值时,会触发getter和setter函数。在getter函数中收集依赖(将Watcher对象添加到订阅者列表中),在setter函数中通知订阅者更新视图。
2.模板编译:在编译阶段,Vue会解析模板中的指令,插值表达式等,生成可执行的渲染函数。渲染函数会建立起数据属性和视图之间的依赖关系,即将数据属性与侦听器(Watcher)关联起来
3.Watcher:Watcher是Vue中的观察者对象,用于监听数据的变化并更新视图。当模板中的数据发生变化时,Watcher会接收到通知,触发更新视图的操作。
4.视图更新:当数据放生变化时,相应的setter方法会被调用,从而通知Vue数据发生了变化,找到与该数据相关的Watcher对象,并执行Wathcer的更新方法,将更新结果渲染到视图上,实现了数据的双向绑定效果
组件的重新渲染
在Vue2中组件的重新渲染主要发生在组件的updated生命周期钩子函数中,updated生命周期钩子函数会在组件的数据发生变化,并且虚拟DOM重新徐渲染之后执行
组件重新渲染的流程
当组件的数据发生变化或父组件强制更新时。Vue2会重新渲染组件
步骤:
1.更新数据:组件的数据发生变化时,Vue会通知组件进行重新渲染
2.执行渲染函数:Vue会执行组件的渲染函数,生成新的虚拟DOM
3.比较差异:Vue会通过虚拟DOM的diff算法比较新旧虚拟DOM的差异,找出需要更新的部分
4.更新视图:Vue会更新真实DOM,只更新发生变化的部分,而不是重新渲染整个组件
Vue2是如何劫持data对象中的各种数据类型的
在Vue 2中,对data对象中的各种数据类型(包括对象、数组、基本数据类型等)的劫持是通过递归遍历对象属性并使用Object.defineProperty()方法实现的。具体来说,Vue对不同数据类型的劫持方式如下:
1. 对象(Object): 对于对象中的属性,Vue会递归遍历对象的每个属性,并使用Object.defineProperty()方法为每个属性定义getter和setter,以实现对对象属性的劫持。当对象属性被访问或修改时,Vue能够捕获这些操作并触发更新。
2. 数组(Array): 对于数组,Vue会重写数组的原型方法(如push、pop、shift等),以实现对数组的变化进行监听和响应。通过重写数组的原型方法,Vue能够实现对数组的劫持,确保对数组的操作能够触发更新。 Vue会将数组的原型方法进行重写,将这些方法指向Vue定义的新方法,这些新方法会在执行时触发Vue的响应式更新机制。
Vue2并没有劫持数组的下标,因此当通过下标修改数组时,无法触发视图的重新渲染
3. 基本数据类型(Number、String、Boolean等): 对于基本数据类型,Vue会将其包装成响应式对象,然后再进行劫持。Vue会为基本数据类型创建一个包装对象,并使用Object.defineProperty()方法为包装对象定义getter和setter,以实现对基本数据类型的劫持。
通过以上方式,Vue能够实现对data对象中各种数据类型的劫持,实现数据的响应式更新和视图的自动更新。这种劫持机制使得Vue能够实现数据驱动视图的特性,让开发者能够更便捷地处理数据和视图之间的关系。
Vue2中,对data中某个对象的原有属性值进行修改,会不会触发渲染?(会,因为数据劫持
Vue2中,对data中某个对象的新增属性值进行修改,会不会触发渲染 (不会,因为数据劫持发生在vue初始化阶段,用 s e t ,因为 set,因为 set,因为set相当于新一轮的数据劫持)
这是因为Vue在实例化时会对data对象进行响应式处理,只有已经存在于data中的属性才会被Vue的响应式系统追踪和监听变化。
当你向data中的对象新增属性时,这个新增的属性并不会被Vue的响应式系统捕获到,因此对新增属性的修改不会触发视图的重新渲染。如果想要让新增的属性也能触发视图更新,可以使用Vue.set()方法或者this.$set()方法来添加响应式属性,这样新增的属性就会被Vue监听到,并能触发视图的重新渲染。
给Vue2添加新的响应式属性的方法
//this.obj是要添加新属性的对象,'newProperty'是新属性的名称,value是新属性的值。
Vue.set(obj, 'newProperty', value);
this.$set(this.obj, 'newProperty', value);
使用Vue.set()或this.$set()方法添加新的响应式属性后,这个新属性就会被Vue监听到,能够触发视图的重新渲染。这样就可以动态地向Vue实例中的对象添加新的响应式属性,实现数据的动态更新和视图的同步显示。
Vue2中,对data中某个数组,用下标的表示修改值,会不会触发渲染?(不会)
Vue无法直接捕获这个操作,因为Vue只能劫持对象属性的访问和修改,而不是数组的下标操作。因此,Vue无法知道数组元素的变化,也就无法触发视图的重新渲染。
为了解决这个问题,Vue提供了Vue.set()方法或this.$set()方法来确保对数组的修改能够被Vue监听到。这两个方法会向数组中添加一个新的属性并触发视图更新,从而让Vue能够检测到数组的变化。
Vue2中,对data中某个数组进行push、pop会不会触发渲染?(会,vue的初始化阶段对数组方法进行重写,重写逻辑和$set差不多,新做了一次数据劫持)
在Vue 2中,对data中某个数组进行push、pop等操作会触发视图的重新渲染。这是因为Vue 2重写了数组的push、pop等方法,并在这些方法内部添加了更新视图的逻辑。当调用这些数组方法时,Vue能够捕获到数组的变化,并触发视图的重新渲染,确保视图与数据的同步更新。
为什么data属性是一个函数而不是一个对象
当data直接是一个对象时,多个组件会共同引用同一个数据对象,当其中一个组件修改了数据,其他组件也会受到影响,造成数据混乱。通过将data定义为一个函数,每次组件创建实例时,都会调用该函数返回一个新的数据对象,从而避免了数据共享的问题
computed和watch的区别,使用场景,举例
使用目的不同:computed是根据其所依赖的属性的值计算一个新属性的值,并将其作为响应式属性暴露给用户,适用于简单的计算逻辑;而侦听器则用于在某些数据变化时候执行异步或开销较大的操作
触发时机不同:计算属性会在其所依赖的属性发生变化时自动更新,而侦听器可以设置要观察的属性,只有当这些属性发生变化时才触发回调
使用场景举例:
场景一 - 使用computed: 假设在一个电子商务网站的项目中,有一个商品列表页面,每个商品有价格和折扣信息,需要计算出每个商品的实际价格(考虑折扣)并展示在页面上。这时可以使用computed属性来计算每个商品的实际价格
场景二 - 使用watch: 假设在一个社交媒体应用的项目中,用户有一个个人资料页面,需要监控用户个人资料的变化,并在变化时发送请求更新用户信息。这时可以使用watch属性来监听用户个人资料的变化
diff算法
虚拟DOM是真实DOM的js对象
Vue2 Diff算法总结(图文结合)
点击前往
Vuediff算法视频:点击前往
key值,为什么不推荐用index去当成key使用(基本上这一点要结合diff算法去回答)
v-for没有key值会发生什么
1.在vue虚拟DOM的对比算法中,无法识别两次渲染的具体变化,只能对整个列表进行重新渲染,从而导致性能下降
2.当数组的顺序发生变化时,vue会认为这是两组不同的元素,从而销毁原来的元素,创建一个新元素,可能导致浏览器的重绘与回流,影响渲染性能
3.当数组中有相同的值时,无法区分,可能会引起一起隐藏问题,如选中状态,切换状态等
key的工作原理
1.当Vue更新渲染真实DOM时,他会对新旧节点进行比较,找出他们之间的差异
2.如果两个节点具有相同的key值,则vue会认为它是相同的节点,会尝试复用已存在的真实DOM节点
3.如果节点具有不同的key值,Vue会视为不同的节点,并进行适当的更新,移动或删除操作
为什么不推荐用index去当成key使用
- 节点身份识别问题: 使用index作为key值时,Vue在进行节点比较时无法准确识别节点的身份。因为index是根据节点在数组中的位置生成的,当数组发生变化时,原本的index也会发生变化,导致Vue无法正确识别节点的身份,从而可能出现错误的更新或重渲染。
- 节点重用问题: 使用index作为key值时,Vue无法准确判断哪些节点是新增的、哪些节点是更新的、哪些节点是删除的,从而无法高效地重用节点。这可能导致不必要的DOM操作,影响性能。