wepy.js借鑑了Vue的語法風格和功能特性,對官方提供的框架進行了封裝,更貼近於MVVM架構模式,讓開發者更加容易上手,增長開發效率。(髒數據處理--是否有標識、是否有響應)css
前端開發的對組件化開發應該都都很熟悉,咱們就講精華的部分:html
首先咱們須要輸入下面的命令:前端
npm install wepy-cli -g // 全局安裝或更新WePY命令行工具 wepy new myproject // 在開發目錄中生成Demo開發項目 cd myproject // 切換至項目目錄 npm install // 安裝依賴 wepy build --watch // 開啓實時編譯
完成上面的命令後,你會看到相似下面的目錄結構(部分文件夾是本人本身的項目業務須要,學習不須要理會):ios
目錄講解:git
--disgithub
文件夾是微信開發者工具指定的目錄(該目錄由WePY的build指令自動編譯生成,請不要直接修改該目錄下的文件)npm
--srcjson
代碼編寫的目錄(該目錄爲使用WePY後的開發目錄)axios
--components小程序
wepy組件目錄(組件不屬於完整頁面,僅供完整頁面或其餘組件引用)
--pages
wepy頁面目錄(屬於完整頁面)
--app.wpy
小程序邏輯、公共配置、公共樣式
--package.json
項目的package配置
wepy官方文檔有五個重要的提示,咱們要跟着規則作,不要給本身挖坑。
使用微信開發者工具
-->添加項目
,項目目錄
請選擇dist
目錄。
微信開發者工具
-->項目
-->關閉ES6轉ES5
。 重要:漏掉此項會運行報錯。
微信開發者工具
-->項目
-->關閉上傳代碼時樣式自動補全
。 重要:某些狀況下漏掉此項也會運行報錯。
微信開發者工具
-->項目
-->關閉代碼壓縮上傳
。 重要:開啓後,會致使真機computed, props.sync 等等屬性失效。(注:壓縮功能可以使用WePY提供的build指令代替,詳見後文相關介紹以及Demo項目根目錄中的wepy.config.js
和package.json
文件。)
本地項目根目錄運行wepy build --watch
,開啓實時編譯。(注:若是同時在微信開發者工具
-->設置
-->編輯器
中勾選了文件保存時自動編譯小程序
,將能夠實時預覽,很是方便。)
用於開發的編輯器,我的喜歡vs code。開發者能夠根據本身熟悉的編輯器(微信開發者工具
僅用於實時預覽和調試)。
1. 在 Code 裏先安裝 Vue 的語法高亮插件 Vetur
。
2. 打開任意 .wpy
文件。
3. 點擊右下角的選擇語言模式,默認爲純文本
。
4. 在彈出的窗口中選擇 .wpy 的配置文件關聯...
。
5. 在選擇要與 .wpy 關聯的語言模式
中選擇 Vue
。
wepy官方提供了一些代碼規範的規則,這裏我列出重要的幾條:
1.變量與方法儘可能使用駝峯式命名,而且注意避免使用$
開頭。
2.事件綁定語法使用優化語法代替。
* 原 bindtap="click"
替換爲 @tap="click"
,原catchtap="click"
替換爲@tap.stop="click"
。
* 原 capture-bind:tap="click"
替換爲 @tap.capture="click"
,原capture-catch:tap="click"
替換爲@tap.capture.stop="click"
。
3.事件傳參使用優化後語法代替。 原bindtap="click" data-index={{index}}
替換爲@tap="click({{index}})"
。
4.自定義組件命名應避開微信原生組件名稱以及功能標籤<repeat>
。 不可使用input、button、view、repeat
等微信小程序原生組件名稱命名自定義組件;另外也不要使用WePY框架定義的輔助標籤repeat
命名。
基於WePY的代碼:
export default class Catalog extends wepy.page //經過繼承自wepy.page的類建立頁面邏輯
methods //事件處理函數(集中保存在methods對象中)
components //支持組件化開發以下圖
注意:WePY中,在父組件template
模板部分插入駝峯式命名的子組件標籤時,不能將駝峯式命名轉換成短橫杆式命名(好比將childCom
轉換成child-com
),這與Vue中的習慣是不一致。
wepy基於原生進行優化:
(使用原生同時最多隻能發起5個請求,使用wepy後沒有了這個限制)
import wepy from 'wepy'; async onLoad() { await wepy.login(); this.userInfo = await wepy.getUserInfo(); }
一個.wpy
文件可分爲三大部分,各自對應於一個標籤:
<script></script>
標籤中的內容,又可分爲兩個部分: 邏輯部分,除了config對象以外的部分,對應於原生的.js
文件;
配置部分,即config對象,對應於原生的.json
文件。
結構部分,即<template></template>
模板部分,對應於原生的.wxml
文件。
樣式部分,即<style></style>
樣式部分,對應於原生的.wxss
文件。
其中,小程序入口文件app.wpy
不須要template
,因此編譯時會被忽略。.wpy
文件中的script
、template
、style
這三個標籤都支持lang
和src
屬性,lang
決定了其代碼編譯過程,src
決定是否外聯代碼,存在src
屬性且有效時,會忽略內聯代碼。
代碼以下
<style lang="less" src="page1.less"></style> <template lang="wxml" src="page1.wxml"></template> <script> // some code </script>
各標籤對應的lang
值以下表所示:
標籤 | lang默認值 | lang支持值 |
---|---|---|
style | css |
css 、less 、scss 、stylus |
template | wxml |
wxml 、xml 、pug(原jade) |
script | babel |
babel 、TypeScript |
下面具體對腳本進行講解,
小程序的入口是app.wpy
<script> import wepy from 'wepy'; export default class extends wepy.app { config = { "pages":[ "pages/index/index" ], "window":{ "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "WeChat", "navigationBarTextStyle": "black" } }; onLaunch() { console.log(this); } } </script> <style lang="less"> /** less **/ </style>
入口文件app.wpy
中所聲明的小程序實例繼承自wepy.app
類,包含一個config
屬性和其它全局屬性、方法、事件。其中config
屬性對應原生的app.json
文件,build編譯時會根據config
屬性自動生成app.json
文件,若是須要修改config
中的內容,請使用微信提供的相關API。
頁面page.wpy
<script> import wepy from 'wepy'; import Counter from '../components/counter'; export default class Page extends wepy.page { config = {}; components = {counter1: Counter}; data = {}; methods = {}; events = {}; onLoad() {}; // Other properties } </script> <template lang="wxml"> <view> </view> <counter1></counter1> </template> <style lang="less"> /** less **/ </style>
頁面文件page.wpy
中所聲明的頁面實例繼承自wepy.page
類,該類的主要屬性介紹以下:
屬性 | 說明 |
---|---|
config | 頁面配置對象,對應於原生的page.json 文件,相似於app.wpy 中的config |
components | 頁面組件列表對象,聲明頁面所引入的組件列表 |
data | 頁面渲染數據對象,存放可用於頁面模板綁定的渲染數據 |
methods | wxml事件處理函數對象,存放響應wxml中所捕獲到的事件的函數,如bindtap 、bindchange |
events | WePY組件事件處理函數對象,存放響應組件之間經過$broadcast 、$emit 、$invoke 所傳遞的事件的函數 |
其它 | 小程序頁面生命週期函數,如onLoad 、onReady 等,以及其它自定義的方法與屬性 |
組件com.wpy
<template lang="wxml"> <view> </view> </template> <script> import wepy from 'wepy'; export default class Com extends wepy.component { components = {}; data = {}; methods = {}; events = {}; // Other properties } </script> <style lang="less"> /** less **/ </style>
組件文件com.wpy
中所聲明的組件實例繼承自wepy.component
類,除了不須要config
配置以及頁面特有的一些生命週期函數以外,其屬性與頁面屬性大體相同。
經過上面的總結,咱們能夠知道,小程序被分紅三個實例:小程序實例App
、頁面實例Page
、組件實例Component
import wepy from 'wepy'; // 聲明一個App小程序實例 export default class MyAPP extends wepy.app { } // 聲明一個Page頁面實例 export default class IndexPage extends wepy.page { } // 聲明一個Component組件實例 export default class MyComponent extends wepy.component { }
在Page頁面實例中,能夠經過this.$parent
來訪問App實例。
Page頁面實際上繼承自Component組件,即Page也是組件。除擴展了頁面所特有的config
配置以及特有的頁面生命週期函數以外,其它屬性和方法與Component一致,所以這裏以Page頁面爲例進行介紹。
注意,對於WePY中的methods屬性,由於與Vue中的使用習慣不一致,很是容易形成誤解,這裏須要特別強調一下:WePY中的methods屬性只能聲明頁面wxml標籤的bind、catch事件,不能聲明自定義方法,這與Vue中的用法是不一致的。示例以下:
import wepy from 'wepy'; export default class MyComponent extends wepy.component { methods = { bindtap () { let rst = this.commonFunc(); // doSomething }, bindinput () { let rst = this.commonFunc(); // doSomething }, } //正確:普通自定義方法在methods對象外聲明,與methods平級 customFunction () { return 'sth.'; } }
須要特別注意的一點:當須要循環渲染WePY組件時(相似於經過wx:for
循環渲染原生的wxml標籤),必須使用WePY定義的輔助標籤<repeat>
,代碼以下:
<template> <!-- 注意,使用for屬性,而不是使用wx:for屬性 --> <repeat for="{{list}}" key="index" index="index" item="item"> <!-- 插入<script>腳本部分所聲明的child組件,同時傳入item --> <child :item="item"></child> </repeat> </template>
computed計算屬性、watcher監聽器跟VUE很類似。
// computed data = { a: 1 } // 計算屬性aPlus,在腳本中可經過this.aPlus來引用,在模板中可經過{{ aPlus }}來插值 computed = { aPlus () { return this.a + 1 } } // wathcer data = { num: 1 } // 監聽器函數名必須跟須要被監聽的data對象中的屬性num同名, // 其參數中的newValue爲屬性改變後的新值,oldValue爲改變前的舊值 watch = { num (newValue, oldValue) { console.log(`num value: ${oldValue} -> ${newValue}`) } } // 每當被監聽的屬性num改變一次,對應的同名監聽器函數num()就被自動調用執行一次 onLoad () { setInterval(() => { this.num++; this.$apply(); }, 1000) }
Props傳值:
props傳值在WePY中屬於父子組件之間傳值的一種機制,包括靜態傳值與動態傳值。
在props對象中聲明須要傳遞的值,靜態傳值與動態傳值的聲明略有不一樣,具體可參看下面的示例代碼。
靜態傳值
靜態傳值爲父組件向子組件傳遞常量數據,所以只能傳遞String字符串類型。
在父組件template
模板部分的組件標籤中,使用子組件props對象中所聲明的屬性名做爲其屬性名來接收父組件傳遞的值。
<child title="mytitle"></child> // child.wpy props = { title: String }; onLoad () { console.log(this.title); // mytitle }
動態傳值
動態傳值是指父組件向子組件傳遞動態數據內容,父子組件數據徹底獨立互不干擾。但能夠經過使用.sync
修飾符來達到父組件數據綁定至子組件的效果,也能夠經過設置子組件props的twoWay: true
來達到子組件數據綁定至父組件的效果。那若是既使用.sync
修飾符,同時子組件props
中添加的twoWay: true
時,就能夠實現數據的雙向綁定了。
注意:下文示例中的twoWay
爲true
時,表示子組件向父組件單向動態傳值,而twoWay
爲false
(默認值,可不寫)時,則表示子組件不向父組件傳值。這是與Vue不一致的地方,而這裏之因此仍然使用twoWay
,只是爲了儘量保持與Vue在標識符命名上的一致性。
在父組件template
模板部分所插入的子組件標籤中,使用:prop
屬性(等價於Vue中的v-bind:prop
屬性)來進行動態傳值。
// parent.wpy <child :title="parentTitle" :syncTitle.sync="parentTitle" :twoWayTitle="parentTitle"></child> data = { parentTitle: 'p-title' }; // child.wpy props = { // 靜態傳值 title: String, // 父向子單向動態傳值 syncTitle: { type: String, default: 'null' }, twoWayTitle: { type: Number, default: 'nothing', twoWay: true } }; onLoad () { console.log(this.title); // p-title console.log(this.syncTitle); // p-title console.log(this.twoWayTitle); // p-title this.title = 'c-title'; console.log(this.$parent.parentTitle); // p-title. this.twoWayTitle = 'two-way-title'; this.$apply(); console.log(this.$parent.parentTitle); // two-way-title. --- twoWay爲true時,子組件props中的屬性值改變時,會同時改變父組件對應的值 this.$parent.parentTitle = 'p-title-changed'; this.$parent.$apply(); console.log(this.title); // 'c-title'; console.log(this.syncTitle); // 'p-title-changed' --- 有.sync修飾符的props屬性值,當在父組件中改變時,會同時改變子組件對應的值。 }
組件之間的通訊:
wepy.component
基類提供$broadcast
、$emit
、$invoke
三個方法用於組件之間的通訊和交互,如:
this.$emit('some-event', 1, 2, 3, 4);
import wepy from 'wepy' export default class Com extends wepy.component { components = {}; data = {}; methods = {}; // events對象中所聲明的函數爲用於監聽組件之間的通訊與交互事件的事件處理函數 events = { 'some-event': (p1, p2, p3, $event) => { console.log(`${this.$name} receive ${$event.name} from ${$event.source.$name}`); } }; // Other properties }
$broadcast
事件是由父組件發起,全部子組件都會收到此廣播事件,除非事件被手動取消。
$emit
與$broadcast
正好相反,事件發起組件的全部祖先組件會依次接收到$emit
事件。
$invoke
是一個頁面或組件對另外一個組件中的方法的直接調用,經過傳入組件路徑找到相應的組件,而後再調用其方法。
組件自定義事件處理:
能夠經過使用.user
修飾符爲自定義組件綁定事件,如:@customEvent.user="myFn"
其中,@
表示事件修飾符,customEvent
表示事件名稱,.user
表示事件後綴。
目前總共有三種事件後綴:
.default
: 綁定小程序冒泡型事件,如bindtap
,.default
後綴可省略不寫;
.stop
: 綁定小程序捕獲型事件,如catchtap
;
.user
: 綁定用戶自定義組件事件,經過$emit
觸發。注意,若是用了自定義事件,則events中對應的監聽函數不會再執行。
// index.wpy <template> <child @childFn.user="parentFn"></child> </template> <script> import wepy from 'wepy' import Child from '../components/child' export default class Index extends wepy.page { components = { child: Child } methods = { parentFn (num, evt) { console.log('parent received emit event, number is: ' + num) } } } </script> // child.wpy <template> <view @tap="tap">Click me</view> </template> <script> import wepy from 'wepy' export default class Child extends wepy.component { methods = { tap () { console.log('child is clicked') this.$emit('childFn', 100) } } } </script>
固然,全部人寫的總結都是基於本身的理解的,所以,我的以爲不管學什麼技術,當本身有必定能力能夠閱讀官方文檔後,最好本身把官方的文檔都看一遍,只有這樣本身的該門技術纔有深刻的理解。
官方文檔地址:https://tencent.github.io/wepy/document.html#/?id=api
若是你閱讀到這裏了,說明你是個有追求的人,本人額外附送兩個連接