vue從建立到完整的餓了麼(10)city.vue的完善(v-if 的簡單使用及本地緩存的存儲與讀取)

說明

1.上一章--頁面圖標ico的設置
2.蒼渡大神的項目源碼--項目地址
3.UI框架--Mint ui
4.數據接口地址--接口地址
5.下一章--組件的使用(svg及watch的簡單使用)vue

開始

1.先看看我們目前的city樣式
圖片描述node

2.再來看看我們須要實現的樣式
圖片描述圖片描述git

3.樣式
city.vue樣式修改以下github

<template>
  <div>
    <mt-header :title="$store.state.nowcity.name" class='fs1-2' fixed>
        <mt-button slot="left"><mt-button icon="back"></mt-button></mt-button>
        <mt-button slot="right" class='fs0-8'>切換城市</mt-button>
    </mt-header>

    <div class="mgtop50 padlr10 bgfff padbot10">
      <input class="cityinput" placeholder="輸入商務樓,學校,地址"></input>
      <div class="submit bgcol ih40">提交</div>
    </div>

    <div class="main">

      <div class="his after">
        <div class='maintop fs0-8 padlr10'>搜索歷史</div>
        <div class="mainbody bgfff ">
          <div class="pad10 after">
              <div class="ih30">南開區公園</div>
              <div class="ih30 fs0-8 col9f">天津市南開區金馬路112號</div>
          </div>
          <div class="pad10 after">
              <div class="ih30">南開區公園</div>
              <div class="ih30 fs0-8 col9f">天津市南開區金馬路112號</div>
          </div>
          <div class="clearall ih30 pad10 col9f">
              清空全部
          </div>
        </div>
      </div>

      <div class='search bgfff'> 
          <div class="pad10 after">
              <div class="ih30">南開區公園</div>
              <div class="ih30 fs0-8 col9f">天津市南開區金馬路112號</div>
          </div>
          <div class="pad10 after">
              <div class="ih30">南開區公園</div>
              <div class="ih30 fs0-8 col9f">天津市南開區金馬路112號</div>
          </div>
      </div>

    </div>

  </div>
</template>

<script>

