Практика Таро - Быстрое развитие [Знать] Мультитерминальное приложение

GitHub Апплет WeChat React.js
Практика Таро - Быстрое развитие [Знать] Мультитерминальное приложение

От товарищей по команде - Аджи, статья о практической практике Таро, надеюсь будет полезна всем.

1. Введение в Таро

Taroпредставляет собой набор следующихReactМноготерминальная унифицированная среда разработки для спецификаций грамматики.

использоватьTaro, мы можем написать только один набор кода, а затем передатьTaroИнструмент-компилятор для компиляции исходного кода в код, который можно запускать на разных сторонах (апплет WeChat, H5, сторона приложения и т. д.). В настоящее времяTaroОн поддерживает компиляцию кода, который поддерживает работу апплета WeChat и H5.Поддержка RN, быстрого приложения и апплета Alipay все еще находится в стадии разработки.

Подробности смотрите в статье"Многотерминальная унифицированная среда разработки - Taro 》и репозиторий GitHub https://github.com/NervJS/taro

2. Предисловие

Для того, чтобы изучить Таро, я нашел его на githubДемонстрация апплета Zhihu, В этой статье реализована версия Zhihu H5 для Таро и небольшая демонстрация программы путем изменения кода.Студенты, интересующиеся Таро, могут пометить или разветвить, чтобы учиться.Адрес GitHub.

3. Установка

УстановитьTaroИнструменты разработки@tarojs/cli

использоватьnpmилиyarnУстановить глобально

npm install -g @tarojs/cli
// 或
yarn global add @tarojs/cli

скачать код

git clone https://github.com/jimczj/taro_zhihu
# 安装依赖
cd taro_zhihu
npm i

4. Запустите код

Каталог файлов выглядит следующим образом:

├── dist                   编译结果目录
├── config                 配置目录
|   ├── dev.js             开发时配置
|   ├── index.js           默认配置
|   └── prod.js            打包时配置
├── src                    源码目录
|   ├── pages              页面文件目录
|   |   ├── index          index页面目录
|   |   |   ├── index.js   index页面逻辑
|   |   |   └── index.css  index页面样式
|   ├── app.css            项目总通用样式
|   └── app.js             项目入口文件
└── package.json

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

Режим предварительного просмотра компиляции апплета WeChat:

# npm script
npm run dev:weapp
# 或 仅限全局安装
taro build --type weapp --watch

Режим предварительного просмотра компиляции H5:

# npm script
npm run dev:h5
# 或 仅限全局安装
taro build --type h5 --watch

5. Внимание перед разработкой

Если вы используете режим предварительного просмотра программы WeChat Mini, вам необходимо загрузить и использоватьИнструменты разработчика WeChatДобавьте проект для предварительного просмотра.В это время вам нужно обратить внимание на настройки проекта инструментов разработчика WeChat.

  • Необходимо настроить функцию ES6 на ES5, чтобы она была отключена, и при ее включении может появиться сообщение об ошибке.
  • Нужно настроить автоматическое завершение стиля при загрузке кода выключено, а при включении может выдаваться ошибка.
  • Вам нужно установить код для сжатия и загрузки, чтобы закрыть, и вы можете сообщить об ошибке при его открытии.

项目设置

6. Подробное объяснение реализации функции

6.1 Глобальная конфигурация мини-программы

app.jsonФайл используется для глобальной настройки апплета WeChat, определения пути к файлу подкачки, производительности окна, установки времени ожидания сети, установки нескольких вкладок и т. д. из оригиналаapp.jsonпревратиться вTaroПроектapp.jsЗатрат почти нет, а конфигурация в основном такая же. Единственное, что следует отметить, это то, что папка ресурсов статического изображения должна быть помещена в каталог src, чтобы ресурсы изображения были скопированы и упакованы при компиляции и упаковке кода. Сначала я поместил папку ресурсов статического изображения на тот же уровень, что и src, а потом не мог найти ресурсы изображения, теряя много времени. Ну, нечего сказать, посмотрите на сравнение кода ниже, вы поймете, что эта миграция очень проста, расшифровывается какReactНаписание, это выглядит более приятным для глаз.

