uni-app移动应用开发(微课版)课件 项目七 一个简单的美食搜索小程序_第1页
uni-app移动应用开发(微课版)课件 项目七 一个简单的美食搜索小程序_第2页
uni-app移动应用开发(微课版)课件 项目七 一个简单的美食搜索小程序_第3页
uni-app移动应用开发(微课版)课件 项目七 一个简单的美食搜索小程序_第4页
uni-app移动应用开发(微课版)课件 项目七 一个简单的美食搜索小程序_第5页
已阅读5页,还剩64页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

项目七一个简单的美食搜索小程序

项目七一个简单的美食搜索小程序

项目任务:任务1实现首页任务2实现餐厅详情页面任务3实现地图定位页面任务4实现登录页面01任务1实现首页

7.1.1首页布局

使用HBuilderX创建一个名为uniappdemo7的新项目。为了在项目中方便使用扩展组件,项目创建时选择创建uni-ui项目。创建完成后首先在pages目录下新建index/index.vue文件。创建时勾选“在pages.json中注册”复选框以便在pages.json文件中配置页面路由,pages.json中pages节点路由配置如下。{ "pages":[{ "path":"pages/index/index", "style":{ "navigationBarTitleText":"美食搜索首页", "enablePullDownRefresh":false } }]}

7.1.1首页布局

在index.vue文件的template和style标签中输入如下代码进行页面布局和样式设置。其中,scroll-view组件用于显示餐厅列表信息。<template> <viewclass="app"style="{overflow:'auto'}"> <viewclass="top"> <viewclass="search"> <inputtype="text"placeholder="搜索餐厅"/> </view> <buttonclass="search-btn"type="primary"size="mini"@click="search">搜索</button> </view> <scroll-viewclass="content":scroll-y="true"@scrolltolower="scrollToLower"> <viewclass="DataItem"> <imgclass="homeImg"src="../../static/restaurant.jpg"alt="phtoto"/> <viewclass="DataItem-content"> <viewclass="DataItem-content-name">餐馆1</view> <viewclass="DataItem-content-rate">¥100</view> <viewclass="DataItem-content-type">粤菜</view> <viewclass="DataItem-content-type">地址1</view> </view> </view><!--剩余代码见下一页-->

7.1.1首页布局 <viewclass="DataItem"> <imgclass="homeImg"src="../../static/restaurant.jpg"alt="phtoto"/> <viewclass="DataItem-content"> <viewclass="DataItem-content-name">餐馆1</view> <viewclass="DataItem-content-rate">¥100</view> <viewclass="DataItem-content-type">粤菜</view> <viewclass="DataItem-content-type">地址1</view> </view> </view> </scroll-view> </view></template><stylelang="scss"scoped> .app{ min-height:100rpx; .top{ padding:3rpx0; display:flex; align-items:center; .search{ height:50rpx; margin-left:4rpx;/*剩余代码见下一页*/

7.1.1首页布局 display:flex; align-items:center; flex:1; border-radius:1rpx; } .search-btn{ margin:020rpx; } } } .searchinput{ width:100%; margin-left:4rpx; } .searchinput::-webkit-input-placeholder{ color:#999; line-height:5rpx; } .content{ height:1000rpx; } .DataItem{ background-color:#fff; display:flex; padding:04rpx;/*剩余代码见下一页*/

7.1.1首页布局 align-items:center; font-size:12px; margin-bottom:3rpx; color:#999; .homeImg{ width:4.4rem; height:3.4rem; margin-right:0.266667rem; } .DataItem-content{ flex:1; .DataItem-content-name{ font-size:14px; margin-top:0.233333rem; width:4rem; overflow:hidden; word-break:keep-all; white-space:nowrap; text-overflow:ellipsis; color:#333; font-size:14px; font-weight:600 }/*剩余代码见下一页*/

7.1.1首页布局 .DataItem-content-rate{ margin:0.263333rem0; } .DataItem-content-type{ padding-bottom:0.2rem; } } }</style>在微信开发者工具中布局效果。

7.1.2首页动态加载餐厅数据

