《全局数据管理》

338 阅读3分钟

记账页面和标签页面都可以新增标签。可是现在有一个bug。在标签页面新增标签之后,在记账页面不会自动同步,要刷新一下才能同步。

这是因为这两个页面的数据tagList都是分别从tagListModel里fetch的。所以就导致了数据不同步。

解决方案:在更高一层的地方统一去tagListModel里fetch一次,把取出来的设成一个全局的属性,然后分别在两个页面直接使用。

我们选择在main.ts入口文件里声明这个全局属性:

window.tagList=tagListModel.fetch()

可是这样会报错,说window里没有这样一个属性。

那么我们就只能在custom.d.ts里自定义声明window里有这样一个属性。

interface Window  {
    tagList: Tag[]
}

这样再回到main.ts,就没有报错了。

然后就可以在两个页面直接使用。

在Money.vue:

export default class Money extends Vue{
        tags=window.tagList
}

在Labels.vue:

export default class Labels extends Vue {
        tags=window.tagList
}

这样就没有那个bug了。在标签页面新增一个标签后,在记账页面也会自动同步。

把数据放到window上以后,读取数据就是通过window操作的。但是写数据,比如删除,增加,修改标签,还是通过tagListModel这个对象的API操作的。

那么为了看起来一致,我们最好把这些API也封装到window上。

//main.ts
//record store
window.recordList=recordListModel.fetch()
window.createRecord=(record: RecordItem)=>{
  recordListModel.create(record)
}

// tag store
window.tagList=tagListModel.fetch()
window.createTag=(name: string)=>{
  const message=tagListModel.create(name)
  if(message==='duplicated'){
    window.alert('标签名重复')
  }else{window.alert('添加成功')}
}
window.removeTag=(id: string)=>{
  tagListModel.remove(id)
}
window.updateTag=(id: string,newName: string)=>{
  return tagListModel.update(id,newName)
}
window.findTag=(id: string)=>{
  return window.tagList.filter(tag=>tag.id===id)[0]
}

把recordListModel,tagListModel上的属性,方法都封装到window上以后,有一个问题。1. window上的变量太多了。2. 太依赖window了,如果在不支持window的情况下,就无法操作。

解决办法: 不要window,把这些API都封装到一个store对象上。在store目录里新建一个index2.ts

const store={
    //record store
    recordList: recordListModel.fetch(),
    createRecord: (record: RecordItem) => {
        recordListModel.create(record);
    },

    // tag store
    tagList: tagListModel.fetch(),
    createTag: (name: string) => {
        const message = tagListModel.create(name);
        if (message === 'duplicated') {
            window.alert('标签名重复');
        } else {
            window.alert('添加成功');
        }
    },
    removeTag: (id: string) => {
        tagListModel.remove(id);
    },
    updateTag: (id: string, newName: string) => {
        return tagListModel.update(id, newName);
    },
    findTag: (id: string) => {
        return store.tagList.filter(tag => tag.id === id)[0];
    }
}

export default store;

以后操作数据就全部调用store

可是这样store对象里有两种数据的操作,我们最好还是把他们分开:

import recordStore from '@/store/recordStore';
import tagStore from '@/store/tagStore';

const store={
    ...recordStore,
    ...tagStore
}

export default store;

分成recordStore和tagStore两个文件。然后统一在store里浅复制

那么全局数据管理的好处是什么?

  1. 解耦:将所有数据相关的逻辑放入 store(也就是 MVC 中的 Model,换了个名字而已)。即从localStorage里取数据,存数据,对数据增删改查,都由store里的API提供,别人要对数据操作,直接调用API就可以,不需要关心里边的逻辑。
  2. 数据读写更方便:任何组件不管在哪里,都可以直接读写数据。比如说,原来Tags子组件里的标签列表是由它的父组件Money传进去的,如果它要增加标签,不能自己增加,要把数据传出去在外边修改。现在做了全局数据管理之后,Tags子组件完全可以自己直接调用store,读写数据,不需要由父组件操作。
  3. 控制力更强:组件对数据的读写只能使用 store 提供的 API 进行(当然也不排除有猪队友直接对 tagList 和 recordList 进行 push 等操作,这是没有办法禁止的)