web123456

Taro introduces f2 chart_Summary of development projects using Taro

Why useTaro

I like it moreReact, Taro's community activity and version iteration speed are welcome, so Taro was chosen without surprise.

Taro Starts

So let's talk about it less, let's talk about Taro...

Taro's development body is personally more fond of React. Taro's community activity and version iteration speed are welcome, so he chose Taro without any surprise. You have experience in React development and can get started smoothly without any difficulties; if you don’t, you can read Taro’s official documentation to get started.

From installation to building a new project to use-

$ npm install -g @tarojs/cli

$ taro init myApp

$ cd myApp

$ npm install

#Development

$ npm run dev:weapp

#Compilation

$ npm run build:weapp

Copy code Copy code After changing weapp in the development and compilation instructions here to h5 / swan / alipay / tt / rn, it can be compiled and run on the corresponding other end. Multi-end code logic can be different. For details, please see Cross-platform development.

Project structure

There is an official best practice article for project based on Redux: "Taro Deep Development Practice".

Officially recommended project structure—

├── config configuration directory

| ├──Development configuration

| ├── Default configuration

| └──Configuration during packaging

├── src source code directory

| ├── components PublicComponentsTable of contents

| ├── pages page file directory

| | ├── index index page directory

| | | | ├── banner page index private component

| | | | ├── index page logic

| | | └── index page style

| ├── utils Public method library

| ├── Project general general style

| └── Project entrance file

└──

Copy Code Copy Code

I did not use Redux/MobX in my project, and the structure after the project "develops and grows" is also relatively simple and clear-

├── dist compile result directory

├── config configuration directory

| ├──Development configuration

| ├── Default configuration

| └──Configuration during packaging

├── src source code directory

| ├── assets Public resource directory (including icons and other resources)

| ├── components Public component directory

| | └── Btn Public Components Btn Directory

| | ├── Public Components Btn Logic

| | └── Public Component Btn Style

| ├── pages page file directory

| | └── index index page directory

| | | ├── components index page's unique component directory

| | | └──Banner component directory of Banner index page

| | | | ├── Banner component logic of index page

| | | └──Banner component style of index page

| | ├── index page logic

| | └── index page style

| ├── subpackages directory (subpackages are recommended when the project is too large)

| | └── profile A subcontract directory called profile

| | └── pages The page file directory of this subcontract

| | └── index The page index directory of this subcontract (the structure below is consistent with the page file of the main package)

| ├── utils Project auxiliary tool directory

| | └───For example, auxiliary api, etc.

| ├── Project general general style

| └── Project entrance file

└──

Copy Code Copy Code

What...Is this also called "simple and clear"? (゚д゚од゚С゚д゚)

This is my favorite way of organization. My project is no longer small, with a total of nearly 30 pages. It really feels quite worry-free and comfortable to maintain using the above method. Of course you can also organize documents according to your preferences~

Compile configuration files

The compilation configuration is stored in the config directory in the project root directory and contains three files

It is a general configuration

It is the configuration during project preview

It is the configuration when packaging the project

Here are some use cases and solutions to some pitfalls -

Path alias

The consequence of constantly importing relative paths in the project is that it cannot easily and intuitively understand the directory structure; if you want to migrate and change a directory and the IDE does not have a very accurate reconstruction function, you need to manually change the path of each import, which is very uncomfortable.

So we want to put:

import A from '../../componnets/A'

Copy Code Copy Code

become

import A from '@/componnets/A'

Copy Code Copy Code

This reference.

The method is as follows:

/* config/ */

const path = require('path')

alias: {

'@/components': (__dirname, '..', 'src/components'),

'@/utils': (__dirname, '..', 'src/utils'),

},

Copy Code Copy Code

Determine the environment in the code

/* config/ */

env: {

NODE_ENV: '"development"', // ('development')

},

Copy code Copy code /* config/ */

env: {

NODE_ENV: '"production"', // ('development')

},

Copy Code Copy Code

In the code, the environment can be judged by .NODE_ENV === 'development'.

APIs that distinguish development from online environments

/* config/ */

defineConstants: {

BASE_URL: '"/api"',

},

Copy code Copy code /* config/ */

defineConstants: {

BASE_URL: '"/api"',

},