首页布局完成后,下一步将动态加载餐厅列表数据。这里数据采用静态JS模拟实现,真实开发中可采用uni.requestAPI向服务端发送请求获取数据。在pages/index目录下创建data.js文件,文件内添加16条静态模拟数据,单条静态数据格式如下。exportdefault[{ "cid":"1", "restaurant":"餐厅1",

"type":"粤菜", "rate":"4.8", "avgPrice":"80", "pic":"../../static/restaurant.jpg", "address":"广东省广州市番禺区迎宾路557-567号", "product":[ {"id":"1","name":"菜品1","num":0,"price":55,image:"../../static/caipin.jpg"}, {"id":"2","name":"菜品2","num":0,"price":65,image:"../../static/caipin.jpg"}, {"id":"3","name":"菜品3","num":0,"price":75,image:"../../static/caipin.jpg"}, {"id":"4","name":"菜品4","num":0,"price":85,image:"../../static/caipin.jpg"}, {"id":"5","name":"菜品5","num":0,"price":80,image:"../../static/caipin.jpg"}, ]}]

7.1.2首页动态加载餐厅数据

下面在index.vue文件的script标签中添加如下代码加载餐厅数据。import{onLoad,onPullDownRefresh}from'@dcloudio/uni-app'import{reactive,ref}from'vue';importdatafrom'/pages/index/data/data.js'//模拟数据源letpageCurrent=ref(1)//分页查询页数letrestArr=reactive([])//餐馆列表数据letpageSize=10/**scroll-view监听滚动条到底部*/functionscrollToLower(){ //滚动条到底部加载下一页数据 pageCurrent.value=pageCurrent.value+1 getRestaurantData(pageCurrent.value,false)}onLoad((option)=>{ //获取餐馆数据列表 getRestaurantData(pageCurrent.value,true)})functiongetRestaurantData(pageCurrent,flag){ //flag为真,代表下拉操作或初始化加载数据清空homeArr, //否则为滚动条到底部加载下一页数据 if(flag){ homeArr.length=0 }//剩余代码见下一页

7.1.2首页动态加载餐厅数据 //分页查询获取符合条件的数据id letpageData=data.filter((item,index)=>{ constidx=index-(pageCurrent-1)*pageSize returnidx<pageSize&&idx>=0 }) if(pageData.length==0){ //pageData长度0,则数据全部加载完成,否则继续加载下一页数据 if(!flag){ uni.showToast({ title:"数据已加载到底" }) } }else{ for(letitemofpageData){ restArr.push({ pic:item.pic, restaurant:item.restaurant, rate:item.rate, avgPrice:item.avgPrice, type:item.type, cid:item.cid, address:item.address, product:duct

}) } }}

7.1.2首页动态加载餐厅数据

上述代码使用onLoad函数,在页面加载时调用getRestaurantData方法从data.js中加载数据。餐厅数据使用分页加载模式,每一页加载10条数据。同时使用scroll-view组件的scrolltolower事件监听滚动条是否到达底部,如果滚动条到达底部则加载下一页数据。餐厅数据使用restArr响应式数据存储。

下面对restArr中的数据进行页面展现。由于每一条餐厅数据内容格式相同,这里使用自定义组件child.vue来封装展现每一条餐厅数据,涉及父子组件之间的传值问题。

在uniappdemo7项目下新建components目录,在components目录下新建child/child.vue文件,在其中输入如下代码。child.vue中使用defineProps来接收index.vue传递的参数,参数名称为obj,参数类型为Object。样式.DataItem-content为index.vue中的原有代码,直接复制过来并删除index.vue中的原有代码。

7.1.2首页动态加载餐厅数据<template> <viewclass="DataItem"> <imgclass="homeImg":src="obj.pic"alt="phtoto"/> <viewclass="DataItem-content"> <viewclass="DataItem-content-name">{{obj.restaurant}}</view> <viewclass="DataItem-content-rate">¥{{obj.avgPrice}}</view> <viewclass="DataItem-content-type">{{obj.type}}</view> <viewclass="DataItem-content-type">{{obj.address}}</view> </view> </view></template><scriptsetup> constprops=defineProps({ obj:{ type:Object, required:false } })</script><stylelang="scss"scoped> .DataItem{ background-color:#fff; display:flex; padding:04rpx; align-items:center; font-size:12px;/*剩余代码见下一页*/

7.1.2首页动态加载餐厅数据 margin-bottom:3rpx; color:#999; .homeImg{ width:4.4rem; height:3.4rem; margin-right:0.266667rem; } .DataItem-content{ flex:1; .DataItem-content-name{ font-size:14px; margin-top:0.233333rem; width:4rem; overflow:hidden; word-break:keep-all; white-space:nowrap; text-overflow:ellipsis; color:#333; font-size:14px; font-weight:600 }/*剩余代码见下一页*/

7.1.2首页动态加载餐厅数据 .DataItem-content-rate{ margin:0.263333rem0; } .DataItem-content-type{ padding-bottom:0.2rem; } } }</style>

