Taro + dva 使用小结(搭建配置过程)

最近写一个微信小程序的项目,由于是协同开发,前期的搭建工作由另一个妹子完成,现在项目阶段一完成了,为了备忘回顾,做一个阶段性小结。
在写小程序之前经过对比最后采用了京东凹凸实验室开发的类react框架Taro,用框架的好处就不多说了,比直接写原生小程序方便太多。数据管理采用的是封装了reduxdva框架,如果没有学过的同学可以去看看文档。先声明篇幅比较长,如果你需要,还请看完,相信一定有帮助,不想看的同学文末放了GitHub地址,自己去下。

附上文档链接:

taro文档:https://nervjs.github.io/taro/docs/README.html
dva文档:https://dvajs.com/guide/

1.基础步骤

// 全局安装taro (cnpm为淘宝镜像)
 cnpm install -g @tarojs/cli
// 创建项目
taro init taro-demo

如下配置(推荐为项目配上ts):

项目创建简单配置

安装与 react-redux API 几乎一致的包 @tarojs/redux
cnpm install --save redux @tarojs/redux @tarojs/redux-h5 redux-thunk redux-logger
安装dva
cnpm install --save dva-core dva-loading
  • dva-core:封装了 redux 和 redux-saga的一个插件
  • dva-loading:管理页面的loading状态

2.整理项目文件

删除
  • 删除./src/page文件夹下的index文件夹
添加
  • ./src文件夹下添加如下文件夹(根据自己实际情况和项目需求进行配置,只罗列一些必要的):
    assets :静态资源,如images、scss、iconfont...
    components :编写共用组件
    config :项目配置文件
    models :dva插件model函数引用或者共用的js
    types :公共typescript类型申明
    utils :封装的插件

3.编写插件(主要且常用的)

1.在./src/config下创建index.ts,添加项目配置信息,例如:
/** 
 * 线上环境
 * 为了方便测试,使用的是聚合数据免费接口
 * 网址:https://www.juhe.cn/
 */
export const ONLINEHOST = 'http://api.juheapi.com'

/**

  • 测试环境
    */
    export const QAHOST = ‘http://xxx.cn’

/**

  • 线上mock
    */
    export const MOCKHOST = ‘http://xxx/mock’

/**

  • 是否mock
    */
    export const ISMOCK = false

/**

  • 当前的host ONLINEHOST | QAHOST | MOCKHOST
    */
    export const MAINHOST = ONLINEHOST

/**

  • 全局的分享信息 不用每一个都去写
    */
    export const SHAREINFO = {
    ‘title’: ‘分享标题’,
    ‘path’: ‘路径’,
    ‘imageUrl’: ‘图片’
    }

2.在./src/utils下创建dva.ts,配置dva,内容如下:
import { create } from 'dva-core';
import { createLogger } from 'redux-logger';
import createLoading from 'dva-loading';

let app
let store
let dispatch
let registered

function createApp(opt) {
// redux日志
opt.onAction = [createLogger()]
app = create(opt)
app.use(createLoading({}))

if (!registered) opt.models.forEach(model => app.model(model))
registered = true
app.start()

store = app._store
app.getStore = () => store
app.use({
onError(err) {
console.log(err)
},
})

dispatch = store.dispatch

app.dispatch = dispatch
return app
}

export default {
createApp,
getDispatch() {
return app.dispatch
}
}

3.在./src/config下创建requestConfig.ts,统一配置请求接口,内容如下:
/** 
 * 请求的公共参数
 */
export const commonParame = {}

/**

  • 请求映射文件
    */
    export const requestConfig = {
    loginUrl: ‘/api/user/wechat-auth’, // 微信登录接口
    }
5.在./src/utils下创建tips.ts,整合封装微信原生弹窗,内容如下:
import Taro from '@tarojs/taro'
/**
 * 提示与加载工具类
 */
