【微信小程序学习笔记02理解与初始准备】【实战天气微信小程序】

目录

参与的udacity 微信小程序的纳米学位期间的学习笔记,其中代码或描述若有不足部分敬请指点,万分感谢!

  • 目录
  • 注册小程序账号,获取AppID
  • 开发准备
    • 目录结构
    • 删快速模板中不必要的代码
  • 视图层
    • 何为WXML
        • 数据绑定
        • 列表渲染
        • 条件渲染
        • 模板
        • 事件
    • 何为WXSS
  • 实战天气wxapp
    • 效果
    • 配置(因为用到别人写好的模拟天气数据的API作练习,为避免跨域问题)
    • 代码
    • 直接编译对应开发页码
    • 涉及的核心知识点
  • 实战天气的代码完整下载
  • 快捷链接

注册小程序账号,获取AppID

要在手机微信上运行测试小程序,必须获取AppID。

开发准备

目录结构

当下基于ReactJs的AntDesignPro v2.0版本的目录使用了umiJs作为项目脚手架。与wxApp一样是基于功能与页面的维度的目录结构不再扁平化。特点都是:结构更加清晰,减少耦合(独立,增加可维护性,),一删全删,方便 copy 和共享。

├── images ##推荐公共图片等资源放在此处!
├── pages                     # 业务页面入口和常用模板
│   ├── index                # 同类型页面文件夹(基于功能与页面的维度的目录结构)
│    │   - index.js          ## 页面数据逻辑(必须)
│    │   - index.wxml        ## 页面结构(必须)
│    │   - index.wxss        ## 页面样式表(非必须)
│    │   - index.jason       ## 页面配置(非必须)
│   └── logs                  # 日志
│       ├── logs.wxml
│       └── logs.js
├── utils                      # 工具类
├── app.js                     # 小程序逻辑(必须)
├── app.wxss                   # 小程序公共样式表(非必须)
├── app.jason                  # 小程序公共配置(必须)!决定页面路径、窗口、网络超时时间、设置tab 

为了方便开发者减少配置项,描述页面的四个文件必须具有相同的路径与文件名。

删快速模板中不必要的代码

  1. 删除 app.js 中的所有代码。 这里会存储整个小程序会执行的一些逻辑,例如权限获取等。我们暂时不需要。
  2. 删除 app.wxss 中的所有代码。这里会存储整个小程序的一些样式。我们暂时不需要。
  3. 删除 app.json 中的第四行 “pages/logs/logs” 以及第三行最后的逗号,这里声明了小程序的第二个页面,我们暂时不需要。
  4. 删除 pages/logs 文件夹以及其中的所有文件。这里定义了小程序的第二个页面,我们暂时不需要。
  5. 删除 utils 文件夹以及其中的所有文件。 这里定义了一些用途函数,我们暂时不需要。
  6. 删除 index.js 中的所有代码,这里会定义 index 页面的逻辑。只保留一行 Page({})
  7. 删除 index.wxml 中的所有代码,这里会定义 index 页面的布局。只保留一行
<view class="title">hello world!view>
  1. 删除 index.wxss 中的所有代码,这里会定义 index 页面的样式。只保留
.title { margin-top: 300rpx; text-align: center; }

视图层

何为WXML

WeiXin Markup Language是框架设计的一套标签语言。与HTML的基本功能一样用于构建出页面的结构。其次还能实现数据绑定,列表渲染,条件渲染,模板(可理解为想ReactJs之类js框架中的component),事件。

数据绑定

 <view> {{message}} view>

列表渲染

 <view wx:for="{{array}}"> {{item}} view>

条件渲染

 <view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW view>

模板

 <template name="staffName"> <view> FirstName: {{firstName}}, LastName: {{lastName}} view> template> <template is="staffName" data="{{...staffA}}">template> <template is="staffName" data="{{...staffB}}">template> <template is="staffName" data="{{...staffC}}">template>
// page.js
Page({ data: { staffA: {firstName: 'Hulk', lastName: 'Hu'}, staffB: {firstName: 'Shang', lastName: 'You'}, staffC: {firstName: 'Gideon', lastName: 'Lin'} } })

事件

<view bindtap="add"> {{count}} view>

何为WXSS

WeiXin Style Sheets是一套样式语言,用于描述 WXML 的组件样式。WXSS 具有 CSS 大部分特性。为性能着想,依旧不建议使用内联样式。

