Write in front:

Small program cloud development issue for some time, recently set out to do a small program based on cloud development project – “weibo fresh knowledge”, this kind of new style from sina although small program interface is very simple and pure and fresh, but the inside is hidden within a lot of mystery, meets a lot of obstacles in the way of implementation, to share with everyone here. I hope to give you some ideas.


To show you the final results: More images are available here

First, the idea of componentization

When developing a complete small program, we should first analyze its internal structure. Repetitive structures are extracted as components, which are very flexible and can be embedded in one or more pages.

In the GIF above we can see that the content of the front page is one news block after another. Although this news block is only used on the front page, I’ve pulled it out as a component. The advantage of this is that the structure of the page will be clearer and less coupled-for example, if you want to change the style of the main interface, you can just add another component to it.

There are also news internal pages, there are a number of sub-headings, each sub-title embedded in the unequal number of news. Without componentization, the WXML structure of inner pages would be a mess. So the advice here is to try to componentize it. Component-based Development Tabbar Is the project’s page and component directory:

Second, database design

Since it is “full stack”, the back end must be done. The core of the back end is the data. So let’s take a look at the database. So here’s the analysis,

  • Get the fields from the page,
  • And then understand the relationships between data, like many-to-many, one-to-one.

So here I’ve built five sets

The subNews field of the fresh-MainNews homepage news set is a sequence that stores the _id of the fresh-Subnews Doc. This binds the two sets together. Later we will talk about fusing the two sets together in the cloud function to return a new set with more complete data.

One might ask if a cloud database isn’t noSQL, why not consolidate all the data into a single, all-in-one JSON so that JSON can be called only once.

My understanding is: we only need to query the data we want, and the data we don’t need can be requested according to the association when needed. For example, the home page news block in this project, each news block is associated with a large number of sub-news, the first time to load all the data that this small program needs to load out is a little crazy.

  • A collection of fresh-subNews headlines on internal pages
  • Fresh-comments Collection of comments
  • Fresh-detailnews Detailed news collection
  • Fresh-users user collection See more database information here

Third, page construction

This brings us to page building. A page can be thought of as a shelf, a container for data. The page comes alive with data. MVVM, data-driven view. Interaction is data, communication between components, and communication between components and pages is data. {{}} -> Like the magic portal of the Vagabonding wizard. An excellent example of component communication will be shown below (click on how to implement title bar top of catalog).

Fourth, about cloud development.

Cloud functions: Generally speaking, the functions you write are run in the cloud and complex business logic can be put in the cloud functions. Database: A JSON database storage that can be operated in the front end of a small program and read and write in the cloud functions: In the front of the small program directly upload/download cloud files, in the cloud development console visual management, you can upload photos download photos, or some other files. Here is a detailed introduction to the process of operating cloud functions to extract database. Here we take home page data as an example:

  1. Start by creating a new function in the cloud functions directory: mianNewsGet

Cloud functions official documentation

  1. Write cloud functions to query data
// cloud function entry file const cloud = require('wx-server-sdk'Cloud.init () // get database handle const db = cloud.database() // exports.main = async () => {const db = cloud.database() // exports.main = async () => {const mainNewsList = []; // Get all the data from the fresh-mainNews collection, because there is not much data in the database now, // If there is more, you can set onelimitConst mainNews = await db.collection(const mainNews = await db.collection("fresh-mainNews").get();  
    for(let i = 0; i < mainNews.data.length; i++) {
      const mainNew = mainNews.data[i];
      letuser_id = mainNew.setMan; Docments const user = await db.collection('fresh-users').where({ _id: user_id }).get(); If there are more than one, add only oneif(user.data.length > 0) {mainnew.setman = user.data[0]} // This loop is a concatenation of collectionsfor (let i = 0; i < mainNew.subNews.length; i++) {
        const subNews = await db.collection("fresh-subNews").where({
          _id: mainNew.subNews[i]
        }).get();
        if(subnews.data.length > 0) {mainnew.subnews [I] = subnews.data [0]} // Merge the data into a more complete JSON array mainnewslist.push (mainNew); }return mainNewsList;
}
Copy the code
  1. Call the cloud function from the onLoad function in index.js
