This project is a fresh e-commerce application. Its main functions include commodity list, commodity details display, shopping cart, login and registration, personal center, etc.

Project source at github.com/apicloudcom… Warehouse under the “multi-terminal case – fresh e-commerce” directory.

The front-end of the project adopts APICloud AVM multi-terminal development technology for development, including scrollview, pull-down refresh, input processing, swiper, network request encapsulation, etc. Using APICloud multi-terminal technology for development, to achieve a set of code multi-terminal operation, support to compile into Android & iOS App and wechat small program.

The back-end of the project is built using APICloud Data Cloud 3.0 custom cloud functions.

Using the step

  1. Use APICloud Studio 3 as a development tool.
  2. Download the source code of the project “Fresh e-commerce APP Development”.
  3. Create a new project in development tools and import this source code into the new project. Update the appID in config.xml to the appID of your project.
  4. Use AppLoader to preview real sync debugging.
  5. Or submit the project source code, and compile the custom Loader for the current project cloud for real machine synchronization debugging preview.
  6. Cloud compilation to generate Android & iOS App and wechat small program source package.

If you are not familiar with APICloud development before, it is recommended that you learn how to initialize, preview, debug, and package a simple project. Please refer to the APICloud Multi-development Quick Start Tutorial.

Network request interface encapsulation

In Script /kn.js, the unified network request interface Ajax method is encapsulated, and the request of the whole project is unified management, including processing incoming parameters, assembling complete request URL, setting request and so on, and finally calling API. Ajax method to initiate the request. In the callback method of the request, it also makes a global judgment on whether the cookie is expired. After the expiration, it will clear the local user login information and prompt you to log in again.

// kn.js u.ajax = function(p, callback) { var param = p; if (! param.headers) { param.headers = {}; } param.headers['x-apicloud-mcm-key'] = 'cZKzX7DabDmYyfez'; if (param.data && param.data.body) { param.headers['Content-Type'] = 'application/json; charset=utf-8'; } if (param.url) { var baseUrl = 'https://a8888888888888-pd.apicloud-saas.com/api/'; param.url = baseUrl + param.url; } api.ajax(param, function(ret, err) { if (callback) callback(ret, err); if (ret) { var status = ret.status; if (status && status == 4001) { var didShowLogoutAlert = api.getGlobalData({ key: 'didShowLogoutAlert' }); if (! didShowLogoutAlert) { api.setGlobalData({ key: 'didShowLogoutAlert', value: true }); u.setUserInfo(''); Function () {api.setGlobalData({key: 'didShowLogoutAlert', value: false}); api.closeToWin({ name: 'root' }); }); }}}}); }Copy the code

Example:

// import $kn from "... /.. FnGetWareTypeList () {var that = this; fnGetWareTypeList() {var that = this; $kn.ajax({ url: 'wareTypes/getWareTypeList', cache: true }, function(ret, err) { if (ret && ret.data) { that.data.wareTypeList = ret.data; that.updatedWareList(); } else {api.toast({MSG: 'failed to get merchandise category ', duration: 2000, location: 'bottom'}); }}); }Copy the code

Custom navigation bar encapsulation (use of APICloud components)

The components/navigationBar STML page, we encapsulate a generic navigation components, including safe – area components can ensure the safety of the content of the inside is always displayed on the screen area, such as not be status bar. In the component page, you can access the properties passed in by the parent page through this.props.

<template> <safe-area class="nav-container"> <view class="nav-header"> <view class="nav-header-button nav-left-button" onclick={this.props.onLeftButton ? this.props.onLeftButton : this.onLeftButton}> <image width={this.props.leftButtonWidth ? this.props.leftButtonWidth : 11} src={this.props.leftButtonIcon ? this.props.leftButtonIcon : '.. /.. /image/back.png'} mode="widthFix"></image> <text class="nav-header-text">{this.props.leftButtonText}</text> </view> <text class="nav-header-title">{this.props.title}</text> <view class="nav-header-button nav-right-button" onclick={this.props.onRightButton}> <image width={this.props.rightButtonWidth ? this.props.rightButtonWidth : 0} src={this.props.rightButtonIcon ? this.props.rightButtonIcon : ''} mode="widthFix"></image> <text class="nav-header-text">{this.props.rightButtonText}</text> </view> </view> </safe-area> </template>Copy the code

When using this component on other pages, you can set the navigation bar title, as well as the text, image, and click events for the left and right buttons.

