Vue3学习文档

一、Vue 3.0 六大两点

  1. Performance:性能比 Vue 2.x快1.2~2倍
  2. Tree shaking support:按需编译,体积比Vue 2.x 更小
  3. Composition API: 组合API(类似React Hooks)
  4. Better TypeScript support:更好的 TS 支持
  5. Custom Renderer API:暴露了自定义渲染API
  6. Fragment, Teleport(Protal), Suspense:更先进的组件

1.1 Vue3.0 是如何变快

1.1.1 diff 算法优化

  • Vue2 中的虚拟dom是进行全量的对比,即数据更新后在虚拟 DOM 中每个标签内容都会对比有没有发生变化
  • Vue3 新增了静态标记(PatchFlag)。在创建虚拟 DOM 的时候会根据 DOM 的内容会不会变化添加 PatchFlag,数据更新后,只对比带有PatchFlag的节点
<p>标签内容p>
<p>{{ msg }}p> 

1.1.2 hoistStatic 静态提升

  • Vue2 中无论元素是否参与更新, 每次都会重新创建, 然后再渲染
  • Vue3 中对于不参与更新的元素, 会做静态提升, 只会被创建一次, 在渲染时直接复用即可

1.1.3 事件监听缓存

默认情况下 onClick 会被视为动态绑定, 所以每次都会去追踪它的变化,但是因为是同一个函数,所以没有追踪变化, 直接缓存起来复用即可

二、创建 Vue 3.0 工程

2.1 使用 vue-cli 创建

脚手架版本需在 4.5.0 版本以上

# 创建工程
vue create <project-name>

# 进入工程目录
cd <project-name>

# 运行
npm run serve

2.2 使用 vite 创建

官网:https://vitejs.cn/

优势:

  1. 极速的服务启动。开发环境下,无需打包操作,可快速的冷启动。
  2. 轻量快速的热重载(HMR)。
  3. 真正的按需编译,不用等待整个应用编译完成。
# 创建工程
npm init vite-app <project-name>

# 进入工程目录
cd <project-name>

# 安装依赖
npm install

# 运行
npm run dev

三、全局 API

3.1 createApp

返回一个提供应用上下文的应用实例。应用实例挂载的整个组件树共享同一个上下文。

import { createApp } from 'vue'
import App from './App.vue'

createApp(App).mount('#app')

参数

支持两个参数

  1. 组件选项对象作为第一个参数

  2. 可以将根 prop 传递给应用程序

    const app = createApp(
      {
        props: ['username']
      },
      { username: 'Evan' }
    )
    
    <div id="app">
      
      {{ username }}
    div>
    

3.2 h

