1、将一个模块挂载到全局,从而不用每次在页面中引入。
// 以使用axios为例
// 首先,我们需要安装axios
// 然后,在main.js中,将它设置为全局属性
// main.js
import { createApp } from 'vue'
import App from './App.vue'
import Axios from 'axios'
const app = createApp(App)
app.config.globalProperties.axios = Axios
app.mount('#app')
2、teleport
比如,我们正常写了div中嵌套了一个子元素span,渲染的结果也是span元素包裹在div中。这时候,如果我们希望渲染后,span元素是包裹在body元素中,而不是div中,我们就可以使用teleport。
Vue3.x中的组件模板属于该组件,有时候我们想把模板的内容移动到当前组件之外的DOM种,这个时候就可以使用teleport。
//span元素将挂载到body上面
<div>
<teleport to="body">
<span>子元素内容</span>
</teleport>
<div>
// to的值可以是一个元素的id
<div>
<teleport to="#app">
<span>子元素内容</span>
</teleport>
<div>
3、Composition API
composition API主要是为了解决代码维护比较复杂,复用性不高而生的。
在vue2.x中,我们定义响应式数据,就是写在data中,定义方法就是写在methods中,监听数据变化就用watch,而composition-api为我们提供了另一种书写方式来实现我们的目的。
composition-api提供了以下几个函数:
setup:- 我们所有的组合式api的代码都需要写在
setup这个方法当中
- 我们所有的组合式api的代码都需要写在
ref- 定义响应式数据的方法
- 主要用于定义String/Number/Boolean/Array数据
reactive- 定义响应式数据的方法
- 主要用于定义Object数据
watchEffectwatch- 这两个监听数据变化的方法和vue2中的
watch基本一样
- 这两个监听数据变化的方法和vue2中的
computed- 计算属性同vue2中的一样
toRefs- 主要是结构响应式对象数据的
- 生命周期的
hooks
(1) setup组件选项中定义响应式数据
import {ref, reactive} from 'vue'
export default {
setup () {
// ref定义响应式数据 string/number/boolean/array
// reactive 定义响应式数据 object
let title = ref('我是一个标题')
let userInfo = reactive({
username: '张三',
age: 20
})
// 这里必须return出去,模板中才能获取到响应式数据
return {
title,
userInfo
}
}
}
(2) setup组件选项中定义方法
import {ref, reactive} from 'vue'
export default {
setup () {
// ref定义响应式数据 string/number/boolean/array
// reactive 定义响应式数据 object
let title = ref('我是一个标题')
let userInfo = reactive({
username: '张三',
age: 20
})
// 获取ref里面定义的数据
let getTitle = () => {
// 这里不能直接获取title,获取到的结果是[object,object]
// 需要获取title.value,才能获取到具体的值
alert(title.value)
}
// 获取reactive里面定义的数据
let getUserName = () => {
alert(userInfo.username)
}
// 设置ref里面定义的数据
let setTitle = () => {
// 设置同样需要改变title.value的值
title.value = '我是改变的ref标题'
}
// 设置reactive里面定义的数据
let setUserName = () => {
userInfo.username = '李四'
}
// 这里必须return出去,模板中才能获取到响应式数据
return {
title,
userInfo,
getTitle,
getUserName,
setTitle,
setUserName
}
}
}
(3) setup组件选项中使用toRefs解构响应式对象数据
比如,我们在reactive中定义了一个对象userInfo,如果我们想在模板中获取userInfo的username和age,就只能通过userInfo.username和userInfo.age这种方式去获取。而toRefs可以让我们在模板中直接使用username和age来获取具体的数据。
<template>
<input v-model="title" type="text">
<input v-model="age" type="text">
</template>
import {ref, reactive, toRefs} from 'vue'
export default {
setup () {
let article = reactive({
title: '我是天下第一',
count: 200
})
// 获取reactive里面定义的数据
let getTitle = () => {
alert(article.title)
}
// 设置reactive里面定义的数据
let setTitle = () => {
article.title = '天下无敌'
}
// 这里必须return出去,模板中才能获取到响应式数据
// 方法一,使用三点运算符把article中的属性与当前对象进行合并,但是这种方法出来的属性不是响应式数据,当视图改变时,数据并没有改变。
return {
// article,
getTitle,
setTitle,
...article
}
// 方法二,使用`toRefs`来解构这个响应式对象,然后与当前`return`出的对象进行合并,这时候的属性还是响应式数据。
return {
// article,
getTitle,
setTitle,
...toRefs(article)
}
}
}
(4) setup组件选项中使用computed
<template>
<input v-model="firstName" type="text" placeholder="fistName">
<input v-model="lastName" type="text" placeholder="lastName">
{{fullName}}
</template>
import {reactive, toRefs, computed} from 'vue'
export default {
setup () {
let userinfo = reactive({
firstName: '',
lastName: ''
})
// 定义计算属性方法
let fullName = computed(() => {
// 这里不能使用this,直接使用我们定义的响应式数据
return userinfo.firstName + ' ' + userinfo.lastName
})
// 这里必须return出去,模板中才能获取到响应式数据
return {
fullName,
...toRefs(userinfo)
}
},
computed: {
// 这是模拟以前的写法,仅用于演示
// 要注意的是,以前的这种写法是不能获取到组合式API中定义的变量
fullName () {
return userinfo.firstName + ' ' + userinfo.lastName
}
}
}
(5) setup组件选项中使用readonly
readonly深层的只读代理
比如,我们有一个响应式数据,当我们改变视图时,数据也会相应的发生变化。这时候,如果我们想让这个响应式数据变成非响应式数据,也就是页面发生变化时,数据并不发生变化,我们可以使用readonly。
我们可以给readonly传入一个对象(响应式或普通)或者ref,这时会返回一个原始对象的只读代理。一个只读的代理是深层的,也就是对象内部任何嵌套的属性都是只读的。
<template>
<h3>原始对象</h3>
<input v-model="obj.username" type="text" placeholder="username">
<input v-model="lastName" type="text" placeholder="lastName">
</template>
import {reactive, readonly} from 'vue'
export default {
setup () {
// 定义了一个原始对象,它是一个非响应式数据
// 原始对象我们可以在页面中绑定它,但是没法在视图发生变化时,改变数据
let obj = {
username: '',
age: ''
}
// 响应式数据
let userinfo = reactive({
firstName: '',
lastName: ''
})
// 将一个响应式数据改为非响应式数据
userinfo = readonly(userinfo)
// 这里必须return出去,模板中才能获取到响应式数据
return {
obj,
...toRefs(userinfo)
}
}
}
(6) setup组件选项中使用watchEffect和watch实现监听
watchEffect和watch的区别:
watchEffect在第一次加载的时候,无论数据是否改变,都会执行一次。而watch是懒执行的,只会在数据改变时,才执行。watch可以明确要监听哪个数据变化watch可以获取变化前后的数据
使用watchEffect监听数据变化
import {reactive, toRefs, watchEffect} from 'vue'
export default {
setup () {
// 响应式数据
let data = reactive({
num: 1
})
let count = reactive({
num: 1
})
// 监听data变化
// 这里如果改变的是非data数据,比如是count,则不会发生变化
// watchEffect可以监听到reactive返回对象的某个属性变化,而watch则不行
watchEffect(() => {
console.log(`num=${data.num}`)
})
// 设置一个定时器,每隔1s钟加1
setInterval(() => {
data.num++
}, 1000)
return {
...toRefs(data)
}
}
}
使用watch监听数据变化
<template>
<input v-model="num" type="text" placeholder="num">
</template>
import {reactive, toRefs, watch} from 'vue'
export default {
setup () {
// 响应式数据
let data = reactive({
num: 1
})
// 监听data变化
// 第一个参数是我们要监听的数据,这个数据必须是reactive返回的这个对象,而不能是这个对象的某个属性。
// 第二个参数是回调函数,该函数的前两个参数分别是变化后的值和变化前的值。
watch(data, (newValue, oldValue) => {
console.log(`data.num=${data.num}`)
console.log(newValue, oldValue)
})
// 设置一个定时器,每隔1s钟加1
setInterval(() => {
data.num++
}, 1000)
return {
...toRefs(data)
}
}
}
(7) setup组件选项中使用生命周期函数
在组合式API中使用生命周期函数,需要在前面加上on
在组合式API中,没有beforeCreate和created这两个生命周期函数。因为setup就是在beforeCreate之前执行的。
import {reactive, watch, onMounted} from 'vue'
export default {
setup () {
// 这里的执行顺序分别是setup、beforecreate、onmounted
console.log('setup')
// 响应式数据
let userinfo = reactive({
firstName: '',
lastName: ''
})
onMounted(() => {
console.log('onmounted')
})
// 这里必须return出去,模板中才能获取到响应式数据
return {
obj,
...toRefs(userinfo)
}
},
beforeCreate () {
console.log('beforecreate')
}
}
(8) setup组件选项中使用props
import {reactive, watch, onMounted} from 'vue'
export default {
props: ['msg'], // 指定接受的props
setup (props) {
// setup的第一个参数,就是props
console.log(props)
}
}
(8) setup组件选项中使用provide和inject
provide和inject主要用于多层嵌套时,父级像子级传递数据时使用。
在Vue2中,在父组件中通过provide提供的的数据,并不是响应式数据。比如,父组件通过provide提供了一个title的数据,子组件引入title后绑定到模板中。当父组件改变title时,子组件中的title并不会发生改变。
在Vue3中,使用组合式API定义的provide提供的数据则是响应式数据,并且不同于props,子组件中改变数据的操作,也会影响父组件中数据的显示。比如,父组件通过provide提供了一个title的数据,子组件引入title后绑定到模板中。当父组件改变title时,子组件中的title会发生改变。同时,如果子组件中改变了title,父组件中的title也会发生改变。
// 父组件 parent.vue
import {ref, provide} from 'vue'
export default {
setup () {
let title = ref("app根组件里面的title")
// 这里是key/value的书写方式
provide('title', title)
return {
title
}
}
}
// 子组件 child.vue
import {ref, inject} from 'vue'
export default {
setup () {
// 引入组件中传入的数据
let title = inject('title')
return {
title
}
}
}
4、Vue中集成Typescript
这样,我们就可以在项目中使用typescript的语法了。
// 安装vue-cli
npm install -global @vue/cli
// 创建一个项目
vue create my-project-name
// 然后进入项目目录
cd my-project-name
// 在项目中添加typescript
vue add typescript
安装过程选择为否的内容:
class-styleskip type checking of all declaration files (recommend for apps) ?
(1) 在vue3中,选项式API与typescript一起使用
- 使用
typescript的前提
// 1、要指定`script`标签的语言类型
<script lang="ts">
// 2、引入defineComponent
import {defineComponent} from 'vue'
// 这里需要注意,使用ts的时候,引入组件的名称需要加上后缀
import Home from './components/Home.vue'
// 3、在暴露组件的时候,调用defineComponent这个方法,当我们在写具体的vue方法时,它会对我们写的内容进行校验。
export default defineComponent({
name: 'App',
data () {
return {
title: '文章标题'
}
},
components: {
Home
}
})
</script>
typescript的具体使用方式:
- 校验某个数据的类型
<script lang="ts">
// 指定title为一个string类型
let title:string = '我是一个Home组件'
import {defineComponent} from 'vue'
export default defineComponent({
name: 'App',
data () {
return {
title
}
},
methods: {
// 这里void表示我们调用这个方法时,没有任何的返回值
setTitle():void {
// 这里赋值必须是字符串类型,如果是其他类型,就有校验失败,出现提示
this.title = '改变后的home组件'
}
}
})
</script>
- 批量配置数据类型的方法
- 可以结合接口来实现
<script lang="ts">
// 1、定义一个接口,在这个接口里面指定所有数据的类型
// News是接口的名称
interface News {
title: string,
description: string,
count: number | string, // 指定多个数据类型
content?: string // 这是一个可选参数,也就是数据对象中可以没有这个数据
}
// 2、定义一个变量newsData实现我们上面定义的那个接口,也就是newsData里面的数据类型按照接口中的规则来定义。
// 在newsData中,title/description/count必须要定义,content是可选参数,所以可有可无
// 实现接口写法一
let newsData:News = {
title: '文章标题',
description: '我是文章描述',
count: 123
}
// 实现接口写法二
let newsData = {
title: '文章标题',
description: '我是文章描述',
count: 123
} as News
import {defineComponent} from 'vue'
export default defineComponent({
name: 'App',
data () {
return newsData
},
methods: {
// 这里表示要取这个方法返回一个字符串类型
reverseTitle():string {
return this.title.split('').reverse().join('')
}
}
})
</script>
- 方法的类型校验
- 批量配置数据类型的方法
- 可以结合接口来实现
<script lang="ts">
interface News {
title: string,
description: string,
count: number | string,
content?: string
}
let newsData:News = {
title: '文章标题',
description: '我是文章描述',
count: 123
}
import {defineComponent} from 'vue'
export default defineComponent({
name: 'App',
data () {
return newsData
},
methods: {
// 这里表示要取这个方法返回一个数字类型
// 这个方法的参数必须是一个数字类型
reverseTitle(count:number):number {
return this.count++
}
}
})
</script>
(2) 在vue3中,组合式API与typescript一起使用
reactive定义的数据方法实现类型校验
<script lang="ts">
// 1、定义一个接口
interface User {
username: string,
age: number,
setUsername(username:string): void, // 有一个字符串类型的参数,并且这个函数不返回任何结果
getUsername(): string // 这个函数返回一个字符串类型的结果
}
import {defineComponent, reactive, toRefs} from 'vue'
export default defineComponent({
setup () {
// 实现接口写法一
let user:User = reactive({
username: '张三',
age: 20,
setUsername(username) { // 我们也可以在reactive中定义方法
// 这里访问数据需要用this
this.username = username
},
getUsrname() {
return this.username
}
})
// 实现接口写法二
// reactive这个方法接口的参数是一个泛型,这个泛型继承了object,所以,我们也可以使用方法二实现接口
// 这里表示要对传入reactive的参数类型进行约束,规则就是我们接口指定的规则
// 这种方式并不是所有方法都可以使用的,必须看方法的参数类型,如果方法的参数类型是泛型,才可以使用这种方法实现接口
let user = reactive<User>({
username: '张三',
age: 20,
setUsername(username) { // 我们也可以在reactive中定义方法
// 这里访问数据需要用this
this.username = username
},
getUsrname() {
return this.username
}
})
// 实现接口写法三
let user = reactive({
username: '张三',
age: 20,
setUsername(username) { // 我们也可以在reactive中定义方法
// 这里访问数据需要用this
this.username = username
},
getUsrname() {
return this.username
}
}) as User
return {
...toRefs(user)
}
}
})
</script>
ref定义的数据方法实现类型校验
<script lang="ts">
import {defineComponent, ref} from 'vue'
export default defineComponent({
setup () {
// ref这个方法接口的参数是一个泛型,所以,我们也可以使用该方法二实现数据类型校
let count = ref<number | string>(20)
// 注意,如果我们用reactive方法一的方式指定类型的时候,会报错
// let num:string = ref(20)
return {
count
}
}
})
</script>
- 计算属性实现类型校验
<script lang="ts">
import {defineComponent, ref} from 'vue'
export default defineComponent({
setup () {
let count = ref<number | string>('张三')
// 表示这个计算属性必须返回一个字符串类型的值
let reverseUsername = computed(():string => {
return count.split('').reverse().join('')
})
return {
count,
reverseUsername
}
}
})
</script>
5、路由
路由可以让应用程序根据用户输入的不同地址动态挂载不同的组件。
(1)使用步骤:
- 1、安装路由模块
npm install vue-router --save
- 2、准备要挂载的组件
<template>
<div>user组件</div>
</template>
- 3、配置路由
新建一个routes.ts文件配置路由
import {createRouter, createWebHashHistory} from 'vue-router'
// 引入组件
import User from './components/User.vue'
// 配置路由表
let routes = [
{path: '/', component: User}
]
// 配置路由
const router = createRouter({
history: VueRouter.createWebHashHistory(),
routes
})
// 暴露router
export default router
- 4、挂载路由
在main.js中挂载路由
// main.js 入口文件
import {create} from 'vue'
import App from './App.vue'
import route from './routes'
let app = createApp(App)
// 挂载路由
app.use(route)
app.mount('#app')
- 5、渲染组件
在模板中通过router-view渲染组件,也就是指定显示组件的位置
<template>
<div>
// 动态切换路由
<ul>
<li>
<router-link to="/">首页</router-link>
</li>
<li>
<router-link to="/user">用户页</router-link>
</li>
</ul>
// 指定组件加载位置
<router-view></router-view>
</div>
</template>
(2)路由传值
- 方式一:动态路由传值
1、配置动态路由,在路由表中指定我们要传递的参数
const router = createRouter({
history: createWebHashHistory(),
routes: [
{path: '/newscontent/:id', component: NewsContent}
]
})
2、路由跳转
<div v-for="{item, index} in list" :key="index">
<router-link :to="`./newscontent/${index}`"></router-link>
</div>
3、获取路由传参
this.$route.params
- 方式二:GET传值
1、路由跳转
<router-link to="./newscontent?id=123"></router-link>
2、获取路由参数
this.$route.query
(3)路由编程式导航及传值
- 动态路由:
this.$router.push({
path: '/newscontent',
parrams: {
id: 123
}
})
- GET传值
this.$router.push({
path: '/newscontent',
query: {
id: 123
}
})
(4)路由HTML5 History模式和hash模式
改为hash模式的配置
默认配置为hash模式
import {createRouter, createWebHashHistory} from 'vue-router'
const router = createRouter({
history: createWebHashHistory(),
routes: [//...]
})
http://localhost:8080/#/user
hash模式的路径,默认自带/#,如果想把它去掉,变成下面的模式,则可以使用HTML5 History模式
http://localhost:8080/user
改为HTML5 History模式的设置
import {createRouter, createWebHistory} from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [//...]
})
注意:开启html5 history模式后,发布到服务器需要配置伪静态。
(5)命名路由
- 动态路由
1、配置路由表
const router = new VueRouter({
routes: [
{
path: '/user:userId',
name: 'user',
component: User
}
]
})
2、路由跳转
this.$router.push(name: 'user', params: {userId: 123})
- GET传值
1、配置路由表
const router = new VueRouter({
routes: [
{
path: '/user',
name: 'user',
component: User
}
]
})
2、路由跳转
this.$router.push(name: 'user', query: {userId: 123})
(6)路由重定向
路由重定向就是,在用户输入/a的路径时,我们会把把它替换为/b的路径,然后去匹配/b。
重定向也需要在routes配置中完成
const routes = [{path: '/', redirect: '/home'}]
重定向也可以针对命名路由
const routes = [{path: '/', redirect: {name: 'homepage'} }]
甚至使用函数进行动态重定向
const routes = [
{
path: '/search/:searchText',
redirect: to => {
return {path: '/search', query: {q: to.params.searchText}}
}
}
]
(7)路由别名
别名就是,当用户访问/a路径时,用户看到的路径不变变化,就是/a,但是,实际上匹配的是路径/b的内容
别名的配置方式和path的配置方式一样,就是一个路径。
const routes = [{path: '/home', component: homepage, alias: '/homeAlias'}]
配置多个别名
const routes = [
{path: '/home',
component: homepage,
alias: ['/homeAlias1', '/homeAlias2']}
]
动态路由别名传参
const routes = [{path: '/home', component: homepage, alias: '/homeAlias/:id'}]
(8)路由嵌套
const router = new VueRouter({
routes: [
{
path: '/user',
name: 'user',
component: User,
children: [
{path:'', redirect: '/user/userlist'},
{path: 'userlist', component: UserList},
{path: 'useradd', component: UserAdd}
]
}
]
})
6、Vue状态管理模式Vuex
Vuex是一个专门为vue.js应用程序开发的状态管理模式。
主要功能:
- 实现不同组件之间的状态共享
- 可以实现组件里面数据的持久化
实现数据缓存的几种方式:
localStoragekeep-alivevuex
vuex的几个概念
state:定义数据Getters:相当于计算属性Mutations:相当于方法Actions:触发mutaions里面的方法,可以写一些异步逻辑Modules:模块
(1)vuex使用步骤
- 1、安装
vuex
npm install vuex --save
- 2、
src目录下面新建一个vuex的文件夹,vuex文件夹里面新建一个store.js
import {createStore} from 'vuex'
const store = createStore({
state () {
return {
count: 1
}
},
getters: {
doneTodosCount (state) {
return state.msg.split('').reverse().join('')
}
},
mutations: {
increment (state) {
state.count++
}
}
})
export default store
- 3、
main.ts中挂载vuex
// main.js 入口文件
import {create} from 'vue'
import App from './App.vue'
import route from './routes'
import store from './vuex/store'
let app = createApp(App)
// 挂载路由
app.use(route)
// 挂载vuex
app.use(store)
app.mount('#app')
(2)将vuex中state数据渲染到页面
- 方法一:用到的组件里面引入
store,然后计算属性里面获取(不推荐)
computed: {
count () {
return store.state.count
}
}
- 方法二:由于全局配置了
Vuexapp.use(store),所以可以直接通过下面方法获取store里面的值
computed: {
count () {
return this.$store.state.count
}
}
- 方法三:通过
mapState助手
如果,当前页面需要使用的state数据量很大,我们可以通过mapState批量把state中的数据映射到当前页面
它的用法就是,在当前组件中的计算属性中,通过扩展运算符将mapState返回的对象与当前计算属性中的对象合并。
如果我们当前组件映射的数据名称和state中的数据名称一样,我们可以直接使用一个数组
computed: {
// 数组中的选项,就是state中数据的名称
...mapState([ 'count', 'list' ])
}
如果我们当前组件映射的数据名称和state中的数据名称不一样,我们可以直接使用一个对象
computed: {
// 传入的这个对象的属性名就是我们自己想要的变量名,后面则是state中映射的数据
...mapState({
myCount: state => state.count,
myList: state => state.list
})
}
(3)将vuex中getters渲染到页面
getters就相当于vuex中的计算属性,在页面中的引入方式和state一样。
- 方法一:(不推荐)
computed: {
count () {
return store.getters.doneTodosCount
}
}
- 方法二:
computed: {
count () {
return this.$store.getters.doneTodosCount
}
}
- 方法三:通过
mapGetters助手
如果我们当前组件映射的数据名称和mapGetters中的数据名称一样,我们可以直接使用一个数组
computed: {
// 数组中的选项,就是state中数据的名称
...mapGetters([ 'doneTodosCount' ])
}
如果我们当前组件映射的数据名称和mapGetters中的数据名称不一样,我们可以直接使用一个对象
computed: {
...mapGetters({
myDoneCount: 'doneTodosCount'
})
}
(4)改变vuex中state的数据(Mutations使用)
- 首先,在
store.js中定义一个改变state的方法,这个方法里面有具体的逻辑处理。
import {createStore} from 'vuex'
const store = createStore({
state () {
return {
count: 1
}
},
// 用于保存改变state的所有方法
mutations: {
// 方法的第一个参数就是state
increment (state) {
state.count++
}
}
})
export default store
- 然后,在页面中触发
mutations中某个具体的方法
export default {
methods: {
inCount () {
// 触发mutations中的某个方法
this.$store.commit('increment')
}
}
}
触发mutations中方法时传参
// store.js
import {createStore} from 'vuex'
const store = createStore({
state () {
return {
count: 1
}
},
mutations: {
setCount (state, num) {
state.count = num
}
}
})
export default store
// home.vue
export default {
methods: {
inCount () {
this.$store.commit('setCount', 123)
}
}
}
(5)改变vuex中state的数据(Actions使用)
mutations主要写一些改变state的方法,这些方法可以是一些异步方法,比如,写一个定时器,过了1s钟,让数字加一,这种需求可以实现。但是,当我们想要在mutations某个方法中调用其他mutations的方法时,这时候就不行了,mutations不支持这种操作。
而actions则没有这种问题,它可以执行mutations中多个不同的方法。在actions中我们可以写一些异步操作。当然,我们也可以把这些异步处理逻辑写在页面中,然后在页面中触发不同的mutations方法。
- 首先,在
store.js中定义一个改变state的方法,这个方法里面有具体的逻辑处理。
import {createStore} from 'vuex'
const store = createStore({
state () {
return {
count: 1
}
},
// 用于保存改变state的所有方法
mutations: {
// 方法的第一个参数就是state
increment (state, msg) {
state.count = msg
}
},
actions: {
inCount (context, msg) {
// 当这里的异步方法成功或失败时,我们可以执行不同的mutations方法
setTimeout(() => {
context.commit('increment', msg) // 执行mutations中方法
}, 1000)
}
}
})
export default store
- 然后,在页面中触发
actions中某个具体的方法
export default {
methods: {
inCount () {
// 触发actions中的某个方法
this.$store.dispatch('inCount', 123)
}
}
}
(5)vuex中Modules使用
当数据量特别大时,所有的数据方法都集中在stote.js中,store对象可能会变得很臃肿。Vuex允许我们将store分割成模块,每个模块都有自己的state/mutations/action/getter,甚至是嵌套子模块,从上到下进行同样方式的分隔。
// moduleA
const moduleA = {
state: () => ({...}),
mutations: () => ({...}),
actions: () => ({...}),
getters: () => ({...}),
}
export default moduleA
// moduleB
const moduleB = {
state: () => ({...}),
mutations: () => ({...}),
actions: () => ({...}),
getters: () => ({...}),
}
export default moduleB
// store.js
import moudleA from './moduleA'
import moduleB from './moduleB'
const store = createStore({
modules: {
a: moduleA,
b: moduleB
}
})
export default store
在页面中使用子模块中的数据
<template>
// 获取a模块中的count,这里在state后面需要加上子模块的名称
<div>{{$store.state.a.count}}</div>
</template>
在页面中使用子模块中的方法
export default {
methods: {
inCount () {
// 这里调用时候,就不在需要加上子模块的名称了
// 需要注意,两个子模块如果有一样的名称,两个方法会同时触发,所以应该避免两个子模块中的方法名一样
this.$store.commit('increment')
}
}
}
(6)vuex结合Composition API
import {computed, defineComponent} from 'vue'
// 1.引入useStore
import {useStore} from 'vuex'
export default defineComponent({
setup() {
// 2.获取store对象
const store = useStore()
return {
count: computed(() => {
return store.state.count
}), // 获取state数据
num: computed(() => {
return store.getters.num
}), // 获取getters
inCount: () => {
store.commit('inCount')
}, // 触发mutations方法
inActionCount: () => {
store.dispach('setCount', 123)
}
}
}
})
(6)vue结合TS的项目中使用vuex
使用步骤
- 1、安装
vuex
npm install vuex --save
- 2、
src目录下面新建一个vuex的文件夹,vuex文件夹里面新建一个store.ts
import {ComponentCustomProperties} from 'vue'
import {createStore, Store} from 'vuex'
// 配置vue+ts的项目里面使用vuex
// 这是个固定写法
declare module '@vue/runtime-core' {
// 声明接口,指定state中数据的类型
interface State {
count: number, // 数字类型
list: string[], // string类型数组
msg: string
}
interface ComponentCustomProperties {
$store: Store<State>
}
}
const store = createStore({
state () {
return {
count: 1,
msg: '你好 vue',
list: ['张总', '王总']
}
},
getters: { // 计算属性
// 这里需要为state指定any类型,否则会有警告提示,并且它找不到state下面的msg
doneTodosCount (state:any) {
return state.msg.split('').reverse().join('')
}
},
mutations: { // 方法
inCount (state:any) {
state.count++
},
setCount(state:any, num:number) {
state.count = num
},
setMsg (state:any, msg:string) {
state.msg = msg
}
}
})
export default store
- 3、
main.ts中挂载vuex
// main.js 入口文件
import {create} from 'vue'
import App from './App.vue'
import route from './routes'
import store from './vuex/store'
let app = createApp(App)
// 挂载路由
app.use(route)
// 挂载vuex
app.use(store)
app.mount('#app')
组件中使用TS
有时,我们在集成ts以后,在组件里面使用this.$store的时候可能会出现警告信息,这时候我们可以安装一个vue3 snipts的插件,然后在重启vscode就可以了。
- 选项式API
// 声明语言类型为ts
<script lang="ts">
import {mapState} from 'vuex'
export default {
computed: {
// 因为这里对state做了映射,它不知道state的数据类型,所以这里需要指定state为any类型,否则会报错
...mapState({
num: (state:any) => state.count
})
},
methods: {
// 当前函数没有任何返回值
inCount():void {
this.$store.commit('inCount')
}
}
}
</script>
- 组合式API
// 声明语言类型为ts
<script lang="ts">
import {defineComponent} from 'vue'
import {useStore} from 'vuex'
export default defineComponent({
setup() {
const store = useStore()
return {
msg: computed(() => {
store.state.msg
}),
count: computed(() => {
store.state.count
}),
setMsg: ():void => {
store.commit('setMsg', '组合式API里面改变后的数据')
}
}
}
})
</script>