Научит вас писать апплет WeChat для обработки изображений с использованием фреймворка Taro.

Апплет WeChat

Научит вас писать апплет WeChat для обработки изображений с использованием фреймворка Taro.

предисловие

В середине 2018 года компания, в которой работает автор, обратилась к нам с просьбой разработать апплет WeChat (Macaron Play Map). Основной игровой процесс заключается в том, что пользователь загружает портретную фотографию, изображение обрабатывается внутренним алгоритмом искусственного интеллекта для идентификации персонажа, а персонаж и окружающая среда сегментируются (широко известная как матирование); внешний интерфейс будет выполнять обработка стилей на возвращенном покрытии, включая настройку размера и положения, вращение и т. д.; с помощью некоторых предустановленных (или загруженных пользователем) тематических сцен и украшенных наклеек или фильтров пользователи могут перемещать или масштабировать эти элементы, что может привести к множеству интересных методов ретуширования. , такие как смена динамических фонов, синтез ленты Динамическое видео со звуком и т. д. (в конце статьи есть QR-код WeChat).

演示

На ранней стадии развития необязательный зрелый WeChat Applet Framework был толькоwepy, После практики разработки выяснилось, что wepy не очень дружелюбен в плане рендеринга многоуровневых вложенных списков, поддержки компонентизации и т.п. Позже техническая команда Meituan открыла исходный код апплета на основе Vue.mpvue, После опыта, хотя опыт в компонентизации ничем не отличается от vue, но преимущества в производительности у него нет.

Пока однажды друг не потянул меня в группу разработки Taro.Оказалось, что фронтенд-команда JD.com тоже разрабатывала небольшой программный фреймворк на основе спецификации React.В то время я беспокоился, что Taro все еще находится на ранней стадии, и может быть недостаточно функций или ошибок. Еще не начал. До недавнего обновления до версии 1.2.4 некоторые даосы в группе сделали волну Amway, поэтому автор решил провести рефакторинг некоторых модулей проекта, и обнаружил, что Taro действительно получил опыт разработки и производительность.Очень приятное улучшение, большая дань уважения авторам Таро. В духе открытого исходного кода автор также поделится с вами исходным кодом демо и опытом этой реконструкции.

анализ спроса

需求分析
После вырезания загруженного пользователем портрета он будет отображаться в области рисования, а отображаемые при этом элементы включают фоновые изображения и подвижные или неподвижные стикеры. Чтобы получить лучший визуальный опыт пользователя, в каждой сцене предварительно задайте размер и положение портретов и наклеек (параметры — это процент области рисования и т. Д.). Портреты и стикеры должны поддерживать операции жестов одним и двумя пальцами для изменения размера и положения, поэтому и портреты, и стикеры могут быть инкапсулированы как компоненты стикера, а подкомпонент стикера передает параметры стиля после операции жеста. к родительскому компоненту страницы, запуская родительский компонент setState для обновления и, наконец, управляя стилем, передавая реквизиты дочернему компоненту.

Некоторые сведения о компоненте «Наклейка» также включают: компонент «Наклейка» находится в активном состоянии (щелкните текущий компонент, чтобы отобразить контроллер, в то время как другие компоненты скрыты); после переключения сцен предыдущие пользовательские операции должны кэшироваться, а при переключении обратно на исходную сцену, а затем восстановить последнее рабочее состояние пользователя в этом сценарии.

После того, как пользователь нажмет «Сохранить», отсортируйте все элементы в области рисования в соответствии с размером иерархии, а затем нарисуйте через интерфейс холста, предоставляемый WeChat, и, наконец, верните синтетическую карту красоты WYSIWYG.

Готов к работе

Согласно ТароДокументация, установить инструменты CLI и создать шаблоны проектов, рекомендуется выбрать метод разработки Typescript.

каталог проекта

Кратко проанализируйте структуру проекта

Taro-makaron-demo
├── dist                   编译结果目录
├── config                 配置目录
|   ├── dev.js             开发时配置
|   ├── index.js           默认配置
|   └── prod.js            打包时配置
├── src                    源码目录
|   ├── assets             静态资源
|   |   ├── images         图片
|   ├── components         组件
|   |   ├── Sticker        贴纸组件
|   |   ├── ...            其他组件
|   ├── model              Redux数据流
|   |   ├── actions        
|   |   ├── constants        
|   |   ├── reducers        
|   |   ├── store        
|   ├── pages              页面文件目录
|   |   ├── home           首页
|   |   |   ├── index.js   index 页面逻辑
|   |   |   └── index.css  index 页面样式
|   |   ├── dynamic        作图页
|   |   |   ├── index.js   index 页面逻辑
|   |   |   └── index.css  index 页面样式
|   ├── services           服务
|   |   ├── config.ts      全局配置
|   |   ├── api.config.ts  api接口配置
|   |   ├── http.ts        封装的http服务
|   |   ├── global_data.ts 全局对象
|   |   ├── cache.ts       缓存服务
|   |   ├── session.ts     会话服务
|   |   ├── service.ts     基础服务或业务服务
|   ├── utils              公共方法
|   |   ├── tool.ts        工具函数
|   ├── app.css            项目总通用样式
|   └── app.js             项目入口文件
└── package.json

Анализ основного кода

  • стикер наклейка компонент

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