注意:新建child.vue文件时,在新建页面窗口不要勾选“在pages.json中注册”复选框。否则在后续调试过程中可能会出现“Error:module‘pages/child/child.js‘isnotdefined,requireargsis‘pages/child/child.js”的错误。

7.1.2首页动态加载餐厅数据

然后修改index.vue中代码,将scroll-view组件中代码替换成如下黑体代码,通过参数obj向child.vue组件传值。传值时child标签中的参数名称必须和child.vue中defineProps内部的参数名称保持一致,否则数据不能正常接收。<scroll-viewclass="content":scroll-y="true"@scrolltolower="scrollToLower"> <viewv-if="restArr.length"> <viewv-for="(item,index)inrestArr":key="index"> <child:obj="item"></child> </view> </view></scroll-view>

7.1.2首页动态加载餐厅数据

在微信开发者工具中效果。

7.1.3首页餐厅搜索功能

下面对index.vue中代码进一步修改,实现餐厅搜索功能。用户可以在列表上部输入框输入餐厅名称,单击“搜索”按钮,即可过滤查看具体某个餐厅信息。

在index.vue文件内部script标签中添加如下代码,定义restaurant响应式数据,并实现search方法内部逻辑。当用户单击“搜索”按钮时,对原始数据data进行过滤,然后从第一页开始加载过滤后的数据。letrestaurant=ref("")//餐馆名称functionsearch(){ pageCurrent.value=1 homeArr.length=0 getMerchantData(pageCurrent.value,restaurant.value,true)}

修改index.vue文件内部template标签内innput输入框代码,在input组件上使用v-model绑定restaurant响应式数据。<viewclass="search"> <inputtype="text"v-model="restaurant"

placeholder="搜索餐厅"/></view>

7.1.3首页餐厅搜索功能

此时,在index.vue页面上部input输入框中输入“餐厅1”单击“搜索”按钮。搜索效果如下。

7.1.4跳转餐厅详情页面

当用户单击餐厅列表中某个餐厅时,页面能够跳转到该餐厅的详情页面,并将该餐厅对应的数据传递过去。实现此功能需使用uni.navigateToAPI进行页面跳转和传值。传值时可直接在url路径后使用?拼接传递的数据。

修改index.vue文件内部的template标签中scroll-view内部代码,在其中给每个餐厅的view组件上添加click函数,如下黑体代码。<scroll-viewclass="content":scroll-y="true"@scrolltolower="scrollToLower"> <viewv-if="homeArr.length"> <view@click="goToRestaurant(item)"

v-for="(item,index)inhomeArr" :key="index"> <child:obj="item"></child> </view> </view></scroll-view>

7.1.4跳转餐厅详情页面

餐厅详情页面路径为/pages/restaurant/restaurant。在index.vue文件内部的script标签中添加goToRestaurant函数,代码如下。其中餐厅数据采用JSON字符串形式传递,并使用了encodeURIComponent函数对JSON字符串进行封装。functiongoToRestaurant(obj){ uni.navigateTo({ url:'/pages/restaurant/restaurant?obj=' +encodeURIComponent(JSON.stringify(obj)) })}02任务2实现餐厅详情页面

7.2.1餐厅详情页面布局

在pages目录下新建restaurant/restaurant.vue文件。创建时勾选“在pages.json中注册”复选框以便在pages.json文件中配置页面路由,pages.json中pages节点路由配置如黑体代码所示。"pages":[{ "path":"pages/index/index", "style":{ "navigationBarTitleText":"美食搜索首页", "enablePullDownRefresh":false }},{ "path":"pages/restaurant/restaurant", "style": { "navigationBarTitleText":"餐厅详情", "enablePullDownRefresh":false }}]

7.2.1餐厅详情页面布局

在restaurant.vue文件的template和style标签中输入如下代码进行页面布局和样式设置。其中,<viewclass="header">组件用于显示餐厅图片、名称、评分、地址等详细信息,scroll-view组件内部用于显示餐厅菜品信息。<template> <viewclass="restaurant"> <view

class="header"> <imgclass="header-img"src="../../static/restaurant.jpg"alt="餐厅图片"/> <viewclass="restaurant-content"> <view>餐厅1</view> <uni-rateclass="restaurant-content-data":readonly="true"/>4.8分