返回一个“虚拟节点(VNode

参数

接收三个参数:typepropschildren

  1. type

    • 类型:String | Object | Function
    • 详细:HTML 标签名、组件、异步组件或函数式组件。使用返回 null 的函数将渲染一个注释。此参数是必需的。
  2. props

    • 类型:Object
    • 详细:一个对象,与我们将在模板中使用的 attribute、prop 和事件相对应。可选。
  3. children

    • 类型:String | Array
    • 详细:子代 VNode,使用 h() 生成,或者使用字符串来获取“文本 VNode”,或带有插槽的对象。可选。
render() {
  return h('div', {}, [
    'Some text comes first.',
    h('h1', 'A headline')
  ])
}

<div>
  Some text comes first.
  <h1>A headlineh1>
div>

3.3 defineAsyncComponent

创建一个只有在需要时才会加载的异步组件。详细参考

3.4 nextTick

将回调推迟到下一个 DOM 更新周期之后执行。在更改了一些数据以等待 DOM 更新后立即使用它。

import { createApp, nextTick } from 'vue'

const app = createApp({
  setup() {
    const message = ref('Hello!')
    const changeMessage = async newMessage => {
      message.value = newMessage
      await nextTick()
      console.log('Now DOM is updated')
    }
  }
})

3.5 mergeProps

合并 prop,后面参数的 property 优先。



import { mergeProps } from 'vue'
setup(props, ctx) {
  const mergeProperty  = mergeProps(
    {
      // 该 class 将与 $attrs 中的其他 class 合并。
      class: 'active'
    },
    ctx.attrs,
    { b: 3 }
  )
  console.log(mergeProperty) // {class: "active", a: "1", b: 3}
}

3.6 useCssModule

允许在 setup的单文件组件函数中访问 CSS 模块。

WARNING

useCssModule 只能在 rendersetup 函数中使用。

姓名:张三

3.7 getCurrentInstance

getCurrentInstance 支持访问内部组件实例。

WARNING

getCurrentInstance 只能setup生命周期钩子中调用。

import { getCurrentInstance } from 'vue'

const MyComponent = {
  setup() {
    const internalInstance = getCurrentInstance()

    internalInstance.appContext.config.globalProperties // 访问 globalProperties
  }
}

四、组合式 API(Composition API)

4.1 setup

  • 组合API的入口函数, 在组件被创建之前props 被解析之后执行 。主要是实现数据和业务逻辑不分离
  • 无法使用 datamethods ,所以为了避免错误使用,直接将内部的 this 改成了 undefined
  • 内部的方法只能是同步,不能是异步

4.1.1 两种返回值

  1. 返回对象。属性、方法均可以在模板中直接使用(重点)

    setup() {
      let name = '张三'
      let age = 18
      function alertAge() {
        alert(age)
      }
      return {
        name,
        age,
        alertAge
      }
    }
    
  2. 返回一个渲染函数。可以自定义渲染内容(了解)

// App.vue
import { h } from 'vue'
export default {
  name: 'App',
  setup() {
    return () => h('h1', { a: 1 }, 'h函数自定义内容')
  }
}

<h1 a="1">h函数自定义内容h1>

4.1.2 入参

  1. props

    值为对象。包含:组件外部传递过来,且组件内部声明接收了的属性。

    // 父组件
    <Demo name="张三" :age="18" />
    
    // Demo 组件
    export default {  
      props: ['name', 'age'],  
      setup(props) {    
        console.log(props)  // Proxy { name: "张三", age: 18 }  
      }
    }
    
  2. context

    上下文对象

    • attrs :值为对象。包含:组件外部传递过来,但没有在 props 配置中声明的属性,相当于 this.$attrs

    • slots :收到的插槽内容,相当于 this.$slots

    • emit :分发自定义事件的函数,相当于this.$emit。区别是需要在 emits 选项中配置。

    • expose :将 property 暴露给外部访问,比如通过父组件的 ref,可以使用 expose 。此时组件内部不能使用

      // app.vue
      <com-a ref="compa" />    
      export default {  
        setup() {
          const compa = ref(null) 
          onMounted(() => { // 使用子组件方法   
            compa.value.setObservedA(2)  
          })  
          return {   
            compa  
          } 
        }
      }
      // comp-a.vue
      export default { 
        setup(props, { expose }) {  
          const observed = reactive({  
            a: 1  
          })    
          function setObservedA(value) {      
            observed.a = value    
          }    
          expose({ // 将 setObservedA 方法暴露给外部访问      
            setObservedA  
          })    
          return { // 组件内部现在不能使用 setObservedA 方法,因为没有 return 出去      
            observed
          } 
        }
      }
      

4.1.3 总结

  1. 尽量不要与 Vue 2.x 配置混用
    • Vue 2.x 配置(data、methods、computed…)中可以访问到 setup 中的属性、方法。
    • setup 中不能访问到 Vue 2.x 配置(data、methods、computed…)
    • 如果有重名,setup 优先
  2. 同步引入的组件 setup 不能是 async 函数,因为返回值不再是 return 的对象,而是 promise。模板看不到 return 对象中的属性
  3. setup 使用 async 函数或者返回值是一个 promise,需要 Suspense 异步组件配合

4.2 Provide / Inject

作用:实现祖孙间组件通信

实现:父组件有一个 provide 选项提供数据,子组件有一个 inject 选项接收数据

// 祖组件
import { provide, ref } from 'vue'

setup() {
  const count = ref(0)
  provide('count', count)
}

// 子组件
import { inject } from 'vue'

setup() {
  const count = inject('count')
}

五、响应性 API

5.1 响应性基础 API

5.1.1 reactive

作用:定义一个对象类型响应式的数据(基本类型别用,用 ref 函数)

备注:

  • 定义的响应式数据是‘深层次的’
  • 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据都是响应式的

<div>工作:{{ job.type }}div>
<button @click="jobChange">修改工作button>
import { reactive } from 'vue'
setup() {
  const job = reactive({
    type: '前端',
    salary: '60K'
  })
  function jobChange() {
    job.type = '后端'
  }
  return {
    job,
    jobChange
  }
}

重要:

当将 ref 分配给 reactive property 时,ref 将被自动解包。

const count = ref(1)
const obj = reactive({})

obj.count = count

console.log(obj.count) // 1
console.log(obj.count === count.value) // true

5.1.2 shallowReactive

浅层次创建一个响应式对象,只有第一层属性是响应式

const state = shallowReactive({
  foo: 1,
  nested: {
    bar: 2
  }
})

// 改变 state 本身的性质是响应式的
state.foo++
// ...但是不转换嵌套对象
isReactive(state.nested) // false
state.nested.bar++ // 非响应式

5.1.3 readonly

让一个响应式数据变为只读的(深层次)

5.1.4 shallowReadonly

让一个响应式数据变为只读的(浅层次),响应式对象第一层数据不可修改

5.1.5 toRaw

返回 reactivereadonly 代理的原始对象。对 ref 的数据无效

const foo = {}
const reactiveFoo = reactive(foo)

console.log(toRaw(reactiveFoo) === foo) // true

5.1.6 makeRaw

标记一个对象,使其永远不会转换为 proxy。返回对象本身。

const person = reactive({
  name: '张三',
  age: 18
})
// person.car 不再是响应式
person.car = makeRaw({})

5.2 Refs

5.2.1 ref

作用:定义一个响应式的数据

备注:

  • 接受的数据可以是基本类型,也可以是复杂类型
  • 基本类型的数据:响应式依然是靠Object.definePropertygetset完成的
  • 复杂类型的数据:内部‘求助’了–reactive函数

<div>姓名:{{ name }}div>
<div>工作:{{ job.type }}div>
<ul>
  <li v-for="(item, index) in list" :key="index" @click="listChange(index)">{{ item }}li>
ul>
<button @click="nameChange">修改名字button>
<button @click="jobChange">修改工作button>
import { ref } from 'vue'
setup() {
  // 创建 ref 对象
  const name = ref('张三') // -- 基本类型
  const job = ref({ // -- 对象类型
    type: '前端',
    salary: '60K'
  })
  const list = ref([1, 2, 3]) // -- 数组类型
  
  // 修改 ref 对象
  function nameChange() {
    name.value = '李四'
  }
  function jobChange() {
    job.value.type = '后端'
  }
  function listChange(index) {
    list.value[index] = list.value[index] + 1
  }
  return {
    name,
    job,
    list,
    nameChange,
    jobChange,
    listChange
  }
}

获取DOM

<com-a ref="coma" />
const coma = ref(null)
onMounted(() => {
  console.log(coma.value.$el) // 组件 Dom
})

return {
  coma
}

5.2.2 unref

如果参数是一个 ref,则返回内部值,否则返回参数本身。这是 val = isRef(val) ? val.value : val 的语法糖函数。

function useFoo(x: number | Ref<number>) {
  const unwrapped = unref(x) // unwrapped 现在一定是数字类型
}

5.2.3 toRef

为源响应式对象上的某个 property 新创建一个 ref。它会保持对其源 property 的响应式连接。

const state = reactive({
  foo: 1,
  bar: 2
})

const fooRef = toRef(state, 'foo')

fooRef.value++
console.log(state.foo) // 2

state.foo++
console.log(fooRef.value) // 3

5.2.4 toRefs

为源响应式对象上的所有 property 新创建一个 ref。它会保持对其源 property 的响应式连接。


<div>姓名:{{ firstName + lastName }}div>
<div>薪资:{{ job.salary }}div>
const person = reactive({
  firstName: '张',
  lastName: '三',
  job: {
    salary: '20K'
  }
})

return { ...toRefs(person) }

5.2.5 shallowRef

浅层次创建 ref 对象,创建基本数据类型时与 ref 无区别,创建对象类型时直接改变属性值不再是响应式,必须要替换源值

let x = shallowRef({
  y: 0
})
x.value.y++ // 值改变,但页面不渲染

const flag = x.value.y === 0 // 直接替换,页面渲染
if (flag) {
  x.value = { y: 1 }
} else {
  x.value = { y: 0 }
}

5.2.6 customRef

创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。参考链接

5.2.7 triggerRef

手动执行与 shallowRef关联的任何作用 (effect)。

const shallow = shallowRef({
  greet: 'Hello, world'
})

// 第一次运行时记录一次 "Hello, world"
watchEffect(() => {
  console.log(shallow.value.greet)
})

// 这不会触发作用 (effect),因为 ref 是浅层的
shallow.value.greet = 'Hello, universe'

// 记录 "Hello, universe"
triggerRef(shallow)

5.3 Computed 与 watch

5.3.1 Computed

里面不能用异步代码(不推荐),但是能执行

import { reactive, computed  } from 'vue'
const person = reactive({
  firstName: '张',
  lastName: '三'
})

person.fullName = computed(() => person.firstName + '-' + person.lastName)
console.log(person.fullName) // 张-三

接受一个具有 getset 函数的对象,用来创建可写的 ref 对象

const count = ref(1)
const plusOne = computed({
  get: () => count.value + 1,
  set: val => {
    count.value = val - 1
  }
})

plusOne.value = 1
console.log(count.value) // 0

5.3.2 watch

侦听 ref 定义的数据

单一源

import { ref, watch } from 'vue'

let count = ref(0)
watch(count, (newVal, oldVal) => {
  console.log(newVal, oldVal) // 0 undefined
}, {
  immediate: true
})

多个源

import { ref, watch } from 'vue'

let count = ref(0)
let name = ref('李四')
watch([count, name], (newVals, oldVals) => {
  console.log(newVals, oldVals) // [0, "李四"] []
}, {
  immediate: true
})

侦听 reactive 定义的数据

**注意:**直接侦听 reactive 定义的数据时,oldValue 会无法获取,deep 默认开启

单一源

const person = reactive({
  firstName: '张'
})

watch(
  () => person.firstName,
  (newVal, oldVal) => {
    console.log(newVal, oldVal) // 张 undefined
  },
  {
    immediate: true
  }
)

多个源

const person = reactive({
  firstName: '张',
  lastName: '三'
})

watch(
  [() => person.firstName, () => person.lastName],
  (newVal, oldVal) => {
    console.log(newVal, oldVal) // ["张", "三"] []
  },
  {
    immediate: true
  }
)

深度侦听

const person = reactive({
  job: {
    salary: '20K'
  }
})
// 这种方式依旧无法获取 oldVal
watch(
  () => person.job,
  (newVal, oldVal) => {
    console.log(newVal, oldVal)
  },
  {
    deep: true
  }
)
// 这种方式就能正确获取
watch(
  () => person.job.salary,
  (newVal, oldVal) => {
    console.log(newVal, oldVal)
  }
)

停止侦听

let count = ref(0)
const stop = watch(
  count,
  (newVal, oldVal) => {
    if (newVal === 1) { // 当 count 为 1 时,移除侦听器。但依旧会执行一次下面的代码
      stop()
    }
    console.log(newVal, oldVal) // 1 0
    setTimeout(() => {
      console.log(111) // 111
    }, 1000)
  }
)

5.3.3 watchEffect

不用指定侦听哪个属性,回调中用到了哪个就侦听哪个,默认先执行一次

let count = ref(0)
// 当count发生改变时触发
watchEffect(() => {
  console.log(count.value) // 0
})

停止侦听

let count = ref(0)
// 当count发生改变时触发
const stop = watchEffect(() => {
  console.log(count.value) // 0
  if (count.value === 1) {
    stop()
  }
})

onInvalidate 函数作入参,解决初次就执行的问题

  • 回调即将重新执行时
  • 侦听器被停止 (如果在 setup() 或生命周期钩子函数中使用了 watchEffect,则在组件卸载时)
let count = ref(0)
watchEffect(onInvalidate => {
  onInvalidate(() => {
    console.log('-----', count.value)
  })
})

5.3.4 Effect 作用域 API

  1. effectScope

    创建一个 effect 作用域对象,以捕获在其内部创建的响应式 effect (例如计算属性或侦听器),使得这些 effect 可以一起被处理。

import { reactive, effectScope, watch } from 'vue'

const job = reactive({
  type: '前端',
  salary: '60K'
})
const scope = effectScope()
scope.run(() => {
  watch(() => job.type, newVal => {
    console.log(newVal)
  })
  watch(() => job.salary, newVal => {
    console.log(newVal)
  })
})

function jobChange() {
  job.type = '后端'
  // 处理该作用域内的所有 effect
  scope.stop()
}
  1. getCurrentScope

    返回当前活跃的 effect 作用域。

  2. onScopeDispose

    在当前活跃的 effect 作用域上注册一个处理回调。该回调会在相关的 effect 作用域结束之后被调用。

import { reactive, effectScope, watch, onScopeDispose } from 'vue'

const job = reactive({
  type: '前端',
  salary: '60K'
})
const scope = effectScope()
scope.run(() => {
  watch(() => job.type, newVal => {
    console.log(newVal)
  })
  onScopeDispose(() => {
    console.log('调用 scope.stop() 执行')
  })
})

5.4 检测类型 API

5.4.1 isRef

检查值是否为一个 ref 对象。

const count = ref(0)
const name = '张三'

console.log(isRef(count), isRef(name)) // true false

5.4.2 isProxy

检查对象是否是由 reactivereadonly 创建的 proxy。

5.4.3 isReactive

检查对象是否是由 reactive 创建的响应式代理。

5.4.3 isReadonly

检查对象是否是由 readonly 创建的只读代理。

5.4.4 reactive 和 ref 的对比

  1. 定义角度
    • ref 用来定义基本类型数据,reactive 用来定义复杂类型数据
    • 注意:ref 也可以定义复杂类型数据,但内部会自动通过 reactive 转为代理对象
  2. 原理角度
    • ref 通过 Object.defineProperty 的 get 与 set 来实现
    • reactive 通过使用 Proxy 来实现,并通过 Reflect 操作源对象内部的数据
  3. 使用角度
    • Vue在解析数据之前,会通过当前数据的__v_ref这个私有属性判断这个数据是否是 ref 类型,如果值为true就是一个 ref 类型的数据
    • ref 定义的数据:操作数据需要.value,模板中读取数据自动添加.value
    • reactive 定义的数据:操作数据和模板中读取数据均不用添加.value

六、选项

6.1 emits

类型:Array | Object

详细:emits 可以是数组或对象,从组件触发自定义事件,emits 可以是简单的数组,也可以是对象,后者允许配置事件验证。

详细参考

6.2 expose

类型: Array

详细:一个将暴露在公共组件实例上的 property 列表。

用法:

export default {
  // increment 将被暴露,
  // 但 count 只能被内部访问
  expose: ['increment'],

  data() {
    return {
      count: 0
    }
  },

  methods: {
    increment() {
      this.count++
    }
  }
}

七、新的组件

7.1 Fragment

  • 在 Vue 2 中:组件必须有个根标签
  • 在 Vue 3 中:组件可以没有根标签,内部会包在一个 Fragment 虚拟元素中
  • 好处:减少标签层级,减小内存占用

7.2 Teleport

将组件 HTML 结构传送到指定位置

  1. to-string。移动 内容的目标元素
<teleport to="body">
  <div>我的结构在 body 标签下div>
teleport>
  1. disabled - boolean。此可选属性可用于禁用 的功能,这意味着其插槽内容将不会移动到任何位置,而是在你在周围父组件中指定了 的位置渲染。
<teleport to="#popup" :disabled="displayVideoInline">
  <video src="./my-movie.mp4">
teleport>

7.3 Suspense

等待异步组件时渲染一些额外内容,让应用有更好的用户体验


<template>
  <Suspense>
    <template #default>
      <Child />
    template>
    <template #fallback>
      <h3>加载中h3>
    template>
  Suspense> 
template>

<script>
  import { defineAsyncComponent } from 'vue'
  import Child from defineAsyncComponent(() => import('./child'))
script>
// child 组件
async setup() {
  const p = new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(0)
    }, 3000)
  })
  return await p
}

