MoreMoney记账总结 1.0

304 阅读2分钟

从零到全局数据管理

第一个小难关:

最开始:

两个数组

然后:

抽成TaglistModel和RecordListModel,然后存进Localstorage

问题:

label页修改了数据,money页并没有显示更新

原因:label页和money是分别从window.localstorage里fetch到的数据

相当于两个页面 对一份数据 各自做了一份拷贝,所以A修改A的拷贝数据,B拷贝的数据不会有任何变化

解决方法:

把数据都放在window上,大家要用数据就从window上拿,这样可以保证大家拿到的是同一份数据

步骤:

  1. custom.d.ts里全局定义数据类型
  2. 在Main.ts里用window.tagList = tagListModel.fetch()
  3. 在label页和Money页直接使用window.taglist和window.recordList

第二个难题:继续封装各种操作tagListModel 和 recordListModel的方法

问题:

  1. 这样太过于依赖window
  2. 全局变量太多了

解决方法1.0:

抽取store全局对象,消除对window的依赖

recordStore和tagStore里分别存放了recordModel和tagModel和对他们的增删改查方法

使用时就用store.createTag()这样的方法就好

解决方法2.0: 用Vuex

步骤:首先引入:

store/index.ts

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex) // 把 store 绑到 Vue.prototype.$store = store

export default new Vuex.Store({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})

解决安卓软键盘问题

思路:会有软键盘问题是因为当软键盘弹起时,页面高度变了

导致页面变形

解决思路:

设置当前页面的高度为页面高度即可

<template>
	<div class="layout-wrapper" :style="{height: scrollerHeight}">
		<div class="content">
			<slot></slot>
		</div>
		<Nav></Nav>
	</div>
</template>

<script lang="ts">
  import Vue from 'vue';
  import {Component} from 'vue-property-decorator';
  @Component
  export  default class App extends Vue {
    get scrollerHeight(){
      return document.documentElement.clientHeight + 'px'
    }

    mounted() {
      // window.onresize监听页面高度的变化
      window.onresize = function()  {
        console.log(document.querySelector('#app').clientHeight)
      }
    }
  }
</script>

<style scoped lang="scss">
	.layout-wrapper {
		display: flex;
		flex-direction: column;
		height: 100vh;
	}

	.content {
		flex-grow: 1; // 让内容尽量占满
		overflow: auto;
		display: flex;
		flex-direction: column;
	}
</style>

点击事件传递

问题:

  • button里加了一个icon组件
  • 当在button上写点击事件时,会没有用
  • 因为点击的是icon组件里面的东西

解决方法:

在icon组件里写一个$emit, 它被点击时,触发外面的点击事件

Labels.vue


<li v-for="(item, index) in this.outputTags"
						:key="index">
    ....
    <Icon :name="'delete2'" @click="deleteTag(item.id)"></Icon>
  </li>
Icon.vue
  // 触发点击事件,这样父组件就可以监听到了
	<svg class="icon" @click="$emit('click', $event)">
		<use :xlink:href="'#' + name"></use>
	</svg>

.sync妙用

问题:点击OK,记完账后,当前数据没有清零

需求:点击ok按钮之后,屏幕上的所有数据清零

	<Layout>
		{{this.recordItem}}
		<Types :value.sync="recordItem.type" @update:selectedTag="onUpdateTag">
		</Types>
		<Tags :is-show="recordItem.type" @update:tag:money="onUpdateTag"
					:out-data-source.sync="outputTags"
					:in-data-source.sync="inputTags"
		></Tags>
		<FormItem :value="recordItem.note" @update:value="onUpdateNote" placeholder="写点备注吧..." is-number-pad="+"></FormItem>
		<NumberPad @update:value="onUpdateAmount" @submit="saveRecord"></NumberPad>

	</Layout>

解决方法:传递一个默认值,然后监听这个值的变化

这就符合.sync语法

  • 但是问题是tags里面操作的是selectedTag数组,不是传进去的值本身,所以这个行不通

  • 但是这个可以修改备注

解决方法:

  1. 清空备注:
    传默认备注进去
  2. 清空选中的标签:
    一开始传递的进去的默认值是tagName标签名,但是由于做选中标签高亮的逻辑是用一个数组来控制的即使tagName清零,但是里面的数组还没有清零,于是想到把传一个空数组进去,控制标签。

CSS最佳实践——deep语法

需求:

多处使用type组件,但是css不同

方法一:传一个变量进去

方法二:deep语法

<template>
	<Layout>
		<Types class="x"></Types>
	</Layout>
</template>

<script lang="ts">
  import Types from '@/components/Money/Types.vue';
</script>

<style scoped lang="scss">
	.x ::v-deep li {
		border: 1px solid red;
	}
</style>

核心是这里:

<style scoped lang="scss">
	.x ::v-deep li {
		border: 1px solid red;
	}
</style>

修改同一个组件CSS的最佳实践:

用表驱动编程

<Layout>
		<Types class-prefix="zzz" :value.sync="yyy"></Types>
	</Layout>
<style scoped lang="scss">
	::v-deep .zzz-item {
		background: white;

		&.selected {
			background: #fed058;
		}
	}
</style>
<li :class="{[classPrefix + '-item']: classPrefix,
					         selected: value === '-' }"
				@click="selectType('-')">
				<span>支出</span>
			</li>
			<li :class="{[classPrefix + '-item']: classPrefix,
					         selected: value === '+' }"
					@click="selectType('+')">
				<span>收入</span>
			</li>

@Prop(String) classPrefix?: string;

定义class:

:class="{[classPrefix + '-item']: classPrefix,
					selected: value === '+' }"

注意如果想在对象的key里写变量,需要用中括号括起来

还可以进一步封装:

封装成一个函数,返回一个对象,还可以接受参数,方便遍历

liClass(type: string) {
      return {
        [this.classPrefix + '-item']: this.classPrefix,
        selected: this.value === type
      };
    }
<li :class="liClass('-')"
	@click="selectType('-')">

代码预览链接:fjliang56.github.io/morney-webs…

记录一下自己第一次做项目碰到的问题和解决方法。