摘要:自定義組件的自定義組件,是基于微信小程序框架的組件之上,進(jìn)一步自定義組合,擁有邏輯處理和樣式。這樣做的目的請(qǐng)參見(jiàn)微信小程序開(kāi)發(fā)三宗罪和解決方案項(xiàng)目中通用自定義組件存放在目錄,一個(gè)組件一般由三個(gè)文件組成,和分別對(duì)應(yīng)微信小程序框架的和文件。
Labrador 是一個(gè)專為微信小程序開(kāi)發(fā)的組件化開(kāi)發(fā)框架。
特性使用Labrador框架可以使微信開(kāi)發(fā)者工具支持加載海量NPM包
支持ES6/7標(biāo)準(zhǔn)代碼,使用async/await能夠有效避免回調(diào)地獄
組件重用,對(duì)微信小程序框架進(jìn)行了二次封裝,實(shí)現(xiàn)了組件重用和嵌套
自動(dòng)化測(cè)試,非常容易編寫(xiě)單元測(cè)試腳本,不經(jīng)任何額外配置即可自動(dòng)化測(cè)試
使用Editor Config及ESLint標(biāo)準(zhǔn)化代碼風(fēng)格,方便團(tuán)隊(duì)協(xié)作
安裝首先您的系統(tǒng)中安裝Node.js和npm v3 下載Node.js,然后運(yùn)行下面的命令將全局安裝Labrador命令行工具。
npm install -g labrador-cli初始化項(xiàng)目
mkdir demo # 新建目錄 cd demo # 跳轉(zhuǎn)目錄 npm init # 初始化npm包 labrador init # 初始化labrador項(xiàng)目項(xiàng)目目錄結(jié)構(gòu)
demo # 項(xiàng)目根目錄 ├── .labrador # Labrador項(xiàng)目配置文件 ├── .babelrc # babel配置文件 ├── .editorconfig # Editor Config ├── .eslintignore # ESLint 忽略配置 ├── .eslintrc # ESLint 語(yǔ)法檢查配置 ├── package.json ├── dist/ # 目標(biāo)目錄 ├── node_modules/ └── src/ # 源碼目錄 ├── app.js ├── app.json ├── app.less ├── components/ # 通用組件目錄 ├── pages/ # 頁(yè)面目錄 └── utils/
配置開(kāi)發(fā)工具注意 dist目錄中的所有文件是由labrador命令編譯生成,請(qǐng)勿直接修改
項(xiàng)目初始化后使用WebStorm或Sublime等你習(xí)慣的IDE打開(kāi)項(xiàng)目根目錄。然后打開(kāi) 微信web開(kāi)發(fā)者工具 新建項(xiàng)目,本地開(kāi)發(fā)目錄選擇 dist 目標(biāo)目錄。
開(kāi)發(fā)流程在WebStorm或Sublime等IDE中編輯 src 目錄下的源碼,然后在項(xiàng)目根目錄中運(yùn)行labrador build 命令構(gòu)建項(xiàng)目,然后在 微信web開(kāi)發(fā)者工具 的調(diào)試界面中點(diǎn)擊左側(cè)菜單的 重啟 按鈕即可查看效果。
我們?cè)陂_(kāi)發(fā)中, 微信web開(kāi)發(fā)者工具 僅僅用來(lái)做調(diào)試和預(yù)覽,不要在 微信web開(kāi)發(fā)者工具 的編輯界面修改代碼。
微信web開(kāi)發(fā)者工具 會(huì)偶爾出錯(cuò),表現(xiàn)為點(diǎn)擊 重啟 按鈕沒(méi)有反應(yīng),調(diào)試控制臺(tái)輸出大量的無(wú)法require文件的錯(cuò)誤,編輯 界面中代碼文件不顯示。這是因?yàn)?labrador build 命令會(huì)更新整個(gè) dist 目錄,而 微信web開(kāi)發(fā)者工具 在監(jiān)測(cè)代碼改變時(shí)會(huì)出現(xiàn)異常,遇到這種情況只需要關(guān)掉 微信web開(kāi)發(fā)者工具 再啟動(dòng)即可。
我們還可以使用 labrador watch 命令來(lái)監(jiān)控 src 目錄下的代碼,當(dāng)發(fā)生改變后自動(dòng)構(gòu)建,不用每一次編輯代碼后手動(dòng)運(yùn)行 labrador build 。
所以最佳的姿勢(shì)是:
在項(xiàng)目中運(yùn)行 labrador watch
在WebStorm中編碼,保存
切換到 微信web開(kāi)發(fā)者工具 中調(diào)試、預(yù)覽
再回到WebStorm中編碼
...
labrador 命令 labrador init 初始化項(xiàng)目命令注意此命令會(huì)初始化當(dāng)前的目錄為項(xiàng)目目錄。
labrador build 構(gòu)建當(dāng)前項(xiàng)目Usage: labrador build [options] Options: -h, --help output usage information -V, --version output the version number -c, --catch 在載入時(shí)自動(dòng)catch所有JS腳本的錯(cuò)誤 -t, --test 運(yùn)行測(cè)試腳本 -d, --debug DEBUG模式 -m, --minify uglify壓縮代碼labrador watch 監(jiān)測(cè)文件變化
Usage: labrador watch [options] Options: -h, --help output usage information -V, --version output the version number -c, --catch 在載入時(shí)自動(dòng)catch所有JS腳本的錯(cuò)誤 -t, --test 運(yùn)行測(cè)試腳本 -d, --debug DEBUG模式 -m, --minify uglify壓縮代碼labrador 庫(kù)
labrador 庫(kù)對(duì)全局的 wx 變量進(jìn)行了封裝,將大部分 wx 對(duì)象中的方法進(jìn)行了Promise支持, 除了以 on* 開(kāi)頭或以 *Sync 結(jié)尾的方法。在如下代碼中使用 labrador 庫(kù)。
import wx from "labrador"; console.log(wx.version); wx.app; // 和全局的 getApp() 函數(shù)效果一樣,代碼風(fēng)格不建議粗暴地訪問(wèn)全局對(duì)象和方法 wx.Component; // Labrador 自定義組件基類 wx.Types; // Labrador 數(shù)據(jù)類型校驗(yàn)器集合 wx.login; // 封裝后的微信登錄接口 wx.getStorage; // 封裝后的讀取緩存接口 //... 更多請(qǐng)參見(jiàn) https://mp.weixin.qq.com/debug/wxadoc/dev/api/
我們建議不要再使用 wx.getStorageSync() 等同步阻塞方法,而在 async 函數(shù)中使用 await wx.getStorage() 異步非阻塞方法提高性能,除非遇到特殊情況。
app.jssrc/app.js 示例代碼如下:
import wx from "labrador"; import {sleep} from "./utils/util"; export default class { globalData = { userInfo: null }; async onLaunch() { //調(diào)用API從本地緩存中獲取數(shù)據(jù) let res = await wx.getStorage({ key: "logs" }); let logs = res.data || []; logs.unshift(Date.now()); await wx.setStorage({ key: "logs", data: logs }); this.timer(); } async timer() { while (true) { console.log("hello"); await sleep(10000); } } async getUserInfo() { if (this.globalData.userInfo) { return this.globalData.userInfo; } await wx.login(); let res = await wx.getUserInfo(); this.globalData.userInfo = res.userInfo; return res.userInfo; } }
代碼中全部使用ES6/7標(biāo)準(zhǔn)語(yǔ)法。代碼不必聲明 use strict ,因?yàn)樵诰幾g時(shí),所有代碼都會(huì)強(qiáng)制使用嚴(yán)格模式。
代碼中并未調(diào)用全局的 App() 方法,而是使用 export 語(yǔ)法默認(rèn)導(dǎo)出了一個(gè)類,在編譯后,Labrador會(huì)自動(dòng)增加 App() 方法調(diào)用,所有請(qǐng)勿手動(dòng)調(diào)用 App() 方法。這樣做是因?yàn)榇a風(fēng)格不建議粗暴地訪問(wèn)全局對(duì)象和方法。
自定義組件Labrador的自定義組件,是基于微信小程序框架的組件之上,進(jìn)一步自定義組合,擁有邏輯處理和樣式。這樣做的目的請(qǐng)參見(jiàn) 微信小程序開(kāi)發(fā)三宗罪和解決方案
項(xiàng)目中通用自定義組件存放在 src/compontents 目錄,一個(gè)組件一般由三個(gè)文件組成,*.js 、 *.xml 和 *.less 分別對(duì)應(yīng)微信小程序框架的 js 、 wxml 和 wxss 文件。在Labardor項(xiàng)目源碼中,我們特意采用了 xml 和 less 后綴以示區(qū)別。如果組件包含單元測(cè)試,那么在組件目錄下會(huì)存在一個(gè) *.test.js 的測(cè)試腳本文件。
自定義組件示例下面是一個(gè)簡(jiǎn)單的自定義組件代碼實(shí)例:
import wx from "labrador"; import randomColor from "../../utils/random-color"; const { string } = wx.Types; export default class Title extends wx.Component { propTypes = { text: string }; props = { text: "" }; data = { text: "", color: randomColor() }; onUpdate(props) { this.setData("text", props.text); } handleTap() { this.setData({ color: randomColor() }); } }
自定義組件的邏輯代碼和微信框架中的page很相似,最大的區(qū)別是在js邏輯代碼中,沒(méi)有調(diào)用全局的 Page() 函數(shù)聲明頁(yè)面,而是用 export 語(yǔ)法導(dǎo)出了一個(gè)默認(rèn)的類,這個(gè)類必須繼承于 labrador.Component 組件基類。
相對(duì)于微信框架中的page,Labrador自定義組件擴(kuò)展了 propTypes 、 props 、 children 選項(xiàng)及 onUpdate 生命周期函數(shù)。children 選項(xiàng)代表當(dāng)前組件中的子組件集合,此選項(xiàng)將在下文中敘述。
Labrador的目標(biāo)是構(gòu)建一個(gè)可以重用、嵌套的自定義組件方案,在現(xiàn)實(shí)情況中,當(dāng)多個(gè)組件互相嵌套組合,就一定會(huì)遇到父子組件件的數(shù)據(jù)和消息傳遞。因?yàn)樗械慕M件都實(shí)現(xiàn)了 setData 方法,所以我們可以使用 this.children.foobar.setData(data) 或 this.parent.setData(data) 這樣的代碼調(diào)用來(lái)解決父子組件間的數(shù)據(jù)傳遞問(wèn)題,但是,如果項(xiàng)目中出現(xiàn)大量這樣的代碼,那么數(shù)據(jù)流將變得非常混亂。
我們借鑒了 React.js 的思想,為組件增加了 props 機(jī)制。子組件通過(guò) this.props 得到父組件給自己傳達(dá)的參數(shù)數(shù)據(jù)。父組件怎樣將數(shù)據(jù)傳遞給子組件,我們下文中敘述。
onUpdate 生命周期函數(shù)是當(dāng)組件的 props 發(fā)生變化后被調(diào)用,類似React.js中的 componentWillReceiveProps 所以我們可以在此函數(shù)體內(nèi)監(jiān)測(cè) props 的變化。
組件定義時(shí)的 propTypes 選項(xiàng)是對(duì)當(dāng)前組件的props參數(shù)數(shù)據(jù)類型的定義。 props 選項(xiàng)代表的是當(dāng)前組件默認(rèn)的各項(xiàng)參數(shù)值。propTypes 、 props 選項(xiàng)都可以省略,但是強(qiáng)烈建議定義 propTypes,因?yàn)檫@樣可以使得代碼更清晰易懂,另外還可以通過(guò)Labrador自動(dòng)檢測(cè)props值類型,以減少BUG。為優(yōu)化性能,只有在DEBUG模式下才會(huì)自動(dòng)檢測(cè)props值類型。
編譯時(shí)加上 -d 參數(shù)時(shí)即可進(jìn)入DEBUG模式,在代碼中任何地方都可以使用魔術(shù)變量 __DEBUG__ 來(lái)判斷是否是DEBUG模式。
另外,Labrador自定義組件的 setData 方法,支持兩種傳參方式,第一種像微信框架一樣接受一個(gè) object 類型的對(duì)象參數(shù),第二種方式接受作為KV對(duì)的兩個(gè)參數(shù),setData 方法將自動(dòng)將其轉(zhuǎn)為 object。
注意 組件中事件響應(yīng)方法必須以 handle 開(kāi)頭!例如上文中的 handleTap,否則子組件將無(wú)法與模板綁定。這樣做也是為了代碼風(fēng)格統(tǒng)一,方便團(tuán)隊(duì)協(xié)作。建議事件響應(yīng)方法命名采用 handle + 組件名 + 事件名 例如:handleUsernameChange handleLoginButtonTap ,這樣我們很容易區(qū)分是模板上哪一個(gè)組件發(fā)生了什么事件,如果省略中間的名詞,如 handleTap ,則代表當(dāng)前整個(gè)自定義組件發(fā)生了 tap 事件。
{{text}}
XML布局文件和微信WXML文件語(yǔ)法完全一致,只是擴(kuò)充了一個(gè)自定義標(biāo)簽
.title-text { font-weight: bold; font-size: 2em; }
雖然我們采用了LESS文件,但是由于微信小程序框架的限制,不能使用LESS的層級(jí)選擇及嵌套語(yǔ)法。但是我們可以使用LESS的變量、mixin、函數(shù)等功能方便開(kāi)發(fā)。
頁(yè)面我們要求所有的頁(yè)面必須存放在 pages 目錄中,每個(gè)頁(yè)面的子目錄中的文件格式和自定義組件一致,只是可以多出一個(gè) *.json 配置文件。
頁(yè)面示例下面是默認(rèn)首頁(yè)的示例代碼:
import wx from "labrador"; import List from "../../components/list/list"; import Title from "../../components/title/title"; import Counter from "../../components/counter/counter"; export default class Index extends wx.Component { data = { userInfo: {}, mottoTitle: "Hello World", count: 0 }; get children() { return { list: new List(), motto: new Title({ text: "@mottoTitle" }), counter: new Counter({ count: "@count", onChange: this.handleCountChange }) }; } async onLoad() { try { //調(diào)用應(yīng)用實(shí)例的方法獲取全局?jǐn)?shù)據(jù) let userInfo = await wx.app.getUserInfo(); //更新數(shù)據(jù) this.setData({ userInfo }); this.update(); } catch (error) { console.error(error.stack); } } onReady() { this.setData("mottoTitle", "Labrador"); } handleCountChange(count) { this.setData({ count }); } //事件處理函數(shù) handleViewTap() { wx.navigateTo({ url: "../logs/logs" }); } }
頁(yè)面代碼的格式和自定義組件的格式一模一樣,我們的思想是 頁(yè)面也是組件。
js邏輯代碼中同樣使用 export default 語(yǔ)句導(dǎo)出了一個(gè)默認(rèn)類,也不能手動(dòng)調(diào)用 Page() 方法,因?yàn)樵诰幾g后,pages 目錄下的所有js文件全部會(huì)自動(dòng)調(diào)用 Page() 方法聲明頁(yè)面。
我們看到組件類中,有一個(gè)對(duì)象屬性 children ,這個(gè)屬性定義了該組件依賴、包含的其他自定義組件,在上面的代碼中頁(yè)面包含了三個(gè)自定義組件 list 、 title 和 counter ,這個(gè)三個(gè)自定義組件的 key 分別為 list 、 motto 和 counter。
自定義組件類在實(shí)例化時(shí)接受一個(gè)類型為 object 的參數(shù),這個(gè)參數(shù)就是父組件要傳給子組件的props數(shù)據(jù)。一般情況下,父組件傳遞給子組件的props屬性在其生命周期中是不變的,這是因?yàn)镴S的語(yǔ)法和小程序框架的限制,沒(méi)有React.js的JSX靈活。但是我們可以傳遞一個(gè)以 @ 開(kāi)頭的屬性值,這樣我們就可以把子組建的 props 屬性值綁定到父組件的 data 上來(lái),當(dāng)父組件的 data 發(fā)生變化后,Labrador將自動(dòng)更新子組件的 props。例如上邊代碼中,將子組件 motto 的 text 屬性綁定到了 @mottoTitle。那么在 onReady 方法中,將父組件的 mottoTitle 設(shè)置為 Labrador,那么子組件 motto 的 text 屬性就會(huì)自動(dòng)變?yōu)?Labrador。
頁(yè)面也是組件,所有的組件都擁有一樣的生命周期函數(shù)onLoad, onReady, onShow, onHide, onUnload,onUpdate 以及setData函數(shù)。
componets 和 pages 兩個(gè)目錄的區(qū)別在于,componets 中存放的組件能夠被智能加載,pages 目錄中的組件在編譯時(shí)自動(dòng)加上 Page() 調(diào)用,所以,pages 目錄中的組件不能被其他組件調(diào)用,否則將出現(xiàn)多次調(diào)用Page()的錯(cuò)誤。如果某個(gè)組件需要重用,請(qǐng)存放在 componets 目錄或打包成NPM包。
{{ userInfo.nickName }}
XML布局代碼中,使用了Labrador提供的
@import "list"; @import "title"; @import "counter"; .motto-title-text { font-size: 3em; padding-bottom: 1rem; } /* ... */
LESS樣式文件中,我們使用了 @import 語(yǔ)句加載所有子組件樣式,這里的 @import "list" 語(yǔ)句按照LESS的語(yǔ)法,會(huì)首先尋找當(dāng)前目錄 src/pages/index/ 中的 list.less 文件,如果找不到就會(huì)按照Labrador的規(guī)則智能地嘗試尋找 src/componets 和 node_modules 目錄中的組件樣式。
接下來(lái),我們定義了 .motto-title-text 樣式,這樣做是因?yàn)?motto key 代表的title組件的模板中(src/compontents/title/title.xml)有一個(gè)view 屬于 title-text 類,編譯時(shí),Labrador將自動(dòng)為其增加一個(gè)前綴 motto- ,所以編譯后這個(gè)view所屬的類為 title-text motto-title-text (可以查看 dist/pages/index/index.xml)。那么我們就可以在父組件的樣式代碼中使用 .motto-title-text 來(lái)重新定義子組件的樣式。
Labrador支持多層組件嵌套,在上述的實(shí)例中,index 包含子組件 list 和 title,list 包含子組件 title,所以在最終顯示時(shí),index 頁(yè)面上回顯示兩個(gè) title 組件。
詳細(xì)代碼請(qǐng)參閱 labrador init 命令生成的示例項(xiàng)目。
自動(dòng)化測(cè)試我們規(guī)定項(xiàng)目中所有后綴為 *.test.js 的文件為測(cè)試腳本文件。每一個(gè)測(cè)試腳本文件對(duì)應(yīng)一個(gè)待測(cè)試的JS模塊文件。例如 src/utils/util.js 和 src/utils/utils.test.js 。這樣,項(xiàng)目中所有模塊和其測(cè)試文件就全部存放在一起,方便查找和模塊劃分。這樣規(guī)劃主要是受到了GO語(yǔ)言的啟發(fā),也符合微信小程序一貫的目錄結(jié)構(gòu)風(fēng)格。
在編譯時(shí),加上 -t 參數(shù)即可自動(dòng)調(diào)用測(cè)試腳本完成項(xiàng)目測(cè)試,如果不加 -t 參數(shù),則所有測(cè)試腳本不會(huì)被編譯到 dist 目錄,所以不必?fù)?dān)心項(xiàng)目會(huì)肥胖。
普通JS模塊測(cè)試測(cè)試腳本中使用 export 語(yǔ)句導(dǎo)出多個(gè)名稱以 test* 開(kāi)頭的函數(shù),這些函數(shù)在運(yùn)行后會(huì)被逐個(gè)調(diào)用完成測(cè)試。如果test測(cè)試函數(shù)在運(yùn)行時(shí)拋出異常,則視為測(cè)試失敗,例如代碼:
// src/util.js // 普通項(xiàng)目模塊文件中的代碼片段,導(dǎo)出了一個(gè)通用的add函數(shù) export function add(a, b) { return a + b; }
// src/util.test.js // 測(cè)試腳本文件代碼片段 import assert from "assert"; //測(cè)試 util.add() 函數(shù) export function testAdd(exports) { assert(exports.add(1, 1) === 2); }
代碼中 testAdd 即為一個(gè)test測(cè)試函數(shù),專門(mén)用來(lái)測(cè)試 add() 函數(shù),在test函數(shù)執(zhí)行時(shí),會(huì)將目標(biāo)模塊作為參數(shù)傳進(jìn)來(lái),即會(huì)將 util.js 中的 exports 傳進(jìn)來(lái)。
自定義組件測(cè)試自定義組件的測(cè)試腳本中可以導(dǎo)出兩類測(cè)試函數(shù)。第三類和普通測(cè)試腳本一樣,也為 test* 函數(shù),但是參數(shù)不是 exports 而是運(yùn)行中的、實(shí)例化后的組件對(duì)象。那么我們就可以在test函數(shù)中調(diào)用組件的方法或則訪問(wèn)組件的props 和 data 屬性,來(lái)測(cè)試行為。另外,普通模塊測(cè)試腳本是啟動(dòng)后就開(kāi)始逐個(gè)運(yùn)行 test* 函數(shù),而組件測(cè)試腳本是當(dāng)組件 onReady 以后才會(huì)開(kāi)始測(cè)試。
自定義組件的第二類測(cè)試函數(shù)是以 on* 開(kāi)頭,和組件的生命周期函數(shù)名稱一模一樣,這一類測(cè)試函數(shù)不是等到組件 onReady 以后開(kāi)始運(yùn)行,而是當(dāng)組件生命周期函數(shù)運(yùn)行時(shí)被觸發(fā)。函數(shù)接收兩個(gè)參數(shù),第一個(gè)為組件的對(duì)象引用,第二個(gè)為run 函數(shù)。比如某個(gè)組件有一個(gè) onLoad 測(cè)試函數(shù),那么當(dāng)組件將要運(yùn)行 onLoad 生命周期函數(shù)時(shí),先觸發(fā) onLoad 測(cè)試函數(shù),在測(cè)試函數(shù)內(nèi)部調(diào)用 run() 函數(shù),繼續(xù)執(zhí)行組件的生命周期函數(shù),run() 函數(shù)返回的數(shù)據(jù)就是生命周期函數(shù)返回的數(shù)據(jù),如果返回的是Promise,則代表生命周期函數(shù)是一個(gè)異步函數(shù),測(cè)試函數(shù)也可以寫(xiě)為async 異步函數(shù),等待生命周期函數(shù)結(jié)束。這樣我們就可以獲取run()前后兩個(gè)狀態(tài)數(shù)據(jù),最后對(duì)比,來(lái)測(cè)試生命周期函數(shù)的運(yùn)行是否正確。
第三類測(cè)試函數(shù)與生命周期測(cè)試函數(shù)類似,是以 handle* 開(kāi)頭,用以測(cè)試事件處理函數(shù)是否正確,是在對(duì)應(yīng)事件發(fā)生時(shí)運(yùn)行測(cè)試。例如:
// src/components/counter/counter.test.js export function handleTap(c, run) { let num = c.data.num; run(); let step = c.data.num - num; if (step !== 1) { throw new Error("計(jì)數(shù)器點(diǎn)擊一次應(yīng)該自增1,但是自增了" + step); } }
生命周期測(cè)試函數(shù)和事件測(cè)試函數(shù)只會(huì)執(zhí)行一次,自動(dòng)化測(cè)試的結(jié)果將會(huì)輸出到Console控制臺(tái)。
項(xiàng)目配置文件labrador init 命令在初始化項(xiàng)目時(shí),會(huì)在項(xiàng)目根目錄中創(chuàng)建一個(gè) .labrador 項(xiàng)目配置文件,如果你的項(xiàng)目是使用 labrador-cli 0.3 版本創(chuàng)建的,可以手動(dòng)增加此文件。
配置文件為JSON格式,默認(rèn)配置為:
{ "npmMap":{ }, "uglify":{ "mangle": [], "compress": { "warnings": false } } }
npmMap 屬性為NPM包映射設(shè)置,例如 {"underscore":"lodash"} 配置,如果你的源碼中有require("underscore") 那么編譯后將成為 require("lodash")。這樣做是為了解決小程序的環(huán)境限制導(dǎo)致一些NPM包無(wú)法使用的問(wèn)題。比如我們的代碼必須依賴于包A,A又依賴于B,如果B和小程序不兼容,將導(dǎo)致A也無(wú)法使用。在這總情況下,我們可以Fork一份B,起名為C,將C中與小程序不兼容的代碼調(diào)整下,最后在項(xiàng)目配置文件中將B映射為C,那么在編譯后就會(huì)繞過(guò)B而加載C,從而解決這個(gè)問(wèn)題。
uglify 屬性為 UglifyJs2 的壓縮配置,在編譯時(shí)附加 -m 參數(shù)即可對(duì)項(xiàng)目中的所有文件進(jìn)行壓縮處理。
ChangeLog 2016-10-09labrador 0.3.0
重構(gòu)自定義組件支持綁定子組件數(shù)據(jù)和事件
2016-10-12labrador 0.4.0
增加自定義組件props機(jī)制
自動(dòng)化測(cè)試
UglifyJS壓縮集成
NPM包映射
增加.labrador項(xiàng)目配置文件
貢獻(xiàn)者鄭州脈沖軟件科技有限公司
梁興臣
開(kāi)源協(xié)議本項(xiàng)目依據(jù)MIT開(kāi)源協(xié)議發(fā)布,允許任何組織和個(gè)人免費(fèi)使用。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/87963.html
摘要:是一個(gè)專為微信小程序開(kāi)發(fā)的模塊化的前端開(kāi)發(fā)框架在微信小程序開(kāi)發(fā)三宗罪和解決方案一文中我向大家闡述了微信小程序開(kāi)發(fā)的三個(gè)弊端,并提供了框架來(lái)解決這些弊端。注意雖然我們采用了文件,但是由于微信小程序框架的限制,不能使用的層級(jí)選擇及嵌套語(yǔ)法。 Labrador 是一個(gè)專為微信小程序開(kāi)發(fā)的模塊化的前端開(kāi)發(fā)框架 在微信小程序開(kāi)發(fā)三宗罪和解決方案一文中我向大家闡述了微信小程序開(kāi)發(fā)的三個(gè)弊端,并提供...
awesome-github-wechat-weapp 是由OpenDigg整理并維護(hù)的微信小程序開(kāi)源項(xiàng)目庫(kù)集合。我們會(huì)定期同步上的項(xiàng)目到這里,也歡迎各位 UI組件開(kāi)發(fā)框架實(shí)用庫(kù)開(kāi)發(fā)工具服務(wù)端項(xiàng)目實(shí)例Demo UI組件 weui-wxss ★1873 - 同微信原生視覺(jué)體驗(yàn)一致的基礎(chǔ)樣式庫(kù)zanui-weapp ★794 - 好用易擴(kuò)展的小程序 UI 庫(kù)wx-charts ★449 - 微信小程...
閱讀 1938·2021-11-23 09:51
閱讀 1250·2019-08-30 15:55
閱讀 1623·2019-08-30 15:44
閱讀 768·2019-08-30 14:11
閱讀 1150·2019-08-30 14:10
閱讀 921·2019-08-30 13:52
閱讀 2636·2019-08-30 12:50
閱讀 621·2019-08-29 15:04