// Import navigationBar from "... /.. / components/navigationBar STML "/ / in other STML page using the / / login STML < navigationBar title =" member login "rightButtonText =" registered" onRightButton={this.onRightButton}></navigationBar> 123456Copy the code

Scroll vertical list

In the development project of fresh food e-commerce APP, list display is used in many places, such as the list of goods on the home page, city selection page, shopping cart list, etc. The list in the project is realized by Using Scroll View with V-for instruction.

// cityselector.stml
<scroll-view class="cityselector-section" scroll-y='true'>
  <view v-for="(item, index) in dataList">
      <text class="cityselector-city" data-item={item} onclick={this.fnSelectCity}>{item.name}</text>
  </view>
</scroll-view>
Copy the code

If the fresh food e-commerce APP development project only needs to support the APP end, it is recommended to use list-view to realize the long list. Compared with the scrollview to create all items at once, list-view will only create items in the visible area, and basically only have those items in the whole scrolling process. Items are recycled and reused during scrolling, and the performance is greatly improved compared with that of ScrollView.

Horizontal scrolling list

The horizontal scroll view is used in both the product category and recommended products on the home page. When the scroll-x property is true, the scroll direction of the scroll-view is horizontal and the layout direction is horizontal, that is, flex-direction becomes row.

// index.stml <scroll-view class="nav" scroll-x show-scrollbar="false"> <text class={'nav-menu'+(this.data.currentIndex==index? ' nav-menu-selected':'')} v-for="(item,index) in wareTypeList" data-index={index} onclick={this.fnSetNavMenuIndex}>{item.name}</text> </scroll-view>Copy the code

Home page drop down refresh, scroll bottom load more

On the home page (Pages /main/main.stml), the list of goods can be displayed through scroll view, and more functions can be achieved by drop-down refresh and scrolling to the bottom to load.

<scroll-view scroll-y='true' class="warelist" enable-back-to-top refresher-enabled refresher-triggered={this.data.refresherTriggered} onrefresherrefresh={this.onrefresherrefresh} onscrolltolower={this.onscrolltolower}> <view class="header"> <image class="banner" src={this.data.bannerUrl} placeholder=".. /.. /image/default_rect.png" thumbnail="false" mode="widthFix"> </view> <view> <view class="cell" v-for="(item, index) in dataList"> <view data-id={item.id} data-wareCount={item.wareCount} class="container" onclick={this.fnOpenDetailWin}> <image class="thumbnail" src={item.thumbnail} placeholder=".. /.. /image/default_square.png"></image> <view class="info"> <text class="info-name">{item.name + ' ' + (item.unit||'')}</text> <text class="info-description">{item.description}</text> <text Class ="info-price">{'¥'+item.price}</text> <text class="info-origin-price">{'¥'+item.originPrice}</text> </view> <view class="control"> <image class={item.wareCount>0?'minus':'none'} data-index={index} src=".. /.. /image/minus.png" onclick={this.fnMinus}> <text class={item.wareCount>0? 'count':'none'}>{item.wareCount}</text> <image class="add" data-index={index} src=".. /.. /image/add.png" onclick={this.fnAdd}> </view> </view> </view> </view> <view class="footer"> <text class="loadDesc">{this.data.haveMoreData? 'Loading... ':' No! '}</text> </view> </scroll-view>Copy the code

Pull-down refresh uses the default pull-down refresh of the Scroll view. The “refresher-enabled” field is used to enable the pull-down refresh, and the “refresherTriggered” attribute is bound to control the pull-down refresh state. The value of “refresh triggered” must be set to true and then false when the data is loaded, so that the bound value changes and the refresh status is notified to the native function.

onrefresherrefresh(){
	this.data.refresherTriggered = true;
	this.fnGetWareList(false);
}
Copy the code

The scrolltolower event of the Scroll view is monitored after the scrollto the bottom, and more data is automatically loaded after the scrollto the bottom. Both fnGetWareList method is called to request more data, and APICloud loadMore_ parameter is used to distinguish the two. Do paging request processing.

