微信小程序開發的思考與總結(一)

1、小程序中 this 的指代問題

箭頭函數可以保證 this 的指代是不變的 :success: res => { }

 wx.request({
      url: `${config.baseUrl}restful風格的api`, 
      data: {
        x: ''
      },
      header: {
        'content-type': 'application/json'
      },
      success: res => {
        
      }
    })

2、小程序各類型文件的分工

wxss:頁面樣式

wxml:頁面骨架

json:相關頁面配置

js:一般是認爲是業務邏輯,但在頁面的 js 裏,真的應該用於寫業務邏輯嗎?

  1. 這個問題應該放在具體場景/項目來講,如果是示例型的,業務邏輯寫在 js 裏完全沒問題。
  2. 但真正大型低耦合的項目中,不注重良好的分層結構,最後導致項目無法維護。
  3. js 本身就是動態語言,沒有類型的約束下,還是把代碼都堆疊在一起,將來一定會是非常混亂的。

所以,頁面的 js 並不應該編寫業務邏輯。

那麼,頁面的 js 不寫業務邏輯,應該做什麼呢?主要用於數據綁定,也即 view (視圖層) ,可以視爲 “業務邏輯” 與 “頁面” 之間的橋樑 / 中間層。

熟悉後端的看到這裏就不陌生了,也即常見的 MVC

3、小程序中使用面向對象的方式編碼

在工程裏新建的 model 目錄,作爲類似後端中的 service 層,那麼名字如何取?

home 不應該是常說的業務對象,那什麼是一個業務對象?按當前請求的數據 / 作用的模塊進行命名,類似後端的用戶 service、其他業務 service 等

4、前端與後端的思維方式?

對於後端來講,很多時間就是需要去找業務對象。

那麼前端同理,如今的前後端的界限其實非常模糊,也即所謂的全佔,哦,寫錯了,是全棧。

因爲在以前本身就沒有前端和服務端之分,程序員嘛,管你什麼類型,一起擼就完事。

只是現在的前端工作非常重,所以一個程序員沒有辦法也沒有那麼多精力(畢竟晚上。。。)同時完成兩端。

從編程的本質來講,前端和服務端確實沒有太大區別。

由此,業務對象的尋找非常重要。(期末要考的,劃線啊)

舉個栗子

比如 user 、search、spu、address、sku 等都是一個業務對象

class User{
  static getUserInfo(){
    
  }
}

export {
    Theme
}

爲什麼是定義成 static ?後面再解釋,這麼猴急幹嘛,衣服都沒脫,哦,不是,是定義一些非 static 方法的時候再來對比。

我偏不要 static 行不行?行啊,在其他地方調用這個方法,你再實例化一次 User 唄。加了 static 就可以直接 User.getUserInfo()

5、model 中方法的命名

getUserInfo() 我寫的駝峯啊,沒問題啊,但是你從大局來看,個人資料裏叫 getUserInfo()  ,個人資料另一個地方要獲取朋友的用戶信息,get 什麼 info呢?

用業務來命名?顯然不對嘛,CMS 裏一改,本來是用戶信息的,現在成了性感荷官在線發牌,還是 getUserInfo() ?

那按順序來吧,都定義一個編號,比如第一個叫 getXxInfoA(),第二個叫 getXxInfoB() 

還不對?我在其他頁面也有用到這個方法呢?再加個前綴唄,getMindXxInfoA()

6、將原 home.js 的業務邏輯搬到 model 的方法裏

這樣真的就合適了嗎?

還想怎樣啊,都按照上面寫的進行了。。。莫急啊,都說了還沒脫褲子,  繼續往下看

一個 class 只有一個 request 請求嗎?顯然不對吧,那每一個 request 都寫一個 wx.request ?重複寫那麼多幹嘛,又不是按代碼行數給你算錢。。。抽成封裝對象

7、封裝 HTTP 請求

就算上述的一個 class 的衆多 request 都不做抽取,那也是沒辦法運行的,模型哪裏啦的 setData?Page 纔有吧,鑑於此

最簡單的方式就是,讓 class 的 方法接收回調函數

class User{
  /*老是忘記寫的註釋*/
  static getMindUserInfoA(callback){
    wx.request({
      url: `${config.baseUrl}restful風格的路徑`,
      data: {
        x: ''
      },
      header: {
        'content-type': 'application/json'
      },
      success: res => {
        callback(res.data);
      }
    })
  }




}