var that = this; Wx.cloud. callFunction({// declare the name of the called function:'mainNewsGet'A = 1 data: {a: 1}}). Then (res => {//res.result)returnSetData ({mainNewsList: {mainNewsList: {setData: {mainNewsList: Console.log (this.data.mainnewslist)}). Catch (err => {console.log(err)})Copy the code

* * * * * * * * * * * * * * * * * * * * * * * * * * * * [_id1.value,_id2.value~~] —> [{_id1:value,key1:value1,key2:value2},~~~]

Cloud function call, database query. Is so simple four steps, the threshold of cloud development is very low, the function is also very powerful, as long as you try, very easy to achieve.

Five, about time formatting.

  1. Add xx.js to the utils folder
const formatTime = date => {
    var dateNow = new Date();
    var date = new Date(date);
    const hour = date.getHours()
    const minute = date.getMinutes()
    var times = (dateNow - date) / 1000;
    let tip = ' ';
    if (times <= 0) {
        tip = 'just'
        return tip;
    } else if (Math.floor(times / 60) <= 0) {
        tip = 'just'
        return tip;
    } else if (times < 3600) {
        tip = Math.floor(times/ + 60)'Minutes ago'
        return tip;
    }
    else if (times> = 3600 && (times <= 86400)) {
        tip = Math.floor(times+ / 3600)'Hours ago'
        return tip;
    } else if (times / 86400 <= 1) {
        tip = Math.ceil(times+ / 86400)'yesterday'
    }
    else if (times / 86400 <= 31 && times / 86400 > 1) {
        tip = Math.ceil(times+ / 86400)'days ago'
    }
    else if (times / 86400 >= 31) {
        tip = 'Light years ago ~~'
    }
    else tip = null;
    return tip + [hour, minute].map(formatNumber).join(':')
}

const formatNumber = n => {
    n = n.toString()
    return n[1] ? n : '0'Module. exports = {formatTime: formatTime,}Copy the code
  1. Import {formatTime} from ‘.. /.. /utils/api.js’;

  2. Format the acquired time data

let mainNewsList = that.data.mainNewsList
      for(leti =0; i < mainNewsList.length; i++) {letTime = formatTime(mainNewsList[I].time) // This issetArray usage of Data(), we often use var STR ='mainNewsList['+i+'].time' 
        that.setData({
          [str]:time
        }) 
    }
Copy the code

6. Tips on small programs that are useful but you may not know

  1. Full screen display of images, the ability to slide multiple images left and right and the digital index is now on the screen, and long press can also bookmark and download.
Wx.previewimage ({current: imgUrl, // HTTP url of the current image: imagePack // HTTP link list of images to preview})Copy the code
  1. A very handy API that can slide to a location
Wx.pagescrollto ({scrollTop: a number (with a px unit), // Scroll to the number duration: 50 // time to scroll})Copy the code
  1. Query the official documents of query.selectall (‘ class name ‘) and query.select(‘#id’)
var that = this
let catalogIndex = that.data.catalogIndex;
query.selectAll('the name of the class').boundingClientRect(function (rects) {
        rects.forEach(function(rect) {rect.top // the upper boundary of the node st, // there are some other attributes, this query node is the directory jump key API})})})}).exec()},Copy the code
  1. SetData () some tricks.
// Array values can also be var xx ='xx['+idx+'].key'In the form of vardoneList = 'doneList['+idx+'] '
      that.setData({
        [doneList]: true,})Copy the code

Sometimes we can change the value of a number before setData(). This is a useful technique for setData(), but it needs to be used to understand it. For example:

 dataPack.likeNum = (supLikeNum===-1 ? dataPack.likeNum: supLikeNum);
    this.setData({
      comment: dataPack,
    })
Copy the code

Vii. The two most exciting parts of the project

(The article code layout may be difficult to read, like the project address given at the end of the article to find out)

1. Click the table of Contents page to put the corresponding news bar at the top and have a look at the effect





  • Click on the directory bar item if the binding to a data – independence idx is equal to the cycle index, can be in the e.c. with our fabrication: urrentTarget. Dataset. Independence idx to get this item index.
  • We pass this data through component communication to the inner page, which then passes the data to the subNews
  • And bind the goTop event of subNews in js of inner page, so that a catalog component ->inner page ->subNews association is generated, and the data is the index of item. 1. Catalog /index. WXML 1. Catalog /index. WXML
<block wx:for="{{subNews}}" wx:for-item="subNewsItem" wx:for-index="idx" wx:key="index">
            <view class="subTitle-item" bind:tap="scrollFind"// Key 1: bind item index data-hi="{{idx}}">
 <text>{{subNewsItem.title}}</text>
                </view>
        </block>
Copy the code
  1. Get the index and bind the inner page catalog/index.js
 scrollFind: function(e) {// Implement the top of the specific news subtitle on the inner page after clickingletCurIndex = e.c. with our fabrication: urrentTarget. Dataset. Hi / / key 2: get in touch with inner page var myEventDetail = {index: Var myEventOption = {} // This. TriggerEvent ('catalog', myEventDetail)
    }
Copy the code
  1. Inner /inner. Js gets the communication with catalog
 onCatalog: functionConsole. log(e.daail.index) // key: store index to data this.setData({catalogIndex: // this.subnews =this.selectComponent(e.daile.index}) // this.subnews =this.selectComponent("#subNews")
    this.subNews.goTop();
  },
Copy the code
  1. Upload catalogIndex to subNews with id
<subNews ~ omitted ~ catalogIndex="{{catalogIndex}}" id="subNews"></subNews>
Copy the code
  1. Define an image loading event in subNews so that its bound event is triggered when the page is finished loading, inspired by waterfall flow. The onImageLoad function can be triggered when the image is loaded, and in this function we can do some preparatory work.
//subNews/index.wxml // an invisible image, inspired by a waterfall stream, can generate actively triggered events"display:none">
  <image src="{{mainImg}}" bindload="onImageLoad"></image>
</view>
Copy the code
//subNews/index.js
onImageLoad: function () {
      var that = this
      letoffsetList = that.data.offsetList; Const Query = wx.createsElectorQuery ().in(this) // The API we talked about earlier gets the node information. We store it in the offsetList array, which stores the location of each node on the screen. Query. SelectAll (wx.pagescrollto)'.subNews-wrapper').boundingClientRect(function (rects) {
        rects.forEach(functionPush (rect.top) that.setData({offsetList,})})}).exec()},Copy the code
  1. Bind the title bar with the goTop event
goTop: function (e) {
      var that = this
      letcatalogIndex = that.data.catalogIndex; // Where offsetList is the data inside a data, to hold the top distance coordinates of all nodesletoffsetList = that.data.offsetList; Wx. pageScrollTo({scrollTop: offsetList[catalogIndex], duration: 50 // Time spent scrolling})}Copy the code

At this point, you have implemented this seemingly simple but very clever function, component -> page -> component, dazzling. If you still don’t understand, you can download my code later. The reason for making an image load trigger that event is that if you put the function that gets the offsetList array in goTop, the first click on the page will not be valid and the experience will be very uncomfortable.

2. Like optimization

To show you the effect:

The “like” delay is greatly reduced, and the “like” is as smooth as milk








  • Start with the traditional, partial refresh optimized, and still very bad code:
for(leti = 0; i< that.data.comments.length; I++) {// when this comment is clicked, only this data is updatedif (i == idx) {
            var str = 'comments['+idx+'].likeNum'
            that.setData({
              [str]:res.result.data.likeNum,
            })
            console.log(likeNumList[idx])
          }
        } 
Copy the code
  • After the optimization:
  data: {
    doneList: [], / / whether the press likeNumList: [], / / simulation likeAdd thumb up counting group: 10, / / thumb up every time we increase number, according to your Settings, back-end every time you add 1 here write 1}, vardoneList = 'doneList['+idx+'] '
likeNumList[idx] = (that.data.comments[idx].likeNum + that.data.likeAdd);
      that.setData({
        likeNumList,
       [doneList]: true,
        likeAdd: that.data.likeAdd+10
      })
Copy the code
<text class="dianzanNum">{{likeNumList[idx]? likeNumList[idx]:item.likeNum}}</text>Copy the code

What is the idea of optimization? Use an array to store/simulate the updated data. If the index position of the number is assigned, the page displays the updated number directly. Because the user is concerned about the change of data, we can produce the change of data first, and let him do it asynchronously and slowly as to the change of data back-end. If you spread your thoughts from here, can the comment function also use the same idea to achieve the ultimate speed and interactive experience?




I don’t have enough space, so thank you for reading. Project address :github.com/HappyBirdwe… Well written project, details are very good yo, welcome everyone


Conclusion: the road of learning is bound to be bumpy, I hope the sharing of this article can provide you with some ideas and reduce a little detours in the process of learning, this is the biggest value of this article, welcome your questions and corrections.

Finally, I would like to thank you for the technical support provided by Tencent Cloud. The author of Sina team’s weibo is not well known. Nuggets is an excellent platform

Micro blog xianzhi small program official portal: the experience is really good oh, the interface is very simple, we can experience a wave