八、Vue Router

8.1 安装

npm install vue-router@4
// main.js
import { createApp } from 'vue'
import router from '@/router'
import App from './App.vue'

const app = createApp(App)
app.use(router)
app.mount('#app')

8.2 router-link

8.2.1 Props

  1. to

    目标路由的链接。当被点击后,内部会立刻把 to 的值传到 router.push()


<router-link to="/home">Homerouter-link>

<a href="/home">Homea>
  1. replace

    设置 replace 属性的话,当点击时,会调用 router.replace()

  2. active-class

    • 类型string

    • 默认值"router-link-active" (或者全局 linkActiveClass)

    • 详细内容

      链接激活时,应用于渲染的 的 class。

  3. exact-active-class

  4. custom

8.2.2 v-slot

注意

记得把 custom 配置传递给 ,以防止它将内容包裹在 元素内。

提示

如果你在 a 元素上添加一个 target="_blank",必须省略 @click="navigate" 的处理。

<router-link
  to="/foo"
  custom
  v-slot="{ href, route, navigate, isActive, isExactActive }"
>
  <li
    :class="[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']"
  >
    <a :href="href" @click="navigate">{{ route.fullPath }}a>
  li>
router-link>

渲染成

  • /foo
  • 8.2.3 404 路由

    import NotFound from '@/views/NotFound'
    
    const routes = [
      {
        path: '/:path(.*)',
        component: NotFound
      }
    ]
    

    8.3 API 参考

    8.3.1 START_LOCATION

    路由所在的初始路由地址。可用于导航守卫中,以区分初始导航。

    import { START_LOCATION } from 'vue-router'
    
    router.beforeEach((to, from) => {
      if (from === START_LOCATION) {
        // 初始导航
      }
    })
    

    8.3.2 useRoute

    返回当前路由地址。相当于在模板中使用 $route。必须在 setup() 中调用。

    8.3.3 useRouter

    返回 router 实例。相当于在模板中使用 $router。必须在 setup() 中调用。

    import { useRouter, useRoute } from 'vue-router'
    
    export default {
      setup() {
        const router = useRouter()
        const route = useRoute()
    
        function pushWithQuery(query) {
          router.push({
            name: 'search',
            query: {
              ...route.query
            }
          })
        }
      }
    }
    

    8.3.4 RouterLink

    使用 标签

    import { RouterLink } from 'vue-router'
    

    8.3.5 createRouter

    Vue Router 不再是一个类,而是一组函数。不用再写 new Router(),而是要调用 createRouter

    import { createRouter } from 'vue-router'
    
    const router = createRouter({
      // ...
    })
    

    8.4 Router 方法

    8.4.1 addRoute

    添加一条新的路由记录到路由。如果路由有一个 name,并且已经有一个与之名字相同的路由,它会先删除之前的路由。

    router.addRoute({ path: '/about', component: About })
    // 我们也可以使用 this.$route 或 route = useRoute() (在 setup 中)
    router.replace(router.currentRoute.value.fullPath)
    

    8.4.2 getRoutes

    获取所有 路由记录的完整列表。

    8.4.3 hasRoute

    确认是否存在指定名称的路由。

    函数签名:

    hasRoute(name: string | symbol): boolean
    

    8.4.4 removeRoute

    通过名称删除现有路由。

    通过名称删除现有路由。

    函数签名:

    removeRoute(name: string | symbol): void
    

    8.5 createRouter 配置项

    8.5.1 history

    路由模式

    • "history": createWebHistory()
    • "hash": createWebHashHistory()
    • "abstract": createMemoryHistory()

    8.5.2 routes

    应该添加到路由的初始路由列表。

    8.5.3 scrollBehavior

    在页面之间导航时控制滚动的函数。可以返回一个 Promise 来延迟滚动。有关更多详细信息,请参见滚动行为。

    九、Vuex

    9.1 安装

    npm install vuex@next --save
    
    // main.js
    import { createApp } from 'vue'
    import store from '@/store'
    import App from './App.vue'
    
    const app = createApp(App)
    app.use(store)
    app.mount('#app')
    

    9.2 API

    9.2.1 useStore

    调用 useStore 函数,与在组件中使用选项式 API 访问 this.$store 是等效的。

    import { useStore } from 'vuex'
    
    export default {
      setup () {
        const store = useStore()
      }
    }
    

    访问:

    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),
          
          // 使用 mutation
          increment: () => store.commit('increment'),
    
          // 使用 action
          asyncIncrement: () => store.dispatch('asyncIncrement')
        }
      }
    }
    

    9.2.2 createStore

    创建一个 store 实例。

    import { createStore } from 'vuex'
    
    const store = createStore({ ...options })
    

    你可能感兴趣的:(#,Vue3,学习,vue.js,前端,前端框架)