Оригинальный апплет WeChatapp.json(Сокращенный) код выглядит следующим образом:

{
  'pages':[
    'pages/index/index',
    'pages/discovery/discovery',
    'pages/more/more',
    'pages/answer/answer',
    'pages/question/question'
  ],
  'window':{
    'backgroundTextStyle':'light',
    'navigationBarBackgroundColor': '#0068C4',
    'navigationBarTitleText': '知乎',
    'navigationBarTextStyle':'white',
    'enablePullDownRefresh':true
  },
  'tabBar': {
    'color': '#626567',
    'selectedColor': '#2A8CE5',
    'backgroundColor': '#FBFBFB',
    'borderStyle': 'white',
    'list': [{
      'pagePath': 'pages/index/index',
      'text': '首页',
      'iconPath': 'images/index.png',
      'selectedIconPath': 'images/index_focus.png'
    }, {
      'pagePath': 'pages/discovery/discovery',
      'text': '发现',
      'iconPath': 'images/discovery.png',
      'selectedIconPath': 'images/discovery_focus.png'
    },  {
      'pagePath': 'pages/more/more',
      'text': '我的',
      'iconPath': 'images/burger.png',
      'selectedIconPath': 'images/burger_focus.png'
    }]
  }
}

Код, записанный в Таро, выглядит следующим образом:

import Taro, { Component } from '@tarojs/taro'
import Index from './pages/index'

import './app.scss'

class App extends Component {
  config = {
    pages: [
      'pages/index/index',
      'pages/discovery/discovery',
      'pages/more/more',
      'pages/answer/answer',
      'pages/question/question'
    ],
    window: {
      backgroundTextStyle: 'light',
      navigationBarBackgroundColor: '#0068C4',
      navigationBarTitleText: 'Taro知乎',
      navigationBarTextStyle: 'white',
      enablePullDownRefresh: true
    },
    tabBar: {
      color: '#626567',
      selectedColor: '#2A8CE5',
      backgroundColor: '#FBFBFB',
      borderStyle: 'white',
      list: [{
        pagePath: 'pages/index/index',
        text: '首页',
        iconPath: './asset/images/index.png',
        selectedIconPath: './asset/images/index_focus.png'
      },{
        pagePath: 'pages/discovery/discovery',
        text: '发现',
        iconPath: './asset/images/discovery.png',
        selectedIconPath: './asset/images/discovery_focus.png'
      }, 
      {
        pagePath: 'pages/more/more',
        text: '我的',
        iconPath: './asset/images/burger.png',
        selectedIconPath: './asset/images/burger_focus.png'
      }]
    }
  }
  render () {
    return (
      <Index />
    )
  }
}

Taro.render(<App />, document.getElementById('app'))

6.2 Главная

Эффект страницы выглядит следующим образом:

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

Действие обновления и продолжения загрузки зависит отScrollViewкомпонент и привязать к компонентуonScrolltoupperиonScrolltolowerдля привязки событий, вызванных прокруткой вверх и вниз, и в то же времяupperThresholdиlowerThresholdВозможность регулировать расстояние от границы при срабатывании.

использование API запроса данныхTaro.request, иwx.requestМетод использования в основном такой же, разницаTaro.requestестественная поддержкаpromiseИмитация использования данныхeasy-mockпредоставлять .

Нажмите, чтобы перейти к использованиюTaro.navigateTowx.navigateToЭто в основном то же самое.При написании прыжка я хотел сначала написать его в виде анонимной функции, и обнаружил, чтоTaroПока не поддерживается, но говорят, что будет поддерживаться.TaroСкорость итерации по-прежнему очень высока.

