vue 使用 @vue/reactivity 实现全局状态管理

428 阅读2分钟

使用场景

比如,后台管理类的项目;

常见的功能就是表格的增删改查, 里边有很多重复的逻辑代码;

是否可以用es6的class把公共功能提取封装,页面中store用继承方式减少重复代码;

兼容版本

  • vue2.7以上
  • vue3

示例代码

1、简单示例

  • view/demo/store/index.js
import { computed, ref } from "vue";

class Store {
  /* 响应式数据 */
  num = ref(0)

  /* 计算属性 */
  sum = computed(()=>{
    return this.num.value + 10
  })

  /* 函数,可改成异步函数 */
  addNum = () => {
    this.num.value++
  }
  
}

/* 抛出单例,否则多组件不共享状态 */
export default new Store()
  • view/demo/index.vue
<template>
  <div @click="addNum">
    <p>{{ num }}</p>
    <p>{{ sum }}</p>
  </div>
</template>

<script setup>
import store from "./store"

/* 
  须把响应式数据解构出来,然后再绑定数据!
  不能在template里边用store.num 绑定,组件不刷新
*/
const { num, sum, addNum } = store
</script>

<style lang="less" scoped></style>

image.png

2、若有多个状态属于同一个功能点可以用reactive

  • view/demo/store/index.js
import {
  reactive,
} from "vue";

class Store {
  /* 若有多个状态属于同一个功能点可以用reactive */
  dataSource = reactive({
    list: [],
    cust: '6'
  })

  /* 改变当前选中项 */
  changeCust = (item) => {
    this.dataSource.cust = item.id;
  }

  /* 模拟请求 */
  getDataSource = () => {
    let arr = []

    for (let index = 1; index <= 10; index++) {
      arr.push({
        id: index + '',
        name: `你好${index}`
      })
    }

    this.dataSource.list = arr;

  }

}

/* 抛出单例,否则多组件不共享状态 */
export default new Store()
  • view/demo/index.vue
<template>
  <div class="demo-box">
    <ul>
      <li v-for="item in dataSource.list" :key="item.id" :class="`${dataSource.cust === item.id ? 'cust-sel' : ''}`"
        @click="changeCust(item)">
        {{ item.name }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { onMounted } from "vue"
import store from "./store"

const { dataSource, getDataSource, changeCust } = store

onMounted(getDataSource)
</script>

<style lang="less" scoped>
.cust-sel {
  background: red;
  color: #fff;
}
</style>

image.png

3、公共逻辑封装、继承

  • src/store/base.js<父类>
import {
  reactive,
  ref
} from "vue"

class BaseStore {
  constructor(props){
    this.api = props.api;
  }

  /* 每模块接口可能不一样,存一个api */
  api = {}

  /* 表格 */
  tableData = reactive({
    search: {},
    list: [],
    pagination: {
      cust: 1,
      size: 20,
    }
  })

  /* 详情 */
  detailData = ref({})

  /* 查询 */
  onSearch = () => {
    let arr = []

    for (let index = 1; index <= 10; index++) {
      arr.push({
        id: index + '',
        name: `你好${index}`
      })
    }

    this.tableData.list = arr;
  }

  /* 新增 */
  onCreate = (item) => {
    /* 调用新增接口... */
  }

  /* 修改 */
  onEdit = (item) => {
    /* 调用修改接口... */
  }

  /* 删除 */
  onDelete = (ids) => {
    /* 调用删除接口... */
  }

  /* 其他公共方法或属性... */
}

/* 这里直接抛出类,子类要继承; 不要抛出单例 */
export default BaseStore
  • view/demo/store/index.js
import BaseStore from "@/store/base.js"

/* 继承父类功能 */
class Store extends BaseStore{
  constructor(){
    /* 初始化父类接口信息 */
    super({
      api: {
        search: {
          url: '/search',
          method: 'get'
        },
        create: {
          url: '/create',
          method: 'post'
        },
        edit: {
          url: '/edit',
          method: 'post'
        },
        delete: {
          url: '/delete',
          method: 'post'
        },
      }
    })
  }
}

/* 抛出单例,否则多组件不共享状态 */
export default new Store()
  • view/demo/index.vue
<template>
  <div class="demo-box">
    <ul>
      <li v-for="item in tableData.list" :key="item.id">
        {{ item.name }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { onMounted } from "vue"
import store from "./store"

const { tableData, onSearch } = store

onMounted(onSearch)
</script>

<style lang="less" scoped>
</style>

结语

  • 上边是使用reactive实现全局状态管理使用方法,包括开始提到的后台管理类代码提取继承;
  • 大家碰到类似项目有没有更好的实现方式?
  • 最后感谢尤大大开发这么好用的框架 orz