export default class Tips {
  static isLoading = false

/**

  • 信息提示
    /
    static toast(title: string, onHide?: () => void) {
    Taro.showToast({
    title: title,
    icon: ‘none’,
    mask: true,
    duration: 1500
    });
    // 隐藏结束回调
    if (onHide) {
    setTimeout(() => {
    onHide();
    }, 500);
    }
    }
    /
    *
  • 弹出加载提示
    */
    static loading(title = ‘加载中’, force = false) {
    if (this.isLoading && !force) {
    return
    }
    this.isLoading = true
    if (Taro.showLoading) {
    Taro.showLoading({
    title: title,
    mask: true
    })
    } else {
    Taro.showNavigationBarLoading()
    }
    }

/**

  • 加载完毕
    */
    static loaded() {
    let duration = 0
    if (this.isLoading) {
    this.isLoading = false
    if (Taro.hideLoading) {
    Taro.hideLoading()
    } else {
    Taro.hideNavigationBarLoading()
    }
    duration = 500
    }
    // 隐藏动画大约500ms,避免后面直接toast时的显示bug
    return new Promise(resolve => setTimeout(resolve, duration))
    }

/**

  • 弹出提示框
    */
    static success(title, duration = 1500) {
    Taro.showToast({
    title: title,
    icon: ‘success’,
    mask: true,
    duration: duration
    });
    if (duration > 0) {
    return new Promise(resolve => setTimeout(resolve, duration));
    }
    }
    }

5.在./src/utils下创建common.ts,共用函数,内容如下:
/** 时间格式的转换 */
export const formatTime = time => {
 `${pad(time.getHours())}:${pad(time.getMinutes())}:${pad(time.getSeconds())}.${pad(time.getMilliseconds(), 3)}`
}

export var globalData: any = {} // 全局公共变量

6.在./src/utils下创建logger.ts,封装log函数,内容如下:
import {
  formatTime
} from './common'

const defaults = {
level: ‘log’,
logger: console,
logErrors: true,
colors: {
title: ‘inherit’,
req: ‘#9E9E9E’,
res: ‘#4CAF50’,
error: ‘#F20404’,
}
}