FnGetWareList (loadMore_) {var limit = 20; if (loadMore_) { this.data.skip += limit; } else { this.data.skip = 0; } var currentCity = $kn.getCurrentCityInfo(); var that = this; $kN. Ajax ({URL: 'wares/getWareList', method: 'POST ', data: {body: {supportAreaId: currentCity? currentCity.id:'', wareTypeId: this.data.wareTypeId, skip: this.data.skip, limit: limit } } }, function(ret, err) { if (ret && ret.data) { var cartData = api.getGlobalData({key: 'cartInfo'}); var data = ret.data; that.data.haveMoreData = data.length == limit; that.getFixedWareList(data, cartData? cartData.wareList:null); if (loadMore_) { that.data.dataList = that.data.dataList.concat(data); } else { that.data.dataList = data; }} else {api.toast({MSG: 'failed to load data ', duration: 2000, location: 'bottom'}); } that.data.refreshState = 'normal'; that.data.refresherTriggered = false; }); }Copy the code

Product details page wheel cast chart

The product detail page path of fresh food e-commerce APP is pages/ware/ware. STML, in which the swiper graph is realized by using the Swiper-item component, the V-for instruction is used to cycle swiper-item, and the picList is the attribute of the array type defined.

<swiper class="swiper shrink" style={'height:'+this.data.swiperHeight+'px; '} indicator-dots indicator-active-color="#e3007f" autoplay circular> <swiper-item v-for="(_item,index) in picList"> <image class="img" placeholder=".. /.. /image/default_square.png" src={_item} mode="aspectFit" thumbnail="false"></image> </swiper-item> </swiper>Copy the code

The width of the rotation image varies with the screen width, and the height is set by the swiperHeight property to keep the image width to height ratio unchanged.

Login and registration page input processing

The structure of login and registration pages is similar. As can be seen from the following code, the login page is composed of two parts, the top is the navigation bar, and an scroll view is added outside the rest of the main content. The purpose of adding scroll view is, on the one hand, to ensure that the contents can be scrolled when the display is incomplete on the small-screen mobile phone. The other purpose is to get the focus of the input box, so that when the keyboard pops up, only the main part of the Scroll view moves up, while the navigation part remains unchanged.

// login. STML <view class="main"> <navigationBar title=" member login "rightButtonText=" register" onRightButton={this.onRightButton}></navigationBar> <scroll-view class="scrollView" scroll-y='true'> <view Class ="container"> <input ID ="username" class=" placeholder" Type ="password" placeholder=" password" /> <text class=" BTN "onclick={this.fnLogin}> login </text> <view class="third-login"> <text Class ="third-login-desc"> </text> <view class="icon-container"> <image class="icon" data-type="Apple" SRC =".. /.. /image/logo_apple.png" onclick={this.fnThirdLogin}/> <image class="icon" data-type=" wechat "SRC =".. /.. /image/logo_wx.png" onclick={this.fnThirdLogin}/> </view> </view> </view> </scroll-view> </view>Copy the code

Personal center upload profile picture

In the center of the individual pages (pages/personalcenter/personalcenter STML), we used the img tags to show the user avatar, when the user can modify the avatar after click on the picture. Here, according to the way the user chooses to select pictures, we will first determine whether there are corresponding permissions. If there are permissions, we will call api.getPicture method to select pictures, if not, we will prompt the user to set permissions.

fnSetAvatar() { var that = this; Api. actionSheet({title: 'Select image ', cancelTitle:' Cancel ', buttons: ['camera', 'album']}, function(ret, err) {var sourceTypes = ['camera', 'album']; if (ret.buttonIndex == (sourceTypes.length + 1)) { return; } var sourceType = sourceTypes[ret.buttonIndex - 1]; var permission = ret.buttonIndex == 1? 'camera':'photos'; var resultList = api.hasPermission({ list: [permission] }); if (resultList[0].granted) { that.getPicture(sourceType); } else {api.confirm({MSG: 'Permission =='camera'? Buttons: [' buttons ', 'set ']}, function(ret1) {if (ret1.buttonIndex == 2) {api.requestPermission({list: [permission], }, function(ret2) { if (ret2.list[0].granted) { that.getPicture(sourceType); }}); }}); }}}); }Copy the code

After successfully selecting the local image, call the encapsulated Ajax method to upload the selected image.

fnUpdateAtavar(avatarUrl_) { var that = this; $kn.ajax({ url: 'users/updateAvatar', method: 'post', data: { values: { filename: 'icon.jpg' }, files: { file: AvatarUrl_}}, function(ret, err) {if (ret && ret. }}); }Copy the code

In order to enable developers to learn and use APICloud platform AVM multi-terminal development technology more quickly, we will continue to update the actual combat project source code explanation video. This period of fresh e-commerce APP development cases here, there are enterprise APP development cases, takeout APP development cases, stamp blue word review oh!