предисловие
Таро из Bump Lab следует за вамиReactграмматическийМультитерминальный план развития,TaroВ настоящее время он был открытым исходным кодом в течение определенного периода времени и широко приветствовался и беспокоился разработчиками интерфейса. до настоящего времениstarЧисло превысило 11,7 тыс., более 200 вопросов все еще открыты, а закрыты более 700. Видно, что много разработчиков, которые используют и участвуют в обсуждениях. В настоящее время Taro поддерживает апплет WeChat, H5, RN, апплет Alipay и апплет Baidu. Taro, который постоянно дорабатывается, также совместим с большим количеством терминалов и добавляет поддержку некоторых новых функций.
Возвращаясь к теме, в этой статье в основном рассказывается о практике углубленного развития Таро.Основываясь на нашем опыте и резюме использования Таро в реальных проектах, мы сначала поговорим о Таро.Почему стоит использовать синтаксис React, а затем изКод организации проекта Таро,Управление статусом данных,оптимизация производительноститак же какСовместимость с несколькими терминаламиНесколько других аспектов, иллюстрирующих опыт глубокой практики развития Таро.
Почему стоит использовать синтаксис React
Это видно по двум аспектам: во-первых, нативный метод разработки небольших программ недостаточно дружелюбен, либо недостаточно инженерен, а разрабатывать какие-то масштабные проекты будет очень сложно, что в основном отражается в следующем точки:
- Страница или компонент апплета должны одновременно содержать 4 файла, поэтому при разработке функционального модуля ему необходимо переключаться между несколькими файлами.
- Sass, Less и более новый синтаксис ES Next нельзя использовать напрямую без специальной предварительной обработки файлов.
- Строковый шаблон слишком слабый Строковый шаблон апплета имитируетVue, но не обеспечиваетVueСтолько синтаксического сахара, при реализации какой-то более сложной обработки писать очень хлопотно, хотя и обеспечивает
wxs
В качестве дополнения, но опыт все еще очень плохой - Отсутствие наборов тестов, неспособность написать тестовый код для обеспечения качества проекта, а также неспособность выполнять непрерывную интеграцию и автоматическую упаковку.
Нативный метод разработки не является дружественным, и, естественно, есть более эффективная альтернатива. Поэтому мы обратили свое внимание на три популярных на рынке интерфейсных фреймворка.React,Vue,Angular.AngularПопулярность в стране невысокая, мы сначала исключили эту грамматическую спецификацию. На рынке уже есть несколько отличных проектов с открытым исходным кодом для Vue-подобных сред разработки апплетов, и технологический стек в нашем отделе в основном React, затемСпецификация синтаксиса ReactЭто, естественно, стало нашим первым выбором. Кроме того, у нас есть следующие соображения:
- React — очень популярный фреймворк с большой аудиторией, использование которого также может снизить стоимость обучения при разработке небольших программ.
- Идея и механизм реализации управляемого данными обновления шаблонов для небольших программ, подобных React
- React использует JSX в качестве собственного шаблона.По сравнению со строковыми шаблонами, JSX более свободен, естественнее и выразительнее.Ему не нужно полагаться на различные синтаксические сахара строковых шаблонов, а также можно выполнять сложную обработку.
- У самого React есть кросс-конечное решение для реализации ReactNative, которое очень зрелое и имеет активное сообщество.Для Таро есть больше возможностей для многоконечной разработки.
Подводя итог, Таро наконец принялСинтаксис реакцииОн используется в качестве собственного стандарта грамматики в сочетании с идеей разработки интерфейса, чтобы создать более элегантный опыт разработки для разработки небольших программ.
Код организации проекта Таро
Чтобы разрабатывать проекты Taro, вы должны сначала установить taro-cli.Чтобы узнать о конкретном методе установки, см.Документация, я не буду вводить здесь слишком много, по умолчанию вы установили taro-cli и можете запускать команды.
Затем мы используем cli для создания нового проекта, и результирующий шаблон проекта выглядит следующим образом:
├── dist 编译结果目录
├── config 配置目录
| ├── dev.js 开发时配置
| ├── index.js 默认配置
| └── prod.js 打包时配置
├── src 源码目录
| ├── pages 页面文件目录
| | ├── index index页面目录
| | | ├── index.js index页面逻辑
| | | └── index.css index页面样式
| ├── app.css 项目总通用样式
| └── app.js 项目入口文件
└── package.json
Если это очень простой проект, такой шаблон можно использовать для удовлетворения требований, а необходимая для страницы логика прописывается в файле index.js.
Если в проекте используется избыточность, как в проекте, который мы разработали ранее, каталог выглядит следующим образом:
├── dist 编译结果目录
├── config 配置目录
| ├── dev.js 开发时配置
| ├── index.js 默认配置
| └── prod.js 打包时配置
├── src 源码目录
| ├── actions redux里的actions
| ├── asset 图片等静态资源
| ├── components 组件文件目录
| ├── constants 存放常量的地方,例如api、一些配置项
| ├── reducers redux里的reducers
| ├── store redux里的store
| ├── utils 存放工具类函数
| ├── pages 页面文件目录
| | ├── index index页面目录
| | | ├── index.js index页面逻辑
| | | └── index.css index页面样式
| ├── app.css 项目总通用样式
| └── app.js 项目入口文件
└── package.json
Для апплета электронной коммерции, который мы разработали ранее, весь проект содержит около 30 000 строк кода и десятки страниц, организованных в соответствии с приведенным выше каталогом. Наиболее важные папки в основномpages
,components
а такжеactions
.
-
pagesВнутри находится входной файл каждой страницы.Простая страница может быть непосредственно входным файлом.Если страница более сложная, входной файл будет использоваться как совокупный файл компонента.
redux
Привязка в основном тоже осуществляется на этой странице. -
компоненты размещеныcomponentsв. Каталог внутри такой, если есть
coupon
страница с купоном, наpages
Конечно, естьcoupon
, как запись страницы, а затем его компоненты сохраняются вcomponents/coupon
внутри, то естьcomponentsОн также будет разделен на модули в соответствии со страницей, и может быть построен общий компонент.components/public
папка для повторного использования.Преимущество этого в том, что между страницаминезависимо друг от друга,не влияют друг на друга. Поэтому некоторые наши разработчики также делят труд по размерам страницы, не мешая друг другу, что значительно повышает эффективность нашей разработки.
-
actionsЭта папка тоже важнее, здесь логика вытягивания данных и повторной обработки данных. Можно сказать, что если данные обрабатываются хорошо и поток понятен, весь проект наполовину успешен.Подробности см. в разделе ***Управление статусом данных*** ниже. как указано выше, если
coupon
страницыactions
, то он будет помещен вactions/coupon
Внутри вы снова можете увидеть, что все модули различаются по размеру страницы.
Помимо,assetСтатические ресурсы, для хранения которых используется файл, например некоторые изображения класса значков, но рекомендуется не хранить слишком много, в конце концов, существуют ограничения на пакет. а такжеconstantsЭто место для хранения констант, напримерapi
Доменное имя, конфигурация и т. д.
После завершения настройки проекта в корневом каталоге командной строкиnpm run build:weapp
илиtaro build --type weapp --watch
Скомпилируйте его в апплет, а затем вы можете открыть инструмент разработки апплета для предварительной разработки. Если вы компилируете на другом конце, вам нужно указать только тип (например, компиляция H5:taro build --type h5 --watch
).
При разработке проекта с Taro, если код хорошо организован и следует спецификациям и условностям, половина успеха будет достигнута, по крайней мере, это сделает разработку более эффективной.
Управление статусом данных
Как упоминалось выше, redux будет использоваться для управления состоянием данных.
Когда дело доходит до редукса, я считаю, что все уже знакомы с ним. В Taro его использование похоже на обычное использование в React, сначала создайтеstore
,reducers
, а затем напишитеactions
; затем по@tarojs/redux
,использоватьProvider
а такжеconnect
, который привязывает хранилище и действия к компоненту. Все знают основы использования, позвольте мне представить вам, как лучше использовать redux.
предварительная обработка данных
Я считаю, что с таким моментом сталкивался каждый, данные, возвращаемые интерфейсом, и данные, отображаемые на странице, не полностью совпадают, и часто требуется слой предобработки. Итак, где должна управляться эта бизнес-логика, внутри компонента илиredux
обработать?
Например:
Например, в модуле корзины покупок, показанном выше, данные, возвращаемые интерфейсом,
{
code: 0,
data: {
shopMap: {...}, // 存放购物车里商品的店铺信息的map
goods: {...}, // 购物车里的商品信息
...
}
...
}
Да, магазин товаров и товар в корзине размещены в двух объектах, но представление требует, чтобы они отображались вместе. В настоящее время, если вы напрямую сохраняете возвращенные данные вstore
, то внутри компонентаrender
Когда придет время собрать воедино, сопоставить две информации, а затем отобразить ее, окажется, что логика внутри компонента очень хаотична и недостаточно чиста.
Поэтому я лично рекомендую, чтобы после того, как интерфейс вернул данные, они были непосредственно обработаны в данные, соответствующие отображению страницы, а затемdispatch
Обработанные данные эквивалентны слою перехвата, а именно:
const data = result.data // result为接口返回的数据
const cartData = handleCartData(data) // handleCartData为处理数据的函数
dispatch({type: 'RECEIVE_CART', payload: cartData}) // dispatch处理过后的函数
...
// handleCartData处理后的数据
{
commoditys: [{
shop: {...}, // 商品店铺的信息
goods: {...}, // 对应商品信息
}, ...]
}
Видно, что процесс обработки данных перехватывается и обрабатывается перед рендерингом, а соответствующий товарный магазин и товар помещаются в один объект.
Это имеет несколько преимуществ:
- Один из них — рендеринг компонентов.чище, вам не нужно заботиться о том, как изменить данные, чтобы они соответствовали требованиям представления внутри компонента,Просто позаботьтесь о логике самого компонента, такие как события кликов, взаимодействия с пользователем и т. д.
- Во-вторых, поток данных.более контролируемый,Фоновые данные——>Обработка перехвата——>ожидаемая структура данных——>компоненты, если данные, возвращаемые в фоновом режиме, изменяются, все, что нам нужно сделать, это изменить
handleCartData
Логика в функции не требует изменения логики внутри компонента.
На самом деле, не только при возврате фоновых данных, но и при необходимости изменения других структур данных может выполняться слой перехвата данных, а время перехвата также может быть скорректировано в соответствии с бизнес-логикой.Соответствуют ли данные представлению, ориентируйтесь только на логику внутреннего взаимодействия, что тоже подходитReact
его первоначальное намерение,представление на основе данных.
Реализация вычисляемых свойств с помощью Connect
Вычисленные свойства? Разве это не доступно только в библиотеке адаптивного представления?На самом деле это не реальное вычисляемое свойство, а только достигается симулированный эффект посредством некоторой обработки. Потому что много раз, когда мы используем редукцию, мы просто копируем ее в соответствии с шаблонным кодом и меняем соответствующие компоненты компонентов.store
,actions
. На самом деле, мы можем заставить его делать больше вещей, например:
export default connect(({
cart,
}) => ({
couponData: cart.couponData,
commoditys: cart.commoditys,
editSkuData: cart.editSkuData
}), (dispatch) => ({
// ...actions绑定
}))(Cart)
// 组件里
render () {
const isShowCoupon = this.props.couponData.length !== 0
return isShowCoupon && <Coupon />
}
Вышеупомянутое очень распространеноconnect
пиши тогдаrender
функционировать в соответствии сcouponData
Будут ли данные отображаться. В это время мы можемthis.props.couponData.length !== 0
Это суждение потеряноconnect
, чтобы достичьcomputed
Эффект следующий:
export default connect(({
cart,
}) => {
const { couponData, commoditys, editSkuData } = cart
const isShowCoupon = couponData.length !== 0
return {
isShowCoupon,
couponData,
commoditys,
editSkuData
}}, (dispatch) => ({
// ...actions绑定
}))(Cart)
// 组件里
render () {
return this.props.isShowCoupon && <Coupon />
}
можно увидеть вconnect
определено вisShowCoupon
переменная, реализующаяcouponData
выполнятьcomputed
Эффект.
По сути, это тоже процесс перехвата данных. Кромеcomputed
, и другие функции также могут быть реализованы, которые могут свободно выполняться чиновниками.
оптимизация производительности
Что касается обработки состояния данных, мы упомянули два момента, в основном об использовании избыточности. Далее поговорим об оптимизации производительности.
Использование setState
На самом деле, при разработке небольших программ наиболее вероятные проблемы с производительностью, которые могут возникнуть, большинство из них появляются вsetData
(Конкретно в Таро стоит призватьsetState
функция). Это вызвано механизмом разработки апплета, каждый раз, когда он вызываетсяsetData
, апплет будет хранить эту часть данных на логическом уровне (среда выполненияJSCore
) для операций, подобных сериализации, преобразования данных в строку и передачи их на уровень представления (среда выполненияWebView
), уровень представления получает данные посредством десериализации, а затем отображает страницу. Этот процесс имеет определенные накладные расходы на производительность.
Так оsetState
использование, есть следующиев общем:
- Избегайте одновременного обновления огромных объемов данных. Это скорее проблема проектирования компонентов, максимально возможное разделение компонентов при балансировании эффективности разработки.
- избегать частых звонков
setState
. На самом деле setState в Taro является асинхронным, и это поможет вам выполнить этот уровень оптимизации в процессе компиляции.Например, если setState вызывается дважды в функции, Taro объединит их в следующем цикле обработки событий и устранит дубликаты. данные. - Избегайте страницы фонового состояния
setState
. Это более вероятно, потому что setState используется в асинхронных операциях, таких как таймеры, заставляя страницу фонового состояния выполнять операцию setState. Для решения проблемы можно выполнить операцию таймера уничтожения при уничтожении или скрытии страницы.
Оптимизация рендеринга списка
На странице со списком продуктов, которую мы разработали, необходимо иметь бесконечную функцию раскрывающегося списка.
Следовательно, будет проблема, когда будет загружено все больше и больше данных о продукте, будет сообщено об ошибке.invokeWebviewMethod 数据传输长度为 1227297 已经超过最大长度 1048576
. Причина в том, что мы сказали выше, апплет будет передавать эту часть данных между уровнем логики и уровнем представления, когда используется setData.Когда объем данных слишком велик, он превысит лимит.
Чтобы решить эту проблему, мы используем метод большой пейджинговой идеи. Это запись текущего пейджинга в раскрывающемся списке.Когда он достигает 10 страниц, 10 страниц используются в качестве точки разделения, а текущая страница делится наthis.state
внутреннийlist
Возьмите данные за точкой разделения и оцените прокрутку вперед, чтобы setState предыдущие данные Блок-схема выглядит следующим образом:
Как видите, мы сначала помещаем все необработанные данные продукта вthis.allList
, а затем определите текущий номер страницы в событии прокрутки страницы в соответствии с высотой прокрутки страницы. Если номер страницы меньше 10, возьмите первые десять элементов this.allList.slice, если он больше или равен 10, возьмите последние десять элементов и, наконец, вызовитеthis.setState
Сделайте рендеринг списка. Основная идея здесь заключается в том, чтоОтрисовываются только видимые данные, чтобы избежать ошибок, вызванных чрезмерным объемом данных.
В то же время, чтобы рендерить заранее, мы установим порог 500, чтобы сделать весь процесс переключения рендеринга более плавным.
Совместимость с несколькими терминалами
Хотя компиляция Taro может быть адаптирована для нескольких целей, в некоторых случаях некоторые API имеют огромные различия в производительности на разных концах, Taro не может помочь нам адаптироваться в настоящее время, нам нужно адаптироваться вручную.
process.env.TARO_ENV
использоватьprocess.env.TARO_ENV
Это может помочь нам оценить текущую среду компиляции, чтобы выполнить некоторую специальную обработку.В настоящее время его значения равныweapp
,swan
,alipay
,h5
,rn
пять. Вы можете использовать эту переменную для написания кода, соответствующего некоторым различным средам.При компиляции код, не принадлежащий текущему типу компиляции, будет удален, и будет сохранен только код текущего типа компиляции, чтобы достичь Цель совместимости. Например, если вы хотите сослаться на разные ресурсы в апплете WeChat и на стороне H5:
if (process.env.TARO_ENV === 'weapp') {
require('path/to/weapp/name')
} else if (process.env.TARO_ENV === 'h5') {
require('path/to/h5/name')
}
После того, как мы узнаем об использовании этой переменной, мы можем выполнить некоторую совместимость с несколькими терминалами.Следующие два примера подробно описаны.
Совместимость с событиями прокрутки
В апплете мониторинг прокрутки страницы должен быть на страницеonPageScroll
В событии и в H5 его нужно вызывать вручнуюwindow.addEventListener
Чтобы выполнить привязку событий, чтобы мы могли обрабатывать конкретную совместимость следующим образом:
class Demo extends Component {
constructor() {
super(...arguments)
this.state = {
}
this.pageScrollFn = throttle(this.scrollFn, 200, this)
}
scrollFn = (scrollTop) => {
// do something
}
// 在H5或者其它端中,这个函数会被忽略
onPageScroll (e) {
this.pageScrollFn(e.scrollTop)
}
componentDidMount () {
// 只有编译为h5时下面代码才会被编译
if (process.env.TARO_ENV === 'h5') {
window.addEventListener('scroll', this.pageScrollFn)
}
}
}
Как видите, мы сначала определяем функции, которые нужно выполнять при прокрутке страницы, а заодно делаем слой обработки троттлинга снаружи (если вы не понимаете троттлинг функций, то можете посмотретьздесь). Затем вonPageScroll
функция, мы выполняем функцию. В то же время вcomponentDidMount
, сделайте экологическую оценку, если даh5
среда привязывает его кwindow
в событии прокрутки.
Благодаря такой обработке в апплете она будет выполняться при прокрутке страницыonPageScroll
функция (эта функция игнорируется на других сторонах); на стороне h5 событие прокрутки напрямую связано сwindow
начальство. Поэтому мы дошли до небольшой программы, и привязка события прокрутки на стороне h5 совместима (обработка на другой стороне аналогична).
холст совместимый
Если вы хотите использовать его в апплете и H5 одновременноcanvas
, что также требует некоторой обработки совместимости.canvas
API-интерфейсы в Mini Programs и H5 в основном одинаковы, но есть несколько отличий:
- Контекст канвы получается по-разному, в h5 он получается напрямую из dom, в апплете его нужно создать вручную, вызвав Taro.createCanvasContext
- При рисовании апплет также должен вручную вызывать CanvasContext.draw для рисования.
Поэтому при обработке совместимости мы должны сосредоточиться на этих двух моментах совместимости.
componentDidMount () {
// 只有编译为h5下面代码才会被编译
if (process.env.TARO_ENV === 'h5') {
this.context = document.getElementById('canvas-id').getContext('2d')
// 只有编译为小程序下面代码才会被编译
} else if (process.env.TARO_ENV === 'weapp') {
this.context = Taro.createCanvasContext('canvas-id', this.$scope)
}
}
// 绘制的函数
draw () {
// 进行一些绘制操作
// .....
// 兼容小程序端的绘制
typeof this.context.draw === 'function' && this.context.draw(true)
}
render () {
// 同时标记上id和canvas-id
return <Canvas id='canvas-id' canvas-id='canvas-id'/>
}
Видно, что сначала в жизненном цикле componentDidMount контекст CanvasContext получается для разных сторонних методов, а на стороне апплета напрямую черезTaro.createCanvasContext
Создайте и нужно передать второй параметрthis.$scope
; со стороны H5 он проходит черезdocument.getElementById(id).getContext('2d')
чтобы получить контекст CanvasContext.
После получения контекста процесс отрисовки одинаков, потому что API на обоих концах в основном одинаковые, и нужно только судить, есть ли у контекста функция отрисовки в конце отрисовки, и если да, то выполнить ее один раз, чтобы быть совместимым с апплетом и нарисовать его.
Мы написали кулон заграждения с Canvas внутри, и именно этот метод обеспечивает совместимость между обоими концами.
Подводя итог вышеприведенным двум конкретным примерам, он основан на встроенной системе Таро.process.env.TARO_ENV
Переменные среды используются для оценки текущей среды, а затем некоторые терминалы индивидуально адаптируются. Поэтому методы совместимости конкретных уровней кода будут варьироваться в зависимости от ваших потребностей.Надеюсь приведенные выше примеры могут вас вдохновить.
Суммировать
В этой статье впервые рассказывается о ТароПочему стоит использовать синтаксис React, а затем изКод организации проекта Таро,Управление статусом данных,оптимизация производительноститак же какСовместимость с несколькими терминаламиЭти аспекты иллюстрируют глубокий опыт практики развития Таро. В целом это какое-то углубленное практическое содержание, если у вас есть какие-либо мнения или возражения, вы можете присоединиться к группе обмена разработками и вместе поучаствовать в обсуждении.