目录

相关组件介绍

一 机票首页布局

二 封装搜索组件

1. 组件布局

2.目标思路

3.步骤

3.1 基本功能

3.2 自动补全

3.3获取真正的推荐数据

3.4 添加城市代号

3.5 处理日期格式

3.6  使用了momentjs,这是一个第三方的包,需要先下载并且导入。

其他功能

优化

三 搜索功能

1.思路

2.实现步骤

获取城市数据

调用城市查询接口

下拉数据选中赋值

搜索跳转

城市切换

往返

3.总结

四 特价机票

1. 思路

2.实现步骤

2.1 特价机票布局

2.2 请求数据接口

五 效果图


相关组件介绍

1.el-autocomplete远程搜索自动补全组件

组件文档:https://element.eleme.cn/#/zh-CN/component/input#yuan-cheng-sou-suo

2.el-date-picker日期选择组件

组件文档:https://element.eleme.cn/#/zh-CN/component/date-picker#xuan-ze-ri

一 机票首页布局

pages/air/index.vue的代码如下 :

<template><section class="container"><h2 class="air-title"><span class="iconfont iconfeiji"></span><i>国内机票</i></h2><!-- 搜索广告栏 --><el-row type="flex" justify="space-between"><!-- 搜索表单 --><div>搜索</div><!-- banner广告 --><div class="sale-banner"><img src="http://157.122.54.189:9093/images/pic_sale.jpeg"></div></el-row><!-- 广告 --><el-row type="flex" class="statement"><el-col :span="8"><i class="iconfont iconweibiaoti-_huabanfuben" style="color:#409EFF;"></i><span>100%航协认证</span></el-col><el-col :span="8"><i class="iconfont iconbaozheng" style="color:green;"></i><span>出行保证</span></el-col><el-col :span="8"><i class="iconfont icondianhua" style="color:#409EFF;"></i><span>7x24小时服务</span></el-col></el-row><h2 class="air-sale-title"><span class="iconfont icontejiajipiao"></span><i>特价机票</i></h2><!-- 特价机票 --><div class="air-sale"></div></section>
</template><script>
export default {}
</script><style scoped lang="less">
.air-sale{border: 1px #ddd solid;padding:20px;margin-bottom:50px;.air-sale-pic{> div{width:225px;height:140px;position: relative;overflow: hidden;img{width:100%;}.layer-bar{position:absolute;bottom:0;left:0;background: rgba(0,0,0,0.5);color:#fff;height:30px;line-height: 30px;width:100%;box-sizing: border-box;padding: 0 15px;font-size: 14px;span:last-child{font-size:18px;}}}}
}.air-sale-group{margin-top:20px;padding-top:8px;border-right:1px #eee solid;&:last-child{border-right:none;}.air-sale-row{font-size:12px;color:#666;margin-bottom:8px;.air-sale-price{color:orange;font-size: 20px;}}
}.container{width:1000px;margin:0 auto;
}.air-title{margin:15px 0;font-size:20px;font-weight: normal;color:orange;span{font-size:20px;}
}.statement{margin:15px 0;border:1px #ddd solid;background:#f5f5f5;height: 58px;padding:10px 0;box-sizing:border-box;> div{text-align: center;line-height: 38px;border-right:1px #ddd solid;&:last-child{border-right: none;}*{vertical-align: middle;}i{font-size:30px;}}
}.air-sale-title{margin:15px 0;font-size:20px;font-weight: normal;color:#409EFF;span{font-size:20px;}
}
</style>

二 封装搜索组件

1. 组件布局

新建机票搜索表单组件components/air/searchForm.vue,并替换以下布局代码 :

