Научит вас писать апплет 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)
}
}
оптимизация производительности
- Избегайте частого setState
Поскольку уровень логики и уровень представления апплета WeChat независимы, передача данных с обеих сторон основана на преобразованных строках. Поэтому, когда частота setData слишком высока, а контент огромен, это вызовет блокировку. Поскольку этот проект включает в себя множество операций с жестами, частота событий touchmove очень высока, поэтому на ранней стадии проекта зависание в системе Android очень очевидно.
Методы оптимизации: уменьшить частоту setData за счет дросселирования функции; привязать данные, не относящиеся к странице, не к данным, а к экземпляру компонента (жертвуя эффективностью вычислений в обмен на эффективность пространства).
Использование пользовательских компонентов WeChat также является большим фактором улучшения.Лично я предполагаю, что изменения во внутренних данных пользовательских компонентов не приведут к обновлению данных других компонентов или страниц. Фреймворк wepy был принят на ранней стадии проекта, и из-за исторических ограничений (WeChat в то время не анонсировал схему пользовательских компонентов) проблема эффективности всегда была головной болью. К счастью, фреймворк Taro отлично поддерживает это решение путем компиляции.
- объединить setState
Например, когда изображение загружено и получен исходный размер, необходимо вычислить заданный размер и положение изображения в текущей сцене. Сначала необходимо рассчитать адаптивную ширину и высоту, а затем можно рассчитать предустановленное смещение. Поэтому, после вычисления параметров размера и позиции, вызовите setState для обновления представления, что не только уменьшит частоту, но и решит баг с мерцанием изображения.
- Использовать кеш
Ранее упоминалось, что модуль кэша используется для хранения информации о состоянии компонента или ресурсах, и здесь повторяться не будем.
опыт
Фреймворк Taro использует метод компиляции: исходный код компилируется отдельно и может использоваться на разных сторонах (апплет WeChat/Baidu/Alipay/ByteDance, H5, React-Native и т. д.), поэтому его можно сравнивать с каждой платформой в Условия выполнения. Будьте последовательны.
Решение mpvue состоит в том, чтобы изменить среду выполнения Vue, связать экземпляр Vue с экземпляром Mini Program Page и связать жизненный цикл. Лично я считаю, что такой метод картирования может привести к снижению эффективности коммуникации, а vue и WeChat итерируются независимо друг от друга, и согласование на более позднем этапе становится все сложнее, поэтому лично мне кажется, что решение Taro немного лучше. Лично я хотел бы спросить Haihan.
напиши в конце
-
Github
Приветствую всех желающих пообщаться в рамках этого демонстрационного проекта.адрес проекта (GitHub.com/Гарри Чен05…), ваши лайки будут моей отличной мотивацией 😊
-
онлайн проект
Онлайн небольшая демонстрация текущего проекта может пройти через опыт сканирования микро-канала 👏 после двухмерного кода
- волна рекламы
versa — компания, занимающаяся искусственным интеллектом, которая занимается применением технологий искусственного интеллекта в области визуальных изображений. Мы ищем разработчиков всех видов. Заинтересованные партнеры могут связаться со мной на сайте. (перепечатано, просьба указать источник)