Пошаговая запись мини-программы WeChat (разработка)

Апплет WeChat

Автор: Сунь Менге

Недавно участвовал в разработке первого апплета компании.Опыт разработки в принципе похож на гибридную разработку на базе webview.Может назвать официальным мощным API,но есть и некоторые ямки или места к которым я не привык. Эта статья начинается с практичности и фиксирует некоторые проблемы в процессе разработки:

1. Смешение стилевых приоритетов

При использовании компонента кнопки обнаружено, что установка ширины в классе не действует, вставьте код ниже:

.my-button{
  width: 140rpx;
  height: 60rpx;
  line-height: 60rpx;
  padding: 0;
}

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

Решение на самом деле относительно простое, добавьте ширину к ширине!importantсуффикс илиstyle="width:140rpx"Вот и все, после модификации давайте посмотрим на эффект:

плюс!importantПосле этого фактическое влияние ширины уже оправдало наши ожидания, но инструмент отладки WeChat по-прежнему показывает, что стиль пользовательского агента имеет приоритет, что следует расценивать как ошибку инструмента отладки.

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

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

Реакция имеет<tag {...props}></tag>Такой способ записи, то есть компонент получает реквизит без обработки, и только передает его следующему компоненту, но апплет такой способ записи не поддерживает (жесткий поиск безрезультатный, а в официальном документе это не поясняется) .

Это означает, что нам нужно поставить всеbuttonПараметры, поддерживаемые компонентом, перечислены в свойствах:

properties: {
    classes: {
      type: String,
      value: '',
    },
    type: {
      type: String,
      value: 'default',
    },
    plain: {
      type: Boolean,
      value: false,
    },
    size: {
      type: String,
      value: 'default',
    },
    ......
  },

3. Селектор глобального стиля*Неполноценный

*{
  box-sizing: border-box;
}

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

Как добавить в апплет глобальный общий стиль? Похоже, я могу только вручную написать все теги, которые использую, благо в интернете есть готовые коды, которые можно выложить:

view,scroll-view,swiper,swiper-item,movable-area,movable-view,cover-view,cover-image,icon,text,rich-text,progress,button,checkbox-group,checkbox,form,input,label,picker,picker-view,radio-group,radio,slider,switch,textarea,navigator,functional-page-navigator,image,video,camera,live-player,live-pusher,map,canvas,open-data,web-view,ad{
  box-sizing: border-box;
}

4. Пользовательский компонент, bind:tap вызывается дважды

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

onTap(e) {
  if (!this.data.disabled && !this.data.loading) {
    this.triggerEvent('tap', e.detail)
  }
},
<button bindtap="onTap"></button>

Компоненты, инкапсулированные таким образом, вызовут два события касания, одно из которых запускается самим апплетом, а другое — событием triggerEvent.

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

onTap(e) {
  if (!this.data.disabled && !this.data.loading) {
    this.triggerEvent('click', e.detail)
  }
},

Предотвращение всплытия события tap также может решить эту проблему:

<button catchtap="onTap"></button>

5. Используйте Boolean() для преобразования типов в wxml

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

// player.wxml
<text class="text1" wx:if="{{ Boolean(leftText) }}">{{ leftText }}</text>
// index.wxml
<player leftText="范读"></player>

этот способ письма,leftTextПоле явно пройдено, но текстовый тег все равно не отображается, когда он написан по-другому:

// player.wxml
<text class="text1" wx:if="{{ leftText }}">{{ leftText }}</text>

Это правильно и соответствует нашим ожиданиям.

Волшебно, правда?

6. После того, как InnerAudioContext вызывает метод seek, обратный вызов onTimeUpdate завершается сбоем.

InnerAudioContextДля воспроизведения аудио передайте его вonTimeUpdateОбратный вызов для получения текущего хода воспроизведения.

но при звонкеseekКогда метод переходит в указанную позицию для воспроизведения,onTimeUpdateбольше не звонят.

На самом деле, многие люди в сообществе Mini Program упоминали об этой проблеме.Команде WeChat потребовалось около полутора лет, чтобы исправить ее, поэтому ее можно исправить только временно компромиссным методом.Решение на самом деле очень простое:

progressOnChange(e) {
  if (this.properties.src && this.data.innerAudioContext) {
    const innerAudioContext = this.data.innerAudioContext;
    innerAudioContext.pause();
    innerAudioContext.seek(innerAudioContext.duration * e.detail.value / 100);
    setTimeout(() => {
      innerAudioContext.play();
    }, 500);
  }
},

Сначала приостановите воспроизведение, затем выполнитеseekметод, а затем установите вызов задержки около 500 мсplayметод.

7. InnerAudioContext решает проблему времени продолжительности

Я думал, что будет невозможно получить продолжительность до того, как звук будет воспроизводиться.Интернет про звонкиonPlay,onCanplayАргумент не очень надежный, одно из решений таково:

innerAudioContext.onCanplay(() => {
  setTimeout(() => {
    this.setData({
      durationStr: secondToTimeStr(innerAudioContext.duration) || '--:--',
    });
  }, 500);
});

не говоря уж оsetTimeoutУстановите, сколько миллисекунд подходит, это недопустимо на реальной машине.

Поэтому его до сих пор используют честноonTimeUpdate:

innerAudioContext.onTimeUpdate(() => {
  this.setData({
    durationStr: secondToTimeStr(innerAudioContext.duration) || '--:--'
  })
});

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

8. Установите цвет фона страницы

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

Если вам нужно установить цвет фона страницы, вы можете установить его через стиль тега страницы:

page{
  background: #f9fafb;
}

в ожидании обновления...