<viewstyle="display:flex;flex:0;"> <view>地址:广东省广州市番禺区迎宾路557-567号</view> <imagesrc="../../static/marker.png" style="height:35rpx;width:35rpx"></image> </view> </view> </view> <view> <scroll-viewstyle="height:870rpx":scroll-y="true"> <viewclass="goods-detail"> <viewclass="detail-left"><!--剩余代码见下一页-->

7.2.1餐厅详情页面布局 <viewclass="goods-left"> <imagesrc="../../static/caipin.jpg" style="width:150rpx;height:140rpx;"></image> </view> <viewclass="goods-name"> <textstyle="font-size:25rpx;">菜品1</text> <textclass="goods-price">55元/件</text> </view> </view> <viewclass="detail-right"> <textclass="reduce">-</text> <textclass="num">0</text> <text

class="add">+</text> </view> </view> <viewclass="goods-detail"> <viewclass="detail-left"> <viewclass="goods-left"> <imagesrc="../../static/caipin.jpg" style="width:150rpx;height:140rpx;"></image> </view> <viewclass="goods-name"> <textstyle="font-size:25rpx;">菜品1</text> <textclass="goods-price">55元/件</text> </view> </view><!--剩余代码见下一页-->

7.2.1餐厅详情页面布局 <viewclass="detail-right"> <textclass="reduce">-</text> <textclass="num">0</text> <text

class="add">+</text> </view> </view> </scroll-view> <viewclass="end"> <viewclass="end-left"> <view>

总计:<textstyle="color:orangered;font-weight:bold;">

0元</text> </view> </view> <viewclass="end-right">