Copy Code Copy Code

In this way, you can directly reference BASE_URL in the code to obtain different API Gateways based on the environment.

Solve problems such as loss of style after packaging

If you encounter no style problem when you develop the development environment, but some styles are lost after compilation and packaging, it may be because of the restructuring feature of csso. It can be closed in :

/* config/ */

plugins: {

csso: {

enable: true,

config: {

restructure: false,

},

},

},

Copy Code Copy Code

Solve the problem of errors in compiling and compressed js files

If you encounter compile time, compressed js filesCompilerAn error can be excluded and compiled:

/* config/ */

weapp: {

compile: {

exclude: [

'src/utils/',

'src/components/third-party/wemark/',

],

},

},

Copy Code Copy Code

Solve the problem of not finding the resource file after compilation

If you encounter that the resource file (such as picture) is not compiled into the dist directory and cannot be found after compilation, you can make it copy directly:

/* config/ */

copy: {

patterns: [

{

from: 'src/assets/',

to: 'dist/assets/',

},

],

},

Copy Code Copy Code

useWeChat appletNative third-party components and plug-ins

It should be noted that if you do this, the project can no longer be compiled in multiple directions.

It’s very simple to use. But I still got stuck in the process of using it. For example, I try to integrate wemark to render markdown. Two problems were found:

Taro misses compiling wxss files that are referenced only in wxss. The solution is to copy all files at compile time.

When compiling compressed js files, it will be compiled again and cause an error, and ignore the copy configuration. The solution is to exclude the compressed js file by excluding the exclude configuration. (As mentioned above.)

So taking wemark as an example, the project integrates native components and needs additional configuration:

/* config/ */

copy: {

patterns: [

{

from: 'src/components/wemark',

to: 'dist/components/wemark',

},

],

},

weapp: {

compile: {

exclude: [

'src/components/wemark/',

],

},

},

Copy Code Copy Code

Then you can quote-

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 (

)

}

}

Copy Code Copy Code

In short, if you encounter similar problems in integrating native components, you can try copying the entire component directory directly and excluding certain js files to prevent overcompilation.

Using Icon Font Component

We want to have our own icon font component in the project, and use it as follows:

Copy Code Why is a UIcon, not an Icon? Because naming cannot conflict with the official component Icon...(|||゚д゚) You can also call it OhMyIcon or something.

Let’s talk about practice first, and then talk about pitfalls…

Practice is that if you don’t have a professional designer or an icon library within the company, you can use Iconfont’s chart library. The advantages are that there are many icons and CDN is available out of the box. You can create a new project, select the icon that suits your project, and directly get the reference code of @font-face:

" />

The reference effect of Unicode and Font class is almost the same. The advantage of the latter is the semantics of class name. Since we need to wrap it another layer to make the class name customizable, we recommend that you choose Unicode.

The advantage of Symbol is that it supports multi-color icons, so why not use it... It's a pitfall, and WeChat applets are incompatible with svg icon QwQ. (I searched a lot of posts in the official community, and the official only said "Okay, let's take a look" and "Please post a code snippet" and then there was no movement... There are many similar situations. I mentioned bugs for a few years, but I never repaired them, so I kept them as a family heirloom... (/‵Д′)/~ ╧╧ )

Then, after adding the above @font-face code to the component's style file, we will write a paragraph similar to the following:

/* */

.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;

}

}

Copy Code Copy Code

Then for each icon, its unicode definition is given:

/* */

.u-icon-add::before {

content: '\e6e0';

}

.u-icon-addition::before {

content: '\e6e1';

}

/* ... */

Copy Code Copy Code

Package like this:

/* */

import Taro, { Component } from '@tarojs/taro'

import { View } from '@tarojs/components'

import './'

export default class UIcon extends Component {

static externalClasses = ['uclass']

static defaultProps = {

icon: '',

}

render() {

return

}

}

Copy Code Copy Code

I noticed here that I added an externalClasses configuration and a className of uclass. The reason is that I want to define the internal style outside the component. After this definition, I can call it like this:

Copy Code Copy Code

For details, please see the external style and global style of the document. (This document is QwQ that I helped me fill in after I stepped on this pit...)

Package a component that reports formId

If you have the need to actively send applet template message cards, you may need such components.

