After nearly two months of groping and crawling, scratching my head and eating melon, various optimizations (single bet X3), I led the development of the first small program is finally online (SKR SKR! ! First of all, I want to thank my boss for not killing me — because when I first got PRD in early June, my boss asked me how long it would take me to do it. I looked at it and said, “Two weeks.” Up to now, I’m still alive Amazing is it?? Of course, some of this time has changed and changed in the pursuit of “boutique applets”. Well, nonsense or not to say, the following began to sum up next ~

1. Selection of framework

I have never learned native small programs, let alone developed a commercial small program. When I was in my former company, the front-end team shared MPVue when they mentioned the solution of small programs. After I joined the new company, the technical leader also mentioned MPVue, and I have been writing VUE for more than a year. I am familiar with vUE writing, and the new company team has been looking forward to the small program for a long time, hoping to hit the shelves as soon as possible, so I choose MPVUE to develop is the fastest and most reasonable!

2. Project construction

After reading the official document of MPvue, vue-CLI was naturally chosen for the construction of the project. After watching the five-minute tutorial, I used the command vue init mpvue/mpvue-quickstart my-project to generate the basic project. In the later development, The configuration of the project is basically unchanged, except that less-loader is added.

3. Directory structure

It is basically the directory structure generated by VUE-CLI, with some folders added, mainly the configuration folder (API folder) of framework FlyIO used for data interaction with the background, and the vuex (Store folder) used for data management of the whole project. The overall directory structure is as follows:

Project └ ─ ─ ─ the build └ ─ ─ ─ the config └ ─ ─ ─ dist └ ─ ─ ─ node_modules └ ─ ─ ─ the SRC └ ─ ─ ─ the API | ajax. Js / / flyio request and response of interceptor configuration file | config. Js / / Request configuration file | index. Js / / generated request API instance documents | for Server js / / the unified management of project data request file └ ─ ─ ─ components └ ─ ─ ─ pages └ ─ ─ ─ store └ ─ ─ ─ modules / / Vuex modules folder | index. Js file / / vuex | App. Vue | config. Js | main. Js └ ─ ─ ─ the static └ ─ ─ ─ images └ ─ ─ ─ the lib └ ─ ─ ─ weui │ README. │ md Package. The json │ package - lock. JsonCopy the code

Step in a hole

I believe that many students who have used MPVue have more or less guessed some pits, I also stepped on a lot of pits wasted a lot of precious time, although the online article on MPVue trample pits search a large basket, but I still want to write… The following is the pit I encountered in the process of small program development (they) and their solutions:

4-1. TabBar icon problem

The first problem was encountered when configuring the bottom tabBar native to the applet: In the designer to me icon icon set the correct path case, the developer tools on the tabBar icon is always very big, and almost fill the entire height, quite ugly, searched, many bloggers have not found a way to solve the problem during the tabBar also tried their implementation, but after see effect of the shocking OuOu ou, Finally, after comparing some mpvue projects on Github, I found that there was a problem with the icon. Finally, I successfully solved the problem: the size of the icon remains unchanged and proper transparency is set aside around it. Blank… It’s easy, isn’t it? This is wasting a lot of my brain cells, forgive me for being stupid… Of course, one of the problems with native tabBar is that the tabBar title text is very, very close to the bottom on real phones. I don’t have a solution for this, except to implement tabBar myself…

4-2. The problem of old data before data retention in detail page

I think many students have encountered this problem, mainly because mpvue does not destroy the page instance after the page jump, but pushes it into the page stack, so it will save the old data before, and I see that there are many people in the issues of MPvue github who have encountered this problem and have been paying attention to it. Enough to show that this is a pain point problem, who let it affect the user experience of small procedures… The uniform solution seen so far is to initialize and assign the data to be displayed on this page when the onLoad page is loaded, as shown in 🌰 :

<template>
    <html-text :text="htmltext"></html-text>
</template>
<script>
    import htmlText from xxxxx
    export default {
        components: {
            htmlText
        },
        data () {
            return {
                htmltext: ' '}},onLoad () {
            this.htmltext = ' '
            this.$http.get('xxxxxxxx').then((res) => {
                this.htmltext = res.htmltext
            })
        }
    }
</script>
Copy the code

The processing of other arrays or object types may be more troublesome, but the method is similar. In this period of time before the data request is returned, we do not want to leave blank to the user, so as to do some loading, always better than the user to face the old data and then jump to the new data experience.

4-3. Created hook functions are completely executed at project initialization

This is a bug in MPvue, I think? This hook function should not be used in a page.

4-4. Poor performance of THE current MPVUE support for complex rich text

This is not a problem to blame on MPVue, the need to display “quite complex” rich text (long content, multiple images and even multiple GIFs) is not something that many users would normally encounter, but unfortunately I did… Who let us committed to do a forced case of the brand? At present, MPVUE-WxParse has been able to solve most of the problems. Some projects on Github have gained hundreds of stars based on this project. However, my boss and technical boss are not satisfied with the results I have made with this project. Images could not load gracefully, and htmltext was too long and had a long blank screen before the images were fully parsed and displayed, so we finally abandoned the scheme. Then I found another project on Github that improved on mpvue-WxParse for complex rich text. Mpvue-htmlparse was a little better, but still far from what my boss wanted. Finally, I had to fork out a code based on this project to change it personally according to the boss’s needs, and finally passed the test. The project address is mpvue-htmlParse, which mainly improved the loading of pictures. After the first picture was loaded, the home page was notified to turn off the preLoading effect. And then add the load effect of chrysanthemum to each image, the image is completely loaded before displays chrysanthemum figure, and then according to the device screen width and image information of images appropriately enlarged or reduced, so the effect of the whole down basic can achieve “bankruptcy version” WeChat public, tweets, the effect of the project scope is limited, Students who need it can improve on this basis.

4-5. Wechat’s native route redirect navigateTo(),redirectTo(),navigateBack(),switchTab(), reLaunch(), etc., performs oddly on real phones

For parameter passing, I also encountered problems similar to old data, which was finally solved by vuEX. In addition, the number of small program page stack is limited, so we must pay attention to the management of the page stack when developing.

4-6. Use onShow() with caution

Keep in mind that the JS code in this hook function will not only be executed when the page is first entered, but will also be executed when the screen is paused and lit up again.

For mpvue pit suddenly can remember not much, for the moment to write so much, after think of it again to update it.

5. The use of Flyio

In the development of the small program, and did not use the small program native wx.Request () to carry out data interaction, but chose the mpVue document recommended use of Flyio, Flyio introduction is not much to introduce, fight can see the document, here I mainly say the request and response interceptor structure: In fact, there is a very detailed introduction and code in the document, but I failed to solve the login failure problem as expected after I wrote it down according to the code: SRC/API /ajax.js: SRC/API /ajax.js:

/** */ const Fly = require('flyio/dist/npm/wx')
const config = require('./config')

const ajaxUrl =
  process.env.NODE_ENV === 'development'
    ? config.Host.development
    : process.env.NODE_ENV === 'production'
      ? config.Host.production
      : config.Host.test
      
let fly = new Fly()
letConst headers = {... } Object.assign(fly.config, { headers: headers, baseURL: ajaxUrl, timeout: 10000, withCredentials:true}) loginfly.config = fly.config const login = () => {return new Promise((resolve, reject) => {
    wx.login({
      success: res => {
        let loginParams = {
          ...
        }
        loginFly.post('/api/locallogin/url', loginParams).then(d => {
          if (d.headers && typeof d.headers['set-cookie']! = ='undefined') {// Update session wx.setStoragesync ('sessionid', d.headers['set-cookie'])
          }
          resolve()
        }).catch(error => {
          log(error) reject(res.data) }) }, fail: res => { console.error(res.errMsg) }, complete: Res = > {}})})} / / request interceptor fly. The interceptors. Request. Use request (= > {if (wx.getStorageSync('sessionid')) {
    request.headers.cookie = wx.getStorageSync('sessionid')}returnRequest}) / / response interceptor fly. The interceptors. Response. Use (response = > {/ / session have failed and need to log back in small programsif (response.data.errCode === 100009) {
      // log('Session invalid, rerequest session based on user information stored locally... '// Lock the response interceptor fly.lock()return login().then(() => {
        fly.unlock()
        // log(' request again: path:${response.request.url}, baseURL:${response.request.baseURL}`)
        return fly.request(response.request)
      }).catch(err => {
        log(err)
      })
    } else {
      return response.data.data
    }
  },
  err => {
    log('error-interceptor', err)
    if (err.status) {
      wx.showToast({
        title: 'Unknown error occurred',
        icon: 'none',
        duration: 3000
      })
    }
  }
)
export default fly
Copy the code

