———— 润物无声,做一个有个风格的coder
小递次、快运用如今可谓是众所周知,也越发亲昵的渗透入我们的生涯中,笔者也算是个爱折腾的人,俗话说的好嘛,“不折腾,不前端“(当然是笔者自身的小心声)。因而在平日里劳碌的事情之余抽出来时刻搞点事(si)情,来写一个属于自身的贴身小天色。说时迟那时快,这就来了…
经由两三年的生长,小递次的职位也步步高升,由腾讯领队的腾讯小递次,再到厥后的支付宝,美团,头条等也都相应推出自家的小递次平台,都想顺着潮水捉住流量分一杯羹,可谓是兵家必争之地。大环境的转变,为了进步小递次的疾速迭代和多人合作开辟的效力,也使得各大厂商都开源了自身的小递次框架,mpvue、wepy、MINA、Taro等置信人人也比较熟习了。而小递次的社区也变得跟雄厚硬朗,也衍生出许多优美的UI框架。有兴致的能够自行去相应的官网相识概略。
虽然上面引见了那末多的框架,而本次笔者并没有运用框架,而是用原生的小递次来开辟本日的主角,也愿望能够用原始的体式格局来给那些和笔者一样的方才入门的小递次开辟者一些协助,也将自身所学的纪录下来。毕竟原生才是最底层的基础,一切的框架都是在原生的基础上开花结果的,如许才以不变应万变(吼吼~)。笔者程度有限,有毛病或许诠释不当的处所还望列位看官多多见谅。
项目源码 润物无声github
在定位功用中,本递次用到腾讯舆图的api
相应的天色接口中,本递次用到的是微风天色供应的api
两者都须要到官网中注册开辟者账号,经由历程注册后取得的appKey来请求我们须要的数据,细致注册步骤请自行度娘
由于须要用到定位功用,而小递次自身的getLocation要领猎取到的是当前位置的坐标:
wx.getLocation({
type: 'gcj02', // 返回坐标的花样
success: res => {
// 此处只能猎取到当前位置的经纬度(坐标)
},
})
所以须要应用腾讯舆图Api,经由历程坐标点反向取得该所在的细致信息。
在app.json中是对全部小递次的一些基础设置
{
"pages": [
"pages/index/index" // 当前小递次的主进口页面
],
// 主窗口的一些设置,以下,对背景色彩和小递次顶部的导航栏的款式举行了设置
"window": {
"backgroundColor": "#A7CAD3",
"backgroundTextStyle": "dark",
"navigationBarBackgroundColor": "#A7CAD3",
"navigationBarTitleText": "蜗牛天色",
"navigationBarTextStyle": "black",
"navigationStyle":"custom"
},
"permission": {
"scope.userLocation": {
"desc": "蜗牛天色尝试猎取您的位置信息" // 讯问用户是不是能够取得猎取位置权限的提醒笔墨
}
}
}
接下来,我们就来一步一步的完成这个小递次吧~~
由于没有UI,再加上笔者歪曲的审美才能(坐在屏幕前最先愣神,堕入寻思…),所以还望列位看官多忍受笔者又想又自创的界面结果…看来今后要多增强这方面的才能(haha~)
好了言归正传,起首,准备用一个页面来处置惩罚战役,那就是列位看到以上的这个页面(都说了是‘小天色’嘛),页面一共分为五个部份,及时天色、24小时内天色状况、将来一星期内天色状况、本日日落日出风向降雨等相干信息和天色的生涯指数,这五个部份构成了全部页面,其对应的相应规划见一下代码
...
...
详细 css 款式,详见 蜗牛小天色 源码
注重:(笔者入坑,一最先运用的纵向的scroll-view,厥后没法的用了本来页面的转动)
scroll-view: 详细属性参考小递次官方文档
在小递次中,内部为我们供应了scroll-view这个页面转动的组件,对机能举行了一些优化,轻易我们的运用。与此同时,也会有一些小坑
- 在运用scroll-view是,假如是纵向(Y轴)转动,scroll-y属性,则必需为此scroll-view设置一个牢固(明白)的高
- 请勿在scroll-view组件标签内运用 textarea、map、canvas、video等组件
- 在运用了scroll-view组件时会阻挠页面的回弹结果,也就是在scroll-view中转动,没法触发onPullDownRefresh要领
- 假如想运用原生的下拉革新(非自定义)或许双击顶部页面回滚到页面顶部,请不要运用scroll-view。
置信列位看官发现了以上代码中有一个
而关于本小递次中
// 小递次中的组件,经由历程挪用Component要领,将组件的逻辑处置惩罚部份,属性以及要领(性命周期)等一对象的体式格局传入Component要领中
Component({
properties: {
type: {
type: String, // type属性的范例
value: '' // 默认值
}
}
});
运用了Component组织器,经由历程参数指定组件的属性,数据,要领以及性命周期中的一些要领,在此组件中定义了接收的type属性,范例为字符串,其默认值为空字符串。
{
"component": true // 设置,当前为组件
}
// CSS 部份略过...
就如许,一个简朴的icon图标组件就封装好了,是不是是很简朴啊。封装是封装好了,那末我们怎样挪用这个组件呢,是不是是很相似于Vue呢,没错,只须要在你挪用的页面中注册一下即可
// 当前想要挪用的页面的*.json文件中,以下
{
"enablePullDownRefresh": true, // 此项与组件无关,此项为是不是用小递次自身的下拉革新功用
"usingComponents": {
"myicon": "../../components/icon/index" // 挪用,注册icon组件
}
}
一最先就说到了须要运用腾讯舆图API的appkey另有微风天色API的appkey,笔者是将appkey设置在了config.js中,看官只需将自身相应的appkey值替代即可,由于appkey是私密的,此处就不公开了,还望体谅。
// config.js
export default {
MAP_API_KEY: 'XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX', // 腾讯舆图key
WEATHER_API_KEY: 'XXXXXXXXXXXXXXXX' // 微风天色key
}
一切数据的接口,都定义在了api.js文件中,此处没什么好说的,看官自行经由历程接口文档查询。接口均采用回调的体式格局,笔者并没有封装成Promise的体式格局,假如有兴致可自行变动。
// 引入config,为了背面的key
import config from '../uitl/config'
// 舆图key
const mapKey = config.MAP_API_KEY
// 微风天色key
const weatherKey = config.WEATHER_API_KEY
// map url
const locatiOnUrl= 'https://apis.map.qq.com/ws/geocoder/v1/'
//天色url
const weatherUrl = 'https://free-api.heweather.net/s6/weather/forecast'
//24小时内 每小时
const everyhoursUrl = 'https://api.heweather.net/s6/weather/hourly'
// 一周内
const everyWeekUrl = 'https://api.heweather.net/s6/weather/forecast'
//空气质量
const airQualityUrl = 'https://api.heweather.net/s6/air/now'
// 实况天色
const weatherLive = 'https://api.heweather.net/s6/weather/now'
// 生涯指数
const lifeStyle = 'https://api.heweather.net/s6/weather/lifestyle'
// 依据当前位置的坐标反取得当前位置的细致信息
// lat,lon 为经纬度坐标
export const getPosition = (lat, lon, success = {}, fail = {}) => {
return wx.request({
url: locationUrl,
header: {
'Content-Type': 'application/json'
},
data: {
location: `${lat},${lon}`,
key: mapKey,
get_poi: 0
},
success,
fail
})
}
// 依据location取得天色信息
// lat,lon 为经纬度坐标
export const getWeaterInfo = (lat, lon, success = {}, fail = {}) => {
return wx.request({
url: weatherUrl,
header: {
'Content-Type': 'application/json'
},
data: {
location: `${lat},${lon}`,
lang: 'zh',
unit: 'm',
key: weatherKey
},
success,
fail
})
}
// 依据location信息取得24小逐小时天色状况
// lat,lon 为经纬度坐标
export const getEveryHoursWeather = (lat, lon, success = {}, fail = {}) => {
return wx.request({
url: everyhoursUrl,
header: {
'Content-Type': 'application/json'
},
data: {
location: `${lat},${lon}`,
lang: 'zh',
unit: 'm',
key: weatherKey
},
success,
fail
})
}
...
... // 其他接口相似
...
}
起首,当首次加载页面时,大致流程为起首经由历程定位猎取位置,然后经由历程位置信息去取得我们须要的每一项天色信息,末了将天色信息衬着后页面中相应的位置
详细流程:
经由历程位置信息猎取天色信息
猎取及时天色信息
当经由历程手动转变位置信息时,按递次反复实行以上步骤
经由历程wx.getLocation原生要领猎取经纬度信息,在经由腾讯舆图api经由历程经纬度逆向猎取到相应的位置信息,关于这个项目来讲猎取位置信息是最重要的信息,故我们愿望在页面一加载的时刻就实行要领猎取,然后『onLoad』要领能够协助我们处置惩罚,这个要领就是小递次的性命周期函数–监听页面加载,此要领会在页面刚加载的时刻(document文档组织衬着完成后)实行。
小递次页面(Page)的性命周期函数:
name | type | functional |
---|---|---|
onLoad | 函数 | 监听页面加载 |
onReady | 函数 | 监听页面首次衬着完成 |
onShow | 函数 | 监听页面显现 |
onHide | 函数 | 监听页面隐蔽 |
onUnload | 函数 | 监听页面卸载 |
以下为猎取位置信息代码:
// onLoad
onLoad: function () {
...
...
this.getPositon() // 挪用猎取位置信息
}
// 原生要领猎取经纬度信息
getPosition: function () {
wx.getLocation({
type: 'gcj02',
success: this.updateLocation, // 胜利会掉 updataLocation 要领为更新位置
fail: err => {
console.log(err)
}
})
}
// 更新位置信息
updateLocation: function(res) {
...
...
let {latitude: x,longitude: y,name} = res;
let data = {
location: {
x,
y,
name: name || '北京市'
},
...
...
};
this.setData(data); // 设置page中data对象中的属性
// 经由历程经纬度逆向取得位置信息
this.getLocation(x, y, name);
}
// 逆向猎取位置信息
getLocation: function(lat, lon, name) {
wx.showLoading({
title: "定位中",
mask: true
})
// 腾讯舆图api接口
getPosition(lat, lon, (res) => {
if (res.statusCode == 200) {
let respOnse= res.data.result
let addr = response.formatted_addresses.recommend || response.rough
this.setData({
position: addr // 赋值给 data对象中的相应属性
})
wx.hideLoading()
this.getData(lat, lon);
}
}, (err => {
console.log(err)
wx.hideLoading()
}))
},
// 当用户点击显现定位处的view时,会挪用原生的chooseLocation要领,内部挪用挑选位置页面
chooseLocation: function() {
wx.chooseLocation({
success: res => {
let {latitude,longitude} = res
let {x,y} = this.data.location
if (latitude == x && lOngitude== y) {
} else {
this.updateLocation(res)
}
}
})
},
上面代码中两次用到了setData要领,该要领接收一个对象,对象中的属性为须要转变的数据,同时接收一个callback函数,用于经由历程转变数据更新页面衬着完成以后的回调。我们来看看data的作用。
page({
data: {
backgroundColor:'red',
fontSize: '20',
...
...
}
})
在page中,data中的属性是衔接逻辑层和视图层的一个桥梁,也就是说我们能够经由历程js代码的逻辑来掌握data中的属性的值,而页面中的一部份显现内容是依据data中的属性的值而变化。这也就是我们所说的mvvm模子,我们只需把重心放在js逻辑层,而无需去频仍的手动的操纵视图层。相识了data的作用,再来讲setData,setData就是在js逻辑层中去转变和设置data中的属性的值,从而使页面取得相应。
...
this.setData({
backgroundColor: 'green' // 转变背景色彩属性,视图中以来此属性的会将色彩变成绿色
})
...
注重:
- 直接修正this.data的值,而不是经由历程挪用this.setData()要领,是没法胜利转变页面的状况的
- 仅仅支撑JSON化的数据(key:value)
- 单词设置的值不能超过1024K,所以运用的时刻只管不要一次设置过量的数据
- 不要把data中的任何一项value值设置成undefined,不然这一项将不能被设置,也能够会有其他题目
- 不要频仍的去挪用this.setData()要领去设置统一个值或许多个值,比方经由历程在循环中挪用this.setData(),如许会致使机能消耗
经由历程上面猎取得的位置信息,用来挪用相应的接口取得当前位置的天色。要领接口已在前面封装好,直接挪用然后经由历程对response举行过滤或许重组等来满足当前的运用,末了经由历程this.setData()要领去更新数据是页面取得相应。
- getWeather(lat, lon) // lat, lon 为当前位置的经纬度
- getAir(lat, lon)
- getHourWeather(lat, lon)
- getWeatherForWeek(lat, lon)
- getLifeIndex(lat, lon)
以上要领不在一一列举个中数据处置惩罚的历程,可自行检察源码 详见 蜗牛小天色 源码
粒子动画在如今越来越多的项目中被用到。从静态到动态末了再到仿真结果更好的视觉体验,也是人们在视觉上寻求极致的体验。我们经由历程粒子,也就是经由历程点和线,来模仿出雨和雪的结果。经由历程小递次中的canvas画布来画出我们想要的结果。
完成道理:
Weather类是一个基类,重要处置惩罚画布的一些信息,比方width,height,定时器,以及当前动画的状况(status)等
const STOP_ANIMATION = 'stop'
const START_ANIMATION = 'start'
class Weather {
constructor(context, width, height, option = {}) {
this.opt = option || {}
this.cOntext= context
this.timer = null
this.status = STOP_ANIMATION
this.width = width
this.height = height
this._init()
}
// 实例挪用此要领,最先在画布上画
start() {
if(this.status !== START_ANIMATION) {
this.status = START_ANIMATION
this.timer = setInterval(() => {
this._drawing()
}, 30)
return this
}
}
stop() {
this.status = STOP_ANIMATION
clearInterval(this.timer)
this.timer = null
return this
}
}
export default Weather
Rain类继续自Weather类,经由历程_init要领和父类中画布参数,以及option参数中的counts(雨滴数目)来初始化。
import Weather from './Weather.js'
class Rain extends Weather {
// 初始化
_init() {
this.context.setLineWidth(2)
this.context.setLineCap('round')
let height = this.height
let width = this.width
let counts = this.opt.counts || 100
let speedCoefficient = this.opt.speedCoefficient
let speed = speedCoefficient * height
this.animatiOnArray= []
let arr = this.animationArray
for (let i = 0; i
x: Math.random() * width,
y: Math.random() * height,
len: 2 * Math.random(),
xs: -1,
ys: 10 * Math.random() + speed,
color: 'rgba(255,255,255,0.1)'
}
arr.push(d)
}
}
// 最先画
_drawing() {
let arr = this.animationArray
let ctx = this.context
ctx.clearRect(0, 0, this.width, this.height)
for (let i = 0; i
ctx.beginPath()
ctx.moveTo(s.x, s.y)
ctx.lineTo(s.x + s.len * s.xs, s.y + s.len * s.ys)
ctx.setStrokeStyle(s.color)
ctx.stroke()
}
ctx.draw()
return this.update()
}
// 更新画布
update() {
let width = this.width
let height = this.height
let arr = this.animationArray
for (let i = 0; i
s.x = s.x + s.xs
s.y = s.y + s.ys
if (s.x > width || s.y > height) {
s.x = Math.random() * width
s.y = -10
}
}
}
}
export default Rain
Snow类继续自Weather类,经由历程_init要领和父类中画布参数,以及option参数中的counts(雪花数目)来初始化。
import Weather from './Weather.js'
class Snow extends Weather {
// 初始化
_init() {
let {
width,
height
} = this
console.log(width)
let colors = this.opt.colors || ['#ccc', '#eee', '#fff', '#ddd']
let counts = this.opt.counts || 100
let speedCoefficient = this.opt.speedCoefficient || 0.03
let speed = speedCoefficient * height * 0.15
let radius = this.opt.radius || 2
this.animatiOnArray= []
let arr = this.animationArray
for (let i = 0; i
x: Math.random() * width,
y: Math.random() * height,
ox: Math.random() * width,
ys: Math.random() + speed,
r: Math.floor(Math.random() * (radius + 0.5) + 0.5),
color: colors[Math.floor(Math.random() * colors.length)],
rs: Math.random() * 80
})
}
console.log(arr)
}
// 最先画
_drawing() {
let arr = this.animationArray
let cOntext= this.context
context.clearRect(0, 0, this.width, this.height)
for (let i = 0; i
x,
y,
r,
color
} = arr[i]
context.beginPath()
context.arc(x, y, r, 0, Math.PI * 2, false)
context.setFillStyle(color)
context.fill()
context.closePath()
}
context.draw()
this._update()
}
// 更新画布
_update() {
let {
width,
height
} = this
let arr = this.animationArray
let v = this.opt.speedCoefficient / 10
for (let i = 0; i
let {
ox,
ys
} = p
p.rs += v
p.x = ox + Math.cos(p.rs) * width / 2
p.y += ys
if (p.x > width || p.y > height) {
p.x = Math.random() * width
p.y = -10
}
}
}
}
export default Snow
完毕!!!
到此,蜗牛小天色就开辟完成了,愿望对列位有协助。
愿望在浏览的同时还请看官别忘了给一个大大的赞👍,码字不容易…
初来乍到,本事有限,程度平常,只是想着用笔墨来纪录自身的进修历程。假如文中有毛病的地方,还请列位多多提意见,配合讨论,也请列位多见谅。