微信小程序体验并构建自己的微信小程序——Lite天气

小程序已经出来很久了,最近又在学习JavaScript,而小程序的开发语言也是基于JavaScript,所以就打算学习一下微信小程序开发。
大家可以在微信小程序里搜搜索Lite天气即可体验。

原理

微信小程序的原理,看一下微信官方的文档写到:

三端的脚本执行环境聚以及用于渲染非原生组件的环境是各不相同的:

  • 在 iOS 上,小程序的 javascript 代码是运行在 JavaScriptCore 中,是由 WKWebView 来渲染的,环境有 iOS8、iOS9、iOS10
  • 在 Android 上,小程序的 javascript 代码是通过 X5 JSCore来解析,是由 X5 基于 Mobile Chrome 53 内核来渲染的
  • 在 开发工具上, 小程序的 javascript 代码是运行在 nwjs 中,是由 Chrome Webview 来渲染的

据我猜测,我觉得微信小程序能够提供如此完整的API,并且性能也有如此之好的体验,其原理应该是和React Native的原理类似,通过微信自己的JavaScript运行引擎,最终将其中的代码翻译成Native的原生控件并展示出来,以达到媲美原生APP的性能以及用户体验。

再说开发工具,文中提到了nw.js,这个nwjs据我所知就是node.js与Browser运行时的合并,据我所知这个nw.js就是一个专门用于跨平台开发的工程,其可利用node.js访问系统原生的API。但是经过我google,我发现现在有一个叫做Electron的项目比nw.js更为火热,其中atom和vscode也是基于Electron开发的。至于微信为什么采用nw.js开发,我也是不是很了解。

其中大概的原理就讲到这里,有兴趣的可以参考一下文章

  1. 微信小程序底层的实现原理是怎样的?
  2. 微信小程序剖析 | 运行机制及框架原理

开发准备

我这里就不过多介绍微信小程序的详细教程,因为微信提供的官方文档已经十分详细地介绍了微信小程序的文件类型、项目结构框架、具体API。

不过我建议在编写微信小程序之前应该要有一下的基础:

  1. JavaScript基础,node.js、ES6基础
  2. XML文件、Html文件基础、CSS基础
  3. 了解flex布局

有了以上的基础知识,在官方文档的指导下,绝对能够快速地进行小程序的开发。

项目实战

项目结构

现在只开发了一个简单的天气页面,因此只写了index页面建立了weather相关的页面。

项目结构

app.js

这个文件相当于Android 程序中的application,整个程序只有一个app.js到单例,因此程序的各种生命周期的回调都在这里,并且可以存储一下程序的全局数据以及变量,例如用户数据等。

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 {
      //调用登录接口
      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:

这个相当于是程序的路由表以及配置表,包括程序的页面注册、网络配置、底部导航栏、顶部导航栏的配置都可以在这里编写,具体的可以在官方文档里进行查看。

{
  "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的全局配置,现在来编写具体的页面。

预期的页面是这个样子的设计。

天气界面

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>空气指数:{{weather.suggestion.air.brf}},{{weather.suggestion.air.txt}}</text>
    <text>舒适度指数:{{weather.suggestion.comf.brf}},{{weather.suggestion.comf.txt}}</text>
    <text>洗车指数:{{weather.suggestion.cw.brf}},{{weather.suggestion.cw.txt}}</text>
    <text>穿衣指数:{{weather.suggestion.drsg.brf}},{{weather.suggestion.drsg.txt}}</text>
    <text>感冒指数:{{weather.suggestion.flu.brf}},{{weather.suggestion.flu.txt}}</text>
    <text>运动指数:{{weather.suggestion.sport.brf}},{{weather.suggestion.sport.txt}}</text>
    <text>旅游指数:{{weather.suggestion.trav.brf}},{{weather.suggestion.trav.txt}}</text>
    <text>紫外线指数:{{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

最后就是页面的数据的获取以及相应的逻辑处理:

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);
  }
})

我将获取位置以及一些数据都封装在了weatherUtil里面,这个天气API是和风天气提供的,可以自己去和风天气官网申请key值:

const baseUrl = 'https://free-api.heweather.com/v5/weather?key=';
const app = getApp();

/**
 * 根据经纬度获取天气
 */
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);
        }
    });
}

/**
 * 获取天气回调
 */
function requestWeatherData(callback) {
    requestLocation((success, latitude, longitude) => {
        if (success == false) {
            latitude = 120.343;
            longitude = 36.088;
        }
        requestWeatherByLocation(latitude, longitude, callback);
    });
}

/**
 * 解析数据
 */
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;
}

/**
 * 获取位置信息,返回经纬度
 */
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,以上就是一个简单的天气页面的开发。

总之,按照官方文档的指导,很轻松就能够制作一个简单的微信小程序。

总结

通过开发这个简答的天气小程序,收获了不少,但是也不得不吐槽一下微信小程序的设计。

  1. 开发十分简单,只要掌握简单的JavaScript基础就能够快速开发。
  2. 提供了较为完整的组件以及各种API
  3. API设计比较蛋疼,有些设计得不太好。
  4. 在程序里使用网络请求需要进行指定对应的域名,否则不能够访问。
  5. 程序的提交审核比较快,我的大概是用了一天的时间就申请好了。

下一个研究的就是ReactNative,之后会用RN开发一个Lite天气。
项目源码:https://github.com/nickming/WXLiteWeather
欢迎star

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,373评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,732评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,163评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,700评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,036评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,425评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,737评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,421评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,141评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,398评论 2 243
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,908评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,276评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,907评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,018评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,772评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,448评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,325评论 2 261

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,544评论 25 707
  • 你也在玩小程序?这些基本原理你知道吗? 微信小程序使用了前端技术栈JavaScript/WXML/WXSS。...
    奋斗的愤青i阅读 2,077评论 0 4
  • 突然发现这哥们很牛……无它……
    逗霸君阅读 209评论 0 2
  • 在儿童乐园当管理员的时候,我每天都会看到很多可爱的小朋友。有一天一个大约8,9岁的小女孩吸引了我的注意。 她在父母...
    陆艳如阅读 325评论 0 0
  • 【读书心语】遇见从美好开始。每次遇见都在人生剧本上增添了一些剧本题材和剧情章节,我们有时是主角有时是配角,因为每次...
    佛前的那朵青莲阅读 118评论 0 0