# 谈谈 vue3 的 ref 和 reactive
# vue 的组件传值如何实现
# vue 的响应式原理
# event bus 如何实现
# vue 声明周期做的事情
# beforeCreate
实例、组件通过 new Vue() 在内存中创建出来之后会初始化事件和生命周期,然后就会执行 beforeCreate 钩子函数,这个时候,数据还没有挂载,只是一个空壳,无法访问到数据和真实的 dom;只包含一些自带的生命周期函数;
# created
进行挂载数据以及绑定事件等;比如处理 inject 、props 、methods 、data 、computed 和 watch 的初始化处理;
这个时候可以获取到数据,也可以更改数据,在这里更改数据不会触发updated 函数,不会触发其他的钩子函数,一般可以在这里做初始数据的获取;
# beforeMount
这个阶段将编译模板为虚拟 dom 放入到 render (渲染)函数中准备渲染,然后执行 beforeMount 钩子函数;
在这个函数中虚拟 dom 已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发 updated,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做初始数据的获取;
# mounted
接下来开始 render,渲染出真实 dom,然后执行 mounted (安装好的)钩子函数;此时,组件已经出现在页面中,数据、真实 dom 都已经处理好了,事件都已经挂载好了,可以在这里操作真实 dom 等事情;
# beforeUpdate
当组件或实例的数据更改之后,会立即执行 beforeUpdate,(更新之前)然后 vue 的虚拟 dom 机制会重新构建虚拟 dom与上一次的虚拟 dom 树利用 diff 算法进行对比之后重新渲染,一般不做什么事儿;需要注意的是界面中的数据还是旧的,但是 data 数据已经更新,页面中和 data 还没有同步;
# updated
当更新完成后,执行 updated,数据已经更改完成,dom 也重新 render 完成,可以操作更新后的虚拟 dom;此时页面中的数据和 data 保持一致;
# beforeDestroy
执行该方法的时候,Vue 的生命周期已经进入销毁阶段,但是实例上的各种数据还出于可用状态;一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件、websocket 服务关闭等等;
# destroyed
组件已经全部销毁,Vue 实例已经被销毁,Vue 中的任何数据都不可用只剩下 dom 空壳,这个时候,执行 destroyed,在这里做善后工作也可以;
# provide/inject 实现响应式数据更新
官网 api 说到:
提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的。
如果我们传入简单的属性并不是可响应的;实现响应式数据更新很简单,就是在 provide 中返回一个函数,这个函数去引用需要监听更新的数据;实际上这个函数存储了父组件实例的引用,所以每次子组件都能获取到最新的数据。如下代码:
父组件:
<template>
<div class="parent-container">
Parent组件
<br/>
<button type="button" @click="changeName">改变name</button>
<br/>
Parent 组件中 name的值: {{name}}
<Child v-bind="{name: 'k3vvvv'}" />
</div>
</template>
<script>
import Child from './Child'
export default {
name: 'Parent',
components: {
Child
},
data () {
return {
name: 'Kevin'
}
},
methods: {
changeName (val) {
this.name = 'parent - 1'
}
},
provide () {
return {
getReaciveNameFromParent: () => this.name
}
}
}
</script>
子组件中:
<template>
<div class="child-container">
Child组件
<br/>
<GrandSon />
</div>
</template>
<script>
import GrandSon from './GrandSon'
export default {
components: {
GrandSon
}
}
</script>
GrandSon 组件:
<template>
<div class="grandson-container">
Grandson组件
<br/>
{{reactiveNameFromParent}}
</div>
</template>
<script>
export default {
inject: ['getReaciveNameFromParent'],
computed: {
reactiveNameFromParent () {
return this.getReaciveNameFromParent()
}
},
watch: {
'reactiveNameFromParent': function (val) {
console.log('来自Parent组件的name值发生了变化', val)
}
}
}
</script>
# vue 如何实现 v-model
首先 v-model 的本质就是语法糖;如下:
<input type="text" v-model="name">
相当于:
<input :value="name" @input="name = $event.target.vaule" >
如下例子:
<template>
<div>
<custom-text-input
v-model='value'
/>
<p> Value: {{ value }} </p>
</div>
</template>
<script>
import CustomTextInput from './CustomTextInput.vue'
export default {
components: {
CustomTextInput,
},
data() {
return {
value: 'Matt',
}
}
}
</script>
然后,我们内部的子组件:
<template>
<input type="text" :value="value" @input="$emit('input', $event.target.value)">
</template>
<script>
export default {
name: 'vmodel',
props: {
value: String
}
}
</script>
<style scoped type="less">
</style>
参考:https://segmentfault.com/a/1190000039219503
# 什么是虚拟 DOM
首先需要知道为何使用虚拟 DOM ,因为我们直接通过 JS 进行 DOM 操作是非常 “昂贵” 的,很消耗性能,浏览器会从构建 DOM 树开始从头到尾执行一遍流程;频繁操作还是会出现页面卡顿,影响用户体验。
虚拟 DOM 就是为了解决浏览器性能问题而被设计出来的。比如一次操作中有 10 次更新 DOM 的动作,虚拟 DOM 不会立即操作 DOM,而是将这 10 次更新的 diff 内容保存到本地一个 JS 对象中,最终将这个 JS 对象一次性 attch 到 DOM 树上,再进行后续操作,避免大量无谓的计算量。所以,用 JS 对象模拟 DOM 节点的好处是,页面的更新可以先全部反映在 JS 对象(虚拟 DOM )上,操作内存中的 JS 对象的速度显然要更快,等更新完成后,再将最终的 JS 对象映射成真实的 DOM,交由浏览器去绘制。
# vuex 实现原理以及使用
# vuex 如何实现持久性存储
# v-if、v-show 实现原理;
# vue-router 的实现原理;各个模式
# nexttrick 如何实现
# vue 整个数据更新流程;
# object.defineproperty 注意。对数组有什么影响,vue2 为何不使用;proxy API;
# 更新策略。以及虚拟 dom 等
# 与 react 相比,数据流向以及更新策略有何不同
# Vue 中父组件能否监听子组件的生命周期
方法一:
// Parent.vue
<Child @mounted="doSomething"/>
// Child.vue
mounted() {
this.$emit("mounted");
}
方法二:
使用 @hook
// Parent.vue
<Child @hook:mounted="doSomething" ></Child>
doSomething() {
console.log('父组件监听到 mounted 钩子函数 ...')
}
// Child.vue
mounted(){
console.log('子组件触发 mounted 钩子函数 ...')
}
// 以上输出顺序为:
// 子组件触发 mounted 钩子函数 ...
// 父组件监听到 mounted 钩子函数 ...
# Vue 父组件与子组件声明周期的执行顺序
Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:
- 加载渲染过程
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
- 子组件更新过程
父 beforeUpdate -> 子 beforeUpdate -> 子 update -> 父 updated
- 父组件更新过程
父 beforeUpdate -> 父 updated
- 销毁过程
父 beforeDestory -> 子 beforeDestory -> 子 destoryed -> 父 destoryed