preface

  • I learned wechat small program cloud development for a while. In order to consolidate the knowledge learned and improve practical experience, I decided to cooperate with my classmates to complete a small program. Here I mainly share the part I am responsible for and some of the learning process, I hope to help you, the new xiao Bai one, there are a lot of deficiencies in all aspects, please give me your advice (~ ▽ ~)

rendering

  • Check out some of the photoshoot from ٩(danjun ^o^ danjun) p
  • Personal center renderings

  • Personal space renderings

  • Friends list effect drawing (can realize unfollow, add follow, group function)

  • Friends fuzzy search effect

Prepare before you start

  • VScode code editor
  • Wechat developer tools
  • Have a good vant component library
  • Iconfont icon library

instructions

  • This project is based on the small program cloud development, using the template of cloud development quick start template, the development process used components, cloud functions, database and other related knowledge, all the project data are stored in the cloud database

Note: Data permissions must be set to all users readable, only the creator can read and write (´△ ‘)

The overall architecture

-- cloudfunctions cloudfunctions remove remove -- commponent custom components list default groups special special concerns -- images icon icon -- pages mine personal center mySpace My space myFriend my focus friendSearch search for friendsCopy the code

Cloud function

Cloud functions simply refer to the code running in the cloud backend (Node.js), and the execution process of these codes cannot be seen locally. The fully closed only exposes the interface for local invocation, and the local only needs to wait for the result to be returned after the cloud code is executed. This is also the idea of interface – oriented programming.

remove Cloud function

  • Called when unfollowing my friends pageremoveCloud function
// const cloud = require('wx-server-sdk') cloud.init() const db=cloud.database() const DefaultList =db.collection('defaultList') const specialConcern=db.collection('specialConcern') // cloud function exports.main = async (event, Context) => {const wxContext = cloud.getwxContext () const _id=event._id // Get the _id of the incoming up host to unattend const dl=await Defaultlist.doc (_id).remove() const sc=await specialConcern. Doc (_id).remove() return {// return the deleted result dl, sc } }Copy the code

Custom Components

This component will be used in my friends page. I created a custom component List and Special under the Commponent folder, and realized the functions of clicking the “follow” button to pop up an operation menu, which can be unfollowed, followed and grouped

  • The WXML part of the Special component (same with the List component)

<view class="special" > <view class="special_hd"> <view class="avatar"> <image SRC ="{{specialConcern. </view> </view> <view class="special_bd"> <text class="up">{{specialConcern.up}}</text> <span class="digest">{{specialConcern.digest}}</span> </view> <view class="special_ft" bindtap="getInfo"> <button Wx :if="{{tapIndex==1}}" class="concern" bindtap="concern"> </button> </button> </view> </view>Copy the code

Access to information