<template><div class="search-form"><!-- 头部tab切换 --><el-row type="flex" class="search-tab"><span v-for="(item, index) in tabs" :key="index"@click="handleSearchTab(item, index)":class="{active: index === currentTab}"><i :class="item.icon"></i>{{item.name}}</span></el-row><el-form class="search-form-content" ref="form" label-width="80px"><el-form-item label="出发城市"><!-- fetch-suggestions 返回输入建议的方法 --><!-- select 点击选中建议项时触发 --><el-autocomplete:fetch-suggestions="queryDepartSearch"placeholder="请搜索出发城市"@select="handleDepartSelect"class="el-autocomplete"></el-autocomplete></el-form-item><el-form-item label="到达城市"><el-autocomplete:fetch-suggestions="queryDestSearch"placeholder="请搜索到达城市"@select="handleDestSelect"class="el-autocomplete"></el-autocomplete></el-form-item><el-form-item label="出发时间"><!-- change 用户确认选择日期时触发 --><el-date-picker type="date" placeholder="请选择日期" style="width: 100%;"@change="handleDate"></el-date-picker></el-form-item><el-form-item label=""><el-button style="width:100%;" type="primary" icon="el-icon-search"@click="handleSubmit">搜索</el-button></el-form-item><div class="reverse"><span @click="handleReverse">换</span></div></el-form>  </div>
</template><script>
export default {data(){return {tabs: [{icon: "iconfont icondancheng", name: "单程"},{icon: "iconfont iconshuangxiang", name: "往返"}],currentTab: 0,}},methods: {// tab切换时触发handleSearchTab(item, index){},// 出发城市输入框获得焦点时触发// value 是选中的值,cb是回调函数,接收要展示的列表queryDepartSearch(value, cb){cb([{value: 1},{value: 2},{value: 3},]);},// 目标城市输入框获得焦点时触发// value 是选中的值,cb是回调函数,接收要展示的列表queryDestSearch(value, cb){cb([{value: 1},{value: 2},{value: 3},]);},// 出发城市下拉选择时触发handleDepartSelect(item) {},// 目标城市下拉选择时触发handleDestSelect(item) {},// 确认选择日期时触发handleDate(value){},// 触发和目标城市切换时触发handleReverse(){},// 提交表单是触发handleSubmit(){}},mounted() {}
}
</script><style scoped lang="less">
.search-form{border:1px #ddd solid;border-top:none;width:360px;height:350px;box-sizing: border-box;
}.search-tab{span{display: block;flex:1;text-align: center;height:48px;line-height: 42px;box-sizing: border-box;border-top:3px #eee solid;background:#eee;}.active{border-top-color: orange;background:#fff;}i{margin-right:5px;font-size: 18px;&:first-child{font-size:16px;}}
}.search-form-content{padding:15px 50px 15px 15px;position: relative;.el-autocomplete{width: 100%;}
}.reverse{position:absolute;top: 35px;right:15px;&:after,&:before{display: block;content: "";position: absolute;left:-35px;width:25px;height:1px;background:#ccc;}&:after{top:0;}&:before{top:60px;}span{display: block;position:absolute;top: 20px;right:0;font-size:12px;background: #999;color:#fff;width:20px;height:20px;line-height: 18px;text-align: center;border-radius: 2px;cursor: pointer;&:after,&:before{display: block;content: "";position: absolute;left:10px;width:1px;height:20px;background:#ccc;}&:after{top:-20px;}&:before{top:20px;}}
}
</style>

创建完成后在pages/air/index.vue中导入组件

<template>
<!-- 其他代码... --><!-- 搜索广告栏 --><el-row type="flex" justify="space-between"><!-- 搜索表单 --><SearchForm/><!-- banner广告 --></el-row><!-- 其他代码... -->
</template>
<script>
import SearchForm from "@/components/air/searchForm";export default {components: {SearchForm},
}
</script>

2.目标思路

通过用户输入数据, 组合成需要的参数 点击搜索, 跳转页面后, 传递到机票搜索结果页面,再发送请求

需要的参数包括

  • 出发地 / 出发地代码 departCity /departCode

  • 到达地 / 到达地代码 destCity / destCode

  • 出发时间 departDate

3.步骤

3.1 基本功能

  • 三个输入框绑定数据

  • 点击按钮, 打印出出全部数据作为参考

3.2 自动补全

先用死数据模拟搜索建议,显示自动补全的两个步骤

  • 声明fetch-suggestion 定义获取建议的函数
  • 在函数当中,可以接受两个参数
  1. element-ui传进来当前的输入值
  2. element-ui提供的封装好的显示列表函数,这个函数我们在形参可以随意命名,只要我们执行这个函数,并且带上结果数组就会显示一个建议列表
  • 出发地输入框弹出搜索建议

  • 到达地输入框弹出搜索建议

3.3获取真正的推荐数据

  • 使用 ajax 获取数据

    这个接口如果没有参数会获取到100条数据

  • 修改数据格式,,再进行回调渲染

    自动补全搜索建议的数组里面的对象,必须有value才可以显示出来

    配合组件的要求 (每个都需要有 value)

3.4 添加城市代号

选择一个选项的时候, 城市名作为 value 无需处理

但是城市代码code必须主动放入数据当中

  • 获取搜索建议列表时, 除了 value 值用来渲染列表需要以外, 还需要将当前城市的 code 放进去备用

  • form 数据有两个属性储存城市代号 departCode / destCode

  • 每当选中一个选项时, 同时将城市代号更新到 form 中

    • 监听 select 事件,函数可以接受一个固定的参数, 就是我们选中的那个城市的数据对象

    • 讲这个数据对象里面的 sort 放入 code 城市代码当中即可

3.5 处理日期格式

  • 使用日期选择组件(基本用法,用 v-model 绑定数据)

  • 选了日期之后, 输出的是一个日期对象

  • 需要转换为合适的格式

    • 可以尝试自己将日期对象改成 YYYY-MM-DD 的格式

    • 饿了么也有一个功能 使用value-format指定绑定值的格式, 可以使用

  • 时间格式转换的时机每次用户修改日期的时候自动触发 (监听 change 事件), 并且修改用户时间格式

3.6  使用了momentjs,这是一个第三方的包,需要先下载并且导入。

下载命令:

npm install --save moment

在组件中引入

import moment from "moment";

传入日期对象即可改变格式

moment(value).format("YYYY-MM-DD");

其他功能

优化

  • 封装获取建议函数,, 将获取出发地搜索建议和获取到达地搜索建议的函数合并

  • 输入后再激活输入建议 :trigger-on-focus="false"

  • 自动高亮第一个选项 : highlight-first-item ="true" (如果不生效请注意elementui 版本)

  • 数据来自第三方, 某些城市缺失代码, 删除获取不到 sort 的数据

    其实可以过滤, 获取简易列表时, 将所有不带有 sort 数据的城市去掉

  • 城市名称不应带有市字, 在获取列表的时候直接替换掉市字即可

    利用 replace 方法, 将数据 name 中最后一个 市字 替换成 空字符串

  • 处理用户没有选择城市,造成缺失代码的问题

    • 搜索得出建议选项的时候,默认将列表的第一项 code 数据放入 form

      默认给一个值, 如果用户自己选了, 再去覆盖

  • 思考:如果用户非要写一个市字, 可以在以下几个时间点进行处理, 只要最终发请求前处理完毕没有市字即可

    • 失去焦点

    • 跳转页面的时候

    • 页面跳转后提交搜索 ajax 的时候

    (建议在搜索时才处理,将这个处理隐藏起来不让用户感知)

三 搜索功能

1.思路

从结果出发,首先来看下我看点击表单后会发生什么事?

点击表单的搜索按钮后会跳转到该页面,并且提供了5个用于查询的参数,暂且不考虑目前有没该页面,我们可以先考虑如何给页面提供这些参数。

参数列表(重要)

  • departCity 出发城市(注意没有字)

  • departCode 出发城市代码

  • destCity 到达城市(注意没有字)

  • destCode 到达城市代码

  • departDate 出发日期

可以从查找机票城市的接口找到城市相关数据,在用户输入城市的同时获得上面的数据。

接口:http://157.122.54.189:9095/airs/city

返回结果:

{
  data: [{
    code: "440100000000",
    created_at: "2019-04-02 08:18:16",
    id: 197,
    level: "2",
    name: "广州市",
    parentCode: "440000000000",
    sort: "CAN",
    updated_at: 1558617184703
  }];
  total: 1
}

2.实现步骤

  • 获取城市数据

在data中新增变量存储表单数据 ,在data中定义需要提交的是5个参数

<script>
export default {data(){return {// 其他代码...form: {departCity: "", // 出发城市departCode: "", // 出发城市代码destCity: "",  // 到达城市destCode: "",  // 到达城市代码departDate: "", // 日期字符串},}},
}
</script>

注意在template的表单中使用v-model双向绑定数据到form的属性。

比如出发城市v-model="form.departCity"

             <el-autocomplete:fetch-suggestions="queryDepartSearch"placeholder="请搜索出发城市"@select="handleDepartSelect"class="el-autocomplete"v-model="form.departCity"></el-autocomplete>

日期departDate只需要在el-date-picker组件中使用v-model="form.departDate"进行绑定即可获得了。

  • 调用城市查询接口

使用实时查询的方式调用查询城市的接口,由于出发城市和到达城市都需要调用这个查询接口,所以把查询操作封装到一个独立函数来调用。

<script>
export default {// 其他代码...methods: {// 出发城市输入框获得焦点时触发// value 是选中的值,cb是回调函数,接收要展示的列表async queryDepartSearch(value, cb){const arr =  await this.querySearchAsync(value)if(arr.length > 0){// 不在下拉列表中选择,则默认选择第一项this.form.departCity = arr[0].value;this.form.departCode = arr[0].sort;}cb(arr)},// 目标城市输入框获得焦点时触发// value 是选中的值,cb是回调函数,接收要展示的列表async queryDestSearch(value, cb){const arr =  await this.querySearchAsync(value)if(arr.length > 0){// 不在下拉列表中选择,则默认选择第一项this.form.destCity = arr[0].value;this.form.destCode = arr[0].sort;}cb(arr)},// 查询城市接口的方法,返回promise// queryString是查询关键字querySearchAsync(queryString) {return new Promise((resolve, reject) => {// 如果关键字是空,则直接返回if(!queryString){return resolve([]);}this.$axios({url: `/airs/city`,params: {name: queryString}}).then(res => {const {data} = res.data;// 下拉提示列表必须要有value字段const arr = data.map(v => {return {...v,value: v.name.replace("市", "")}});resolve(arr);});});},// 其他代码...}}
</script>
  • 下拉数据选中赋值

针对城市下拉框选项选中的事件处理,我们应该把选中的选项当做是当前的数据

<script>export default {// 其他代码...methods: {// 其他代码...// 出发城市下拉选择时触发// item代表当前选中项handleDepartSelect(item) {this.form.departCity = item.value;this.form.departCode = item.sort;},// 目标城市下拉选择时触发// item代表当前选中项handleDestSelect(item) {this.form.destCity = item.value;this.form.destCode = item.sort;},// 确认选择日期时触发handleDate(value){this.form.departDate = moment(value).format("YYYY-MM-DD");},// 其他代码...}}
</script>
  • 搜索跳转

下面来实现页面跳转,需要在URL中把5个参数都到带过去给搜索结果页/air/flights

<script>export default {// 其他代码...methods: {// 其他代码...// 提交表单是触发handleSubmit(){// 表单验证数据const rules = {depart: {value: this.form.departCity, message: "请选择出发城市"},dest: {value: this.form.destCity, message: "请选择到达城市"},departDate: {value: this.form.departDate, message: "请选择出发时间"},}let valid = true; // 表单验证结果Object.keys(rules).forEach(v => {// 只要有一个结果不通过,就停止循环if(!valid) return;const item = rules[v];// 数据字段为空if(!item.value){valid = false;this.$confirm(item.message, '提示', {confirmButtonText: '确定',showCancelButton: false,type: 'warning'})}});// 不通过验证,不需要往下执行if(!valid) return;this.$router.push({path: "/air/flights",query: this.form})}}}
</script>

/air/flights页面暂时还没创建,不过只要能从URL中看到参数正确传递即可。

  • 城市切换

这是个把出发城市和到达城市对换位置的功能,实现起来非常简单,把form的数据对调换就可以了

调换的事件函数

<script>export default {// 其他代码...methods: {// 其他代码...// 触发和目标城市切换时触发handleReverse(){const { departCity, departCode, destCity, destCode} = this.form;this.form.departCity = destCity;this.form.departCode = destCode;this.form.destCity = departCity;this.form.destCode = departCode;},}}
</script>
  • 往返

目前接口不支持往返,需要添加一个提示

// tab切换时触发
handleSearchTab(item, index){if(index === 1){this.$confirm("目前暂不支持往返,请使用单程选票!", '提示', {confirmButtonText: '确定',showCancelButton: false,type: 'warning'})}
},

3.总结

  1. 关键点在于如何获取跳转链接需要的5个参数

  2. el-autocomplete组件的使用(查看文档)

  3. 使用momentjs进行时间转换

  4. 表单自定义验证

四 特价机票

1. 思路

思路: 其实就是获取数据布局, 点击的结果就是模拟一个搜索

  1. 特价机票布局 :注意链接跳转时的数据拼接

  2. 请求数据接口 :在机票首页 created/mounted 生命周期里面获取数据 赋值到 data sales 然后遍历渲染页面即可

2.实现步骤

2.1 特价机票布局

新增特价机票布局和模拟数据。

pages/air/index.vue

<template><section class="container"><!-- 其他代码... --><!-- 特价机票 --><div class="air-sale"><el-row type="flex" class="air-sale-pic" justify="space-between"><el-col :span="6" v-for="(item, index) in sales" :key="index"><nuxt-link :to="`/air/flights?departCity=${item.departCity}&departCode=${item.departCode}&destCity=${item.destCity}&destCode=${item.destCode}&departDate=${item.departDate}`"><img :src="item.cover"/><el-row class="layer-bar" type="flex" justify="space-between"><span>{{item.departCity}}-{{item.destCity}}</span><span>¥699</span></el-row></nuxt-link></el-col></el-row></div></section>
</template><script>
// 其他代码...
export default {data(){return {sales: [{cover: "https://gss0.bdstatic.com/94o3dSag_xI4khGkpoWK1HF6hhy/baike/s%3D220/sign=9154c841bcfd5266a32b3b169b199799/3812b31bb051f8199687c7e0d0b44aed2f73e7fe.jpg",departCity: "广州",departCode: "CAN",departDate: "2019-06-17",destCity: "上海",destCode: "SHA",price: 760}]}},// 其他代码...
}
</script>

注意跳转链接的nuxt-link :to="/air/flights?xxxx的参数拼接

2.2 请求数据接口

<script>
import SearchForm from "@/components/air/searchForm";export default {data(){return {sales: [] // 去除模拟数据}},mounted(){this.$axios({url: `/airs/sale`}).then(res => {this.sales = res.data.data;});},// 其他代码...
}
</script>

五 效果图

闲云旅游项目开发-(第四篇:机票首页/机票搜索功能(`el-autocomplete`远程搜索组件)/moment.js的使用/日期选择组件el-date-picker)相关推荐

  1. 闲云旅游项目开发-(第一篇:使用Element-ui实现主页轮播图)

    业务需求: 初始化布局 页头页脚公共组件 首页轮播图 一 初始化默认全局布局 nuxtjs 提供了一个公共组件 layouts/default.vue,相当于以前的 app.vue .该布局组件默认作 ...

  2. 闲云旅游项目开发-(第二篇:实现登录功能,使用vuex的store管理数据)

    目录 一 登录注册页布局 二 登录功能 1.思路 2.实现步骤 2.1 新建登录表单组件 2.2 表单数据绑定及验证 2.3 登录接口 3.总结 三  使用vuex/store管理数据 1.思路 2. ...

  3. 项目开发流程_绿维文旅:旅游项目开发模式与流程

    一.旅游项目开发模式 旅游综合开发是立足旅游项目自有资源基础,以旅游产业为主导,以市场为导向,以资本为驱动,以资源整合为核心,通过集中土地.资本.技术.交通.劳动力等生产要素,推进土地开发.交通建设. ...

  4. 基于GBT28181:SIP协议组件开发-----------第四篇SIP注册流程eXosip2实现(一)

    原创文章,引用请保证原文完整性,尊重作者劳动,原文地址http://www.cnblogs.com/qq1269122125/p/3945294.html. 上章节讲解了利用自主开发的组件SIP组件l ...

  5. 仿LOL项目开发第四天

    ---恢复内容开始--- 仿LOL项目开发第四天 by草帽 上节讲了几乎所有的更新版本的逻辑,那么这节课我们来补充界面框架的搭建的讲解. 我们知道游戏中的每个界面都有自己的一个类型:比如登陆界面,创建 ...

  6. Agv、Rgv 车辆控制调度系统开发第四篇

    Agv.Rgv 车辆控制调度系统开发第四篇 车辆调度模拟器 前言 一.车辆模拟器是什么? 二.如何做模拟器 1.动作仿真模拟器 2.完全仿真模拟器 总结 下期预告 系列文章链接 其他文章 新篇章 前言 ...

  7. 动力节点CRM项目开发【准备篇】

    CRM项目开发[准备篇] (参考B站视频CRM项目) 01-基本技术框架 视图层(View):展示数据,负责跟用户交互 html,css,js,jquery,bootstrap 控制层(Control ...

  8. 重构ElementUI解决DatePicker日期选择组件修改父组件placement参数问题[Vue.js项目实践: 新冠自检系统]

    新冠疫情自我检测系统网页设计开发文档 Sylvan Ding 的第一个基于 Vue.js 的项目. 本项目所提供的信息,只供参考之用,不保证信息的准确性.有效性.及时性和完整性,更多内容请查看国家卫健 ...

  9. vue日期选择组件_一个Vue组件,为波斯开发人员提供日期选择器

    vue日期选择组件 Vue波斯日期选择器 (vue persian datepicker) This is a Jalali date picker component for Vue. 这是Vue的 ...

最新文章

  1. pandas使用pct_change函数计算数据列的百分比变化:计算当前元素和前一个元素之间的百分比变化(包含NaN值的情况以及数据填充方法)
  2. 2021毛纲源常考题型解题方法_总结2021年考研数学六大常考题型
  3. centos下pg_dump的服务器版本不匹配问题
  4. mysql数据库varchar的区别_MySQL数据库char与varchar的区别分析及使用建议
  5. 如何按 value 对 dictionary 进行排序?
  6. sqlserver注释巧清理
  7. css 友情链接效果,友链样式与位置很重要!
  8. 【java8新特性】——默认方法(五)
  9. 小爬爬1:jupyter简单使用爬虫相关概念
  10. Python写数据结构:循环队列
  11. Visual Studio 开发(三):Visual Studio 使用时常见问题解决方案
  12. latex 图、表 中英文标题
  13. 2D渲染pixi项目实战总结
  14. 将MATLAB任务栏变成白色的图标恢复
  15. 正六面体染色(java)
  16. Milvus 群星闪耀时|又一个小目标达成 :社区正式突破 15,000 星!
  17. 2021-10-21《能源与节能》能源环保省级期刊
  18. Python输入一个字符串,输出其中每个字符的出现次数。要求使用标准库collotections中的Counter类...
  19. 微信小程序中使用阿里矢量字体图标
  20. 爬取微信公众号详情页

热门文章

  1. 《重学Java系列》之 泛型(下)
  2. HW-2022 0day Nday漏洞 汇总 0728
  3. 兮米安装包制作工具绿色版
  4. 《Java SE实战指南》05-09:语句(Statements)
  5. Linux 的基本使用(上)· 背景故事 · 环境搭建 · 常用命令 vim less cp mv等(基本能覆盖 Linux 日常使用80%场景)· Linux 文件结构的意义 · 相对路径和绝对路径
  6. 分类型变量python聚类分析_用python对包含分类变量和数值变量的数据进行聚类的最佳方法是什么...
  7. 关于mysql错误的是_下面关于MySQL描述错误的是( )。_学小易找答案
  8. 爱情公寓第二季 MKV高清下载地址 普清地址也有哦!
  9. JAVA集合一些面试题
  10. 位图索引Bitmap indexes(数据库索引)