最近在用vue作一個小demo,作了幾個小小的功能模塊,當作是學習練手吧。畢竟本身能力仍是比較受限的,只能慢慢進步啦。最近就想着本身作一個移動端的記帳小demo,由於本身沒有弄後臺(實際上是還沒去接觸學習哇咔咔),因此關於數據的存儲暫時就先用localstorage來存儲數據啦。html
項目在線demo
項目github地址
項目github地址git
最近在作的是小demo,這個是其中的一兩個頁面,是記帳模塊。專門抽出來說。總的代碼我會放在github上,今天講的這一部分代碼主要是下面三個文件內。github
首先,上一下一一開始的設計圖(略醜)。個人目的是,能夠記錄每一天的消費收入狀況(包括消費項目 ,時間以及消費金額),經過選擇時間能夠篩選每月份的消費收入狀況。每一天的收入消費狀況爲一個節點,點擊每條條目均可以進入編輯頁面進行消費項目 ,時間以及消費金額的編輯。因此編輯項目頁面和新增項目頁面是同一個頁面。
對了,關於收入支出的icon列表,我一開始就已經定義了一些常見的icon。在icon list中的設置能夠進行icon的編輯。後端
實踐開始:
1 數據存儲的形式:數組
我決定把每一條消費收入項目定義成一條這樣的數據形式,而後存儲在一個數組裏。bash
list = [
{type: "支出", money: "9999", date: "2017-10-6", icontype: "travel"},
{type: "支出", money: "449", date: "2017-10-6", icontype: "travel"},
{type: "支出", money: "799", date: "2017-10-8", icontype: "travel"},
{type: "收入", money: "34", date: "2017-10-7", icontype: "pay"},
{type: "支出", money: "9999", date: "2017-11-6", icontype: "travel"},
{type: "收入", money: "34", date: "2017-11-6", icontype: "pay"},
{type: "收入", money: "34", date: "2017-9-6", icontype: "pay"},
]
// 其中type是消費的類型,是收入仍是支出。money是消費的金額。
date則是消費時間,icontype是我存儲的icon的名字,能夠根據icontype的名字來顯示icon複製代碼
接着就是數據的篩選了。上面的示例裏是有9月,10月,11月的數據,固然咱們只須要的是某一個月份的數據,因此須要作一個filterData的方法來先過濾數據。數據結構
// 經過年和月來篩選數據,返回篩選出來的數據。傳進去的data參數是要篩選的數據
filterData (data, year, month) {
let filterData = []
for (let i = 0; i < data.length; i++) {
let dateArr = data[i].date.split('-')
if (dateArr[0] === year) {
if (dateArr[1] === month) {
filterData.push(data[i])
}
}
}
return filterData
}複製代碼
接着,就已經篩選出來了某一年某一月的消費數據了。我指定了年月是2017年10月,篩選出來以後數據以下所示:學習
list = [
{type: "支出", money: "9999", date: "2017-10-6", icontype: "travel"},
{type: "支出", money: "449", date: "2017-10-6", icontype: "travel"},
{type: "支出", money: "799", date: "2017-10-6", icontype: "travel"},
{type: "收入", money: "34", date: "2017-10-7", icontype: "pay"}
]複製代碼
篩選出某一年某一個月的數據仍是不夠的。由於咱們須要向這樣的一種格式去顯示出來,就意味着須要將屬於同一天的數據存儲在一塊兒ui
因此,我又寫了一個方法sortDatabyDate()
,來將數據進行篩選組合,先看一下轉換以後的數據格式,以下所示:這個格式的好處就是,計算總的收入支出的時候,
list = [
// 這是2017-10-6的數據
{date: "2017-10-6", income:34, outcome:'10377', sortindex:"6", list: [
{type: "支出", money: "9999", date: "2017-10-6", icontype: "travel"},
{type: "支出", money: "449", date: "2017-10-6", icontype: "travel"},
{type: "支出", money: "799", date: "2017-10-6", icontype: "travel"}]},
// 這是2017-10-7的數據
{date: "2017-10-6", income:34, outcome:'10377', sortindex:"6", list: [
{type: "收入", money: "34", date: "2017-10-7", icontype: "pay"}]}
]複製代碼
其實就是,將每一天的數據存在一個對象裏,而後其中的list就是這一天的每一條消費收入。其中的sortindex是爲了排序使用的,就是將天天的數據存儲在list中以後,還須要按照日期從上到下排序,因此我會將這個月的日期,存儲在sortindex中。後續要排序也比較方便了。
sortDatabyDate () {
var map = []
var dest = []
var income = 0
var outcome = 0
// 獲取當前年月的全部的數據
for (let i = 0; i < this.filterConsumeData.length; i++) {
var time = this.filterConsumeData[i].date
if (this.filterConsumeData[i].type === '收入') {
income = this.filterConsumeData[i].money
outcome = 0
} else {
outcome = this.filterConsumeData[i].money
income = 0
}
// map是存儲這個月的日期的數組,若是當前數據的時間不存在mapl裏面,就直接先建立一條數據
if (map.indexOf(time) === -1) {
dest.push({
income: +income,
outcome: +outcome,
sortindex: time.split('-')[2],
date: time,
list: [this.filterConsumeData[i]]
})
map.push(time)
} else {
// 當前這個數據的日期已經存在了,找到這條數據的索引,存儲進這條數據的list對象內就能夠了
for (let j = 0; j < dest.length; j++) {
if (dest[j].date === time) {
let oldIncome = dest[j].income
let oldOutcome = dest[j].outcome
dest[j].income = (+oldIncome) + (+income)
dest[j].outcome = (+oldOutcome) + (+outcome)
dest[j].list.push(this.filterConsumeData[i])
}
}
}
}
console.log(dest, '這是排序以前的')
// 再將獲得的數據進行排序,**sortByfield方法能夠根據對象的屬性進行排序**
dest.sort(this.sortByfield('sortindex'))
this.showConsumeList = dest // 這是獲得的最終的數據
// 將獲得的最終的數據,獲取當前的總收入和總支出
// 一開始先賦值爲0
this.inCome = 0
this.outCome = 0
for (let i = 0; i < this.showConsumeList.length; i++) {
this.inCome = (+this.inCome) + (+this.showConsumeList[i].income)
this.outCome = (+this.outCome) + (+this.showConsumeList[i].outcome)
}
}複製代碼
其中的排序方法,其實就是根據數組對象中每個對象中的sortIndex屬性來排序。這個能夠結合數組的sort()
屬性來使用。
(友情連接)數組對象根據對象排序 sort
// 其中field就是要排序的對象屬性,而後結合數組的sort方法,直接使用就能夠,。
// array.sort(sortByfield(屬性名))
sortByfield (field) {
return function (a, b) {
return a[field] - b[field]
}
}複製代碼
這樣寫下來就能夠實現數據的轉換了。結合vue的for循環指令,就能夠很愉快地將數據渲染出來了。是否是很棒。
2 如何獲取當前的編輯項目
細心的你會發現,就是在我點擊每個條目以後,會跳轉到編輯頁面。並且這個編輯頁面會自動渲染初始數據,那麼這個數據如何去傳遞呢?
個人作法
我是經過這個當前這個點擊的條目的信息,去獲取這個條目在總數據中的索引值,再將這個索引值用localStorage中存儲,跳轉到編輯頁面以後,只要從localstorage中獲取就能夠了,若是編輯改動了,就直接在總數據中根據索引值去修改就能夠了。
editList (item) {
this.$router.replace({path: '/moneyRecord'}) // 頁面跳轉到編輯頁面
let totalData = JSON.parse(localStorage.getItem('list') || '[]') //這是全部的條目數據
// 點擊進去以後就將數據傳遞到頁面
this.editIndex = this.findIndex(totalData, item) // 自定義的一個方法,從全部的數據中獲取到index值。
localStorage.setItem('editIndex', JSON.stringify(this.editIndex)) // 將index存儲下來
localStorage.setItem('editItem', JSON.stringify(item))
},複製代碼
其中的 findIndex方法
定義以下,使用了數組自帶的findindex
方法,能夠本身去google一下,arr.findIndex(callback[, thisArg])
findIndex (array, target) {
let index = array.findIndex((item) => {
return (item.date === target.date) && (item.type === target.type) && (item.icontype === target.icontype) && (item.money === target.money)
})
return index
}複製代碼
其實不論是編輯仍是新增,都只是須要填寫下面的基本信息而已,時間 金額 項目。
因此我是共用一個頁面的,惟一的區別就是編輯項目的時候須要數據初始化。那麼如何知道是編輯仍是新增呢?
個人作法
前面我已經提到了用localstorage去存儲editIndex
了。只要在進入當前頁面的時候,即monted的時候
獲取這個editIndex
是否存在,存在的話,就定義editType = 'edit'
,相反,就是editType = 'add'
.
固然,在你離開頁面的時候,還須要將editIndex
給remove掉。
因此,在moneyRecord頁面,我會刪除。
mounted () {
this.getIconList()
let editItem = JSON.parse(localStorage.getItem('editItem') || '[]')
if (editItem.length !== 0) {
// 編輯狀態,進行數據的初始化
this.Edittype = 'edit' // 當前是編輯狀態
this.type = editItem.type
this.selectedIcon = editItem.icontype
this.consumeMoney = editItem.money
this.pickerFormateValue = editItem.date
if (this.type === '支出') {
this.highlight = 'output'
this.showIcon = this.outputIcon
} else {
this.highlight = 'income'
this.showIcon = this.incomeIcon
}
} else {
// 新增狀態,將數據清空。
this.Edittype = 'add' // 當前是新增狀態
this.pickerFormateValue = this.setDateFormate(new Date())
this.highlight = 'output'
this.showIcon = this.outputIcon
this.selectedIcon = ''
this.consumeMoney = ''
}
},
beforeDestroy () {
bus.$off('get', this.myhandle)
localStorage.removeItem('editItem')
localStorage.removeItem('editIndex')
}複製代碼
能夠手動控制icon的顯示和隱藏。我會先初始化定義一些icon的數據,初始化存儲在localstorage中。而後經過監聽數據的變化,來實時變化存儲的數據。由於要監聽到的是對象屬性值的變化,因此須要深度監聽。
// 經過type 中的狀態來判斷是否顯示icon
getIconList () {
this.outputIcon = JSON.parse(localStorage.getItem('outputIcon') || '[]')
this.incomeIcon = JSON.parse(localStorage.getItem('incomeIcon') || '[]')
console.log(this.incomeIcon, this.outputIcon, '這是新的輸出icon', '這是新的輸入icon')
if (this.incomeIcon.length === 0) {
this.incomeIcon = [
{name: 'pay', title: '薪資', iconClass: 'icon-zhifuxinshui', type: true},
{name: 'getmoney', title: '獎金', iconClass: 'icon-jiangxuejinv', type: true},
{name: 'shorttime', title: '兼職', iconClass: 'icon-jianzhizhongdiangong', type: true},
{name: 'rate', title: '投資收益', iconClass: 'icon-touzihouhuodeshouyi', type: true}]
this.outputIcon = [
{name: 'shopping', title: '購物', iconClass: 'icon-gouwu', type: true},
{name: 'money', title: '理財', iconClass: 'icon-licai', type: true},
{name: 'traffic', title: '交通', iconClass: 'icon-jiaotong', type: true},
{name: 'fun', title: '娛樂', iconClass: 'icon-yule', type: true},
{name: 'meal', title: '餐飲', iconClass: 'icon-icon', type: true},
{name: 'travel', title: '旅行', iconClass: 'icon-lvyou', type: true},
{name: 'medical', title: '醫療', iconClass: 'icon-yiliao', type: true},
{name: 'specialMoney', title: '禮金', iconClass: 'icon-lijin', type: true},
{name: 'beauty', title: '美容', iconClass: 'icon-meirong', type: true}]
localStorage.setItem('outputIcon', JSON.stringify(this.outputIcon))
localStorage.setItem('incomeIcon', JSON.stringify(this.incomeIcon))
}
}
// 監聽數據的變化,數據變化,就從新存儲數據。
outputIcon: {
handler: function (val) { localStorage.setItem('outputIcon', JSON.stringify(val)) },
deep: true
},
incomeIcon: {
handler: function (val) { localStorage.setItem('incomeIcon', JSON.stringify(val)) },
deep: true
}複製代碼
vue 的主要核心就是數據驅動,作這個項目的時候就深入地意識到,事先定義比如較好的數據結構是多麼重要。一旦數據結構定義好以後,再進行後期的數據處理,就能夠很好地根據數據進行渲染了。
因此在這裏數據的後期處理就很重要,掌握好數組的一些方法,像sort findIndex 以及split等方法都很重要。
是時候學點後端的東西啦。。。。。