Мини-программа WeChat «Улучшенный зеленый оранжевый велосипед»

внешний интерфейс WeChat Апплет WeChat
Мини-программа WeChat «Улучшенный зеленый оранжевый велосипед»

первоначальное намерение

Слышал что 2018 будет годом взрыва маленьких программ.Может быть это для того,чтобы следовать тренду.Как front-end ученик я тоже начал играться с маленькими программами.Теперь,когда спотыкаюсь уже больше месяца Сам того не зная, я тоже хочу что-то сделать, чтобы потренировать свои руки, поэтому у меня есть этот небольшой проект.

Введение в проект

В этом году в моем городе прописали зелено-оранжевый велосипед.Внешний вид простой и модный.В любом случае он мне очень нравится. Так случилось, что я снова изучал апплет, поэтому я хотел сымитировать фронтальную реализацию зелено-оранжевого велосипедного апплета.Проект большой фабрики все еще очень впечатляет.Есть много деталей для улучшения опыта, которые стоят обучения.Я также ввел это в него.Несколько собственных мыслей, в общем, я думаю, что опыт обмена велосипедами может быть лучше.

В процессе этого проекта я наступил на множество ям, которые стоит записать. Поэтому я написал статью и поделился различными аспектами своего процесса реализации, надеясь помочь некоторым студентам.

Моделирование обновления велосипеда

сбросить таргетинг
Определить ближайший велосипед
Нажмите на автоматическое планирование велосипедного пути.
Номер мобильного телефона в поле ввода автоматически делится
Имитация входа
Имитировать поездку с кодом сканирования
Завершить поездку и оплатить

Обновление 2018.6.13 Исправлена ​​ошибка, из-за которой номер мобильного телефона отображался как нулевой.

Адрес источника на Github: Улучшенная версия зеленого 🍊 велосипедаДобро пожаловать в форк, если вам это нужно, если вам это нравится, пожалуйста, дайте звезду


конкретное содержание

Ниже приводится подробное введение

Структура каталогов

●
┣━ config # 存放伪造数据的mock
┣━ images # 图片素材
┣━ libs   # 引入的高德地图SDK
┣━ pages  ● 页面
          ┣━ init                   //主界面
          ┣━ login                  //登录界面
          ┣━ userCenter             //个人中心
          ┣━ messageCenter          //消息中心
          ┣━ unlock                 //解锁
          ┣━ charge                 //计价
          ┣━ end                    //结束行程
          ┣━ repair                 //单车报修
          ┗━ record                 //行程记录
┣━ utils
┣━ app.js
┣━ app.wxss
┣━ app.json
┗━ project.config.json

Создайте гармоничный и последовательный основной интерфейс карты

Основной интерфейс очень простой, верхняя часть представляет собой компонент карты, а нижняя часть — кнопка разблокировки скан-кода, в компоненте карты есть три небольших элемента управления и баннер. Вроде просто, но чтобы сделать такой интерфейс, нужно сначала немного подумать.

Компонент карты — самый сложный компонент апплета, это нативный компонент, созданный клиентом, и его уровень самый высокий, и уровень не может контролироваться z-index.. Это предложение означает, что обычные компоненты не могут быть наложены поверх него. ноcover-viewа такжеcover-imageИсключением является компонент, который будет использоваться следующим.

Для получения более подробной информации см. официальную документацию компонента карты.Карта компонента

Используйте гибкий план, чтобы расположить карту сверху и сканировать код, чтобы разблокировать кнопку внизу

Фактическое измерение показало, что нижняя кнопка зелено-оранжевого велосипеда не является компонентом кнопки, а используется компонент представления, но добавлены некоторые стили. Высота нижней кнопки фиксирована, используя относительную единицу измерения rpx. На разных устройствах высота компонента карты должна иметь возможность автоматически растягиваться или уменьшаться в соответствии с высотой экрана устройства, не влияя на эффект отображения. Использование гибкой верстки — лучшее решение,Просто установите нижней кнопке flex: 1, а верхняя будет адаптивной.

Используйте обложку для создания гармоничных элементов управления

Мы можем использовать элементы управления компонента карты для создания элементов управления. Его также можно сделать с помощью обложки-изображения.

