共计 6423 个字符,预计需要花费 17 分钟才能阅读完成。
vue3.x 曾经公布了这么久,相干的生态也缓缓起来了,包含 vite 这个新的打包工具,在 vue3.0 学习过程中有一些实用性的 api 比照,心愿能在开发中给大家做个示范,精确的应用对应的 api 去实现咱们的我的项目开发
生命周期的变更
要特地阐明一下的就是,setup
函数代替了 beforeCreate
和 created
两个生命周期函数,因而咱们能够认为它的执行工夫在beforeCreate
和 created
之间
Vue2 | Vue3 |
---|---|
beforeCreate | setup |
created | setup |
beforeMount | onBeforeMount |
mounted | onMounted |
beforeUpdate | onBeforeUpdate |
updated | onUpdated |
beforeDestory | onBeforeUnmount |
destoryed | onUnmounted |
理解过 vue3 的小伙伴儿都晓得,当初应用都会用到 setup 函数,对于在 setup 函数操作数据,咱们用例子说明会好一点
reactive
reactive
办法是用来创立一个响应式的数据对象,该 API 也很好地解决了 Vue2 通过 defineProperty
实现数据响应式的缺点
用法很简略,只需将数据作为参数传入即可
<template>
<div id="app">
<!-- 4. 拜访响应式数据对象中的 count -->
{{state.count}}
</div>
</template>
<script>
// 1. 从 vue 中导入 reactive
import {reactive} from 'vue'
export default {
name: 'App',
setup() {
// 2. 创立响应式的数据对象
const state = reactive({count: 3})
// 3. 将响应式数据对象 state return 进来,供 template 应用
return {state}
}
}
</script>
ref
在介绍 setup
函数时,咱们应用了 ref
函数包装了一个响应式的数据对象,这里外表上看上去跟 reactive
如同性能截然不同啊,的确差不多,因为 ref
就是通过 reactive
包装了一个对象,而后是将值传给该对象中的 value
属性,这也就解释了为什么每次拜访时咱们都须要加上 .value
咱们能够简略地把 ref(obj)
了解为这个样子 reactive({value: obj})
<script>
import {ref, reactive} from 'vue'
export default {
name: 'App',
setup() {const obj = {count: 3}
const state1 = ref(obj)
const state2 = reactive(obj)
console.log(state1)
console.log(state2)
}
}
</script>
留神: 这里指的 .value
是在 setup
函数中拜访 ref
包装后的对象时才须要加的,在 template
模板中拜访时是不须要的,因为在编译时,会自动识别其是否为 ref
包装过的
那么咱们到底该如何抉择 ref
和 reactive
呢?
倡议:
- 根本类型值(
String
、Nmuber
、Boolean
等)或单值对象(相似像{count: 3}
这样只有一个属性值的对象)应用ref
- 援用类型值(
Object
、Array
)应用reactive
咱们在 vue2.x 中获取元素标签是用 ref
,vue3.x 咱们要获取元素标签怎么办呢?
<template>
<div>
<div ref="el">div 元素 </div>
</div>
</template>
<script>
import {ref, onMounted} from 'vue'
export default {setup() {
// 创立一个 DOM 援用,名称必须与元素的 ref 属性名雷同
const el = ref(null)
// 在挂载后能力通过 el 获取到指标元素
onMounted(() => {el.value.innerHTML = '内容被批改'})
// 把创立的援用 return 进来
return {el}
}
}
</script>
获取元素的操作一共分为以下几个步骤:
- 先给指标元素的
ref
属性设置一个值,假如为el
- 而后在
setup
函数中调用ref
函数,值为null
,并赋值给变量el
,这里要留神,该变量名必须与咱们给元素设置的ref
属性名雷同 - 把对元素的援用变量
el
返回(return)进来
补充:设置的元素援用变量只有在组件挂载后能力拜访到,因而在挂载前对元素进行操作都是有效的
当然如果咱们援用的是一个组件元素,那么取得的将是该组件的实例对象
toRef
toRef
是将某个对象中的某个值转化为响应式数据,其接管两个参数,第一个参数为 obj
对象;第二个参数为对象中的属性名
<script>
// 1. 导入 toRef
import {toRef} from 'vue'
export default {setup() {const obj = {count: 3}
// 2. 将 obj 对象中属性 count 的值转化为响应式数据
const state = toRef(obj, 'count')
// 3. 将 toRef 包装过的数据对象返回供 template 应用
return {state}
}
}
</script>
下面又有个 ref,又有个 toRef,不是抵触了吗?两个有不一样的效用:
<template>
<p>{{state1}}</p>
<button @click="add1"> 减少 </button>
<p>{{state2}}</p>
<button @click="add2"> 减少 </button>
</template>
<script>
import {ref, toRef} from 'vue'
export default {setup() {const obj = {count: 3}
const state1 = ref(obj.count)
const state2 = toRef(obj, 'count')
function add1() {
state1.value ++
console.log('原始值:', obj);
console.log('响应式数据对象:', state1);
}
function add2() {
state2.value ++
console.log('原始值:', obj);
console.log('响应式数据对象:', state2);
}
return {state1, state2, add1, add2}
}
}
</script>
ref
是对原数据的一个 拷贝 ,不会影响到原始值,同时响应式数据对象值扭转后会同步更新视图toRef
是对原数据的一个 援用,会影响到原始值,然而响应式数据对象值扭转后会不会更新视图
toRefs
将传入的对象里所有的属性的值都转化为响应式数据对象,该函数反对一个参数,即 obj
对象
<script>
// 1. 导入 toRefs
import {toRefs} from 'vue'
export default {setup() {
const obj = {
name: '前端印象',
age: 22,
gender: 0
}
// 2. 将 obj 对象中属性 count 的值转化为响应式数据
const state = toRefs(obj)
// 3. 打印查看一下
console.log(state)
}
}
</script>
返回的是一个对象,对象里蕴含了每一个包装过后的响应式数据对象
shallowReactive
听这个 API 的名称就晓得,这是一个浅层的 reactive
,难道意思就是本来的 reactive
是深层的呗,没错,这是一个用于性能优化的 API
<script>
<template>
<p>{{state.a}}</p>
<p>{{state.first.b}}</p>
<p>{{state.first.second.c}}</p>
<button @click="change1"> 扭转 1 </button>
<button @click="change2"> 扭转 2 </button>
</template>
<script>
import {shallowReactive} from 'vue'
export default {setup() {
const obj = {
a: 1,
first: {
b: 2,
second: {c: 3}
}
}
const state = shallowReactive(obj)
function change1() {state.a = 7}
function change2() {
state.first.b = 8
state.first.second.c = 9
console.log(state);
}
return {state}
}
}
</script>
首先咱们点击了第二个按钮,扭转了第二层的 b
和第三层的 c
,尽管值产生了扭转,然而视图却没有进行更新;
当咱们点击了第一个按钮,扭转了第一层的 a
时,整个视图进行了更新;
由此可阐明,shallowReactive
监听了第一层属性的值,一旦产生扭转,则更新视图
shallowRef
这是一个浅层的 ref
,与 shallowReactive
一样是拿来做性能优化的,配合triggerRef
,调用它就能够立马更新视图,其接管一个参数 state
,即须要更新的 ref
对象
shallowReactive
是监听对象第一层的数据变动用于驱动视图更新,那么 shallowRef
则是监听 .value
的值的变动来更新视图的
<template>
<p>{{state.a}}</p>
<p>{{state.first.b}}</p>
<p>{{state.first.second.c}}</p>
<button @click="change"> 扭转 </button>
</template>
<script>
import {shallowRef, triggerRef} from 'vue'
export default {setup() {
const obj = {
a: 1,
first: {
b: 2,
second: {c: 3}
}
}
const state = shallowRef(obj)
console.log(state);
function change() {
state.value.first.b = 8
state.value.first.second.c = 9
// 批改值后立刻驱动视图更新
triggerRef(state)
console.log(state);
}
return {state, change}
}
}
</script>
toRaw
toRaw
办法是用于获取 ref
或 reactive
对象的原始数据的
<script>
import {reactive, toRaw} from 'vue'
export default {setup() {
const obj = {
name: '前端印象',
age: 22
}
const state = reactive(obj)
const raw = toRaw(state)
console.log(obj === raw) // true
}
}
</script>
上述代码就证实了 toRaw
办法从 reactive
对象中获取到的是原始数据,因而咱们就能够很不便的通过批改原始数据的值而不更新视图来做一些性能优化了
留神: 补充一句,当
toRaw
办法接管的参数是ref
对象时,须要加上.value
能力获取到原始数据对象
markRaw
markRaw
办法能够将原始数据标记为非响应式的,即应用 ref
或 reactive
将其包装,仍无奈实现数据响应式,其接管一个参数,即原始数据,并返回被标记后的数据。即便咱们批改了值也不会更新视图了,即没有实现数据响应式
<template>
<p>{{state.name}}</p>
<p>{{state.age}}</p>
<button @click="change"> 扭转 </button>
</template>
<script>
import {reactive, markRaw} from 'vue'
export default {setup() {
const obj = {
name: '前端印象',
age: 22
}
// 通过 markRaw 标记原始数据 obj, 使其数据更新不再被追踪
const raw = markRaw(obj)
// 试图用 reactive 包装 raw, 使其变成响应式数据
const state = reactive(raw)
function change() {
state.age = 90
console.log(state);
}
return {state, change}
}
}
</script>
watchEffect
watchEffect
它与 watch
的区别次要有以下几点:
- 不须要手动传入依赖
- 每次初始化时会执行一次回调函数来主动获取依赖
- 无奈获取到原值,只能失去变动后的值
<script>
import {reactive, watchEffect} from 'vue'
export default {setup() {const state = reactive({ count: 0, name: 'zs'})
watchEffect(() => {console.log(state.count)
console.log(state.name)
/* 初始化时打印:0
zs
1 秒后打印:1
ls
*/
})
setTimeout(() => {
state.count ++
state.name = 'ls'
}, 1000)
}
}
</script>
没有像 watch
办法一样先给其传入一个依赖,而是间接指定了一个回调函数
当组件初始化时,将该回调函数执行一次,主动获取到须要检测的数据是 state.count
和 state.name
依据以上特色,咱们能够自行抉择应用哪一个监听器
getCurrentInstance
咱们都晓得在 Vue2 的任何一个组件中想要获取以后组件的实例能够通过 this
来失去,而在 Vue3 中咱们大量的代码都在 setup
函数中运行,并且在该函数中 this
指向的是undefined
,那么该如何获取到以后组件的实例呢?这时能够用到另一个办法,即 getCurrentInstance
<template>
<p>{{num}}</p>
</template>
<script>
import {ref, getCurrentInstance} from 'vue'
export default {setup() {const num = ref(3)
const instance = getCurrentInstance()
console.log(instance)
return {num}
}
}
</script>
instance
中重点关注 ctx
和 proxy
属性,这两个才是咱们想要的 this
。能够看到 ctx
和 proxy
的内容非常相似,只是后者绝对于前者内部包装了一层 proxy
,由此可阐明 proxy
是响应式的
useStore
在 Vue2 中应用 Vuex,咱们都是通过 this.$store
来与获取到 Vuex 实例,但上一部分说了本来 Vue2 中的 this
的获取形式不一样了,并且咱们在 Vue3 的 getCurrentInstance().ctx
中也没有发现 $store
这个属性,那么如何获取到 Vuex 实例呢?这就要通过 vuex
中的一个办法了,即 useStore
// store 文件夹下的 index.js
import Vuex from 'vuex'
const store = Vuex.createStore({
state: {
name: '前端印象',
age: 22
},
mutations: {……},
……
})
// example.vue
<script>
// 从 vuex 中导入 useStore 办法
import {useStore} from 'vuex'
export default {setup() {
// 获取 vuex 实例
const store = useStore()
console.log(store)
}
}
</script>
而后接下来就能够像之前一样失常应用 vuex
了
参考:vue3 罕用 api 应用