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>

运行试试
图片描述图片描述图片描述图片描述
解决!

下面,我们写点击搜索结果的另外一个反应--页面跳转

相关文章
相关标签/搜索