In the past two weeks, we have all seen the news of JD’s launch of paipai Second-hand trading platform and the official launch of “Paipai Second-hand” APP. At the same time, we are also on the “clap second hand” micro channel small program development. The whole process is painful and happy, experiencing the pain of digging the pit, and the joy of jumping out of the pit.

Project introduction

“Clap second hand” has three main businesses: recycling, quality goods and personal idle trade. Jd.com “will integrate recycling, testing, reprocessing, sales and other reverse supply chain resources with a platform operation idea to do second-hand quality.” , and based on wechat has a huge social relationship chain, which is conducive to the promotion of products, directly facing users, help their own business and other advantages. The company decided to launch the micro channel mini program version of “clap second hand”.

The main page of wechat applet is:

  • On the first page
  • Paipaiqun Home Page
  • One click resale list page
  • Product release page
  • Product Details page
  • Order Details page
  • Mine (post, sell, collect)

Let’s open up the mini program and watch a video of it in action:

The download file

It can be said that a sparrow has all the organs.

Project preparatory

Before this project, we had experience in several small programs, so when the project was launched, we adopted the way of “front-end driving business” to promote business students to apply for the qualifications that small programs rely on in advance, such as: small program account, name record, payment qualification, Tencent map daily visits and so on. At the same time, different from the small programs we have done before, this project will transplant the overall process of second-hand C2C to the small program platform, and realize the transaction experience based on wechat group. In the process of requirement review, we roughly encountered the following problems, and carried out technical pre-research. The results of pre-study will be explained in the technical difficulties.

The technical architecture

On the basis of the existing applets framework, we have enriched the custom components, added a new base class library, introduced SASS, Eslint applications in applets. Here are a few simple points:

  1. Due to the limitation of small program package size (package size limit is 2M during development); We also optimized the static picture resources, and put most of the ICONS in the CDN, small program directly access network resources.
  2. The use of SASS not only follows our existing PC and M-side refactoring methods (which we are all familiar with), but also greatly improves the efficiency of small program development.
  3. The application of ESLint, using the code specification we set, checks our code output.

In addition, we refined the route jump scheme for each process due to the limitation of the hop level of the applet route (initially 5).

Technical difficulties

In the following, we will focus on analyzing the difficult problems and solutions encountered in the project. We illustrate the size of the minipackage, compatibility issues, existing component defects, the potholes we encounter these days, the miniprogram components we develop, and providing alternatives to the business.

Applets size limits

In order to achieve no more than 2M code, we must think about how to reduce the amount of code in the development process and improve the user experience. How to improve the code reuse rate of small programs, but also reduce their coupling.

First, we use the way of front and back end separation, the front and back end agreement interface document; Also abandoned the traditional front-end static page and then set the page, template development, front-end directly according to the interface specification simulation data reconstruction + development;

Second, we did a lot of discussion before the development, from dozens of design drafts can be generalized modules, wrote a lot of common components; A number of public methods have been written for data processing, distilled into the util class;

Third, we mapped the static resources Sprite and Tiny and published them to the CDN. The icon dependent elements in the small program directly reference network resources.

Applets compatibility problem

There are some known problems in the compatibility of small programs, which have been clearly pointed out in the documentation. However, the documentation of the recently released iPhone X is not comprehensive. We also tested this model this time, and sorted out some compatibility problems we encountered, hoping to help you.

First of all, LET me show you a picture. There are two problems in it, and I will introduce their treatment methods one by one:

1. After setting border-radius, the border display of elements in iphoneX is incomplete

When encountering this problem, just change RPX to PX. In fact, this problem is not limited to small programs, in the M-side development process if the use of REM units will inevitably cause this problem.

2. The padding-left setting of view in iphoneX is biased in the mobile phone

<view class="com-lab "> <span> </span> </view> <view class="sel-box">Copy the code

This code is very simple, we see that shipping has a SPAN tag package, classification is not, while we wrote WXSS in this way

