preface

See nuggets also more than a year, sigh you big guy technology 6 of a group, just go to school also give a person to make one or two small procedures, suddenly want to sum up experience, give yourself also make a cool cool, by the way also write a, let you big guy see what problems, after all, this diaofan open-minded group

Chicken without picture => Finished picture

Dish chicken practice summarizes some tips

  • Small program login to obtain user information (interaction with the server)
  • Applet displays rich text with MarkDown (using towXML)
  • A small wrapper for Wx. request (make it promise)
  • Iview Appellate Component Use
  • Use of native components of applets
  • More tips on pull-up loading
  • Manually implement a simple fake waterfall stream

The functional requirements

  1. Display blog by category
  2. Display blog content (rich text /Markdown)
  3. Users log in using the wechat mini program
  4. Users log in and comment on blogs
  5. Show some information about books I like (special service)
  6. Send books to Kindle with one click (Special Service)

preparation

  1. Go to UI China or other sites and grab a nice UI design (after all, aesthetic is hard)
  2. Go to Ali icon website to find a pleasing set of ICONS. Select a few for the bottom TAB bar of the small program, because the small program TAB icon switch is by changing pictures to achieve, so you can from ali icon on each icon under two, the gray version of the next, the color version of the next. Sort out the naming of the ICONS a little bit

Data interface preparation (an important part, always can’t be empty frame)

The main interfaces used in this project are

  1. GetSlides Interface for getting the top multicast graph
  2. GetPostOfCategory: getPostOfCategory: getPostOfCategory
  3. Get the interface for the article (getPost)
  4. User Login Interface (wxLogin)
  5. User binding mailbox interface (bindMail)
  6. Interface for sending books (sendBook)
  7. Get the configured interface (getConfig)
  8. Interface to get comments on articles
  9. GetConfig, Recommendation of the day, homepage blog, etc., are used to display posts from different columns on the server, so you need a column ID to call the getPostOfCategory interface, but you don’t want to write the column ID in the widget. In case of a bad day to delete the column small procedures do not change the code? Just at that time to do the background of a configuration management function, this time just use; Special for the small program to create a new configuration group, the small program used column ID and other random things (such as paging per page size, background map, etc.) in the form of key-value back end, each time the small program started from the back end to get the configuration stored in localStorage, so in the background to change the configuration, Small program display column naturally also switched.

Stop messing around and turn it on

infrastructure

  1. According to the requirements of the plan, in the Pages folder to the required page to create a new right click
  2. Since we are using the iView component and towXML, we put them in the root directory as well
  3. Create a new netutils. js (network layer), encapsulate wx.request, and put it in netUtils. At the same time, put the server address baseUrl as a constant in netUtils. All network access urls are assembled from baseUrl, which is convenient for switching test and generation environment
  4. On top of that, create a dataUtils (data layer) where all network requests (all promises) for data from the server are stored
  5. (Optional) Since many pages will jump to the article content page, search page, etc., so I made a navutils.js to write commonly used jump in this, save every time to write again

File structure:

Key part of netutils.js
const BASEURL = "https://localhost:8888/";
const APIURL = "https://localhost:8888/api/"; /** * encapsulates request */ const requestPromise =function ({ url, data, header,
  method = 'GET'{})return new Promise((resolve, reject) => {
    wx.request({
      url: url,
      data: data,
      header: header,
      method: method,
      success: (res) => { resolve(res) },
      fail: (err) => { reject(err) }
    })
  });
};
module.exports={
  BASEURL:BASEURL,
  APIURL:APIURL,
  request: requestPromise
}
Copy the code
Key parts of dataUtils
let netUtils = require('./netUtils.js'); /** * The basic method of obtaining server data */function getServerDataPromise(url,data,header=null,method='GET') {let dataUrl = netUtils.BASEURL+url;
  returnnew Promise((resolve, reject) => { netUtils.request({ url: dataUrl, data: data, header:header, method:method }).then(res => { resolve(res); }).catch(err => { reject(err); }); }); } /** * get the column under the article */function getPostOfCategoryPromise(data) {
  let url ='api/front/portal/getPostOfCategory';
  returngetServerDataPromise(url,data); }; /** * get slide */function getSlidesPromise(data){
  let url ='api/front/portal/getSlide';
  returngetServerDataPromise(url,data); }... Dear brother according to actual situation make your interface to encapsulate the make a module. Exports = {getPostOfCategory: getPostOfCategoryPromise getSlides: getSlidesPromise, checkToken: checkToken, userLogin:userLoginPromise, getContent: getContentPromise, addComment: addCommentPromise, getComment:getCommentPromise, getKindleEmail: getKindleEmailPromise,bindKindleEmail: bindKindleEmailPromise,
  sendBook: sendBookPromise,
  getNav:getNavPromise,
  search: searchPromise,
  getUser: getUserPromise,
  checkLogin: checkLoginPromise,
  getConfig: getConfigPromise
};
Copy the code

Start with a front page

My personal habit is to write the js part of the page to get data first, and then to write WXML and WXSS. With data filling, it is easier to see the effect of the page than to teach. After debugging the page, I take JS to click events, jump and other code completion. The front-end code is relatively simple, so I will not post it here. It is worth noting that the home page uses the iView component, so in index.json should be used to configure the component