При рефакторинге домашней страницы наиболее трудоемкой проблемой должна бытьwxssпревратиться вscss,TaroПосле того, как компоненты преобразованы в апплет WeChat и веб-сайт, метки меняются, напримерImageкомпонент станетimageилиimgтеги, однако оригиналwxssИмя тега используется для обозначения css, что приводит к тому, что апплет WeChat ведет себя несовместимо с веб-стилем. Поэтому не рекомендуется использовать имя тега для имени css, рекомендуется использовать класс напрямую.

export default class Index extends Component {
  config = {
    navigationBarTitleText: '首页'
  }
  constructor() {
    super(...arguments)
    this.state = {
      loading:true,
      list:[]
    }
  }
  componentDidMount () { 
    // 获取远程数据
    this.updateList()
  }
  updateList() {
    Taro.showLoading({title: '加载中'})
    Taro.request({
      url: 'https://easy-mock.com/mock/5b21d97f6b88957fa8a502f2/example/feed'
    }).then(res => {
      Taro.hideLoading()
      if (res.data.success) {
        this.setState({
          loading:false,
          list:res.data.data
        })
      }
    })
  }
  appendNextPageList() {
    Taro.showLoading({title: '加载中'})
    Taro.request({
      url: 'https://easy-mock.com/mock/5b21d97f6b88957fa8a502f2/example/feed'
    }).then(res => {
      Taro.hideLoading()
      if (res.data.success) {
        this.setState({
          list: this.state.list.concat(res.data.data)
        })
      }
    })
  }
  render () {
    return (<ScrollView className='container'
        scrollY
        scrollWithAnimation
        scrollTop='0'
        lowerThreshold='10'
        upperThreshold='10'
        onScrolltoupper={this.updateList}
        onScrolltolower={this.appendNextPageList}
        >
        <View className='search flex-wrp'>
          <View className='search-left flex-item'>
              <View className='flex-wrp'>
                <View className='flex1'><Image src={searchPng}></Image></View>
                <View className='flex6'><Input type='text' placeholder='搜索话题, 问题或人' placeholderClass='search-placeholder'/></View>
              </View>
          </View>
          <View className='search-right flex-item'>
              <Image src={lightingPng}></Image>
          </View>
        </View>
        {
          this.state.loading 
          ? <View className='txcenter'><Text>加载中</Text></View>
          : this.state.list.map((item,index)=>{
          return <Feed key={item} />})
        }
      </ScrollView>
    )
  }
}

6.3 Компоненты Таро

На самом деле, я никогда не понимал апплет WeChat.Componentкомпонент сPageФункцию жизненного цикла страницы следует выполнять по-другому.onLoad、onReady、onUnloadи так далее, а в компоненте этоcreated、attached 、readyд., в отличие отTaroОн более унифицирован, будь то страница или компонент, написаниеReactЖизненный цикл постоянен, и разработка единого API проходит намного проще.

тем не мениеTaroКомпонент по-прежнему имеет много ограничений, например, он не поддерживает прямой рендеринг.children, то есть не поддерживаетthis.props.children;propsне может быть доставленjsx;

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

  • На письме,TaroПервая буква компонента должна быть заглавной и использоваться в верблюжьем регистре, например, вwxmlЭтикетка внутри естьview、scroll-view、image,существуетTaroбыть записано какView、ScrollView、Image.Taroпривязки событий все привязки событий начинаются сonначните с верблюжьего регистра
// 小程序代码
<scroll-view scroll-y='true' class='container' bindscrolltoupper='upper' upper-threshold='10' lower-threshold='5' bindscrolltolower='lower'>
</scroll-view>

// Taro 代码
<ScrollView className='container'
        scrollY
        scrollWithAnimation
        scrollTop='0'
        lowerThreshold='10'
        upperThreshold='10'
        onScrolltoupper={this.upper.bind(this)}
        onScrolltolower={this.lower.bind(this)}
        >