去结算(0) </view> </view> </view> </view></template><stylelang="scss"scoped> .restaurant{ min-height:100vh; background-color:#f2f2f2; font-size:24rpx;/*剩余代码见下一页*/

7.2.1餐厅详情页面布局 .header{ background-color:#333; display:flex; align-items:center; padding:0.266667rem0.4rem; .header-img{ width:2.4rem; height:1.6rem; margin-right:0.266667rem; border-radius:0.133333rem; } .restaurant-content{ flex:1; color:#fff; .restaurant-content-data{ margin-top:0.266667rem } } } } .goods-detail{ line-height:70rpx; display:flex; padding:20rpx15rpx20rpx20rpx; justify-content:space-between; align-items:center;/*剩余代码见下一页*/

7.2.1餐厅详情页面布局 .detail-left{ display:flex; .goods-left{ display:flex; align-items:center; } .goods-name{ display:flex; justify-content:space-around; flex-direction:column; margin-left:25rpx; .goods-price{ font-size:25rpx; color:red; } } } .detail-right{ text{ width:55rpx; line-height:55rpx; text-align:center; display:inline-block; margin-right:10rpx; }/*剩余代码见下一页*/

7.2.1餐厅详情页面布局 .add{ color:red; margin-right:20rpx; } } } .end{ width:100%; height:100rpx; position:fixed; bottom:80rpx; left:0; display:flex; align-items:center; .end-left{ width:75%; display:flex; justify-content:space-between; padding:025rpx; .end-flex{ display:flex; align-items:center; } }/*剩余代码见下一页*/

7.2.1餐厅详情页面布局 .end-right{ width:25%; line-height:90rpx; background-color:red; text-align:center; color:white; } }</style>在微信开发者工具中布局效果。

7.2.2动态加载餐厅详细信息

餐厅详情页面布局完成后,下一步将动态加载餐厅详细信息。在restaurant.vue中<viewclass="header">组件内部代码替换成如下黑体代码,动态加载餐厅详细信息。<viewclass="header"> <imgclass="header-img":src="obj.pic"alt="餐厅图片"/> <viewclass="restaurant-content"> <view>{{obj.restaurant}}</view> <uni-rateclass="restaurant-content-data"v-model="obj.rate" :readonly="true"/>{{obj.rate}}分

<viewstyle="display:flex;flex:0;"> <view>地址:{{obj.address}}

</view> <imagesrc="../../static/marker.png" style="height:35rpx;width:35rpx"></image> </view> </view></view>

7.2.2动态加载餐厅详细信息

在restaurant.vue中的script标签中添加代码动态接收index.vue传过来的参数。import{onLoad}from'@dcloudio/uni-app'import{reactive,computed}from'vue';letobj=reactive({ pic:"", restaurant:"", rate:"", avgPrice:"", type:"", cid:"", address:""})onLoad((option)=>{ //接收传过来的数据赋值给obj letrecData=JSON.parse(decodeURIComponent(option.obj)) obj.pic=recData.pic obj.restaurant=recData.restaurant obj.rate=recData.rate obj.avgPrice=recData.avgPrice obj.type=recData.type obj.cid=recData.cid obj.address=recData.address})

7.2.3动态加载餐厅菜品

餐厅菜品存在于index.vue传参的product属性中,product属性数据如下。"product":[

{"id":"1","name":"菜品1","num":0,"price":55,image:"../../static/caipin.jpg"},

{"id":"2","name":"菜品2","num":0,"price":65,image:"../../static/caipin.jpg"},

{"id":"3","name":"菜品3","num":0,"price":75,image:"../../static/caipin.jpg"},

{"id":"4","name":"菜品4","num":0,"price":85,image:"../../static/caipin.jpg"},

{"id":"5","name":"菜品5","num":0,"price":80,image:"../../static/caipin.jpg"},]

在显示时还需考虑之前用户是否已选择某些菜品,如用户已选择某些菜品,菜品的num属性并不一定为0。这里将用户选择的菜品保存在本地缓存中,如果用户初次使用,未选择任何菜品,则餐厅菜品使用product属性的默认值,所有菜品的num属性都为0。如果用户不是初次使用,已选择一些菜品,那么需要根据本地缓存中的数据实时更新对应菜品的num属性值。本地缓存中数据格式同data.js,也是一个数组,只不过每个菜品的num值不同。

7.2.3动态加载餐厅菜品

将restaurant.vue中的scroll-view标签内部原有代码替换成如下黑体代码。<scroll-viewstyle="height:870rpx":scroll-y="true">

<viewclass="goods-detail"v-for="(item,index)induct"

:key="index">

<viewclass="detail-left">

<viewclass="goods-left">

<image:src="item.image"

style="width:150rpx;height:140rpx;"></image>

</view>

<viewclass="goods-name">

<textstyle="font-size:25rpx;">{{}}</text>

<textclass="goods-price">{{item.price}}元/件</text>

</view>

</view>

<viewclass="detail-right">

<textclass="reduce"@click="reduce(item)">-</text>

<textclass="num">{{item.num}}</text>

<text@click="add(item)"class="add">+</text>

</view>

</view></scroll-view>

7.2.3动态加载餐厅菜品

在restaurant.vue中的script标签中添加如下黑体代码,动态加载菜品信息。import{onLoad}from'@dcloudio/uni-app'import{reactive,computed}from'vue';letobj=reactive({ pic:"", restaurant:"", rate:"", avgPrice:"", type:"", cid:"", address:"", product:[]})onLoad((option)=>{ //接收传过来的数据赋值给obj letrecData=JSON.parse(decodeURIComponent(option.obj)) obj.pic=recData.pic obj.restaurant=recData.restaurant obj.rate=recData.rate obj.avgPrice=recData.avgPrice obj.type=recData.type obj.cid=recData.cid obj.address=recData.address//剩余代码见下一页

7.2.3动态加载餐厅菜品 //页面加载获取缓存的数据

uni.getStorage({ key:"store", success:(res)=>{//如果缓存存在,更新本餐厅已选择的菜品数量

if(res.data){ letgetFlag=false for(letitemofres.data){ if(item.cid==recData.cid){

//有本餐厅选择的菜品

duct=duct getFlag=true } } if(getFlag==false){

//没有本餐厅选择的菜品

duct=recDduct } }else{ duct=recDduct } }, fail:(res)=>{//如果缓不存存在,使用recData数据

duct=recDduct } })})

7.2.4对菜品操作按钮添加业务逻辑

菜品列表中每道菜品右侧都对应了“+”和“-”两个操作按钮供用户新增和删除菜品。这里对“+”和“-”两个操作按钮添加相应的业务逻辑代码。

1.“+”按钮的业务逻辑“+”按钮的业务逻辑如下:当用户单击“+”按钮时,应首先读取本地缓存,检查缓存中是否有菜品选择数据,如果有进一步确定是否是本餐厅的菜品选择数据,如果是就直接更新对应菜品的num值,存入本地缓存。如果不是则在缓存中新增一个数组元素用于保存本餐厅选择的菜品,存入本地缓存。如果缓存中没有任何数据,则也在缓存中新增一个数组元素用于保存本餐厅选择的菜品,存入本地缓存。“+”按钮对应的add函数实现代码如下。

7.2.4对菜品操作按钮添加业务逻辑functionadd(item){ letnum=item.num item.num=num+1 //获取缓存的数据

uni.getStorage({ key:"store", success:(res)=>{ letresData=res.data if(resData){ letgetFlag=false for(letresDataItemofresData){ //如果缓存中有该餐厅点菜数据,则更新num if(resDataItem.cid==obj.cid){ getFlag=true for(letitem1ofresDataIduct){ if(item1.id==item.id){ item1.num=item.num } } } }//剩余代码见下一页

7.2.4对菜品操作按钮添加业务逻辑 //如果缓存中没有该餐厅点菜数据,则resData数组中新增该餐厅obj if(getFlag==false){ resData.push(obj) } } //console.log(resData) //将新的数据存入缓存

uni.setStorage({ key:"store", data:resData, }) }, fail:()=>{//缓存中没有数据,直接存入该餐厅obj letarray=[] array.push(obj) uni.setStorage({ key:"store", data:array, }) } })}

7.2.4对菜品操作按钮添加业务逻辑

2.“-”按钮的业务逻辑“-”按钮的业务逻辑如下:当用户单击“-”按钮时,应首先读取本地缓存,如果本地缓存没有数据或没有本餐厅选择的菜品数据,则本餐厅所有菜品num值为0,单击“-”按钮则提示“不能减少数量”。如果本地缓存中有本餐厅选择的菜品数据,则对应的菜品num值减一,然后还需确认菜品num值减一后本餐厅是否还选择了其他菜品,如果没有则清空缓存中的本餐厅数据,否则将num值减一后的数据存入本地缓存中。“-”按钮对应的reduce函数实现代码如下。

7.2.4对菜品操作按钮添加业务逻辑functionreduce(item){ letnum=item.num //如果商品数量大于等于1,则减一

if(num>=1){ num-=1 }else{ //如果商品数量等于0,则提示不能减少数量了

uni.showToast({ title:"不能减少数量" }) } //更新商品数量

item.num=num //获取缓存的购物车数据

uni.getStorage({ key:"store", success:(res)=>{//缓存中有数据

letresData=res.data if(resData){ //更新resData中菜品数量num for(letresDataItemofresData){ if(resDataItem.cid==obj.cid){//剩余代码见下一页

7.2.4对菜品操作按钮添加业务逻辑 for(letitem1ofresDataIduct){ if(item1.id==item.id){ item1.num=num } } } } //当该餐厅没有点菜时,清除该餐厅缓存数据

letremoveFlag=true for(letresDataItemofresData){ if(resDataItem.cid==obj.cid){ for(letresDataItemEleofresDataIduct){ if(resDataItemEle.num!=0){ removeFlag=false break } } } }//剩余代码见下一页

7.2.4对菜品操作按钮添加业务逻辑 if(removeFlag==true){ for(letindexinresData){ if(resData[index].cid==obj.cid){ resData.splice(resData[index],1) } } } } //console.log(resData) //将新的数据存入缓存 uni.setStorage({ key:"store", data:resData, }) } })}

7.2.5动态计算选择菜品的数量和总计金额

当用户单击“+”和“-”两个操作按钮时,如果操作成功则页面下方“去结算”按钮括号中的选择菜品的数量和总计金额也应该同步更新,注意这里选择菜品的数量和总计金额并不只针对当前餐厅来说,应该显示用户在所有餐厅中选择的菜品数量和总计金额,类似于购物车功能。

以动态计算选择菜品的数量为例,实现思路如下:可将选择菜品的数量分为两部分,一部分是当前餐厅的选择菜品的数量,一部分是其他所有餐厅的选择菜品的数量,用户操作只会对当前餐厅的选择菜品的数量产生影响,其他所有餐厅的选择菜品的数量是不会改变的。因此可以在页面加载时就从本地缓存获取缓存数据,计算当前餐厅的选择菜品的数量和其他所有餐厅的选择菜品的数量这两部分数值,然后利用Vue中计算属性实时监控单击“+”和“-”两个操作按钮更新当前餐厅的选择菜品的数量。该思路也适用于动态计算总计金额。

7.2.5动态计算选择菜品的数量和总计金额<viewclass="end">

<viewclass="end-left">

<view>

总计:<textstyle="color:orangered;font-weight:bold;">

{{totalPrice}}元</text>

</view>

</view>

<viewclass="end-right"@click="payMoney">

去结算({{totalNum}})

</view></view>

此功能具体实现代码如下,首先将restaurant.vue中的<viewclass="end">标签内部原有代码替换成如下黑体代码。

7.2.5动态计算选择菜品的数量和总计金额

然后在restaurant.vue中的script标签中添加如下黑体代码。import{ref,reactive,computed}from'vue';lettotalPriceOther=ref(0)//除当前餐厅外其他所有餐厅的订餐金额lettotalNumOther=ref(0)//除当前餐厅外其他所有餐厅的订餐数量onLoad((option)=>{ //接收传过来的数据赋值给obj letrecData=JSON.parse(decodeURIComponent(option.obj)) obj.pic=recData.pic obj.restaurant=recData.restaurant obj.rate=recData.rate obj.avgPrice=recData.avgPrice obj.type=recData.type obj.cid=recData.cid obj.address=recData.address //页面加载获取缓存的数据

uni.getStorage({ key:"store", success:(res)=>{//如果缓存存在,更新本店已选择的菜品数量

console.log(res.data) if(res.data){ letgetFlag=false for(letitemofres.data){//剩余代码见下一页

7.2.5动态计算选择菜品的数量和总计金额 if(item.cid==recData.cid){//有本店选择的菜品

duct=duct getFlag=true } } if(getFlag==false){//没有本店选择的菜品

duct=recDduct } //计算除当前餐厅外其他所有餐厅的订餐金额和订餐数量

lettotalPriceOthertemp=0 lettotalNumOthertemp=0 for(letitemofres.data){ if(item.cid!=recData.cid){ for(letproductItemofduct){ totalPriceOthertemp=totalPriceOthertemp+ productItem.num*productItem.price totalNumOthertemp=totalNumOthertemp +productItem.num } } } totalPriceOther.value=totalPriceOthertemp totalNumOther.value=totalNumOthertemp }else{ duct=recDduct } },//剩余代码见下一页

7.2.5动态计算选择菜品的数量和总计金额 fail:(res)=>{//如果缓不存存在,使用recData数据

duct=recDduct } })})lettotalNum=computed(()=>{ //设置totalNum为计算属性,实时计算购买商品总数量

lettotalNumSelf=0//本店购买商品总数量

duct.map(item=>{ totalNumSelf+=item.num }) returntotalNumOther.value+totalNumSelf})lettotalPrice=computed(()=>{ //设置totalPrice为计算属性,实时计算购买商品总金额

lettotalPriceSelf=0//本店购买商品总金额

duct.map(item=>{ totalPriceSelf+=item.num*item.price }) returntotalPriceOther.value+totalPriceSelf})functionpayMoney(){ uni.showToast({ title:"付款总计"+totalPrice.value+"元" })}

7.2.5动态计算选择菜品的数量和总计金额

在微信开发者工具中执行效果。03任务3实现地图定位页面

任务3实现地图定位页面

地图定位页面主要功能为在腾讯地图上显示餐厅地理位置。在餐厅详情页面的餐厅地址右侧有一个绿色气泡图标。单击该图标,页面将跳转到地图定位页面,在地图上可视化显示当前餐厅的地理位置。

在pages目录下新建map/map.vue文件。创建时勾选“在pages.json中注册”复选框以便在pages.json文件中配置页面路由,pages.json中pages节点路由配置如黑体代码所示。"pages":[{ "path":"pages/index/index", "style":{ "navigationBarTitleText":"美食搜索首页", "enablePullDownRefresh":false }},{ "path":"pages/restaurant/restaurant", "style": { "navigationBarTitleText":"餐厅详情", "enablePullDownRefresh":false }}{ "path":"pages/map/map", "style": { "navigationBarTitleText":"餐厅位置", "enablePullDownRefresh":false }}]

任务3实现地图定位页面

在restaurant.vue中<viewclass="header">组件内部添加如下黑体代码,定义click事件跳转map.vue页面。<viewclass="header"> <imgclass="header-img":src="obj.pic"alt="餐厅图片"/> <viewclass="restaurant-content"> <view>{{obj.restaurant}}</view> <uni-rateclass="restaurant-content-data"v-model="obj.rate" :readonly="true"/>{{obj.rate}}分

<viewstyle="display:flex;flex:0;"> <view>地址:{{obj.address}}

</view> <imagesrc="../../static/marker.png" @click="toMap(obj.address)" style="height:35rpx;width:35rpx"></image> </view> </view></view>toMap方法内部代码如下,跳转页面同时将餐厅地址作为参数传递给map.vue。unctiontoMap(address){ uni.navigateTo({ url:"/pages/map/map?address="+address })}

任务3实现地图定位页面

map.vue页面接收到餐厅地址后,需将该地址作为参数调用腾讯地图的getSuggestionAPI接口获取该餐厅的经纬度坐标,才能在腾讯地图上显示。

在uniappdemo7项目中将腾讯地图SDK文件qqmap-wx-jssdk.js放入项目的\static\js\utils\qqmap-wx-jssdk目录中,以便后续使用。

在map.vue页面中输入以下代码创建腾讯地图对象qqMapWx,并调用其getSuggestion方法获取当前餐厅的经纬度坐标,然后将位置显示在地图上。<template> <view> <mapclass="map":markers="markers":latitude="latitude" :longitude="longitude"></map> </view></template><scriptsetup> import{onLoad}from'@dcloudio/uni-app' import{ref,reactive}from'vue'; letQQMapWX=require('../../static/js/utils/qqmap-wx-jssdk/qqmap-wx-jssdk.js'); letqqMapWx="" letlatitude=ref(0)//地图中心点纬度

letlongitude=ref(0)//地图中心点经度//剩余代码见下一页

任务3实现地图定位页面 letmarkers=reactive([ { id:0, latitude:0,//标记点纬度

longitude:0,//标记点经度

iconPath:"../../static/marker.png",//标记点图标

width:"30",//标记点图标宽度

height:"30"//标记点图标高度

}, ]) onLoad((option)=>{ qqMapWx=newQQMapWX({ key:"替换成自己的腾讯地图Key" }) letaddress=option.address qqMapWx.getSuggestion({ //获取输入框值并设置keyword参数

keyword:address, success:function(res){ latitude.value=res.data[0].location.lat longitude.value=res.data[0].location.lng markers[0].latitude=res.data[0].location.lat markers[0].longitude=res.data[0].location.lng console.log(latitude.value) console.log(longitude.value) },//剩余代码见下一页

任务3实现地图定位页面 fail:function(error){ console.log(error); } }) })</script><stylescoped> .map{width:750rpx;height:750rpx}</style>在微信开发者工具中地图显示。04任务4实现登录页面

7.4.1用户名密码登录

用户名密码登录的流程和Web系统登录差不多,需要自己处理登录流程。基本步骤如下。(1)前端提供页面提供输入框给用户输入用户名和密码。‌(2)用户输入用户名和密码后将数据发送到后台服务器进行验证。‌(3)后端服务器验证用户名和密码,如果验证通过,‌则生成登录凭证Token‌返回给前端页面。(4)前端页面接收到登录凭证后,‌可以将其保存在本地缓存,‌例如使用uni.setStorageSync方法存储Token,‌这样用户在下一次打开小程序时只要在本地缓存中读取到Token,就无需再次登录,‌直到token过期失效。

这里省略后台服务器对上述流程进行简化,直接在前端页面验证用户名和密码,模拟生成Token。

7.4.1用户名密码登录

在pages目录下新建login/login.vue文件。创建时勾选“在pages.json中注册”复选框以便在pages.json文件中配置页面路由,pages.json中pages节点路由配置如下。{ "path":"pages/login/login", "style": { "navigationBarTitleText":"登录页面", "enablePullDownRefresh":false }}

在login.vue文件的template标签中添加如下代码,定义用户名和密码两个输入框和“登录”按钮。<viewclass="login-content">用户名密码 <inputclass="login-item"type="text"placeholder="请输入账号" v-model="userName"> <inputclass="login-item"type="safe-password"placeholder="请输入密码" v-model="password"> <viewclass="view-button"><button@click="login">登录</button></view></view>

7.4.1用户名密码登录

相应的样式代码如下。.login-content{ .login-item{ padding:10rpx; height:60rpx; width:80%; } .view-button{ button{ background-color:#10c52f; width:90%; height:85rpx; text-align:center; line-height:85rpx; color:#fff; } }}

7.4.1用户名密码登录

在login.vue文件的script标签中添加如下代码。当用户名和密码都为admin,则通过验证模拟生成一个Token。然后调用setStorageAPI接口将Token存入本地缓存并跳转到index.vue页面。import{ref}from'vue';letuserName=ref("")letpassword=ref("")functionlogin(){ //可通过uni.request向后端发送请求验证用户名密码是否正确,如果正确返回Token if(userName.value=="admin"&&password.value=="admin"){ lettoken=userName.value+pas

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论