vue移動(dòng)助手實(shí)踐(三)————結(jié)合vue和localstorage的移動(dòng)端記賬demo

最近在用vue做一個(gè)小demo,做了幾個(gè)小小的功能模塊宽档,當(dāng)做是學(xué)習(xí)練手吧炭懊。畢竟自己能力還是比較受限的并级,只能慢慢進(jìn)步啦。最近就想著自己做一個(gè)移動(dòng)端的記賬小demo凛虽,因?yàn)樽约簺]有弄后臺(其實(shí)是還沒去接觸學(xué)習(xí)哇咔咔)死遭,所以關(guān)于數(shù)據(jù)的存儲(chǔ)暫時(shí)就先用localstorage來存儲(chǔ)數(shù)據(jù)啦。

項(xiàng)目在線demo

項(xiàng)目在線演示demo(切換到移動(dòng)端調(diào)試模式哦)

項(xiàng)目github地址

項(xiàng)目github地址

最近在做的是小demo,這個(gè)是其中的一兩個(gè)頁面凯旋,是記賬模塊呀潭。專門抽出來講≈练牵總的代碼我會(huì)放在github上钠署,今天講的這一部分代碼主要是下面三個(gè)文件內(nèi)。

image.png
1 非常粗糙的草圖 (莫嫌棄哈哈哈荒椭,丑帥丑帥的字)

首先谐鼎,上一下一一開始的設(shè)計(jì)圖(略丑)。我的目的是趣惠,可以記錄每一天的消費(fèi)收入情況(包括消費(fèi)項(xiàng)目 ,時(shí)間以及消費(fèi)金額)狸棍,通過選擇時(shí)間可以篩選每個(gè)月份的消費(fèi)收入情況。每一天的收入消費(fèi)情況為一個(gè)節(jié)點(diǎn)味悄,點(diǎn)擊每條條目都可以進(jìn)入編輯頁面進(jìn)行消費(fèi)項(xiàng)目 ,時(shí)間以及消費(fèi)金額的編輯草戈。所以編輯項(xiàng)目頁面和新增項(xiàng)目頁面是同一個(gè)頁面。
對了侍瑟,關(guān)于收入支出的icon列表唐片,我一開始就已經(jīng)定義了一些常見的icon。在icon list中的設(shè)置可以進(jìn)行icon的編輯涨颜。

image.png
2 成果先看一步(UI有點(diǎn)丑费韭,我后期要美化=钕帧H锍獭!K斡妗5稹)
test.gif
3 項(xiàng)目的整個(gè)過程
問題難點(diǎn):
  • 數(shù)據(jù)格式的定義:因?yàn)樯婕暗娇梢院Y選出某一年的某一個(gè)月的所有數(shù)據(jù)钉汗,同時(shí)每一個(gè)月的某一天的數(shù)據(jù)也可以被篩選羹令,所以數(shù)據(jù)格式的定義以及數(shù)據(jù)的存儲(chǔ)方式很重要。
  • 數(shù)據(jù)后期處理篩選:存儲(chǔ)了數(shù)據(jù)之后损痰,如何根據(jù)年月來選擇篩選數(shù)據(jù),同時(shí)要將屬于同一天的數(shù)據(jù)篩選出來酒来。
  • 獲取當(dāng)前被編輯的項(xiàng)目:因?yàn)辄c(diǎn)擊每一條項(xiàng)目之后卢未,都可以相應(yīng)跳轉(zhuǎn)進(jìn)去編輯頁面,當(dāng)前的編輯頁面需要自動(dòng)填充當(dāng)前項(xiàng)目的數(shù)據(jù)堰汉,因?yàn)檫@涉及到兩個(gè)頁面之間的數(shù)據(jù)傳遞辽社,我最后還是選擇了用localstorage 來存儲(chǔ)傳遞數(shù)據(jù)。

實(shí)踐開始:
1 數(shù)據(jù)存儲(chǔ)的形式:

