я и эта статья
Я фронтенд-энтузиаст, сейчас джуниор. На втором курсе второго курса я начал разрабатывать небольшие программы.На данный момент единственным проектом, над которым я все еще работаю, является uCourse, небольшая программа оценки курсов для студентов в кампусе.
Использовали родной язык апплета WeChat для разработки апплета, а также использовали ряд сторонних фреймворков, которые следуют ему, напримерWePY(1.х),mpvue(1.x) иTaro(0.x пока).
Причина появления такого количества сторонних фреймворков в том, что, на мой взгляд, "внесли свою лепту" иррациональность и дефекты родного языка апплета WeChat. В то же время появившаяся позже партия "хх апплета" усилили важность многотерминальных требований к компиляции. И мне посчастливилось испытать процесс разработки этой партии фреймворков с первых дней до настоящего времени, и у меня также были некоторые собственные сравнительные ощущения, и в конце концов я выбрал Таро.
В этой статье я хотел бы кратко обобщить некоторые из моего опыта и подводных камней при использовании Taro для разработки небольших программ, а также мое ментальное путешествие во всех аспектах, когда запутался с апплетом WeChat... (в основном апплет WeChat, я еще не Разработать многоцелевой.)
Помимо самого Таро, он также принесет несколько небольших практик разработки программ. В любом случае, это беспорядок, я надеюсь, что это может помочь вам.
Разработка собственных апплетов против сторонних фреймворков
Болевые точки разработки нативных апплетов
Каковы болевые точки разработки нативных апплетов? Таро это«Почему мы используем Таро для написания небольших программ — рождение Таро», дело вполне на месте.
заключить:
- Одностраничная файловая структура громоздка (до четырех)
- Синтаксис похож на React, Vue и Wind (четыре разных).
- Соглашения об именах компонентов/методов не являются единообразными (сегментация символов подчеркивания/конкатенация слов/верблюжий регистр смешаны)
- Неполный опыт фронтенд-разработки (отсутствие webpack, синтаксис ES 6+, препроцессоры CSS и т. д.)
Конечно, официальная команда WeChat Mini Program также постоянно совершенствуется и развивается. Тем не менее, скорость итерации и энтузиазм сообщества разработчиков действительно нелестны...
Список сторонних фреймворков
В настоящее время (март 2019 г.) -
- WePY(класс Vue.js)
- mpvue(Vue.js + H5/Baidu/Byte/Alipay)
- Min(класс Vue.js)
- Taro(React.js + H5/Baidu/Byte/Alipay/RN)
- nanachi(React.js + H5/Baidu/Byte/Alipay)
- uni-app(Vue.js + H5/Baidu/Byte/Alipay/родной)
Что касается того, что лучше, я не могу сейчас всесторонне сравнивать фреймворки, поскольку фреймворки итерируются. Предлагается, чтобы разработчики могли посмотреть на активное сообщество, посмотреть на спрос на многотерминальную компиляцию и посмотреть, не соответствует ли стек технологий навыкам команды.
В июле и августе прошлого года последние два фреймворка еще не были запущены, я сравнил первые четыре: потому что у WePY было слишком много питов, сообщество Min не было активным, а после того, как mpvue был открыт, движения почти не было. лично предпочитаю React. Активность сообщества Taro и скорость итерации версий радуют, поэтому неудивительно, что выбор Taro. Но теперь первые два фреймворка начали план разработки 2.x, и появляются два других фреймворка... Так что вы можете сравнить их еще раз. _(:з」∠)_
Таро Начало работы
Итак, без лишних слов, вернемся к Таро...
Можно сказать, что опыт разработки Таро ничем не отличается от React. Если у вас есть опыт в React-разработке, вы без труда сможете начать работу, если нет — смотрите прямо на Taro’sофициальная документацияНачать работу не проблема.
От установки до создания нового проекта с использованием --
$ npm install -g @tarojs/cli
$ taro init myApp
$ cd myApp
$ npm install
# 开发
$ npm run dev:weapp
# 编译
$ npm run build:weapp
в инструкциях по разработке и компиляции здесь
weapp
заменитьh5
/swan
/alipay
/tt
/rn
После этого вы можете скомпилировать и запустить на соответствующем другом конце. Логика кода нескольких терминалов может быть разной, подробнее см.Кроссплатформенная разработка.
Структура проекта
Существует официальная статья о лучших практиках проекта на основе Redux:«Практика Таро Глубокого Развития».
Официально рекомендуемая структура проекта -
├── config 配置目录
| ├── dev.js 开发时配置
| ├── index.js 默认配置
| └── prod.js 打包时配置
├── src 源码目录
| ├── components 公共组件目录
| ├── pages 页面文件目录
| | ├── index index 页面目录
| | | ├── banner 页面 index 私有组件
| | | ├── index.js index 页面逻辑
| | | └── index.css index 页面样式
| ├── utils 公共方法库
| ├── app.css 项目总通用样式
| └── app.js 项目入口文件
└── package.json
Я не использовал Redux/MobX в проекте, а структура проекта после "расти-расти" относительно проста и понятна -
├── dist 编译结果目录
├── config 配置目录
| ├── dev.js 开发时配置
| ├── index.js 默认配置
| └── prod.js 打包时配置
├── src 源码目录
| ├── assets 公共资源目录(内含图标等资源)
| ├── components 公共组件目录
| | └── Btn 公共组件 Btn 目录
| | ├── Btn.js 公共组件 Btn 逻辑
| | └── Btn.scss 公共组件 Btn 样式
| ├── pages 页面文件目录
| | └── index index 页面目录
| | ├── components index 页面的独有组件目录
| | | └── Banner index 页面的 Banner 组件目录
| | | ├── Banner.js index 页面的 Banner 组件逻辑
| | | └── Banner.scss index 页面的 Banner 组件样式
| | ├── index.js index 页面逻辑
| | └── index.scss index 页面样式
| ├── subpackages 分包目录(项目过大时建议分包)
| | └── profile 一个叫 profile 的分包目录
| | └── pages 该分包的页面文件目录
| | └── index 该分包的页面 index 目录(其下结构与主包的页面文件一致)
| ├── utils 项目辅助类工具目录
| | └── api.js 比如辅助类 api 等
| ├── app.css 项目总通用样式
| └── app.js 项目入口文件
└── package.json
Что... это еще называется "просто и понятно"? (゚д゚≡゚д゚)
Это мой любимый способ организации. Мой проект не так уж и мал, всего около 30 страниц, использование описанного выше метода для его обслуживания кажется вполне удобным. Конечно, вы также можете организовать файлы в соответствии с вашими предпочтениями~
файл конфигурации сборки
Конфигурация компиляции хранится в корневом каталоге проекта.config
каталог, содержащий три файла
-
index.js
это общая конфигурация -
dev.js
это конфигурация при предварительном просмотре проекта -
prod.js
это конфигурация, когда проект упакован
Давайте поговорим о некоторых вариантах использования и решениях некоторых ям -
Псевдоним пути
постоянно в проектеimport
Следствием относительных путей является то, что структура каталогов не может быть легко и интуитивно понятна; если вы хотите мигрировать и изменить каталог, а в IDE нет очень точной функции рефакторинга, вам нужно вручную изменить каждый каталог.import
путь, очень неудобный.
Итак, мы хотим поставить:
import A from '../../componnets/A'
стать
import A from '@/componnets/A'
эта цитата.
Способ следующий:
/* config/index.js */
const path = require('path')
alias: {
'@/components': path.resolve(__dirname, '..', 'src/components'),
'@/utils': path.resolve(__dirname, '..', 'src/utils'),
},
Оценка окружения в коде
/* config/dev.js */
env: {
NODE_ENV: '"development"', // JSON.stringify('development')
},
/* config/prod.js */
env: {
NODE_ENV: '"production"', // JSON.stringify('development')
},
можно передать в кодеprocess.env.NODE_ENV === 'development'
судить об окружающей среде.
API-интерфейсы, разделяющие среду разработки и живую среду
/* config/dev.js */
defineConstants: {
BASE_URL: '"https://dev.com/api"',
},
/* config/prod.js */
defineConstants: {
BASE_URL: '"https://prod.com/api"',
},
Таким образом, на него можно ссылаться непосредственно в коде.BASE_URL
чтобы получить другой шлюз API в зависимости от среды.
Решение таких проблем, как потеря стиля после упаковки
Если у вас не возникает проблем со стилями в среде разработки во время разработки, но некоторые стили теряются после компиляции и упаковки, это может быть связано с функцией реструктуризации csso. допустимыйplugins.csso
отключить через:
/* config/prod.js */
plugins: {
csso: {
enable: true,
config: {
restructure: false,
},
},
},
Решить проблему ошибки при компиляции сжатых файлов js
Если вы столкнулись с ошибкой при компиляции сжатого файла js компилятором, вы можете исключить его из компиляции:
/* config/index.js */
weapp: {
compile: {
exclude: [
'src/utils/qqmap-wx-jssdk.js',
'src/components/third-party/wemark/remarkable.js',
],
},
},
Решить проблему, из-за которой файл ресурсов не может быть найден после компиляции.
Если вы столкнулись с компиляцией, файлы ресурсов (например, изображения) не компилируются вdist
Если его нельзя найти в каталоге, его можно скопировать напрямую:
/* config/index.js */
copy: {
patterns: [
{
from: 'src/assets/',
to: 'dist/assets/',
},
],
},
Используйте сторонние компоненты и плагины, встроенные в мини-программу WeChat.
Официальная документация:Дочь Ви — .GitHub.IO/taro/docs/no….
Следует отметить, что если вы сделаете это, проект не может быть скомпилирован на нескольких концах.
Метод использования можно увидеть в официальном описании документа, который очень прост. Но я на самом деле наступил на яму в процессе его использования. Например, я пытаюсь интегрироватьwemarkДля рендеринга уценки. Были обнаружены две проблемы:
- Таро пропустит компиляцию только тогда, когда
wxss
цитируется вwxss
документ. решение необходимоcopy
Конфигурация копирует все файлы во время компиляции. - При компиляции сжатого файла js он пройдет другую компиляцию и вызовет ошибку и проигнорирует
copy
конфигурация. решение необходимоexclude
Настройте, чтобы исключить сжатые файлы js. (Как указано выше.)
Итак, на примере wemark проект интегрирует нативные компоненты и требует дополнительной настройки:
/* config/index.js */
copy: {
patterns: [
{
from: 'src/components/wemark',
to: 'dist/components/wemark',
},
],
},
weapp: {
compile: {
exclude: [
'src/components/wemark/remarkable.js',
],
},
},
Тогда вы можете процитировать -
import Taro, { Component } from '@tarojs/taro'
import { View } from '@tarojs/components'
export default class Comp extends Component {
config = {
usingComponents: {
wemark: '../components/wemark/wemark'
}
}
state = {
md: '# heading'
}
render() {
return (
<View>
<wemark md={this.state.md} link highlight type="wemark" />
</View>
)
}
}
Короче говоря, если вы столкнетесь с подобными проблемами при интеграции нативных компонентов, вы можете попробовать напрямуюcopy
Весь каталог компонентов и некоторые js-файлы исключаются для предотвращения перекомпиляции.
Использование компонента Icon Font
Мы надеемся, что в проекте будет свой собственный компонент иконочных шрифтов, используя следующий метод:
<UIcon icon="home" />
Зачем
UIcon
, вместоIcon
? Потому что название не может соответствовать официальным встроенным компонентам.Icon
Конфликт...(|||゚д゚) Вы также можете позвонить емуOhMyIcon
какой-то тип.
Давайте сначала поговорим о практике, а потом поговорим о ямах...
Практика такова, что если у вас нет профессионального дизайнера или внутренней библиотеки иконок компании, вы можете использоватьIconfontПреимущество библиотеки диаграмм в том, что есть много и отличных иконок, а CDN готов к использованию из коробки. Вы можете создать новый проект, выбрать значок, который подходит для вашего проекта, и получить его напрямую.@font-face
Цитируемый код:
Ссылочный эффект Unicode и класса Font почти одинаков.Преимущество последнего заключается в семантике имени класса.Поскольку нам нужно сделать еще один уровень упаковки, чтобы сделать имя класса настраиваемым, рекомендуется выбрать Unicode.
Преимущество Symbol в том, что он поддерживает многоцветные иконки, так почему бы его не использовать... Наступая на яму, наступая на яму, апплет WeChat не совместим с иконкой svg QwQ. (Я перерыл много постов в официальном сообществе, официальный сказал только "Хорошо, давайте посмотрим", "Пожалуйста, опубликуйте фрагмент кода" и ничего не произошло... Подобных ситуаций много, и баги упоминались для нескольких лет.Никогда не ремонтируйте,сохраните как семейную реликвию...(/‵Д′)/~ ╧╧ )
Затем мы добавляем указанный выше абзац в файл стилей компонента.@font-face
После кода напишите что-то вроде следующего:
/* UIcon.scss */
.u-icon {
display: inline-block;
&:before {
font-family: 'iconfont' !important;
font-style: normal;
font-weight: normal;
speak: none;
display: inline-block;
text-decoration: inherit;
width: 1em;
text-align: center;
}
}
Затем для каждого значка дайте его определение юникода:
/* UIcon.scss */
.u-icon-add::before {
content: '\e6e0';
}
.u-icon-addition::before {
content: '\e6e1';
}
/* ... */
UIcon.js
Упаковано так:
/* UIcon.js */
import Taro, { Component } from '@tarojs/taro'
import { View } from '@tarojs/components'
import './UIcon.scss'
export default class UIcon extends Component {
static externalClasses = ['uclass']
static defaultProps = {
icon: '',
}
render() {
return <View className={`uclass u-icon u-icon-${this.props.icon}`} />
}
}
Обратите внимание, что я добавилexternalClasses
конфигурация иuclass
изclassName
. Причина в том, что я хочу определить внутренний стиль вне компонента, поэтому после этого определения я могу назвать его так:
<UIcon icon="home" uclass="external-class" />
Подробности смотрите в документацииВнешние и глобальные стили для компонентов. (Этот документ представляет собой QwQ, который я помог составить после того, как наступил на эту яму...)
обернуть отчетformId
s компонент
Такой компонент может потребоваться, если вам нужно активно отправлять карточку сообщения шаблона мини-программы.
Текущая политика апплета заключается в том, что вы можете запускать только одинbutton
Однократный 7-дневный срок действия сообщается вам после события кликаformId
, который вы используете для однократной отправки шаблонного сообщения. Поэтому появилась группа остроумных разработчиков небольших программ.button
Обернувшись вокруг всей страницы, пользователь сообщает оformId
, После сохранения вам в любом случае не придется беспокоиться об этом в течение семи дней, и он будет выпущен медленно. А чиновник, похоже, закрывает глаза... (●` 艸 ´)
Реализовать такую обертку в Taro тоже просто:
/* FormIdReporter.js */
import Taro, { Component } from '@tarojs/taro'
import { Button, Form } from '@tarojs/components'
import './FormIdReporter.scss'
export default class FormIdReporter extends Component {
handleSubmit = e => {
console.log(e.detail.formId) // 这里处理 formId
}
render() {
return (
<Form reportSubmit onSubmit={this.handleSubmit}>
<Button plain formType="submit" hoverClass="none">
{this.props.children}
</Button>
</Form>
)
}
}
При вызове просто оберните всю страницу:
<FormIdReporter>
{/* 一些其他组件 */}
</FormIdReporter>
Следует отметить, что здесьButton
Вам нужно использовать следующий код стиля, чтобы очистить стиль по умолчанию для достижения «скрытого» эффекта:
/* FormIdReporter.scss */
button {
width: 100%;
border-radius: 0;
padding: 0;
margin: 0;
&:after {
border: 0;
}
}
Быстрая проверка доступа/входа с помощью Decorator
Так как эта часть контента также изучается из других мест, и существуют существующие туториалы, я не буду подливать масла в огонь. Ссылаться на:
- Использование Decorator для быстрой реализации обмена апплетами в Taro
- Схема авторизованного входа в апплет WeChat и реализация декоратора Decorator под Taro
Далее речь пойдет о некоторых практических случаях самого апплета. Конечно, это также основано на Таро.
i18n интернационализация
Так как проекту нужно реализовать интернационализацию текста апплета, я нашел много кейсов, и наконец сослался на идею этого относительно лаконичного решения:weapp-i18n. Он использовался в двух проектах. В Таро его можно обернуть в следующий класс:
/* utils/i18n.js */
export default class T {
constructor(locales, locale) {
this.locales = locales
if (locale) {
this.locale = locale
}
}
setLocale(code) {
this.locale = code
}
_(line) {
const { locales, locale } = this
if (locale && locales[locale] && locales[locale][line]) {
line = locales[locale][line]
}
return line
}
}
создать новыйlocales.js
, напишите свой локализованный язык,key
Имя должно соответствовать названию системного языка WeChat:
/* utils/locales.js */
locales.zh_CN = {
Discover: '发现',
Schools: '学校',
Me: '我',
'Courses of My Faculty': '我的院系课程',
'Popular Evaluations Monthly': '本月热门评测',
'Popular Evaluations': '热门评测',
'Recent Evaluations': '最新评测',
'Top Courses': '高分课程',
/* ... */
}
locales.zh_TW = {
...locales.zh_CN,
Discover: '發現',
Schools: '學校',
Me: '我',
'Courses of My Faculty': '我的院系課程',
'Popular Evaluations Monthly': '本月熱門評測',
'Popular Evaluations': '熱門評測',
'Recent Evaluations': '最新評測',
'Top Courses': '高分課程',
/* ... */
}
используется вApp.js
Сначала инициализируйте:
/* App.js */
componentWillMount() {
this.initLocale()
}
initLocale = () => {
let locale = Taro.getStorageSync('locale')
if (!locale) { // 初始化语言
const systemInfo = await Taro.getSystemInfo()
locale = systemInfo.language // 默认使用系统语言
Taro.setStorage({ key: 'locale', data: locale })
}
Taro.T = new T(locales, locale) // 初始化本地化工具实例并注入 Taro.T
// 手动更改 TabBar 语言(目前只能这么做)
Taro.setTabBarItem({
index: 0,
text: Taro.T._('Discover'),
})
Taro.setTabBarItem({
index: 1,
text: Taro.T._('Me'),
})
}
Используемые компоненты:
<Button>{Taro.T._('Hello')}</Button>
Если в апплете предусмотрена функция смены языка, то после изменения пользователем сохраните конфигурацию, а затем непосредственноTaro.reLaunch
Перейдите на домашнюю страницу и измените язык панели вкладок, как описано выше.
Это действительно неприятно, но, на мой взгляд, это самый удобный и реальный способ добиться интернационализации в небольших программах...(*´ω`)People(´ω`*)
Обертывание методов API
Хотя Таро предоставляетTaro.request
Этот метод, но я все же выбираюFly.jsЭта библиотека обертывает собственный метод запроса:
/* utils/request.js */
import Taro from '@tarojs/taro'
import Fly from 'flyio/dist/npm/wx'
import config from '../config'
import helper from './helper'
const request = new Fly()
request.config.baseURL = BASE_URL
const newRquest = new Fly() // 这是用来 lock 时用的,详见后面
// 请求拦截器,我在这里的使用场景是:除了某些路由外,如果没有权限的用户「越界」了,就报错给予提示
request.interceptors.request.use(async conf => {
const { url, method } = conf
const allowedPostUrls = [
'/login',
'/users',
'/email',
]
const isExcept = allowedPostUrls.some(v => url.includes(v))
if (method !== 'GET' && !isExcept) {
try {
await helper.checkPermission() // 一个用来检测用户权限的方法
} catch (e) {
throw e
}
}
return conf
})
// 响应拦截器,我在这里的使用场景是:如果用户的 session 过期了,就锁定请求队列,完成重新登录,然后继续请求队列
request.interceptors.response.use(
response => response,
async err => {
try {
if (err.status === 0) { // 网络问题
throw new Error(Taro.T._('Server not responding'))
}
const { status } = err.response
if (status === 401 || status === 403) { // 这两个状态码表示用户没有权限,需要重新登录领 session
request.lock() // 锁定请求队列,避免重复请求
const { errMsg, code } = await Taro.login() // 重新登录
if (code) {
const res = await newRquest.post('/login', { code }) // 使用新实例完成登录
const { data } = res.data
const { sessionId, userInfo } = data
Taro.setStorageSync('sessionId', sessionId) // 储存新 session
if (userInfo) {
Taro.setStorageSync('userInfo', userInfo) // 更新用户信息
}
request.unlock() // 解锁请求队列
err.request.headers['Session-Id'] = sessionId // 在请求头加上新 session
return await request.request(err.request) // 重新完成请求
} else {
request.unlock()
throw new Error(Taro.T._('Unable to get login status'), errMsg)
return err
}
}
} catch (e) {
Taro.showToast({ title: e.message, icon: 'none' })
throw e
}
},
)
export default request
Вы можете обернуть другой слой поверх этогоapi.js
SDK. Очень удобно использовать~σ ゚∀ ゚) ゚∀゚)σ
Использование сторонней статистики
До сих пор я использовал две сторонние статистические данные,АладдиниTalkingData. Сравнив их, выяснилось, что сообщество Aladdin более активно, а TalkingData предоставляет API для сбора данных. Но при использовании выяснилось, что TalkingData не очень совместим с Taro.После моего отзыва я получил ответ, что для апплета существует слишком много сторонних сред разработки, поэтому его поддержка не планируется (´c_ `); хотя Aladdin делал это раньше, но это было исправлено в версии, выпущенной несколько месяцев назад, и в нее была интегрирована справочная документация.
Так что, если у вас есть такая потребность, вы можете взглянуть на Аладдина~
Унифицированный файл конфигурации глобального стиля
Наконец, поговорим о практике объединения глобальных стилей. Это так же просто, как создать_scheme.scss
документ:
/* utils/_scheme.js */
$f1: 80px; // 阿拉伯数字信息,如:金额、时间等
$f2: 40px; // 页面大标题,如:结果、控状态等信息单一页面
$f3: 36px; // 大按钮字体
$f4: 34px; // 首要层级信息,基准的,可以是连续的,如:列表标题、消息气泡
$f5: 28px; // 次要描述信息,服务于首要信息并与之关联,如:列表摘要
$f6: 26px; // 辅助信息,需弱化的内容,如:链接、小按钮
$f7: 22px; // 说明文本,如:版权信息等不需要用户关注的信息
$f8: 18px; // 十分小
$color-primary: #ff9800; // 品牌颜色
$color-secondary: lighten($color-primary, 10%);
$color-tertiary: lighten($color-primary, 20%);
$color-line: #ececec; // 分割线颜色
$color-bg: #ebebeb; // 背景色
$color-text-primary: #000000; // 主内容
$color-text-long: #353535; // 大段说明的主要内容
$color-text-secondary: #888888; // 次要内容
$color-text-placeholder: #b2b2b2; // 缺省值
$color-link-normal: #576b96; // 链接用色
$color-link-press: lighten($color-link-normal, 10%);
$color-link-disable: lighten($color-link-normal, 20%);
$color-complete-normal: $color-primary; // 完成用色
$color-complete-press: lighten($color-complete-normal, 10%);
$color-complete-disable: lighten($color-complete-normal, 20%);
$color-success-normal: #09bb07; // 成功用色
$color-success-press: lighten($color-success-normal, 10%);
$color-success-disable: lighten($color-success-normal, 20%);
$color-error-normal: #e64340; // 出错用色
$color-error-press: lighten($color-error-normal, 10%);
$color-error-disable: lighten($color-error-normal, 20%);
Затем укажите ссылку на этот файл конфигурации в файле стиля и используйте соответствующие переменные вместо абсолютных значений.
Кстати, в Тароpx
На самом деле это означаетrpx
; если вы хотите настоящийpx
, можно писать с большой буквыPX
.
Это все, что сказано выше. Если вы не будете делать заметки во время разработки, возможно, вы упустите много моментов, поэтому постарайтесь наверстать упущенное позже. Писать так много — это, с одной стороны, резюме, а с другой — делиться. Спасибо, что вы здесь. Если что-то не так, пожалуйста, поправьте меня. Мне еще многому предстоит научиться!
Использование Таро для разработки небольших программ по-прежнему довольно круто. Приходите и используйте (помашите рукой~)
٩(´ ω` )۶