1. <dd id="mhwbf"><track id="mhwbf"></track></dd>

  2. <em id="mhwbf"></em><dd id="mhwbf"></dd>
  3. <rp id="mhwbf"><object id="mhwbf"></object></rp>

    1. <em id="mhwbf"><ruby id="mhwbf"></ruby></em>
      <button id="mhwbf"><acronym id="mhwbf"></acronym></button>

          <dd id="mhwbf"></dd>

          近兩萬字小程序攻略發布了

          來源:掘金
          2021-02-27
          726
          導語:該內容由銀科控股融匯研發部曹俊及其團隊授權提供。該團隊擁有 10 多名小程序開發,深耕小程序領域,總結出了本篇優質長文。同時本篇內容也已經合并入我的 開源項目 中,目前項目內容包含了 JS、網絡、瀏覽器相關、性能優化、安全、框架、Git、數據結構、算法等內容,無論是基礎還是進階,亦或是源碼解讀,你都能在本圖譜中得到滿意的答案,希望這個面試圖譜能夠幫助到大家更好的準備面試。
          閱讀本文大概需要15分鐘

          小程序-登錄

          unionid和openid

          了解小程序登陸之前,我們寫了解下小程序/公眾號登錄涉及到兩個最關鍵的用戶標識:

          • OpenId 是一個用戶對于一個小程序/公眾號的標識,開發者可以通過這個標識識別出用戶。
          • UnionId 是一個用戶對于同主體微信小程序/公眾號/APP的標識,開發者需要在微信開放平臺下綁定相同賬號的主體。開發者可通過UnionId,實現多個小程序、公眾號、甚至APP 之間的數據互通了。

          關鍵Api

          登錄流程設計

          以下從筆者接觸過的幾種登錄流程來做闡述:

          利用現有登錄體系

          直接復用現有系統的登錄體系,只需要在小程序端設計用戶名,密碼/驗證碼輸入頁面,便可以簡便的實現登錄,只需要保持良好的用戶體驗即可。

          利用OpenId 創建用戶體系

          ?提過,OpenId 是一個小程序對于一個用戶的標識,利用這一點我們可以輕松的實現一套基于小程序的用戶體系,值得一提的是這種用戶體系對用戶的打擾最低,可以實現靜默登錄。具體步驟如下:

          1. 小程序客戶端通過 wx.login 獲取 code

          2. 傳遞 code 向服務端,服務端拿到 code 調用微信登錄憑證校驗接口,微信服務器返回 openid 和會話密鑰 session_key ,此時開發者服務端便可以利用 openid 生成用戶入庫,再向小程序客戶端返回自定義登錄態

          3. 小程序客戶端緩存 (通過storage)自定義登錄態(token),后續調用接口時攜帶該登錄態作為用戶身份標識即可

          利用 Unionid 創建用戶體系

          如果想實現多個小程序,公眾號,已有登錄系統的數據互通,可以通過獲取到用戶 unionid 的方式建立用戶體系。因為 unionid 在同一開放平臺下的所所有應用都是相同的,通過 unionid 建立的用戶體系即可實現全平臺數據的互通,更方便的接入原有的功能,那如何獲取 unionid 呢,有以下兩種方式:

          1. 如果戶關注了某個相同主體公眾號,或曾經在某個相同主體App、公眾號上進行過微信登錄授權,通過 wx.login 可以直接獲取 到 unionid

          2. 結合 wx.getUserInfo

          注意事項

          1. 需要獲取 unionid 形式的登錄體系,在以前(18年4月之前)是通過以下這種方式來實現,但后續微信做了調整(因為一進入小程序,主動彈起各種授權彈窗的這種形式,比較容易導致用戶流失),調整為必須使用按鈕引導用戶主動授權的方式,這次調整對開發者影響較大,開發者需要注意遵守微信的規則,并及時和業務方溝通業務形式,不要存在僥幸心理,以防造成小程序不過審等情況。
             wx.login(獲取code) ===> wx.getUserInfo(用戶授權) ===> 獲取 unionid
          復制代碼
          1. 因為小程序不存在 cookie 的概念, 登錄態必須緩存在本地,因此強烈建議為登錄態設置過期時間

          2. 值得一提的是如果需要支持風控安全校驗,多平臺登錄等功能,可能需要加入一些公共參數,例如platform,channel,deviceParam等參數。在和服務端確定方案時,作為前端同學應該及時提出這些合理的建議,設計合理的系統。

          3. openid , unionid 不要在接口中明文傳輸,這是一種危險的行為,同時也很不專業。

          小程序-圖片導出

          經常開發和使用小程序的同學對這個功能一定不陌生,這是一種常見的引流方式,一般同時會在圖片中附加一個小程序二維碼。

          基本原理

          1. 借助 canvas 元素,將需要導出的樣式首先在 canvas 畫布上繪制出來 (api基本和h5保持一致,但有輕微差異,使用時注意即可)

          2. 借助微信提供的 canvasToTempFilePath 導出圖片,最后再使用 saveImageToPhotosAlbum (需要授權)保存圖片到本地

          如何優雅實現

          根據上述的原理來看,實現是很簡單的,只不過就是設計稿的提取,繪制即可,但是作為一個常用功能,每次都這樣寫一坨代碼豈不是非常的難受。那小程序如何設計一個通用的方法來幫助我們導出圖片呢?思路如下:

          1. 繪制出需要的樣式這一步是省略不掉的。但是我們可以封裝一個繪制庫,包含常見圖形的繪制,例如矩形,圓角矩形,圓, 扇形, 三角形, 文字,圖片減少繪制代碼,只需要提煉出樣式信息,便可以輕松的繪制,最后導出圖片存入相冊。筆者覺得以下這種方式繪制更為優雅清晰一些,其實也可以使用加入一個type參數來指定繪制類型,傳入的一個是樣式數組,實現繪制。

          2. 結合上一步的實現,如果對于同一類型的卡片有多次導出需求的場景,也可以使用自定義組件的方式,封裝同一類型的卡片為一個通用組件,在需要導出圖片功能的地方,引入該組件即可。

              
            class CanvasKit {
              constructor() {
              }
              drawImg(option = {}) {
                ...
                return this
              }
              drawRect(option = {}) {
                return this
              }
              drawText(option = {}) {
                ...
                return this
              }
              static exportImg(option = {}) {
                ...
              }
            }
          
            let drawer = new CanvasKit('canvasId').drawImg(styleObj1).drawText(styleObj2)
            drawer.exportImg()
          
          復制代碼

          注意事項

          1. 小程序中無法繪制網絡圖片到canvas上,需要通過downLoadFile 先下載圖片到本地臨時文件才可以繪制
          2. 通常需要繪制二維碼到導出的圖片上,有一種方式導出二維碼時,需要攜帶的參數必須做編碼,而且有具體的長度(32可見字符)限制,可以借助服務端生成 短鏈接 的方式來解決

          小程序-數據統計

          數據統計作為目前一種常用的分析用戶行為的方式,小程序端也是必不可少的。小程序采取的曝光,點擊數據埋點其實和h5原理是一樣的。但是埋點作為一個和業務邏輯不相關的需求,我們如果在每一個點擊事件,每一個生命周期加入各種埋點代碼,則會干擾正常的業務邏輯,和使代碼變的臃腫,筆者提供以下幾種思路來解決數據埋點:

          設計一個埋點sdk

          小程序的代碼結構是,每一個 Page 中都有一個 Page 方法,接受一個包含生命周期函數,數據的 業務邏輯對象 包裝這層數據,借助小程序的底層邏輯實現頁面的業務邏輯。通過這個我們可以想到思路,對Page進行一次包裝,篡改它的生命周期和點擊事件,混入埋點代碼,不干擾業務邏輯,只要做一些簡單的配置即可埋點,簡單的代碼實現如下:

            
            代碼僅供理解思路
            page = function(params) {
              let keys = params.keys()
              keys.forEach(v => {
                  if (v === 'onLoad') {
                    params[v] = function(options) {
                      stat()   //曝光埋點代碼
                      params[v].call(this, options)
                    }
                  }
                  else if (v.includes('click')) {
                    params[v] = funciton(event) { 
                      let data = event.dataset.config
                      stat(data)  // 點擊埋點
                      param[v].call(this)
                    }
                  }
              })
            }
          復制代碼

          這種思路不光適用于埋點,也可以用來作全局異常處理,請求的統一處理等場景。

          分析接口

          對于特殊的一些業務,我們可以采取 接口埋點,什么叫接口埋點呢?很多情況下,我們有的api并不是多處調用的,只會在某一個特定的頁面調用,通過這個思路我們可以分析出,該接口被請求,則這個行為被觸發了,則完全可以通過服務端日志得出埋點數據,但是這種方式局限性較大,而且屬于分析結果得出過程,可能存在誤差,但可以作為一種思路了解一下。

          微信自定義數據分析

          微信本身提供的數據分析能力,微信本身提供了常規分析和自定義分析兩種數據分析方式,在小程序后臺配置即可。借助小程序數據助手這款小程序可以很方便的查看。

          小程序-工程化

          工程化做什么

          目前的前端開發過程,工程化是必不可少的一環,那小程序工程化都需要做些什么呢,先看下目前小程序開發當中存在哪些問題需要解決:

          1. 不支持 css預編譯器,作為一種主流的 css解決方案,不論是 less,sass,stylus 都可以提升css效率
          2. 不支持引入npm包 (這一條,從微信公開課中聽聞,微信準備支持)
          3. 不支持ES7等后續的js特性,好用的async await等特性都無法使用
          4. 不支持引入外部字體文件,只支持base64
          5. 沒有 eslint 等代碼檢查工具

          方案選型

          對于目前常用的工程化方案,webpack,rollup,parcel等來看,都常用與單頁應用的打包和處理,而小程序天生是 “多頁應用” 并且存在一些特定的配置。根據要解決的問題來看,無非是文件的編譯,修改,拷貝這些處理,對于這些需求,我們想到基于流的 gulp非常的適合處理,并且相對于webpack配置多頁應用更加簡單。所以小程序工程化方案推薦使用 gulp

          具體開發思路

          通過 gulp 的 task 實現:

          1. 實時編譯 less 文件至相應目錄
          2. 引入支持async,await的運行時文件
          3. 編譯字體文件為base64 并生成相應css文件,方便使用
          4. 依賴分析哪些地方引用了npm包,將npm包打成一個文件,拷貝至相應目錄
          5. 檢查代碼規范

          上述實現起來其實并不是很難,但是這樣的話就是一份純粹的 gulp 構建腳本和 約定好的目錄而已,每次都有一個新的小程序都來拷貝這份腳本來處理嗎?顯然不合適,那如何真正的實現 小程序工程化 呢? 我們可能需要一個簡單的腳手架,腳手架需要支持的功能:

          1. 支持新建項目,創建Page,創建Component
          2. 支持內置構建腳本
          3. 支持發布小程序,也可以想辦法接入Jenkins等工具做持續集成 (小程序持續集成后面會提) ...

          小程序架構

          architecture">

          微信小程序的框架包含兩部分 View 視圖層、App Service邏輯層。View 層用來渲染頁面結構,AppService 層用來邏輯處理、數據請求、接口調用。

          它們在兩個線程里運行。

          它們在兩個線程里運行。

          它們在兩個線程里運行。

          視圖層和邏輯層通過系統層的 JSBridage 進行通信,邏輯層把數據變化通知到視圖層,觸發視圖層頁面更新,視圖層把觸發的事件通知到邏輯層進行業務處理。

          補充

          one-context

          視圖層使用 WebView 渲染,iOS 中使用自帶 WKWebView,在 Android 使用騰訊的 x5 內核(基于 Blink)運行。

          邏輯層使用在 iOS 中使用自帶的 JSCore 運行,在 Android 中使用騰訊的 x5 內核(基于 Blink)運行。

          開發工具使用 nw.js 同時提供了視圖層和邏輯層的運行環境。

          在 Mac下 使用 js-beautify 對微信開發工具 @v1.02.1808080代碼批量格式化:

          cd /Applications/wechatwebdevtools.app/Contents/Resources/package.nw
          find . -type f -name '*.js' -not -path "./node_modules/*" -not -path -exec js-beautify -r -s 2 -p -f '{}' \;
          復制代碼

          js/extensions/appservice/index.js 中找到:

          	267: function(a, b, c) {
              const d = c(8),
                e = c(227),
                f = c(226),
                g = c(228),
                h = c(229),
                i = c(230);
              var j = window.__global.navigator.userAgent,
                k = -1 !== j.indexOf('game');
              k || i(), window.__global.getNewWeixinJSBridge = (a) => {
                const {
                  invoke: b
                } = f(a), {
                  publish: c
                } = g(a), {
                  subscribe: d,
                  triggerSubscribeEvent: i
                } = h(a), {
                  on: j,
                  triggerOnEvent: k
                } = e(a);
                return {
                  invoke: b,
                  publish: c,
                  subscribe: d,
                  on: j,
                  get __triggerOnEvent() {
                    return k
                  },
                  get __triggerSubscribeEvent() {
                    return i
                  }
                }
              }, window.WeixinJSBridge = window.__global.WeixinJSBridge = window.__global.getNewWeixinJSBridge('global'), window.__global.WeixinJSBridgeMap = {
                __globalBridge: window.WeixinJSBridge
              }, __devtoolsConfig.online && __devtoolsConfig.autoTest && setInterval(() => {
                console.clear()
              }, 1e4);
              try {
                var l = new window.__global.XMLHttpRequest;
                l.responseType = 'text', l.open('GET', `http://${window.location.host}/calibration/${Date.now()}`, !0), l.send()
              } catch (a) {}
            }
          復制代碼

          js/extensions/gamenaitveview/index.js 中找到:

            299: function(a, b, c) {
              'use strict';
              Object.defineProperty(b, '__esModule', {
                value: !0
              });
              var d = c(242),
                e = c(241),
                f = c(243),
                g = c(244);
              window.WeixinJSBridge = {
                on: d.a,
                invoke: e.a,
                publish: f.a,
                subscribe: g.a
              }
            },
          復制代碼

          js/extensions/pageframe/index.js中找到:

          317: function(a, b, c) {
              'use strict';
          
              function d() {
                window.WeixinJSBridge = {
                  on: e.a,
                  invoke: f.a,
                  publish: g.a,
                  subscribe: h.a
                }, k.a.init();
                let a = document.createEvent('UIEvent');
                a.initEvent('WeixinJSBridgeReady', !1, !1), document.dispatchEvent(a), i.a.init()
              }
              Object.defineProperty(b, '__esModule', {
                value: !0
              });
              var e = c(254),
                f = c(253),
                g = c(255),
                h = c(256),
                i = c(86),
                j = c(257),
                k = c.n(j);
              'complete' === document.readyState ? d() : window.addEventListener('load', function() {
                d()
              })
            },
          復制代碼

          我們都看到了 WeixinJSBridge 的定義。分別都有 on、invoke、publish、subscribe 這個幾個關鍵方法。

          invoke 舉例,在 js/extensions/appservice/index.js中發現這段代碼:

          f (!r) p[b] = s, f.send({
              command: 'APPSERVICE_INVOKE',
              data: {
                  api: c,
                  args: e,
                  callbackID: b
              }
          });
          復制代碼

          js/extensions/pageframe/index.js 中發現這段代碼:

          g[d] = c, e.a.send({
              command: 'WEBVIEW_INVOKE',
              data: {
                  api: a,
                  args: b,
                  callbackID: d
              }
          })
          
          復制代碼

          簡單的分析得知:字段 command 用來區分行為,invoke 用來調用 Native 的 Api。在不同的來源要使用不同的前綴。data 里面包含 Api 名,參數。另外 callbackID 指定接受回調的方法句柄。Appservice 和 Webview 使用的通信協議是一致的。

          我們不能在代碼里使用 BOM 和 DOM 是因為根本沒有,另一方面也不希望 JS 代碼直接操作視圖。

          在開發工具中 remote-helper.js 中找到了這樣的代碼:

          const vm = require("vm");
          
          const vmGlobal = {
              require: undefined,
              eval: undefined,
              process: undefined,
              setTimeout(...args) {
                  //...省略代碼
                  return timerCount;
              },
              clearTimeout(id) {
                  const timer = timers[id];
                  if (timer) {
                      clearTimeout(timer);
                      delete timers[id];
                  }
              },
              setInterval(...args) {
                  //...省略代碼
                  return timerCount;
              },
              clearInterval(id) {
                  const timer = timers[id];
                  if (timer) {
                      clearInterval(timer);
                      delete timers[id];
                  }
              },
              console: (() => {
                  //...省略代碼
                  return consoleClone;
              })()
          };
          const jsVm = vm.createContext(vmGlobal);
          // 省略大量代碼...
          function loadCode(filePath, sourceURL, content) {
              let ret;
              try {
                  const script = typeof content === 'string' ? content : fs.readFileSync(filePath, 'utf-8').toString();
                  ret = vm.runInContext(script, jsVm, {
                      filename: sourceURL,
                  });
              }
              catch (e) {
                  // something went wrong in user code
                  console.error(e);
              }
              return ret;
          }
          復制代碼

          這樣的分層設計顯然是有意為之的,它的中間層完全控制了程序對于界面進行的操作, 同時對于傳遞的數據和響應時間也能做到監控。一方面程序的行為受到了極大限制, 另一方面微信可以確保他們對于小程序內容和體驗有絕對的控制。

          這樣的結構也說明了小程序的動畫和繪圖 API 被設計成生成一個最終對象而不是一步一步執行的樣子, 原因就是 Json 格式的數據傳遞和解析相比與原生 API 都是損耗不菲的,如果頻繁調用很可能損耗過多性能,進而影響用戶體驗。

          下載小程序完整包

          download">

          App Service - Life Cylce

          lifecycle">

          面試題

          1.動畫需要綁定在 data 上,而繪圖卻不用。你覺得是為什么呢?

          var context = wx.createCanvasContext('firstCanvas')
              
          context.setStrokeStyle("#00ff00")
          context.setLineWidth(5)
          context.rect(0, 0, 200, 200)
          context.stroke()
          context.setStrokeStyle("#ff0000")
          context.setLineWidth(2)
          context.moveTo(160, 100)
          context.arc(100, 100, 60, 0, 2 * Math.PI, true)
          context.moveTo(140, 100)
          context.arc(100, 100, 40, 0, Math.PI, false)
          context.moveTo(85, 80)
          context.arc(80, 80, 5, 0, 2 * Math.PI, true)
          context.moveTo(125, 80)
          context.arc(120, 80, 5, 0, 2 * Math.PI, true)
          context.stroke()
          context.draw()
          復制代碼
          Page({
            data: {
              animationData: {}
            },
            onShow: function(){
              var animation = wx.createAnimation({
                duration: 1000,
            	  timingFunction: 'ease',
              })
          
              this.animation = animation
              
              animation.scale(2,2).rotate(45).step()
              
              this.setData({
                animationData:animation.export()
              })
            }
          })
          復制代碼

          2.小程序的 Http Rquest 請求是不是用的瀏覽器 Fetch API?

          知識點考察

          • 知道 Request 是由 Native 實現的
          • JSCore 是不帶 Http Request、Websocket、Storage等功能的,那是 Webkit 帶的
          • 小程序的 wx.request 是不是遵循 fetch API 規范實現的呢?答案,顯然不是。因為沒有 Promise

          View - WXML

          WXML(WeiXin Markup Language)

          • 支持數據綁定
          • 支持邏輯算術、運算
          • 支持模板、引用
          • 支持添加事件(bindtap)

          WXML">

          Wxml編譯器:Wcc 把 Wxml文件 轉為 JS

          執行方式:Wcc index.wxml

          使用 Virtual DOM,進行局部更新

          View - WXSS

          WXSS(WeiXin Style Sheets)

          WXSS">

          wxss編譯器:wcsc 把wxss文件轉化為 js

          執行方式: wcsc index.wxss

          支持大部分CSS特性

          親測包含但不限于如下內容:

          • Transition
          • Animation
            • Keyframes
          • border-radius
          • calc()
          • 選擇器,除了官方文檔列出的,其實還支持
            • element>element
            • element+element
            • element element
            • element:first-letter
            • element:first-line
            • element:first-child
            • element:last-child
            • element~element
            • element:first-of-type
            • element:last-of-type
            • element:only-of-type
            • element:only-child
            • element:nth-child(n)
            • element:nth-last-child(n)
            • element:nth-of-type(n)
            • element:nth-last-of-type(n)
            • :root
            • element:empty
            • :not(element)
          • iconfont

          建議 Css3 的特性都可以做一下嘗試。

          尺寸單位 rpx

          rpx(responsive pixel): 可以根據屏幕寬度進行自適應。規定屏幕寬為 750rpx。公式:

          const dsWidth = 750
          
          export const screenHeightOfRpx = function () {
            return 750 / env.screenWidth * env.screenHeight
          }
          
          export const rpxToPx = function (rpx) {
            return env.screenWidth / 750 * rpx
          }
          
          export const pxToRpx = function (px) {
            return 750 / env.screenWidth * px
          }
          
          復制代碼
          設備 rpx換算px (屏幕寬度/750) px換算rpx (750/屏幕寬度)
          iPhone5 1rpx = 0.42px 1px = 2.34rpx
          iPhone6 1rpx = 0.5px 1px = 2rpx
          iPhone6 Plus 1rpx = 0.552px 1px = 1.81rpx

          可以了解一下 pr2rpx-loader 這個庫。

          樣式導入

          使用 @import語句可以導入外聯樣式表,@import后跟需要導入的外聯樣式表的相對路徑,用 ; 表示語句結束。

          內聯樣式

          靜態的樣式統一寫到 class 中。style 接收動態的樣式,在運行時會進行解析,請盡量避免將靜態的樣式寫進 style 中,以免影響渲染速度。

          全局樣式與局部樣式

          定義在 app.wxss 中的樣式為全局樣式,作用于每一個頁面。在 page 的 wxss 文件中定義的樣式為局部樣式,只作用在對應的頁面,并會覆蓋 app.wxss 中相同的選擇器。

          iconfont

          截止20180810

          小程序未來有計劃支持字體。參考微信公開課。

          小程序開發與平時 Web開發類似,也可以使用字體圖標,但是 src:url() 無論本地還是遠程地址都不行,base64 值則都是可以顯示的。

          將 ttf 文件轉換成 base64。打開這個平臺 transfonter.org/。點擊 Add fonts 按鈕,加載ttf格式的那個文件。將下邊的 base64 encode 改為 on。點擊 Convert 按鈕進行轉換,轉換后點擊 download 下載。

          復制下載的壓縮文件中的 stylesheet.css 的內容到 font.wxss ,并且將 icomoon 中的 style.css 除了 @font-face 所有的代碼也復制到 font.wxss 并將i選擇器換成 .iconfont,最后:

          <text class="iconfont icon-home" style="font-size:50px;color:red">text>
          復制代碼

          View - Component

          小程序提供了一系列組件用于開發業務功能,按照功能與HTML5的標簽進行對比如下:

          Component">

          小程序的組件基于Web Component標準

          使用Polymer框架實現Web Component

          View - Native Component

          目前Native實現的組件有

          • cavnas

          • video

          • map

          • textarea

            Native Component

          Native組件層在 WebView 層之上。這目前帶來了一些問題:

          • Native 實現的組件會遮擋其他組件
          • WebView 渲染出來的視圖在滾動時,Native 實現的組件需要更新位置,這會帶來性能問題,在安卓機器上比較明顯
          • 小程序原生組件 cover-view 可以覆蓋 cavnas video 等,但是也有一下弊端,比如在 cavnas 上覆蓋 cover-view,就會發現坐標系不統一處理麻煩

          目前小程序的問題或限制

          截止20180810

          包含但不限于:

          • 小程序仍然使用 WebView 渲染,并非原生渲染。(部分原生)

          • 服務端接口返回的頭無法執行,比如:Set-Cookie。

          • 依賴瀏覽器環境的 JS 庫不能使用。

          • 不能使用 npm,但是可以自搭構建工具或者使用 mpvue。(未來官方有計劃支持)

          • 不能使用 ES7,可以自己用babel+webpack自搭或者使用 mpvue。

          • 不支持使用自己的字體(未來官方計劃支持)。

          • 可以用 base64 的方式來使用 iconfont。

          • 小程序不能發朋友圈(可以通過保存圖片到本地,發圖片到朋友前。二維碼可以使用B接口)。

          • 獲取二維碼/小程序接口的限制。

            • B 接口 scene 最大32個可見字符。
            • AC 接口總共生成的碼數量限制為 100,000,請謹慎調用。
            • 真機掃描二維碼只能跳轉到線上版本,所以測試環境下只可通過開發者工具的通過二維碼編譯進行調試。
            • 沒有發布到線上版本的小程序頁面路徑會導致生成二維碼失敗,需要先將添加了頁面的小程序發布到線上版本。
          • 小程序推送只能使用“服務通知” 而且需要用戶主動觸發提交 formId,formId 只有7天有效期。(現在的做法是在每個頁面都放入form并且隱藏以此獲取更多的 formId。后端使用原則為:優先使用有效期最短的)

          • 小程序大小限制 2M,分包總計不超過 8M

          • 轉發(分享)小程序不能拿到成功結果,原來可以。鏈接(小游戲造的孽)

          • 拿到相同的 unionId 必須綁在同一個開放平臺下。開放平臺綁定限制:

            • 50個移動應用
            • 10個網站
            • 50個同主體公眾號
            • 5個不同主體公眾號
            • 50個同主體小程序
            • 5個不同主體小程序
          • 公眾號關聯小程序,鏈接

            • 所有公眾號都可以關聯小程序。
            • 一個公眾號可關聯10個同主體的小程序,3個不同主體的小程序。
            • 一個小程序可關聯500個公眾號。
            • 公眾號一個月可新增關聯小程序13次,小程序一個月可新增關聯500次。
          • 一個公眾號關聯的10個同主體小程序和3個非同主體小程序可以互相跳轉

          • 品牌搜索不支持金融、醫療

          • 小程序授權需要用戶主動點擊

          • 小程序不提供測試 access_token

          • 安卓系統下,小程序授權獲取用戶信息之后,刪除小程序再重新獲取,并重新授權,得到舊簽名,導致第一次授權失敗

          • 開發者工具上,授權獲取用戶信息之后,如果清緩存選擇全部清除,則即使使用了wx.checkSession,并且在session_key有效期內,授權獲取用戶信息也會得到新的session_key

          小程序HTTP2支持情況

          HTTP2支持情況:模擬器與真機均不支持

          為了驗證小程序對HTTP的支持適配情況,我找了兩個服務器做測試,一個是網上搜索到支持HTTP2的服務器,一個是我本地起的一個HTTP2服務器。測試中所有請求方法均使用 wx.request。

          1. 網上支持HTTP2的服務器:HTTPs://www.snel.com:443

          2. 在Chrome上查看該服務器為 HTTP2

            WechatIMG11">

          3. 在模擬器上請求該接口,請求頭的HTTP版本為HTTP1.1,模擬器不支持HTTP2

            WechatIMG12">

          4. 由于小程序線上環境需要在項目管理里配置請求域名,而這個域名不是我們需要的請求域名,沒必要浪費一個域名位置,所以打開不驗證域名,TSL 等選項請求該接口,通過抓包工具表現與模擬器相同

            WechatIMG14">

          HTTP2服務器需要對小程序做兼容性適配

          由上可以看出,在真機與模擬器都不支持 HTTP2,但是都是成功請求的,并且 響應頭 里的 HTTP 版本都變成了HTTP1.1 版本,說明服務器對 HTTP1.1 做了兼容性適配。

          1. 本地新啟一個 node 服務器,返回 JSON 為請求的 HTTP 版本

            WechatIMG16">

          2. 如果服務器只支持 HTTP2,在模擬器請求時發生了一個 ALPN 協議的錯誤。并且提醒使用適配 HTTP1

            WechatIMG8">

          3. 當把服務器的 allowHTTP1,設置為 true,并在請求時處理相關相關請求參數后,模擬器能正常訪問接口,并打印出對應的 HTTP 請求版本

            WechatIMG15

          授權獲取用戶信息流程

          • session_key 有有效期,有效期并沒有被告知開發者,只知道用戶越頻繁使用小程序,session_key 有效期越長
          • 在調用 wx.login 時會直接更新 session_key,導致舊 session_key 失效
          • 小程序內先調用 wx.checkSession 檢查登錄態,并保證沒有過期的 session_key 不會被更新,再調用 wx.login 獲取 code。接著用戶授權小程序獲取用戶信息,小程序拿到加密后的用戶數據,把加密數據和 code 傳給后端服務。后端通過 code 拿到 session_key 并解密數據,將解密后的用戶信息返回給小程序

          面試題:先授權獲取用戶信息再 login 會發生什么?

          • 用戶授權時,開放平臺使用舊的 session_key 對用戶信息進行加密。調用 wx.login 重新登錄,會刷新 session_key,這時后端服務從開放平臺獲取到新 session_key,但是無法對老 session_key 加密過的數據解密,用戶信息獲取失敗
          • 在用戶信息授權之前先調用 wx.checkSession 呢?wx.checkSession 檢查登錄態,并且保證 wx.login 不會刷新 session_key,從而讓后端服務正確解密數據。但是這里存在一個問題,如果小程序較長時間不用導致 session_key 過期,則 wx.login 必定會重新生成 session_key,從而再一次導致用戶信息解密失敗。

          性能優化

          我們知道view部分是運行在webview上的,所以前端領域的大多數優化方式都有用。

          我們知道view部分是運行在webview上的,所以前端領域的大多數優化方式都有用。

          我們知道view部分是運行在webview上的,所以前端領域的大多數優化方式都有用。

          加載優化

          preload">

          代碼包的大小是最直接影響小程序加載啟動速度的因素。代碼包越大不僅下載速度時間長,業務代碼注入時間也會變長。所以最好的優化方式就是減少代碼包的大小。

          load-time-series">

          小程序加載的三個階段的表示。

          優化方式

          • 代碼壓縮。
          • 及時清理無用代碼和資源文件。
          • 減少代碼包中的圖片等資源文件的大小和數量。
          • 分包加載。

          首屏加載的體驗優化建議

          • 提前請求: 異步數據請求不需要等待頁面渲染完成。
          • 利用緩存: 利用 storage API 對異步請求數據進行緩存,二次啟動時先利用緩存數據渲染頁面,在進行后臺更新。
          • 避免白屏:先展示頁面骨架頁和基礎內容。
          • 及時反饋:即時地對需要用戶等待的交互操作給出反饋,避免用戶以為小程序無響應。

          使用分包加載優化

          sub-package">

          在構建小程序分包項目時,構建會輸出一個或多個功能的分包,其中每個分包小程序必定含有一個主包,所謂的主包,即放置默認啟動頁面/TabBar 頁面,以及一些所有分包都需用到公共資源/JS 腳本,而分包則是根據開發者的配置進行劃分。

          在小程序啟動時,默認會下載主包并啟動主包內頁面,如果用戶需要打開分包內某個頁面,客戶端會把對應分包下載下來,下載完成后再進行展示。

          優點:

          • 對開發者而言,能使小程序有更大的代碼體積,承載更多的功能與服務
          • 對用戶而言,可以更快地打開小程序,同時在不影響啟動速度前提下使用更多功能

          限制:

          • 整個小程序所有分包大小不超過 8M
          • 單個分包/主包大小不能超過 2M

          原生分包加載的配置 假設支持分包的小程序目錄結構如下:

          ├── app.js
          ├── app.json
          ├── app.wxss
          ├── packageA
          │   └── pages
          │       ├── cat
          │       └── dog
          ├── packageB
          │   └── pages
          │       ├── apple
          │       └── banana
          ├── pages
          │   ├── index
          │   └── logs
          └── utils
          
          復制代碼

          開發者通過在 app.json subPackages 字段聲明項目分包結構:

          {
            "pages":[
              "pages/index",
              "pages/logs"
            ],
            "subPackages": [
              {
                "root": "packageA",
                "pages": [
                  "pages/cat",
                  "pages/dog"
                ]
              }, {
                "root": "packageB",
                "pages": [
                  "pages/apple",
                  "pages/banana"
                ]
              }
            ]
          }
          
          復制代碼

          分包原則

          • 聲明 subPackages 后,將按 subPackages 配置路徑進行打包,subPackages 配置路徑外的目錄將被打包到 app(主包) 中
          • app(主包)也可以有自己的 pages(即最外層的 pages 字段
          • subPackage 的根目錄不能是另外一個 subPackage 內的子目錄
          • 首頁的 TAB 頁面必須在 app(主包)內

          引用原則

          • packageA 無法 require packageB JS 文件,但可以 require app、自己 package 內的 JS 文件
          • packageA 無法 import packageB 的 template,但可以 require app、自己 package 內的 template
          • packageA 無法使用 packageB 的資源,但可以使用 app、自己 package 內的資源

          官方即將推出 分包預加載

          preload-sub-package">

          獨立分包

          single-sub-package">

          渲染性能優化

          render">

          • 每次 setData 的調用都是一次進程間通信過程,通信開銷與 setData 的數據量正相關。

          • setData 會引發視圖層頁面內容的更新,這一耗時操作一定時間中會阻塞用戶交互。

          • setData 是小程序開發使用最頻繁,也是最容易引發性能問題的。

          避免不當使用 setData

          • 使用 data 在方法間共享數據,可能增加 setData 傳輸的數據量。。data 應僅包括與頁面渲染相關的數據。
          • 使用 setData 傳輸大量數據,**通訊耗時與數據正相關,頁面更新延遲可能造成頁面更新開銷增加。**僅傳輸頁面中發生變化的數據,使用 setData 的特殊 key 實現局部更新。
          • 短時間內頻繁調用 setData,**操作卡頓,交互延遲,阻塞通信,頁面渲染延遲。**避免不必要的 setData,對連續的setData調用進行合并。
          • 在后臺頁面進行 setData,**搶占前臺頁面的渲染資源。**頁面切入后臺后的 setData 調用,延遲到頁面重新展示時執行。

          one-context">

          避免不當使用onPageScroll

          • 只在有必要的時候監聽 pageScroll 事件。不監聽,則不會派發。
          • 避免在 onPageScroll 中執行復雜邏輯
          • 避免在 onPageScroll 中頻繁調用 setData
          • 避免滑動時頻繁查詢節點信息(SelectQuery)用以判斷是否顯示,部分場景建議使用節點布局橡膠狀態監聽(inersectionObserver)替代

          使用自定義組件

          在需要頻繁更新的場景下,自定義組件的更新只在組件內部進行,不受頁面其他部分內容復雜性影響。

          官方小程序技術能力規劃

          自定義組件2.0

          小程序的幾個頁面間,存在一些相同或是類似的區域,這時候可以把這些區域邏輯封裝成一個自定義組件,代碼就可以重用,或者對于比較獨立邏輯,也可以把它封裝成一個自定義組件,也就是微信去年發布的自定義組件,它讓代碼得到復用、減少代碼量,更方便模塊化,優化代碼架構組織,也使得模塊清晰,后期更好地維護,從而保證更好的性能。

          但微信打算在原來的基礎上推出的自定義組件 2.0,它將擁有更高級的性能:

          • usingComponents 計劃支持全局定義和通配符定義:這意味著不用在每個頁面反復定義,可以批量導入目錄下的所有自定義組件
          • 計劃支持類似 Computed 和 watch 的功能,它能使代碼邏輯更清晰
          • 計劃支持 Component 構造器插件,在實例化一個自定義組件的時候,允許你在構造器的這個階段,加入一些邏輯,方便進行一些擴展,甚至是可以擴展成 Vue 的語法

          npm支持

          目前小程序開發的痛點是:開源組件要手動復制到項目,后續更新組件也需要手動操作。不久的將來,小程序將支持npm包管理,有了這

          相關標簽
          免費獲取專屬 《策劃方案 》及報價
          免費體驗我們的業務系統、OA系統、在線教育、電商系統、智慧辦公等產品定制化方案,助力您的信息化發展之路
          即時交流
          在線咨詢 電話咨詢
          在線咨詢
          產品經理

          一對一產品經理

          180 8812 7777
          電話咨詢

          電話咨詢

          0871-6718 6978
          到訪面聊
          返回頂部
          欧美人妻久久精品,久久国产色av免费看,女人国产香蕉久久精品,伊人久久综在合线亚洲