我決定把每一條消費(fèi)收入項(xiàng)目定義成一條這樣的數(shù)據(jù)形式,然后存儲(chǔ)在一個(gè)數(shù)組里翘鸭。

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是消費(fèi)的類型滴铅,是收入還是支出。money是消費(fèi)的金額就乓。
date則是消費(fèi)時(shí)間汉匙,icontype是我存儲(chǔ)的icon的名字,可以根據(jù)icontype的名字來顯示icon

接著就是數(shù)據(jù)的篩選了生蚁。上面的示例里是有9月噩翠,10月11月的數(shù)據(jù)邦投,當(dāng)然我們只需要的是某一個(gè)月份的數(shù)據(jù)伤锚,所以需要做一個(gè)filterData的方法來先過濾數(shù)據(jù)。

  // 通過年和月來篩選數(shù)據(jù),返回篩選出來的數(shù)據(jù)志衣。傳進(jìn)去的data參數(shù)是要篩選的數(shù)據(jù)
    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
    }

接著屯援,就已經(jīng)篩選出來了某一年某一月的消費(fèi)數(shù)據(jù)了。我指定了年月是2017年10月念脯,篩選出來之后數(shù)據(jù)如下所示:

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"}
]

篩選出某一年某一個(gè)月的數(shù)據(jù)還是不夠的狞洋。因?yàn)槲覀冃枰蜻@樣的一種格式去顯示出來,就意味著需要將屬于同一天的數(shù)據(jù)存儲(chǔ)在一起

image.png

所以和二,我又寫了一個(gè)方法sortDatabyDate()徘铝,來將數(shù)據(jù)進(jìn)行篩選組合,先看一下轉(zhuǎn)換之后的數(shù)據(jù)格式惯吕,如下所示:這個(gè)格式的好處就是惕它,計(jì)算總的收入支出的時(shí)候,

list = [
// 這是2017-10-6的數(shù)據(jù)
    {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的數(shù)據(jù)
    {date: "2017-10-6", income:34, outcome:'10377', sortindex:"6", list: [
       {type: "收入", money: "34", date: "2017-10-7", icontype: "pay"}]}
]

其實(shí)就是废登,將每一天的數(shù)據(jù)存在一個(gè)對象里淹魄,然后其中的list就是這一天的每一條消費(fèi)收入。其中的sortindex是為了排序使用的堡距,就是將每天的數(shù)據(jù)存儲(chǔ)在list中之后甲锡,還需要按照日期從上到下排序兆蕉,所以我會(huì)將這個(gè)月的日期,存儲(chǔ)在sortindex中缤沦。后續(xù)要排序也比較方便了虎韵。

 sortDatabyDate () {
      var map = []
      var dest = []
      var income = 0
      var outcome = 0
// 獲取當(dāng)前年月的所有的數(shù)據(jù)
      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是存儲(chǔ)這個(gè)月的日期的數(shù)組,如果當(dāng)前數(shù)據(jù)的時(shí)間不存在mapl里面缸废,就直接先創(chuàng)建一條數(shù)據(jù)
        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 {
// 當(dāng)前這個(gè)數(shù)據(jù)的日期已經(jīng)存在了包蓝,找到這條數(shù)據(jù)的索引,存儲(chǔ)進(jìn)這條數(shù)據(jù)的list對象內(nèi)就可以了
          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, '這是排序之前的')
      // 再將得到的數(shù)據(jù)進(jìn)行排序企量,**sortByfield方法可以根據(jù)對象的屬性進(jìn)行排序**
      dest.sort(this.sortByfield('sortindex'))
      this.showConsumeList = dest  // 這是得到的最終的數(shù)據(jù)
      // 將得到的最終的數(shù)據(jù)测萎,獲取當(dāng)前的總收入和總支出
    // 一開始先賦值為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)
      }
    }

