您的位置:首页 > 移动开发 > 微信开发

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

2018-09-16 16:20 585 查看
版权声明:本文为博主原创文章,未经博主允许不得转载。(github:KuanG97) https://blog.csdn.net/m0_37136491/article/details/82694331

目录

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

  • 视图层
  • 何为WXSS
  • 实战天气wxapp
  • 实战天气的代码完整下载
  • 快捷链接
  • 注册小程序账号,获取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),事件。

    数据绑定

    <!--wxml-->
    <view> {{message}} </view>

    列表渲染

    <!--wxml-->
    <view wx:for="{{array}}"> {{item}} </view>

    条件渲染

    <!--wxml-->
    <view wx:if="{{view == 'WEBVIEW'}}"> WEBVIEW </view>

    模板

    <!--wxml-->
    <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作练习,为避免跨域问题)

    代码

    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>
    <!-- 0: 未弹窗, 1: 已拒绝, 2: 已同意 -->
    <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
    })
    }
    })

    直接编译对应开发页码

    涉及的核心知识点

    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~

    阅读更多
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: