从零到全局数据管理
第一个小难关:
最开始:
两个数组
然后:
抽成TaglistModel和RecordListModel,然后存进Localstorage
问题:
label页修改了数据,money页并没有显示更新
原因:label页和money是分别从window.localstorage里fetch到的数据
相当于两个页面 对一份数据 各自做了一份拷贝,所以A修改A的拷贝数据,B拷贝的数据不会有任何变化
解决方法:
把数据都放在window上,大家要用数据就从window上拿,这样可以保证大家拿到的是同一份数据
步骤:
- custom.d.ts里全局定义数据类型
- 在Main.ts里用window.tagList = tagListModel.fetch()
- 在label页和Money页直接使用window.taglist和window.recordList
第二个难题:继续封装各种操作tagListModel 和 recordListModel的方法
问题:
- 这样太过于依赖window
- 全局变量太多了
解决方法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数组,不是传进去的值本身,所以这个行不通
-
但是这个可以修改备注
解决方法:
- 清空备注:
传默认备注进去 - 清空选中的标签:
一开始传递的进去的默认值是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…
记录一下自己第一次做项目碰到的问题和解决方法。