.com-lab span{
  padding-left:30rpx;
}
.sel-box{
  padding-left:30rpx
}Copy the code

On the iphoneX, the bias shown above can be easily modified

.com-lab{ padding-left:30rpx; } 
.sel-box{ padding-left:30rpx }Copy the code

I took out the padding of the SPAN tag and put it in the outer view so that there is no bias, but the first one is also correct in the browser. Why is it wrong on ios? I think it’s due to the syntax of the applet at compile time, so try to minimize these differences when refactoring the page.

3, iphoneX adaptation oF wechat bottom operation area problems

As we all know, iPhoneX has the concept of safety zone after opening the bangs mode, and we need to put all the display contents in the safety zone, so we need to deal with the black Home Indicatorzuo at the bottom, otherwise it will block the text. The first is to distinguish the models in the JS code

wx.getSystemInfo({ success: function(res) { if(res.model.toLowerCase().indexOf('iphone x') ! = -1) { me.globalData.isIpx = true; }}});Copy the code

Then do some styling in WXSS

.fix-ipx-tabbar-bottom {bottom: 66rpx; } .fix-ipx-tabbar-bottom::after { content: ''; position: fixed; bottom: 0rpx; height: 66rpx; width: 100%; background: #FFF; }Copy the code

It is not difficult to deal with such a way, the key is that we need to know that there is such a problem with iphoneX, then the future domestic mobile phone will have a new shape, we can also use this method to deal with, simple and effective is the best.

4. Wx. showModal click mask layer to trigger confirm, there is a white background behind the prompt text in ios

Since the modal window is the API of the applet and there is no change style entry, we simply reused the ModalDialog component we wrote and replaced this method.

Defects in existing components of applets

1. Compatibility problems of text input in ios

The download file

Commonly used tags for text input are input and Textarea. When we use these two tags to do some text editing, we encounter three problems in ios, which are as follows:

  1. When a page has a mask layer, it cannot cover the text content of a Textarea.
  2. On ios, modify the text content in a textarea or input. If you modify it in text, the cursor will run to the end.
  3. On ios, textarea adds a padding, and we can’t get rid of the padding no matter how much style control we use.

Take the product description as an example, which uses the text input tag textarea. Here is the WXML code:

<view class="des-msg"> <span> <span> <textarea bindinput="charactersDesc" class="{{desshow == 1? 'shows' : 'hidden'}} {{postData.devicesType == 2 ? 'iosText' : Placeholder ="{{charactersDesc, charactersDesc, charactersDesc, charactersDesc} "/> </view>Copy the code

Problem 1: Our solution is to add a class named shows when a mask layer is created, so that the tag is hidden, not gone. If we use wx: if= “{{}}” the tag will be removed if the textarea content is not synchronized to postData.charactersdesc which was generated before the tag was generated.

Some of you writing here may be wondering why we didn’t sync postData.charactersdesc during the modification process. This is because of the description of problem 2, which will cause a bug in the ios system. So we hide the tag instead of removing it.

Question 2: We need to record the user’s input, and the recorded content is stored in charactersDesc, and the Value of textarea is also used in charactersDesc. This caused the bug. The event I bound in textarea was bindinput instead of Bindblur. If I used Bindblur, I would have no problem.

The ideal is beautiful, but the reality is cruel. The ios system is very unfriendly and brings us this trouble. When we tested the real machine, we found that textarea did not lose focus when typing on the keyboard, but console.log kept printing. This means that every input triggers a Bindblur, and we’re all in a mess. To solve this problem, I created a new object in data called tempCharactersDesc to store your changes for other purposes. For example, label re-rendering.

DevicesType == 2? ‘iosText’ : ‘andText’}}

Wx.getsysteminfo ({success: function(res) {let types = 0; if (res.system.split(' ')[0] == "iOS") { types = 2; } if (res.system.split(' ')[0] == "Android") { types = 1; } $that.setData({ ['postData.devicesType']: types }) } })Copy the code

