概述
在实际工作中,App既需要支持Android手机,又要支持IOS手机,还要支持微信小程序,公众号等,面对这样的需求,是否劳心费力,苦不堪言,还要考虑各平台的兼容性。现在uni-app以“开发一次,多端覆盖”的理念,海纳百川,求同存异,受到大多数开发者的青睐。uni-app是采用vue.js作为开发前端应用的框架,开发者编写一套代码,可发布到iOS、Android、Web(响应式)、以及各种小程序(微信/支付宝/百度/头条/QQ/钉钉/淘宝)、快应用等多个平台。本文以一个天气预报的小例子,简述uni-app的开发步骤。
为什么选择uni-app ?
- uni-app实现了一套代码,同时运行到多个平台。
- uni-app在开发者数量、案例、跨端抹平度、扩展灵活性、性能体验、周边生态、学习成本、开发成本等8大关键指标上拥有更强的优势。
- DCloud为uni-app开发提供了开发利器HBuilderX,以其轻巧极速,强大的语法提示,清爽护眼,和专为vue量身打造的优势,吸引了大多数的开发者。
uni-app目录结构
一个uni-app工程,默认包含如下目录及文件,如下图所示:
uni-app应用生命周期
注意:应用生命周期仅可在App.vue
中监听,在其它页面监听无效。
uni-app页面生命周期
关于其他uni-app介绍,可以参考uni-app官网
示例效果图
本次开发是一个天气预报的小例子,在Chrome浏览器里面如下图所示:
在Android手机上如下所示:
源码分析
在uni-app开发小例子时,为了代码的复用,自定义三个组件,包括,风车组件,圆形进度球组件,天气组件。源码分别如下:
(一)圆形进度球组件
组件包含三部分,分别是页面(template),脚本(JavaScript),样式(CSS),源码如下:
1 <template> 2 view class="content" 3 ="progress" 4 ="progress_outer" 5 ="progress_inner"></view 6 ="progress_masker" :style="maskStyle" 7 </ 8 ="progress_value">{{cvalue}}% 9 10 11 >
脚本(JavaScript)代码如下:
1 <script> 2 export default { 3 props: { 4 cvalue: { // 进度条百分比 6 type: Number, 7 default: 10,1)"> 8 },1)"> 9 },1)">10 data() { 12 return13 14 }; 15 16 computed: { 17 maskStyle(){ 18 var top=100-this.cvalue; 19 return {marginTop : top + '%'}; 20 21 22 } 23 24 } 25 </script>
样式(CSS)代码如下:
1 <style> 2 .content{ 3 width: 200rpx; 4 height: 5 display: block; 6 Box-sizing: border-Box; 7 } 8 .progress { 9 position: relative; 10 11 12 padding: 0; 13 14 } 15 .progress_outer 16 { 17 height:100%; 18 width:19 background-color:gray; 20 border-radius:calc(100%/2); 21 border:5px solid rgba(0,0.1); 22 padding:0; 23 Box-shadow: 0px 2px 4px #555555; 24 -webkit-Box-shadow:25 -moz-Box-shadow:26 position: absolute; 27 Box-sizing:28 overflow: hidden; 29 30 } 31 .progress_inner 32 { 33 height:34 width:35 border:1px solid yellow; 36 border-radius:37 position:absolute; 38 background-color:white; 39 text-align:center; 40 Box-sizing:41 42 } 43 .progress_masker 44 { 45 46 47 background: -webkit-gradient(linear,center top,center bottom,from(#0ff),to(#0f0)); 48 -moz-linear-gradient( top,#fff,#0f0); 49 -o-linear-gradient( top,1)">50 51 52 } 53 .progress_value 54 { 55 56 color:black; 57 font-weight:bolder; 58 transparent; 59 text-align:60 61 margin-top: 90rpx; 62 } 63 </style>
(二)风车组件
风车组件包含两部分,分别是页面(template),样式(CSS),源码如下:
="wind_mill"="cicle" 5 ="vane"="vane1"="vane2" 8 ="vane3" 9 10 ="blade"11 13 14 >
样式(CSS)代码如下:
.wind_mill{ 220rpx; 5 /* background-color: rgba(25,83,157,0.5); */ @keyframes vanflash{ from{transform: rotate(0deg); transform-origin: center;} 10 to{transform: rotate(360deg);transform-origin:11 12 .vane{ 14 15 16 animation-name: vanflash; animation-duration: 5s; animation-iteration-count: infinite; -webkit-animation-name: -webkit-animation-duration: -webkit-animation-iteration-count:22 } 23 .vane1{ 80rpx; 4rpx; background-color: #FFFFFF; border-radius: 5rpx; 29 30 left: 100rpx; 31 top:100rpx; 32 transform: rotate(0deg); transform-origin:left; -webkit-transform:rotate(0deg); 35 36 } 37 .vane2{ 41 42 43 44 rotate(120deg); rotate(120deg); 48 } 49 .vane3{ 52 53 54 rotate(240deg); rotate(240deg); 60 } 61 .cicle{ 62 63 64 90rpx; 65 66 20rpx; 67 68 16rpx; 69 } 70 .blade{ 71 120rpx; 72 10rpx; 73 74 75 76 77 78 rotate(90deg); 79 80 rotate(90deg); 81 } 82 (三)天气组件天气组件,引用了前面两个组件,并有自定义数据内容,如下所示:
View Codescroll-view scroll-y="true" class="main"="current"="district">{{district}}="temp">{{temp}}°C 6 ="temp_range">{{temprange}}="temp_desc">{{tempdesc}}br="temp_src"10 ="temp_src_left">中国气象11 ="temp_src_right">上次更新时间:{{updatetime}}14 scroll-x="true"15 ="hour" enable-flex16 ="each_hour" v-for="item in timelist"17 ="each_hour_time">{{item.time}}18 image :src="item.img" mode="scaleToFill"="each_hour_img" image19 ="each_hour_temp">{{item.temp}}20 21 22 scroll-view24 ="sevenday"25 ="each_day"="item in daylist"26 ="each_day_text"27 {{item.day}} {{item.week}} 28 29 ="each_day_img" :src=""30 ="each_day_temp"31 32 33 34 ="air"35 ="air_title"36 ="" style="flex: 1;">空气质量37 ="text-align: right;flex: 1;">更多>38 39 ="air_body"40 ="air_left"41 airprogress ="airprogress" :cvalue="airvalue"airprogress42 43 ="air_right"44 ="air_content"="item in airlist"45 ="air_content_name">{{item.name}}46 ="air_content_value">{{item.value}}47 48 49 50 51 ="wind"52 ="wind_title"53 >风向风力54 55 56 ="wind_body"57 ="wind_left"58 windmill ="wind01"windmill59 ="wind02"60 61 ="wind_right"62 ="wind_right_direction"63 style="flex: 1;text-align: left;">风向64 >{{winddirection}}65 66 ="wind_right_power"67 >风力68 >{{windpower}}69 70 71 72 73 ="provider">provide by Alan.hsiang74 75 >脚本(JavaScript)代码如下:
View Code2 import windmill from "../windmill/windmill.vue" 3 import airprogress from "../airprogress/airprogress.vue" 4 export 5 components: { windmill,1)"> 7 airprogress props:{ 10 district:{ type:String,1)">12 required:true13 temp:{ type:Number,1)">default:0 18 temprange:{ 19 20 21 tempdesc:{ 23 24 25 26 updatetime:{ 28 29 30 timelist:{ 31 type:Array,1)">32 33 34 daylist:{ 35 36 37 38 airvalue:{ 39 default:1041 42 43 airlist:{ 44 45 46 47 winddirection:{ 48 49 50 51 windpower:{ 52 53 54 } 55 56 57 58 59 60 61 62 63 </script>样式(CSS)代码如下:
View Code1 2 view { 3 border: #007AFF 1rpx solid; 4 font-family: Arial,Helvetica,sans-serif; 5 font-size: 28rpx; 6 2rpx; 7 } 8 9 .main { 10 100%; 11 12 13 rgba(25,0.5); 14 color: 15 } 16 17 .current { 18 flex; 19 flex-direction: column; 20 vertical-align: middle; 21 justify-content: center; 22 400rpx; 23 border-bottom: #F1F1F1 2rpx solid; 24 } 25 26 .current view { 27 margin-bottom: 28 } 29 30 .district { 31 60rpx; 32 45rpx; 33 text-align: 34 35 } 36 37 .temp { 38 39 70rpx; 40 41 line-height: 1.5; 42 } 43 44 .temp_range { 45 46 40rpx; 47 48 49 } 50 51 .temp_desc { 52 50rpx; 53 30rpx; 54 55 56 } 57 58 .temp_src { 59 60 row; 61 justify; 62 bottom; 63 } 64 65 .temp_src_left {} 66 67 .temp_src_right { 68 flex: 1; 69 right; 70 } 71 72 .top { 73 74 75 } 76 77 .hour { 78 79 80 81 small; 82 margin-top: 83 84 85 } 86 .each_hour{ 87 margin-left: 6rpx; 88 } 89 .each_hour_img{ 90 91 92 } 93 .sevenday { 94 95 96 } 97 98 .each_day { 99 100 101 102 103 104 105 } 106 107 108 .each_day_text { 109 110 left; 111 2; 112 } 113 114 115 .each_day_img { 116 117 118 } 119 120 .each_day_temp { 121 122 123 124 } 125 126 .air { 127 128 129 margin:130 } 131 132 .air_title { 133 134 135 136 } 137 138 .air_body { 139 140 141 } 142 143 .air_left { 144 145 inline-block; 146 147 148 } 149 .airprogress{ 150 151 152 } 153 .air_right { 154 155 156 157 } 158 159 .air_content { 160 161 162 } 163 164 .air_content_name { 165 166 167 } 168 169 .air_content_value { 170 171 172 } 173 174 175 .wind{ 176 177 178 260rpx; 179 180 } 181 .wind_title{ 182 183 184 } 185 .wind_body{ 186 187 188 } 189 .wind_left{ 190 191 192 150rpx; 193 } 194 .wind_right{ 195 196 197 198 } 199 .wind_right_direction{ 200 0.5; 201 202 203 } 204 .wind_right_power{ 205 206 207 208 } 209 .wind_left_img{ 210 140rpx; 211 212 } 213 .wind01{ 214 215 216 0rpx; 217 } 218 .wind02{ 219 220 -20rpx; 221 222 } 223 .provider{ 224 225 } 226 </style>
(四)页面调用组件
当组件定义完成,就可以在页面引用组件,如下所示:
本例采用swiper来实现左右滑动功能,页面(template)源码如下:
View Codeswiper :indicator-dots="showIndicatorDots" indicator-color="#FFFFFF" indicator-active-color="#FF0000" :autoplay="isAutoPlay"swiper-item v-for="(item,index) in weather_content"weather :id="index" :district="item.district" 7 :temp="item.temp" 8 :tempdesc="item.tempdesc" :temprange="item.temprange" :updatetime="item.updatetime" :timelist="item.time_list" :daylist="item.day_list" :airvalue="item.air_value" :airlist="item.air_list" :winddirection="item.winddirection" :windpower="item.windpower" class="weather"18 weather20 swiper-item21 swiper22 >本例通过脚本造了一些数据,没有进行接口调用,脚本(JavaScript)代码如下:
View Code1 <script> 2 import weather from "@/components/weather/weather.vue" 3 export 4 5 weather 6 7 8 9 title: 'Hello' 10 showIndicatorDots: 11 isAutoPlay:false 12 weather_content:[{ 13 district:"龙岗区" 14 temp:23 15 temprange:"-2°C / 10°C" 16 tempdesc:"晴 空气良" 17 updatetime:"22:10" 18 time_list: [{ 19 time: "00:00" 20 img: "../../static/day/00.png" 21 temp: "0°C" 22 },1)"> 23 { 24 time: "01:00" 25 img: "../../static/day/01.png" 26 temp: "1°C" 27 28 time: "02:00" 29 img: "../../static/day/02.png" 30 temp: "2°C" 31 32 33 time: "03:00" 34 img: "../../static/day/03.png" 35 temp: "3°C" 36 37 time: "04:00" 38 img: "../../static/day/04.png" 39 temp: "4°C" 40 41 42 time: "05:00" 43 img: "../../static/day/05.png" 44 temp: "5°C" 45 46 time: "06:00" 47 img: "../../static/day/06.png" 48 temp: "6°C" 49 50 51 time: "07:00" 52 img: "../../static/day/07.png" 53 temp: "7°C" 54 55 time: "08:00" 56 img: "../../static/day/08.png" 57 temp: "8°C" 58 59 60 time: "09:00" 61 img: "../../static/day/09.png" 62 temp: "9°C" 63 64 time: "10:00" 65 img: "../../static/day/10.png" 66 temp: "10°C" 67 68 69 time: "11:00" 70 img: "../../static/day/11.png" 71 temp: "11°C" 72 73 time: "12:00" 74 img: "../../static/day/12.png" 75 temp: "12°C" 76 77 78 time: "13:00" 79 img: "../../static/day/13.png" 80 temp: "13°C" 81 82 time: "14:00" 83 img: "../../static/day/14.png" 84 temp: "14°C" 85 86 87 time: "15:00" 88 img: "../../static/day/15.png" 89 temp: "15°C" 90 91 time: "16:00" 92 img: "../../static/day/16.png" 93 temp: "16°C" 94 95 96 time: "17:00" 97 img: "../../static/day/17.png" 98 temp: "17°C" 99 100 time: "18:00"101 img: "../../static/day/18.png"102 temp: "18°C" 103 104 105 time: "19:00"106 img: "../../static/day/19.png"107 temp: "19°C" 108 109 time: "20:00"110 img: "../../static/day/20.png"111 temp: "20°C" 112 113 114 time: "21:00"115 img: "../../static/day/21.png"116 temp: "21°C" 117 118 time: "22:00"119 img: "../../static/day/22.png"120 temp: "22°C" 121 122 123 time: "23:00"124 img: "../../static/day/23.png"125 temp: "23°C" 126 } 127 ],1)">128 day_list: [{ 129 day: "10月31日"130 week: "昨天"131 img: "../../static/night/00.png"132 temp: "26°C/21°C" 133 134 135 day: "11月01日"136 week: "今天"137 img: "../../static/night/01.png"138 temp: "22°C/11°C" 139 140 141 day: "11月02日"142 week: "明天"143 img: "../../static/night/03.png"144 temp: "12°C/11°C" 145 146 147 day: "11月03日"148 week: "星期二"149 img: "../../static/night/04.png"150 temp: "18°C/01°C" 151 152 153 day: "11月04日"154 week: "星期三"155 img: "../../static/night/06.png"156 temp: "22°C/02°C" 157 158 159 day: "11月05日"160 week: "星期四"161 img: "../../static/night/07.png"162 temp: "12°C/02°C" 163 164 165 day: "11月07日"166 week: "星期五"167 img: "../../static/night/09.png"168 temp: "06°C/02°C" 169 170 171 air_value:30172 air_list: [{ 173 name: "PM10"174 value: 23 175 176 177 name: "PM2.5"178 value: 25 179 180 181 name: "NO2"182 value: 28 183 184 185 name: "SO2"186 value: 5 187 188 189 name: "O3"190 value: 35 191 192 193 name: "CO"194 value: 0.91 195 196 197 winddirection:"北风"198 windpower:"3~4级" 199 },1)">200 district:"东城区"201 temp:13202 temprange:"12°C / 20°C"203 tempdesc:"阴 空气很好"204 updatetime:"22:00"205 206 time: "00:00"207 img: "../../static/night/00.png"208 temp: "0°C" 209 210 211 time: "01:00"212 img: "../../static/night/01.png"213 temp: "1°C" 214 215 time: "02:00"216 img: "../../static/night/02.png"217 temp: "2°C" 218 219 220 time: "03:00"221 img: "../../static/night/03.png"222 temp: "3°C" 223 224 time: "04:00"225 img: "../../static/night/04.png"226 temp: "4°C" 227 228 229 time: "05:00"230 img: "../../static/night/05.png"231 temp: "5°C" 232 233 time: "06:00"234 img: "../../static/night/06.png"235 temp: "6°C" 236 237 238 time: "07:00"239 img: "../../static/night/07.png"240 temp: "7°C" 241 242 time: "08:00"243 img: "../../static/night/08.png"244 temp: "8°C" 245 246 247 time: "09:00"248 img: "../../static/night/09.png"249 temp: "9°C" 250 251 time: "10:00"252 img: "../../static/night/10.png"253 temp: "10°C" 254 255 256 time: "11:00"257 img: "../../static/night/11.png"258 temp: "11°C" 259 260 time: "12:00"261 img: "../../static/night/12.png"262 temp: "12°C" 263 264 265 time: "13:00"266 img: "../../static/night/13.png"267 temp: "13°C" 268 269 time: "14:00"270 img: "../../static/night/14.png"271 temp: "14°C" 272 273 274 time: "15:00"275 img: "../../static/night/15.png"276 temp: "15°C" 277 278 time: "16:00"279 img: "../../static/night/16.png"280 temp: "16°C" 281 282 283 time: "17:00"284 img: "../../static/night/17.png"285 temp: "17°C" 286 287 time: "18:00"288 img: "../../static/night/18.png"289 temp: "18°C" 290 291 292 time: "19:00"293 img: "../../static/night/19.png"294 temp: "19°C" 295 296 time: "20:00"297 img: "../../static/night/20.png"298 temp: "20°C" 299 300 301 time: "21:00"302 img: "../../static/night/21.png"303 temp: "21°C" 304 305 time: "22:00"306 img: "../../static/night/22.png"307 temp: "22°C" 308 309 310 time: "23:00"311 img: "../../static/night/23.png"312 temp: "23°C" 313 314 315 316 day: "10月31日"317 week: "昨天"318 img: "../../static/day/00.png"319 temp: "6°C/21°C" 320 321 322 day: "11月01日"323 week: "今天"324 img: "../../static/day/01.png"325 temp: "12°C/11°C" 326 327 328 day: "11月02日"329 week: "明天"330 img: "../../static/day/03.png"331 temp: "22°C/09°C" 332 333 334 day: "11月03日"335 week: "星期二"336 img: "../../static/day/04.png"337 temp: "28°C/11°C" 338 339 340 day: "11月04日"341 week: "星期三"342 img: "../../static/day/06.png"343 temp: "12°C/02°C" 344 345 346 day: "11月05日"347 week: "星期四"348 img: "../../static/day/07.png"349 temp: "22°C/12°C" 350 351 352 day: "11月07日"353 week: "星期五"354 img: "../../static/night/09.png"355 temp: "16°C/12°C" 356 357 358 air_value:67359 360 name: "PM10"361 value: 63 362 363 364 name: "PM2.5"365 value: 39 366 367 368 name: "NO2"369 value: 23 370 371 372 name: "SO2"373 value: 5 374 375 376 name: "O3"377 value: 65 378 379 380 name: "CO"381 value: 0.71 382 383 384 winddirection:"东南风"385 windpower:"1~4级" 386 }] 387 388 389 onLoad() { 390 console.log("测试加载页面") 391 392 onShow(){ 393 console.log("页面onshow...."394 395 methods: { 396 397 398 399 </script>样式(CSS)代码如下:
.content { #007AFF; 6 } 7 swiper{ 10 } .swiper-item{ border: #007AFF 1rpx solid; 13 } 14 .weather{ 16 } 17 (五)注意事项例子虽小,开发时也会踩坑,具体事项如下:
1. 开发过程中,在运行到Chrome浏览器,一切正常,但是当运行到Android真机时,页面除了导航条显示,其他一片空白,后来发现,需要在App.vue中定义页面的高度,才可以正常显示。App.vue源码如下所示:
View Code<script> export default { onLaunch: function() { console.log('App Launch') 5 } 6 onShow: function() { console.log('App Show') 8 } 9 onHide: function() { console.log('App Hide') 11 } 13 </script> 14 16 每个页面公共css uni-page-body,#app {width:100%;height: 100%;} 18 #ifdef APP-PLUS 19 20 以下样式用于 hello uni-app 演示所需 21 page { background-color: #F4F5F6; font-size: 28rpx; 25 line-height: 1.8; 26 } 27 #endif28 </style>2. 在开发过程中,最初圆形进度条是采用svg进行开发,在Chrome浏览器显示正常,但是在手机App上显示不出来,并造成页面显示一大片空白,后来不得已采用css实现。
备注
次北固山下
【作者】王湾 【朝代】唐
客路青山外,行舟绿水前。
潮平两岸阔,风正一帆悬。
海日生残夜,江春入旧年。
乡书何处达?归雁洛阳边。