// create API instance SRC/API /index.js:

import Server from './Server.js'

class Api {
  constructor() { Object.assign(this, ... Array.from(arguments)) } }export default new Api(Server)

Copy the code

6. The use of vuex

Because it is a small program of life shopping, involving complex logic such as shopping cart + address selection, data sharing is required in many places. In this project, VUEX plays a great role because there are many modules. If all the data is written in a file, it will undoubtedly bring great difficulties for later maintenance. Therefore, the data of each module is divided separately and written in their own files, so that the overall process is much clearer. Here is the code for dividing the main file of the module SRC/API/server.js:

/** * This module is mainly used to interact with the server */ import Ajax from'./ajax.js'
async function requestFunction ({params}) {
    let res = await ajax.get('/request/url/', {params})
    ...
    return res.data
}
export default {
    requestFunction
}
Copy the code

src/store/index.js:

import Vue from 'vue'
import Vuex from 'vuex'

import modules1 from './modules/modules1'
import modules2 from './modules/modules2'
import modules3 from './modules/modules3'. Vue.use(Vuex)exportModules1, modules2, modules3, modules3, modules1, modules2, modules3... }})Copy the code

src/store/modules/modules1.js:

import api from '@/api'// Actions use const state = {aaaa,... } const getters = { aaaa (state) {return state.aaaa
    },
    bbbb (state, getters, rootState) {
        returngetters.aaaa }, ... } // Actions can be asynchronous actions const actions = {async anExample ({state, getters, dispatch, commit}, {params}) {let res = await api.requestFunction({params})
        ...
        return res
    },
    ...
}
const mutations = {
    setStateX (state, Y) {
        state.X = Y
    },
    ...
}
export default {
  namespaced: true, // it's importantCopy the code

Call SRC /pages/xxx.vue in the. Vue file

<script>
import { mapState, mapGetters } from 'vuex'
exportDefault {computed: {// Call getters... mapGetters('modules'['aaaa'.'bbbb'}, methods: {// call actionfuncA () {
            this.$store.dispatch('modules1/anExample', {params}).then(res => { ... })}, // call mutationfuncB () {
            this.$store.commit('modules1/setStateX', Y)
        }
    }
}
</script>
Copy the code

7. To summarize

This summary mainly introduces the structure of the project and the problems encountered. (There are many problems encountered in the project, but suddenly feel that those are not problems when writing?) , the use of Flyio (with emphasis on interceptor configuration), and a brief introduction to vuex. Actually wanted to think after completion of project development is not so much, just go during a lot of detours, did a lot of “useless”, actually is useless, but also from the harvest quite a lot, after all from scratch yourself from 0 to 1 build a project, including a lot of trouble, but really can make people grow a lot, also let me feel quite full. Because the small program is the company’s commercial is not my personal project, so the project code can not open source, if there is a problem can contact me, to prevent the suspicion of advertising here does not explain the name of the small program, want to experience can be private letter to me, also welcome everyone to correct!

The boss came to me for issue two. Incoming!