export {
    Theme
}

在原來寫這段代碼的地方進行調用

Theme.getMindUserInfoA(data => {
     this.setData({
         userinfo: data
     });
   });

假如這個 class 裏要寫 100個 request 請求呢?那就要一百遍 wx.request 啊,所以再封裝一次

在 utils 下新建一個 js 

import { config } from "../config/config";

class Http{
  static request({url, data, callback, method='GET'}){
    wx.request({
      url: `${config.baseUrl}${url}`,
      data,
      method,
      header:{
        'content-type': 'application/json'
      },
      success(res){
        callback(res.data)
      }
    })
  }
}

export {
  Http
}

改造原有 User 下的 getMindUserInfoA()

import { Http } from "../utils/http";

class User{
  static getMindUserInfoA(callback){
    //調用方法的時候傳入一個對象
    Http.request({
      url: `restful風格的路徑`,
      data: {
        x: ''
      },
      method: 'GET',
      callback: data => {
        callback(JSON.parse(data))
      }
    });



  }
}






export {
    User
}

原來 home 下的 js 不變(別忘記引入 User

import {User} from "../../model/User";

User.getMindUserInfoA(data => {
     this.setData({
         userInfo: data
     });
   });

爲何上面 User 下的 getMindUserInfoA() 調了回調函數又調一次?因爲 home 下的 js 傳入了一個 callback

尼瑪,回調函數裏又有回調函數,跟我說封裝好了?別急,再往下看,真的褲子還沒脫

8、小程序中使用 async 和 await (小程序中暫時還是不支持的,你不知道嗎?)

第 7 點鐘封裝的 http 請求還是很麻煩,它在每一層調用的時候,都需要主動接收一個 callback 回調函數作爲參數,爲何?

舉個栗子

比如有 fun1,fun2,fun3 ,依次進行調用,也即 fun1 調用 fun2,fun2 調用 fun3 ,一層層調用的時候是不需要 callbak 的,那爲何上面的調用需要呢?

原因是本栗子的三個函數的調用都是同步,但是第 7 點中由於最裏面 wx.request 是異步的請求,在各個層之間,只要有一層是異步調用,那麼就會導致層與層之間的函數調用都必須是異步的,否則 http.js 的請求還沒完,第一層就 setData了,那肯定不行的。

9、處理異步調用的三種方式

1、callback  

最基礎的一種形式,但卻是最噁心的,第 7 點的封裝才3層,已經用兩個 callback 了

2、promise

這種方式依然不夠簡潔,雖然比 callbak 要強

3、async await

基於 promise 的,只有一個函數返回 promise 才能使用此種方式

10、如何在小程序中全面支持 async await

有人就會說了,直接加上不就得了唄

import { config } from "../config/config";

class Http{
  //由於在函數內部出現了 await,那麼在方法名前就要加 async
  static async request({url, data, callback, method='GET'}){
    await wx.request({
      url: `${config.baseUrl}${url}`,
      data,
      method,
      header:{
        'content-type': 'application/json'
      },
      success(res){
        callback(res.data)
      }
    })
  }
}

export {
  Http
}

但是,如果要在一個函數的調用比如 wx.request 中使用 await 的前提,是這個函數的調用必須要返回結果(不是說一定要返回 promise ),事實上一個函數返回的結果不是 promise 也是可以加 await 的,比如一個函數的調用後返回的是 1 ,只不過1這種常量的結果,加 await 是沒有意義的。

所以,不是說 await 一定要加在 promise 前面,一個函數調用返回的結果是常量,也可以加 await,只不過是脫褲子放屁

事實上,await 是求值,返回的是1,用 await 加上1,結果還是 1。

wx.request 這個函數並不會返回 promise,至少目前小程序版本不會返回。事實上,這個函數不會返回任何值,所以直接加上 await 是沒有意義的。

另外提一點

小程序的雲開發中有很多內置函數,類似 wx.request ,調用了雲函數但如果不傳 success ,那麼雲函數就會知道,你期望的不是使用回調函數的結果來接收這次 API 的調用,而是要使用 promise 來接收。

但,小程序中所有 wx 開頭的 API 中都不能直接返回 promise,都只能夠使用回調函數的形式返回結果。(別問我,問騰訊)

11、來完成第 10 點的封裝吧

軟件裏各種各樣的疑難雜症,都是可以通過一層層封裝來解決。事實上,軟件世界,就是在不斷的封裝

在 utils 中新建一個 js,將內置非 promise  API 轉爲 promise

const promisic = function (func) {
  return function (params = {}) {
    return new Promise((resolve, reject) => {
      const args = Object.assign(params, {
        success: (res) => {
          resolve(res);
        },
        fail: (error) => {
          reject(error);
        }
      });
      func(args);
    });
  };
};



export {
  promisic
};

這段代碼的作用:可以將小程序內置的任意 API 全部都可以轉成 promise 形式返回

基本用法

將 wx.request 作爲參數傳到 promise 中(傳入的雖然是函數,但不能加(),加了()就表示已經直接調用這個函數了)

可以簡單理解成就是調用了 promise 函數,函數調用則需返回結果,這個返回結果比較特殊,返回的是一個函數(看到這裏是不是又覺得很熟悉?對,沒錯,類似 Java8 新特性,通過行爲參數化傳遞代碼,傳遞 Lambda 表達式)

既然是一個函數,那麼就可以在最後加()調用

promisic(wx.request)()

小問題

原來 wx.request 需要傳遞參數,使用 promisic 包裝後怎麼傳?只需要在最後的 () 傳遞即可

promisic(wx.request)({url, data, callback, method='GET'})

回到 http.js 中

import { config } from "../config/config";
import { promisic } from "utils";

class Http{
  static async request({url, data, callback, method='GET'}){
    await promisic(wx.request)({
      url: `${config.baseUrl}${url}`,
      data,
      method,
      header:{
        'content-type': 'application/json'
      }
    })
  }
}




export {
  Http
}

12、promisic 簡易原理

實際上 promisic 定義的就是一個 function,它需要接收另一個 function 作爲參數,然後在內部進行包裝,這也就是爲什麼傳遞函數作爲參數之後還可以加() 並增加參數。

因爲它返回結果本身就還是一個function ,自不過這個 promisic 內部使用 promise 把原來的 API 進行了包裝,所以是在 promise 裏面幫你調用了原來的 API success 和 fail 。

在這個 promise 也用到了一種設計模式,代理模式。原來是直接調用的 API,現在是通過 promisic 代理調用。

13、將回調函數全部替換爲 async 和 await 

callback 不需要了,因爲 async 與 await 實際上就是同步的方式調用異步的函數。

回到 class 下的 User

(一個函數前面加上了 async 之後,表示這個函數的返回結果最終一定會返回 promise,哪怕返回的是 1,那也是通過peeomise 包裝後的 1)

import { Http } from "../utils/http";

class User{
  static async getMindUserInfoA(){
    //調用方法的時候傳入一個對象
    return  await Http.request({
      url: `restful風格的路徑`,
      data: {
        x: ''
      },
      method: 'GET'
    });
  }
}






export {
    User
}

home.js 調用處

const resData = await User.getMindUserInfoA();
var data = resData.data.data;
data = JSON.parse(data);
this.setData({
  userInfo: data
});

 

14、<block> 

其實只是一個佔位符,沒有實際意義

 

15、swiper 與 swiper-item 中 image 的樣式

除了要設定 swiper-item 中 image 的樣式,還得設置最外面swiper 的高寬

16、使用 npm 引入現成組件,比如 lin-ui

"dependencies": {

    "lin-ui": "~0.6.0"

},

其中 ~ 的作用是,會幫你選擇該組件在 npm 庫中最高的版本號版本安裝,但如果是有 0.7.0 版本,則 npm 只會匹配到 0.6 的最高版本,而不會匹配 0.7.0 版本。(想要了解更多,可以自行搜索 semver )

如果我想更新中間那個版本號呢?比如 發佈的版本是 1.2.3,升級的版本是 1.3.2 ,使用 ^ 即可(使用 latest、< > 均可)

"dependencies": {

    "lin-ui": "^0.6.0"

},

17、component 的 js 屬性

properties:主要是定義外部屬性,因爲 component 需要接收參數,哪些參數需要接收則定義在此即可

data:主要用於放置內部的屬性

methods:顧名思義,就是定義組件的相關方法

18、component 的 js properties 屬性接收數據方式

有兩種,如果是數組,設置數組最快的方式就是:grid:Array  等同於:grid: { type: Array,value: [ ] }

19、組件名問題

組件名不對,小程序並不會報錯,只有當組件路徑不對時纔會報錯

20、自定義組件的 class 問題

自定義組件是不能直接設置 class ,如果要設置一個組件的樣式,不能使用 class,要使用組件的外部樣式類。

外部樣式類的作用就類似與 slot (插槽),插槽可以自定義組件內容,而外部樣式類可以自定義組件內容的樣式。

21、view 組件下的所有元素居中

display: flex;

flex-direction: row;

align-items: center;

justify-content: center;

22、小程序下的體驗優化

小程序不同於 APP,限制於很多機器的性能可能不是那麼的強悍,所以在使用過程中經常會出現一定延遲,但是可以通過添加一些動畫來減少這樣的一個對於用戶的反饋延遲,也提高了體驗。

這就有點類似APP啓動頁,從視覺效果上達到假裝正在初始化,從而避免APP啓動過久,導致啓動時一片空白的尷尬。

23、組件設計原則

1、如果要設置自己的組件,最重要的原則就是你必須在這個組件的靈活性、易用性、穩定性之間做出選擇,又或者在這幾者之間找到一個平衡點。其實靈活性和穩定性是相違背的,一個組件越靈活說明穩定性是相對差的,同時易用性 也是相對較低的。也就是說,這種情況下組件的上手難度其實越高,過於靈活,穩定性因此會相對較差。

24、組件的意義到底是什麼?

在 vue 中幾乎都是隨處可見的組件,究竟爲何如今的前端變得如此極端?不管什麼場景也好還是業務也好,都以組件來實現?其實小程序的 js 中的 Page ,是可以變成 Component 的 ,爲什麼?因爲 Page 本身就是一個 Component 。

Component({

})

也就是說,實際上來講,小程序本身也是一個全組件驅動的框架,只不過微信並沒有像 Vue 那樣極端,之所以這樣,是因爲小程序剛出來時是沒有 Component 的。好的架構 / 系統 都是演進來的,而不是設計出來的。

在小程序中 將 Page 都變成 Component 來處理會更好,好處就在於 Page 非常呆板,他不具有組件的一些行爲,但 Component 可以像類一樣繼承並相互引用,還可以有統一的行爲規則。

回到上面的問題,究竟爲何如今的前端變得如此極端?因爲組件的好處實在是太多了,組件最主要其實有三大基本特性:

  1. 樣式:組件都會提供一些樣式,避免重複編寫樣式
  2. 骨架:避免重複造輪子,做無用功
  3. 業務邏輯/行爲:其實組件也是對行爲的一種封裝

25、組件的靈活性與自定義性

組件的意義具有上述三大特性,既然是組件,那麼就要考慮到靈活性,組件默認的三大特性可能並不符合任何的開發者當前的業務場景需求,所以基於靈活性考慮,必須提供一些機制和手段,幫助開發者自行改造組件。

  1. 對於樣式,在小程序中,外部樣式類是讓開發者自定義樣式非常重要的手段;
  2. 對於骨架,slot 插槽,這個是微信小程序對於改造骨架的一種有力輔助;
  3. 對於業務邏輯,無論哪一種組件都沒有對業務場景有一個很好的支撐,這也是受限於與技術無關的機制

其實可以把一些相同的業務場景提取成一個 Behavior ,然後這個 Behavior 就是一種行爲。

爲什麼業務邏輯比較難以自定義?這是因爲業務邏輯本身就是組件的一個特性/特徵,如果更改了一個業務邏輯,那麼可能這個組件就不再是這個組件了。

所以爲什麼 A 與 B 兩個組件不一樣?這是因爲它們本身就有非常鮮明的業務特徵,所以把一些業務特徵抽象成了 A 組件,而把另一些特徵抽象成了 B 組件,如果把 B 組件的業務邏輯改得都不像 B 的了,那麼是否更應該尋找 C 組件來使用呢?

26、組件之間的靈活性、易用性、穩定性有沒有相對要好的平衡點?

可以給默認值。不管是樣式的默認值,還是插槽的默認值,都應該設置一個能夠滿足 50% 以上用戶需求的默認值。

27、在小程序中,如果沒有明確理由,儘量不要設置固定的高和寬

其實對一個元素定高和定寬,是人類一種固有思維。這個時候需要轉變下思維,當面對一個元素時,確實是想設置高和寬,但是此時應該想想有沒有必要設置,也即如果不設置高和寬會出現什麼?

如果不設置高寬就能滿足需求,那麼優先考慮不設置高寬。有理由就可以設置,比如這個元素太小了,我需要把寬度高度拉大點,便於用戶點擊,提高用戶體驗。

固定高寬有兩個問題:

  1. 高和寬並不是那麼容易直接從設計圖得到,就算是具體量出來也是非常麻煩與不準確的;
  2. 很多情況下,設置了高寬,後期維護是非常困難的。雖然 css3 中的 calc 幫助開發者快速計算剩餘高或寬,但是很多時候還是讓元素自適應,而不是設置成固定。

28、優惠券

優惠券其實大多難點在於後端,對於前端來講,主要的難點就在於覈算。

優惠券其實是分類型的:

  1. 滿減
  2. 折扣
  3. 使用條件
  4. 全場券
  5. 品類券

另一個難點在於需要判斷過期時間,簡單理解可以認爲是在時間段內,超出無效。

但其實還有一種就是優惠券並不是在一個固定的時間範圍內的,可能是以用戶領取這個券的某個時間點開始算起

甚至還有更復雜的條件,總體來說,越大型的電商,計算規則也就越複雜。

29、關於優惠券的相關概念

領取、使用、過期、類型

活動:優惠券活動,包含了 開始時間、結束時間、上架、下架、分類(比如一個活動只能作用於若干個商品)

30、小程序設置背景顏色

看似  backgroundColor 可以設置頁面的背景顏色,但實際上這個屬性是設置下拉後底部窗口的背景色,而不是頁面的背景色。

兩種方式:

1、可以在所需頁面的最外層 view 的背景色(這種方式可能侷限於頁面範圍,如果其他頁面也要呢?)並且缺點也是有的,就是頁面最頂端會無緣無故多出來一塊背景色的區域(通常在 wxml 中都包裹着一個 view ,如果該 view 的class 爲 container,而小程序有一個全局的樣式,在 app.wxss 中也有一個 container ,此時就會相沖突,從而導致這個全局樣式的部分效果也會作用於該頁面);另外一方面,有些 view 與 view 之間會無緣無故多出一小段距離的背景色,小程序的頁面如果頁面有圖片時,會自帶一個間距,這個間距大概在 10 rpx,如何消除呢?將該圖片的樣式改爲 flex 佈局。也即 display: flex;

2、第一種方式也不會整個頁面都鋪滿設置的背景色的,只會作用於已有內容的 view 上,但需要實現的是整個頁面的背景色。小程序頁面本身就有一個 page 標籤

31、既然前端要盡請求,那麼首頁的數據爲何後端不能一次性返回呢?而要通過多個接口

有以下幾種情況,衡量 API 的依據有什麼呢?

HTTP 請求數量;每次 HTTP 會引起多少次數據庫查詢;接口的靈活性;服務器接口的可維護性

  1. 每一個數據都發送一個請求
  2. 整個首頁發送一個請求
  3. 有選擇的把部分請求合併成一個

32、在 JS 中使用函數式編程

假如返回的是一個數組,那麼可以使用 find 方法過濾需要的數據,該方法接收一個函數,如下

dataArray = dataArray.find(d => d.id === '0');

意思是:查找這個數組中 id 爲 0 的元素

33、JS 中雙等號 與 三等號

雙等號在 JS 中會做類型轉換,三等號則絕對等於

34、小程序中動態設置圖片的高寬

要保持圖片的比例,小程序的 image 組件自帶有該設置,也即 mode。但這並不是一種非常好的方式,因爲 mode 雖然是可以保持縱橫比,但是縮放模式還是不能達到最好的效果,所以還是需要動態計算高和寬。

35、如何在小程序中儘量減少 HTTP 請求,減少冗餘代碼(比如同一個數組要在頁面多個地方用到,但需要多次 find)

  1. this.data.dataArray = 返回的數組 (每次使用都需要判斷是否爲空,並且頁面本身不應該保存數據)
  2. 保存到小程序的緩存中(不手動清除將永久保存)
  3. 保存到全局變量(全局變量並不適合存儲返回的請求數據,特殊的除外)

以上都不是特別好的方法,並且在整個小程序裏面只能保存一份。看到這裏,Java 中的類保存數據就又出現了,瞭解面向對象的都知道,類的對象本身就具有保存數據的功能。

類的對象本身就具有保存數據的功能,這句話是對的,但不確切,爲什麼?類確實可以保存數據,但是類不能保存狀態。

類實例化之後的對象是既可以保存數據,也可以保存狀態。

爲什麼類可以保存數據,但不能保存狀態?

class Clazz{
  static A = '1';
  static B = '2';
  static C = '3';
  static D = '4';
}

上述定義了一個類,類中定義了若干個屬性,由於這些屬性都是 static ,所以是和類相關的,也就是說在使用 Clazz 的時候是不需要實例化該類的,屬性的值是可以直接用的。

但是狀態的數據可能是不同的,如果狀態全部都是相同的,就談不上狀態了。那麼怎麼保存狀態呢?

假如實例化了 Clazz,並且使得 t.age = 1,也即

const t = new Clazz();
t.age = 1;
const t2 = new Clazz();
t2.age = 2;

同樣的屬性,由於對象不同,它保存了兩個不同的數據狀態。

再來看看數據獲取

Clazz.age = 1;
Clazz.age = 2;

執行完這兩行代碼之後,age 肯定等於 2,所以肯定是不能同時保存1 和 2 的。

最好還是不要使用類的 static 保存狀態或者數據,否則擴展性是不夠的,因爲 static 定義之後,全局中這個變量的值只能有一份。

36、JS 操作與對象模型

既然建立了一個業務對象,那麼和這個對象有關的操作,都應該放到這個對象模型裏面,而不要讓這些代碼都零散的放到頁面的 JS 中

37、符號特徵

業務對象很多時候是具有一個符號的特徵,有些複雜的業務必須抽象出多個具有符號意義的業務對象才能幫助開發者思考。

38、Spu 和 Sku

Standard Product Unit - 標準化產品單元:

  • 商品信息聚合的最小單位,是一組可複用、易檢索的標準化信息的集合,該集合描述了一個產品的特性。通俗點講,屬性值、特性相同的商品就可以稱爲一個SPU。
SPU 是商品信息聚合的最小單位。
例如:品牌蘋果+型號:5s可以確定一個產品,即SPU
再加上顏色白色,尺碼4.0,即表示一個SKU
SPU + 顏色 + 尺碼,就是一個SKU,SKU是從屬於SPU的關係

Stock keeping Unit - 庫存量單位:

  • 對每一個產品和服務的唯一標示符,該系統的使用SKU的植根於數據管理,使公司能夠跟蹤系統,如倉庫和零售商店或產品的庫存情況。他們往往在分配和商人的水平上連載。
一款商品多色,則是有多個SKU,例:一件衣服,有紅色、白色、藍色,則SKU編碼也不相同,
如相同則會出現混淆,發錯貨。

SKU,定義爲保存庫存控制的最小可用單位,例如紡織品中一個SKU通常表示:規格、顏色、款式。 
STOCK KEEP UNIT,這是客戶拿到商品放到倉庫後給商品編號,歸類的一種方法。

39、是不是所有的類方法都要加 static ?什麼時候應該加,什麼時候不應該加?

static 是和類相關的,類是不具有保存狀態的,由此只需要考慮數據是否需要保存狀態即可。

也即,是通過類直接調用,還是實例化之後再調用。

是否應該 static 不應該由代碼層面推測,而是應該從面向對象的本質去推測。

40、是不是方法都需要加 async 和 await ?

首先討論下,加 await 是爲了什麼?是爲了在方法中等待拿到此次請求返回的結果,但如果是直接 return 也即沒有後續代碼(比如賦值)的情況下,可以不加 await。

類方法中有沒有必要加 async?async 是強制保證一個方法最後返回一個 promise,但如果一個方法不需要強制保證返回 promise,則不需要加(或者統一封裝的 HTTP 請求方法已經強制保證了返回 promise 的情況下)

41、小程序組件中變量的駝峯方式

在組件 JS 中的 properties 定義的駝峯命名方式的變量,調用方傳遞的變量名需要 snake 形式,比如

在組件 JS 中的 properties 定義的是: sublimeText,

傳遞時,應該寫成:subline-text="{{}}"

42、爲什麼通常外部樣式類需要加 important?

1、小程序的自定義組件中明確說明了,外部樣式類和組件內部已經設置的默認樣式之間的優先級關係是不確定的,不確定的原因沒有明確說明,所以這時候就需要加上 !important 

2、HTML 中class 如果設置兩個,後面的會覆蓋前面的,但小程序中如果 class 的值有兩個,卻依然是不確定的。

3、並不是所有的外部樣式類都需要加 !important 來提高優先級。css 中,每一個 css 樣式都是有權重的,凡是能夠提高外部樣式權重的方案都是可以的,最簡單粗暴的是 !important 。

43、小程序  scroll-view 使用 flex 佈局

需要在標籤屬性上開啓 enable-flex

<scroll-view enable-flex class="scroll-view">


</scroll-view>

view 是不需要的

44、使用 scroll-view 開啓橫向滾動後,組件下方出現很長一段空白區

scroll-view 是小程序的原生組件,可以大致認爲和 HTML 裏的元素行爲是一致的,比如 view 通常認爲是 div,那麼 scroll-view 是一個功能更加豐富的 view 組件,但是 scroll-view 不能和 HTML 的元素做對等。

一般地,如果在沒有設置 view 組件的高度時,那麼這個容器應該是由內部的元素撐開,也就是說 view 不是固定的。

scroll-view 與 view 是有點不一致的,設置了 flex 佈局後,高度大致與沒設置樣式之前是一致的,也就是說空白區域是豎排留下的空間(僅推測)。

怎麼解決?

  1. 設置 scroll-view 的高度(不推薦)
  2. 可以在 scroll-view 裏再包裹一個 view,並設置 flex 的 row 排列,將 scroll-view 的 enable-flex 去除

45、scroll-view 不要限定寬度

如果固定寬度(就算是100%),下方會出現滾動條,因爲scroll-view 中的元素不可能緊挨在一起,總得設置元素之間的距離,那麼整體寬度100% 之後會再加上元素之間的內邊距,一定是大於 100%的。

既然寬度是 750rpx,知道左邊或者右邊的內邊距,用總體的內邊距減去左右兩邊的內邊距,然後再設置 width ,這樣也是可以,但這樣非常麻煩(頻繁計算)。

另外一種就是更改 scroll-view 的盒模型,也即更改 box-sizing 爲 border-box,這樣就不會再計算左右內邊距了。

46、text 文本太長,文本省略的三種速思路

  1. 可以在 js 中對字符進行截斷
  2. 直接 css 樣式處理
  3. wxs 處理(wxs 是小程序很重要的功能,非常適合邏輯處理非常複雜的時候)

47、wxs 有何不同

wxs 其實也是 JavaScript,那麼問題來了,

1、wxs 寫的代碼和在 JS 中寫的代碼有何區別?

  •  主要區別在於 wxs 的 js 代碼只支持 ES5,類似 const、``、export 這些都是不能用的

2、爲何會出現兩種 JS?

  • 之所以會出現兩種 JS,是因爲小程序的邏輯層(JS 中的代碼實際上是運行在邏輯層的環境裏)和渲染層/視圖層(wxs 的代碼是運行在渲染層的環境中)是兩個分離的環境。
  • 在 HTML 的頁面中寫 JS 是可以的,但在小程序的 wxml 中直接寫 JS 是不允許的,需要使用 wxs 。

48、小程序的運行環境其實有三套

小程序可以認爲是以 Web 技術爲驅動的新型技術,但不能簡單的認爲小程序就是 Web 技術

IOS

小程序在 IOS 的邏輯層主要是 JavaScriptCore,而視圖層是 WKWebView

Android

 在 Android 上 的邏輯層是 V8 引擎,視圖層是 XWeb (也是基於Chrome 內核進行渲染的)

PC

在 PC 上邏輯層是 NW.js,視圖層是 Chromium 內核渲染的

49、WebStorm 自定義代碼片段

file -> settings -> Live Templates -> 點擊右側 + ,選擇 template group,輸入 group name。

單擊選中新建的 group,再點擊右側 + ,選擇 live template,填寫  Abbreviation(快捷字母)比如 fc ,

description 填說明, Template text 填需要粘貼的代碼片段,

在模板片段下方的 No applicable contexts 的提示中點擊選擇應用的上下文。

最後在右下方的 Options 的 Expand with(默認是 輸入快捷字母后按下 Tab 鍵粘貼)選擇需要觸發粘貼事件的快捷鍵

那麼在file 中就可以輸入 fc,然後按下Tab 鍵,即可粘貼定義好的代碼片段。

50、外部樣式類的使用

如果要實現外部樣式類,那麼需要在組件 JS 的 Component 下定義一個特別的屬性:externalClasses: [''],

這個屬性是個數組,每一個元素都是代表着定義的外部樣式類,類名字自定義即可。

爲什麼要定義外部樣式類屬性呢?

  • 樣式並不是一定是自定義組件固定的,它需要由開發者定義好之後傳到自定義組件中引用,就好比定義 properties 中的屬性一樣,需要接收後才能使用

如何在自定義組件中使用?

  • 直接將定義好的外部樣式類數組中的元素名寫在組件的 class 上即可,比如在自定義組件中有一個 scroll-view組件
  <scroll-view class="scroll-view 外部樣式類名">
  </scroll-view>

51、新監聽器Observers

可以監聽單個屬性,比如

properties: {
    banner: Object
  },
observers:{
    "banner":function(banner){
        
    }

},

屬性名和 observers 中保持一致,括號中的 banner 是監聽器監聽到 properties 中banner 的變化之後傳遞的參數

可以監聽單個屬性,比如

properties: {
    banner: Object,
    Theme: Object
  },
observers:{
    "banner, Theme":function(banner, Theme){
        
    }

},

52、在 view 中使用點擊態

樣式動畫類:hover-class

動畫響應時間:hover-stay-time(毫秒)

自定義組件具有封閉性,直接在 app.wxss 中寫樣式,然後引入,不能直接作用在自定義組件中。

53、編程原則之一

多用return提前結束函數,少用else

54、小程序兩個頁面傳參

1、通過路由的 URL 後附加查詢參數

  • 但參數非常複雜(不是簡單的數字或字符串,而是 JS 對象),怎麼傳?以前小程序沒有狀態管理的功能,使用 全局變量的方式也不合適

2、現在小程序可以通過 兩個頁面之間的事件的方式進行傳遞,EventChannel

  • 雖然小程序支持 EventChannel ,但它的事件模型比較難以理解,用起來不是那麼的舒服

55、SPU 與 SKU

https://phubing.blog.csdn.net/article/details/103358119

56、兩個編程的技巧

1、當我們去思考一些複雜問題的時候,通常會覺得思維轉換不過來。複雜問題都有一個特性,就是它的思維週期非常長,可能是需要思考一個小時或者幾個小時。人的記憶力又是有限的,那在這樣的場景下,必須要把這些複雜的邏輯問題找到自己熟悉的事物對應起來,也就是必須要藉助一些形象化、符號化的東西來輔助思考。最重要的是,要注意變量的命名,這些變量的命名必須是具有一些形象化、符號化意義的,因爲此時變量的命名早已脫離了規範性的範疇。

2、要善於把核心的問題能夠抽象出來。當拿到一張圖時,設計師不會考慮是如何做出來的、技術難度是什麼,所以拆分設計圖,也是能力所在。

57、自定義組件的理解

1、可以粗淺的認爲:自定義組件要麼就是爲了封裝在一起,然後把代碼進行分離。

2、另一個就是自定義組件是爲了複用。

3、但自定義組件在面對複雜的問題時,它同樣是一種很好的輔助思考的工具。

58、變量命名的思考

帶有強烈領域對象的命名並非不可以,處理簡單邏輯的時候確實可以帶上領域對象作爲變量的前綴命名。

但是在處理複雜問題的時候,帶有領域對象前綴命名的變量其實是有很多個可描述的角度的。

發佈了116 篇原創文章 · 獲贊 231 · 訪問量 70萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章