前段時間學習了關於微信小程序的開發,光說不練假把式,因此就打算本身手擼一個微信小程序,而網上電商類小程序太多了,因此就選擇了旅遊攻略類小程序來練手。這是我第一次寫小程序和第一次寫文章,不足之處請多包涵,謝謝。下面我會分享我在寫小程序的時候遇到的問題和得到的經驗,但願能給你帶來幫助,也歡迎大佬指正。最後,我要感謝我在寫小程序的時候給我幫助的老師和同窗,還有百度上全部給過我幫助的有名的無名的做者。個人廢話說完了,先上項目效果圖。php
微信小程序自帶的 [頂部導航欄](https://developers.weixin.qq.com/miniprogram/dev/reference/configuration/page.html) 知足不了實際的需求因此就本身寫了一個組件,頂部導航欄要想使用 [自定義組件](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/)(連接中詳細介紹了關於自定義組件的使用方法)必須把app.json中window屬性設置爲:
"window": { "navigationBarTextStyle": "black",//導航欄標題顏色,僅支持 black / white "navigationStyle": "custom" //導航欄樣式,僅支持如下值:default 默認樣式custom 自定義導航欄,只保留右上角膠囊按鈕 }
wxmlcss
<view class='nav-wrap' style='height: {{height*2 + 20}}px; background-color:{{navbarData.backgroundColor}};opacity:{{navbarData.opacity}}'> <view style="width:100%;height:100%;"> <!--城市名--> <navigator url="/pages/destination/destination" hover-class="none"> <view class="nav-city" style='margin-top:{{height*2 + 20-36}}px;' wx:if='{{navbarData.showMain}}'> <text>{{navbarData.cityName}}</text> <view class="downtips"></view> </view> </navigator> <navigator url="/pages/search/search" hover-class="none"> <!--搜索框--> <view class="section" style='top:{{height*2 + 20-34}}px;' wx:if='{{navbarData.showMain}}'> // 這裏的搜索框不是一個input組件,只是一個view可供點擊而後跳到搜索頁 <view class='search_icon'> <icon type='search' size='14px'></icon> </view> <view class='placehold'>搜索目的地/景點/攻略</view> </view> </navigator> </view> <!-- 標題 --> <view wx:if="{{navbarData.title!=''}}" class='nav-title' style='line-height: {{height*2 + 44}}px;'> {{navbarData.title}} </view> <!-- 返回上一級按鈕 和 返回主頁按鈕--> <block wx:if="{{navbarData.showCapsule===1}}"> <view class='nav'> <view class='nav_back' bindtap="_navback"> <image src='/images/back.png'></image> </view> <view class="line"></view> <view class='nav_home' bindtap="_backhome"> <image src='/images/home.png'></image> </view> </view> </block> </view>
組件中的元素均可以經過當前頁面傳入組件的數據控制顯示與否html
js就寫了兩個 路由跳轉 函數,微信小程序官方文檔有很詳細的介紹,這裏就很少贅述了。git
初進小程序,會跳到登陸受權頁面,由於微信小程序再也不支持wx.getUserInfo 接口直接彈出受權框的開發方式,因此這裏直接使用 button 組件,並將 open-type 指定爲 getUserInfo 類型,獲取用戶基本信息。github
<button style='background:green; color:#fff' open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">贊成受權</button
小程序在受權容許訪問用戶信息後,又會彈出位置受權框用來獲取用戶當前所在地,來渲染主頁面的數據。調用小程序給的接口 wx.getLocation(須要用戶受權) 來獲取經緯度,再把獲取到的經緯度利用 百度地圖開放平臺 提供給小程序使用的API來獲取當前城市的名字,並將城市名字放入緩存,好讓主頁面獲取到。正則表達式
"permission": { "scope.userLocation": { "desc": "小程序將獲取你的位置信息" } }
登陸界面jsjson
// miniprogram/pages/login/login.js const app = getApp() Page({ /** * 頁面的初始數據 */ data: { show: false, // 頂部導航欄數據 navbarData: { showCapsule: 0, //是否顯示左上角圖標 1表示顯示 0表示不顯示 title: '馬蜂窩旅遊', //導航欄 中間的標題 backgroundColor: '#354a98', //'#354a98' opacity: 1, showMain: 0, }, // 此頁面 頁面內容距最頂部的距離 height: app.globalData.height * 2 + 20, }, bindGetUserInfo(res) { let that =this let info = res; if (info.detail.userInfo) { wx.login({ success: function (res) { that.getPlaceData() } }) } }, /** * 生命週期函數--監聽頁面加載 */ onLoad: function (options) { let that = this; //頁面加載時判斷用戶是否受權過,若是受權過直接跳到主頁面,沒有就顯示受權按鈕 wx.getUserInfo({ success: function (res) { wx.switchTab({ url: '/pages/main/index' }) }, fail(err) { that.setData({ show: true }) } }) }, // 獲取城市名字 getCityName(location) { return new Promise((resolve, reject) => { let that = this; var e = { coord_type: "gcj02", output: "json", pois: 0, ak: '',//放上本身的ak密鑰 密鑰申請見上文百度地圖開方平臺連接 sn: "", timestamp: "" }; e.location = location; wx.request({ url: "https://api.map.baidu.com/geocoder/v2/", data: e, header: { "content-type": "application/json" }, method: "GET", success: function (t) { let currentCity = t.data.result.addressComponent.city; if (currentCity.slice(currentCity.length - 1) == "市") { currentCity = currentCity.slice(0, currentCity.length - 1) } wx.setStorageSync('currentCity', currentCity) resolve(currentCity) //經過城市名字 請求城市數據 } }) }) }, // 獲取經緯度 getLocation() { return new Promise((resolve, reject) => { wx.getLocation({ type: 'wgs84', success(res) { const latitude = res.latitude const longitude = res.longitude let location = latitude + ',' + longitude console.log(location) resolve(location) //獲取城市名字 } }) }) }, getPlaceData() { // 獲取地理信息 let that = this this.getLocation().then((val) => { return that.getCityName(val) }).then(()=>{ wx.switchTab({ url: '/pages/main/index' }) }) } })
寫小程序的時候我不知道主頁面有兩種樣式,等我知道的時候已經寫了很多東西了,因此就沒有寫成組件了,代碼看起來就很冗長,這是個人失誤(MangFu),但願你在想好寫什麼小程序的時候,必定要把小程序的頁面結構想好來不然就會和我同樣,要改的話就要改不少地方。小程序
進入主頁是,頁面會先獲取到緩存中的城市名字,再經過城市名字去請求數據,再根據請求到的數據中的ishot屬性,若是ishot屬性爲真,就顯示熱門城市的頁面 ,反之就顯示普通城市的頁面微信小程序
‘個人’頁面中主要是爲了顯示用戶收藏的內容api
由於種種緣由(lan)頁面中的大半數據沒有放到Easy Mock裏,馬蜂窩原本就以大數據出名,數據ttm多了。
這個頁面的佈局分爲三部分,頭部搜索框用絕對定位定死、左部各大洲的列表用絕對定位定死,右部各大洲的國家是一個微信小程序自帶的組件scroll-view
wxml
<!-- pages/destination/destination.wxml --> <nav-bar navbar-data='{{navbarData}}'></nav-bar> <view class="destination" style='top: {{height}}px'> <!--頭部--> <view class="des_head"> <navigator url="/pages/search/search" hover-class="none"> <view class="des_search"> <view class="des_search_icon"> <icon type='search' size='30rpx' color="#000000"></icon> </view> 搜索目的地 </view> </navigator> </view> <!--左部--> <view class="des_continents"> <view class="des_continent {{curIndex===index?'add':''}}}" wx:for="{{continents}}" wx:for-item="continent" wx:key='{{index}}' data-index='{{index}}' bindtap="switch_des"> <view class='des_continent_name {{curIndex===index?"on":""}}}'>{{continent.name}}</view> </view> </view> <!--右部--> <scroll-view class='des_cities' scroll-y> <block wx:if="{{curIndex==0}}"> <view class="des_cities_content" wx:for="{{continents[curIndex].cities}}" wx:key="{{index}}" wx:for-item="des_city"> <view class="des_cities_title">{{des_city.title}}</view> <view class="des_city" wx:for="{{des_city.city}}" wx:key="{{index}}" bindtap='goMain' data-city_name="{{item.city_name}}"> {{item.city_name}} </view> </view> </block> <block wx:else> <view class="des_area" wx:for="{{continents[curIndex].cities}}" wx:key="{{index}}" wx:for-item="des_city" bindtap='goMain' data-city_name="{{des_city.city_name}}"> <view class="des_img"> <image src="{{des_city.img}}" /> </view> <view class="des_city_name">{{des_city.city_name}}</view> </view> </block> </scroll-view> </view>
js
// pages/destination/destination.js const app = getApp() Page({ /** * 頁面的初始數據 */ data: { <!--頂部導航欄數據--> navbarData: { showCapsule: 1, //是否顯示左上角圖標 1表示顯示 0表示不顯示 title: '目的地切換', //導航欄 中間的標題 backgroundColor: '#fff',//背景顏色 showMain: 0 ///顯示搜索框 }, height: app.globalData.height * 2 + 20, continents: [], curIndex: 0 //當前洲的索引值 }, <!--左部各大洲的點擊事件,來改變右邊顯示的內容,而且改變自身樣式--> switch_des(e) { let curIndex = e.currentTarget.dataset.index; this.setData({ curIndex, }) }, <!--右部國家/城市的點擊事件,獲取點擊的元素上綁定的國家/城市的名字,放入緩存,並跳轉到主頁--> goMain(e){ const city_name = e.currentTarget.dataset.city_name; wx.setStorageSync('currentCity', city_name) wx.switchTab({ url: '/pages/main/index' }) }, /** * 生命週期函數--監聽頁面加載 */ onLoad: function (options) { let that = this <!--請求數據--> wx.request({ url: 'https://www.easy-mock.com/mock/5ca457f04767c3737055c868/example/mafengwo/continents', success:(res)=>{ that.setData({ continents: res.data.continents }) } }) } }
以主頁爲例
其實全部的切換列表功能都差很少,實現方法就是在被點擊元素上設置一個 自定義屬性 ( data-* ) 爲惟一索引值,用 bind-tap 綁定一個點擊事件,經過點擊事件獲取這個惟一索引值,再經過惟一索引值去數據源找到想要的內容,而後經過數據控制頁面上顯示的內容,在data數據源中設置一個數據如mcurIndex,表示當前選擇的元素,用來區別於其餘元素,顯示不一樣的樣式。
wxml
<view class='menu_list'> <!-- {{mcurIndex===index?"on":""}} 表示若是自身的索引值爲當前選擇的元素索引值時,添加一個類名‘on’--> <view class='list {{mcurIndex===index?"on":""}}' wx:for="{{placeData.allGuide}}" data-mindex="{{index}}" bindtap='selected_menu' wx:key="{{index}}"> {{item.name}} </view> </view>
js
selected_menu(e) { this.setData({ mcurIndex: e.target.dataset.mindex, size: 0, showend: false }) <!--調用本身寫的函數來獲取要顯示的內容的數據--> this.bitiyan() }
以主頁爲例
這裏的實現方法是使用 scroll-view 組件,組件中有個 bindscroll 屬性,會在頁面滾動時觸發bindscroll 綁定的事件還會給函數傳遞一個對象event,其中的scrollTop屬性是咱們須要的,根據scrollTop知道頁面滾動了多少,而後動態設置要傳給組件的數據裏的 opacity 屬性。
<scroll-view class="main_scro" scroll-y bindscroll="scroll" bindscrolltolower="bindDownLoad"> </scroll-view>
js
scroll(e) { let opacity = 0; if (e.detail.scrollTop < 60) { opacity = (e.detail.scrollTop / 100).toFixed(1); } else { opacity = 1; } this.data.navbarData.opacity = opacity; if (e.detail.scrollTop<10){ this.setData({ shownav: false }) }else{ this.setData({ shownav: true }) } this.setData({ navbarData: this.data.navbarData, }) }
以主頁爲例
這裏的實現方法在 scroll-view 組件中加 bindscrolltolower 屬性,會在頁面觸底時觸發bindscrolltolower 綁定的事件。
<scroll-view class="main_scro" scroll-y bindscroll="scroll" bindscrolltolower="bindDownLoad"> </scroll-view>
bindDownLoad() { let part = 0; //已經顯示的數據長度 let all = 0; //總的數據長度 <!--判斷當前城市是否爲熱門城市--> if (this.data.ishot) { // 待完善 由於效果相同就沒寫了 } else { if (this.data.mcurIndex === 0) { part = this.data.cur_view.length * 2; all = this.data.placeData.allGuide[this.data.mcurIndex].content[this.data.hlcurIndex].content.length; } else { part = this.data.cur_view.length; all = this.data.placeData.allGuide[this.data.mcurIndex].content.length; } if (part < all) { wx.showLoading({ title: '正在加載' }) setTimeout(() => { this.bitiyan(this.data.placeData) wx.hideLoading() }, 1000) } else { <!--當全部數據都加載完了,就顯示end 圖標--> this.setData({ showend: true }) } } }
收藏功能我是寫在一個組件裏,原本是想和頂部組件同樣,供多個頁面使用,後來由於寫的頁面中就只有一個有用到這個組件,這裏就不單獨說明這個組件了,並且這個組件和頂部組件基本差很少。
收藏功能的實現,當點擊某一個景點時會觸發點擊事件,相信你看了列表切換功能,已經知道了 bind-tap 的使用方法,這裏就不重複了。這裏就是獲取元素上的自定義屬性,經過路由傳參的方法傳給詳情頁,詳情頁根據傳遞過來的數據,去數據源裏獲取相應的數據,再將數據傳遞給組件,當點擊詳情頁上的收藏按鈕時,會觸發綁定的事件,而後會更新緩存中的collectData收藏夾數據。‘個人’頁面會顯示收藏夾中的數據
詳情頁js
<!--生命週期函數,監聽頁面加載--> onLoad: function(options) { <!--options中包含了傳遞過來的參數--> let name = options.name; this.getinfo(name) }, <!--經過名字獲取想要的數據--> getinfo(name){ <!--先獲取緩存中已經存在的收藏夾數據,若是不存在就將collectData設爲空數組--> let collectData = wx.getStorageSync('collectData') || []; if (collectData.filter(e => e.name === name).length > 0) { this.setData({ placeData: collectData.filter(e => e.name === name)[0] }) } else { let placeData = wx.getStorageSync('placeData') let view = placeData.allGuide[0].content.map(e => e.content) let newView = [] for (let i = 0; i < view.length; i++) { newView.push(...view[i]) } this.setData({ placeData: newView.find(e => e.name === name) }) } this.setBottom(); }, <!--設置要傳遞給bottom組件的數據--> setBottom(){ this.data.bottomData.placeData = this.data.placeData; let bottomData = this.data.bottomData; this.setData({ bottomData }) }
bottom組件的js
// components/bottom/bottom.js const app = getApp() Component({ /** * 組件的屬性列表 */ properties: { bottomData: { // 由父頁面傳遞的數據,變量名字自命名 type: Object, value: {}, observer: function (newVal, oldVal) { } } }, /** * 組件的初始數據 */ data: { height: '' }, attached: function () { // 獲取是不是經過分享進入的小程序 this.setData({ share: app.globalData.share }) // 定義導航欄的高度 方便對齊 this.setData({ height: app.globalData.height }) }, /** * 組件的方法列表 */ methods: { <!--點擊收藏按鈕觸發的事件--> collected(){ <!--將isCollect(是否收藏過),collectors(收藏人數)從數據中解構出來--> let {isCollect,collectors} = this.data.bottomData.placeData; isCollect = !isCollect; this.data.bottomData.placeData.isCollect = isCollect; let collectData = wx.getStorageSync('collectData') || []; if(isCollect){ wx.showToast({ title: '收藏成功', icon: 'success', duration: 2000 }) collectors++; collectData.push(this.data.bottomData.placeData); }else{ wx.showToast({ title: '已取消收藏', icon: 'success', duration: 2000 }) collectors--; collectData = collectData.filter(e => e.name != this.data.bottomData.placeData.name) } this.data.bottomData.placeData.collectors = collectors; <!--將收藏夾數據放入緩存--> wx.setStorageSync('collectData', collectData) let bottomData = this.data.bottomData; this.setData({ bottomData }) } } })
效果一
效果二
搜索功能的實現是經過原生組件 input 上的bindinput屬性,當鍵盤輸入時觸發bindinput屬性綁定的方法,實時獲取中輸入的值,而後將獲取到的值放入請求地址中請求數據,再將請求得到的數據放入頁面的data數據源中,當請求到的數據不爲空時,頁面上會顯示獲得的全部相關數據,如效果一。當按下搜索按鈕時會觸發input框上bindconfirm屬性綁定的事件,此時頁面上會顯示請求到的數據中的第一條,如效果二。
wxml
<input style='width:500rpx' bindconfirm='confirm' confirm-type='search' focus='true' placeholder="搜索目的地/景點/攻略" bindinput='search'></input>
js
// pages/search/search.js const app = getApp() Page({ /** * 頁面的初始數據 */ data: { navbarData: { showCapsule: 1, //是否顯示左上角圖標 1表示顯示 0表示不顯示 title: '馬蜂窩旅遊', //導航欄 中間的標題 backgroundColor: '#ffffff', //'#354a98' city: '', opacity: 1, showMain: 0 }, height: app.globalData.height * 2 + 20, result: [], searchparams: '', show: true, searchHistory: [], showResult: false, showconfirm: false, placedata: [] }, <!--清空歷史紀錄--> clear() { this.setData({ searchHistory: [] }) wx.removeStorageSync('searchHistory') }, <!--當點擊鍵盤上搜索按鈕觸發的事件--> confirm(e) { if (e.detail.value != '') { let searchHistory = wx.getStorageSync('searchHistory') || [] if (searchHistory.filter(a => a === e.detail.value).length === 0) { searchHistory.push(e.detail.value) wx.setStorageSync('searchHistory', searchHistory) } if (this.data.result.length > 0) { let currentCity = this.data.result[0].name; this.getCityDataByName(currentCity); } this.setData({ show: false, showResult: false, showconfirm: true }) } }, <!--跳到主頁面--> gotomain(e) { wx.setStorageSync('currentCity', e.currentTarget.dataset.name) wx.switchTab({ url: '/pages/main/index', }) }, <!--點擊歷史紀錄觸發的事件,效果和confirm方法基本相同,不一樣的是confirm是從頁面data中獲取數據,而dosearch是從接口中獲取數據--> gosearch(e) { let that = this wx.request({ url: `https://www.easy-mock.com/mock/5ca457f04767c3737055c868/example/mafengwo/search?name=${e.currentTarget.dataset.name}`, success: (res) => { if (res.data.data.length > 0) { that.getCityDataByName(res.data.data[0].name) } else { this.setData({ show: false, showResult: false, showconfirm: true }) } } }) }, // 經過城市名字 獲取城市數據 getCityDataByName(cityname) { let that = this wx.request({ url: 'https://www.easy-mock.com/mock/5ca457f04767c3737055c868/example/mafengwo/china', success: (res) => { let placedata = []; placedata.push(...res.data.data.china.filter(e => e.chName === cityname)) that.setData({ placedata, show: false, showResult: false, showconfirm: true }) } }) }, <!--當鍵盤輸入時觸發的事件--> search(e) { let that = this wx.request({ url: `https://www.easy-mock.com/mock/5ca457f04767c3737055c868/example/mafengwo/search?name=${e.detail.value}`, success: (res) => { if (res.data.data.length > 0) { that.changecolor(res.data.data, e.detail.value) } else { that.setData({ result: [], searchparams: '', showResult: false }) } } }) }, <!--改變名字顏色--> changecolor(result, searchparams) { for (let j = 0; j < result.length; j++) { let i = result[j].name.search(searchparams); let left = result[j].name.slice(0, i), mid = result[j].name.slice(i, i + searchparams.length), right = result[j].name.slice(i + searchparams.length); result[j].left = left; result[j].mid = mid; result[j].right = right; } this.setData({ result, searchparams, show: false, showResult: true, showconfirm: false }) }, _navback() { wx.navigateBack({ delta: 1 }) }, /** * 生命週期函數--監聽頁面加載 */ onLoad: function() { <!--獲取緩存中的搜索歷史並放入數據源--> let searchHistory = wx.getStorageSync('searchHistory') || [] this.setData({ searchHistory }) }
這個API接口是我用 Easy Mock寫的
Easy Mock 代碼
{ "data": function({ _req }) { let i = 0, <!--數據源_data因爲篇幅緣由就放了一小段數據--> _data = [ { name: '亞洲', type: '目的地' }, { name: '歐洲', type: '目的地' }, { name: '大洋洲', type: '目的地' }, { name: '非洲', type: '目的地' }, { name: '北美洲', type: '目的地' }, { name: '南美洲', type: '目的地' }, { name: '南極洲', type: '目的地' } ], <!--_req是easymock封裝的對象,_req.query(將查詢參數字符串進行解析並以對象的形式返回,若是沒有查詢參數字字符串則返回一個空對象);--> name = _req.query.name; if (name != '') { <!--當輸入的值不爲空時--> let result = []; let data = [] for (let j = 0; j < result.length; j++) { <!--eval() 函數可計算某個字符串,並執行其中的的 JavaScript 代碼。這裏主要是爲了給正則表達式動態傳參--> if (eval('/' + name + '/').test(result[j].name)) { data.push(result[j]) } <!--當查詢到8個匹配項時跳出循環--> if (data.length > 8) break; } return data } else { <!--當輸入的值爲空時直接返回空數組--> return [] } } }
由於動畫只有6個元素,因此就沒有必要寫成數組遍歷建立了,直接寫6個盒子,給他們的樣式初始化,讓他們到本身的初始位置去。微信小程序提供了建立動畫實例的API wx.createAnimation
wxml
<view class='video a' animation="{{animation1}}" data-index='0' bindtap="_play"> <view class='context'> <text>{{placeData.vlog[0].title}}</text> </view> <view class='vdoIcon'> <image src='/images/play.png'></image> </view> </view> <view class='video b' animation="{{animation2}}" data-index='1' bindtap="_play"> <view class='context'> <text>{{placeData.vlog[1].title}}</text> </view> <view class='vdoIcon'> <image src='/images/play.png'></image> </view> </view> <view class='video c' animation="{{animation3}}" data-index='2' bindtap="_play"> <view class='context'> <text>{{placeData.vlog[2].title}}</text> </view> <view class='vdoIcon'> <image src='/images/play.png'></image> </view> </view> <view class='video d' animation="{{animation4}}" data-index='3' bindtap="_play"> <view class='context'> <text>{{placeData.vlog[3].title}}</text> </view> <view class='vdoIcon'> <image src='/images/play.png'></image> </view> </view> <view class='video e' animation="{{animation5}}" data-index='4' bindtap="_play"> <view class='context'> <text>{{placeData.vlog[4].title}}</text> </view> <view class='vdoIcon'> <image src='/images/play.png'></image> </view> </view> <view class='video f' animation="{{animation6}}" data-index='5' bindtap="_play"> <view class='context'> <text>{{placeData.vlog[5].title}}</text> </view> <view class='vdoIcon'> <image src='/images/play.png'></image> </view> </view>
wxss
.a{ opacity: 0.9; } .b{ transform: translate(170rpx,-110rpx) scale(0.8); opacity: 0.8; } .c{ transform: translate(210rpx,-250rpx) scale(0.7); opacity: 0.7; } .d{ transform: translate(10rpx,-350rpx) scale(0.6); opacity: 0.6; } .e{ transform: translate(-250rpx,-290rpx) scale(0.8); opacity: 0.5; } .f{ transform: translate(-300rpx,-130rpx) scale(0.9); opacity: 0.8; }
js
// 動畫的運行路線 translate: function(i) { // 獲取屏幕寬度來實現自適應 let windowwidth = this.data.windowWidth; //動畫的運行狀態status[x軸偏移量,y軸偏移量,scale縮放倍數,opacity透明度],也是動畫的運行路線 let status = [ [170, -110, 0.8, 0.7], [210, -250, 0.7, 0.6], [10, -350, 0.6, 0.5], [-250, -300, 0.8, 0.7], [-300, -130, 0.9, 0.8], [0, 0, 1, 0.9] ]; let x = 0, y = 0, scale = 0, opacity = 0; for (let j = 0; j < 6; j++) { let animationName = 'animation' + (j + 1); x = status[(i + j) % 6][0] / 750 * windowwidth; y = status[(i + j) % 6][1] / 750 * windowwidth; scale = status[(i + j) % 6][2]; opacity = status[(i + j) % 6][3]; this.animation.translate(x, y).scale(scale).opacity(opacity).step() this.setData({ [animationName]: this.animation.export()//導出動畫數據傳遞給組件的 animation 屬性 }) } }, hotCityAnimation() { let i = 0; <!--建立動畫實例--> this.animation = wx.createAnimation({ duration: 2000, timingFunction: 'ease', }) let that = this let anicontrol = this.data.anicontrol anicontrol = setInterval(function() { that.translate(i) if (i == 5) { i = -1; } i++; }, 3000) this.setData({ anicontrol }) }
這裏要注意的是,由於這是寫在tabbar頁面的動畫,並且用了setinterval定時器,會按照指定的週期(以毫秒計)來執行註冊的回調函數,意思就是即便你跳轉到別的頁面,動畫依然在運行,當你回到主頁時,動畫就會運行出錯,出現鬼畜,因此要在主頁的onHide周期函數,監聽頁面隱藏時就把定時器給清除了,而且把動畫實例也清除。
onHide: function() { let anicontrol = this.data.anicontrol; clearInterval(anicontrol) this.setData({ animation1: '', animation2: '', animation3: '', animation4: '', animation5: '', animation6: '' }) }
寫這個小程序我沒有用到任何UI框架,這有壞處,也有好處,壞處就是代碼進度賊慢,好處就是本身增長了不少對css的理解。有想用UI框架的可使用 WeUI 。連接裏有詳細的使用方法。
由於時間和精力的緣故,小程序只寫了幾個頁面和小部分功能,在寫項目的過程當中也發現了本身的不少不足,所以吃到了很多苦頭,可是也學到了很多,能夠說痛並快樂着。但願這篇文章可以對打算寫小程序的你有一點幫助。GitHub源碼在這裏,須要自取。