The current strategy of mini programs is that you can only report to you a one-time 7-day expired formId after the user triggers a button click event, and you use it to send a template message once. So a group of smart mini program developers emerged, wrapping the buttons on the entire page, and reporting a formId for every click of the user. After saving it, you will not have to worry about it within seven days, so send it slowly. And the official seems to have turned a blind eye... (●` ´)

Implementing such a wrapper in Taro is also very simple:

/* */

import Taro, { Component } from '@tarojs/taro'

import { Button, Form } from '@tarojs/components'

import './'

export default class FormIdReporter extends Component {

handleSubmit = e => {

console.log() // Process formId here

}

render() {

return (

{}

)

}

}

Copy Code Copy Code

When calling, wrap the entire page:

{/* Some other components */}

Copy Code Copy Code

It should be noted that the Button here needs to use the following style code to clear the default style to achieve the "hidden" effect:

/* */

button {

width: 100%;

border-radius: 0;

padding: 0;

margin: 0;

&:after {

border: 0;

}

}

Copy Code Copy Code

Use Decorator to achieve fast sharing/login verification

Since this part of the content is also something I learned from other places and there are established tutorials, I will no longer add fuel to the fire. refer to:

What we are talking about below are more about some practical cases of the mini program itself. Of course, it is also based on Taro.

i18n International

Since the project needs to realize the internationalization of mini-program texts, I found many cases and finally referred to the idea of ​​this relatively concise solution: weapp-i18n. It has been applied to two projects. In Taro, it can be wrapped into the following class:

/* utils/ */

export default class T {

constructor(locales, locale) {

= locales

if (locale) {

= locale

}

}

setLocale(code) {

= code

}

_(line) {

const { locales, locale } = this

if (locale && locales[locale] && locales[locale][line]) {

line = locales[locale][line]

}

return line

}

}

Copy Code Copy Code

Create a new one and write your localized language. The key name should be consistent with the WeChat system language name:

/* utils/ */

locales.zh_CN = {

Discover: 'Discover',

Schools: 'school',

Me: 'I',

'Courses of My Faculty': 'My Faculty Courses',

'Popular Evaluations Monthly': 'Popular Reviews This Month',

'Popular Evaluations': 'Popular Reviews',

'Recent Evaluations': 'Latest Reviews',

'Top Courses': 'High Score Courses',

/* ... */

}

locales.zh_TW = {

...locales.zh_CN,

Discover: 'Discover',

Schools: 'School',

Me: 'I',

'Courses of My Faculty': 'My department courses',

'Popular Evaluations Monthly': 'Hot reviews this month',

'Popular Evaluations': 'Popular Evaluations',

'Recent Evaluations': 'Latest Reviews',

'Top Courses': 'High Score Courses',

/* ... */

}

Copy Code Copy Code

How to use is to initialize it in:

/* */

componentWillMount() {

()

}

initLocale = () => {

let locale = ('locale')

if (!locale) { // Initialize the language

const systemInfo = await ()

locale = // The default system language is used

({ key: 'locale', data: locale })

}

= new T(locales, locale) // Initialize the localization tool instance and inject it

// Manually change the TabBar language (this is only possible at present)

({

index: 0,

text: ._('Discover'),

})

({

index: 1,

text: ._('Me'),

})

}

Copy Code Copy Code

Used in components:

{._('Hello')}

Copy Code Copy Code

If the applet provides the function of changing the language, after the user changes, save the configuration, then go directly to the homepage, and change the TabBar language as described above.

It's indeed a little frustrated, but in my opinion, it is already the most convenient and feasible way to achieve internationalization in mini programs... (*´ω`) People (´ω`*)

Packaging API Method

Although Taro provides this method, I still chose this library and wrapped my own request method:

/* utils/ */

import Taro from '@tarojs/taro'

import Fly from 'flyio/dist/npm/wx'

import config from '../config'

import helper from './helper'

const request = new Fly()

= BASE_URL

const newRquest = new Fly() // This is used when locking, see the details later

// Request an interceptor. My use scenario here is: Except for some routes, if a user without permission "crosses the boundary", he will report an error and give a prompt.

(async conf => {

const { url, method } = conf

const allowedPostUrls = [

'/login',

'/users',

'/email',

]

const isExcept = (v => (v))

if (method !== 'GET' && !isExcept) {

try {

await () // A method used to detect user permissions

} catch (e) {

throw e

}

}

return conf

})

// Response interceptor, my use scenario here is: If the user's session expires, lock the request queue, complete login again, and then continue to request queue

(

response => response,

async err => {

try {

if ( === 0) { // Network problem

throw new Error(._('Server not responding'))

}

const { status } =

if (status === 401 || status === 403) { // These two status codes indicate that the user does not have permission and needs to log in again to receive the session

() // Lock the request queue to avoid repeated requests

const { errMsg, code } = await () // Log in again

if (code) {

const res = await ('/login', { code }) // Complete login with a new instance

const { data } =

const { sessionId, userInfo } = data

('sessionId', sessionId) // Store new session

if (userInfo) {

('userInfo', userInfo) // Update user information

}

() // Unlock the request queue

['Session-Id'] = sessionId // Add a new session to the request header

return await () // Re-complete the request

} else {

()

throw new Error(._('Unable to get login status'), errMsg)

return err

}

}

} catch (e) {

({ title: , icon: 'none' })

throw e

}

},

)

export default request

Copy Code Copy Code

You can package another layer of SDK based on this. Very comfortable to use ~σ ゚∀ ゚) ゚∀ ゚) ゚∀ ゚) ゚∀ ゚) σ

Use third-party statistics

I have used two of them in third-party statistics, Aladdin and TalkingData. After comparing the two, we found that the Aladdin community is more active, and TalkingData provides an API for data acquisition. However, during use, it was found that TalkingData is not very compatible with Taro. After I feedback, the reply I got was that there were too many third-party development frameworks for the applet, so there was no supported plan (´c_`); although Aladdin had such a problem before, it was fixed in a version a few months ago and provided an integrated reference document.

