WePY項(xiàng)目的創(chuàng)建與使用
1.0全局安裝或更新WePY命令行工具
npm install wepy-cli -g
1.2 在開發(fā)目錄中生成Demo開發(fā)項(xiàng)目
wepy new myproject
# 1.7.0之后的版本使用 wepy init standard myproject 初始化項(xiàng)目,使用 wepy list 查看項(xiàng)目模板
切換至項(xiàng)目目錄
cd myproject
安裝依賴
npm install
開啟實(shí)時(shí)編譯
wepy build --watch
添加項(xiàng)目
1.7.0 之后的版本init新生成的代碼包會(huì)在根目錄包含project.config.json文件蚊丐,之前生成的代碼包可能不存在project.config.json文件。 檢查根目錄是否存在該文件仁锯。
如果存在匙姜,使用微信開發(fā)者工具-->添加項(xiàng)目,項(xiàng)目目錄請(qǐng)選擇項(xiàng)目根目錄即可根據(jù)配置完成項(xiàng)目信息自動(dòng)配置番宁。
如果不存在元莫,建議手動(dòng)創(chuàng)建該文件后再添加項(xiàng)目。project.config.json文件內(nèi)容如下:
{
"description": "project description",
"setting": {
"urlCheck": true,
"es6": false,
"postcss": false,
"minified": false
},
"compileType": "miniprogram",
"appid": "touristappid",
"projectname": "Project name",
"miniprogramRoot": "./dist"
}
.wpy文件說(shuō)明
- 腳本部分蝶押,即<script></script>標(biāo)簽中的內(nèi)容踱蠢,又可分為兩個(gè)部分:邏輯部分,除了config對(duì)象之外的部分棋电,對(duì)應(yīng)于原生的.js文件茎截;配置部分,即config對(duì)象赶盔,對(duì)應(yīng)于原生的.json文件企锌。
- 結(jié)構(gòu)部分,即<template></template>模板部分于未,對(duì)應(yīng)于原生的.wxml文件撕攒。
- 樣式部分,即<style></style>樣式部分烘浦,對(duì)應(yīng)于原生的.wxss文件抖坪。
普通組件引用
當(dāng)頁(yè)面需要引入組件或組件需要引入子組件時(shí),必須在.wpy文件的<script>腳本部分先import組件文件谎倔,然后在components對(duì)象中給組件聲明唯一的組件ID柳击,接著在<template>模板部分中添加以components對(duì)象中所聲明的組件ID進(jìn)行命名的自定義標(biāo)簽以插入組件。如:
<template>
<!-- 以`<script>`腳本部分中所聲明的組件ID為名命名自定義標(biāo)簽片习,從而在`<template>`模板部分中插入組件 -->
<child></child>
</template>
<script>
import wepy from 'wepy';
//引入組件文件
import Child from '../components/child';
export default class Index extends wepy.page {
//聲明組件捌肴,分配組件id為child
components = {
child: Child
};
}
</script>
需要注意的是,WePY中的組件都是靜態(tài)組件藕咏,是以組件ID作為唯一標(biāo)識(shí)的状知,每一個(gè)ID都對(duì)應(yīng)一個(gè)組件實(shí)例,當(dāng)頁(yè)面引入兩個(gè)相同ID的組件時(shí)孽查,這兩個(gè)組件共用同一個(gè)實(shí)例與數(shù)據(jù)饥悴,當(dāng)其中一個(gè)組件數(shù)據(jù)變化時(shí),另外一個(gè)也會(huì)一起變化盲再。
如果需要避免這個(gè)問(wèn)題西设,則需要分配多個(gè)組件ID和實(shí)例。代碼如下:
<template>
<view class="child1">
<child></child>
</view>
<view class="child2">
<anotherchild></anotherchild>
</view>
</template>
<script>
import wepy from 'wepy';
import Child from '../components/child';
export default class Index extends wepy.page {
components = {
//為兩個(gè)相同組件的不同實(shí)例分配不同的組件ID答朋,從而避免數(shù)據(jù)同步變化的問(wèn)題
child: Child,
anotherchild: Child
};
}
</script>
注意:WePY中贷揽,在父組件template模板部分插入駝峰式命名的子組件標(biāo)簽時(shí),不能將駝峰式命名轉(zhuǎn)換成短橫桿式命名(比如將childCom轉(zhuǎn)換成child-com)梦碗,這與Vue中的習(xí)慣是不一致禽绪。
組件的循環(huán)渲染
當(dāng)需要循環(huán)渲染W(wǎng)ePY組件時(shí)(類似于通過(guò)wx:for循環(huán)渲染原生的wxml標(biāo)簽),必須使用WePY定義的輔助標(biāo)簽<repeat>洪规,代碼如下:
<template>
<!-- 注意印屁,使用for屬性,而不是使用wx:for屬性 -->
<repeat for="{{list}}" key="index" index="index" item="item">
<!-- 插入<script>腳本部分所聲明的child組件斩例,同時(shí)傳入item -->
<child :item="item"></child>
</repeat>
</template>
<script>
import wepy from 'wepy';
// 引入child組件文件
import Child from '../components/child';
export default class Index extends wepy.page {
components = {
// 聲明頁(yè)面中要使用到的Child組件的ID為child
child: Child
}
data = {
list: [{id: 1, title: 'title1'}, {id: 2, title: 'title2'}]
}
}
</script>
computed 計(jì)算屬性
computed計(jì)算屬性雄人,是一個(gè)有返回值的函數(shù),可直接被當(dāng)作綁定數(shù)據(jù)來(lái)使用念赶。因此類似于data屬性础钠,代碼中可通過(guò)this.計(jì)算屬性名來(lái)引用,模板中也可通過(guò){{ 計(jì)算屬性名 }}來(lái)綁定數(shù)據(jù)晶乔。
data = {
a: 1
}
// 計(jì)算屬性aPlus珍坊,在腳本中可通過(guò)this.aPlus來(lái)引用,在模板中可通過(guò){{ aPlus }}來(lái)插值
computed = {
aPlus () {
return this.a + 1
}
}
watcher 監(jiān)聽器
通過(guò)監(jiān)聽器watcher能夠監(jiān)聽到任何屬性的更新正罢。監(jiān)聽器在watch對(duì)象中聲明阵漏,類型為函數(shù),函數(shù)名與需要被監(jiān)聽的data對(duì)象中的屬性同名翻具,每當(dāng)被監(jiān)聽的屬性改變一次履怯,監(jiān)聽器函數(shù)就會(huì)被自動(dòng)調(diào)用執(zhí)行一次。
data = {
num: 1
}
// 監(jiān)聽器函數(shù)名必須跟需要被監(jiān)聽的data對(duì)象中的屬性num同名裆泳,
// 其參數(shù)中的newValue為屬性改變后的新值叹洲,oldValue為改變前的舊值
watch = {
num (newValue, oldValue) {
console.log(`num value: ${oldValue} -> ${newValue}`)
}
}
// 每當(dāng)被監(jiān)聽的屬性num改變一次,對(duì)應(yīng)的同名監(jiān)聽器函數(shù)num()就被自動(dòng)調(diào)用執(zhí)行一次
onLoad () {
setInterval(() => {
this.num++;
this.$apply();
}, 1000)
}
props 傳值
靜態(tài)傳值
靜態(tài)傳值為父組件向子組件傳遞常量數(shù)據(jù)工禾,因此只能傳遞String字符串類型
<child title="mytitle"></child>
// child.wpy
props = {
title: String
};
onLoad () {
console.log(this.title); // mytitle
}
靜態(tài)傳值
動(dòng)態(tài)傳值是指父組件向子組件傳遞動(dòng)態(tài)數(shù)據(jù)內(nèi)容运提,父子組件數(shù)據(jù)完全獨(dú)立互不干擾蝗柔。但可以通過(guò)使用.sync修飾符來(lái)達(dá)到父組件數(shù)據(jù)綁定至子組件的效果,也可以通過(guò)設(shè)置子組件props的twoWay: true來(lái)達(dá)到子組件數(shù)據(jù)綁定至父組件的效果民泵。那如果既使用.sync修飾符癣丧,同時(shí)子組件props中添加的twoWay: true時(shí),就可以實(shí)現(xiàn)數(shù)據(jù)的雙向綁定了
注意:下文示例中的twoWay為true時(shí)栈妆,表示子組件向父組件單向動(dòng)態(tài)傳值胁编,而twoWay為false(默認(rèn)值,可不寫)時(shí)鳞尔,則表示子組件不向父組件傳值嬉橙。這是與Vue不一致的地方,而這里之所以仍然使用twoWay寥假,只是為了盡可能保持與Vue在標(biāo)識(shí)符命名上的一致性
在父組件template模板部分所插入的子組件標(biāo)簽中市框,使用:prop屬性(等價(jià)于Vue中的v-bind:prop屬性)來(lái)進(jìn)行動(dòng)態(tài)傳值。
<child :title="parentTitle" :syncTitle.sync="parentTitle" :twoWayTitle="parentTitle"></child>
data = {
parentTitle: 'p-title'
};
// child.wpy
props = {
// 靜態(tài)傳值
title: String,
// 父向子單向動(dòng)態(tài)傳值
syncTitle: {
type: String,
default: 'null'
},
twoWayTitle: {
type: String,
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時(shí)昧旨,子組件props中的屬性值改變時(shí)拾给,會(huì)同時(shí)改變父組件對(duì)應(yīng)的值
this.$parent.parentTitle = 'p-title-changed';
this.$parent.$apply();
console.log(this.title); // 'c-title';
console.log(this.syncTitle); // 'p-title-changed' --- 有.sync修飾符的props屬性值,當(dāng)在父組件中改變時(shí)兔沃,會(huì)同時(shí)改變子組件對(duì)應(yīng)的值蒋得。
}
組件通信與交互
wepy.component基類提供broadcast、invoke三個(gè)方法用于組件之間的通信和交互,如:
this.$emit('some-event', 1, 2, 3, 4);
用于監(jiān)聽組件之間的通信與交互事件的事件處理函數(shù)需要寫在組件和頁(yè)面的events對(duì)象中额衙,如:
import wepy from 'wepy'
export default class Com extends wepy.component {
components = {};
data = {};
methods = {};
// events對(duì)象中所聲明的函數(shù)為用于監(jiān)聽組件之間的通信與交互事件的事件處理函數(shù)
events = {
'some-event': (p1, p2, p3, $event) => {
console.log(`${this.$name} receive ${$event.name} from ${$event.source.$name}`);
}
};
// Other properties
}
$broadcast
$broadcast事件是由父組件發(fā)起,所有子組件都會(huì)收到此廣播事件怕吴,除非事件被手動(dòng)取消.
$invoke
$invoke是一個(gè)頁(yè)面或組件對(duì)另一個(gè)組件中的方法的直接調(diào)用窍侧,通過(guò)傳入組件路徑找到相應(yīng)的組件,然后再調(diào)用其方法转绷。
比如伟件,想在頁(yè)面Page_Index中調(diào)用組件ComA的某個(gè)方法:
this.$invoke('ComA', 'someMethod', 'someArgs');
如果想在組件ComA中調(diào)用組件ComG的某個(gè)方法:
this.$invoke('./../ComB/ComG', 'someMethod', 'someArgs');
組件自定義事件處理函數(shù)
可以通過(guò)使用.user修飾符為自定義組件綁定事件,如:@customEvent.user="myFn"
其中议经,@表示事件修飾符斧账,customEvent 表示事件名稱,.user表示事件后綴煞肾。
目前總共有三種事件后綴:
.default: 綁定小程序冒泡型事件咧织,如bindtap,.default后綴可省略不寫籍救;
.stop: 綁定小程序捕獲型事件习绢,如catchtap;
.user: 綁定用戶自定義組件事件蝙昙,通過(guò)$emit觸發(fā)闪萄。注意梧却,如果用了自定義事件,則events中對(duì)應(yīng)的監(jiān)聽函數(shù)不會(huì)再執(zhí)行桃煎。
<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>
數(shù)據(jù)綁定
原生小程序的數(shù)據(jù)綁定方式
this.setData({title: 'this is title'});
WePY數(shù)據(jù)綁定方式
WePY使用臟數(shù)據(jù)檢查對(duì)setData進(jìn)行封裝篮幢,在函數(shù)運(yùn)行周期結(jié)束時(shí)執(zhí)行臟數(shù)據(jù)檢查大刊,一來(lái)可以不用關(guān)心頁(yè)面多次setData是否會(huì)有性能上的問(wèn)題为迈,二來(lái)可以更加簡(jiǎn)潔去修改數(shù)據(jù)實(shí)現(xiàn)綁定,不用重復(fù)去寫setData方法缺菌。代碼如下:
this.title = 'this is title';
需注意的是葫辐,在異步函數(shù)中更新數(shù)據(jù)的時(shí)候,必須手動(dòng)調(diào)用$apply方法伴郁,才會(huì)觸發(fā)臟數(shù)據(jù)檢查流程的運(yùn)行耿战。如:
setTimeout(() => {
this.title = 'this is title';
this.$apply();
}, 3000);