Примечания к выпуску:
I. Метеорологические данные изОткрытая платформа карты Baiduизменен назефир погода, вам необходимо зарегистрировать учетную запись, чтобы получитьkey
;
II.d0e51c8
версия послеОблачная мини-программаверсии, если функция облачной разработки не включена, чтобы не влиять на нормальную работу апплета, можно откатить номер версии доgit reset d0e51c8 --hard
или закомментируйте код, связанный с облачной разработкой. Подробности можно посмотретьздесь.
Введение
Это полноценный апплет приложения погоды, который уже работает онлайн.Нажмите, чтобы просмотреть исходный код, вы можете звездить по желанию. Вы также можете отсканировать приведенный ниже код апплета, чтобы испытать его непосредственно. Кстати, порекомендуйте другой апплет с открытым исходным кодомСтороннее издание Nuggets,Исходный код здесь.
Новая версия домашней страницы (опционально встроенный фон)
Изображение эффекта:
Источники данных
Геокодирование, данные о погоде изОткрытая платформа карты Baidu. Персональная разработка полностью бесплатна, есть соответствующий апплет sdk, присоединиться можно, но возвращаемых данных о погоде меньше.
Подготовка перед бегом
- Зарегистрируйте мини-программу WeChat, будь осторожен
- регистрОткрытая платформа карты BaiduРазработчик, создай заявку, получи ак (другие конфигурации проверяй сам)
- Замените ak в globalData на свой ak в app.js
- Run
акционер
без
Сбор данных о погоде
Поскольку это только персональная версия DEMO (полная версия), я решил выбрать бесплатные данные о погоде перед разработкой (бесплатно для личного развития), мне было лень искать другие данные о погоде, и мне было лень регистрировать учетную запись. , поэтому я выбрал его напрямую.Открытая платформа карты BaiduДанные о погоде приложения также предоставляют SDK, соответствующий аплету, но данные, возвращаемые Baidu, могут быть меньше, чем у других API погоды: pm2. Но этого достаточно для простого апплета приложения погоды.
Геокодирование
При получении данных о погоде по умолчанию возвращаются данные о погоде в текущем городе.Если вы хотите получить данные о погоде в других городах, вам необходимо указать широту и долготу. Чтобы получить широту и долготу других городов, используйте интерфейс геокодирования карты, используемый здесь, введите название города, выведите широту и долготу, а затем вызовите API для получения данных о погоде.
Реализация
В приложении всего пять страниц: домашняя страница, страница выбора города, страница настроек, страница о системе, страница информации о системе (страница отображения). следующим образом:
титульная страница
Окончательный эффект отображения домашней страницы выглядит следующим образом:
Сверху вниз: поиск погоды в другом городе, отображение данных о текущем городе, отображение данных о погоде на текущий день и следующие три дня, отображение текущего индекса жизни, нижний колонтитул. При нажатии на кнопку «Обновить» обновляются данные о погоде для текущего региона. Среди них топовый поиск погоды по городу и жилой индекс можно скрыть в настройках. В правом нижнем углу экрана находится плавающий шар (слайс??) меню, которое можно перемещать, после нажатия на которое всплывает выбор города, настройки и про входы на страницы. Цвет фона по умолчанию#40a7e7
Сплошной цвет, фоновое изображение можно изменить в настройках, а в прогноз погоды на ближайшие три дня и индекс жизни добавлен прозрачный черный фон. эскизный проект? Нет, чистая отладка невооруженным глазом, пока не выглядишь комфортно.
Главная страница
Сначала определите метод для получения данных о погоде в текущей области:
init(params) {
let that = this
let BMap = new bmap.BMapWX({
ak: globalData.ak,
})
BMap.weather({
location: params.location,
fail: that.fail,
success: that.success,
})
},
ak
Пожалуйста, замените на свойak
, потому что необходимо получить географическое положение пользователя, поэтому вfail
Логика отказа пользователя от получения географического местоположения должна быть обработана в обратном вызове .3000ms
назадwx.openSetting()
Перейдите на страницу настроек апплета следующим образом:
fail (res) {
wx.stopPullDownRefresh()
let errMsg = res.errMsg || ''
// 拒绝授权地理位置权限
if (errMsg.indexOf('deny') !== -1 || errMsg.indexOf('denied') !== -1) {
wx.showToast({
title: '需要开启地理位置权限',
icon: 'none',
duration: 3000,
success (res) {
let timer = setTimeout(() => {
clearTimeout(timer)
wx.openSetting({})
}, 3000)
},
})
} else {
wx.showToast({
title: '网络不给力,请稍后再试',
icon: 'none',
})
}
},
После получения географического местоположения пользователя выполнитеsuccess
:
success (data) {
wx.stopPullDownRefresh()
let now = new Date()
// 存下来源数据
data.updateTime = now.getTime()
data.updateTimeFormat = utils.formatDate(now, "MM-dd hh:mm")
let results = data.originalData.results[0] || {}
data.pm = this.calcPM(results['pm25'])
// 当天实时温度
data.temperature = `${results.weather_data[0].date.match(/\d+/g)[2]}`
wx.setStorage({
key: 'cityDatas',
data: data,
})
this.setData({
cityDatas: data,
})
},
Взгляните на возвращенный формат данных о погоде:
{
"error": 0,
"status": "success",
"date": "2018-06-29",
"results": [
{
"currentCity": "北京市",
"pm25": "55",
"index": [
{
"des": "天气炎热,建议着短衫、短裙、短裤、薄型T恤衫等清凉夏季服装。",
"zs": "炎热",
"tipt": "穿衣指数",
"title": "穿衣"
},
{
"des": "较适宜洗车,未来一天无雨,风力较小,擦洗一新的汽车至少能保持一天。",
"zs": "较适宜",
"tipt": "洗车指数",
"title": "洗车"
},
{
"des": "各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。",
"zs": "少发",
"tipt": "感冒指数",
"title": "感冒"
},
{
"des": "天气较好,无雨水困扰,但考虑气温很高,请注意适当减少运动时间并降低运动强度,运动后及时补充水分。",
"zs": "较不宜",
"tipt": "运动指数",
"title": "运动"
},
{
"des": "属中等强度紫外线辐射天气,外出时建议涂擦SPF高于15、PA+的防晒护肤品,戴帽子、太阳镜。",
"zs": "中等",
"tipt": "紫外线强度指数",
"title": "紫外线强度"
}
],
"weather_data": [
{
"date": "周五 06月29日 (实时:34℃)",
"dayPictureUrl": "http://api.map.baidu.com/images/weather/day/duoyun.png",
"nightPictureUrl": "http://api.map.baidu.com/images/weather/night/qing.png",
"weather": "多云转晴",
"wind": "东南风微风",
"temperature": "38 ~ 25℃"
},
{
"date": "周六",
"dayPictureUrl": "http://api.map.baidu.com/images/weather/day/duoyun.png",
"nightPictureUrl": "http://api.map.baidu.com/images/weather/night/duoyun.png",
"weather": "多云",
"wind": "东南风微风",
"temperature": "36 ~ 23℃"
},
{
"date": "周日",
"dayPictureUrl": "http://api.map.baidu.com/images/weather/day/qing.png",
"nightPictureUrl": "http://api.map.baidu.com/images/weather/night/qing.png",
"weather": "晴",
"wind": "东南风微风",
"temperature": "35 ~ 23℃"
},
{
"date": "周一",
"dayPictureUrl": "http://api.map.baidu.com/images/weather/day/qing.png",
"nightPictureUrl": "http://api.map.baidu.com/images/weather/night/duoyun.png",
"weather": "晴转多云",
"wind": "南风微风",
"temperature": "35 ~ 25℃"
}
]
}
]
}
success
Последние полученные данные о погоде + время обновления кэшируются вcityDatas
, метод нельзя использовать в шаблоне апплета, поэтому данные должны быть вjs
Сначала отформатируйте.calcPM
Он используется для расчета качества текущего pm2.5 и возвращает такие слова, как «хороший и плохой», а стандарт диапазона можно найти самостоятельно. Дневная температура в реальном времени не выделяется в отдельное поле, а смешиваетсяwearther_data[0]
изdata
В поле:"date": "周五 06月29日 (实时:34℃)"
, вам нужно извлечь его самостоятельно. Возвращенный значок погоды не соответствует оттенку, поэтому не используется. Другие данные могут быть заполнены непосредственно в соответствии с форматом, который мы хотим отобразить.
Поиск погоды в городе
Параметрами для получения данных о погоде являются широта и долгота, поэтому при поиске погоды в городе нужно преобразовать город в соответствующие широту и долготу, а затем вызвать API для получения данных о погоде. API для получения широты и долготы:
https://api.map.baidu.com/geocoder/v2/?address=${address}&output=json&ak=${yourak}
Формат возвращаемых данных:
{
"status":0,
"result":{
"location":{
"lng":117.21081309155257,
"lat":39.143929903310074
},
"precise":0,
"confidence":12,
"level":"城市"
}
}
Затем напрямую вызовите Get Weather API. Конкретный код выглядит следующим образом:
geocoder (address, success) {
let that = this
wx.request({
url: getApp().setGeocoderUrl(address),
success (res) {
let data = res.data || {}
if (!data.status) {
let location = (data.result || {}).location || {}
// location = {lng, lat}
success && success(location)
} else {
wx.showToast({
title: data.msg || '网络不给力,请稍后再试',
icon: 'none',
})
}
},
fail (res) {
wx.showToast({
title: res.errMsg || '网络不给力,请稍后再试',
icon: 'none',
})
},
complete () {
that.setData({
searchText: '',
})
},
})
},
search (val) {
// 动画
if (val === '520' || val === '521') {
this.setData({
searchText: '',
})
this.dance()
return
}
wx.pageScrollTo({
scrollTop: 0,
duration: 300,
})
if (val) {
let that = this
this.geocoder(val, (loc) => {
that.init({
location: `${loc.lng},${loc.lat}`
})
})
}
},
Поиск анимированных пасхалок
Поиск в окне поиска520
или521
, будет аккуратная анимация сверху вниз, как показано ниже:
Реализация здесь относительно проста.
создалheartbeat
с компонент.wxml
Структура состоит в том, чтобы пройти по массиву и создать несколько изображений случайных размеров и позиций:
<image wx:for='{{arr}}' wx:key='{{index}}' animation='{{animations[index]}}' class='heart' style='left:{{lefts[index]}}px;top:{{tops[index]}}px;width:{{widths[index]}}rpx;height:{{widths[index]}}rpx;' src='/img/heartbeat.png'></image>
Затем используйте предоставленный апплетомwx.createAnimation
, использовать анимацию относительно просто, создайте анимацию, а затем дайтеanimation
Можно использовать свойства, что относительно просто, но тоже имеет ограничения, например, нет прямого обратного вызова после окончания анимации, но его можно использоватьsetTimeout
осознавать и т. Здесь будет использоваться доступная ширина и высота окна, потому что этот параметр используется во многих местах, поэтому вapp.js
Сначала он получается асинхронно.
Код анимации выглядит следующим образом:
dance (callback) {
let windowWidth = this.data.windowWidth
let windowHeight = this.data.windowHeight
let duration = this.data.duration
let animations = []
let lefts = []
let tops = []
let widths = []
let obj = {}
for (let i = 0; i < this.data.arr.length; i++) {
lefts.push(Math.random() * windowWidth)
tops.push(-140)
widths.push(Math.random() * 50 + 40)
let animation = wx.createAnimation({
duration: Math.random() * (duration - 1000) + 1000
})
animation.top(windowHeight).left(Math.random() * windowWidth).rotate(Math.random() * 960).step()
animations.push(animation.export())
}
this.setData({
lefts,
tops,
widths,
})
let that = this
let timer = setTimeout(() => {
that.setData({
animations,
})
clearTimeout(timer)
}, 200)
let end = setTimeout(() => {
callback && callback()
clearTimeout(end)
}, duration)
},
},
После поиска определенного ключевого слова на главной странице вызовите компонентdance
метод, который запускает тщательную анимацию.
Меню плавающего шара
Плавающий шар в правом нижнем углу экрана обеспечивает доступ к трем страницам: странице выбора города, странице настроек и странице сведений. Будет анимация, когда меню всплывает и убирается.
Анимация здесь разделена на всплывающую и втягивающую, они в принципе одинаковые, но параметры анимации разные. Анимация всплывающего окна размещена здесь:
// wxml
<!-- 悬浮菜单 -->
<view class='menus'>
<image src="/img/location.png" animation="{{animationOne}}" class="menu" bindtap="menuOne" style='top:{{pos.top}}px;left:{{pos.left}}px;'></image>
<image src="/img/setting.png" animation="{{animationTwo}}" class="menu" bindtap="menuTwo" style='top:{{pos.top}}px;left:{{pos.left}}px;'></image>
<image src="/img/info.png" animation="{{animationThree}}" class="menu" bindtap="menuThree" style='top:{{pos.top}}px;left:{{pos.left}}px;'></image>
<image src="/img/menu.png" animation="{{animationMain}}" class="menu main" bindtap="menuMain" catchtouchmove='menuMainMove' style='top:{{pos.top}}px;left:{{pos.left}}px;'></image>
</view>
// js
popp() {
let animationMain = wx.createAnimation({
duration: 200,
timingFunction: 'ease-out'
})
let animationOne = wx.createAnimation({
duration: 200,
timingFunction: 'ease-out'
})
let animationTwo = wx.createAnimation({
duration: 200,
timingFunction: 'ease-out'
})
let animationThree = wx.createAnimation({
duration: 200,
timingFunction: 'ease-out'
})
animationMain.rotateZ(180).step()
animationOne.translate(-50, -60).rotateZ(360).opacity(1).step()
animationTwo.translate(-90, 0).rotateZ(360).opacity(1).step()
animationThree.translate(-50, 60).rotateZ(360).opacity(1).step()
this.setData({
animationMain: animationMain.export(),
animationOne: animationOne.export(),
animationTwo: animationTwo.export(),
animationThree: animationThree.export(),
})
},
Плавающее меню можно свободно перемещать по экрану, и этот метод также очень прост.touchmove
Событие достаточное, потому что направление раскрытия меню слева, поэтому самое дальнее расстояние, на которое плавающее меню может переместиться влево, должно иметь интервал, иначе расширенное меню войдет в левый экран, и та же логика будет перемещена наверх (позже можно изменить на расширение меню. Ориентация меняется при движении, а не просто расширяется влево).
код показывает, как показано ниже:
menuMainMove (e) {
// 如果已经弹出来了,需要先收回去,否则会受 top、left 会影响
if (this.data.hasPopped) {
this.takeback()
this.setData({
hasPopped: false,
})
}
let windowWidth = SYSTEMINFO.windowWidth
let windowHeight = SYSTEMINFO.windowHeight
let touches = e.touches[0]
let clientX = touches.clientX
let clientY = touches.clientY
// 边界判断
if (clientX > windowWidth - 40) {
clientX = windowWidth - 40
}
if (clientX <= 90) {
clientX = 90
}
if (clientY > windowHeight - 40 - 60) {
clientY = windowHeight - 40 - 60
}
if (clientY <= 60) {
clientY = 60
}
let pos = {
left: clientX,
top: clientY,
}
this.setData({
pos,
})
},
Что касается некоторых стилевых и логических деталей, то я не буду их здесь повторять.Посмотреть исходный код.
Страница выбора города
Страница выбора города представляет собой список следующих городов:
Щелкните соответствующий город, чтобы перейти на домашнюю страницу и получить данные о погоде в выбранном городе. Данные города здесь представляют собой неупорядоченный список, отформатированный следующим образом:
{ "letter": "B", "name": "北京市" }
Поскольку его нужно отсортировать по алфавиту, его нужно сначала отсортировать, а затем пройти (данные города — это данные, которые использовались ранее, и они вставляются напрямую без сортировки). код показывает, как показано ниже:
// 按照字母顺序生成需要的数据格式
getSortedAreaObj(areas) {
// let areas = staticData.areas
areas = areas.sort((a, b) => {
if (a.letter > b.letter) {
return 1
}
if (a.letter < b.letter) {
return -1
}
return 0
})
let obj = {}
for (let i = 0, len = areas.length; i < len; i++) {
let item = areas[i]
delete item.districts
let letter = item.letter
if (!obj[letter]) {
obj[letter] = []
}
obj[letter].push(item)
}
// 返回一个对象,直接用 wx:for 来遍历对象,index 为 key,item 为 value,item 是一个数组
return obj
},
После нажатия на город нужно уведомить домашнюю страницу "Я поменял города, пожалуйста, получите данные этого города, спасибо", вот использованиеgetCurrentPages
Как получить стек страниц и изменить данные домашней страницы. код показывает, как показано ниже:
choose(e) {
let item = e.currentTarget.dataset.item
let name = item.name
let pages = getCurrentPages()
let len = pages.length
let indexPage = pages[len - 2]
indexPage.setData({
// 是否切换了城市
cityChanged: true,
// 需要查询的城市
searchCity: name,
})
wx.navigateBack({})
},
О странице
Страница «О странице» — это страница отображения, взаимодействия не так много, используемый API копируется только в буфер обмена.wx.setClipboardData
. «Быстрый контакт WeChat» использует метод, предоставляемый мини-программой, для связи со службой поддержки клиентов.<button open-type="contact" class='btn'></button>
,Будуbutton
Абсолютное позиционирование может быть скрыто под областью щелчка. Если у вас есть энергия, вы можете создать свой собственный сервис и отправить сообщение апплета в свой собственный сервис.
Страница настроек
Функционал страницы настроек выглядит многовато, но это не так уж и много, просто куча вызовов API. Эта страница разделена на три части: «Настроить», «Проверить наличие обновлений», «Виджеты» и «Очистить данные». Каждый параметр настройки сохраняется вstorage
середина. По одному.
1. Настроить
- Настройте фон главной страницы
Пользовательский фон — это изображение, которое будет выбрано (wx.chooseImage
)спасти(wx.saveFile
) на локальную, а потом попадает на домашнюю страницу (wx.getSavedFileList
) сохраненные изображения могут отображаться на домашней странице. Нажмите и удерживайте, чтобы удалить, затем получите (wx.getSavedFileList
) сохраненное изображение, затемwx.removeSavedFile
Просто брось это. Теперь он настроен на локальное сохранение только одного изображения, поэтому при сбросе других фонов предыдущее фоновое изображение будет удалено, а затем снова будет сохранено новое фоновое изображение.
Реализация выглядит следующим образом:
defaultBcg () {
this.removeBcg(() => {
wx.showToast({
title: '恢复默认背景',
duration: 1500,
})
})
},
removeBcg (callback) {
wx.getSavedFileList({
success: function (res) {
let fileList = res.fileList
let len = fileList.length
if (len > 0) {
for (let i = 0; i < len; i++)
(function (path) {
wx.removeSavedFile({
filePath: path,
complete: function (res) {
if (i === len - 1) {
callback && callback()
}
}
})
})(fileList[i].filePath)
} else {
callback && callback()
}
},
fail: function () {
wx.showToast({
title: '出错了,请稍后再试',
icon: 'none',
})
},
})
},
customBcg () {
let that = this
wx.chooseImage({
success: function (res) {
that.removeBcg(() => {
wx.saveFile({
tempFilePath: res.tempFilePaths[0],
success: function (res) {
wx.navigateBack({})
},
})
})
},
fail: function (res) {
let errMsg = res.errMsg
// 如果是取消操作,不提示
if (errMsg.indexOf('cancel') === -1) {
wx.showToast({
title: '发生错误,请稍后再试',
icon: 'none',
})
}
},
})
},
- Открыть топ погоды в городе быстрый поиск
Это действие просто помещает поиск в верхнюю часть главной страницы.wx:if
Просто брось это.switch
Стиль компонента можно изменить, изменив класс по умолчанию, и вы можете настроить тот, который вас устраивает:
.wx-switch-input{width:84rpx !important;height:43rpx !important;}
.wx-switch-input::before{width:82rpx !important;height: 38rpx !important;}
.wx-switch-input::after{width: 38rpx !important;height: 38rpx !important;}
- Показать информацию об индексе жизни
такой жеwx:if
Терять.
- Проверить наличие обновлений
Проверка обновлений по умолчанию отключена. Обновление апплета проверяется при холодном старте, если есть новая версия, то она будет загружена асинхронно, и новая версия будет загружена при повторном холодном старте. используется здесьwx.getUpdateManager
, потому что минимальная версия, поддерживаемая базовой библиотекой API, – 1.9.90. Если версия базовой библиотеки ниже, появится сообщение о том, что она не поддерживается, и отображаемый текст будет соответствующим образом изменен.
- маленькие инструменты
1) НФК
использоватьwx.getHCEState
.
2) Яркость экрана
API-интерфейсы, используемые для получения яркости экрана, установки яркости экрана и поддержания ее всегда включенной:wx.getScreenBrightness
,wx.setScreenBrightness
,wx.setKeepScreenOn
. Полная реализация может бытьПосмотреть исходный код.
3) Системная информация
Системная информация перейдет на новую страницу.
- очистить данные
1) Сброс шара домашней подвески
Информация о положении плавающего шара на домашней странице является локальной переменной.pos
, сбросить положение, очиститьpos
Вот и все.
2) Восстановить первоначальные настройки
Информация о настройках — это переменная, которая сохраняет локальныеsetting
, сбросить положение, очиститьsetting
Вот и все.
3) Очистить все локальные данные
wx.clearStorage
Вот и все.
Совет: Восстановите первоначальные настройки, очистите все локальные данные и не удаляйте фоновое изображение настроек (если настройки есть), это можно будет добавить позже.
разное
Другие детали кода здесь повторяться не будут.Посмотреть исходный код.
Еще одна рекомендация апплета с открытым исходным кодом
Апплет Наггетс: статьяЗдесь: One Nuggets WeChat Mini Program за две недели,Исходный код здесь.