2. Quick click on the page can be triggered repeatedly

The download file

Description: The applet has a delay in jumping from page to page, giving the user the chance to click twice quickly, which is terrible if left unhandled. Considering that you open the same page twice at the same time, not only does it create a bad user experience, but it also creates a chance for more routes to freeze than can be added infinitely, and the function that determines the source of the route from the route introduces unnecessary pitfalls.

Use app () in app.js to register a global function, and then call this method where the trigger is involved to prevent the trigger. Here is how to do it

globalLastTapTime:0,
preventMoreTap:function(e){
      var globaTime = this.globalLastTapTime;
      var time = e.timeStamp;
      if(Math.abs(time-globaTime) < 500 && globaTime != 0) {
        this.globalLastTapTime = time; 
        return true;
      } else{
        this.globalLastTapTime = time; 
        return false;
      }     
 }Copy the code

Call method:

let app = getApp(); Page({ xxx:function(e){ if(app.preventMoreTap(e)) { return ; } // jump}})Copy the code

3. Lock the page after repeated jump several times

Description: The page of commodity release is a module of central process in paipai Second-hand. The upstream and downstream pages jump frequently, and even the internal classification jumps to a new page. And we need to convey a set of information between each page jump. Obviously, according to the official documents, we will choose navigateTo and redirecTo.

With navigateTo, you can only jump to the page 10 times, and nothing will happen after the 11th time. With A redirecTo page, when clicking on the upper left corner of the page triggers the back button, the page returned is no longer a publish page, but a different page.

First of all, we give an example: when we jump to use navigateTo, from the release page to the classification page, the classification page to select a classification to jump back to the release page, repeated several times found that the page is not moving. NavigateTo jumps back to the current page and adds the current page to the route, then jumps back to the page and adds the new page to the route. Using getCurrentPages(), we get an array of 2 lengths. When the length is 5 the page cannot jump.

Obviously, you can’t do that. If we use redirecTo, we can solve the problem, but if we click back in the upper left corner of the page, we find that it does not return to the product release page as we expected, but to the previous page of the product release.

[navigateBack] [navigateBack] [navigateBack] [navigateBack] [navigateBack] [navigateBack] [navigateBack]

  1. NavigateTo or redirecTo, pass it in the URL
  2. The changing parameters are put into the cache, and the cache is updated. This is obviously not a good approach, as there will be multiple parameters in the cache.
  3. Get an array object with getCurrentPages() and take the sequence of the last page and use the setData() method
var pages = getCurrentPages();
var prevPage = pages[pages.length - 2];
prevPage.setData({
    classId: id,
    classifyName2: className,
    classTags: classtags
})
wx.navigateBack()Copy the code

To sum up, the third way to transfer parameters is the best. This allows you to jump back and forth between the two pages, and click back on the upper left to return from the category to the product release page. Note that using the method in 3 we need to determine pages[pages.length -2];

4. The number of requests for uploading images in batches is less than the actual number of adding images

When I write this question, the mood is mixed, regarding the image part of the processing, the small program gives us chooseImage, previewImage, getImageInfo allows us to select the image, preview the image, also has a method for uploading uploadFile. Here’s an example of a single image upload:

wx.chooseImage({ count:1, sizeType : ['compressed'], success : function(res) { let tempFilePaths = res.tempFilePaths; wx.uploadFile({ url : xxx, filePath:tempFilePaths[0] , name: 'xzInputFile', formData: { 'user': 'test' }, success: Obj. success, fail:obj.fail})})Copy the code

Doesn’t it feel easy. How could such a simple code have a bug? Often when it comes to image uploading, we are uploading multiple pictures. In the process of uploading, there is also a display waiting for uploading. If uploading fails, the uploaded pictures will be displayed back after success.

Batch upload We came up with the idea of uploading images using a for loop:

wx.chooseImage({ count:12, sizeType : ['compressed'], success : function(res) { let tempFilePaths = res.tempFilePaths; for(let i = 0,index ; src = tempFilePaths[i]){ wx.uploadFile({ url : xxx, filePath:tempFilePaths[0] , name: 'xxx', formData: { 'user': 'test'}, success: obj.success, fail:obj.fail})}})Copy the code

The problem with writing this is that with a for loop, uploadFile may access the server in 0.001ms, resulting in a loop of 5 times with fewer than 5 actual visits to the server. We modified this code to include a setTimeout delay function, which can effectively avoid fast request to the server.

wx.chooseImage({ count:12, sizeType : ['compressed'], success : function(res) { let tempFilePaths = res.tempFilePaths; for(let i = 0,index ; src = tempFilePaths[i]){ setTimeout(function(){ wx.uploadFile({ url : xxx, filePath:tempFilePaths[0] , name: 'XXX ', formData: {'user': 'test'}, success: obj.success, fail:obj.fail})}, 1000)}})Copy the code

After that, we only need to update the information returned by the service to the data according to the sequence. If it succeeds, the waiting upload will be replaced with the uploaded picture; if it fails, the uploaded picture will be replaced with the failed upload picture.

These days we come across pits

1. Uploading pictures always fails. The network is out of order

When all the components are packaged, there is no problem in the preview version, but in the pre-release version, we find that the image always fails to upload, which is mostly because the legitimate domain name of uploadFile does not add the uploaded image. If there is any problem with upload or request data, first check our domain name.

2. Range data has not loaded the picker binding event

I hope to achieve the sliding selection as shown in the picture above, wechat mini program is very thoughtful to give us encapsulated picker component.

<picker bindchange="bindPickerChange" value="{{index}}" range-key="logisticsName" range="{{logisticsArray}}" > <view </label> <span>{{logisticsArray[index]. LogisticsName}}</span> </view> </picker>Copy the code

The Range property can be Array or Object Array. The default value is []. The type of the range-key attribute is String. When Range is an Object Array, range-key is used to specify the key value in the Object as the selector. The Value attribute is of type Number and the default Value is 0. The Value of Value indicates the number of items in the range selected (based on the index Value). Bindchange is used to bind pickers to events. The change event is triggered when value changes, event.detail = {value: value}.

Now everything looks fine, as the design has a default value of “Please select shipping company”. Very simple idea, we set up an initial array. Then query the data returned by the express company interface and splice it.

Data: {logisticsArray: [{logisticsCode: "", logisticsName: ""}]} var _self = this; Wx. request({url: 'getLogisticsArray', // Just an example, not a real interface address Data: {}, header: {'content-type': 'application/json' }, success: function(res) { if (res.success) { var logisticsCompany = _self.data.logisticsArray.concat(res.data); _self.setData({ logisticsArray: logisticsCompany }) } } })Copy the code

Do you see anything wrong with your sharp eyes? When I thought everything was going as planned, the test student gave me a screenshot below. BindChange the picker when the interface data does not return. There will be only one please choose the express company, the other no. That is, the user action must follow the data return, depending on how fast the interface returns.

As usual, we might do a render method after the data is returned. Let the DOM update, but now that the user is already in the interface, it doesn’t make sense. So the idea is that the interface must return data before allowing the user to operate.

However, ao Jiao users do not. Well, I’m proud of it. I’m not gonna show him what he does. Once you’ve identified your ideas, analyze them. There was an initial logisticsArray with length 1. When the data is returned, length > 1. From this direction, this will need to work with the WXML file.

<view wx:if = "{{logisticsarray.length > 1}}" >< picker></picker> </view> <view wx:else> <image SRC = "loading. Png0" > < / image > < / view >Copy the code

It is simple to implement, mainly a small shift in conventional thinking. It not only solves the problem, but also guarantees the user experience.

3. OnReachBottom and onPullDownRefresh are executed simultaneously

The download file

List page, which triggered the onReachBottom function used for pagination when executing onPullDownRefresh. We can resolve this conflict by adding a parameter

OnReachBottom: function () {// To the bottom of the page, request list if (! this.data.noMoreData && ! this.data.isPullDown) { this.setData({ currentPage: ++this.data.currentPage }); this.getCollectList(this.data.currentPage); }}Copy the code

4. Component open-data format problem

This is not strictly a component defect, but rather a documentation defect.

<open-data type="groupName" open-gid=" XXXXXX "></open-data> open-gid="xxxxxx"/>Copy the code

5. Drop down refresh the default styles of the three white dots are not displayed

Since the background color of the page is also white, the three dots are not visible. The first method is to modify the background color, but the impact on the current style is relatively large; The second method is used. Add “backgroundTextStyle” : “dark” to the JSON file corresponding to the drop-down refresh page, and you can see three white dots.

We develop small program components

Over the course of the project we developed a number of custom components, such as: warning pop-ups, search bars, bottom status bars, TAB menus, calculators, and pop-ups with confirm cancel. Let’s take the following component as an example

Toast and ModalDailog components

The methods of showToast and showModalDialog provided by the small program cannot meet our requirements due to design style problems, and they only support the display of a few characters (in ipX compatibility test, we also found the problem of white background of text), so we have been using our own packaged components.

The components are created and used as follows.

<template name="confirm">
  <view class="jdc-confirm">
    <view class="jdc-confirm__content">
      .
      .
      .
    </view>
  </view>
</template>Copy the code

Reference this template

<import src=".. /template/template.wxml" /> <template is="toast" wx:if="{{toastShow}}" data="{{... toastData}}"></template>Copy the code

Control in JS

data: { confirmData: { visible: false, title: '', message: 'xxxx', leftTxt: 'xxx', rightTxt: 'xxx' } }, submit:function(){ ...... }, cancel:function(){ ...... }}Copy the code

We build a reusable popover from a simple template, so as to solve the problem of native popover of small programs.

Provide alternatives for the business

Landing page – Invokes the app implementation

To invoke APP in the small program, from the perspective of the implementation protocol evoked, the small program is not supported. The small program currently only supports HTTPS, and does not support other custom protocols, so the scheme way of evoking APP is not a problem.

Of course, we can tell the business, this small program can not be implemented, goodbye! But we are the technology, and finding solutions is the ultimate goal. If you can’t evoke the APP, can you also try to expose the link of the APP? However, small programs do not support external links, so our solution is to provide users with the two-dimensional code of the landing page, prompting users to save and scan the code to download.

This is not a smart and risky solution, but it can solve the way the landing page evokes the APP.

Future applets development exploration

1. Integration of development tools In this development, we have gradually referred to SASS, ESlint and other tools to assist development, we will integrate more tools in the future, such as using CSS-Sprite to integrate Sprite image to achieve image processing, to improve our development efficiency. We will extract more common components and methods, and complete UI and components suitable for our own company style, and apply them in more future small programs. Of course, there’s still a lot to do, and we’ll keep working on it and find more interesting implementations

Final version of the feeling

Jia Huibin: Only through experience can you understand.

S S: 100 feet pole head, further, and then ‘into’ has nested 10 layers.

Good is like water: practice brings true knowledge.

Fishsif: I hope the wechat developer tools get better and better.

Hanyuxinting: Keep on singing along the path of miniprogram

Pupil: write small program, play small program. Explore different product experiences.

Lin rufeng: pain and happiness, if give me a chance, I will be better.

All the way thorns all over, suddenly look back, is the flowers on both sides. Believe that project will be the development of the program easily again, anyway don’t cry because it is a small program is run in WeChat compatibility will feel very good, on the contrary, because the program was born to the present time is short, so there are still many deficiencies, we in the use of small programs to provide us with the components of it is important to note that these components at the bottom of the tip. After reading these, what questions do you have about wechat small program? If you have any questions, please leave a message.

JDC front-end – small program development team (Lin rufeng, hanyuxinting, fishsif, shangshanruoshui, pupil, s s, jia huibin) co-edited.