export default {
  data () {
    return {
      
    }
  },
  component:{
  //註冊組件

  },
  mounted:function(){
  //生命週期


  },
  computed:{
  //計算屬性
      
  },
  methods:{
  //函數
    

  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.cityinput{
  width:100%;
  height:40px;
  margin:10px 0px;
  outline:0px;
  padding:0px 5px;
  box-sizing:border-box;
}
.submit{
  text-align:center;
  color:white;
  border-radius:3px;
}
.fs0-8{
  font-size:0.8rem !important;
}

.main{
  border-top:2px solid #E4E4E4;
}
.maintop{ 
  border-bottom:2px solid #E4E4E4;
}
.clearall{
  text-align:center;
}
</style>

頁面顯示爲
圖片描述vuex

咱們先把全部的樣式都寫出來,而後再來控制顯示哪一個divsegmentfault

4.點擊搜索
4.1當咱們在搜索框輸入地址後,點擊提交,應該彈出全部搜索的地址。因此咱們應該設置一個變量inputval來存放輸入框的值,一個變量list來存放搜索到的數據。api

data () {
    return {
      inputval:"",
      list:""
    }
  }

4.2點擊事件。先看數據接口api
圖片描述
先寫發送請求函數searchcity(這裏我把參數拼接到url上就沒錯,在url後加個{}來傳參數就報 參數錯誤 ,哪位老鐵知道玄機麼?)數組

methods:{
  //函數
    searchcity:function(){
      this.$http.get('http://cangdu.org:8001/v1/pois?city_id='+this.$store.state.nowcity.id+'&keyword='+this.inputval+'&type=search').then(response => {
        console.log(response);
        this.list=response.body;
      }, response => {
        console.log(response);
        
      });
    }

  }

this.$store.state.nowcity.id是從vuex裏獲取當前城市的id,在第八章存入;this.inputval是我們輸入框的值。
而後把點擊函數searchcity綁定到元素上緩存

<div @click="searchcity" class="submit bgcol ih40">提交</div>

運行試試,結果以下
圖片描述
解決,能夠看到數據已經請求回來了。框架

4.3顯示
如今咱們來控制class='his'(搜索歷史的div)和class='search'(搜索結果的div)的顯示與隱藏。當咱們點擊提交時,請求數據,將請求的數據加到list上去。那咱們就判斷,list爲空時,說明沒點提交,就顯示搜索歷史的div,list不爲空時,顯示搜索結果的div。
那咱們怎麼控制div的顯示隱藏呢?vue封裝了一個方法v-if。在使用元素上加上v-if=""便可,只要""中間返回的值是true,元素就會顯示,反之則隱藏。maindiv修改以下

<div class="main">

      <div v-if="list==''" class="his after">
        <div class='maintop fs0-8 padlr10'>搜索歷史</div>
        <div class="mainbody bgfff ">
          <div class="pad10 after">
              <div class="ih30">南開區公園</div>
              <div class="ih30 fs0-8 col9f">天津市南開區金馬路112號</div>
          </div>
          <div class="pad10 after">
              <div class="ih30">南開區公園</div>
              <div class="ih30 fs0-8 col9f">天津市南開區金馬路112號</div>
          </div>
          <div class="clearall ih30 pad10 col9f">
              清空全部
          </div>
        </div>
      </div>

      <div v-if="list!=''" class='search bgfff'> 
          <div class="pad10 after">
              <div class="ih30">南開區公園</div>
              <div class="ih30 fs0-8 col9f">天津市南開區金馬路112號</div>
          </div>
          
      </div>

    </div>

div顯示隱藏寫好了,下面用顯示數據。數據循環顯示依舊用v-for,我們在第五章已經講過了。maindiv修改以下

<div class="main">

      <div v-if="list==''" class="his after">
        <div class='maintop fs0-8 padlr10'>搜索歷史</div>
        <div class="mainbody bgfff ">
          <div class="pad10 after">
              <div class="ih30">南開區公園</div>
              <div class="ih30 fs0-8 col9f">天津市南開區金馬路112號</div>
          </div>
          <div class="pad10 after">
              <div class="ih30">南開區公園</div>
              <div class="ih30 fs0-8 col9f">天津市南開區金馬路112號</div>
          </div>
          <div class="clearall ih30 pad10 col9f">
              清空全部
          </div>
        </div>
      </div>

      <div v-if="list!=''" class='search bgfff'> 
          <div v-for="item in list" class="pad10 after">
              <div class="ih30">{{item.name}}</div>
              <div class="ih30 fs0-8 col9f">{{item.address}}</div>
          </div>
      </div>

    </div>

看看結果
圖片描述圖片描述

完美!數據顯示成功。

5.存儲搜索歷史

首先咱們要設置一個變量his來存放搜索歷史,這樣咱們顯示的時候直接v-for循環就能夠了。

data () {
    return {
      inputval:"",
      list:"",
      his:""
    }
  },

如今要點擊搜索結果列表,會有兩個反應。一個是頁面跳轉到商家列表頁,我們先不作,另外一個是把點擊的地點存到搜索歷史裏。那咱們把搜索歷史存到哪裏?想了想後以爲存到localstorage裏(哪位老鐵另有妙計?),既然要存,我們天然不能犯前面的錯誤(只存名字),因此咱們要把經度,緯度,經緯度合計,名字,地址都存進去。
先寫點擊事件goaddress在methods裏

goaddress:function(e){
      var arr=[];
      if(localStorage.getItem("his")){
          arr=JSON.parse(localStorage.getItem("his"));
          arr.push(e);
      }else{
          arr.push(e);
      }
      localStorage.setItem("his",JSON.stringify(arr));
      this.his=JSON.parse(localStorage.getItem("his"));
      this.list='';
    },

其中his使咱們要存到localStorage裏的鍵值名稱,先判斷有沒有,有說明有歷史記錄,咱們就把當前新加的地址放到his裏,沒有咱們就新建一個his,而後再存到localStorage裏。添加結束後咱們要把his賦值給city.vue的his裏,這樣咱們就能夠循環his在頁面裏顯示了(其實應該不用顯示,直接頁面就跳轉了,但咱們爲了效果先不作跳轉,先作歷史記錄的存儲與讀取,this.list=''是爲了讓搜索結果的div隱藏)。

函數寫完後咱們綁定到要點擊的元素上

<div v-if="list!=''" class='search bgfff'> 
          <div v-for="item in list" @click="goaddress({name:item.name,latitude:item.latitude,longitude:item.longitude,address:item.address,geohash:item.geohash})" class="pad10 after">
              <div class="ih30">{{item.name}}</div>
              <div class="ih30 fs0-8 col9f">{{item.address}}</div>
          </div>
      </div>

我們直接把要存儲的對象當作參數傳給點擊事件goaddress,參數爲{name:名字,latitude:經度,longitude:維度,address:地址,,geohash:經緯度合計}

如今咱們先點擊試試
圖片描述圖片描述

成功!咱們能夠在右側的控制檯(F12)的Application下的localStorage裏看到咱們已經存進去了一條數據

6.顯示搜索歷史
如今咱們的變量his已經有數據了,咱們只須要把它顯示出來就能夠

<div class="main">

      <div v-if="list==''" class="his after">
        <div class='maintop fs0-8 padlr10'>搜索歷史</div>
        <div v-if="his!=''" class="mainbody bgfff ">
          <div v-for="item in his" class="pad10 after">
              <div class="ih30">{{item.name}}</div>
              <div class="ih30 fs0-8 col9f">{{item.address}}</div>
          </div>
          <div class="clearall ih30 pad10 col9f">
              清空全部
          </div>
        </div>
      </div>

      <div v-if="list!=''" class='search bgfff'> 
          <div v-for="item in list" @click="goaddress({name:item.name,latitude:item.latitude,longitude:item.longitude,address:item.address,geohash:item.geohash})" class="pad10 after">
              <div class="ih30">{{item.name}}</div>
              <div class="ih30 fs0-8 col9f">{{item.address}}</div>
          </div>
      </div>

    </div>

這時候發現 清空全部 按鈕 並無功能,因此咱們再寫一個清空搜索歷史的函數removeall(並不會把搜索歷史hislocalStorage綁定起來,每次都要手動管理his,哪位老鐵可有妙計?)

removeall:function(){
      localStorage.clear();
      this.his="";
    }

而後綁定到清空全部的div上

<div @click='removeall' class="clearall ih30 pad10 col9f">
              清空全部
</div>

ok,運行試試

圖片描述圖片描述圖片描述圖片描述圖片描述圖片描述

看着沒問題了,可是可能有老鐵已經注意到了--歷史記錄應該頁面一進來就顯示出來,因此咱們應該在vue的生命週期mounted函數裏寫操做

mounted:function(){
  //生命週期
    if(localStorage.getItem("his")){
     this.his=localStorage.getItem("his");
    }
  },

判斷本地緩存是否有his,有就加到city.vue裏的his裏。city.vue完整代碼以下

<template>
  <div>
    <mt-header :title="$store.state.nowcity.name" class='fs1-2' fixed>
        <mt-button slot="left"><mt-button icon="back"></mt-button></mt-button>
        <mt-button slot="right" class='fs0-8'>切換城市</mt-button>
    </mt-header>

    <div class="mgtop50 padlr10 bgfff padbot10">
      <input v-model="inputval" class="cityinput" placeholder="輸入商務樓,學校,地址"></input>
      <div @click="searchcity" class="submit bgcol ih40">提交</div>
    </div>

    <div class="main">

      <div v-if="list==''" class="his after">
        <div class='maintop fs0-8 padlr10'>搜索歷史</div>
        <div v-if="his!=''" class="mainbody bgfff ">
          <div v-for="item in his" class="pad10 after">
              <div class="ih30">{{item.name}}</div>
              <div class="ih30 fs0-8 col9f">{{item.address}}</div>
          </div>
          <div @click='removeall' class="clearall ih30 pad10 col9f">
              清空全部
          </div>
        </div>
      </div>

      <div v-if="list!=''" class='search bgfff'> 
          <div v-for="item in list" @click="goaddress({name:item.name,latitude:item.latitude,longitude:item.longitude,address:item.address,geohash:item.geohash})" class="pad10 after">
              <div class="ih30">{{item.name}}</div>
              <div class="ih30 fs0-8 col9f">{{item.address}}</div>
          </div>
      </div>

    </div>

  </div>
</template>

<script>

export default {
  data () {
    return {
      inputval:"",
      list:"",
      his:""
    }
  },
  component:{
  //註冊組件

  },
  mounted:function(){
  //生命週期
    if(localStorage.getItem("his")){
     this.his=JSON.parse(localStorage.getItem("his"));
    }
  },
  computed:{
  //計算屬性
      
  },
  methods:{
  //函數
    searchcity:function(){
      this.$http.get('http://cangdu.org:8001/v1/pois?city_id='+this.$store.state.nowcity.id+'&keyword='+this.inputval+'&type=search').then(response => {
        console.log(response);
        this.list=response.body;
      }, response => {
        console.log(response);
        
      });
    },
    goaddress:function(e){
      var arr=[];
      if(localStorage.getItem("his")){
          arr=JSON.parse(localStorage.getItem("his"));
          arr.push(e);
      }else{
          arr.push(e);
      }
      localStorage.setItem("his",JSON.stringify(arr));
      this.his=JSON.parse(localStorage.getItem("his"));
      this.list='';
    },
    removeall:function(){
      localStorage.clear();
      this.his="";
    }

  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.cityinput{
  width:100%;
  height:40px;
  margin:10px 0px;
  outline:0px;
  padding:0px 5px;
  box-sizing:border-box;
}
.submit{
  text-align:center;
  color:white;
  border-radius:3px;
}
.fs0-8{
  font-size:0.8rem !important;
}

.main{
  border-top:2px solid #E4E4E4;
}
.maintop{ 
  border-bottom:2px solid #E4E4E4;
}
.clearall{
  text-align:center;
}
</style>

運行試試--
圖片描述圖片描述圖片描述

ok!到這裏city.vue的搜索歷史的存儲與
讀取基本寫完了

修改

頁面目前還有幾個小bug

1.輸入框數據爲空時不能點擊提交,把輸入框放到form表單裏,增長一個required屬性

<div class="mgtop50 padlr10 bgfff padbot10">
      <form v-on:submit.prevent>
        <input v-model="inputval" class="cityinput" required placeholder="輸入商務樓,學校,地址"></input>
        <input type='submit' name='submit' value='提交' @click="searchcity" class="submit bgcol ih40"></input>
      </form>
    </div>

再在函數searchcity裏判斷搜索地址數據是否爲空,不爲空再發送請求。

searchcity:function(){
      if(this.inputval){
        this.$http.get('http://cangdu.org:8001/v1/pois?city_id='+this.$store.state.nowcity.id+'&keyword='+this.inputval+'&type=search').then(response => {
          console.log(response);
          this.list=response.body;
        }, response => {
          console.log(response);
          
        });
      }     
    },

2.頁面內容明明就沒有填滿,卻出現滾動條,這是由於我們的第一個div即form的父元素(固定定位的頭部不算)有一個magtop50致使的(碰見過不少次,緣由是啥不知道),我們去掉這個class再在form的父元素外層加一個div加上padtop50

<div class='padtop50'>
      <div class="padlr10 bgfff padbot10">
        <form v-on:submit.prevent>
          <input v-model="inputval" class="cityinput" required placeholder="輸入商務樓,學校,地址"></input>
          <input type='submit' name='submit' value='提交' @click="searchcity" class="submit bgcol ih40"></input>
        </form>
      </div>
</div>

3.搜索的結果返回數據爲空怎麼辦?地址輸入 隱隱 點擊提交
圖片描述
能夠看到,返回數據的body爲空。那我們就給他彈出個消息框提示數據爲空。
消息提示框能夠用 Mint UI 的 Toast組件,例子寫的很清楚,我們用最簡單的就行
圖片描述
在city.vue的<script>裏第一行寫入

import { Toast } from 'mint-ui';

先引入,引入後就可使用。在提交的點擊事件searchcity裏判斷返回數據是否爲空

searchcity:function(){
      if(this.inputval){
        this.$http.get('http://cangdu.org:8001/v1/pois?city_id='+this.$store.state.nowcity.id+'&keyword='+this.inputval+'&type=search').then(response => {
          console.log(response);
          this.list=response.body;
          if(response.body==""){
            Toast('抱歉,空空如也');
          }
        }, response => {
          console.log(response);
          
        });
      }     
    },

運行試試
圖片描述

解決!彈出返回數據爲空時消息提示框!

4.判斷是否重複
當點擊搜索結果與搜索歷史有相同時,就不添加到歷史記錄。

goaddress:function(e){
      var arr=[];
      if(localStorage.getItem("his")){
          arr=JSON.parse(localStorage.getItem("his"));
          for(var i=0;i<arr.length;i++){
            if(arr[i].geohash==e.geohash){
               var isok=true;
            }
          }
          if(!isok){
            arr.unshift(e);
          }
      }else{
          arr.unshift(e);
      }
      localStorage.setItem("his",JSON.stringify(arr));
      this.his=JSON.parse(localStorage.getItem("his"));
      this.list='';
},

這裏要注意

  1. 經過經緯度的集合geohash來判斷是否相等
  2. 由於最近點擊的搜索地址要在搜索歷史的最上面,因此要用unshift添加而不是push
  3. 最重要一點,可能有老鐵會問,在判斷是否有相同的地址後,爲何要經過isok這個中間變量來改變是否添加新地址,而不是把 arr.unshift(e)直接寫在if判斷裏。。。嘿嘿,若是你用unshift在if判斷直接添加新元素,會出現死循環,由於當你把元素加到數組第一位後,數組全部的元素都會日後退一位,這樣你下次循環進來,取到的元素還是上一次循環的元素...(我也沒想明白,而個人學長強哥Topqiang一眼就看出來了,各位老鐵若是有其餘的好方法能夠分享一下)

city.vue修改後的完整代碼以下

<template>
  <div>
    <mt-header :title="$store.state.nowcity.name" class='fs1-2' fixed>
        <mt-button slot="left"><mt-button icon="back"></mt-button></mt-button>
        <mt-button slot="right" class='fs0-8'>切換城市</mt-button>
    </mt-header>

    <div class='padtop50'>
      <div class="padlr10 bgfff padbot10">
        <form v-on:submit.prevent>
          <input v-model="inputval" class="cityinput" required placeholder="輸入商務樓,學校,地址"></input>
          <input type='submit' name='submit' value='提交' @click="searchcity" class="submit bgcol ih40"></input>
        </form>
      </div>
    </div>

    <div class="main">

      <div v-if="list==''" class="his after">
        <div class='maintop fs0-8 padlr10'>搜索歷史</div>
        <div v-if="his!=''" class="mainbody bgfff ">
          <div v-for="item in his" class="pad10 after">
              <div class="ih30 nowarp">{{item.name}}</div>
              <div class="nowarp ih30 fs0-8 col9f">{{item.address}}</div>
          </div>
          <div @click='removeall' class="clearall ih30 pad10 col9f">
              清空全部
          </div>
        </div>
      </div>

      <div v-if="list!=''" class='search bgfff'> 
          <div v-for="item in list" @click="goaddress({name:item.name,latitude:item.latitude,longitude:item.longitude,address:item.address,geohash:item.geohash})" class="pad10 after">
              <div class="ih30 nowarp">{{item.name}}</div>
              <div class="nowarp ih30 fs0-8 col9f">{{item.address}}</div>
          </div>
      </div>

    </div>

  </div>
</template>

<script>
import { Toast } from 'mint-ui';

export default {
  data () {
    return {
      inputval:"",
      list:"",
      his:""
    }
  },
  component:{
  //註冊組件

  },
  mounted:function(){
  //生命週期
    if(localStorage.getItem("his")){
     this.his=JSON.parse(localStorage.getItem("his"));
    }
  },
  computed:{
  //計算屬性
      
  },
  methods:{
  //函數
    searchcity:function(){
      if(this.inputval){
        this.$http.get('http://cangdu.org:8001/v1/pois?city_id='+this.$store.state.nowcity.id+'&keyword='+this.inputval+'&type=search').then(response => {
          console.log(response);
          this.list=response.body;
          if(response.body==""){
            Toast('抱歉,空空如也');
          }
        }, response => {
          console.log(response);
          
        });
      }     
    },
    goaddress:function(e){
      var arr=[];
      if(localStorage.getItem("his")){
          arr=JSON.parse(localStorage.getItem("his"));
          for(var i=0;i<arr.length;i++){
            if(arr[i].geohash==e.geohash){
               var isok=true;
            }
          }
          if(!isok){
            arr.unshift(e);
          }
      }else{
          arr.unshift(e);
      }
      localStorage.setItem("his",JSON.stringify(arr));
      this.his=JSON.parse(localStorage.getItem("his"));
      this.list='';
    },
    removeall:function(){
      localStorage.clear();
      this.his="";
    }

  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.cityinput{
  width:100%;
  height:40px;
  margin:10px 0px;
  outline:0px;
  padding:0px 5px;
  box-sizing:border-box;
}
.submit{
  text-align:center;
  color:white;
  border-radius:3px;
  width:100%;
  border:0px;
  outline:0px;
}
.fs0-8{
  font-size:0.8rem !important;
}

.main{
  border-top:2px solid #E4E4E4;
}
.maintop{ 
  border-bottom:2px solid #E4E4E4;
}
.clearall{
  text-align:center;
}
</style>

運行試試
圖片描述圖片描述圖片描述圖片描述
解決!

下面,我們寫點擊搜索結果的另外一個反應--頁面跳轉

相關文章
相關標籤/搜索