Изучив другие апплеты карт, я обнаружил, что большинство элементов управления картой используют компонент карты.controlsЧтобы сделать, элемент управления поставляется с интерактивным эффектом нажатия, но он может использовать только изображения и не может устанавливать стили, а их единицы ширины и высоты по умолчанию - px.На разных устройствах реальный опыт очень странный.

Зеленое оранжевое использование велосипедаcover-imageЭто сделать элементы управления, покрывающие поверхность карты, и установить размер элемента управления через относительную единицу rpx в стиле, что может принести комфортный эффект.cover-imageбудет полностью заменен в будущемcontrols

Сделайте эффект тени на компоненте карты

В процессе разработки стартовой страницы карты это меня больше всего впечатлило, ведь она меня очень долго мучила. Чтобы привести два случайных примера, давайте посмотрим на эффект в этих небольших программах.

Наличие теневого эффекта никак не влияет на фактическое использование, но, возможно, это внешний интерфейс.РебеСказал, что:Потому что мы инженеры. Даже если его реальный опыт лучше всего на 1%, мы готовы приложить 99% наших усилий..

упомянутый ранеекомпонент картыизВысший уровень. Это тоже точка в яме. Сначала я думал, что использую CSS.свойство box-shadowЭто можно сделать, и эффект тени действительно будет отображаться в противных инструментах разработчика, но при тестировании реальной машины все тени будут покрыты компонентом карты.Я пробовал разные методы безрезультатно, и покрытие- view и cover-image Существует лишь несколько простых стилей CSS, которые могут поддерживаться.В принципе невозможно использовать css для создания теневых эффектов на компонентах карты..

В настоящее время есть только одно решение,Используйте обложку для добавления изображения, которое можно наложить на компонент карты для имитации теней.. На самом деле, эти большие компании делают это.

Проанализировав вышеуказанные проблемы, мы можем успешно сделать эффект этого основного интерфейса.Вы поймете, как это сделать, прикрепив wxml главной страницы.Что касается конкретного метода реализации стиля, вы можете проверить мойисходный код

<view class='map-box'>
  <map id='myMap' latitude='{{latitude}}' longitude='{{longitude}}' markers='{{markers}}' polyline='{{polyline}}' scale='{{scale}}' bindcontroltap='controltap' bindregionchange='regionchange' bindmarkertap='toVisit' show-location>
      <!-- 地图上下阴影 -->
      <cover-image class='map-shadow-top' src='/images/map-shadow-top.png'/>
      <cover-image class='map-shadow-btm' src='/images/map-shadow-btm.png'/>
      <!-- 顶部横幅 -->
      <cover-view class='top-tips'>
        <cover-image class='top-icon' src='/images/top-tip.png'/>
        <cover-view class='top-text'>{{topText}}</cover-view>
      </cover-view>
      <!-- 中心坐标 -->
      <cover-image class='map-icon_point' src='/images/point_in_map.png'/>
      <!-- 控件 -->
      <cover-image class='map-icon map-icon_msg' src='/images/icon-msg.png' bindtap='toMsg'/>
      <cover-image class='map-icon map-icon_user' src='/images/icon-user.png' bindtap='toUser'/>
      <cover-image class='map-icon map-icon_reset' src='/images/reset.png' bindtap='toReset'/>
  </map>
</view>
<view class='main-btn' bindtap='toScan'>
  <text class='main-text'>扫码解锁</text>
</view>

Добавить функцию определения местоположения на карту

Апплет предоставляет нам множество полезных API, с которыми можно ознакомиться во время разработки.API мини-программы

Просто позвониwx.getLocation(OBJECT)Этот API может легко получить текущее местоположение

