小程序已經(jīng)出來很久了,最近又在學習JavaScript,而小程序的開發(fā)語言也是基于JavaScript,所以就打算學習一下微信小程序開發(fā)。 大家可以在微信小程序里搜搜索Lite天氣即可體驗。
微信小程序的原理,看一下微信官方的文檔寫到:
三端的腳本執(zhí)行環(huán)境聚以及用于渲染非原生組件的環(huán)境是各不相同的:
- 在 iOS 上,小程序的 javascript 代碼是運行在 JavaScriptCore 中,是由 WKWebView 來渲染的,環(huán)境有 iOS8、iOS9、iOS10
- 在 Android 上,小程序的 javascript 代碼是通過 X5 JSCore來解析,是由 X5 基于 Mobile Chrome 53 內(nèi)核來渲染的
- 在 開發(fā)工具上, 小程序的 javascript 代碼是運行在 nwjs 中,是由 Chrome Webview 來渲染的
據(jù)我猜測,我覺得微信小程序能夠提供如此完整的API,并且性能也有如此之好的體驗,其原理應該是和React Native的原理類似,通過微信自己的JavaScript運行引擎,最終將其中的代碼翻譯成Native的原生控件并展示出來,以達到媲美原生APP的性能以及用戶體驗。
再說開發(fā)工具,文中提到了nw.js,這個nwjs據(jù)我所知就是node.js與Browser運行時的合并,據(jù)我所知這個nw.js就是一個專門用于跨平臺開發(fā)的工程,其可利用node.js訪問系統(tǒng)原生的API。但是經(jīng)過我google,我發(fā)現(xiàn)現(xiàn)在有一個叫做Electron的項目比nw.js更為火熱,其中atom和vscode也是基于Electron開發(fā)的。至于微信為什么采用nw.js開發(fā),我也是不是很了解。
其中大概的原理就講到這里,有興趣的可以參考一下文章
我這里就不過多介紹微信小程序的詳細教程,因為微信提供的官方文檔已經(jīng)十分詳細地介紹了微信小程序的文件類型、項目結構框架、具體API。
不過我建議在編寫微信小程序之前應該要有一下的基礎:
有了以上的基礎知識,在官方文檔的指導下,絕對能夠快速地進行小程序的開發(fā)。
項目結構:
現(xiàn)在只開發(fā)了一個簡單的天氣頁面,因此只寫了index頁面建立了weather相關的頁面。

app.js:
這個文件相當于Android 程序中的application,整個程序只有一個app.js到單例,因此程序的各種生命周期的回調(diào)都在這里,并且可以存儲一下程序的全局數(shù)據(jù)以及變量,例如用戶數(shù)據(jù)等。
App({
onLaunch: function () {
},
onShow: () => {
console.log('onshow');
},
onHide: () => {
console.log('onHide');
},
getUserInfo: function (cb) {
var that = this
if (this.globalData.userInfo) {
typeof cb == "function" && cb(this.globalData.userInfo)
} else {
//調(diào)用登錄接口
wx.login({
success: function () {
wx.getUserInfo({
success: function (res) {
that.globalData.userInfo = res.userInfo
typeof cb == "function" && cb(that.globalData.userInfo)
}
})
}
})
}
},
globalData: {
userInfo: null
}
})
app.json:
這個相當于是程序的路由表以及配置表,包括程序的頁面注冊、網(wǎng)絡配置、底部導航欄、頂部導航欄的配置都可以在這里編寫,具體的可以在官方文檔里進行查看。
{
"pages": [
"pages/weather/index/weather",
"pages/weather/city/city",
"pages/weather/detail/detail",
"pages/weather/setting/setting"
],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#09bb07",
"navigationBarTitleText": "Lite天氣",
"navigationBarTextStyle": "white",
"enablePullDownRefresh": true
},
"tabBar": {
"list": [
{
"pagePath": "pages/weather/index/weather",
"text": "天氣",
"iconPath": "/resources/weather_icon_normal.png",
"selectedIconPath": "/resources/weather_icon_selected.png"
},
{
"pagePath": "pages/weather/setting/setting",
"text": "我的",
"iconPath": "/resources/setting_icon_normal.png",
"selectedIconPath": "/resources/setting_icon_selected.png"
}
],
"color": "#dbdbdb",
"selectedColor": "#09bb07",
"backgroundColor": "#ffffff",
"borderStyle": "black"
},
"networkTimeout": {
"request": 5000,
"connectSocket": 20000,
"uploadFile": 20000,
"downloadFile": 20000
}
}
之前都是app的全局配置,現(xiàn)在來編寫具體的頁面。
預期的頁面是這個樣子的設計。

