美文网首页Taro转载专题
Taro + dva 使用小结(搭建配置过程)

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

作者: 陈小生_1017 | 来源:发表于2018-12-04 14:49 被阅读293次

    最近写一个微信小程序的项目,由于是协同开发,前期的搭建工作由另一个妹子完成,现在项目阶段一完成了,为了备忘回顾,做一个阶段性小结。
    在写小程序之前经过对比最后采用了京东凹凸实验室开发的类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 => `color: ${s}; font-weight: bold`
    
      // render
      logger.group(`%c ${title} @${formatTime(started)}`, ...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: `${opts.host || MAINHOST}${opts.url}`
        }
      }
    
      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() }
    
        // token存在
        // let options = Object.assign(opts, { header: { 'token': this.getToken() } })
    
        //  Taro.request 请求
        const res = await Taro.request(opts)
    
        // 是否mock
        if (ISMOCK) { return res.data }
    
        // 登陆失效 
        if (res.data.code === 99999) { await this.login(); return this.request(opts) }
    
        // 请求成功
        // if (res.data && res.data.code === 0 || res.data.succ === 0) { return res.data }
        if (res.data) { return res.data }
    
        // 请求错误
        const d = { ...res.data, err: (res.data && res.data.msg) || `网络错误~` }
        Tips.toast(d.err);
        throw new Error(d.err)
      }
    
      /**
       * 
       * @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: `${MAINHOST}${requestConfig.loginUrl}`,
            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.keys(requestConfig).forEach((key) => {
          this.apiLists[key] = this.creatRequests(requestConfig[key])
        })
    
        return this.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, ${capPirName}State } from './${dirName}.interface'
    import './${dirName}.scss'
    // import { } from '../../components'
    
    // @connect(({ ${dirName} }) => ({
    //     ...${dirName},
    // }))
    
    class ${capPirName} extends Component<${capPirName}Props,${capPirName}State > {
      config:Config = {
        navigationBarTitleText: '标题'
      }
      constructor(props: ${capPirName}Props) {
        super(props)
        this.state = {}
      }
    
      componentDidMount() {
        
      }
    
      render() {
        return (
          <View className='${dirName}-wrap'>
              
          </View>
        )
      }
    }
    
    export default ${capPirName}
    `
    
    // scss文件模版
    const scssTep = `
    ${dirName}-wrap {
        width: 100%;
        min-height: 100vh;
    }
    `
    
    // config 接口地址配置模板
    const configTep = `
    export default {
      test: '/wechat/perfect-info', //xxx接口
    }
    `
    // 接口请求模板
    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(`./src/pages/${dirName}`); // mkdir $1
    process.chdir(`./src/pages/${dirName}`); // cd $1
    
    fs.writeFileSync(`${dirName}.tsx`, indexTep); //tsx
    fs.writeFileSync(`${dirName}.scss`, scssTep); // scss
    fs.writeFileSync('config.ts', configTep); // config
    fs.writeFileSync('service.ts', serviceTep); // service
    fs.writeFileSync('model.ts', modelTep); // model
    fs.writeFileSync(`${dirName}.interface.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, ${capPirName}State } from './${dirName}.interface'
    import './${dirName}.scss'
    
    class ${capPirName} extends Component<${capPirName}Props,${capPirName}State > {
      constructor(props: ${capPirName}Props) {
        super(props)
        this.state = {}
      }
      static options = {
        addGlobalClass: true
      }
      static defaultProps:${capPirName}Props = {}
    
      render() {
        return (
          <View className='fx-${dirName}-wrap'>
    
          </View>
        )
      }
    }
    
    export default ${capPirName}
    `
    
    // scss文件模版
    const scssTep = `
    ${dirName}-wrap {
        width: 100%;
     }
    `
    
    const interfaceTep = `
    /**
     * ${dirName}.state 参数类型
     *
     * @export
     * @interface ${capPirName}State
     */
    export interface ${capPirName}State {}
    
    /**
     * ${dirName}.props 参数类型
     *
     * @export
     * @interface ${capPirName}Props
     */
    export interface ${capPirName}Props {}
    `
    
    fs.mkdirSync(`./src/components/${dirName}`); // mkdir $1
    process.chdir(`./src/components/${dirName}`); // cd $1
    
    fs.writeFileSync(`${dirName}.tsx`, indexTep); //tsx
    fs.writeFileSync(`${dirName}.scss`, scssTep); // scss
    fs.writeFileSync(`${dirName}.interface.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/fxTaroInit.js"
    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.$router.params.referrerInfo;
        const query = this.$router.params.query;
        !globalData.extraData && (globalData.extraData = {});
        if (referrerInfo && referrerInfo.extraData) {
          globalData.extraData = referrerInfo.extraData;
        }
        if (query) {
          globalData.extraData = {
            ...globalData.extraData,
            ...query
          };
        }
    
        // 获取设备信息
        const sys = await Taro.getSystemInfo();
        sys && (globalData.systemInfo = sys);
      }
    
      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>{`${month}月${day}日`}</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={`background-image: url(${item.pic})`}></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就用微信提供给你测试的,名字随便输入一个,点击确定,之前步骤都没问题的话,最后显示的结果如下图:
    小程序界面图

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

    -------------------------- END -----------------------

    示例GitHub地址:

    相关文章

      网友评论

        本文标题:Taro + dva 使用小结(搭建配置过程)

        本文链接:https://www.haomeiwen.com/subject/xfxycqtx.html