国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

帶你玩轉(zhuǎn)小程序開發(fā)實踐|含直播回顧視頻

fxp / 1451人閱讀

摘要:小程序的視圖層目前使用作為渲染載體,而邏輯層是由獨立的作為運行環(huán)境。比如小程序的,通信一次就像是寫情書所以,嚴格來說,小程序是微信定制的混合開發(fā)模式。出棧入棧解決小程序接口不支持的問題小程序的所有接口,都是通過傳統(tǒng)的回調(diào)函數(shù)形式來調(diào)用的。

作者:張利濤,視頻課程《微信小程序教學(xué)》、《基于Koa2搭建Node.js實戰(zhàn)項目教學(xué)》主編,滬江前端架構(gòu)師

本文原創(chuàng),轉(zhuǎn)載請注明作者及出處

小程序和 H5 區(qū)別

小程序的運行過程

解決小程序接口不支持 Promise 的問題

小程序組件化開發(fā)及通信

小程序和 H5 區(qū)別
我們不一樣,不一樣,不一樣。
運行環(huán)境 runtime

首先從官方文檔可以看到,小程序的運行環(huán)境并不是瀏覽器環(huán)境:

小程序框架提供了自己的視圖層描述語言 WXML 和 WXSS,以及基于 JavaScript 的邏輯層框架,并在視圖層與邏輯層間提供了數(shù)據(jù)傳輸和事件系統(tǒng),可以讓開發(fā)者可以方便的聚焦于數(shù)據(jù)與邏輯上。

小程序的視圖層目前使用 WebView 作為渲染載體,而邏輯層是由獨立的 JavascriptCore 作為運行環(huán)境。在架構(gòu)上,WebView 和 JavascriptCore 都是獨立的模塊,并不具備數(shù)據(jù)直接共享的通道。當(dāng)前,視圖層和邏輯層的數(shù)據(jù)傳輸,實際上通過兩邊提供的 evaluateJavascript 所實現(xiàn)。即用戶傳輸?shù)臄?shù)據(jù),需要將其轉(zhuǎn)換為字符串形式傳遞,同時把轉(zhuǎn)換后的數(shù)據(jù)內(nèi)容拼接成一份 JS 腳本,再通過執(zhí)行 JS 腳本的形式傳遞到兩邊獨立環(huán)境。

而 evaluateJavascript 的執(zhí)行會受很多方面的影響,數(shù)據(jù)到達視圖層并不是實時的。同一進程內(nèi)的 WebView 實際上會共享一個 JS VM,如果 WebView 內(nèi) JS 線程正在執(zhí)行渲染或其他邏輯,會影響 evaluateJavascript 腳本的實際執(zhí)行時間,另外多個 WebView 也會搶占 JS VM 的執(zhí)行權(quán)限;另外還有 JS 本身的編譯執(zhí)行耗時,都是影響數(shù)據(jù)傳輸速度的因素。

而所謂的運行環(huán)境,對于任何語言的運行,它們都需要有一個環(huán)境——runtime。瀏覽器和 Node.js 都能運行 JavaScript,但它們都只是指定場景下的 runtime,所有各有不同。而小程序的運行環(huán)境,是微信定制化的 runtime。

大家可以做一個小實驗,分別在瀏覽器環(huán)境和小程序環(huán)境打開各自的控制臺,運行下面的代碼來進行一個 20 億次的循環(huán):

var k
for (var i = 0; i < 2000000000; i++) {
  k = i
}

瀏覽器控制臺下運行時,當(dāng)前頁面是完全不能動,因為 JS 和視圖共用一個線程,相互阻塞。

小程序控制臺下運行時,當(dāng)前視圖可以動,如果綁定有事件,也會一樣觸發(fā),只不過事件的回調(diào)需要在 『循環(huán)結(jié)束』 之后。

視圖層和邏輯層如果共用一個線程,優(yōu)點是通信速度快(離的近就是好),缺點是相互阻塞。比如瀏覽器。

視圖層和邏輯層如果分處兩個環(huán)境,優(yōu)點是相互不阻塞,缺點是通信成本高(異地戀)。比如小程序的 setData,通信一次就像是寫情書!

所以,嚴格來說,小程序是微信定制的混合開發(fā)模式。

在 JavaScript 的基礎(chǔ)上,小程序做了一些修改,以方便開發(fā)小程序。