</ScrollView>
  • Апплет ссылается на локальные статические ресурсы непосредственно вsrcНапишите относительный путь,TaroСсылка на локальные статические ресурсы требует сначалаimportЗайди и воспользуйся еще раз.Чтобы путь к образу не ошибался при развёртывании h5, лучше всего поставить образ на сервер, а потом прописать путь http напрямую.
// 小程序 引用本地静态资源
<image src='../../images/search.png'></image>

// Taro 引用本地静态资源
import searchPng from '../../asset/images/search.png'
// ...此处省略无数代码
<Image src={searchPng}></Image>

// 最好把图片放在服务器上,然后写http 路径
<Image src='https://image.ibb.co/kUissy/search.png'></Image> 
  • Разница между обходом списка: апплет использует язык шаблонов, аTaroиспользоватьjsx
// 小程序
<block wx:for='{{feed}}' wx:for-index='idx' wx:for-item='item' data-idx='{{idx}}'>
    <view class='feed-item'>
        ...
    </view>
</block>

// Taro 代码
{
    this.state.list.map((item,index)=>{
       return <Feed {...item} key={index} />
    })
}

В абстрактном процессе компонента ответа я хочу написать его прямо в чистой функциональной форме

// 暂不支持这种写法
const Text = ({ answer }) => 
  <p>{answer}</p>

Я обнаружил, что он еще не поддерживается, поэтому я честно написал его в виде класса:

export default class Feed extends Component {
  navigateTo(url) {
    Taro.navigateTo({url:url})
  }
  render() {
    return (
      <View className='feed-item'>
        <View className='feed-source'>
          <View className='avatar flex1'>
              <Image src={this.props.feed_source_img}></Image>
          </View>
          <View className='flex8'>
            <Text className='feed-source-txt'>{this.props.feed_source_name}{this.props.feed_source_txt}</Text>
          </View>
          <View className='flex1'>
            <Image className='item-more' mode='aspectFit' src={more}></Image>
          </View>
        </View>
        <View className='feed-content'>
            <View className='question' onClick={this.navigateTo.bind(this,'/pages/question/question')}>
                <View className='question-link'>
                    <Text>{this.props.question}</Text>
                </View>
            </View>
            <View className='answer-body'>
                <View>
                    <Text className='answer-txt' onClick={this.navigateTo.bind(this,'/pages/answer/answer')} >{this.props.answer_ctnt}</Text>
                </View>
                <View className='answer-actions'>
                    <View className='like dot'>
                        <View>{this.props.good_num} 赞同 </View>
                    </View>
                    <View className='comments dot'>
                        <View>{this.props.comment_num} 评论 </View>
                    </View>
                    <View className='follow-it'>
                        <View>关注问题</View>
                    </View>
                </View>
            </View>
        </View>
      </View>
    )
  }
}

Во время использования пакета я хочу использовать{...item}Способ разобрать задание, я обнаружил, что оно пока не поддерживается, и мое сердце немного разбито.

Но, к счастью, напоминание об ошибках Таро очень удобно для пользователя, и я не тратил здесь много времени на отладку, поэтому честно присваиваю значения одно за другим.

this.state.list.map((item,index) => {
    return <Feed 
        feed_source_img={item.feed_source_img}
        feed_source_txt={item.feed_source_txt}
        question={item.question}
        answer_ctnt={item.answer_ctnt} 
        good_num={item.good_num} 
        comment_num={item.comment_num} 
        key={index} />
})

6.4 Функция переключения вкладок «Страницы обнаружения»

Принцип переключения вкладок:Привязать к компонентуonClickизменение событияthis.state.currentNavtabзначение, а затем реализовать через суждениеtabПереключатель, метод передачи параметров функцииthis.switchTab.bind(this,index), конкретный код выглядит следующим образом:

export default class Discovery extends Component {
    constructor() {
    super(...arguments)
    this.state = {
        currentNavtab: 0,
        navTab: ['推荐', '圆桌', '热门', '收藏'],
    }
  }
  switchTab(index,e) {
    this.setState({
      currentNavtab: index
    });
  }
  render () {
    return (
      <View>
        <View className='top-tab flex-wrp flex-tab' >
        {
          this.state.navTab.map((item,index) => {
            return (<View className={this.state.currentNavtab === index ? 'toptab flex-item active' : 'toptab flex-item' } key={index} onClick={this.switchTab.bind(this,index)}>
              {item}
            </View>)
          })
        }
        </View>
        <ScrollView scroll-y className='container discovery withtab'>
          <View className='ctnt0' hidden={this.state.currentNavtab==0 ? false : true}>
              ...
          </View>
            <View className='txcenter' hidden={this.state.currentNavtab==1 ? false : true}>
              <Text>圆桌</Text>
            </View>
            <View className='txcenter' hidden={this.state.currentNavtab==2 ? false : true}>
              <Text>热门</Text>
            </View>
            <View className='txcenter' hidden={this.state.currentNavtab==3 ? false : true}>
              <Text>收藏</Text>
            </View>
        </ScrollView>
      </View> 
    )
  }
}

6.5 Функция карусели

страница карусели используетсяSwiperКомпоненты, параметры и небольшие программы находятся во взаимно однозначном соответствии.Подробности можно посмотреть в подробной документации.В процессе рефакторинга основныеwxmlзаменитьjsxформа.

<Swiper className='activity' indicatorDots='true'
    autoplay='true' interval='5000' duration='500'>
    {this.state.imgUrls.map((item,index) => {
        return (<SwiperItem key={index}>
            <Image src={item} className='slide-image' width='355' height='375' />
        </SwiperItem>)
    })}
</Swiper>

7. Краткое описание проблем, обнаруженных при использовании

  • TaroПосле того, как компоненты преобразованы в апплет WeChat и веб-сайт, метки меняются, напримерImageкомпонент станетimageилиimgтег, поэтому не рекомендуется использовать имя тега для имени css, рекомендуется использовать класс напрямую
  • Текущая привязка события не поддерживает анонимные функции.
// 不支持
<View onClick={()=> this.navigateTo('/pages/answer/answer')} >  </View>
  • TaroКомпоненты имеют много свойств и событий на веб-стороне, которые еще не поддерживаются.
  • В зависимости от операционной среды некоторые API должны обрабатываться по-разному в зависимости от среды, напримерwx.getUserInfoНа веб-странице его нет, в настоящее время нам нужно оценить среду для выполнения кода.
if (Taro.getEnv() === Taro.ENV_TYPE.WEAPP) {
    // 小程序环境
} else if (Taro.getEnv() === Taro.ENV_TYPE.WEB ) {
    // WEB(H5)环境
}
  • TaroВ настоящее время не поддерживаетсяSVG(ведь апплет его не поддерживает) В настоящее время сторонних библиотек все еще относительно немного (ведьTaroОн только что вышел, я надеюсь, что в будущем сообщество выпустит различные библиотеки пользовательского интерфейса)
  • TaroКомпонент в настоящее время не поддерживает чистые функции и не поддерживает присваивание деструктурирования.{...item}

8. Резюме

Перенести проект наTaroСтоимость не высока, и большая часть работы заключается в преобразовании синтаксиса.TaroиспользоватьReactМетод написания апплета WeChat, общее впечатление очень хорошее, естьReactНебольшие партнеры с опытом разработки считают, что они могут быстро приступить к работе. Удивительно, что один и тот же код может поддерживать как веб-сторону, так и апплет.Хотя текущая поддержка веб-стороны еще не улучшена, направление верное, и следующий шаг — лишь вопрос времени. ожидатьTaroв следующем спектакле. Наконец, студенты, заинтересованные в проекте, могут загрузить код и запустить его.Адрес GitHub.