其中的排序方法,其實(shí)就是根據(jù)數(shù)組對象中每一個(gè)對象中的sortIndex屬性來排序届巩。這個(gè)可以結(jié)合數(shù)組的sort()屬性來使用硅瞧。
(友情鏈接)數(shù)組對象根據(jù)對象排序 sort

// 其中field就是要排序的對象屬性,然后結(jié)合數(shù)組的sort方法恕汇,直接使用就可以腕唧,。
// array.sort(sortByfield(屬性名))
   sortByfield (field) {
      return function (a, b) {
        return a[field] - b[field]
      }
    }

這樣寫下來就可以實(shí)現(xiàn)數(shù)據(jù)的轉(zhuǎn)換了拇勃。結(jié)合vue的for循環(huán)指令四苇,就可以很愉快地將數(shù)據(jù)渲染出來了。是不是很棒方咆。

2 如何獲取當(dāng)前的編輯項(xiàng)目

細(xì)心的你會(huì)發(fā)現(xiàn)月腋,就是在我點(diǎn)擊每一個(gè)條目之后,會(huì)跳轉(zhuǎn)到編輯頁面瓣赂。而且這個(gè)編輯頁面會(huì)自動(dòng)渲染初始數(shù)據(jù)榆骚,那么這個(gè)數(shù)據(jù)如何去傳遞呢?

我的做法
我是通過這個(gè)當(dāng)前這個(gè)點(diǎn)擊的條目的信息煌集,去獲取這個(gè)條目在總數(shù)據(jù)中的索引值妓肢,再將這個(gè)索引值用localStorage中存儲(chǔ),跳轉(zhuǎn)到編輯頁面之后苫纤,只要從localstorage中獲取就可以了,如果編輯改動(dòng)了碉钠,就直接在總數(shù)據(jù)中根據(jù)索引值去修改就可以了。

   editList (item) {
      this.$router.replace({path: '/moneyRecord'}) // 頁面跳轉(zhuǎn)到編輯頁面
      let totalData = JSON.parse(localStorage.getItem('list') || '[]')  //這是所有的條目數(shù)據(jù)
      // 點(diǎn)擊進(jìn)去之后就將數(shù)據(jù)傳遞到頁面
      this.editIndex = this.findIndex(totalData, item) // 自定義的一個(gè)方法卷拘,從所有的數(shù)據(jù)中獲取到index值喊废。
      localStorage.setItem('editIndex', JSON.stringify(this.editIndex)) // 將index存儲(chǔ)下來
      localStorage.setItem('editItem', JSON.stringify(item))
    },

其中的 findIndex方法定義如下,使用了數(shù)組自帶的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
    }
3 新增項(xiàng)目和編輯項(xiàng)目共用一個(gè)頁面

其實(shí)不管是編輯還是新增,都只是需要填寫下面的基本信息而已乍赫,時(shí)間 金額 項(xiàng)目瓣蛀。
所以我是共用一個(gè)頁面的陆蟆,唯一的區(qū)別就是編輯項(xiàng)目的時(shí)候需要數(shù)據(jù)初始化。那么如何知道是編輯還是新增呢惋增?

我的做法

前面我已經(jīng)提到了用localstorage去存儲(chǔ)editIndex了叠殷。只要在進(jìn)入當(dāng)前頁面的時(shí)候,即monted的時(shí)候獲取這個(gè)editIndex是否存在器腋,存在的話溪猿,就定義editType = 'edit',相反,就是editType = 'add'.
當(dāng)然纫塌,在你離開頁面的時(shí)候,還需要將editIndex給remove掉讲弄。