增加 App 和 Page 方法,進行程序和頁面的注冊。【增加了 Component】

增加 getApp 和 getCurrentPages 方法,分別用來獲取 App 實例和當(dāng)前頁面棧。

提供豐富的 API,如微信用戶數(shù)據(jù),掃一掃,支付等微信特有能力?!菊{(diào)用原生組件:Cordova、ReactNative、Weex 等】

每個頁面有獨立的作用域,并提供模塊化能力。

由于框架并非運行在瀏覽器中,所以 JavaScript 在 web 中一些能力都無法使用,如 document,window 等。【小程序的 JsCore 環(huán)境】

開發(fā)者寫的所有代碼最終將會打包成一份 JavaScript,并在小程序啟動的時候運行,直到小程序銷毀。類似 ServiceWorker,所以邏輯層也稱之為 App Service。

與傳統(tǒng)的 HTML 相比,WXML 更像是一種模板式的標(biāo)簽語言

從實踐體驗上看,我們可以從小程序視圖上看到 Java FreeMarker 框架、Velocity、smarty 之類的影子。

小程序視圖支持如下

數(shù)據(jù)綁定 {{}}
列表渲染 wx:for
條件判斷 wx:if
模板 tempalte
事件 bindtap
引用 import include
可在視圖中應(yīng)用的腳本語言  wxs
...

Java FreeMarker 也同樣支持上述功能。

數(shù)據(jù)綁定 ${}
列表渲染 list指令
條件判斷 if指令
模板 FTL
事件 原生事件
引用 import include 指令
內(nèi)建函數(shù) 比如『時間格式化』
可在視圖中應(yīng)用的腳本語言 宏 marco
...
 小程序的運行過程

我們在微信上打開一個小程序
微信客戶端在打開小程序之前,會把整個小程序的代碼包下載到本地。

微信 App 從微信服務(wù)器下載小程序的文件包
為了流暢的用戶體驗和性能問題,小程序的文件包不能超過 2M。另外要注意,小程序目錄下的所有文件上傳時候都會打到一個包里面,所以盡量少用圖片和第三方的庫,特別是圖片。

解析 app.json 配置信息初始化導(dǎo)航欄,窗口樣式,包含的頁面列表

加載運行 app.js
初始化小程序,創(chuàng)建 app 實例

根據(jù) app.json,加載運行第一個頁面初始化第一個 Page

路由切換
以棧的形式維護了當(dāng)前的所有頁面。最多 5 個頁面。出棧入棧

 解決小程序接口不支持 Promise 的問題

小程序的所有接口,都是通過傳統(tǒng)的回調(diào)函數(shù)形式來調(diào)用的?;卣{(diào)函數(shù)真正的問題在于他剝奪了我們使用 return 和 throw 這些關(guān)鍵字的能力。而 Promise 很好地解決了這一切。

那么,如何通過 Promise 的方式來調(diào)用小程序接口呢?

查看一下小程序的官方文檔,我們會發(fā)現(xiàn),幾乎所有的接口都是同一種書寫形式:

wx.request({
  url: "test.php", //僅為示例,并非真實的接口地址
  data: {
    x: "",
    y: ""
  },
  header: {
    "content-type": "application/json" // 默認值
  },
  success: function(res) {
    console.log(res.data)
  },
  fail: function(res) {
    console.log(res)
  }
})

所以,我們可以通過簡單的 Promise 寫法,把小程序接口裝飾一下。代碼如下:

wx.request2 = (option = {}) => {
  // 返回一個 Promise 實例對象,這樣就可以使用 then 和 throw
  return new Promise((resolve, reject) => {
    option.success = res => {
      // 重寫 API 的 success 回調(diào)函數(shù)
      resolve(res)
    }
    option.fail = res => {
      // 重寫 API 的 fail 回調(diào)函數(shù)
      reject(res)
    }
    wx.request(option) // 裝飾后,進行正常的接口請求
  })
}

上述代碼簡單的展現(xiàn)了如何把一個請求接口包裝成 Promise 形式。但在實戰(zhàn)項目中,可能有多個接口需要我們?nèi)グb處理,每一個都多帶帶包裝是不現(xiàn)實的。這時候,我們就需要用一些技巧來處理了。

其實思路很簡單:我們把需要 Promise 化的『接口名字』存放在一個『數(shù)組』中,然后對這個數(shù)組進行循環(huán)處理。

這里我們利用了 ECMAScript5 的特性 Object.defineProperty 來重寫接口的取值過程。

let wxKeys = [
  // 存儲需要Promise化的接口名字
  "showModal",
  "request"
]
// 擴展 Promise 的 finally 功能
Promise.prototype.finally = function(callback) {
  let P = this.constructor
  return this.then(
    value => P.resolve(callback()).then(() => value),
    reason =>
      P.resolve(callback()).then(() => {
        throw reason
      })
  )
}
wxKeys.forEach(key => {
  const wxKeyFn = wx[key] // 將wx的原生函數(shù)臨時保存下來
  if (wxKeyFn && typeof wxKeyFn === "function") {
    // 如果這個值存在并且是函數(shù)的話,進行重寫
    Object.defineProperty(wx, key, {
      get() {
        // 一旦目標(biāo)對象訪問該屬性,就會調(diào)用這個方法,并返回結(jié)果
        // 調(diào)用 wx.request({}) 時候,就相當(dāng)于在調(diào)用此函數(shù)
        return (option = {}) => {
          // 函數(shù)運行后,返回 Promise 實例對象
          return new Promise((resolve, reject) => {
            option.success = res => {
              resolve(res)
            }
            option.fail = res => {
              reject(res)
            }
            wxKeyFn(option)
          })
        }
      }
    })
  }
})

注: Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現(xiàn)有屬性,并返回這個對象。

用法也很簡單,我們把上述代碼保存在一個 js 文件中,比如 utils/toPromise.js,然后在 app.js 中引入就可以了:

import "./util/toPromise"

App({
  onLoad() {
    wx
      .request({
        url: "http://www.weather.com.cn/data/sk/101010100.html"
      })
      .then(res => {
        console.log("come from Promised api, then:", res)
      })
      .catch(err => {
        console.log("come from Promised api, catch:", err)
      })
      .finally(res => {
        console.log("come from Promised api, finally:")
      })
  }
})
小程序組件化開發(fā)

小程序從 1.6.3 版本開始,支持簡潔的組件化編程

官方支持組件化之前的做法
// 組件內(nèi)部實現(xiàn)
export default class TranslatePop {
    constructor(owner, deviceInfo = {}) {
        this.owner = owner;
        this.defaultOption = {}
    }
    init() {
        this.applyData({...})
    }
    applyData(data) {
        let optData = Object.assign(this.defaultOption, data);
        this.owner && this.owner.setData({
            translatePopData: optData
        })
    }
}
// index.js 中調(diào)用
translatePop = new TranslatePop(this);
translatePop.init();

實現(xiàn)方式比較簡單,就是在調(diào)用一個組件時候,把當(dāng)前環(huán)境的上下文 content 傳遞給組件,在組件內(nèi)部實現(xiàn) setData 調(diào)用。

應(yīng)用官方支持的方式來實現(xiàn)

官方組件示例:

Component({
  properties: {
    // 這里定義了innerText屬性,屬性值可以在組件使用時指定
    innerText: {
      type: String,
      value: "default value"
    }
  },
  data: {
    // 這里是一些組件內(nèi)部數(shù)據(jù)
    someData: {}
  },
  methods: {
    // 這里是一個自定義方法
    customMethod: function() {}
  }
})
結(jié)合 Redux 實現(xiàn)組件通信

在 React 項目中 Redux 是如何工作的

單一數(shù)據(jù)源

整個應(yīng)用的 state 被儲存在一棵 object tree 中,并且這個 object tree 只存在于唯一一個 store 中。

State 是只讀的

惟一改變 state 的方法就是觸發(fā) action,action 是一個用于描述已發(fā)生事件的普通對象

使用純函數(shù)來執(zhí)行修改

為了描述 action 如何改變 state tree ,你需要編寫 reducers。

Props 傳遞 —— Render 渲染

如果你有看過 Redux 的源碼就會發(fā)現(xiàn),上述的過程可以簡化描述如下:

訂閱:監(jiān)聽狀態(tài)————保存對應(yīng)的回調(diào)

發(fā)布:狀態(tài)變化————執(zhí)行回調(diào)函數(shù)

同步視圖:回調(diào)函數(shù)同步數(shù)據(jù)到視圖

第三步:同步視圖,在 React 中,State 發(fā)生變化后會觸發(fā) Render 來更新視圖。

而小程序中,如果我們通過 setData 改變 data,同樣可以更新視圖。

所以,我們實現(xiàn)小程序組件通信的思路如下:

觀察者模式/發(fā)布訂閱模式

裝飾者模式/Object.defineProperty (Vuejs 的設(shè)計路線)

在小程序中實現(xiàn)組件通信

先預(yù)覽下我們的最終項目結(jié)構(gòu):

├── components/
│     ├── count/
│        ├── count.js
│        ├── count.json
│        ├── count.wxml
│        ├── count.wxss 
│     ├── footer/ 
│        ├── footer.js
│        ├── footer.json
│        ├── footer.wxml
│        ├── footer.wxss
├── pages/
│     ├── index/
│        ├── ...
│     ├── log/ 
│        ├── ...
├── reducers/
│     ├── counter.js
│     ├── index.js
│     ├── redux.min.js
├── utils/
│     ├── connect.js
│     ├── shallowEqual.js
│     ├── toPromise.js
├── app.js
├── app.json
├── app.wxss
1. 實現(xiàn)『發(fā)布訂閱』功能

首先,我們從 cdn 或官方網(wǎng)站獲取 redux.min.js,放在結(jié)構(gòu)里面

創(chuàng)建 reducers 目錄下的文件:

// /reducers/index.js
import { createStore, combineReducers } from "./redux.min.js"
import counter from "./counter"

export default createStore(combineReducers({
  counter: counter
}))

// /reducers/counter.js
const INITIAL_STATE = {
  count: 0,
  rest: 0
}
const Counter = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case "COUNTER_ADD_1": {
      let { count } = state
      return Object.assign({}, state, { count: count + 1 })
    }
    case "COUNTER_CLEAR": {
      let { rest } = state
      return Object.assign({}, state, { count: 0, rest: rest+1 })
    }
    default: {
      return state
    }
  }
}
export default Counter