{
  "usingComponents": {
    "i-row": ".. /.. /iview/row/index"."i-col": ".. /.. /iview/col/index"."i-spin": ".. /.. /iview/spin/index"."i-icon": ".. /.. /iview/icon/index"."i-message": ".. /.. /iview/message/index"."i-divider": ".. /.. /iview/divider/index"
  },
  "enablePullDownRefresh":true
}
Copy the code

index.js

let netUtils=require('.. /.. /utils/netUtils.js');
let dataUtils=require('.. /.. /utils/dataUtils.js');
let navUtils=require('.. /.. /utils/navUtils.js');
const { $Message } = require('.. /.. /iview/base/index'); // pages/index/index.js Page({/** ** the initial data */ data: {IMGURL: Recommend :[], recommend recommend :[], recommendPage:1, recommendPageSize:5, // blog blogs: [], blogPage: 1, blogPageSize: 10, //config slideId: getApp().globalData.StorageDB.get('config.slideId'),
    recommendCategoryId: getApp().globalData.StorageDB.get('config.recommendCategoryId'),
    blogCategoryId:getApp().globalData.StorageDB.get('config.blogCategoryId'),
    hasMore:true}, /** * lifecycle function -- listen for page load */ onLoad:function (options) {
    this.getSlides();
    this.getRecommend();
    this.getBlog(a); }, /** * page-related event handlers -- listen to the user pull down */ onPullDownRefresh:function() {this.setData({// recommend recommends: [], recommendPage: 1, recommendPageSize: 5, // blogs blogs: [], blogPage: 1, blogPageSize: 10, hasMore:true
    });
    this.getSlides();
    this.getRecommend();
    this.getKindleBook();
    this.getBlog(a); }, /** * the page on the bottom event handler */ onReachBottom:function () {
    this.getBlog(a); }, // custom methodsgetSlides(){
    dataUtils.getSlides({id:1})
    .then(res=>{
      if(res.data.status=='200'){ this.setData({ slides:res.data.data.item }); }}); },getRecommend(){
    dataUtils.getPostOfCategory({
      page:this.data.recommendPage,
      pageSize:this.data.recommendPageSize,
      id:this.data.recommendCategoryId
    }).then(res=>{
      if (res.data.status == '200') {
        if(res.data.data.pageData.length==0){
          return;
        }
        let recommendPage = this.data.recommendPage;
        recommendPage = recommendPage + 1;
        let recommends = this.data.recommends.concat(res.data.data.pageData);
        this.setData({
          recommends: recommends,
          recommendPage: recommendPage
        });
      }
      else{
        $Message({
          content: 'No data obtained ~'.type: 'error'}); }}); },getBlog() {
    dataUtils.getPostOfCategory({
      page: this.data.blogPage,
      pageSize: this.data.blogPageSize,
      id: this.data.blogCategoryId
    }).then(res => {
      if (res.data.status == '200') {
        if (res.data.data.pageData.length == 0) {
          this.setData({
            hasMore:false
          });
          return;
        }
        let blogPage = this.data.blogPage;
        blogPage = blogPage + 1;
        let blogs = this.data.blogs.concat(res.data.data.pageData);
        let blogLeft=blogs.filter((value,index)=>{returnindex%2! = 0});let blogRight = blogs.filter((value, index) => { return index % 2 == 0 });
        this.setData({
          blogs: res.data.data.pageData,
          blogLeft:blogLeft,
          blogRight:blogRight,
          blogPage: blogPage
        });
      }
      else {
        $Message({
          content: 'No data obtained ~'.type: 'error'}); }}); }, navToContent(e){ navUtils.navToContent(e.currentTarget.dataset.id); },navToBlog(){
    wx.switchTab({
      url: '.. /blog/blog'}); }})Copy the code

The code is relatively simple (after all, the technology is a bit clunkier), but it’s worth noting that the getBlog method takes the blog from the middle and bottom of the front page and loads more when the page hits the bottom

I felt that the simple arrangement was quite mediocre, so I wanted to create a waterfall stream, since there were no performance and appearance requirements, so I made a fake waterfall stream. The specific operation was to divide the data into two halves, the left half and the right half, and loop the two arrays separately in the front end.

Because the page has a pull down refresh and a pull down to the bottom it loads more, so the logic here is,

When pull-up loading is triggered

  1. Data is retrieved from the server
  2. Check whether the data is empty. If it is empty, no more data can be loaded. Set hasMore to false
  3. If it is not empty, it will be spliced to the end of the existing data array, and the page number will be +1 on the existing basis (that is, the operation of the page number will be placed after each request, so that each request can be directly used without considering whether the page number +1), that is, the first spliced before processing the page number and the last setData

When the drop-down refresh is triggered

  1. Set page to 1 to empty the existing blogs data
  2. Call the getBlog

Does this allow getBlog to do both the pull-down refresh and pull-up load functions without having to decide how to process (replace or concatenate) the data requested from the server

End of Issue 1

Rory it wordy of a bit long, more write more feel do not zha to write more zha, see you see the officer make do of see (estimate not a few people will see this place…) I also sorted out my thoughts, hoping to write out what I want to express in the second issue.