微信小程式也已出來有一段時間了,最近寫了幾款微信小程式項目,今天來說說感受。
首先開發一款微信小程式,最主要的就是針對于公司來營運的,因為,在申請appid(微信小程式ID号)時候,需要填寫相關的公司認證資訊如,營業執照等
再次就是用一個未曾開通過公衆号的QQ号或微信号來注冊一個微信小程式号。
最後,下載下傳微信小程式開發工具。
由于這裡,我們更多的關注如何去開發一些app,而不是科譜微信小程式,故在此不在過多的解釋,詳細的說明,可以去官網幫助文檔。
首先,我們拿自己的項目在一步一步的說明并開發吧,下面是一個微信app的截圖
在看到上圖,小夥伴們大緻有一個了解,這個是調試工具中的,一些效果沒有在真機上好看。
由于在開發中,本以為畫面不是很流利,實際上完全出乎我的意料,動畫效果很流暢,可以與ios,andriod app相媲美,以後有時間講講開發其它app的相關例子。
在介紹這個文章前,假設使用者都已看過微信小程式的相關文檔。
這個項目基本上是按照微信原有的檔案結構來的,并沒有額外的去添加特别多的檔案結構,因為微信小程式規定,項目檔案大小不能超過1M,要求我們盡可能的壓縮小程式代碼或其它圖檔檔案等,下面是微信app檔案結構整體截圖
1.app.js 主要是全局公共的js方法聲明及調用所在的檔案
2.app.json 是小程式整個的配置檔案,是以有的頁面都在要此注冊,不然不允許通路(如下圖所示)
3.app.wxss 是小程式全局的css檔案,公共css寫在此最好不過的了
4.pages下是對應着所有頁面,每個頁面,可以添加四種類型的檔案,.json,.wxss,.wxml,.js (如下圖所示)
5.utils 是我們公共的js存放的地方,因為微信小程式要求,每個js檔案裡的方法不可以直接引用或調用,必須要用 module.exports方法導出,這樣pages 下的.js檔案才可以調用到我們在此寫的js方法。這點特别要注意
1)app.json頁面配置及注冊:
2)pages頁面結構:
下面我們開始詳細的講解每個頁面
一、首頁
首頁分為四個檔案組成,如下圖所示,具體的頁面功能,上面已說過。
下面來看下,index.wxml效果
最上面的“來運吧”标題,在index.json檔案下定義的,每個檔案都可以用不同的.json來定義,當然代碼也可以動态改變它
很簡單吧,标題就這麼簡單的出現了。
1)接下來看看橫向滾動的banner,
index.wxml這樣來描述
那麼swiper是什麼東東呢?微信小程式幫助文檔這樣說明的 swiper滑塊視圖容器
屬性名 | 類型 | 預設值 | 說明 |
---|---|---|---|
indicator-dots | Boolean | false | 是否顯示面闆訓示點 |
autoplay | Boolean | false | 是否自動切換 |
current | Number | 目前所在頁面的 index | |
interval | Number | 5000 | 自動切換時間間隔 |
duration | Number | 500 | 滑動動畫時長 |
circular | Boolean | false | 是否采用銜接滑動 |
bindchange | EventHandle | current 改變時會觸發 change 事件,event.detail = {current: current} |
注意:其中隻可放置
<swiper-item/>
元件,其他節點會被自動删除。
swiper-item
僅可放置在
<swiper/>
元件中,寬高自動設定為100%。
1 示例代碼:
2
3 <swiper indicator-dots="{{indicatorDots}}"
4 autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
5 <block wx:for="{{imgUrls}}">
6 <swiper-item>
7 <image src="{{item}}" class="slide-image" width="355" height="150"/>
8 </swiper-item>
9 </block>
10 </swiper>
11 <button bindtap="changeIndicatorDots"> indicator-dots </button>
12 <button bindtap="changeAutoplay"> autoplay </button>
13 <slider bindchange="intervalChange" show-value min="500" max="2000"/> interval
14 <slider bindchange="durationChange" show-value min="1000" max="10000"/> duration
15 Page({
16 data: {
17 imgUrls: [
18 \'http://img02.tooopen.com/images/20150928/tooopen_sy_143912755726.jpg\',
19 \'http://img06.tooopen.com/images/20160818/tooopen_sy_175866434296.jpg\',
20 \'http://img06.tooopen.com/images/20160818/tooopen_sy_175833047715.jpg\'
21 ],
22 indicatorDots: false,
23 autoplay: false,
24 interval: 5000,
25 duration: 1000
26 },
27 changeIndicatorDots: function(e) {
28 this.setData({
29 indicatorDots: !this.data.indicatorDots
30 })
31 },
32 changeAutoplay: function(e) {
33 this.setData({
34 autoplay: !this.data.autoplay
35 })
36 },
37 intervalChange: function(e) {
38 this.setData({
39 interval: e.detail.value
40 })
41 },
42 durationChange: function(e) {
43 this.setData({
44 duration: e.detail.value
45 })
46 }
47 })
View Code
看了上面的官方文檔,就可以清楚的知道,這個就是我們類似在寫html裡用到的banner滑動插件一樣,拿過來就可以使用,多麼的友善。
我們的項目中同樣用參數綁定的方式,輸出的相關參數
參數定義在index.js pages({...})方法中
為什麼要綁定參數?為什麼不直接寫入參數呢?好處太多,圖檔我們不可能寫死,從伺服器請求圖檔,同時可以友善的控制我們的相關參數來改變swiper的行為等。
至于參數綁定,官網說的也很清楚,這裡不在解釋。
2)城市選擇及切換
這塊看起來很簡單,實際上很麻煩,如果對動畫不熟悉的朋友,可以會苦惱一番的。
上面的動畫很流暢,可能是因為抓屏工具不太好,這點大可不用關心。
我們點選中間的“交換圓”的時候,”出發城市“與”到達城市“互相交換,他們不是立即變化,而是中間有一個"位移"效果,同時,那個“交換的圓”也要旋轉180度。
這樣體驗感立馬"高上大"。呵呵,不是嗎?下面我們詳細的來實作它。
我們首先來溫習下,官網動畫相關的文檔說明
wx.createAnimation(OBJECT)
建立一個動畫執行個體animation。調用執行個體的方法來描述動畫。最後通過動畫執行個體的
export
方法導出動畫資料傳遞給元件的
animation
屬性。
注意:
export
方法每次調用後會清掉之前的動畫操作
OBJECT參數說明:
參數 | 類型 | 必填 | 說明 |
---|---|---|---|
duration | Integer | 否 | 動畫持續時間,機關ms,預設值 400 |
timingFunction | String | 否 | 定義動畫的效果,預設值"linear",有效值:"linear","ease","ease-in","ease-in-out","ease-out","step-start","step-end" |
delay | Integer | 否 | 動畫延遲時間,機關 ms,預設值 0 |
transformOrigin | String | 否 | 設定transform-origin,預設為"50% 50% 0" |
var animation = wx.createAnimation({
transformOrigin: "50% 50%",
duration: 1000,
timingFunction: "ease",
delay: 0
})
animation
動畫執行個體可以調用以下方法來描述動畫,調用結束後會傳回自身,支援鍊式調用的寫法。
樣式:
方法 | 參數 | 說明 |
---|---|---|
opacity | value | 透明度,參數範圍 0~1 |
backgroundColor | color | 顔色值 |
width | length | 長度值,如果傳入 Number 則預設使用 px,可傳入其他自定義機關的長度值 |
height | length | 長度值,如果傳入 Number 則預設使用 px,可傳入其他自定義機關的長度值 |
top | length | 長度值,如果傳入 Number 則預設使用 px,可傳入其他自定義機關的長度值 |
left | length | 長度值,如果傳入 Number 則預設使用 px,可傳入其他自定義機關的長度值 |
bottom | length | 長度值,如果傳入 Number 則預設使用 px,可傳入其他自定義機關的長度值 |
right | length | 長度值,如果傳入 Number 則預設使用 px,可傳入其他自定義機關的長度值 |
旋轉:
方法 | 參數 | 說明 |
---|---|---|
rotate | deg | deg的範圍-180~180,從原點順時針旋轉一個deg角度 |
rotateX | deg | deg的範圍-180~180,在X軸旋轉一個deg角度 |
rotateY | deg | deg的範圍-180~180,在Y軸旋轉一個deg角度 |
rotateZ | deg | deg的範圍-180~180,在Z軸旋轉一個deg角度 |
rotate3d | (x,y,z,deg) | 同transform-function rotate3d |
縮放:
方法 | 參數 | 說明 |
---|---|---|
scale | sx,[sy] | 一個參數時,表示在X軸、Y軸同時縮放sx倍數;兩個參數時表示在X軸縮放sx倍數,在Y軸縮放sy倍數 |
scaleX | sx | 在X軸縮放sx倍數 |
scaleY | sy | 在Y軸縮放sy倍數 |
scaleZ | sz | 在Z軸縮放sy倍數 |
scale3d | (sx,sy,sz) | 在X軸縮放sx倍數,在Y軸縮放sy倍數,在Z軸縮放sz倍數 |
偏移:
方法 | 參數 | 說明 |
---|---|---|
translate | tx,[ty] | 一個參數時,表示在X軸偏移tx,機關px;兩個參數時,表示在X軸偏移tx,在Y軸偏移ty,機關px。 |
translateX | tx | 在X軸偏移tx,機關px |
translateY | ty | 在Y軸偏移tx,機關px |
translateZ | tz | 在Z軸偏移tx,機關px |
translate3d | (tx,ty,tz) | 在X軸偏移tx,在Y軸偏移ty,在Z軸偏移tz,機關px |
傾斜:
方法 | 參數 | 說明 |
---|---|---|
skew | ax,[ay] | 參數範圍-180~180;一個參數時,Y軸坐标不變,X軸坐标延順時針傾斜ax度;兩個參數時,分别在X軸傾斜ax度,在Y軸傾斜ay度 |
skewX | ax | 參數範圍-180~180;Y軸坐标不變,X軸坐标延順時針傾斜ax度 |
skewY | ay | 參數範圍-180~180;X軸坐标不變,Y軸坐标延順時針傾斜ay度 |
矩陣變形:
方法 | 參數 | 說明 |
---|---|---|
matrix | (a,b,c,d,tx,ty) | 同transform-function matrix |
matrix3d | 同transform-function matrix3d |
動畫隊列
調用動畫操作方法後要調用
step()
來表示一組動畫完成,可以在一組動畫中調用任意多個動畫方法,一組動畫中的所有動畫會同時開始,一組動畫完成後才會進行下一組動畫。step 可以傳入一個跟
wx.createAnimation()
一樣的配置參數用于指定目前組動畫的配置。
示例:
1 <view animation="{{animationData}}" style="background:red;height:100rpx;width:100rpx"></view>
2 Page({
3 data: {
4 animationData: {}
5 },
6 onShow: function(){
7 var animation = wx.createAnimation({
8 duration: 1000,
9 timingFunction: \'ease\',
10 })
11
12 this.animation = animation
13
14 animation.scale(2,2).rotate(45).step()
15
16 this.setData({
17 animationData:animation.export()
18 })
19
20 setTimeout(function() {
21 animation.translate(30).step()
22 this.setData({
23 animationData:animation.export()
24 })
25 }.bind(this), 1000)
26 },
27 rotateAndScale: function () {
28 // 旋轉同時放大
29 this.animation.rotate(45).scale(2, 2).step()
30 this.setData({
31 animationData: this.animation.export()
32 })
33 },
34 rotateThenScale: function () {
35 // 先旋轉後放大
36 this.animation.rotate(45).step()
37 this.animation.scale(2, 2).step()
38 this.setData({
39 animationData: this.animation.export()
40 })
41 },
42 rotateAndScaleThenTranslate: function () {
43 // 先旋轉同時放大,然後平移
44 this.animation.rotate(45).scale(2, 2).step()
45 this.animation.translate(100, 100).step({ duration: 1000 })
46 this.setData({
47 animationData: this.animation.export()
48 })
49 }
50 })
View Code
這裡我并不想一個一個的介紹官方的動畫說明文檔,因為寫的很清楚了,而是我想說下一些關于動畫的機制。
不管是位移,縮放,旋轉,可能都會涉及到三個軸,那就是x,y,z,軸,這三個軸大緻這樣的如下圖
x軸是水準的,y軸在垂直方向上,而z軸,是"指向我們的方向"的一個軸,這點必須清楚,不然動畫的很多東西,你就沒辦法了解了。
好了,我們再來回過頭來看看官網的幾個動畫方法。
旋轉:1.rotate(deg),2.rotateX(deg),3.rotateY(deg),4.rotateZ(deg),5.rotate3d(x,y,z,deg)
1.rotate表示以原點在順時針旋轉一個度數deg範圍在-180~180
假如我們要讓一個圖檔,順時針旋轉90度,以原點為中心
可能剛開始圖檔這樣排列的如下圖
旋轉後,由圖A順時針旋轉90度至圖B,它是在一個X與Y的平面上與Z軸成垂直90度來順時針旋轉的。
由上述可以看出,圖檔的左上角坐标是(x:0,y:0,z:0);而我們要旋轉一個圖檔,一般不希望在左上角做為旋轉點,最多的情況下,就是以圖檔的中心點為旋轉點(x:50%,y:50%,z:0) z坐标是指向我們的坐标,就像css裡的z-index一樣,我們應該把它設為0,即使你設為任何一個數字,你的視角差也感不到任何不同,因為,圖檔的z軸是垂直我們視線的,故一般設定為0。
就像下面如圖所示,可能是我們希望的旋轉效果:
不好意思呀,用QQ繪圖工具繪制,可能效果不太好,但是大緻的表達了這種示意圖,
上圖描述了,由圖檔A由中心點,旋轉90度後的效果,那麼如何初始化,讓圖檔的原點由(x:0,y:0,z:0)更換為(x:50%,y:50%,z:0)呢?回過頭來看下官網教程的wx.createAnimation(OBJECT)方法
其中屬性transformOrigin 已說明,預設為圖檔的中心點,可能是作者的初衷也這麼認為的,旋轉應該以”元素“的中心點來操作應用比較多點,這是合情可理的
至此,我們旋轉一個圖檔得了到大緻的思路。其它的以X軸,Y軸,Z軸旋轉與些類似,不在累述。
animation樣式:
如何讓一個元素從一個位置從A點移到B點呢?可能通過上述的樣式屬性在改變”元素“的top bottom left right 達到效果,
當然也可以通過其它動畫方法來改變,如偏移 translate(x,y,z)。
通過top bottom left right 樣式屬性來實作動畫,前提是,這個”元素“一定是相對定位或者絕對定位的,不然是不出效果的,這和寫css裡的position:absolute相同的原理。
如果要讓一個元素或圖檔從A點平移至B點,就像下圖是以示
假如初始A坐标為(x:10px,y:0px,z:0px)移至B點坐标(x:120px,y:0px,z:0px),那樣我們隻需改變元素的left或者right即可,
同理,可以用bottom,top來改變y坐标。
好了,到此為止,我們項目的所需動畫可能要用到的效果都基本上有了思路。那麼下面我們就來實作它。
首先,我們在”出發城市\'與"到達城市"以及"旋轉圖檔"定義如下:
對應的wxml界面:
然後,我們為注意到在index.wxss(如下圖)裡給了絕對定位,目的就是想用left或right來動畫交換城市
這裡注意一點,animationsSourceCity初始化的時候,css裡用了left, 動畫時,必須用它的left來"位移",而不是right
不然會看不到效果,這點,在玩css3動畫的時候,就遇到過。同理,下面的animationsDestCity隻能用right來"位移"。
為什麼有的朋友會想在初始化的時候用left可動畫的時候想right的呢?可能考慮到元素的準确的定位原因,畢竟,精确的定位不是一件很容易的事情。 為什麼這麼說呢?因為考慮到app在其它屏上顯示。
從上面的截圖可以看到,現實中的問題,中間這塊,寬與高是用了px,就是說,我們不希望中間這個旋轉按扭自适應不同的手機屏,而希望他能夠保持不變。這個時候,如果我們僅僅用left來平移"出發城市"至"到達城市"的坐标處,可能不管你用px還是rpx或其它機關,都達不到精确定位了(為什麼?)。
這個時候,換個角度來思考下,我們不需要讓它精确的位移至“到達城市”,為什麼這麼說呢?在”出發城市“移至”到達城市“前的一點很短的時間内,我們讓它在0s交換城市(也就是複位但文本内容已交換),因為0s互換城市文本内容,估計沒有任何人可以發覺到的。這就需要一個“恰當的時間”。
好了,我們來看看代碼:
定義三個動畫:
1 animation1 = wx.createAnimation({
2 duration: 300,
3 timingFunction: \'linear\',
4 transformOrigin: "50%,50%"
5 })
6
7 this.setData({
8 animationData: animation1.export()
9 })
10
11 animation2 = wx.createAnimation({
12 duration: 300,
13 timingFunction: \'linear\'
14 })
15
16 this.setData({
17 animationSourceCity: animation2.export()
18 })
19
20 animation3 = wx.createAnimation({
21 duration: 300,
22 timingFunction: \'linear\'
23 })
24
25 this.setData({
26 animationDestCity: animation3.export()
27 })
animation1是旋轉圖檔的動畫定義(初始化,具體的參數官網說的很清楚,不多說)。
animation2與animation3分别是”出發城市“與”到達城市“定義
下面我們先來說說animation2,animation3
animation2要完成的是從left ”出發城市“水準移動至”到達城市“坐标
我們看看點選旋轉圖檔時事件:
1 animation2.left(\'600rpx\').step()
2 this.setData({
3 animationSourceCity: animation2.export()
4 })
5
6 setTimeout(function(){
7 animation2.left(\'30rpx\').step({duration: 0, transformOrigin: "50%,50%",timingFunction: \'linear\'})
8 that.setData({
9 animationSourceCity: animation2.export()
10 })
11 },285)
12
13 animation3.right(\'580rpx\').step()
14 this.setData({
15 animationDestCity: animation3.export()
16 })
17
18 setTimeout(function(){
19 animation3.right(\'30rpx\').step({duration: 0, transformOrigin: "50%,50%",timingFunction: \'linear\'})
20 that.setData({
21 animationDestCity: animation3.export()
22 })
23 },285)
我們來分析下上面的代碼:
在初始化的時候,設定了動畫完成時間duration:300ms,緊接着,點選圖檔開始水準移動600rpx
animation2.left(\'600rpx\').step()
this.setData({
animationSourceCity: animation2.export()
})
這個時候600rpx隻是粗略的計算,并不是真正的精确定位,原因上面我們解釋很清楚了,移動600rpx所需時間是300ms,緊接着,如果這樣的結束的話,很可能位置會錯位,是以我們要寫一個"特殊的動畫"setTimeout(function(){
animation2.left(\'30rpx\').step({duration: 0, transformOrigin: "50%,50%",timingFunction: \'linear\'})
that.setData({
animationSourceCity: animation2.export()
})
},285)
這個動畫表示,在285ms後,将要在0s時間完成"複位",在0s時間,估計沒有人會查覺得到,呵呵,複位的好處,太多了,如果不複位,意味,我們的元素真的交換了,那樣事件也給交換了,給我們帶來了
太多的麻煩,
而複位,可以讓我們僅僅交換了”城市文本“而不是所有。哈哈~開心,隻是以定義285ms,是給一個很短的機會,讓人看不到複位的執行,畢竟上面的300ms的水準動畫還沒有執行完嘛
而真正的換交在下面的一句話
var tempSourceCity=this.data.sourceCity
var tempDestCity=this.data.destCity
this.setData({
sourceCity:tempDestCity,
destCity:tempSourceCity
})
同理,right也一樣來現實,這裡不多說了,有興趣的可以嘗試下。
下面我們來說說,交換按扭圖檔的旋轉動畫
如果在點選事件rotate裡我們這樣寫入
animation1.rotate(180).step()
this.setData({
animationData: animation1.export()
})
恩,看起來不錯,我們嘗試的時候,第一旋轉了,然後第二次,第三次。。。并沒有旋轉。啊呀,愁人的事情又來了。我會不盡的報怨,小程式呀,你的bug又來了。
其實你看官網給出的例子也是如此,旋轉一下,再也不旋轉了,除非你重新整理下頁面。
報怨歸報怨,納悶歸納悶,問題還要是解決的。
這是不是我們自己的問題呢?一萬個為什麼。。。
不是!還記得,在css3動畫的時候,确實也這樣,我來畫圖解釋下為什麼!
圖一、旋轉前:(注意A點的位置)
圖二、旋轉180度後(注意A的位置)
圖二是點選旋轉圖檔後,自己處于180度狀态,此時,再次點選此旋轉圖檔,意味着,讓它再次從0度旋轉到180度,可是我們的代碼是
animation1.rotate(180).step()
這行代碼表示,讓它在300ms(初始化建立的時間)内旋轉到180度,而是此時已處理180度啦,你點選當然它不會再旋轉了。它會不停報怨”我已在180度了呀,你還想怎麼樣?!...“
是以,此時,我們能不能直接再讓旋轉360度,那麼它不就相對于180度後的狀态又轉了180度了嗎?可是看看官網,旋轉的範圍是-180~180度,既使沒有這麼範圍限制,那麼我們也會折騰死,不是嗎?每次都要180*2,180*3...,表示不服!
我想隻要問題找到了,其實都很簡單了,此時估計都有朋友想到了,就是直接讓它歸0度嘛,這個歸0度的動畫時間必須要短,不然就要讓人看到了一個”倒旋轉的過程“,哇,那多麼的難看呀,OK,動畫嘛,上面我們都有先例,0s複位到0度,你眼神再好,也查覺不到,嘿嘿。。。
完整的旋轉代碼如下:
1 animation1.rotate(180).step()
2
3 this.setData({
4 animationData: animation1.export()
5 })
6
7 var that=this;
8 setTimeout(function(){
9 animation1.rotate(0).step({duration: 0, transformOrigin: "50%,50%",timingFunction: \'linear\'})
10 that.setData({
11 animationData: animation1.export()
12 })
13 },300)
意思是,在點選時候,在300ms内旋轉180度,同時在300ms後執行一個在0s時間完成新的動畫讓它複位至0度,下次點選時,它就再次可以旋轉了!
animation1.rotate(0).step({duration: 0, transformOrigin: "50%,50%",timingFunction: \'linear\'})
//歸0度”複位“
上面的思想并不難,就是有時候不好發現,或者說,沒接觸過動畫的朋友,一時半時找不出問題所在,寫在此,盡可能的讓大家少走彎路。
好了,這部分的動畫就全部完成了,下面我們還有首頁的上下不間斷滾動、類似蘋果手機ios app的滑動、删除效果,以及https api(基于asp.net mvc)的搭建、互動等等,期待着我們一個一個的解決呢,這些我準備将在後面的文章陸陸續續的寫出,敬請關注,謝謝。
未完待續。。。
參考資料
微信小程式, https://mp.weixin.qq.com/debug/wxadoc/dev/framework/MINA.html?t=20161230