weather.wxml:
<view class="container">
<image src="{{backgroudUrl}}" mode="scaleToFill"></image>
<view class="header">
<view class="header-top">
<view id="city">{{weather.city}}</view>
<view>{{weather.update}}</view>
</view>
<view class="header-condition">
<view id="temp">{{weather.now.tmp}}℃</view>
<view>{{weather.now.cond.txt}}</view>
</view>
</view>
<view class="item-list" wx:for="{{weather.daily}}">
<view class="daily-item">
<view class="item-date">{{item.date}}</view>
<view class="item-date">{{item.cond.txt_d}}</view>
<view class="item-date">{{item.tmp.max}}</view>
<view class="item-date">{{item.tmp.min}}</view>
</view>
</view>
<view class="air-list">
<view class="air-item">
<view>{{weather.aqi.qlty}}</view>
<view>空氣質量</view>
</view>
<view class="air-item">
<view>{{weather.aqi.aqi}}</view>
<view>AQI</view>
</view>
<view class="air-item">
<view>{{weather.aqi.pm25}}</view>
<view>PM2.5</view>
</view>
<view class="air-item">
<view>{{weather.aqi.pm10}}</view>
<view>PM10</view>
</view>
<view class="air-item">
<view>{{weather.now.hum}}%</view>
<view>濕度</view>
</view>
</view>
<view class="life-suggestion">
<text>空氣指數(shù):{{weather.suggestion.air.brf}},{{weather.suggestion.air.txt}}</text>
<text>舒適度指數(shù):{{weather.suggestion.comf.brf}},{{weather.suggestion.comf.txt}}</text>
<text>洗車指數(shù):{{weather.suggestion.cw.brf}},{{weather.suggestion.cw.txt}}</text>
<text>穿衣指數(shù):{{weather.suggestion.drsg.brf}},{{weather.suggestion.drsg.txt}}</text>
<text>感冒指數(shù):{{weather.suggestion.flu.brf}},{{weather.suggestion.flu.txt}}</text>
<text>運動指數(shù):{{weather.suggestion.sport.brf}},{{weather.suggestion.sport.txt}}</text>
<text>旅游指數(shù):{{weather.suggestion.trav.brf}},{{weather.suggestion.trav.txt}}</text>
<text>紫外線指數(shù):{{weather.suggestion.uv.brf}},{{weather.suggestion.uv.txt}}</text>
</view>
</view>
類似于css的可以設置在weather.wxss
.container {
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
}
image {
width: 100%;
height: 250%;
filter: blur(1px);
position: absolute;
z-index: -1;
}
.header {
padding: 20rpx;
height: 400rpx;
display: flex;
justify-content: space-between;
flex-direction: column;
margin-bottom: 20rpx;
}
.header-top {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.header-condition {
padding: 20rpx;
display: flex;
align-self: flex-end;
align-items: center;
flex-direction: column;
justify-content: flex-end;
}
#temp {
color: #fff;
margin-bottom: 20rpx;
font-size: 100rpx;
}
.header view {
color: #fff;
font-size: 30rpx;
}
.item-list {
padding: 20rpx;
margin-left: 40rpx;
margin-right: 40rpx;
background: rgba(0, 0, 0, 0.2);
border-radius: 3rpx;
}
.daily-item {
font-size: 30rpx;
color: white;
display: flex;
flex-direction: row;
justify-content: space-around;
}
.air-list {
margin-left: 40rpx;
margin-right: 40rpx;
margin-top: 60rpx;
margin-bottom: 40rpx;
display: flex;
height: 100px;
color: white;
font-size: 30rpx;
align-items: center;
flex-direction: row;
justify-content: space-around;
background: rgba(0, 0, 0, 0.2);
border-radius: 3rpx;
}
.air-item {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.air-item view {
margin: 20rpx;
}
.life-suggestion {
color: white;
padding: 50rpx;
font-size: 30rpx;
margin-left: 40rpx;
margin-right: 40rpx;
margin-bottom: 40rpx;
display: flex;
flex-direction: column;
background: rgba(0, 0, 0, 0.2);
border-radius: 3rpx;
}
.life-suggestion text {
margin-top: 20rpx;
font-style: oblique;
}
weather.js
最后就是頁面的數(shù)據(jù)的獲取以及相應的邏輯處理:
const weatherUtil = require('../../../utils/weatherUtil.js');
const imageUtil=require('../../../utils/imageUtil.js');
var app = getApp();
function refreshData(that) {
weatherUtil.loadWeatherData((success, data) => {
that.setData({
weather: data
});
wx.stopPullDownRefresh();
});
}
Page({
data: {
title: 'Lite天氣',
weather: {},
backgroudUrl:''
},
bindViewTap: function () {
},
onLoad: function () {
var that=this;
imageUtil.requestDailyImageUrl((url)=>{
that.setData({
backgroudUrl:url
});
});
refreshData(that);
},
onPullDownRefresh: function () {
refreshData(this);
}
})
我將獲取位置以及一些數(shù)據(jù)都封裝在了weatherUtil里面,這個天氣API是和風天氣提供的,可以自己去和風天氣官網(wǎng)申請key值:
const baseUrl = 'https://free-api.heweather.com/v5/weather?key=';
const app = getApp();
/**
* 根據(jù)經(jīng)緯度獲取天氣
*/
function requestWeatherByLocation(latitude, longitude, callback) {
wx.request({
url: baseUrl + '&city=' + longitude + ',' + latitude,
data: {},
method: 'GET', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
// header: {}, // 設置請求的 header
success: function (res) {
// success
var result = pareseWeahterData(res);
callback(true, result);
},
fail: function (res) {
// fail
callback(false);
}
});
}
/**
* 獲取天氣回調(diào)
*/
function requestWeatherData(callback) {
requestLocation((success, latitude, longitude) => {
if (success == false) {
latitude = 120.343;
longitude = 36.088;
}
requestWeatherByLocation(latitude, longitude, callback);
});
}
/**
* 解析數(shù)據(jù)
*/
function pareseWeahterData(orign) {
var weather = {};
console.log(orign);
var data = orign.data.HeWeather5[0];
weather.city = data.basic.city;
weather.now = data.now;
weather.daily = data.daily_forecast;
weather.suggestion = data.suggestion;
weather.basic = data.basic;
weather.update = data.basic.update.loc.substring(10, 16);
weather.aqi=data.aqi.city;
console.log(weather);
return weather;
}
/**
* 獲取位置信息,返回經(jīng)緯度
*/
function requestLocation(callback) {
wx.getLocation({
type: 'wgs84', // 默認為 wgs84 返回 gps 坐標,gcj02 返回可用于 wx.openLocation 的坐標
success: function (res) {
callback(true, res.latitude, res.longitude);
},
fail: function (res) {
callback(false);
}
});
}
function loadWeatherData(callback) {
requestWeatherData(callback);
}
module.exports = { loadWeatherData: loadWeatherData }
ok,以上就是一個簡單的天氣頁面的開發(fā)。
總之,按照官方文檔的指導,很輕松就能夠制作一個簡單的微信小程序。
通過開發(fā)這個簡答的天氣小程序,收獲了不少,但是也不得不吐槽一下微信小程序的設計。
下一個研究的就是ReactNative,之后會用RN開發(fā)一個Lite天氣。
項目源碼:https://github.com/nickming/WXLiteWeather
歡迎star