当前位置: 首页 > Web前端 > vue.js

深入解析APICloudAVM多端开发案例(上)--点单app开发

时间:2023-04-01 10:31:27 vue.js

AVM多端开发是APICloud定义的一套新的代码编写标准(DSL):基于标准的WebComponents组件化思想,兼容Vue/React语法特性,通过一次性编码,分别编译成Android和iOSAPP和小程序代码,实现多端开发。《餐饮点餐》是一款单点餐厅堂食应用。开发者可以通过本案例体验一套编译Android和iOSapp+小程序的代码。其主要功能包括浏览商家主页信息、查看推荐菜品、订购商品、取餐等号等。项目源码位置:https://github.com/apicloudcom/ordering-food主页为什么要处理TabBar结构需要一个app.json配置文件《点餐》项目首页由一组窗口组成,可以在同一层级切换。在APP原生端,我们可以使用FrameGroup来实现这样的切换组。原生的,小程序使用app.json配置文件来配置和定义TabBar的相关属性。为了统一两端的差异,在weight根目录下定义了一个app.json文件。具体字段说明请参考《openTabLayout布局文档》。因此,如果你只写原生应用,不打算支持小程序,这个配置文件是可选的。TabBar页面的组织在这个配置文件中,可以声明底栏的标签文字,对应图标的选中和未选中状态,以及对应需要跳转的页面路径。所以你需要准备四个主页面。准备在pages目录下构建这四个页面。它们是“商家主页”main_home、“菜单页”main_menu、“购物车页”main_cart和“用户主页”main_user。为了兼容小程序的目录结构,需要用同名文件夹包裹起来。把商家首页的main_home写到首页的效果图中,然后大致分析一下页面结构。源代码在/widget/pages/main_home/main_home.stml中。页面的主要部分是滚动效果,需要使用scroll-view作为滚动部分的容器。header有一个固定的header,跟随上面提到的scroll-view的scroll-height进行透明度反馈。布局结构采用系统推荐的flex布局。需要注意的一点是,flex布局的flex-direction默认是column,也就是垂直排列的方向,这一点与传统网页不同。此外,每个组件都带有display:flex;默认属性。请求接口数据(数据处理和请求库封装)在页面的生命周期apiready中,有一个this.getData()方法,就是在请求数据。functiongetData(){GET('shops/getInfo').then(data=>{this.data.shopInfo=data;})}这个函数主要是通过GET方法实现的。该方法来自:import{GET}from"../../script/req";在这个文件中,主要处理应用请求、会话、异常处理的逻辑。相关业务代码仅供参考,具体项目根据实际的session认证方式、服务接口方式和个人喜好来组织。获取到数据后,通过this.data.shopInfo=data将数据传递给页面的data字段,方便接下来的数据绑定展示。商户头图和主要信息(数据绑定)头图不会随着scroll-view滚动,所以应该在scrollcontainer之外。使用img图像标签显示图像。它的数据是来自服务器接口的数据,使用avm.js提供的《数据绑定》来处理数据。商户的商家信息也一样上面,根据接口数据绑定设置相应的字段,就会显示出来。{{shopInfo.name}}{{shopInfo.city}}{{shopInfo.country}}{{shopInfo.address}}营业时间09:00-13:00,16:00-22:00拨打电话的动作(事件绑定)点击手机图标后,需要实现拨打电话的效果。给它绑定一个点击事件,叫做callPhone,在methods中实现:呼叫({类型:'tel_prompt',号码:this.data.shopInfo.phone});}}推荐菜品和栏目(v-for循环和组件)仔细观察这里的模板和数据,其实可以分解成一个主标题加上一组菜品来循环。其中一组菜肴重用循环来呈现单个项目。使用循环显示三组数据。每个循环包含一个组件。该组件来自自定义组件:importgoodsListItemfrom'../../components/goods-list-item.stml';在自定义组件中,完成了组件内部的组件样式、数据管理和事件响应,符合组件化开发思想,提高了项目开发效率和可维护性。在这个组件中,还使用了一个循环来处理每一列的item数据。每个商品都绑定一个intoGoodsDetail事件,跳转到商品详情页。functionintoGoodsDetail(item){api.openWin({name:'goods_detail',url:'../../pages/goods_detail/goods_detail.stml',pageParam:{item}})}页头header{{shopInfo.name}}header是常见的视图+文本结构。为了实现滚动透明,将其绑定到动态样式属性。动态改变其不透明度。而这个opacity的值取决于scroll-view的滚动高度。scroll-view的滚动会触发相关数据的变化,所以绑定了一个滚动事件@scroll="onScroll"以及onScroll相关的处理逻辑。函数onScroll(e){consty=isMP()?e.detail.scrollTop:e.detail.y;letthreshold=this.photoRealHeight-y;如果(阈值<0){阈值=0;}这个数据。opacity=1-threshold/this.photoRealHeight;api.setStatusBarStyle&&api.setStatusBarStyle({style:this.statusBarStyle});}在onScroll中可以得到对应的滚动高度,计算出最终的透明度结果。同时发现透明度的变化也会伴随顶部状态栏文字的颜色变化。使用结束功能api.setStatusBarStyle进行相应设置。这样,业务首页相关逻辑的数据处理就差不多完成了,基本的事件和数据处理同时介绍。商品详情页(组件通讯、全局数据和事件)加载时,可以通过页面传参获取商品详情数据。另一个商品的追加购买数量存储在名为CART-DATA的全局数据中,相关数据在页面生命周期函数apiready中获取:this.data.goods=api.pageParam.item.togoods;//获取产品主要数据letcartList=api.getPrefs({sync:true,key:'CART-DATA'});//获取额外购买数量if(cartList){car??tList=JSON.parse(cartList)this.data.cartData=cartList[this.data.goods.id];如果(this.data.cartData){this.data.count=this.data.cartData.count;}}counter组件goods_counter商品详情页使用了两个自定义组件,一个是goods_counter,也就是商品计数器。以后可能会被其他页面用到,所以封装起来。使用一个动态属性:count="count"添加当前商品传入的新获取数量.在goods_counter中,单击加号和减号按钮会触发countChange事件。事件中传递给父页面:functioncountChange(change){if(this.props.count+change===0){returnapi.toast({msg:'不能再减少n可以在购物中编辑cartmodeRemove',location:'middle'})}this.fire('CountChange',{change,props:this.props})}所以在调用组件的时候,绑定一个onCountChange={this.countChange.bind(这)}。这里的this.countChange是goods_detail的函数,在组件创建的时候作为props传递给子组件,这个函数可以直接在子组件中执行,也可以用fire来“点燃”。附加购买动作栏goods_action商品详情页使用了两个自定义组件,另一个是goods_action,这是一个附加购买动作栏。主体是两个按钮,一个是加购,一个是结算。结算是将当前项目数据携带到预付款页面。逻辑很简单,就是携带数据到新的页面。添加购买稍微复杂一点,但是逻辑上还是使用fire向父页面抛出addCart事件,因为后续不同页面添加购买的逻辑可能不同,具体实现交给父页面。所以注意力还是转回到goods_detail的addCart的实现上。functionaddCart(){letcartList=api.getPrefs({sync:true,key:'CART-DATA'})||'{}'cartList=JSON.parse(cartList)cartList[this.data.goods.id]={goods:this.data.goods,count:this.data.count};api.setPrefs({key:'CART-DATA',value:cartList});api.toast({msg:'加入成功'+this.data.count+'pcstocart',location:'middle'})setTabBarBadge(2,Object.keys(cartList).length);考虑添加购买数据后的相关购物车页面和底部的小红点。这时候如果不考虑小程序,也可以直接发送全局广播,自己处理相关逻辑。