wx.getLocation({
  type: 'gcj02',
  success: (res) => {
    let longitude = res.longitude;
    let latitude = res.latitude;
    this.setData({
      longitude,
      latitude
    })
})

Сделайте хорошее взаимодействие с картой

В апплете карты наиболее важным взаимодействием с компонентом карты являетсясбросить таргетингэта кнопка

Функция сброса позиционирования очень проста в реализации,Просто сначала создайте контекст карты,Опять такиВызов API moveToLocation()может быть достигнут

 onReady() {
    // 创建map上下文  保存map信息的对象
    this.mapCtx = wx.createMapContext('myMap');
  }

В использованииМобайкВ апплете, если вы увеличили поле зрения карты, вам придется вручную масштабировать карту, чтобы найти велосипеды каждый раз после сброса позиционирования, потому что велосипеды сгруппированы вместе.

В зелено-оранжевом велосипеде опыт намного лучше.После сброса позиционирования уровень масштабирования поля зрения карты также будет сброшен, и вы можете быстро определить положение прикрепленного велосипеда.Метод реализации очень прост. Вам нужно только установить 1 с после сброса позиционирования.

toReset(){
    //调回缩放比,提升体验
    setTimeout(()=>{
      this.setData({
        scale: 18
      })
    },1000)
    this.mapCtx.moveToLocation();
}

Это тоже маленькая деталь,Апплет в виде картыМожно использовать, эффект следующий, этот опыт оченьпрохладно

Напишите случайную функцию для создания поддельных велосипедов

Для достижения большегоРасширенные возможности, мне пришлось сделать некоторые поддельные данные, чтобы смоделировать более реалистичный опыт.

Я просто написал метод для случайной генерации группы велосипедов рядом с текущей координатной точкой.

tocreate(res) {
// 随机单车数量设置 这里设置为1-20辆
    let ran = Math.ceil(Math.random() * 20);
    let markers = this.data.markers;
    for(let i = 0; i < ran; i++) {
      // 定义一个临时单车对象
      var t_bic = {
        "id": 0,
        "title":'去这里',
        "iconPath": "/images/map-bicycle.png",
        "callout":{},
        "latitude": 0,
        "longitude": 0,
        "width": 52.5,
        "height": 30
      }
      // 随机
      var sign_a = Math.random();
      var sign_b = Math.random();
      // 单车分布密集度设置
      var a = (Math.ceil(Math.random() * 99)) * 0.00002;
      var b = (Math.ceil(Math.random() * 99)) * 0.00002;
      t_bic.id = i;
      t_bic.longitude = (sign_a > 0.5 ? res.longitude + a : res.longitude - a);
      t_bic.latitude = (sign_b > 0.5 ? res.latitude + b : res.latitude - b);
      markers.push(t_bic);
    }
    //将模拟的单车数据暂时存储到本地
    wx.setStorage({
      key: 'bicycle',
      data: markers
    })
    this.setData({
      markers
    })
}

Далее, пока компонент картыbindregionchangeПросто вызовите функцию поддельного велосипеда в событии

bindregionchangeСобытие может срабатывать при изменении поля зрения карты, но я не хочу, чтобы карта немного двигалась, чтобы обновить байк, поэтому мне также нужно просто смоделировать порог для перемещения байка обновления

regionchange(e){ 
    // 拿到起点经纬度
    if(e.type == 'begin') {
      this.mapCtx.getCenterLocation({
        type: 'gcj02',
        success: (res) => {
          this.setData({
            lastLongitude: res.longitude,
            lastLatitude: res.latitude
          })
        }
      })
    }
    // 拿到当前经纬度
    if (e.type == 'end') {
      this.mapCtx.getCenterLocation({
        type: 'gcj02',
        success: (res) => {
          let lon_distance = res.longitude - this.data.lastLongitude;
          let lat_distance = res.latitude - this.data.lastLatitude;
          // console.log(lon_distance,lat_distance)
          // 判断屏幕移动距离,如果超过设定的阈值,模拟刷新单车
          if (Math.abs(lon_distance) >= 0.0035 || Math.abs(lat_distance) >= 0.0022){
            console.log('刷新单车')
            this.setData({
              // 刷新单车之前先清空原来的单车
              markers: []
            })
            this.tocreate(res)
          }
        }
      })
    }
}

Таким образом достигается следующий эффект

Реализовать функцию оценки ближайшего велосипеда

Вы должны были давно обнаружить, что среди велосипедов на карте ближайший велосипед будет иметь离我最近маленький пузырь. Это функция поиска ближайшего велосипеда.Мобайквыполняет эту функцию, нозеленый оранжевый велосипедОфициальный не присоединился к этому небольшому опыту, который должен быть в будущем. Вот пытаюсь реализовать

реализовать логику

  1. Пройдите расстояние между каждым велосипедом на текущей карте и центральной точкой координат и сохраните его в массиве.

  2. Пройдите массив, найдите в нем наименьшее значение и верните индекс наименьшего значения.

  3. Добавьте всплывающую подсказку к велосипеду, соответствующему минимальному индексу.

    nearestBic(res) {
        // 找出最近的单车
        let markers = this.data.markers;
        let min_index = 0;
        let distanceArr = [];        //存放单车距离的数组
        for (let i = 0; i < markers.length; i++) {
          let lon = markers[i].longitude;
          let lat = markers[i].latitude;
          // 计算距离  sqrt((x1-x2)^2 + (y1-y2)^2 )
          let t = Math.sqrt((lon - res.longitude) * (lon - res.longitude) + (lat - res.latitude) * (lat - res.latitude));
          let distance = t;
          // 将每一次计算的距离加入数组 distanceArr
          distanceArr.push(distance)
        }
        //从距离数组中找出最小值
        let min = distanceArr[0];
        for (let i = 0; i < distanceArr.length; i++) {
          if (parseFloat(distanceArr[i]) < parseFloat(min)) {
            min = distanceArr[i];
            min_index = i;
          }
        }
        let callout = "markers[" + min_index + "].callout";
        // 清除旧的气泡,设置新气泡
        wx.getStorage({
          key: 'bicycle',
          success: (res) => {
            this.setData({
              markers: res.data,
              [callout]: {
                "content": '离我最近',
                "color": "#ffffff",
                "fontSize": "16",
                "borderRadius": "50",
                "padding": "10",
                "bgColor": "#0082FCaa",
                "display": 'ALWAYS'
              }
            })
          }
        })
    }
    

поместите эту функцию вОбновляйте велосипед каждый раза такжеизменение поля зрения картыПри вызове вы можете увидеть следующие эффекты, перейдите к подробному процессу вызова:исходный код

Реализуйте ручной выбор велосипедов для автоматического планирования пешеходного маршрута.

Эм. . . Я думаю, что эта функция все еще необходима, и она будет встречаться в некоторых сценариях.

Например: я хочу покататься на велосипеде, но передо мной нет машины.

Или, если машина всего одна, откройте WeChat для сканирования кода, и тогда появится плохой результат: велосипед временно недоступен.

Я все еще хочу кататься на велосипеде, но я не хочу идти пешком. Функция карты работает. Я буду проверять другие велосипеды возле карты. В это время я вижу несколько велосипедов, но мне нужно пройти некоторое время, чтобы найти Если я смогу щелкнуть по этому велосипеду, просто автоматически спланирую свой пешеходный маршрут.

Итак, я смело сделал реализацию, как показано ниже

Далее поговорим о том, как этого добиться

Если вы хотите реализовать функцию автоматического планирования пути, реализовать ее самостоятельно в принципе невозможно, для этого нужно использовать мощную силу третьей стороны.

Представляем AutoNavi Map SDK

Во-первых, я не знаю, подумаете ли вы так:Что? AutoNavi SDK используется в Tencent Maps?

Это не невозможно. В WeChat Applet, будь то карта Baidu, карта автонави, или карта Tencent, JavaScript SDK специально предоставлен для апплета.

SDK апплета с микрописьмом на высоконравственной карте может помочь нам разбогатеть в апплетеописание адреса,POIа такжеданные о погоде в режиме реального времении реализоватьГеокодированиеа такжеобратное геокодированиеОн очень мощный, но здесь нам нужно только его использоватьплан маршрутафункция

SDK программы AutoNavi Map WeChat Mini

Ни Tencent Maps, ни Baidu Maps не предоставляют функцию автоматического планирования маршрута для мини-программ WeChat, поэтому AutoNavi Maps по-прежнему очень внимателен.

Чтобы использовать его, вы должны перейти на открытую платформу карт AutoNavi, чтобы зарегистрироваться и получить свой собственный ключ.Подробные шаги находятся вРуководство по началу работы с пакетом SDK для программы AutoNavi Map WeChat Miniясно объяснил в

адрес загрузки SDK

После скачивания распакуйте его, создайте новую папку libs в директории проекта и поместите в нее

Затем импортируйте его в начало файла js, который необходимо использовать.

var amapFile = require('../../libs/amap-wx.js');
var myAmapFun = new amapFile.AMapWX({ key: '你的key' });

С его помощью вы можете написать метод, посвященный пути к правилу.

route(bic){
    // 获取当前中心经纬度
    this.mapCtx.getCenterLocation({
      success: (res) => {
        // 调用高德地图步行路径规划API
        myAmapFun.getWalkingRoute({
          origin: `${res.longitude},${res.latitude}`,
          destination: `${bic.longitude},${bic.latitude}`,
          success: (data) => {
            let points = [];
            if (data.paths && data.paths[0] && data.paths[0].steps) {
              let steps = data.paths[0].steps;
              for (let i = 0; i < steps.length; i++) {
                let poLen = steps[i].polyline.split(';');
                for (let j = 0; j < poLen.length; j++) {
                  points.push({
                    longitude: parseFloat(poLen[j].split(',')[0]),
                    latitude: parseFloat(poLen[j].split(',')[1])
                  })
                }
              }
            }
            // 设置map组件polyline,绘制线路
            this.setData({
              polyline: [{
                points: points,
                color: "#ffffffaa",
                arrowLine:true,
                borderColor: "#3CBCA3",
                borderWidth:2,
                width: 5,
              }]
            });
          }
        })
      }
    })
}

Апплет WeChatкомпонент картыпри условиисвойство полилинии, он может нарисовать путь в соответствии с заданной точкой над компонентом карты

Цвет и стиль пути можно установить, вау ~ это немного круто

Здесь, чтобы отдать дань уважения зелено-оранжевому велосипеду, я стараюсь сделать стиль дорожки похожим на зелено-оранжевый велосипед 😀, а затем давайте рассмотрим эффект

Создайте хороший интерфейс входа

Об основном интерфейсе карты позаботились, теперь давайте напишем интерфейс входа в систему.

Страница входа кажется простой, но если вы хотите сделать интерфейс входа удобным, в нем все еще много логики.

Автоматическое разделение номеров мобильных телефонов

В зелено-оранжевом аплете велосипеда я нашел такую ​​маленькую деталь, номер мобильного телефона, введенный в поле ввода, будетразделить автоматически, Я чувствую, что это хороший пользовательский интерфейс.Номер мобильного телефона, отображаемый в разбивке, может с первого взгляда сделать ошибки в процессе ввода, и это выглядит более освежающим.

Чтобы повторить этот опыт, я реализовал его по собственной логике.

Моя логика реализации

  1. Номер мобильного телефона состоит из 11 цифр, разделенных на три сегмента.XXXпространствоXXXXпространствоXXXX,мы в3-й входа также7-й входДобавьте пробел после числа, разве вы не можете добиться такого эффекта?

  2. Поскольку добавляются два пробела, максимальная длина поля ввода составляет 13 цифр.

  3. ВходvalueСвойство привязано к phoneText, определенному в данных логического слоя, а затем вы можете использовать js для изменения его отображения.важный!!

  4. Установите свойство bindinput для выполнения функции ввода для каждого ввода.

    <input class='input' placeholder='请输入手机号' maxlength="13" value='{{phoneText}}' bindinput='input'/>

Я написал этот метод ввода для сегментации номеров мобильных телефонов.

    input(e) {
        let value = e.detail.value;
        //正则过滤
        value = value.replace(/[\u4E00-\u9FA5`~!@#$%^&*()_+<>?:"{},.\/;'[\]\-\sa-zA-Z]*/g, "");
        let result = [];
        for (let i = 0; i < value.length; i++) {
          if (i == 3 || i == 7) {
            result.push(" ", value.charAt(i));
          }
          else {
            result.push(value.charAt(i));
          }
        }
        this.setData({
          phoneText: result.join("")
        })
    }

Примечание. Однако для достижения этого эффекта были сделаны некоторые компромиссы, то есть встроенная цифровая клавиатура WeChat не может быть вызвана. В противном случае вы не увидите эффекта от этой сегментации

Фактически, с помощью встроенной клавиатуры WeChat можно легко избежать ввода недопустимых символов, то есть символов, отличных от цифр, таких как:английский алфавит,ПунктуацияЖдать.

кнопка доступна и недоступна логика

До того, как основное заполнение поля ввода будет завершено, кнопка должна быть недоступна, а поле ввода проверочного кода должно быть скрыто.После того, как пользователь завершит заполнение, появится окно ввода проверочного кода, а кнопка загорится после проверочного кода является вводом. Он должен больше соответствовать психологическому внушению пользователя.

На этой странице есть две кнопки获取验证码так же как下一步с одним清楚输入框图标

  • Поле ввода номера мобильного телефона не должно позволять вводить символы, кроме цифр, хотя здесь его точно не будет.xss, но для строгости все же используется для фильтрации
  • Когда в поле ввода есть содержимое,кнопка очистки содержимогопоявляется после очистки содержимого,кнопка очистки содержимогопропадать,все кнопкинедоступен
  • Заполните его номер телефона,Кнопка "Получить код подтверждения"становится доступным, и появляется окно ввода проверочного кода
  • Удовлетворены как номер мобильного телефона, так и проверочный код.После заполнения условий,следующая кнопкаСтановятся доступными
  • Нажмите «Далее» или получите код подтверждения, проверьте правильность номера мобильного телефона.

Эффект реализации выглядит следующим образом, пожалуйста, перейдите к исходному коду для конкретного кода реализации.

Функция разблокировки скан-кодом

Чтобы добиться разблокировки скан-кода, вам нужно всего лишь вызвать апплетwx.scanCode()Этот API может вызвать функцию сканирования кода камеры.Конечно, проверка входа выполняется перед сканированием кода.Если вы не вошли в систему, переключитесь на интерфейс входа.Поскольку это только реализация функции интерфейса , вы можете сразу перейти к интерфейсу разблокировки после сканирования кода.

toScan(){
    if (!app.globalData.loginStatus) {
      wx.showModal({
        title: '提示',
        content: '请先登录',
        success: (res) => {
          if (res.confirm) {
            wx.navigateTo({
              url: '/pages/login/login'
            })
          }
        }
      })
    } else {
      wx.scanCode({
        success: (res) => {
          onlyFromCamera: false,
          console.log('扫码成功');
          wx.navigateTo({
            url: '/pages/unlock/unlock',
          })
        }
      })
    }
}

После разблокировки войдите в состояние езды, эффект будет следующим:

В состоянии движения отображается только текущее движущееся транспортное средство, а над транспортным средством добавляется пузырь, указывающий на то, что происходит движение.

Оплата проезда

Зарядка общих велосипедов оценивается по времени использования.Поскольку нет внутренних данных, здесь можно написать только метод таймера Time() для имитации зарядки.

 Time(){
    let s = 0;
    let m = 0
    // 计时开始
    this.timer = setInterval(() => {
      this.setData({
        second: s++
      })
      if (s == 60) {
        s = 0;
        m++;
        setTimeout(() => {
          this.setData({
            minute: m
          });
        }, 1000)
      };
    }, 1000)
  }

Когда поездка начинается, вызовите таймер, запустите таймер, нажмите, чтобы закончить поездку, таймер останавливается, цена рассчитывается в зависимости от продолжительности и переходите на страницу оплаты.

Эпилог

Поскольку время относительно короткое, некоторые функции проекта еще не добавлены, а также есть некоторые области, которые нужно улучшить. В будущем я найду время, чтобы медленно отшлифовать его. Если у вас есть идеи получше, вы также можете связаться мне улучшить его вместе.

Наконец, снова прикрепите адрес моего проекта:Улучшенный зеленый 🍊 велосипед

Если вам это нравится, не скупитесь на свою Звезду!

Оригинальная ссылка:Хижина роста без зазрений совести: «улучшенная версия зеленого 🍊 велосипеда»