/ / get up information about the main getInfo () {enclosing triggerEvent (' getInfo, {. Avatar: this data. SpecialConcern. Avatar, up:this.data.specialConcern.up, digest:this.data.specialConcern.digest }) }Copy the code

The operating menu

  • Click the concerned button to pop up the operation menu, custom components trigger events, usetriggerEventMethod that specifies the event name, detail object, and event options

Wx. showActionSheet({itemList:[' default group ',' unconcern '], success:res=>{console.log(res); This.setdata ({tapIndex:res.tapIndex // Select the default group, tapIndex is 0; Unfollow, TapIndex 1}) / / custom triggers cancle this. TriggerEvent (" cancle ", {_id: this. Data. SpecialConcern. _id, TapIndex: this. Data. TapIndex})}})}, / / a renewed focus on concern () {enclosing setData ({tapIndex: 2 / / let the + button hidden, Has focused on button appears}) / / custom trigger concern this. TriggerEvent (" concern ", {_id: this. Data. SpecialConcern. _id, tapIndex:this.data.tapIndex }) }Copy the code

Personal Center page

Authorized to log in

  • The main focus of the personal-centric page is the login operation, so I will only cover the login aspect here
  • Considering that user information will be used in multiple pages, for convenience, I store the information obtained through authorization globally and do the following operations in app.js
 globalData : {},
  onLaunch: function () {
    const userInfo=wx.getStorageSync('userInfo')
    if(userInfo){
      this.globalData.userInfo=userInfo
    }
Copy the code
  • Before login, the page content is blank, and the profile picture is the default profile picture. After authorization, obtain the information and log in, expand the content and usehasUserInfoCheck whether the login status is authorized
<block wx:if="{{canIUse && ! hasUserInfo}}"> <image src=".. /.. /images/icons/defaultTx.png" mode="aspectFill" class="owner-avatar"/> <button class="owner-name" open-type="getUserInfo" </button> </block> <block wx:else> <image class="owner-avatar" src="{{userInfo.avatarUrl}}" mode="aspectFill"></image> <text class="owner-name">{{userInfo.nickName}}</text> </block>Copy the code
Data: {canIUse: wx.caniuse (' button.open-type.getUserinfo '), // Check whether the API of the applet is available in the current version hasUserInfo:false, userInfo: Async getUserInfo(e){wx.setStoragesync ('userInfo', If (app.globaldata.userinfo){app.globaldata.userInfo) app.globaldata.userInfo = e.dail.userInfo / / here is this. In order to determine whether authorization success setData ({the userInfo: e.d etail. The userInfo, hasUserInfo: true, canIUseGetUserProfile: true})}}, // Remember to authorize login, Async onLoad(options) {const userInfo= app.globaldata.userinfo if(userInfo){this.setData({ hasUserInfo:true, userInfo:userInfo, }) } },Copy the code

My space page

The page layout

  • The overall page layout is simple, mostly using Flex layout
  • To customize the header navigation bar for the background image, just add a single line of code to the JSON
"navigationStyle": "custom"
Copy the code
  • For navigation bars and sliders,currentRepresents the current slide page,indexRepresents the navigation bar index, using them to link the navigation bar to the page, the rest of the HTML layout of the page is not covered.
<! <view class="nav"> <view class="nav-content {{index==current? 'active-nav':''}}" wx:for="{{navList}}" wx:key='{{index}}' data-index="{{index}}" bindtap="currentNav"> <text>{{item.title}}</text> </view> </view> </view> <! -- swiper --> <swiper style="height:{{currentHeight}}px; background-color: white;" CurrentPage (e){this.setData({current: e.diail.current})}, / / the currently selected navigation currentNav (e) {enclosing setData ({index: urrentTarget of e.c. with our fabrication:. The dataset. The index, current:e.currentTarget.dataset.index }) },Copy the code

My friends page

The navigation bar

  • On the page, swiper will make two sliders of attention and fans. You can slide back and forth, and click the navigation bar to switch, realizing linkage between the navigation bar and the slider
wxml <! <view class="nav" > <view class="concern-fans {{index==current? 'active-nav':''}}" wx:for="{{concern_fans}}" wx:key="index" data-index="{{index}}" bindtap="currentNav">{{item.title}}</view> </view> <! <swiper style="height: 100vh;" Current ="{{current}}" bindchange="currentPage"> js // currentPage(e){this.setData({current: e.dail.current}) }, / / the currently selected navigation currentNav (e) {enclosing setData ({index: urrentTarget of e.c. with our fabrication:. The dataset. The index, current:e.currentTarget.dataset.index })Copy the code

Component declarations

  • The search bar uses the Vant component library to be declared, as well as the custom components of the focus list (declared in JSON)
//myFriend.json "usingComponents": { "list":"/components/list/index", "special":"/components/special/index", "van-search":".. /.. /miniprogram_npm/@vant/weapp/search/index" },Copy the code

Search bar

  • In the search part, I directly introduced van-search component, here you can see the detailsVant component library, the real search does not need to realize the search function in this page, the real search will build a separate page to complete, it only needs to complete the jump. So I set up a separate search pagefriendSearchPut it in the Pages folder, as explained in the search page below.
<! -- Search bar --> <navigator URL =".. / friendSearch friendSearch "> < van - search focus =" false "shape =" round "placeholder =" search my attention "> < / van - search > < / navigator >Copy the code

Focus list bar

  • List title bar, where the only detail is by changespecialisShowTo control whether the list bar is expanded or not.

//myFriend.wxml <! <view class="content"> <view class="concern" bindtap="openClose1"> <image wx:if="{{specialisShow}}" class="arrows" src=".. /.. /images/icons/downarrow.png"/> <image wx:else class="arrows" src=".. /.. / images/ICONS/uparrow. PNG "/ > < text class =" text "> special attention < / text > < span class =" count "> {{specialCount}} < / span > < / view > // myfriend.js openClose1(e){// List whether to expand const specialisShow= this.data.specialisshow if(specialisShow==true){ this.setData({ specialisShow:false, }) }else { this.setData({ specialisShow:true, }) } }Copy the code
  • Focus on the list bar, which uses custom component Special (detailed in the previous component directory) to bind custom trigger events in component methods in myfriend.jsgetInfo.cancle.concernAnd the value

//myFriend.wxml <! Wx :key="index" wx:if="{{specialisShow}}"> <special id="special" specialConcern="{{item}}" bind:getInfo="getInfo" bind:cancle="specialCancle" bind:concern="specialConcern"></special> </block> // myfriend.js getInfo(e){// Cache the selected up main information wx.setStoragesync ('info', e.fix)}, SpecialConcern (){let info= wx.getStoragesync ('info') // Get selected up specialConcern. Add ({data:{up:info.up, digest:info.digest, avatar:info.avatar } }) } specialCancle(event){ let tapIndex=event.detail.tapIndex let _id=event.detail._id If (tapIndex = = 1) {/ / tapIndex = 1 indicates operation menu select cancel attention wx. Cloud. CallFunction ({/ / remove cloud function called to cancel the attention function name: 'remove', Data :{_id:_id}})} else if(tapIndex==0){//tapIndex=0 let info= wx.getStoragesync ('info') // Get information and add information to the target group Defaultlist. add({data:{up:info.up, digest:info.digest, avatar:info.avatar}}) wx.cloud.callFunction({// After adding information to the target group, Name :'remove', data:{_id:_id}})}},Copy the code

Search page

  • This page is the real search page by clicking on the search bar in your friend’s page, where the search function will be implemented.
// search box <van-search value="{{value}}" shape="round" focus="true" placeholder=" search my attention Bind :change="onChage" bind:search="onSearch"> <view slot="action" bind:tap="onClick"> </view> </van-search <block wx:for="{{defaultList}}" wx:key="index"> <list defaultList="{{item}}"></list> </block> / search failed <view class="blank"  wx:if="{{searchError}}"> <image class="blank-img" SRC = "https://s1.hdslb.com/bfs/static/jinkela/space/assets/nodata02.png" / > < text class = "blank - the text" > can't find the user ~ < / text > </view>Copy the code

Fuzzy query

  • Search success

  • Search failure

  • Listen for input values, passonChange()Always listen for the value entered in the search box and assign the value to value
onChage(e){            
    // console.log(e);
    this.setData({
      value:e.detail
    })
  }
Copy the code
  • Encapsulating query functionqueryArray()inputtedvalueValue to implement the query, the details are what I use in order to implement the fuzzy queryindexOfQuery a string. If at least one match is successful, output the result
async queryArray(){ let value=this.data.value let arrList=this.data.arrList for(let i=0; i<arrList.length; i++){ if(arrList[i].up.indexOf(value)>=0){ // console.log([arrList[i]]); This.setdata ({searchError:true})} else{// Query failed this.setData({searchError:true})},Copy the code
  • Merge array, because I put the data that I care about and the data that I care about by default in two sets, but I want them to be in one array for easy query, so I need to merge the two arrays and define a merge array functionaddArray(), it is ok to call it when needed
Async addArray(){let arr1= await db.collection('defaultList').get().then(res=>{return res.data}) let Arr2 = await db.collection('specialConcern').get().then(res=>{return res.data}) let arr=[...arr1,...arr2] this.setData({ arrList:arr }) },Copy the code
  • Call a functionqueryArray()
OnClick (){this.queryArray()},Copy the code

The source code

Project source, also contains the results of the other two students, including home page and other pages of the source

conclusion

Finally finished, (ಡωಡ) Hiahiahia would like to thank the teachers and students who helped me when I encountered a bug and pulled my hair to save me in time. If you like this article or can help you, give it a thumbs up! Also, you have a cameo appearance with suggestions below!