摘要:潤物無聲,做一個有個格調的小程序快應用現在可謂是家喻戶曉,也更加密切的滲透入我們的生活中,筆者也算是個愛折騰的人,俗話說的好嘛,不折騰,不前端當然是筆者自己的小心聲。于是在平日里忙碌的工作之余抽出來時間搞點事情來寫一個屬于自己的貼身小天氣。
———— 潤物無聲,做一個有個格調的coder小程序、快應用現在可謂是家喻戶曉,也更加密切的滲透入我們的生活中,筆者也算是個愛折騰的人,俗話說的好嘛,“不折騰,不前端“(當然是筆者自己的小心聲)。于是在平日里忙碌的工作之余抽出來時間搞點事(si)情,來寫一個屬于自己的貼身小天氣。說時遲那時快,這就來了...
經過兩三年的發展,小程序的地位也步步高升,由騰訊領隊的騰訊小程序,再到后來的支付寶,美團,頭條等也都相應推出自家的小程序平臺,都想順著潮流抓住流量分一杯羹,可謂是兵家必爭之地。大環境的改變,為了提高小程序的快速迭代和多人合作開發的效率,也使得各大廠商都開源了自己的小程序框架,mpvue、wepy、MINA、Taro等相信大家也比較熟悉了。而小程序的社區也變得跟豐富健壯,也衍生出很多精美的UI框架。有興趣的可以自行去相應的官網了解詳情。
雖然上面介紹了那么多的框架,而本次筆者并沒有使用框架,而是用原生的小程序來開發今天的主角,也希望能夠用原始的方式來給那些和筆者一樣的剛剛入門的小程序開發者一些幫助,也將自己所學的記錄下來。畢竟原生才是最底層的基礎,所有的框架都是在原生的基礎上開花結果的,這樣才能以不變應萬變(吼吼~)。筆者水平有限,有錯誤或者解釋不當的地方還望各位看官多多包涵。
蝸牛小天氣 效果圖項目源碼 潤物無聲github
概況在定位功能中,本程序用到騰訊地圖的api
相應的天氣接口中,本程序用到的是和風天氣提供的api
兩者都需要到官網中注冊開發者賬號,通過注冊后得到的appKey來請求我們需要的數據,詳細注冊步驟請自行度娘由于需要用到定位功能,而小程序本身的getLocation方法獲取到的是當前位置的坐標:
wx.getLocation({ type: "gcj02", // 返回坐標的格式 success: res => { // 此處只能獲取到當前位置的經緯度(坐標) }, })
所以需要利用騰訊地圖Api,通過坐標點反向獲得該地點的詳細信息。
在app.json中是對整個小程序的一些基本配置
{ "pages": [ "pages/index/index" // 當前小程序的主入口頁面 ], // 主窗口的一些配置,如下,對背景顏色和小程序頂部的導航欄的樣式進行了配置 "window": { "backgroundColor": "#A7CAD3", "backgroundTextStyle": "dark", "navigationBarBackgroundColor": "#A7CAD3", "navigationBarTitleText": "蝸牛天氣", "navigationBarTextStyle": "black", "navigationStyle":"custom" }, "permission": { "scope.userLocation": { "desc": "蝸牛天氣嘗試獲取您的位置信息" // 詢問用戶是否可以得到獲取位置權限的提示文字 } } }
接下來,我們就來一步一步的實現這個小程序吧~~
1.界面由于沒有UI,再加上筆者扭曲的審美能力(坐在屏幕前開始愣神,陷入沉思...),所以還望各位看官多忍耐筆者又想又借鑒的界面成果...看來以后要多加強這方面的能力(haha~)
好了言歸正傳,首先,準備用一個頁面來解決戰斗,那就是各位看到以上的這個頁面(都說了是‘小天氣’嘛),頁面一共分為五個部分,實時天氣、24小時內天氣情況、未來一星期內天氣情況、今天日落日出風向降雨等相關信息和天氣的生活指數,這五個部分組成了整個頁面,其對應的相應布局見一下代碼
{{position}} ... {{item.time}}點 {{item.tmp}}° {{item.weekday}} {{item.date}} {{item.cond_txt_d}} {{item.tmp_min}}~{{item.tmp_max}}° {{item.cond_txt_n}} {{item.wind_dir == "無持續風向" ? "無" : item.wind_dir}} {{item.wind_sc}}級 ... {{lifeEnum[item.type]}} {{item.brf}}
具體 css 樣式,詳見 蝸牛小天氣 源碼
注意:(筆者入坑,一開始使用的縱向的scroll-view,后來無奈的用了原來頁面的滾動)
scroll-view: 具體屬性參考小程序官方文檔
在小程序中,內部為我們提供了scroll-view這個頁面滾動的組件,對性能進行了一些優化,方便我們的使用。與此同時,也會有一些小坑在使用scroll-view是,如果是縱向(Y軸)滾動,scroll-y屬性,則必須為此scroll-view設置一個固定(明確)的高
請勿在scroll-view組件標簽內使用 textarea、map、canvas、video等組件
在使用了scroll-view組件時會阻止頁面的回彈效果,也就是在scroll-view中滾動,無法觸發onPullDownRefresh方法
如果想使用原生的下拉刷新(非自定義)或者雙擊頂部頁面回滾到頁面頂部,請不要使用scroll-view。
相信各位看官發現了以上代碼中有一個
*.wxml ----文檔結構 => 等同于html
*.js ----處理業務邏輯
*.json ----當前頁面或組件的一些配置和選項
*.wxss ----樣式文件 => 等同于css
而對于本小程序中
// 小程序中的組件,通過調用Component方法,將組件的邏輯處理部分,屬性以及方法(生命周期)等一對象的方式傳入Component方法中 Component({ properties: { type: { type: String, // type屬性的類型 value: "" // 默認值 } } });
使用了Component構造器,通過參數指定組件的屬性,數據,方法以及生命周期中的一些方法,在此組件中定義了接受的type屬性,類型為字符串,其默認值為空字符串。
{ "component": true // 配置,當前為組件 }
// CSS 部分略過...
就這樣,一個簡單的icon圖標組件就封裝好了,是不是很簡單啊。封裝是封裝好了,那么我們怎么調用這個組件呢,是不是很類似于Vue呢,沒錯,只需要在你調用的頁面中注冊一下即可
// 當前想要調用的頁面的*.json文件中,如下 { "enablePullDownRefresh": true, // 此項與組件無關,此項為是否用小程序本身的下拉刷新功能 "usingComponents": { "myicon": "../../components/icon/index" // 調用,注冊icon組件 } }2.相關數據API
一開始就說到了需要使用騰訊地圖API的appkey還有和風天氣API的appkey,筆者是將appkey配置在了config.js中,看官只需將自己相應的appkey值替換即可,由于appkey是私密的,此處就不公開了,還望諒解。
// config.js export default { MAP_API_KEY: "XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX", // 騰訊地圖key WEATHER_API_KEY: "XXXXXXXXXXXXXXXX" // 和風天氣key }
所有數據的接口,都定義在了api.js文件中,此處沒什么好說的,看官自行通過接口文檔查詢。接口均采用回調的方式,筆者并沒有封裝成Promise的方式,如果有興趣可自行更改。
// 引入config,為了后面的key import config from "../uitl/config" // 地圖key const mapKey = config.MAP_API_KEY // 和風天氣key const weatherKey = config.WEATHER_API_KEY // map url const locationUrl = "https://apis.map.qq.com/ws/geocoder/v1/" //天氣url const weatherUrl = "https://free-api.heweather.net/s6/weather/forecast" //24小時內 每小時 const everyhoursUrl = "https://api.heweather.net/s6/weather/hourly" // 一周內 const everyWeekUrl = "https://api.heweather.net/s6/weather/forecast" //空氣質量 const airQualityUrl = "https://api.heweather.net/s6/air/now" // 實況天氣 const weatherLive = "https://api.heweather.net/s6/weather/now" // 生活指數 const lifeStyle = "https://api.heweather.net/s6/weather/lifestyle" // 根據當前位置的坐標反得到當前位置的詳細信息 // lat,lon 為經緯度坐標 export const getPosition = (lat, lon, success = {}, fail = {}) => { return wx.request({ url: locationUrl, header: { "Content-Type": "application/json" }, data: { location: `${lat},${lon}`, key: mapKey, get_poi: 0 }, success, fail }) } // 根據location得到天氣信息 // lat,lon 為經緯度坐標 export const getWeaterInfo = (lat, lon, success = {}, fail = {}) => { return wx.request({ url: weatherUrl, header: { "Content-Type": "application/json" }, data: { location: `${lat},${lon}`, lang: "zh", unit: "m", key: weatherKey }, success, fail }) } // 根據location信息得到24小逐小時天氣情況 // lat,lon 為經緯度坐標 export const getEveryHoursWeather = (lat, lon, success = {}, fail = {}) => { return wx.request({ url: everyhoursUrl, header: { "Content-Type": "application/json" }, data: { location: `${lat},${lon}`, lang: "zh", unit: "m", key: weatherKey }, success, fail }) } ... ... // 其他接口類似 ... }3.實現邏輯(業務代碼) 3.1 流程
首先,當初次加載頁面時,大體流程為首先通過定位獲取位置,然后通過位置信息去得到我們需要的每一項天氣信息,最后將天氣信息渲染后頁面中相應的位置
具體流程:
獲取位置經緯度
通過經緯度逆向獲得位置信息
通過位置信息獲取天氣信息
獲取實時天氣信息
判斷是否為白天和晚上(改變頁面背景)--該小程序中定義早上6點到晚上18點為淺色背景,其他時間為深色背景
判斷當前天氣的情況(雨或雪的大小),在實況天氣界面中通過canvas模擬雨雪的動畫
獲取24小時天氣信息
獲取一星期的天氣信息
獲取生活指數信息
當通過手動改變位置信息時,按順序重復執行以上步驟3.2 獲取經緯度以及逆向出位置信息
通過wx.getLocation原生方法獲取經緯度信息,在經過騰訊地圖api通過經緯度逆向獲取到相應的位置信息,對于這個項目來說獲取位置信息是最重要的信息,故我們希望在頁面一加載的時候就執行方法獲取,然后『onLoad』方法可以幫助我們解決,這個方法就是小程序的生命周期函數--監聽頁面加載,此方法會在頁面剛加載的時候(document文檔結構渲染完成后)執行。
小程序頁面(Page)的生命周期函數:
name | type | functional |
---|---|---|
onLoad | 函數 | 監聽頁面加載 |
onReady | 函數 | 監聽頁面初次渲染完成 |
onShow | 函數 | 監聽頁面顯示 |
onHide | 函數 | 監聽頁面隱藏 |
onUnload | 函數 | 監聽頁面卸載 |
以下為獲取位置信息代碼:
// onLoad onLoad: function () { ... ... this.getPositon() // 調用獲取位置信息 } // 原生方法獲取經緯度信息 getPosition: function () { wx.getLocation({ type: "gcj02", success: this.updateLocation, // 成功會掉 updataLocation 方法為更新位置 fail: err => { console.log(err) } }) } // 更新位置信息 updateLocation: function(res) { ... ... let {latitude: x,longitude: y,name} = res; let data = { location: { x, y, name: name || "北京市" }, ... ... }; this.setData(data); // 設置page中data對象中的屬性 // 通過經緯度逆向獲得位置信息 this.getLocation(x, y, name); } // 逆向獲取位置信息 getLocation: function(lat, lon, name) { wx.showLoading({ title: "定位中", mask: true }) // 騰訊地圖api接口 getPosition(lat, lon, (res) => { if (res.statusCode == 200) { let response = res.data.result let addr = response.formatted_addresses.recommend || response.rough this.setData({ position: addr // 賦值給 data對象中的相應屬性 }) wx.hideLoading() this.getData(lat, lon); } }, (err => { console.log(err) wx.hideLoading() })) }, // 當用戶點擊顯示定位處的view時,會調用原生的chooseLocation方法,內部調用選擇位置頁面 chooseLocation: function() { wx.chooseLocation({ success: res => { let {latitude,longitude} = res let {x,y} = this.data.location if (latitude == x && longitude == y) { } else { this.updateLocation(res) } } }) },
上面代碼中兩次用到了setData方法,該方法接受一個對象,對象中的屬性為需要改變的數據,同時接受一個callback函數,用于通過改變數據更新頁面渲染完成之后的回調。我們來看看data的作用。
page({ data: { backgroundColor:"red", fontSize: "20", ... ... } })
在page中,data中的屬性是連接邏輯層和視圖層的一個橋梁,也就是說我們可以通過js代碼的邏輯來控制data中的屬性的值,而頁面中的一部分顯示內容是根據data中的屬性的值而變化。這也就是我們所說的mvvm模型,我們只需把重心放在js邏輯層,而無需去頻繁的手動的操作視圖層。了解了data的作用,再來說setData,setData就是在js邏輯層中去改變和設置data中的屬性的值,從而使頁面得到響應。
... this.setData({ backgroundColor: "green" // 改變背景顏色屬性,視圖中以來此屬性的會將顏色變成綠色 }) ...
3.3 獲取天氣注意:
直接修改this.data的值,而不是通過調用this.setData()方法,是無法成功改變頁面的狀態的
僅僅支持JSON化的數據(key:value)
單詞設置的值不能超過1024K,所以使用的時候盡量不要一次設置過多的數據
不要把data中的任何一項value值設置成undefined,否則這一項將不能被設置,也可能會有其他問題
不要頻繁的去調用this.setData()方法去設置同一個值或者多個值,比如通過在循環中調用this.setData(),這樣會導致性能損耗
通過上面獲得到的位置信息,用來調用相應的接口獲得當前位置的天氣。方法接口已在前面封裝好,直接調用然后通過對response進行過濾或者重組等來滿足當前的應用,最后通過this.setData()方法去更新數據是頁面得到響應。
getWeather(lat, lon) // lat, lon 為當前位置的經緯度
getAir(lat, lon)
getHourWeather(lat, lon)
getWeatherForWeek(lat, lon)
getLifeIndex(lat, lon)
以上方法不在一一列舉其中數據處理的過程,可自行查看源碼 詳見 蝸牛小天氣 源碼
粒子動畫在現在越來越多的項目中被用到。從靜態到動態最后再到仿真效果更好的視覺體驗,也是人們在視覺上追求極致的體驗。我們通過粒子,也就是通過點和線,來模擬出雨和雪的效果。通過小程序中的canvas畫布來畫出我們想要的效果。
實現原理:
首先我們通過點和線來模擬雨滴下落和雪花飄落
我們通過在同一時間同一塊區域(也就是此小程序頁面中實況天氣的區域)中雨滴或雪花的多少來表示大小
構造一個總的Weather基類,來設置畫布的width,height,以及雨滴或雪花的數量,同時會有兩個Start和Stop方法(也就是開始和停止方法)
構造一個Rain類和一個Snow類,都繼承自Weather類,Rain和Snow都有自己私有的 _init(初始化), _drawing(畫), _update(更新畫布)三個方法來控制Rain和Snow的動作
Weather類Weather類是一個基類,主要處理畫布的一些信息,例如width,height,定時器,以及當前動畫的狀態(status)等
const STOP_ANIMATION = "stop" const START_ANIMATION = "start" class Weather { constructor(context, width, height, option = {}) { this.opt = option || {} this.context = context this.timer = null this.status = STOP_ANIMATION this.width = width this.height = height this._init() } // 實例調用此方法,開始在畫布上畫 start() { if(this.status !== START_ANIMATION) { this.status = START_ANIMATION this.timer = setInterval(() => { this._drawing() }, 30) return this } } stop() { this.status = STOP_ANIMATION clearInterval(this.timer) this.timer = null return this } } export default WeatherRain類
Rain類繼承自Weather類,通過_init方法和父類中畫布參數,以及option參數中的counts(雨滴數量)來初始化。
import Weather from "./Weather.js" class Rain extends Weather { // 初始化 _init() { this.context.setLineWidth(2) this.context.setLineCap("round") let height = this.height let width = this.width let counts = this.opt.counts || 100 let speedCoefficient = this.opt.speedCoefficient let speed = speedCoefficient * height this.animationArray = [] let arr = this.animationArray for (let i = 0; i < counts; i++) { let d = { x: Math.random() * width, y: Math.random() * height, len: 2 * Math.random(), xs: -1, ys: 10 * Math.random() + speed, color: "rgba(255,255,255,0.1)" } arr.push(d) } } // 開始畫 _drawing() { let arr = this.animationArray let ctx = this.context ctx.clearRect(0, 0, this.width, this.height) for (let i = 0; i < arr.length; i++) { let s = arr[i] ctx.beginPath() ctx.moveTo(s.x, s.y) ctx.lineTo(s.x + s.len * s.xs, s.y + s.len * s.ys) ctx.setStrokeStyle(s.color) ctx.stroke() } ctx.draw() return this.update() } // 更新畫布 update() { let width = this.width let height = this.height let arr = this.animationArray for (let i = 0; i < arr.length; i++) { let s = arr[i] s.x = s.x + s.xs s.y = s.y + s.ys if (s.x > width || s.y > height) { s.x = Math.random() * width s.y = -10 } } } } export default RainSnow類
Snow類繼承自Weather類,通過_init方法和父類中畫布參數,以及option參數中的counts(雪花數量)來初始化。
import Weather from "./Weather.js" class Snow extends Weather { // 初始化 _init() { let { width, height } = this console.log(width) let colors = this.opt.colors || ["#ccc", "#eee", "#fff", "#ffffd"] let counts = this.opt.counts || 100 let speedCoefficient = this.opt.speedCoefficient || 0.03 let speed = speedCoefficient * height * 0.15 let radius = this.opt.radius || 2 this.animationArray = [] let arr = this.animationArray for (let i = 0; i < counts; i++) { arr.push({ x: Math.random() * width, y: Math.random() * height, ox: Math.random() * width, ys: Math.random() + speed, r: Math.floor(Math.random() * (radius + 0.5) + 0.5), color: colors[Math.floor(Math.random() * colors.length)], rs: Math.random() * 80 }) } console.log(arr) } // 開始畫 _drawing() { let arr = this.animationArray let context = this.context context.clearRect(0, 0, this.width, this.height) for (let i = 0; i < arr.length; i++) { let { x, y, r, color } = arr[i] context.beginPath() context.arc(x, y, r, 0, Math.PI * 2, false) context.setFillStyle(color) context.fill() context.closePath() } context.draw() this._update() } // 更新畫布 _update() { let { width, height } = this let arr = this.animationArray let v = this.opt.speedCoefficient / 10 for (let i = 0; i < arr.length; i++) { let p = arr[i] let { ox, ys } = p p.rs += v p.x = ox + Math.cos(p.rs) * width / 2 p.y += ys if (p.x > width || p.y > height) { p.x = Math.random() * width p.y = -10 } } } } export default Snow
結束!!!
到此,蝸牛小天氣就開發完成了,希望對各位有幫助。
希望在閱讀的同時還請看官別忘了給一個大大的贊
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102882.html
摘要:課程內容以打造一款擁有天氣預報和簽到功能的小程序為主線,從基礎知識到小程序運行機制,從開發環境搭建到小程序云開發的接口使用調試上線,打通微信小程序開發全流程。 9 月 11 日,微信開發者工具新增小程序「云開發」功能。 showImg(https://segmentfault.com/img/bVbjQLW?w=1000&h=544); 大多數開發者在開發應用時和部署服務時,無論是選擇...
摘要:開眼短視頻仿照開眼視頻端舊版新版已改變做的一個,每天更新一個精美短視頻應用,一個非常美的短視頻應用,界面基本上是參照開眼視頻端來做的。 開眼短視頻(OpenEyes) 仿照(開眼視頻)Android端(舊版UI,新版UI已改變)做的一個App,每天更新一個精美短視頻應用,一個非常美的短視頻應用,UI界面基本上是參照開眼視頻Android端來做的。 在該項目中,我采用的是Vitamio的...
摘要:項目名稱我這里是模仿萬達電影小程序,你也可以自己換一個,這里隨意。 如果你是一個小白,想學習或者了解小程序,但是不知從何下手,那么這篇文章應該會對你有所幫助,如果您是一位大佬,那么這篇文章歡迎您吐槽! 什么是小程序? 小程序是微信新推出來的一種連接用戶與服務的方式。是一種不需安裝下載就能使用的應用。實現了用完即走的夢想。 小程序的優勢 不用安裝,即開即用,省流量,不占用桌面 對于小程...
閱讀 1661·2019-08-30 12:51
閱讀 655·2019-08-29 17:30
閱讀 3695·2019-08-29 15:17
閱讀 851·2019-08-28 18:10
閱讀 1355·2019-08-26 17:08
閱讀 2168·2019-08-26 12:16
閱讀 3428·2019-08-26 11:47
閱讀 3497·2019-08-23 16:18