所以措左,在moneyRecord頁面,我會(huì)刪除。

  mounted () {
    this.getIconList()
    let editItem = JSON.parse(localStorage.getItem('editItem') || '[]')
    if (editItem.length !== 0) {
//  編輯狀態(tài)避除,進(jìn)行數(shù)據(jù)的初始化
      this.Edittype = 'edit'  // 當(dāng)前是編輯狀態(tài)
      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 {
//  新增狀態(tài)怎披,將數(shù)據(jù)清空。
      this.Edittype = 'add'  // 當(dāng)前是新增狀態(tài)
      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')
  }

4 實(shí)現(xiàn)icon的開關(guān)設(shè)置

可以手動(dòng)控制icon的顯示和隱藏瓶摆。我會(huì)先初始化定義一些icon的數(shù)據(jù)凉逛,初始化存儲(chǔ)在localstorage中。然后通過監(jiān)聽數(shù)據(jù)的變化群井,來實(shí)時(shí)變化存儲(chǔ)的數(shù)據(jù)状飞。因?yàn)橐O(jiān)聽到的是對象屬性值的變化,所以需要深度監(jiān)聽书斜。

// 通過type 中的狀態(tài)來判斷是否顯示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: '獎(jiǎng)金', 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: '理財(cái)', 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: '醫(yī)療', 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))
      }
    }

// 監(jiān)聽數(shù)據(jù)的變化诬辈,數(shù)據(jù)變化,就重新存儲(chǔ)數(shù)據(jù)荐吉。
  outputIcon: {
      handler: function (val) { localStorage.setItem('outputIcon', JSON.stringify(val)) },
      deep: true
    },
    incomeIcon: {
      handler: function (val) { localStorage.setItem('incomeIcon', JSON.stringify(val)) },
      deep: true
    }
test.gif

vue 的主要核心就是數(shù)據(jù)驅(qū)動(dòng)焙糟,做這個(gè)項(xiàng)目的時(shí)候就深刻地意識到,事先定義好比較好的數(shù)據(jù)結(jié)構(gòu)是多么重要样屠。一旦數(shù)據(jù)結(jié)構(gòu)定義好之后穿撮,再進(jìn)行后期的數(shù)據(jù)處理,就可以很好地根據(jù)數(shù)據(jù)進(jìn)行渲染了痪欲。
所以在這里數(shù)據(jù)的后期處理就很重要悦穿,掌握好數(shù)組的一些方法,像sort findIndex 以及split等方法都很重要勤揩。

是時(shí)候?qū)W點(diǎn)后端的東西啦咧党。。陨亡。傍衡。深员。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蛙埂,隨后出現(xiàn)的幾起案子倦畅,更是在濱河造成了極大的恐慌,老刑警劉巖绣的,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叠赐,死亡現(xiàn)場離奇詭異,居然都是意外死亡屡江,警方通過查閱死者的電腦和手機(jī)芭概,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惩嘉,“玉大人罢洲,你說我怎么就攤上這事∥睦瑁” “怎么了惹苗?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長耸峭。 經(jīng)常有香客問我桩蓉,道長,這世上最難降的妖魔是什么劳闹? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任院究,我火速辦了婚禮,結(jié)果婚禮上玷或,老公的妹妹穿的比我還像新娘儡首。我一直安慰自己,他們只是感情好偏友,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布蔬胯。 她就那樣靜靜地躺著,像睡著了一般位他。 火紅的嫁衣襯著肌膚如雪氛濒。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天鹅髓,我揣著相機(jī)與錄音舞竿,去河邊找鬼。 笑死窿冯,一個(gè)胖子當(dāng)著我的面吹牛骗奖,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼执桌,長吁一口氣:“原來是場噩夢啊……” “哼鄙皇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起仰挣,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤伴逸,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后膘壶,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體错蝴,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年颓芭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了顷锰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡亡问,死狀恐怖馍惹,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情玛界,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布悼吱,位于F島的核電站慎框,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏后添。R本人自食惡果不足惜笨枯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望遇西。 院中可真熱鬧馅精,春花似錦、人聲如沸粱檀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茄蚯。三九已至压彭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間渗常,已是汗流浹背壮不。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留皱碘,地道東北人询一。 一個(gè)月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親健蕊。 傳聞我的和親對象是個(gè)殘疾皇子菱阵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容