vue.js开发记账(5)

85 阅读2分钟

project from jirengu.com

MVC重构

  • MVC设计模式,把项目代码在数据层面进行重构,所有数据Model层面的集中到一个文件,所有视图View放在一起。
    1. 初始化数据:
recordList: Record[] = JSON.parse(window.localStorage.getItem(recordList) || '[]');
    1. 更新数据,往数据里添加东西:
saveRecord() {
    const record2: Record = JSON.parse(JSON.stringify(this.record));
    record2.createdAt = new Date();
    this.recordList.push(record2);
}
    1. 保存数据:
@Watch('recordList')
onRecordListChange() {
    window.localStorage.setItem(recordList, JSON.stringify(this.recordList));
  • 如何用js来封装Model:新建文件在src根目录下,名为model.js
const localStorageKeyName= 'recordList'
const model = {
    fetch(){   //获取数据
       return JSON.parse(window.localStorage.getItem(localStorageKeyName) || '[]')
    },
    save(data){
        window.localStorage.setItem(localStorageKeyName, JSON.stringify(this.recordList));
    }
}

export default model
  • 此时直接在Money.vue中的ts引入model.js文件,会出现识别fetch函数的情况,是因为引入语法的问题:
const model = require('@/model.js')  //ts引入js的正确打开方式
const recordList: Record[] = model.fetch()

77.png

  • 应修改导出model.js的原语句为具名导出:
export default model //原来的导出语句
export {model}       //修改为此方式
//Money.vue
const model = require('@/model.js').model; 
const {model} =require('@/model.js'); //这种析构写法也可以
const recordList: Record[] = model.fetch();
  • 如何把model.js改写为model.ts

  • 直接在原model.js右键,refactor->rename,取消勾选,改后缀为model.ts,再把Money.vue中的Record重构为RecordItem,最后在src根目录新建一个custom.d.ts,用来自定义全局声明。

//custom.d.ts
type RecordItem = {  //TS类型声明只写类型,JS类型声明写具体内容
    tags: string[]
    notes: string
    type: string
    amount: number
    createdAt: Date
}
//model.ts
save(data: RecordItem[]) {
    window.localStorage.setItem(localStorageKeyName, JSON.stringify(data));

}
  • 重新引用model:
//Money.vue
import  model  from '@/model';
const recordList: RecordItem[] = model.fetch()
//model.ts
const localStorageKeyName = 'recordList';
const model = {
    fetch() {   //获取数据
      return JSON.parse(window.localStorage.getItem(localStorageKeyName) || '[]');
    },
    save(data: RecordItem[]) {
        window.localStorage.setItem(localStorageKeyName, JSON.stringify(data));
    }
};

export default model;
  • fetch的返回值类型定义一下:
fetch() {   //获取数据
    return JSON.parse(window.localStorage.getItem('localStorageKeyName') || '[]') as RecordItem[];
},

封装的结果为:

//Money.vue
<template>
    <Layout class-prefix="layout">
        {{recordList}}
        <NumberPad @update:value="onUpdateAmount" @submit="saveRecord"/>
        <Types :value.sync="record.value"/>
        <Notes @update:value="onUpdateNotes"/>
        <Tags :data-source.sync="tags" @update:value="onUpdateTags"/>
    </Layout>
</template>

<script lang="ts">
    import Vue from 'vue';
    import NumberPad from '@/components/Money/NumberPad.vue';
    import Types from '@/components/Money/Types.vue';
    import Notes from '@/components/Money/Notes.vue';
    import Tags from '@/components/Money/Tags.vue';
    import {Component, Watch} from 'vue-property-decorator';
    import model from '@/model';

    const recordList = model.fetch();

    @Component({
        components: {Tags, Notes, Types, NumberPad}
    })
    export default class Money extends Vue {
        tags = ['餐饮', '购物', '交通', '娱乐', '医疗'];
        recordList: RecordItem[] = JSON.parse(window.localStorage.getItem('recordList') || '[]');
        record: RecordItem = {
            tags: [], notes: '', type: '-', amount: 0
        };

        onUpdateAmount(value: string) {
            this.record.amount = parseFloat(value);
        }

        onUpdateType(value: string) {
            this.record.type = value;
        }

        onUpdateNotes(value: string) {
            this.record.notes = value;
        }

        onUpdateTags(value: string[]) {
            this.record.tags = value;
        }

        saveRecord() {
            const record2: RecordItem = model.clone(this.record);
            record2.createdAt = new Date();
            this.recordList.push(record2);
        }

        @Watch('recordList')
        onRecordListChange() {
            model.save(this.recordList);
        }
    }
</script>

<style lang="scss">
    .layout-content {
        display: flex;
        flex-direction: column-reverse;
    }
</style>
//custom.d.ts
type RecordItem = {  //TS类型声明只写类型,JS类型声明写具体内容
    tags: string[]
    notes: string
    type: string
    amount: number
    createdAt: Date
}
//model.ts
const localStorageKeyName = 'recordList';

const model = {
    clone(data:RecordItem[]| RecordItem) {
        return JSON.parse(JSON.stringify(data));
    },
    fetch() {   //获取数据
        return JSON.parse(window.localStorage.getItem('localStorageKeyName') || '[]') as RecordItem[];
    },
    save(data: RecordItem[]) {
        window.localStorage.setItem('localStorageKeyName', JSON.stringify(data));

    }

};

export default model;

本节中一个坑,要注意

  • 所有model数据内容中涉及到window.localStorage.setItem,第一项参数,要注意不要有引号,应该是默认敲代码时候会自动加,这样会影响后面的开发体验,无法保存当前页面数据。应都改为如下代码:
//model.ts
fetch() {   //获取数据
        return JSON.parse(window.localStorage.getItem('localStorageKeyName') || '[]') as RecordItem[];  //此行为敲代码默认写法,是错误的
        return JSON.parse(window.localStorage.getItem(localStorageKeyName) || '[]') as RecordItem[];  //此行为正确写法,去掉引号
    },
    save(data: RecordItem[]) {
        window.localStorage.setItem('localStorageKeyName', JSON.stringify(data)); //此行为敲代码默认写法,是错误的
        window.localStorage.setItem(localStorageKeyName, JSON.stringify(data)); //此行为正确写法,去掉引号
    }