現(xiàn)學(xué)現(xiàn)賣微信小程序開發(fā)(一)
現(xiàn)學(xué)現(xiàn)賣微信小程序開發(fā)(二)
現(xiàn)學(xué)現(xiàn)賣微信小程序開發(fā)(三):引入Rx腥刹,為小程序插上翅膀
一個Todo應(yīng)用的小程序版
好的把敞,那么下一步我們就先照貓畫虎刻获,新建一個todos文件夾,然后一套四樣同名文件準備齊全
![新建todos目錄和相關(guān)文件](https://user-gold-cdn.xitu.io/2017/1/3/6265399ec2c5e5f673c0ab55494e4a95.png)
先在app.json中報個到,在pages中加入 "pages/todos/todos"
域醇。接下來把首頁 index.js
中的導(dǎo)航改為 ../todos/todos
//事件處理函數(shù)
bindViewTap: function() {
wx.navigateTo({
url: '../todos/todos'
})
},
然后呢,我們簡單的先寫一個界面蓉媳,其實什么都沒有譬挚,就是一個view。把 todos.wxml
改成下面的模樣:
<!--todos.wxml-->
<view class="container todo-list">
</view>
然后把導(dǎo)航欄標(biāo)題設(shè)置一下酪呻,叫 Awesome Todos
吧减宣,把 todos.json
改成下面的樣子:
{
"navigationBarTitleText": "Awesome Todos"
}
樣式呢,也非常簡單粗暴的來一個吧:
.todo-list {
display: block;
padding: 40rpx;
width: 100vw;
margin: 0 auto;
}
快速搭建一個Web API
好的玩荠,下面我們要寫關(guān)鍵的 todos.js
了漆腌。在寫之前,我們需要一個服務(wù)器提供數(shù)據(jù)阶冈,這里介紹一個可以非趁颇颍快速便捷的搭建一個仿真Web API的利器:json-server。 使用 npm i -g json-server
安裝女坑,然后隨便挑一個目錄建一個todos-data.json 文件:
{
"todos": [
{
"id": 1,
"desc": "have breakfast",
"completed": false
},
{
"id": 2,
"desc": "have lunch",
"completed": false
},
{
"id": 3,
"desc": "take a break",
"completed": false
},
{
"id": 4,
"desc": "having fun",
"completed": false
},
{
"id": 5,
"desc": "新的服務(wù)器版本不錯",
"completed": true
}
]
}
這個時候填具,你的Web API就差一步之遙了,現(xiàn)在在命令行窗口敲入 json-server ./todos-data.json
就大功告成了。
![json-server服務(wù)啟動了](https://user-gold-cdn.xitu.io/2017/1/3/1ff78b7c0d97d1fa4adee580d8e5504e.png)
你可以打開瀏覽器輸入 http://localhost:3000/todos
看看是否返回的是我們的數(shù)據(jù)劳景。這個Web API是完全RESTful的誉简,也就是說
- 查詢所有待辦事項:以GET方法訪問
http://localhost:3000/todos
- 查詢單個待辦事項:以GET方法訪問
http://localhost:3000/todos/id
,比如id是1盟广,那么訪問http://localhost:3000/todos/1
- 更新某個待辦事項:以PUT方法訪問
http://localhost:3000/todos/id
- 刪除某個待辦事項:以DELETE方法訪問
http://localhost:3000/todos/id
- 增加一個待辦事項:以POST方法訪問
http://localhost:3000/todos
回到正題闷串,開始Todo的開發(fā)
我們一開始的 todos.js
是這個樣子的:
const URL = 'http://localhost:3000/todos'
let pageParams = {
data: { todos: [], desc: '' }
}
pageParams.onLoad = function () {
const that = this
wx.request({
url: URL,
data: JSON.stringify({}),
header: { 'content-type': 'application/json' },
method: 'GET',
success: res => {
console.log(res.data)
that.setData({
todos: res.data
})
},
fail: () => console.error('something is wrong'),
complete: () => console.log('todos loaded')
})
}
Page(pageParams)
這段代碼非常簡單,創(chuàng)建一個pageParams對象并給本地數(shù)據(jù)初始化筋量。然后定義onLoad生命周期函數(shù)烹吵,利用 wx.request
創(chuàng)建一個 HTTP GET 請求取得返回的數(shù)據(jù),然后用setData去更新本地數(shù)據(jù)桨武。注意一點 const that = this
是一個常用的避免 this
的context出現(xiàn)切換時出現(xiàn)問題的小技巧年叮。再有就是我們無法直接寫入data,只能使用setData方法來進行更新玻募。
那么我們看看是否成功吧只损,點擊左側(cè)的調(diào)試,然后點首頁的頭像進入我們的todo頁面七咧,當(dāng)然現(xiàn)在界面上啥也沒有跃惫,但Console中還是有料滴。
![Console中可以看到我們的Web API返回的結(jié)果](https://user-gold-cdn.xitu.io/2017/1/3/5154acf46facd7efbec3f0d84013f82e.png)
既然API調(diào)通了艾栋,我們就來讓結(jié)果顯示到頁面上吧爆存,首先改造頁面如下。
<!--todos.wxml-->
<view class="container todo-list">
<block wx:for="{{todos}}" wx:for-item="todo" wx:key="todo.id">
<view class="todo-item">
<text class="desc">{{todo.desc}}</text>
</view>
</block>
</view>
這段代碼中蝗砾,view
是個視圖容器先较,感覺可以把它想象成HTML中的div。微信小程序中除了 view
之外悼粮,目前還提供了 scroll-view
和 swiper
兩種容器闲勺,顧名思義 scroll-view
是用于可滾動的場景,而 swiper
是用于可以手指滑動切換內(nèi)容的場景扣猫。
在組件上使用 wx:for
綁定一個數(shù)組菜循,即可使用數(shù)組中各項的數(shù)據(jù)重復(fù)渲染該組件。wx:for-item
意思是設(shè)定數(shù)組當(dāng)前元素的變量名申尤。wx:key
設(shè)置列表中項目的唯一的標(biāo)識符癌幕。注意提供wx:key
可以提升重新渲染時的性能,所以盡量提供昧穿。
block
是一個挺怪的設(shè)計勺远,它不是一個可視化的元素,感覺純粹為提供數(shù)據(jù)綁定而準備时鸵,在數(shù)據(jù)綁定時胶逢,以 block
來組織比較復(fù)雜的組件組合。所以block
這一段的意思就是對于數(shù)組todos中的每一個todo,重復(fù)渲染下面這段
<view class="todo-item">
<text class="desc">{{todo.desc}}</text>
</view>
當(dāng)然我們也需要拓展一下css宪塔,哦,不對囊拜,是wxss某筐。
.todo-list {
display: block;
padding: 40rpx;
width: 100vw;
margin: 0 auto;
}
.todo-item {
display: flex;
flex-direction: row;
flex-basis: 1;
justify-content: space-around;
align-items: stretch;
width: 80 vw;
padding: 20rpx;
border-bottom: 1rpx solid #ededed;
}
.desc {
vertical-align: middle;
flex-grow: 1;
}
現(xiàn)在看一下效果,列表成功顯示了冠跷。
![todos列表](https://user-gold-cdn.xitu.io/2017/1/3/9e0e34b57fda86438453440ee5f0715a.png)
事件的處理
現(xiàn)在我們給Todos添加兩個功能吧:Toggle(切換完成狀態(tài))和Remove(刪除該事項)南誊。這樣的話,需要給todo的描述之前加一個完成狀態(tài)的復(fù)選框以及一個在todo的描述之后的刪除按鈕蜜托。我們沒有使用微信提供的 checkbox
抄囚,而是用 icon
組件和 wx:if
來做處理,目的也是多展示一些特性橄务。
<!--todos.wxml-->
<view class="container todo-list">
<block wx:for="{{todos}}" wx:for-item="todo" wx:key="todo.id">
<view class="todo-item">
<icon bindtap="toggleTodo" data-todo="{{todo}}" class="icon" type="success" wx:if="{{todo.completed}}"></icon>
<icon bindtap="toggleTodo" data-todo="{{todo}}" class="icon" type="success_circle" wx:if="{{!todo.completed}}"></icon>
<text bindtap="toggleTodo" data-todo="{{todo}}" class="desc">{{todo.desc}}</text>
<icon bindtap="removeTodo" data-todo="{{todo}}" class="remove" type="clear"></icon>
</view>
</block>
</view>
上面的模版中幔托,我們看到多了一些新面孔:
-
wx:if
:這個比較好理解,就是條件渲染蜂挪,在todo已完成的狀態(tài)下顯示一個icon重挑,未完成狀態(tài)下顯示另一個icon。 -
bindtap
:這個是什么呢棠涮?它是微信小程序提供的綁定事件的機制谬哀,其綁定表達式為:bind+事件="事件處理函數(shù)"。我們上面的例子中的bindtap="toggleTodo"
就是對于tap(觸碰后馬上離開)事件處理是一個在Page中定義的叫toggleTodo
的函數(shù)严肪。 -
data-todo
:很多時候我們需要在事件傳遞時攜帶一些數(shù)據(jù)過去史煎,比如Toggle這個功能,我們需要在事件處理函數(shù)中知道是哪個todo要切換完成狀態(tài)驳糯。data-todo
就是定義要傳輸?shù)臄?shù)據(jù)用的篇梭,data表明是要在 事件中傳輸?shù)臄?shù)據(jù),而后面的todo表明這個數(shù)據(jù)在dataset中的key酝枢,通過這個key我們可以在Page中使用event.target.dataset.todo
得到這個數(shù)據(jù)很洋。這也意味著我們可以通過多個key傳遞多個數(shù)據(jù)。
值的注意的一點是除了 bindXXX
這種綁定事件的形式外隧枫,還有一種形式是 catchXXX
喉磁,它們的區(qū)別是 bind
事件綁定不會阻止冒泡事件向上冒泡,catch
事件綁定可以阻止冒泡事件向上冒泡官脓。什么是冒泡呢协怒?事件會繼續(xù)向上(父組件或父節(jié)點)傳遞就是冒泡,反之就是非冒泡卑笨。
在微信小程序中孕暇,冒泡的事件如下表列出的,其他如沒有特殊的聲明都是非冒泡事件
事件 | 觸發(fā)條件 |
---|---|
touchstart | 手指觸摸動作開始 |
touchmove | 手指觸摸后移動 |
touchcancel | 手指觸摸動作被打斷,如來電提醒妖滔,彈窗 |
touchend | 手指觸摸動作結(jié)束 |
tap | 手指觸摸后馬上離開 |
longtap | 手指觸摸后隧哮,超過350ms再離開 |
對于這些冒泡事件來說,如果我們要阻止其冒泡的行為座舍,可以使用 catchXXX
來綁定事件沮翔。
const URL = 'http://localhost:3000/todos'
let pageParams = {
data: { todos: [], desc: '' }
}
pageParams.onLoad = function () {
const that = this
wx.request({
url: URL,
data: JSON.stringify({}),
header: { 'content-type': 'application/json' },
method: 'GET',
success: res => {
console.log(res.data)
that.setData({
todos: res.data
})
},
fail: () => console.error('something is wrong'),
complete: () => console.log('get req completed')
})
}
pageParams.toggleTodo = function (event) {
const that = this
const selectedTodo = event.target.dataset.todo
const url = `${URL}/${selectedTodo.id}`
const updatedTodo = Object.assign({}, selectedTodo, {completed: !selectedTodo.completed})
wx.request({
url: url,
data: JSON.stringify(updatedTodo),
header: { 'content-type': 'application/json' },
method: 'PUT',
success: res => {
console.log(res.data)
that.setData({
todos: that.data.todos.map(todo => {
if(todo.id === updatedTodo.id){
return updatedTodo
}
return todo
})
})
},
fail: () => console.error('something is wrong'),
complete: () => console.log('toggle req completed')
})
}
pageParams.removeTodo = function (event) {
const that = this
const selectedTodo = event.target.dataset.todo
const url = `${URL}/${selectedTodo.id}`;
wx.request({
url: url,
data: JSON.stringify(selectedTodo),
header: { 'content-type': 'application/json' },
method: 'DELETE',
success: res => {
console.log(res.data)
that.setData({
todos: that.data.todos.filter(todo => todo.id !== selectedTodo.id)
})
},
fail: () => console.error('something is wrong'),
complete: () => console.log('delete req completed')
})
}
Page(pageParams)
接下來的事情就變的很簡單,我們在 todos.js
中增加兩個處理函數(shù)用于處理toggle和remove曲秉,事件處理函數(shù)有一個參數(shù)就是event采蚀。處理邏輯還是先提交HTTP請求處理服務(wù)器端數(shù)據(jù),處理成功后再處理本地內(nèi)存數(shù)據(jù)承二。
當(dāng)然 wxss
再更新一下:
.todo-list {
display: block;
padding: 40rpx;
width: 100vw;
margin: 0 auto;
}
.todo-item {
display: flex;
flex-direction: row;
flex-basis: 1;
justify-content: space-around;
align-items: stretch;
width: 80 vw;
padding: 20rpx;
border-bottom: 1rpx solid #ededed;
}
.icon {
vertical-align: middle;
}
.remove {
float: right;
align-self: flex-end;
}
.desc {
vertical-align: middle;
flex-grow: 1;
}
現(xiàn)在的效果是這樣滴
![可以工作的todo榆鼠,當(dāng)然還沒有新增todo的功能](https://user-gold-cdn.xitu.io/2017/1/3/5d961686ed425c5eedc97ec9f4770eff.png)
新增Todo亥鸠、過濾器妆够、優(yōu)化代碼結(jié)構(gòu)、引入Rx等話題我們后面繼續(xù)负蚊,這次就先到這里责静。