当前位置: 首页 > 新闻动态 > 软件编程

微信小程序基于高德地图API实现天气组件(动态效果)

作者:用户投稿 浏览: 发布日期:2026-01-11
[导读]:这篇文章主要介绍了微信小程序基于高德地图API实现天气组件(动态效果),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
目录
  • 1.组件介绍
    • 1.1 组件效果预览图
    • 1.2 构造形式
    • 1.3 支持的动画效果
  • 2.组件的使用
    • 2.1 自定义模式
    • 2.2 默认模式
  • 4.组件代码

    ​在社区翻腾了许久,没有找到合适的天气插件。迫不得已,只好借鉴互联网上的web项目,手动迁移到小程序中使用。现在分享到互联网社区中,帮助后续有需要的开发者。

    1.组件介绍

    1.1 组件效果预览图

    ​小程序组件继承了外部样式colorui的色彩,但实际动画会根据父节点的color属性自动填充颜色,即使不引入colorui这个样式库,也可以在该组件引用外定义一个有color属性的块包裹该组件,同样可以达到如图的效果。

    1.2 构造形式

    1.3 支持的动画效果

    简单介绍下,动画由3个部分组成

    一个是主体块,这几个动画中的大云朵就是;第二个是背景块,如第一个中的太阳和第三个中的多层云;第三个就是状态块,如第一个中的雨水和第二个中的雷。每个块有且仅能展示一个。可以根据自己的需要,自行组合这几个块,来满足对应的天气需求。

    注:如想要实现雷雨交加的效果,需要定义两个动画,一个是雷一个是雨,然后通过定时器进行动画的来回切换,如果有完成的可以在评论里留下代码,我懒得实现了,哈哈。

    2.组件的使用

    组件的使用,需要授权获取位置信息,在app.json中配置授权。

    "permission": {
     "scope.userLocation": {
      "desc": "你的位置信息将用于定位效果和天气信息展示"
     }
     }

    组件配置完成后,在全局app.json中进行引入。

    "usingComponents": {
     "uweather":"animation/uweather/weather"
     }

    组件有两种模式:

    用户自定义模式默认模式(引入amap-wx.js,申请高德地图key,具体步骤参见参考文档第一个)

    • 用户自定义模式下,所有的信息包括动画和信息展示,都由用户传入的信息来控制。
    • 默认模式下,即用户未传入任何信息,这时候组件就会基于位置信息,请求高德地图对应接口来获取地理位置及其天气信息。

    组件在被创建的时候会检测是否有对应值的传入,如果有值传入,那么就是用户自定义模式,如果没有值传入,那么就是默认模式。

    lifetimes:{
     attached(){
      if(this.properties.winfo == null){
      this.setData({
       amapPlugin: new amap.AMapWX({
       key: this.data.key
       })
      },()=>{
       //获取天气信息
       this.getWeather()
      })
      }
     }
     },

    2.1 自定义模式

    自定义模式下,传入的数据要按照规定的的格式(也可以自己修改组件的属性值)

    例如在page中配置的属性如下

    weather:'雷',
     winfo:{
      province:'自定义省份',
      city:'自定义城市',
      temperature:'自定义温度',
      weather:'自定义天气',
      winddirection:'自定义风向',
      windpower:'自定义风力'
     }

    wxml页面中的组件使用如下

    <uweather
    	weather="{{weather}}"
    	winfo="{{winfo}}"
    >
    </uweather>

    那么对应的组件展示效果就是这样子的

    2.2 默认模式

    ​默认模式需要获得用户的地理位置信息授权,确认在app.json中进行了授权配置和使用组件前完成了授权信息的校验。

    ​组件生命周期会在每一次组件被装如页面树时,监听是否有对应数据的传入,如果没有,就会请求对应的接口,获取地图信息。使用默认方法,还需要配置 https://restapi.amap.com 为合法的request域名和申请对应的key用于开发,申请步骤参见参考文档。

    ​默认模式下不需要传入任何参数,直接引入组件即可。

    <uweather> </uweather>

    3.组件使用注意事项

    ​默认方法的天气返回值具有很多种,具体使用还需要自己修改组件,完成不同天气到对应动画的映射,例如小雨、中雨、大雨都可以映射到这个动画状态。下图是高德地图天气API的部分信息,全部请参见参考文档。

    4.组件代码

    ​详细的组件在项目中的使用结构 请看[开源项目](miniprogram/animation/uweather · Kindear/校园小程序 - 码云 - 开源中国 (gitee.com)),记得给个⭐,感谢。

    uweather.js

    // animation/uweather/rain.js
    const amap = require('../../lib/amap-wx.js');
    Component({
     options: {
     addGlobalClass: true,
     multipleSlots: true
     },
     /**
     * 组件的属性列表
     */
     properties: {
     weather:{
      type:String,
      value:'',
      observer:function(n,o){
      //天气变化
      }
     },
     winfo:{
      type:Object,
      value:null,
      observer:function(n,o){
      //如果有自定义的值就使用自定义的值
       this.setData({
       obj:n
       })
      }
     }
     },
    
     /**
     * 组件的初始数据
     */
     data: {
     amapPlugin: null,
     key: "6799b5f6f88d3d9fb52ac244855a8759",
     obj:{},
     },
     lifetimes:{
     attached(){
      if(this.properties.winfo == null){
      this.setData({
       amapPlugin: new amap.AMapWX({
       key: this.data.key
       })
      },()=>{
       this.getWeather()
      })
      }
     }
     },
     /**
     * 组件的方法列表
     */
     methods: {
     //获取天气数据
     getWeather:function(){
     wx.showLoading({
      title: '请稍候...'
     })
    
     // type:天气的类型。默认是live(实时天气),可设置成forecast(预报天气)。
     // city:城市对应的adcode,非必填。为空时,基于当前位置所在区域。 如:440300,返回深圳市天气
     // success(data) :调用成功的回调函数。
     // fail(info) :调用失败的回调函数。
     this.data.amapPlugin.getWeather({
      success: (data) =>{
      //成功回调
      console.log(data)
      wx.hideLoading()
      this.setData({
       obj:data.liveData,
       
      })
      if(this.properties.weather == ''){
       this.setData({
       weather:data.liveData.weather
       })
      }
      },
      fail: function (info) {
      //失败回调
      console.log(info)
      }
     })
     },
     }
    })

    uweather.wxml

    <view class="padding-sm">
    		<view class="bg-gradual-blue padding radius shadow-blur" style="display: flex;flex-direction: row;">
    			<view style="width:50%;height:100%;color:#1A94E6;">
    				<view class="icon sun-shower " wx:if="{{weather == '太阳雨'}}">
    					<view class="cloud"></view>
    					<view class="sun"><view class="rays"></view></view>
    					<view class="rain"></view>
    				</view>
    				<view class="icon sun-shower " wx:if="{{weather == '多云'}}">
    					<view class="cloud"></view>
    					<view class="sun"><view class="rays"></view></view>
    				</view>
    				<view class="icon thunder-storm" wx:if="{{weather == '雷'}}">
    					<view class="cloud"></view>
    					<view class="lightning">
    						<view class="bolt"></view>
    						<view class="bolt"></view>
    					</view>
    				</view>
    				<view class="icon cloudy" wx:if="{{weather == '阴'}}">
    					<view class="cloud"></view>
    					<view class="cloud"></view>
    				</view>
    				<view class="icon flurries" wx:if="{{weather == '雪'}}">
    					<view class="cloud"></view>
    					<view class="snow">
    						<view class="flake"></view>
    						<view class="flake"></view>
    					</view>
    				</view>
    				<view class="icon sunny" wx:if="{{weather == '晴'}}">
    					<view class="sun"><view class="rays"></view></view>
    				</view>
    				<view class="icon rainy" wx:if="{{weather == '雨'}}"><view class="cloud"></view></view>
    			</view>
    			<!--文字部分-->
    			<view style="width:50%;height:100%;">
    		<view class="title">
    			<view class="text-cut" style="margin-top:20rpx;">{{obj.province}}-{{obj.city}}</view>
    			<!--view class="text-cut">湿度:{{obj.humidity.data}}</view-->
    			<view class="text-cut" style="margin-top:20rpx;">温度:{{obj.temperature}}℃</view>
    			<view class="text-cut" style="margin-top:20rpx;">天气:{{obj.weather}}</view>
    			<view class="text-cut" style="margin-top:20rpx;">{{obj.winddirection}}风{{obj.windpower}}级</view>
    		</view>
    			</view>
    		</view>
    	</view>

    uweather.wxss

    body {
     max-width: 42em;
     padding: 2em;
     margin: 0 auto;
     color: #161616;
     font-family: 'Roboto', sans-serif;
     text-align: center;
     background-color: currentColor;
    }
    
    h1 {
     margin-bottom: 1.375em;
     color: #fff;
     font-weight: 100;
     font-size: 2em;
     text-transform: uppercase;
    }
    p,
    a {
     color: rgba(255,255,255,0.3);
     font-size: small;
    }
    p { margin: 1.375rem 0; }
    
    .icon {
     position: relative;
     display: inline-block;
     width: 12em;
     height: 10em;
     font-size: 1em; /* control icon size here */
    }
    
    .cloud {
     position: absolute;
     z-index: 1;
     top: 50%;
     left: 50%;
     width: 3.6875em;
     height: 3.6875em;
     margin: -1.84375em;
     background: currentColor;
     border-radius: 50%;
     box-shadow:
     -2.1875em 0.6875em 0 -0.6875em,
     2.0625em 0.9375em 0 -0.9375em,
     0 0 0 0.375em #fff,
     -2.1875em 0.6875em 0 -0.3125em #fff,
     2.0625em 0.9375em 0 -0.5625em #fff;
    }
    .cloud:after {
     content: '';
     position: absolute;
     bottom: 0;
     left: -0.5em;
     display: block;
     width: 4.5625em;
     height: 1em;
     background: currentColor;
     box-shadow: 0 0.4375em 0 -0.0625em #fff;
    }
    .cloud:nth-child(2) {
     z-index: 0;
     background: #fff;
     box-shadow:
     -2.1875em 0.6875em 0 -0.6875em #fff,
     2.0625em 0.9375em 0 -0.9375em #fff,
     0 0 0 0.375em #fff,
     -2.1875em 0.6875em 0 -0.3125em #fff,
     2.0625em 0.9375em 0 -0.5625em #fff;
     opacity: 0.3;
     transform: scale(0.5) translate(6em, -3em);
     animation: cloud 4s linear infinite;
    }
    .cloud:nth-child(2):after { background: #fff; }
    
    .sun {
     position: absolute;
     top: 50%;
     left: 50%;
     width: 2.5em;
     height: 2.5em;
     margin: -1.25em;
     background: currentColor;
     border-radius: 50%;
     box-shadow: 0 0 0 0.375em #fff;
     animation: spin 12s infinite linear;
    }
    .rays {
     position: absolute;
     top: -2em;
     left: 50%;
     display: block;
     width: 0.375em;
     height: 1.125em;
     margin-left: -0.1875em;
     background: #fff;
     border-radius: 0.25em;
     box-shadow: 0 5.375em #fff;
    }
    .rays:before,
    .rays:after {
     content: '';
     position: absolute;
     top: 0em;
     left: 0em;
     display: block;
     width: 0.375em;
     height: 1.125em;
     transform: rotate(60deg);
     transform-origin: 50% 3.25em;
     background: #fff;
     border-radius: 0.25em;
     box-shadow: 0 5.375em #fff;
    }
    .rays:before {
     transform: rotate(120deg);
    }
    .cloud + .sun {
     margin: -2em 1em;
    }
    
    .rain,
    .lightning,
    .snow {
     position: absolute;
     z-index: 2;
     top: 50%;
     left: 50%;
     width: 3.75em;
     height: 3.75em;
     margin: 0.375em 0 0 -2em;
     background: currentColor;
    }
    
    .rain:after {
     content: '';
     position: absolute;
     z-index: 2;
     top: 50%;
     left: 50%;
     width: 1.125em;
     height: 1.125em;
     margin: -1em 0 0 -0.25em;
     background: #0cf;
     border-radius: 100% 0 60% 50% / 60% 0 100% 50%;
     box-shadow:
     0.625em 0.875em 0 -0.125em rgba(255,255,255,0.2),
     -0.875em 1.125em 0 -0.125em rgba(255,255,255,0.2),
     -1.375em -0.125em 0 rgba(255,255,255,0.2);
     transform: rotate(-28deg);
     animation: rain 3s linear infinite;
    }
    
    .bolt {
     position: absolute;
     top: 50%;
     left: 50%;
     margin: -0.25em 0 0 -0.125em;
     color: #fff;
     opacity: 0.3;
     animation: lightning 2s linear infinite;
    }
    .bolt:nth-child(2) {
     width: 0.5em;
     height: 0.25em;
     margin: -1.75em 0 0 -1.875em;
     transform: translate(2.5em, 2.25em);
     opacity: 0.2;
     animation: lightning 1.5s linear infinite;
    }
    .bolt:before,
    .bolt:after {
     content: '';
     position: absolute;
     z-index: 2;
     top: 50%;
     left: 50%;
     margin: -1.625em 0 0 -1.0125em;
     border-top: 1.25em solid transparent;
     border-right: 0.75em solid;
     border-bottom: 0.75em solid;
     border-left: 0.5em solid transparent;
     transform: skewX(-10deg);
    }
    .bolt:after {
     margin: -0.25em 0 0 -0.25em;
     border-top: 0.75em solid;
     border-right: 0.5em solid transparent;
     border-bottom: 1.25em solid transparent;
     border-left: 0.75em solid;
     transform: skewX(-10deg);
    }
    .bolt:nth-child(2):before {
     margin: -0.75em 0 0 -0.5em;
     border-top: 0.625em solid transparent;
     border-right: 0.375em solid;
     border-bottom: 0.375em solid;
     border-left: 0.25em solid transparent;
    }
    .bolt:nth-child(2):after {
     margin: -0.125em 0 0 -0.125em;
     border-top: 0.375em solid;
     border-right: 0.25em solid transparent;
     border-bottom: 0.625em solid transparent;
     border-left: 0.375em solid;
    }
    
    .flake:before,
    .flake:after {
     content: '\2744';
     position: absolute;
     top: 50%;
     left: 50%;
     margin: -1.025em 0 0 -1.0125em;
     color: #fff;
    
     opacity: 0.2;
     animation: spin 8s linear infinite reverse;
    }
    .flake:after {
     margin: 0.125em 0 0 -1em;
     font-size: 1.5em;
     opacity: 0.4;
     animation: spin 14s linear infinite;
    }
    .flake:nth-child(2):before {
     margin: -0.5em 0 0 0.25em;
     font-size: 1.25em;
     opacity: 0.2;
     animation: spin 10s linear infinite;
    }
    .flake:nth-child(2):after {
     margin: 0.375em 0 0 0.125em;
     font-size: 2em;
     opacity: 0.4;
     animation: spin 16s linear infinite reverse;
    }
    
    
    /* Animations */ 
    
    @keyframes spin {
     100% { transform: rotate(360deg); }
    }
    
    @keyframes cloud {
     0% { opacity: 0; }
     50% { opacity: 0.3; }
     100% {
     opacity: 0;
     transform: scale(0.5) translate(-200%, -3em);
     }
    }
    
    @keyframes rain {
     0% {
     background: #0cf;
     box-shadow:
      0.625em 0.875em 0 -0.125em rgba(255,255,255,0.2),
      -0.875em 1.125em 0 -0.125em rgba(255,255,255,0.2),
      -1.375em -0.125em 0 #0cf;
     }
     25% {
     box-shadow:
      0.625em 0.875em 0 -0.125em rgba(255,255,255,0.2),
      -0.875em 1.125em 0 -0.125em #0cf,
      -1.375em -0.125em 0 rgba(255,255,255,0.2);
     }
     50% {
     background: rgba(255,255,255,0.3);
     box-shadow:
      0.625em 0.875em 0 -0.125em #0cf,
      -0.875em 1.125em 0 -0.125em rgba(255,255,255,0.2),
      -1.375em -0.125em 0 rgba(255,255,255,0.2);
     }
     100% {
     box-shadow:
      0.625em 0.875em 0 -0.125em rgba(255,255,255,0.2),
      -0.875em 1.125em 0 -0.125em rgba(255,255,255,0.2),
      -1.375em -0.125em 0 #0cf;
     }
    }
    
    @keyframes lightning {
     45% {
     color: #fff;
     background: #fff;
     opacity: 0.2;
     }
     50% {
     color: #0cf;
     background: #0cf;
     opacity: 1;
     }
     55% {
     color: #fff;
     background: #fff;
     opacity: 0.2;
     }
    }

    参考文档

    入门指南-微信小程序SDK | 高德地图API (amap.com)

    天气查询-API文档-开发指南-Web服务 API | 高德地图API (amap.com)

    校园小程序: 基于强智教务系统的校园服务类小程序--多校版本(默认 山科)使用云开发 (gitee.com)

    免责声明:转载请注明出处:http://sczxchw.cn/news/563537.html

    扫一扫高效沟通

    多一份参考总有益处

    免费领取网站策划SEO优化策划方案

    请填写下方表单,我们会尽快与您联系
    感谢您的咨询,我们会尽快给您回复!