我們定義了一個需要傳遞的場景值 count,用來代表例子中的『點擊次數(shù)』,rest 代表『重置次數(shù)』。

然后在 app.js 中引入,并植入到小程序全局中:

//app.js
import Store from "./reducers/index"
App({
  Store,
})
2. 利用 『裝飾者模式』,對小程序的生命周期進行包裝,狀態(tài)發(fā)生變化時候,如果狀態(tài)值不一樣,就同步 setData
// 引用了 react-redux 中的工具函數(shù),用來判斷兩個狀態(tài)是否相等
import shallowEqual from "./shallowEqual"
// 獲取我們在 app.js 中植入的全局變量 Store
let __Store = getApp().Store
// 函數(shù)變量,用來過濾出我們想要的 state,方便對比賦值
let mapStateToData
// 用來補全配置項中的生命周期函數(shù)
let baseObj = {
  __observer: null,
  onLoad() { },
  onUnload() { },
  onShow() { },
  onHide() { }
}
let config = {
  __Store,
  __dispatch: __Store.dispatch,
  __destroy: null,
  __observer() {
    // 對象中的 super,指向其原型 prototype
    if (super.__observer) {
      super.__observer()
      return
    }
    const state = __Store.getState()
    const newData = mapStateToData(state)
    const oldData = mapStateToData(this.data || {})
    if (shallowEqual(oldData, newData)) {// 狀態(tài)值沒有發(fā)生變化就返回
      return
    }
    this.setData(newData)
  },
  onLoad() {
    super.onLoad()
    this.__destroy = this.__Store.subscribe(this.__observer)
    this.__observer()
  },
  onUnload() {
    super.onUnload()
    this.__destroy && this.__destroy() & delete this.__destroy
  },
  onShow() {
    super.onShow()
    if (!this.__destroy) {
      this.__destroy = this.__Store.subscribe(this.__observer)
      this.__observer()
    }
  },
  onHide() {
    super.onHide()
    this.__destroy && this.__destroy() & delete this.__destroy
  }
}
export default (mapState = () => { }) => {
  mapStateToData = mapState
  return (options = {}) => {
    // 補全生命周期
    let opts = Object.assign({}, baseObj, options)
    // 把業(yè)務(wù)代碼中的 opts 配置對象,指定為 config 的原型,方便『裝飾者調(diào)用』
    Object.setPrototypeOf(config, opts)
    return config
  }
}

