目录
1、核心·-响应式
2、getCurrentInstance
3、5个内置组件
3-1、 Transition组件
基于 CSS 的过渡效果#
CSS 的 animation#
同时使用 transition 和 animation#
深层级过渡与显式过渡时长#
性能考量#
JavaScript 钩子#
可复用过渡效果#
出现时过渡#
过渡模式
3-2、TransitionGroup组件
和 的区别#
3-3、 KeepAlive组件
基本使用#
在 DOM 模板中使用时,它应该被写为 。
包含/排除#
最大缓存实例数#
缓存实例的生命周期#
3-4、Teleport 组件
3-5、Suspense组件
4、响应式-进阶
5、由于少了 export,没法传参,也不方便暴露接口,所以就增加了三个工具方法
defineProps
defineEmits
defineExpose
语法
defineProps :
1、适用于父组件向子组件传递属性
2、带默认值的defineProps
defineEmits
defineExpose
子组件:detail.vue
父组件:main.vue
6、其他的Composition API
6.1.shallowReactive与shallowRef
2.readonly与shallowReadonly
3.toRaw与markRaw
4.customRef
7.provide与inject
8、TypeScript 与组合式 API
9、Vuex与组合式API
组合式Api要求我们要将响应式的变量声明在setup函数中,setup函数是一个专门用于组合式Api的钩子函数。而且我们需要借助reactive函数来创建响应式的对象。
setup函数的两种返回值:
若返回一个对象,则对象中的属性、方法,在模板中均可以直接使用。(重点关注)
若返回一个渲染函数:则可以自定义渲染内容。
setup不能是一个async函数,因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性
setup的两个注意点
setup执行的时机:在beforeCreate之前执行一次,this是undefined
setup的参数
props:值为对象,包含: 组件外部传递过来,且组件内部声明接收了属性
context:上下文对象
attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性,相当于 this.$attrs
slots:收到插槽的内容,相当于$slots
emit: 分发自定义事件的函数,相当于this.$emit
//父组件
是插槽吗
meiyou
//子组件
export default {
name: 'test3',
props: ['msg'],
emits:['hello'],
//这里setup接收两个参数,一个是props,一个是上下文context
setup(props,context){
/**
* props就是父组件传来的值,但是他是Porxy类型的对象
* >Proxy:{msg:'传递吧'}
* 可以当作我们自定义的reactive定义的数据
*/
/**
* context是一个对象 包含以下内容:
* 1.emit触发自定义事件的
* 2.attrs 相当于vue2里面的 $attrs 包含:组件外部传递过来,但没有在props配置中声明的属性
* 3.slots 相当于vue2里面的 $slots
* 3.expose 是一个回调函数
*/
console.log(context.slots);
let person = reactive({
name: '张三',
age: 17,
})
function changeInfo(){
context.emit('hello', 666)
}
//返回对象
return {
person,
changeInfo
}
//返回渲染函数(了解) 这个h是个函数
//return () => h('name','age')
}
}
{{ datas.num }}
如上,即为组合式Api的典型写法。
在组合式Api中一定记得将需要暴露到模板的对象return出去(单独使用setup的时候)。
更多声明响应式对象的方法
前面我们已经了解了data方法(选项式Api中使用)、reactive(组合式Api中使用)两种不同的声明响应式对象的方式,那还有其他方式吗?
ref
因为reactive方法仅仅对,对象,数组、Map、Set类型生效,对于string、number、boolean类型是无效的。
鉴于这种情况,vue3引入了ref方法来帮助开发者创建任意类型的响应式对象。
toRef
当我们想要将reactive创建的响应式对象的某个属性单独传递出来时,我们可以使用toRef实现
{{ tms }}
姓名:{{ datas.name }}
年龄:{{ datas.age }}
toRefs
类似toRef,toRefs可以将reactive声明的响应式变量的所有元素都转换为ref对象。
{{ tms.num }}
姓名:{{ tms.name }}
年龄:{{ tms.age }}
toRefs的返回值是一个字典,格式为:
{name: ObjectRefImpl, age: ObjectRefImpl, num: ObjectRefImpl}
如上,我们已经将reactive定义的对象元素全部转换为了ref对象,而且属性值的变化会同步更新到reactive的对象中。
isRef
vue3为我们提供了判断时否为ref对象的方法,即isRef。
结果: 简化在setup中的return 前面我们有说,在组合式Api中,我们必须将模板需要的属性暴露出去。通常大多数的属性都是需要暴露出去的,为了方便,vue3支持在单文件组件(SFC)的场景下,使用
如上,我们直接使用
reactive对比ref
从定义数据角度对比:
ref用来定义: 基本数据类型
reactive用来定义: 对象(或数组)类型数据
备注: ref也可以用来定义对象(或数组)类型数据,它内部会自动通过reactive转为代理对象
从原理角度对比:
ref通过Object.defineProperty()的get和set来实现响应式(数据劫持)
reactive通过Proxy来实现响应式(数据劫持),并通过Reflect操作源对象内部的数据
从使用角度对比:
ref定义数据:操作数据需要 .value ,读取数据时模板中直接读取不需要 .value
reactive 定义的数据: 操作数据和读取数据均不需要 .value
箭头函数
箭头函数也叫匿名函数,将function关键字省略掉了。 一个简单例子区分普通函数和箭头函数。
// 普通函数
var f1=function(arg1,agr2){
return arg1+arg2
}
// 箭头函数-多参数
var f2 = (arg1,arg2)=>{
return arg1+arg2
}
// 箭头函数-无参数:不能省略括号
var f3 = ()=>{
return true
}
// 箭头函数-单参数:可以省略括号
var f3 = a =>{
return a
}
computed()
computed() 用来创建计算属性,computed() 函数的返回值是一个 ref 的实例。这个值模式是只读的:
import { ref, computed } from 'vue'
export default {
setup() {
const count = ref(0)
const plusCount = computed(() => count.value + 1)
plusCount.value = 10
console.log('plusCount:',plusCount.value)
console.log('count:', count.value)
}
}
// 打印结果:
// plusCount.value: 1
// count.value: 0
或者传入一个拥有 get 和 set 函数的对象,创建一个可手动修改的计算状态:
import { ref, computed } from 'vue'
export default {
setup() {
const count = ref(0)
const plusCount = computed({
get: () => count.value + 1,
set: val => {
count.value = val - 1
}
})
plusCount.value = 10
console.log('plusOne:',plusCount.value)
console.log('count:', count.value)
}
}
// 打印结果:
// plusOne.value: 10
// count.value: 9
计算属性与监视
computed函数
与vue2.x中的写法一致、需要引入computed
一个人的信息
姓:
名:
简名:{{person.smallName}}
全名:{{person.fullName}}
watch函数
和computed一样,需要引入api
有两个小坑:
1.监视reactive定义的响应式数据的时候:oldValue无法获取到正确的值,强制开启了深度
监视(deep配置无效)
2.监视reactive定义的响应式数据中某个属性的时候:deep配置有效
具体请看下面代码以及注释
当前求和为: {{sum}}
当前信息为: {{msg}}
姓名: {{person.name}}
年龄: {{person.age}}
watchEffect函数
watch的套路是:既要指明监视的属性,也要指明监视的回调
watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性
watchEffect有点像computed:
但computed注重的计算出来的值(回调函数的返回值),所以必须要写返回值
而watchEffect更注重的是过程(回调函数的函数体),所以不用写返回值
Vue2中,可以通过this来获取当前组件实例;
Vue3中,在setup中无法通过this获取组件实例,console.log(this)打印出来的值是undefined。
在Vue3中,getCurrentInstance()可以用来获取当前组件实例
let {proxy} =getCurrentInstance();
在setup中分别打印下面3个值,结果如下:
可以看到,getCurrentInstance是一个function方法,getCurrentInstance()是一个对象,proxy也是一个对象。proxy是getCurrentInstance()对象中的一个属性,通过对象的解构赋值方式拿到proxy。
getCurrentInstance只能在setup或生命周期钩子中使用。
1.在onMunted生命周期中打印getCurrentInstance
2.定义一个handClick方法,通过click事件触发方法
ctx和proxy都是getCurrentInstance()对象中的属性,通过解构赋值的方式拿到。可以看到,2者有所区别。ctx是普通对象,proxy是Proxy对象。
补充:Vue3中关于getCurrentInstance的大坑
应用场景1:如果开发中只适用于调试! 不要用于线上环境,否则会有问题!
解决方案:
方案2.使用proxy线上也不会出现问题
应用场景2:全局挂载变量或方法
方法1:
在页面中使用:
方法2:
通过provide和inject挂载
在src文件夹下创建symbol文件夹,并创建index.ts文件
main.ts定义:
Transition
组件
是一个内置组件,这意味着它在任意别的组件中都可以被使用,无需注册。它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组件上。进入或离开可以由以下的条件之一触发:
v-if
所触发的切换v-show
所触发的切换
切换的动态组件以下是最基本用法的示例:
当一个
组件中的元素被插入或移除时,会发生下面这些事情:
Vue 会自动检测目标元素是否应用了 CSS 过渡或动画。如果是,则一些 CSS 过渡 class 会在适当的时机被添加和移除。
如果有作为监听器的 JavaScript 钩子,这些钩子函数会在适当时机被调用。
如果没有探测到 CSS 过渡或动画、也没有提供 JavaScript 钩子,那么 DOM 的插入、删除操作将在浏览器的下一个动画帧后执行。
CSS 过渡 class#
一共有 6 个应用于进入与离开过渡效果的 CSS class。
v-enter-from
:进入动画的起始状态。在元素插入之前添加,在元素插入完成后的下一帧移除。
v-enter-active
:进入动画的生效状态。应用于整个进入动画阶段。在元素被插入之前添加,在过渡或动画完成之后移除。这个 class 可以被用来定义进入动画的持续时间、延迟与速度曲线类型。
v-enter-to
:进入动画的结束状态。在元素插入完成后的下一帧被添加 (也就是 v-enter-from
被移除的同时),在过渡或动画完成之后移除。
v-leave-from
:离开动画的起始状态。在离开过渡效果被触发时立即添加,在一帧后被移除。
v-leave-active
:离开动画的生效状态。应用于整个离开动画阶段。在离开过渡效果被触发时立即添加,在过渡或动画完成之后移除。这个 class 可以被用来定义离开动画的持续时间、延迟与速度曲线类型。
v-leave-to
:离开动画的结束状态。在一个离开动画被触发后的下一帧被添加 (也就是 v-leave-from
被移除的同时),在过渡或动画完成之后移除。
v-enter-active
和 v-leave-active
给我们提供了为进入和离开动画指定不同速度曲线的能力,我们将在下面的小节中看到一个示例。
我们可以给
组件传一个 name
prop 来声明一个过渡效果名:
template
...
对于一个有名字的过渡效果,对它起作用的过渡 class 会以其名字而不是 v
作为前缀。比如,上方例子中被应用的 class 将会是 fade-enter-active
而不是 v-enter-active
。这个“fade”过渡的 class 应该是这样:
css
原生 CSS 动画和 CSS transition 的应用方式基本上是相同的,只有一点不同,那就是 *-enter-from
不是在元素插入后立即移除,而是在一个 animationend
事件触发时被移除。
对于大多数的 CSS 动画,我们可以简单地在 *-enter-active
和 *-leave-active
class 下声明它们。下面是一个示例:
Vue 需要附加事件监听器,以便知道过渡何时结束。可以是 transitionend
或 animationend
,这取决于你所应用的 CSS 规则。如果你仅仅使用二者的其中之一,Vue 可以自动探测到正确的类型。
然而在某些场景中,你或许想要在同一个元素上同时使用它们两个。举例来说,Vue 触发了一个 CSS 动画,同时鼠标悬停触发另一个 CSS 过渡。此时你需要显式地传入 type
prop 来声明,告诉 Vue 需要关心哪种类型,传入的值是 animation
或 transition
:
尽管过渡 class 仅能应用在
的直接子元素上,我们还是可以使用深层级的 CSS 选择器,在深层级的元素上触发过渡效果。
你可能注意到我们上面例子中展示的动画所用到的 CSS 属性大多是 transform
和 opacity
之类的。用这些属性制作动画非常高效,因为:
他们在动画过程中不会影响到 DOM 结构,因此不会每一帧都触发昂贵的 CSS 布局重新计算。
大多数的现代浏览器都可以在执行 transform
动画时利用 GPU 进行硬件加速。
相比之下,像 height
或者 margin
这样的属性会触发 CSS 布局变动,因此执行它们的动画效果更昂贵,需要谨慎使用。我们可以在 CSS-Triggers 这类的网站查询哪些属性会在执行动画时触发 CSS 布局变动。
你可以通过监听
组件事件的方式在过渡过程中挂上钩子函数:
这些钩子可以与 CSS 过渡或动画结合使用,也可以单独使用。
在使用仅由 JavaScript 执行的动画时,最好是添加一个 :css="false"
prop。这显式地向 Vue 表明可以跳过对 CSS 过渡的自动探测。除了性能稍好一些之外,还可以防止 CSS 规则意外地干扰过渡效果。在有了 :css="false"
后,我们就自己全权负责控制什么时候过渡结束了。这种情况下对于 @enter
和 @leave
钩子来说,回调函数 done
就是必须的。否则,钩子将被同步调用,过渡将立即完成。
得益于 Vue 的组件系统,过渡效果是可以被封装复用的。要创建一个可被复用的过渡,我们需要为
组件创建一个包装组件,并向内传入插槽内容:
如果你想在某个节点初次渲染时应用一个过渡效果,你可以添加 appear
prop:
在之前的例子中,进入和离开的元素都是在同时开始动画的,因此我们不得不将它们设为 position: absolute
以避免二者同时存在时出现的布局问题。
然而,很多情况下这可能并不符合需求。我们可能想要先执行离开动画,然后在其完成之后再执行元素的进入动画。手动编排这样的动画是非常复杂的,好在我们可以通过向
传入一个 mode
prop 来实现这个行为:
Senior Frontend Engineer, CoreSenior Frontend Engineer, Core
是一个内置组件,用于对 v-for
列表中的元素或组件的插入、移除和顺序改变添加动画效果。
的区别#
支持和
基本相同的 props、CSS 过渡 class 和 JavaScript 钩子监听器,但有以下几点区别:
默认情况下,它不会渲染一个容器元素。但你可以通过传入 tag
prop 来指定一个元素作为容器元素来渲染。
过渡模式在这里不可用,因为我们不再是在互斥的元素之间进行切换。
列表中的每个元素都必须有一个独一无二的 key
attribute。
CSS 过渡 class 会被应用在列表内的元素上,而不是容器元素上。
Senior Frontend Developer
Nordhealth Oy · Remote
Front End Web Developer (Manager)
Hudson Creative · New York City, NY, USA
Jobs by vuejobs.com
是一个内置组件,它的功能是在多个组件间动态切换时缓存被移除的组件实例。
在组件基础章节中,我们已经介绍了通过特殊的
元素来实现动态组件的用法:
template
默认情况下,一个组件实例在被替换掉后会被销毁。这会导致它丢失其中所有已变化的状态 —— 当这个组件再一次被显示时,会创建一个只带有初始状态的新实例。
在下面的例子中,你会看到两个有状态的组件——A 有一个计数器,而 B 有一个通过 v-model
同步 input 框输入内容的文字展示。尝试先更改一下任意一个组件的状态,然后切走,再切回来:
你会发现在切回来之后,之前已更改的状态都被重置了。
在切换时创建新的组件实例通常是有意义的,但在这个例子中,我们的确想要组件能在被“切走”的时候保留它们的状态。要解决这个问题,我们可以用
内置组件将这些动态组件包装起来:
template
现在,在组件切换时状态也能被保留了:
在演练场中尝试一下
TIP
。
默认会缓存内部的所有组件实例,但我们可以通过 include
和 exclude
prop 来定制该行为。这两个 prop 的值都可以是一个以英文逗号分隔的字符串、一个正则表达式,或是包含这两种类型的一个数组:
template
它会根据组件的 name 选项进行匹配,所以组件如果想要条件性地被 KeepAlive
缓存,就必须显式声明一个 name
选项。
TIP
在 3.2.34 或以上的版本中,使用 的单文件组件会自动根据文件名生成对应的
name
选项,无需再手动声明。
我们可以通过传入 max
prop 来限制可被缓存的最大组件实例数。
的行为在指定了 max
后类似一个 LRU 缓存:如果缓存的实例数量即将超过指定的那个最大数量,则最久没有被访问的缓存实例将被销毁,以便为新的实例腾出空间。
template
当一个组件实例从 DOM 上移除但因为被
缓存而仍作为组件树的一部分时,它将变为不活跃状态而不是被卸载。当一个组件实例作为缓存树的一部分插入到 DOM 中时,它将重新被激活。
一个持续存在的组件可以通过 onActivated() 和 onDeactivated() 注册相应的两个状态的生命周期钩子:
vue
请注意:
onActivated
在组件挂载时也会调用,并且 onDeactivated
在组件卸载时也会调用。
这两个钩子不仅适用于
缓存的根组件,也适用于缓存树中的后代组件。
{{ data.count }}
1s之后更新
{{ text }}
shallowReactive
{{ stateReactive.foo }}
effectScope
{{ counter}}
import {customRef} from 'vue'
export function useDebouncedRef(value:any,delay=200){
let timeout:any
return customRef((track,trigger)=>{
return {
get(){
track()
return value
},
set(newValue){
clearTimeout(timeout)
timeout=setTimeout(()=>{
value=newValue
trigger()
},delay)
}
}
})
}
export
,没法传参,也不方便暴露接口,所以就增加了三个工具方法defineProps
defineEmits
defineExpose
注意,这三个工具方法只是帮助 Vue 编译器构建组件,它们不会出现在最终代码里,我们也不能预期它们会像普通函数那样工作。比如下面这段代码,就得不到常见的结果:
const props = defineProps({
userMenu: {
type: Array,
default() {
return []
}
}
})
console.log(props) // 该对象中的 userName 总是有值
console.log(props.userMenu) // 该对象始终是一个空数据
因为 Vue 是 MVVM 框架,它的视图会在数据变化后自动渲染,于是通常情况下,
props 里的值什么时候被填充并不重要,Vue 开发团队也不想追求 defineProps 工作的一般化。
所以使用目前版本,上面这段代码,访问到的 props 是 reactive 对象,数据被填充后就能看到
userName 里有值;
而 props.userMenu 在访问时还没有被填充,所以得到的是 default() 返回的默认值,一直是空的。
同时大家还要知道,console.log() 输出的是对象的指针,而非快照。
所以里面的值只跟你展开时有关,跟运行时关系不大
在 script setup 中必须使用 defineProps 和 defineEmits API 来声明 props 和 emits ,它们具备完整的类型推断并且在 script setup 中是直接可用的
子组件
// 定义Props
const props = defineProps<{
result: number,
name: string
}>()
父组件
适用于带默认值的Props,经测试不能与defineProps在同一组件同时定义。
子组件
interface IProps {
labels?: string[]
result: number,
name:string
}
// 定义带默认值的Props
const defaultProps = withDefaults(defineProps(), {
name: 'hello',
result:0,
labels: () => ['one', 'two']
})
父组件
适用于父组件向子组件传递方法
子组件
// 定义Emits
const emits = defineEmits<{
(e: 'add', id: number): void
(e: 'reset', value: number): void
}>()
const btnAdd = () => {
emits('add',2)
}
const btnReset = () => {
emits("reset",0)
}
夫组件
const result = ref(0);
const add = (num:number)=>{
result.value+=num
}
const reset = (num:number)=>{
result.value = num
}
适用于子组件向父组件暴露方法和属性,父组件通过子组件示例进行调用。
子组件
// 定义
Expose const exposeStr = ref("") defineExpose({ exposeStr })
父组件
// 必须跟组件ref保持一致
const detail = ref()
setTimeout (() => {
detail.value.exposeStr = "exposeStr"
},1000)
完整代码
{{defaultProps.name}} - {{defaultProps.result}} - {{defaultProps.labels}}
{{exposeStr}}
shallowReactive:只处理对象最外层属性的响应式(浅响应式)只考虑第一层数据的响应式。
shallowRef:只处理基本数据类型的响应式,不进行对象的响应式处理,传递基本数据类型的话跟ref没有任何区别,ref是可以进行对象的响应式处理的
我们正常的ref创建的数据,里面的.value是一个proxy,而shallowRef创建的数据 .value里面是一个object数据类型,所以不会响应式数据
什么时候使用?:
如果有一个对象数据,结构比较深,但变化时只是外层属性变化 ===> shallowReactive
如果有一个对象数据,后续功能不会修改对象中的属性,而是生新的对象来替换 ===> shallowRef
readonly:让一个响应式的数据变成只读的(深只读)
shallowReadonly: 让一个响应式数据变成只读的(浅只读)
应用场景:不希望数据被修改的时候
toRaw
作用:将一个由reactive生成的响应式对象转换为普通对象
使用场景:用于读取响应式对象对应的普通对象,对这个普通对象的所有操作,不会引起页面更新
markRaw:
作用:标记一个对象,使其永远不会再成为响应式对象
使用场景:
1.有些值不应被设置成响应式的,例如复杂的第三方类库等
2.当渲染具有不可变数据的大列表时候,跳过响应式转换可以提高性能
import {reactive,toRaw,markRaw} from 'vue'
setup(){
let person = reactive({
name: '张三',
})
function showRawPerson(){
const p = toRaw(person)
p.age++
console.log(p)
}
function addCar(){
let car = {name: '奔驰'}
person.car = markRaw(car) //一旦这么做时候,他就永远不能当成响应式数据去做了
}
}
创建一个自定义的ref,并对其依赖项跟踪和更新触发进行显示控制
实现防抖效果:
{{keyword}}
作用:实现祖孙组件间的通信
套路:父组件有一个provide选项提供数据,子组件有一个inject选项来开始使用这些数据
具体写法:
//父组件
我是父组件, {{name}}--{{price}}
//子组件
我是子组件
//孙组件
我是孙组件
{{name}}-{{price}}
1.为组件的 props 标注类型
// 场景一: 使用
//也可以将 props 的类型移入一个单独的接口中
//场景二: 不使用
2.为组件的 emits 标注类型
//场景一: 使用
//场景二: 不使用
//因此,建议显式地为事件处理函数的参数标注类型,需要显式地强制转换 event 上的属性:
function handleChange(event: Event) {
console.log((event.target as HTMLInputElement).value)
}
7.为 provide / inject 标注类型
/*
provide 和 inject 通常会在不同的组件中运行。要正确地为注入的值标记类型,
Vue 提供了一个 InjectionKey 接口,它是一个继承自 Symbol 的泛型类型,
可以用来在提供者和消费者之间同步注入值的类型:
*/
import { provide, inject } from 'vue'
import type { InjectionKey } from 'vue'
const key = Symbol() as InjectionKey
provide(key, 'foo') // 若提供的是非字符串值会导致错误
const foo = inject(key) // foo 的类型:string | undefined
//建议将注入 key 的类型放在一个单独的文件中,这样它就可以被多个组件导入。
//当使用字符串注入 key 时,注入值的类型是 unknown,需要通过泛型参数显式声明:
const foo = inject('foo') // 类型:string | undefined
//注意注入的值仍然可以是 undefined,因为无法保证提供者一定会在运行时 provide 这个值。
//当提供了一个默认值后,这个 undefined 类型就可以被移除:
const foo = inject('foo', 'bar') // 类型:string
//如果你确定该值将始终被提供,则还可以强制转换该值:
const foo = inject('foo') as string
8.为模板引用标注类型
//模板引用需要通过一个显式指定的泛型参数和一个初始值 null 来创建:
/**
注意为了严格的类型安全,有必要在访问 el.value 时使用可选链或类型守卫。这是因为直到组件被挂载前,
这个 ref 的值都是初始的 null,并且在由于 v-if 的行为将引用的元素卸载时也可以被设置为 null。
*/
9.为组件模板引用标注类型
//有时,你可能需要为一个子组件添加一个模板引用,以便调用它公开的方法。举例来说,我们有一个 MyModal 子组件,它有一个打开模态框的方法
//为了获取 MyModal 的类型,我们首先需要通过 typeof 得到其类型,再使用 TypeScript 内置的 InstanceType 工具类型来获取其实例类型:
注意,如果你想在 TypeScript 文件而不是在 Vue SFC 中使用这种技巧,需要开启 Volar 的Takeover 模式。
组合式API 可以通过调用 useStore 函数,来在 setup 钩子函数中访问 store。这与在组件中使用选项式 API 访问 this.$store 是等效的。
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
}
}
1.访问 state 和 getter
为了访问 state 和 getter,需要创建 computed 引用以保留响应性,这与在选项式 API 中创建计算属性等效。
import { computed } from 'vue'
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
return {
// 在 computed 函数中访问 state
count: computed(() => store.state.count),
// 在 computed 函数中访问 getter
double: computed(() => store.getters.double)
}
}
}
2.访问 Mutation 和 Action
要使用 mutation 和 action 时,只需要在 setup 钩子函数中调用 commit 和 dispatch 函数。
import { useStore } from 'vuex'
export default {
setup () {
const store = useStore()
return {
// 使用 mutation
increment: () => store.commit('increment'),
// 使用 action
asyncIncrement: () => store.dispatch('asyncIncrement')
}
}
}
后续更新中。。。