So if you have this requirement, you can consider Aladdin~

Uniform configuration file for global styles

Finally, let’s talk about a practice of unifying global styles. It's very simple, for example, create a _scheme.scss file:

/* utils/_scheme.js */

$f1: 80px; // Arabic numeric information, such as: amount, time, etc.

$f2: 40px; // Large page title, such as: single page of results, status control and other information

$f3: 36px; // Large button font

$f4: 34px; // The primary level information, the benchmark, can be continuous, such as: list title, message bubble

$f5: 28px; // Secondary description information, serving and associated with primary information, such as: list summary

$f6: 26px; // Auxiliary information, content that needs to be weakened, such as: links, small buttons

$f7: 22px; // Instruction text, such as: copyright information, etc., information that does not require user attention

$f8: 18px; // Very small

$color-primary: #ff9800; // Brand color

$color-secondary: lighten($color-primary, 10%);

$color-tertiary: lighten($color-primary, 20%);

$color-line: #ececec; // Dividing line color

$color-bg: #ebebeb; // Background color

$color-text-primary: #000000; // Main content

$color-text-long: #353535; // The main content of the long paragraph

$color-text-secondary: #888888; // Secondary content

$color-text-placeholder: #b2b2b2; // Default value

$color-link-normal: #576b96; // Link color

$color-link-press: lighten($color-link-normal, 10%);

$color-link-disable: lighten($color-link-normal, 20%);

$color-complete-normal: $color-primary; // Complete color usage

$color-complete-press: lighten($color-complete-normal, 10%);

$color-complete-disable: lighten($color-complete-normal, 20%);

$color-success-normal: #09bb07; // Use color successfully

$color-success-press: lighten($color-success-normal, 10%);

$color-success-disable: lighten($color-success-normal, 20%);

$color-error-normal: #e64340; // Use color error

$color-error-press: lighten($color-error-normal, 10%);

$color-error-disable: lighten($color-error-normal, 20%);

Copy Code Copy Code

Then refer to this configuration file in the style file, use the corresponding variable, instead of using absolute values.

By the way, px in Taro actually refers to rpx; if you want real px, you can capitalize PX.

All of the above are. If you fail to take notes while developing, you may have missed a lot of points. Please try to make up for it later. Writing so much is a summary on the one hand, and a sharing on the other hand. Thank you for seeing this. If anything is wrong, please give me some advice. There are many more things I want to learn!