说明
1.上一章--页面图标ico的设置
2.苍渡大神的项目源码--项目地址
3.UI框架--Mint ui
4.数据接口地址--接口地址
5.下一章--组件的使用(svg及watch的简单使用)
开始
1.先看看咱们目前的city样式
2.再来看看咱们需要实现的样式
3.样式
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 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>
页面显示为
我们先把所有的样式都写出来,然后再来控制显示哪个div
4.点击搜索
4.1当我们在搜索框输入地址后,点击提交,应该弹出所有搜索的地址。所以我们应该设置一个变量inputval
来存放输入框的值,一个变量list
来存放搜索到的数据。
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
,元素就会显示,反之则隐藏。main
div修改如下
<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
,咱们在第五章已经讲过了。main
div修改如下
<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
(并不会把搜索历史his
与localStorage
绑定起来,每次都要手动管理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='';
},
这里要注意
- 通过经纬度的集合
geohash
来判断是否相等 - 因为最近点击的搜索地址要在搜索历史的最上面,所以要用
unshift
添加而不是push
- 最重要一点,可能有老铁会问,在判断是否有相同的地址后,为什么要通过
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>
运行试试
解决!
下面,咱们写点击搜索结果的另一个反应--页面跳转
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。