与 CSS 相比,WXSS 扩展的特性
1. 尺寸单位rpx:可以根据屏幕宽度进行自适应。规定屏幕宽为750rpx。如在 iPhone6 上,屏幕宽度为375px,共有750个物理像素,则750rpx = 375px = 750物理像素,1rpx = 0.5px = 1物理像素。同理iPhone6 Plus 1rpx = 0.552px= 1物理像素。
2. 使用@import语句可以导入外联样式表,@import后跟需要导入的外联样式表的相对路径
3. 支持的选择器:类、id、元素、和(,)、::after、::before
4. 全局(app.wxss)与局部(对应page文件夹里的.wxss,注意!会覆盖 app.wxss 中相同的选择器

实战天气wxapp

效果

配置(因为用到别人写好的模拟天气数据的API作练习,为避免跨域问题)

【微信小程序学习笔记02理解与初始准备】【实战天气微信小程序】_第1张图片

代码

weather.wxml

<view class='contain'> <button class="location-wrapper" open-type="{{ locationAuthType==1 ? 'openSetting' : ''}}" bindopensetting="onTapLocation" bindtap="onTapLocation" plain="true"> <view class="location"> <image class="location-icon" src="/img/icon/location-icon.png">image> <view class="location-text">{{city}}view> view>  <view wx:if="{{locationAuthType==0}}"class="location-tips">点击获取当前位置view> <view wx:if="{{locationAuthType==1}}"class="location-tips">点击开启位置权限view> <view wx:if="{{locationAuthType==2}}"class="location-tips">view> button> <view class="title">{{nowTemp}}view> <view class="weather">{{nowWeather}}view> <image class='weatherBg' src='{{bgUrl}}'>image> <view class="day-weather" bindtap = "onTapDayWeather"> <view class="day-text">{{todayDate}}view> <view class="temp-text">{{todayTemp}}view> <image class="arrow-icon" src="/img/icon/arrow.png">image> view> view> <view class="timeTitle"> <image class="timeTitleIcon" src="/img/icon/time-icon.png">image> <view class="timeTitleText">未来24小时天气预测view> view> <scroll-view class='scrollView' scroll-x style="width: 100%"> <view class='list'> <view class='listItem' wx:key="index" wx:for="{{forecast}}"> <view class= 'item'>{{item.time}}view> <image class= 'itemImg' src='{{item.img}}'>image> <view class= 'item'>{{item.temp}}view> view> view> scroll-view> 

weather.js

// 初始化常量:中文天气、天气对应的nav颜色
const weatherMap = {
  'sunny': '晴天',
  'cloudy': '多云',
  'overcast': '阴天',
  'lightrain': '小雨',
  'heavyrain': '大雨',
  'snow': '雪'
}
const weatherColorMap = {
  'sunny': '#cbeefd',
  'cloudy': '#deeef6',
  'overcast': '#c6ced2',
  'lightrain': '#bdd5e1',
  'heavyrain': '#c5ccd0',
  'snow': '#aae1fc'
}
// 腾讯:通过经纬度得出对应位置的城市
const QQMapWX = require('../../libs/qqmap-wx-jssdk.js')
// 未弹窗
const UNPROMPTED = 0
// 无权限
const UNAUTHORIZED = 1
// 已同意
const AUTHORIZED = 2 
Page({
  data:{
    nowTemp: '14°',
    nowWeather: '阴天',
    bgUrl:"",
    forecast:[],
    todayTemp: "",
    todayDate: "",
    city:"广州市",
    locationAuthType: UNPROMPTED
  },

  onLoad(){
    // 实例化API核心类
    this.qqmapsdk = new QQMapWX({
      key: 'EAXBZ-33R3X-AA64F-7FIPQ-BY27J-5UF5B'
    });
    // 无参调用getNow则无停止刷新时间
    wx.getSetting({
      success: res => {
        let auth = res.authSetting['scope.userLocation']
        this.setData({
          locationAuthType: auth ? AUTHORIZED
            : (auth === false) ? UNAUTHORIZED : UNPROMPTED
        })

        if (auth)
          this.getCityAndWeather()
        else
          this.getNow() //使用默认城市广州
      },
      fail: () => {
        this.getNow() //使用默认城市广州
      }
    })
  },

  // callback为停止刷新函数参数
  getNow(callback) {
    // 发起网络请求url请求链接、data请求参数
    wx.request({
      url: 'https://test-miniprogram.com/api/weather/now',
      data: {
        city: this.data.city
      },
      success: res => {
        let result = res.data.result
        let now = result.now
        let forecastRes = result.forecast
        let forecast=[];
        let nowHour = new Date().getHours()
        for (let i = 0; i < 8; i += 1) {
          forecast.push({
            time: (i*3 + nowHour) % 24 +'时',
            img: '/img/icon/' + forecastRes[i].weather+'-icon.png',
            temp: forecastRes[i].temp+'°'
          })
        }
        forecast[0].time = "现在";
        this.setToday(result.today);
        this.setData({
          nowTemp: now.temp + '°',
          nowWeather: weatherMap[now.weather],
          bgUrl: '/img/' + now.weather + '-bg.png',
          forecast: forecast
        })
        // 根据weather设置对应头部颜色
        wx.setNavigationBarColor({
          frontColor: '#000000',
          backgroundColor: weatherColorMap[now.weather],
        })
      },
      // 在完成刷新(无论成功失败)都调用
      complete: () => {
        // &&当callback存在则调用下拉刷新动作的函数
        callback && callback()
      }
    })
  },

  // 下拉刷新
  onPullDownRefresh: function () {
    // 下拉刷新是调用getNow方法并返回一个停止下拉刷新动作的函数为参数
    this.getNow(() => { wx.stopPullDownRefresh() }) }, setToday(result) { let date = new Date() this.setData({ todayTemp: `${result.minTemp}° - ${result.maxTemp}°`, todayDate: `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()} 今天` }) }, onTapDayWeather() { // wx.showToast() wx.navigateTo({ url: '/pages/weather/list/list?city='+this.data.city, }) }, onTapLocation() { this.getCityAndWeather() }, getCityAndWeather() { wx.getLocation({ success: res => { //调用接口 this.qqmapsdk.reverseGeocoder({ location: { latitude: res.latitude, longitude: res.longitude }, success: res => { let city = res.result.address_component.city this.setData({ city: city, locationAuthType: AUTHORIZED }) this.getNow() }, fail: () => { console.log("city fail"); } }) }, fail: () => { console.log("locat fail"); this.setData({ locationAuthType: UNAUTHORIZED, }) } }) } })

list.wxml

<view> <view class='date-item' wx:for="{{weekWeather}}"> <view class="date-wrapper"> <view class="day">{{item.day}}view> <view class="date">{{item.date}}view> view> <view class="temp">{{item.temp}}view> <image class="weather-icon" src="{{item.iconPath}}">image> view> view>

list.js

const dayMap = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
Page({
  date: {
    weekWeather: []
  },
  onLoad(options) {
    this.setData({
      city: options.city
    })

    this.getWeekWeather()
  },
  onPullDownRefresh() {
    this.getWeekWeather(() => { wx.stopPullDownRefresh() }) }, getWeekWeather(callback) { wx.request({ url: 'https://test-miniprogram.com/api/weather/future', data: { time: new Date().getTime(), city: this.data.city }, success: res => { let result = res.data.result this.setWeekWeather(result) }, complete: () => { callback && callback() } }) }, setWeekWeather(result) { let weekWeather = [] for (let i = 0; i < 7; i++) { let date = new Date() date.setDate(date.getDate() + i) weekWeather.push({ day: dayMap[date.getDay()], date: `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`, temp: `${result[i].minTemp}° - ${result[i].maxTemp}°`, iconPath: '/img/icon/' + result[i].weather + '-icon.png' }) } weekWeather[0].day = '今天' this.setData({ weekWeather: weekWeather }) } }) 

直接编译对应开发页码

【微信小程序学习笔记02理解与初始准备】【实战天气微信小程序】_第2张图片

【微信小程序学习笔记02理解与初始准备】【实战天气微信小程序】_第3张图片

涉及的核心知识点

  1. 生命周期——进入第二页,返回第一页的生命周期顺序理解:
//初始页
onLoad
onShow
onReady
onHide
//进入第二页,则第一页隐藏(并没有卸载)
onLoad
onShow
onReady
onUnload
//返回第一页(第二页卸载,且由于第二页还存在只是隐藏了而已无需再加载和准备页面,所以只调用了onshow
  1. 调用API(wx.request)
  2. 异步调用:所有生命周期函数、所有手势响应函数、所有函数类型的参数
  3. 理解setData中的异步和同步(调用 setData 之后,this.data 的值将会立即改变。然而,小程序的页面(即视图层)需要等待页面再次渲染才能够更新。总结:页面数据无需刷新的重新渲染对应部分为异步,赋值为同步);与React中的status很相似(直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。)
  4. 下拉刷新(配置开启下拉刷新+且要注意每次下拉刷新后无论成功与否都要使用wx.stopPullDownRefresh())
  5. 按钮响应(bindTap)
  6. 页面跳转并能传参(wx.navigateTo)
  7. 获取位置(通过 wx.getLocation 获取当前经纬度,通过百度api将经纬度转换为城市)
  8. 条件渲染(wx.if)

实战天气的代码完整下载

我学习微信小程序的整理,不仅仅只有天气! clickHere 》

快捷链接

全部React学习笔记的目录 Click Here>>
全部Javascript学习笔记的目录 Click Here>>
Less学习笔记 Click Here>>
安利一波前端开发推荐使用的工具 Click Here>>
ESLint问题记录 Click Here>>
github各类实战练习源码下载 Click Here>>
如果你觉得我的东西能帮到你,无限欢迎给我的github库点个收藏Star~0v 0~

你可能感兴趣的:(小程序)