調(diào)用方法:

// pages/index/index.js
import connect from "../../utils/connect"
const mapStateToProps = (state) => {
  return {
    counter: state.counter
  }
}
Page(connect(mapStateToProps)({
  data: {
    innerText: "Hello 點我加1哦"
  },
  bindBtn() {
    this.__dispatch({
      type: "COUNTER_ADD_1"
    })
  }
}))

最終效果展示:

項目源碼地址:
https://github.com/ikcamp/xcx-redux

直播視頻地址:
https://www.cctalk.com/v/15137361643293

iKcamp官網(wǎng):https://www.ikcamp.com

iKcamp新課程推出啦~~~~~開始免費連載啦~每周2更共11堂iKcamp課|基于Koa2搭建Node.js實戰(zhàn)項目教學(xué)(含視頻)| 課程大綱介紹

滬江iKcamp出品微信小程序教學(xué)共5章16小節(jié)匯總(含視頻)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/92306.html

相關(guān)文章

  • 老司機【分享】帶你玩轉(zhuǎn)阿里云服務(wù)器

    摘要:阿里云是國內(nèi)云服務(wù)器市場的龍頭,性價比高,速度快又安全,是站長建站首選的云服務(wù)器之一。作為一個老司機,福利吧也和大家分享一下我的阿里云推廣經(jīng)驗,教大家如何免費推廣云大使。阿里云是國內(nèi)云服務(wù)器市場的龍頭,性價比高,速度快又安全,是站長建站首選的云服務(wù)器之一。福利吧使用的也是阿里云服務(wù)器,是折騰了很多次網(wǎng)站搬家后,才選擇了阿里云。身邊好幾個站長最后都殊途同歸,用了阿里云,可見阿里云服務(wù)器性能確實...

    banana_pi 評論0 收藏0
  • 【深入淺出容器云】五分鐘帶你玩轉(zhuǎn)Docker容器服務(wù)

    摘要:深入淺出容器云系列文章是由時速云出品,本文是第二篇,歡迎大家不吝賜教。容器服務(wù)是一種高度可擴展的高性能容器管理服務(wù),服務(wù)于應(yīng)用的完整生命周期。存儲卷容器服務(wù)支持有狀態(tài)和無狀態(tài)服務(wù)。當(dāng)容器重新部署時也會隨著容器在不同主機之間遷移。 導(dǎo)語:隨著以Docker為代表的容器技術(shù)在國內(nèi)的迅速發(fā)展,容器云也逐漸被廣大開發(fā)者所熟知,但容器云(CaaS)相比傳統(tǒng)的云主機(IaaS)在實際應(yīng)用中還存在著...

    AlexTuan 評論0 收藏0
  • 帶你玩轉(zhuǎn) JavaScript ES6 (七) - 異步

    摘要:說明處理方法被異步執(zhí)行了。意味著操作成功完成。狀態(tài)的對象可能觸發(fā)狀態(tài)并傳遞一個值給相應(yīng)的狀態(tài)處理方法,也可能觸發(fā)失敗狀態(tài)并傳遞失敗信息。注生命周期相關(guān)內(nèi)容引用自四使用和異步加載圖片這是官方給出的示例,部分的代碼如下 帶你玩轉(zhuǎn) JavaScript ES6 (七) - 異步 本文同步帶你玩轉(zhuǎn) JavaScript ES6 (七) - 異步,轉(zhuǎn)載請注明出處。 本章我們將學(xué)習(xí) ES6 中的 ...

    he_xd 評論0 收藏0
  • 帶你玩轉(zhuǎn)css3的3D!

    摘要:透視即是以現(xiàn)實的視角來看屏幕上的事物,從而展現(xiàn)的效果。旋轉(zhuǎn)則不再是平面上的旋轉(zhuǎn),而是三維坐標(biāo)系的旋轉(zhuǎn),就包括軸,軸,軸旋轉(zhuǎn)。必須與屬性一同使用,而且只影響轉(zhuǎn)換元素。可自由轉(zhuǎn)載引用,但需署名作者且注明文章出處。 showImg(https://segmentfault.com/img/bVzJoZ); 話不多說,先上demo 酷炫css3走馬燈/正方體動畫: https://bupt-...

    Panda 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<