// 使用
class Page extends Component {
    state = {
        foreground: { // 人像state
          id: 'foreground', // id
          remoteUrl: '', // url
          zIndex:2, // 层级
          width:0, // 宽
          height:0, // 高
          x: 0, // x轴偏移量
          y:0, // y轴偏移量
          rotate: 0, // 旋转角度
          originWidth: 0, // 原始宽度
          originHeight: 0, // 原始高度
          autoWidth: 0, // 自适应后的宽度
          autoHeight: 0, // 自适应后的高度
          autoScale: 0, // 相对画框缩放比例
          fixed: false, // 是否固定
          isActive: true, // 是否激活
          visible: true, // 是否显示
        }
    }
    render () {
        reuturn <Sticker 
                    ref="foreground"
                    url={foreground.remoteUrl}
                    stylePrams={foreground}                
                    framePrams={frame}
                    onChangeStyle={this.handleChangeStyle}
                    onImageLoaded={this.handleForegroundLoaded}
                    onTouchstart={this.handleForegroundTouchstart}
                    onTouchend={this.handleForegroundTouchend}
              />
    }
}

// 组件定义
class Sticker extends Component {
...
    render() {
        const { url, stylePrams } = this.props
        const { framePrams } = this.state
        const styleObj = this.formatStyle(this.props.stylePrams)
        return (
          <View 
            className={`sticker-wrap ${stylePrams.fixed ? 'event-through' : ''} ${(stylePrams.visible && stylePrams.width > 0) ? '' : 'hidden' }`}
            style={styleObj}
          > 
            <Image 
              src={url} 
              mode="widthFix" 
              style="width:100%;height:100%"
              onLoad={this.handleImageLoaded} // 图片加载后将原始尺寸信息通知给父组件
              onTouchstart={this.stickerOntouchstart} 
              onTouchmove={this.throttledStickerOntouchmove} // touchmove比较频繁,需要节留
              onTouchend={this.stickerOntouchend}/>
            <View className={`border ${stylePrams.isActive ? 'active' : ''}`}></View>
            <View className={`control ${stylePrams.isActive ? 'active' : ''}`}
              onTouchstart={this.arrowOntouchstart} 
              onTouchmove={this.throttledArrowOntouchmove}
              onTouchend={this.arrowOntouchend}
            >
              <Image src={scale} mode="widthFix" style="width:50%;height:50%"/>
            </View>
          </View>
        )
    }
}

  • кэш-сервис Служба кэширования очень полезна для повышения производительности. Например, для рисования на холсте требуется, чтобы изображение было локальным. Вы можете использовать словарь данных, чтобы сопоставить удаленный адрес изображения с адресом, загруженным на локальный, что значительно сэкономит сетевых ресурсов и времени.
// services/cache.ts 缓存服务
function Cache (name) {
  this.name = name
}
Cache.prototype = {
  set: function (key, value) {
    this[key] = value
    return this[key]
  },
  get: function (key) {
    return this[key]
  },
  clear: function () {
    // 清空
    Object.keys(this).forEach(v => {
      this[v] = null
    })
  }
}

export const createCache = (name:string) => {
  return new Cache(name)
}
// 使用
import {createCache} from '../../services/cache'
class Page extends Component {
  cache = {
    source: createCache('source'),
  }
  // 下载照片并存储到本地
  downloadRemoteImage = async (remoteUrl = '') => {
    const cacheKey = `${remoteUrl}_localPath`
    const cache_source = this.cache['source']
    let localImagePath = ''
    if (cache_source.get(cacheKey)) {
      // 有缓存
      return cache_source.get(cacheKey)
    } else {
      try {
        const result = await service.base.downloadFile(remoteUrl)
        localImagePath = result.tempFilePath
      } catch (err) {
        console.log('下载图片失败', err)
      }
    }
    return cache_source.set(cacheKey, localImagePath)
  }
}

оптимизация производительности

  1. Избегайте частого setState

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

Методы оптимизации: уменьшить частоту setData за счет дросселирования функции; привязать данные, не относящиеся к странице, не к данным, а к экземпляру компонента (жертвуя эффективностью вычислений в обмен на эффективность пространства).

Использование пользовательских компонентов WeChat также является большим фактором улучшения.Лично я предполагаю, что изменения во внутренних данных пользовательских компонентов не приведут к обновлению данных других компонентов или страниц. Фреймворк wepy был принят на ранней стадии проекта, и из-за исторических ограничений (WeChat в то время не анонсировал схему пользовательских компонентов) проблема эффективности всегда была головной болью. К счастью, фреймворк Taro отлично поддерживает это решение путем компиляции.

  1. объединить setState

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

  1. Использовать кеш

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

опыт

Фреймворк Taro использует метод компиляции: исходный код компилируется отдельно и может использоваться на разных сторонах (апплет WeChat/Baidu/Alipay/ByteDance, H5, React-Native и т. д.), поэтому его можно сравнивать с каждой платформой в Условия выполнения. Будьте последовательны.

Решение mpvue состоит в том, чтобы изменить среду выполнения Vue, связать экземпляр Vue с экземпляром Mini Program Page и связать жизненный цикл. Лично я считаю, что такой метод картирования может привести к снижению эффективности коммуникации, а vue и WeChat итерируются независимо друг от друга, и согласование на более позднем этапе становится все сложнее, поэтому лично мне кажется, что решение Taro немного лучше. Лично я хотел бы спросить Haihan.

напиши в конце

  • Github

    Приветствую всех желающих пообщаться в рамках этого демонстрационного проекта.адрес проекта (GitHub.com/Гарри Чен05…), ваши лайки будут моей отличной мотивацией 😊

  • онлайн проект

Онлайн небольшая демонстрация текущего проекта может пройти через опыт сканирования микро-канала 👏 после двухмерного кода

马卡龙玩图

  • волна рекламы

versa — компания, занимающаяся искусственным интеллектом, которая занимается применением технологий искусственного интеллекта в области визуальных изображений. Мы ищем разработчиков всех видов. Заинтересованные партнеры могут связаться со мной на сайте. (перепечатано, просьба указать источник)