function printBuffer(logEntry, options) {
const {
logger,
colors
} = options;

let {
title,
started,
req,
res
} = logEntry

// Message
const headerCSS = [‘color: gray; font-weight: lighter;’]
const styles = s => </span><span class="token string">color: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>s<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">; font-weight: bold</span><span class="token template-punctuation string">

// render
logger.group(</span><span class="token string">%c </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>title<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string"> @</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">formatTime</span><span class="token punctuation">(</span>started<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">, headerCSS)
logger.log(’%c req’, styles(colors.req), req)
logger.log(’%c res’, styles(colors.res), res)
logger.groupEnd()
}

interface LogEntry {
started?: object // 触发时间
}

function createLogger(options: LogEntry = {}) {
const loggerOptions = Object.assign({}, defaults, options)
const logEntry = options
logEntry.started = new Date()
printBuffer(logEntry, Object.assign({}, loggerOptions))
}

export {
defaults,
createLogger,
}

7.在./src/utils下创建request.ts,封装http请求,内容如下:
import Taro, { Component } from '@tarojs/taro'
import {
  ISMOCK,
  MAINHOST
} from '../config'
import {
  commonParame,
  requestConfig
} from '../config/requestConfig'
import Tips from './tips'

// import { createLogger } from ‘./logger’

declare type Methods = “GET” | “OPTIONS” | “HEAD” | “POST” | “PUT” | “DELETE” | “TRACE” | “CONNECT”;
declare type Headers = { [key: string]: string };
declare type Datas = { method: Methods;[key: string]: any; };
interface Options {
url: string;
host?: string;
method?: Methods;
data?: Datas;
header?: Headers;
}

export class Request {
//登陆的promise
static loginReadyPromise: Promise<any> = Promise.resolve()
// 正在登陆
static isLogining: boolean = false
// 导出的api对象
static apiLists: { [key: string]: () => any; } = {}
// token
static token: string = ‘’

// constructor(setting) {

// }
/**

  • @static 处理options
  • @param {Options | string} opts
  • @param {Datas} data
  • @returns {Options}
  • @memberof Request
    */
    static conbineOptions(opts, data: Datas, method: Methods): Options {
    typeof opts === ‘string’ && (opts = { url: opts })
    return {
    data: { .conmomPrams, .opts.data, .data },
    method: opts.method || data.method || method || ‘GET’,
    url: $<span class="token punctuation">{</span>opts<span class="token punctuation">.</span>host <span class="token operator">||</span> MAINHOST<span class="token punctuation">}</span>$<span class="token punctuation">{</span>opts<span class="token punctuation">.</span>url<span class="token punctuation">}</span>
    }
    }

static getToken() {
!this.token && (this.token = Taro.getStorageSync(‘token’))
return this.token
}

/**
*

  • @static request请求 基于 Taro.request
  • @param {Options} opts
    */
    static async request(opts: Options) {
    // token不存在
    // if (!this.getToken()) { await this.login() }
<span class="token comment">// token存在</span>
<span class="token comment">// let options = Object.assign(opts, { header: { 'token': this.getToken() } })</span>

<span class="token comment">//  Taro.request 请求</span>
<span class="token keyword">const</span> res <span class="token operator">=</span> await Taro<span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>opts<span class="token punctuation">)</span>

<span class="token comment">// 是否mock</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>ISMOCK<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span>data <span class="token punctuation">}</span>

<span class="token comment">// 登陆失效 </span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>data<span class="token punctuation">.</span>code <span class="token operator">===</span> <span class="token number">99999</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> await <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">login</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">request</span><span class="token punctuation">(</span>opts<span class="token punctuation">)</span> <span class="token punctuation">}</span>

<span class="token comment">// 请求成功</span>
<span class="token comment">// if (res.data &amp;&amp; res.data.code === 0 || res.data.succ === 0) { return res.data }</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>data<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> res<span class="token punctuation">.</span>data <span class="token punctuation">}</span>

<span class="token comment">// 请求错误</span>
<span class="token keyword">const</span> d <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token operator">..</span><span class="token punctuation">.</span>res<span class="token punctuation">.</span>data<span class="token punctuation">,</span> err<span class="token operator">:</span> <span class="token punctuation">(</span>res<span class="token punctuation">.</span>data <span class="token operator">&amp;&amp;</span> res<span class="token punctuation">.</span>data<span class="token punctuation">.</span>msg<span class="token punctuation">)</span> <span class="token operator">||</span> `网络错误~` <span class="token punctuation">}</span>
Tips<span class="token punctuation">.</span><span class="token function">toast</span><span class="token punctuation">(</span>d<span class="token punctuation">.</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">throw</span> new <span class="token function">Error</span><span class="token punctuation">(</span>d<span class="token punctuation">.</span>err<span class="token punctuation">)</span>

}

/**
*

  • @static 登陆
  • @returns promise
  • @memberof Request
    */
    static login() {
    if (!this.isLogining) { this.loginReadyPromise = this.onLogining() }
    return this.loginReadyPromise
    }

/**
*

  • @static 登陆的具体方法

  • @returns

  • @memberof Request
    */
    static onLogining() {
    this.isLogining = true
    return new Promise(async (resolve, reject) => {
    // 获取code
    const { code } = await Taro.login()

    // 请求登录
    const { data } = await Taro.request({
    url: $<span class="token punctuation">{</span>MAINHOST<span class="token punctuation">}</span>$<span class="token punctuation">{</span>requestConfig<span class="token punctuation">.</span>loginUrl<span class="token punctuation">}</span>,
    data: { code: code }
    })

    if (data.code !== 0 || !data.data || !data.data.token) {
    reject()
    return
    }

    Taro.setStorageSync(‘token’, data.data.token)
    this.isLogining = false
    resolve()
    })
    }

/**
*

  • @static 创建请求函数
  • @param {(Options | string)} opts
  • @returns
  • @memberof Request
    */
    static creatRequests(opts: Options | string): () => {} {
    return async (data = {}, method: Methods = “GET”) => {
    const _opts = this.conbineOptions(opts, data, method)
    const res = await this.request(_opts)
    // createLogger({ title: ‘request’, req: _opts, res: res })
    return res
    }
    }

/**
*

  • @static 抛出整个项目的api方法
  • @returns
  • @memberof Request
    */
    static getApiList(requestConfig) {
    if (!Object.keys(requestConfig).length) return {}
Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>requestConfig<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forEach</span><span class="token punctuation">(</span><span class="token punctuation">(</span>key<span class="token punctuation">)</span> <span class="token operator">=</span><span class="token operator">&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">this</span><span class="token punctuation">.</span>apiLists<span class="token punctuation">[</span>key<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">creatRequests</span><span class="token punctuation">(</span>requestConfig<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span>apiLists

}
}

// 导出
const Api = Request.getApiList(requestConfig)
Component.prototype.$api = Api
export default Api as any

Tip:这时候tslint会报这样的错:类型“Component<any, any>”上不存在属性“$api”。,因为我们没有添加声明,我们可以这样解决,在./src目录下创建app-shim.d.ts,内容如下:

/**
 *
 * @static 添加taro等自定义类型
 * @interface Component
 */
import Taro, { Component } from '@tarojs/taro'

// 在Component上定义自定义方法类型
declare module ‘@tarojs/taro’ {
interface Component {
$api: any
}
}

//声明
declare var require: any
declare var dispach: any

这时候应该不报错了。

8.在./src/config下创建taroConfig.ts,封装taro小程序的一些方法,内容如下:
/**
 * 进行taro的处理 
 * 1.方法的改写
 * 2.utils的挂载
 * 
 */
import Taro, { Component } from "@tarojs/taro";
import { SHAREINFO } from '../config/index'

/**

  • navigateTo 超过8次之后 强行进行redirectTo 否则会造成页面卡死

*/
const nav = Taro.navigateTo
Taro.navigateTo = (data) => {
if (Taro.getCurrentPages().length > 8) {
return Taro.redirectTo(data)
}
return nav(data)
}

/**

  • Component挂载分享方法
    */
    Component.prototype.onShareAppMessage = function () {
    return SHAREINFO
    }

4.编写node命令快速创建pagecomponent

先来看一张图,就明白为什么需要编写这样一个命令了

文件示意图

当你每次需要创建一个页面的时候需要不断的创建,这样太麻烦了,而且容易出错,所以写个node命令快速生成如图中index文件夹下的5个文件,一条命令的事情,下面上代码:
首先在 根目录下创建 scripts文件夹,在该文件夹下添加如下文件:

  1. 添加./scripts/template.js,内容如下:
/**
 * pages页面快速生成脚本 
 * 用法:npm run tep `文件名`
 */

const fs = require(‘fs’);

const dirName = process.argv[2];
const capPirName = dirName.substring(0, 1).toUpperCase() + dirName.substring(1);
if (!dirName) {
console.log(‘文件夹名称不能为空!’);
console.log(‘示例:npm run tep test’);
process.exit(0);
}

//页面模板
const indexTep = `
import Taro, { Component, Config } from ‘@tarojs/taro’
import { View } from ‘@tarojs/components’
// import { connect } from ‘@tarojs/redux’
// import Api from ‘…/…/utils/request’
// import Tips from ‘…/…/utils/tips’
import { ${capPirName}Props, KaTeX parse error: Expected 'EOF', got '}' at position 129: …n punctuation">}̲</span> from <s…{dirName}.interface’
import ‘./${dirName}.scss’
// import { } from ‘…/…/components’

// @connect(({ KaTeX parse error: Expected 'EOF', got '}' at position 11: {dirName} }̲) =&gt; ({</spa…{dirName},
// }))

class KaTeX parse error: Expected 'EOF', got '&' at position 211: …oken operator">&̲lt;</span>{capPirName}Props,${capPirName}State > {
config:Config = {
navigationBarTitleText: ‘标题’
}
constructor(props: ${capPirName}Props) {
super(props)
this.state = {}
}

componentDidMount() {

}

render() {
return (
<View className=’${dirName}-wrap’>

  <span class="token operator">&lt;</span><span class="token operator">/</span>View<span class="token operator">&gt;</span>
<span class="token punctuation">)</span>

}
}

export default ${capPirName}
`

// scss文件模版
const scssTep = $<span class="token punctuation">{</span>dirName<span class="token punctuation">}</span><span class="token operator">-</span>wrap <span class="token punctuation">{</span> width<span class="token punctuation">:</span> <span class="token number">100</span><span class="token operator">%</span><span class="token punctuation">;</span> min<span class="token operator">-</span>height<span class="token punctuation">:</span> <span class="token number">100</span>vh<span class="token punctuation">;</span> <span class="token punctuation">}</span>

// config 接口地址配置模板
const configTep = <span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span> test<span class="token punctuation">:</span> <span class="token string">'/wechat/perfect-info'</span><span class="token punctuation">,</span> <span class="token comment">//xxx接口</span> <span class="token punctuation">}</span>
// 接口请求模板
const serviceTep = `
import Api from ‘…/…/utils/request’

export const testApi = data => Api.test(
data
)
`

//model模板

const modelTep = `
// import Taro from ‘@tarojs/taro’;
import * as ${dirName}Api from ‘./service’;

export default {
namespace: ‘${dirName}’,
state: {
},

effects: {},

reducers: {}

}
`

const interfaceTep = `
/**

  • ${dirName}.state 参数类型
  • @export
  • @interface ${capPirName}State
    */
    export interface ${capPirName}State {}

/**

  • ${dirName}.props 参数类型
  • @export
  • @interface ${capPirName}Props
    */
    export interface ${capPirName}Props {}
    `

fs.mkdirSync(<span class="token punctuation">.</span><span class="token operator">/</span>src<span class="token operator">/</span>pages<span class="token operator">/</span>$<span class="token punctuation">{</span>dirName<span class="token punctuation">}</span>); // mkdir 1 < / s p a n > p r o c e s s < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > . < / s p a n > < s p a n c l a s s = " t o k e n f u n c t i o n " > c h d i r < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ( < / s p a n > ‘ < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > . < / s p a n > < s p a n c l a s s = " t o k e n o p e r a t o r " > / < / s p a n > s r c < s p a n c l a s s = " t o k e n o p e r a t o r " > / < / s p a n > p a g e s < s p a n c l a s s = " t o k e n o p e r a t o r " > / < / s p a n > 1</span> process<span class="token punctuation">.</span><span class="token function">chdir</span><span class="token punctuation">(</span>`<span class="token punctuation">.</span><span class="token operator">/</span>src<span class="token operator">/</span>pages<span class="token operator">/</span> 1</span>process<spanclass="tokenpunctuation">.</span><spanclass="tokenfunction">chdir</span><spanclass="tokenpunctuation">(</span><spanclass="tokenpunctuation">.</span><spanclass="tokenoperator">/</span>src<spanclass="tokenoperator">/</span>pages<spanclass="tokenoperator">/</span>{dirName}`); // cd $1

fs.writeFileSync($<span class="token punctuation">{</span>dirName<span class="token punctuation">}</span><span class="token punctuation">.</span>tsx, indexTep); //tsx
fs.writeFileSync($<span class="token punctuation">{</span>dirName<span class="token punctuation">}</span><span class="token punctuation">.</span>scss, scssTep); // scss
fs.writeFileSync(‘config.ts’, configTep); // config
fs.writeFileSync(‘service.ts’, serviceTep); // service
fs.writeFileSync(‘model.ts’, modelTep); // model
fs.writeFileSync($<span class="token punctuation">{</span>dirName<span class="token punctuation">}</span><span class="token punctuation">.</span>interface<span class="token punctuation">.</span>ts, interfaceTep); // interface
process.exit(0);

  1. 添加./scripts/component.js,内容如下:
/**
 * pages页面快速生成脚本 
 * 用法:npm run com `文件名`
 */

const fs = require(‘fs’);

const dirName = process.argv[2];
const capPirName = dirName.substring(0,1).toUpperCase() + dirName.substring(1);
if (!dirName) {
console.log(‘文件夹名称不能为空!’);
console.log(‘示例:npm run com test’);
process.exit(0);
}

//页面模板
const indexTep = `import Taro, { Component } from ‘@tarojs/taro’
import { View } from ‘@tarojs/components’
import { ${capPirName}Props, KaTeX parse error: Expected 'EOF', got '}' at position 129: …n punctuation">}̲</span> from <s…{dirName}.interface’
import ‘./${dirName}.scss’

class KaTeX parse error: Expected 'EOF', got '&' at position 211: …oken operator">&̲lt;</span>{capPirName}Props,${capPirName}State > {
constructor(props: < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > < / s p a n > c a p P i r N a m e < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > < / s p a n > P r o p s < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ) < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > < / s p a n > < s p a n c l a s s = " t o k e n k e y w o r d " > s u p e r < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ( < / s p a n > p r o p s < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ) < / s p a n > < s p a n c l a s s = " t o k e n k e y w o r d " > t h i s < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > . < / s p a n > s t a t e < s p a n c l a s s = " t o k e n o p e r a t o r " > = < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > < / s p a n > < s p a n c l a s s = " t o k e n k e y w o r d " > s t a t i c < / s p a n > o p t i o n s < s p a n c l a s s = " t o k e n o p e r a t o r " > = < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > < / s p a n > a d d G l o b a l C l a s s < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > : < / s p a n > < s p a n c l a s s = " t o k e n b o o l e a n " > t r u e < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > < / s p a n > < s p a n c l a s s = " t o k e n k e y w o r d " > s t a t i c < / s p a n > d e f a u l t P r o p s < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > : < / s p a n > <span class="token punctuation">{</span>capPirName<span class="token punctuation">}</span>Props<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">static</span> options <span class="token operator">=</span> <span class="token punctuation">{</span> addGlobalClass<span class="token punctuation">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span> <span class="token keyword">static</span> defaultProps<span class="token punctuation">:</span> <spanclass="tokenpunctuation"></span>capPirName<spanclass="tokenpunctuation"></span>Props<spanclass="tokenpunctuation">)</span><spanclass="tokenpunctuation"></span><spanclass="tokenkeyword">super</span><spanclass="tokenpunctuation">(</span>props<spanclass="tokenpunctuation">)</span><spanclass="tokenkeyword">this</span><spanclass="tokenpunctuation">.</span>state<spanclass="tokenoperator">=</span><spanclass="tokenpunctuation"></span><spanclass="tokenpunctuation"></span><spanclass="tokenpunctuation"></span><spanclass="tokenkeyword">static</span>options<spanclass="tokenoperator">=</span><spanclass="tokenpunctuation"></span>addGlobalClass<spanclass="tokenpunctuation">:</span><spanclass="tokenboolean">true</span><spanclass="tokenpunctuation"></span><spanclass="tokenkeyword">static</span>defaultProps<spanclass="tokenpunctuation">:</span>{capPirName}Props = {}

render() {
return (
<View className=‘fx-${dirName}-wrap’>

  <span class="token operator">&lt;</span><span class="token operator">/</span>View<span class="token operator">&gt;</span>
<span class="token punctuation">)</span>

}
}

export default ${capPirName}
`

// scss文件模版
const scssTep = $<span class="token punctuation">{</span>dirName<span class="token punctuation">}</span><span class="token operator">-</span>wrap <span class="token punctuation">{</span> width<span class="token punctuation">:</span> <span class="token number">100</span><span class="token operator">%</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>

const interfaceTep = `
/**

  • ${dirName}.state 参数类型
  • @export
  • @interface ${capPirName}State
    */
    export interface ${capPirName}State {}

/**

  • ${dirName}.props 参数类型
  • @export
  • @interface ${capPirName}Props
    */
    export interface ${capPirName}Props {}
    `

fs.mkdirSync(<span class="token punctuation">.</span><span class="token operator">/</span>src<span class="token operator">/</span>components<span class="token operator">/</span>$<span class="token punctuation">{</span>dirName<span class="token punctuation">}</span>); // mkdir 1 < / s p a n > p r o c e s s < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > . < / s p a n > < s p a n c l a s s = " t o k e n f u n c t i o n " > c h d i r < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ( < / s p a n > ‘ < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > . < / s p a n > < s p a n c l a s s = " t o k e n o p e r a t o r " > / < / s p a n > s r c < s p a n c l a s s = " t o k e n o p e r a t o r " > / < / s p a n > c o m p o n e n t s < s p a n c l a s s = " t o k e n o p e r a t o r " > / < / s p a n > 1</span> process<span class="token punctuation">.</span><span class="token function">chdir</span><span class="token punctuation">(</span>`<span class="token punctuation">.</span><span class="token operator">/</span>src<span class="token operator">/</span>components<span class="token operator">/</span> 1</span>process<spanclass="tokenpunctuation">.</span><spanclass="tokenfunction">chdir</span><spanclass="tokenpunctuation">(</span><spanclass="tokenpunctuation">.</span><spanclass="tokenoperator">/</span>src<spanclass="tokenoperator">/</span>components<spanclass="tokenoperator">/</span>{dirName}`); // cd $1

fs.writeFileSync($<span class="token punctuation">{</span>dirName<span class="token punctuation">}</span><span class="token punctuation">.</span>tsx, indexTep); //tsx
fs.writeFileSync($<span class="token punctuation">{</span>dirName<span class="token punctuation">}</span><span class="token punctuation">.</span>scss, scssTep); // scss
fs.writeFileSync($<span class="token punctuation">{</span>dirName<span class="token punctuation">}</span><span class="token punctuation">.</span>interface<span class="token punctuation">.</span>ts, interfaceTep); // interface

Tip:最后也是重点,记得在根目录的package.jsonscripts里加上如下内容:

"scripts": {
  ...
  "tep": "node scripts/template",
  "com": "node scripts/component"
}

5.编写业务代码

上面4个步骤基本已经配置完了,接下去进入正题,可以愉快的撸代码了。
运行我们上面写的快速生成脚本,在命令行里输入:

cnpm run tep index

ok,这时候tslint应该不报找不到index的错了,可以看到我们page文件夹下生成了一个index的文件夹,里面包含config.tsindex.interface.tsindex.scssindex.tsxmodel.tsservice.ts

1.改写./src/app.tsx

首先先下载taro的@tarojs/async-await,在命令行输入如下:

cnpm i --save @tarojs/async-await

下载完了之后,按照如下改写app.tsx

import Taro, { Component, Config } from "@tarojs/taro";
import "@tarojs/async-await";
import { Provider } from "@tarojs/redux";
import "./utils/request";
import Index from "./pages/index";
import dva from './utils/dva'
import models from './models'
import './app.scss'
import { globalData } from "./utils/common";

const dvaApp = dva.createApp({
initialState: {},
models: models,
});

const store = dvaApp.getStore();

class App extends Component {
config: Config = {
pages: [
‘pages/index/index’
],
window: {
backgroundTextStyle: ‘light’,
navigationBarBackgroundColor: ‘#fff’,
navigationBarTitleText: ‘WeChat’,
navigationBarTextStyle: ‘black’
}
}

/**
*

  • 1.小程序打开的参数 globalData.extraData.xx
  • 2.从二维码进入的参数 globalData.extraData.xx
  • 3.获取小程序的设备信息 globalData.systemInfo
  • @memberof App
    */
    async componentDidMount() {
    // 获取参数
    const referrerInfo = this. r o u t e r < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > . < / s p a n > p a r a m s < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > . < / s p a n > r e f e r r e r I n f o < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > ; < / s p a n > < s p a n c l a s s = " t o k e n k e y w o r d " > c o n s t < / s p a n > q u e r y < s p a n c l a s s = " t o k e n o p e r a t o r " > = < / s p a n > < s p a n c l a s s = " t o k e n k e y w o r d " > t h i s < / s p a n > < s p a n c l a s s = " t o k e n p u n c t u a t i o n " > . < / s p a n > router<span class="token punctuation">.</span>params<span class="token punctuation">.</span>referrerInfo<span class="token punctuation">;</span> <span class="token keyword">const</span> query <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span> router<spanclass="tokenpunctuation">.</span>params<spanclass="tokenpunctuation">.</span>referrerInfo<spanclass="tokenpunctuation">;</span><spanclass="tokenkeyword">const</span>query<spanclass="tokenoperator">=</span><spanclass="tokenkeyword">this</span><spanclass="tokenpunctuation">.</span>router.params.query;
    !globalData.extraData && (globalData.extraData = {});
    if (referrerInfo && referrerInfo.extraData) {
    globalData.extraData = referrerInfo.extraData;
    }
    if (query) {
    globalData.extraData = {
    globalData.extraData,
    query
    };
    }
<span class="token comment">// 获取设备信息</span>
<span class="token keyword">const</span> sys <span class="token operator">=</span> <span class="token keyword">await</span> Taro<span class="token punctuation">.</span><span class="token function">getSystemInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
sys <span class="token operator">&amp;&amp;</span> <span class="token punctuation">(</span>globalData<span class="token punctuation">.</span>systemInfo <span class="token operator">=</span> sys<span class="token punctuation">)</span><span class="token punctuation">;</span>

}

componentDidShow() { }

componentDidHide() { }

componentDidCatchError() { }

// 在 App 类中的 render() 函数没有实际作用
// 请勿修改此函数
render() {
return (
<Provider store={store}>
<Index />
</Provider>
)
}
}

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

发现tslint找不到模块“./models”。这样的错,不要急,我们在./models文件夹下创建index.ts这样一个文件夹,内容如下:

import index from '../pages/index/model';// index 页面的model

// 这里记得export的是数组,不是对象
export default [
index
]

可以发现,tslint已经不报错了。

2.改写./src/pages/index/config.ts
export default {
  getLists: '/japi/toh', // 获取历史上的今天接口
}
3.在./src/config/requestConfig.ts引入上面配置的接口,如下修改:
import index from '../pages/index/config' // index接口
/** 
 * 请求的公共参数
 */
export const commonParame = {}

/**

  • 请求映射文件
    */
    export const requestConfig = {
    loginUrl: ‘/api/user/wechat-auth’, // 微信登录接口
    index
    }
4.改写./src/pages/index/service.ts,如下:
import Api from '../../utils/request'

export const getLists = (data) => {
return Api.getLists(data)
}

5.改写./src/pages/index/index.interface.ts,如下:

/**
 * index.state 参数类型
 *
 * @export
 * @interface IndexState
 */
export interface IndexState {
  month: number
  day: number
}

/**

  • index.props 参数类型
  • @export
  • @interface IndexProps
    */
    export interface IndexProps {
    dispatch?: any,
    data?: Array<DataInterface>
    }

export interface DataInterface {
day: number
des: string
lunar: string
month: number
pic: string
title: string
year: number
_id: string
}

6.改写./src/pages/index/model.ts,如下:
// import Taro from '@tarojs/taro';
import * as indexApi from './service';

export default {
namespace: ‘index’,
state: {
data: [],
key: ‘72eed010c976e448971655b56fc2324e’,
v: ‘1.0’
},

effects: {
* getLists({ payload }, { select, call, put }) {
const { key, v } = yield select(state => state.index)
const { error, result } = yield call(indexApi.getLists, {
key,
v,
payload
})
if (!error) {
yield put({
type: ‘updateState’,
payload: {
data: result
}
})
}
}
},

reducers: {
updateState(state, { payload: data }) {
return { state, data }
}
}

}

7.改写./src/pages/index/index.tsx,如下:

import Taro, { Component, Config } from '@tarojs/taro'
import { View, Text } from '@tarojs/components'
import { connect } from '@tarojs/redux'
// import Api from '../../utils/request'
// import Tips from '../../utils/tips'
import { IndexProps, IndexState } from './index.interface'
import './index.scss'
// import {  } from '../../components'

@connect(({ index }) => ({
index,
}))

class Index extends Component<IndexProps, IndexState> {
config: Config = {
navigationBarTitleText: ‘Taro + dva demo’
}
constructor(props: IndexProps) {
super(props)
this.state = {
month: 0,
day: 0
}
}

// 获取今日数据
async getData(month: number, day: number) {
await this.props.dispatch({
type: ‘index/getLists’,
payload: {
month: month,
day: day
}
})
}

// 获取系统当前时间并请求参数
getDate() {
const myDate = new Date()
const m = myDate.getMonth() + 1
const d = myDate.getDate()
this.setState({
month: m,
day: d
})
this.getData(m, d)
}

componentDidMount() {
this.getDate()
}

render() {
const { month, day } = this.state
const { data } = this.props
return (
<View className=fx-index-wrap>
<View className=index-topbar>
<Text>{</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>month<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">月</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>day<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">日</span><span class="token template-punctuation string">}</Text>
<View>历史上的今天都发生了这些大事</View>
</View>
<View className=index-list>
{
data && data.map((item, index) => {
return <View className=index-li key={index}>
<View className=index-bg style={</span><span class="token string">background-image: url(</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>item<span class="token punctuation">.</span>pic<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">)</span><span class="token template-punctuation string">}></View>
<View className=index-info>
<View className=index-title>{item.title}</View>
<View className=index-des>{item.des}</View>
</View>
</View>
})
}
</View>
</View>
)
}
}

export default Index

5.接下来写样式./src/pages/index/index.scss,如下:
.index {
  &-wrap {
    width: 100%;
    min-height: 100vh;
  }

&-topbar {
padding: 10rpx 50rpx;
text-align: center;
font-weight: bold;

Text {
  color: rgb(248, 122, 3);
  font-size: 40rpx;
}

View {
  color: #333;
  font-size: 30rpx;
}

}

&-list {
padding: 50rpx;
}

&-li {
box-shadow: 0 4rpx 20rpx rgba($color: #000000, $alpha: 0.1);
margin-bottom: 50rpx;
border-radius: 8rpx;
overflow: hidden;
}

&-bg {
width: 100%;
height: 300rpx;
background-repeat: no-repeat;
background-size: contain;
background-position: center center;
background-color: #f5f5f5;
}

&-info {
padding: 15rpx;
}

&-title {
font-size: 30rpx;
font-weight: bold;
margin-bottom: 10rpx;
}

&-des {
font-size: 26rpx;
color: #666;
}
}

这时候基本结束了,在命令行运行:

cnpm run dev:weapp

如下显示,说明编译成功(tip:以后记得先编译,我是之前写好了的,不然很有可能一堆报错,那时候估计你会绝望的)

编译成功显示图

最后的最后,打开微信开发者工具,选择微信小程序,选择taro-demo文件夹下编译成功的 dist,appid就用微信提供给你测试的,名字随便输入一个,点击确定,之前步骤都没问题的话,最后显示的结果如下图:
小程序界面图

最后,恭喜你,配置完了,可以满足基本开发和需求了,如果有什么错误还望指出

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值