一个在线运行的Taro小程序完整实例

一个完整的基于taro3版本开发的微信小程序案例。我们要实现的基本功能,在微信小程序选择产品,然后系统显示产品与国家标准的对比情况,具体功能可以扫码查查看演示。
 

1、文件结构
 

     src 
│  │  ├─ pages
│  │  │  ├─ composition.jsx        
│  │  │  ├─ gbnew.js                 
│  │  │  ├─ gbold.js                    
│  │  │  └─ index
│  │  │     ├─ index.jsx
│  │  │     └─ index.scss
│  │  ├─ components
│  │  │  ├─ AtTable.js
│  │  │  ├─ AtTable.scss
│  │  │  ├─ banner.js
│  │  │  ├─ banner.scss
│  │  │  ├─ ColorFlag.js
│  │  │  ├─ ConstructTable.js
│  │  │  ├─ ConstructTable.scss
│  │  │  ├─ milkimage.js
│  │  │  ├─ milkimage.scss
│  │  │  ├─ PagePicker.js
│  │  ├─ project.config.json
│  │  ├─package.json
│  │  ├─ app.config.js
│  │  ├─ app.js
│  │  ├─ app.scss
│  │  ├─ index.html

2、app.config.js  页面配置

export default {
  pages: [
    'pages/index/index',
    'pages/gbnew',
    'pages/gbold',
    'pages/composition',
  ],
  window: {
    backgroundTextStyle: 'light',
    navigationBarBackgroundColor: '#fff',
    navigationBarTitleText: '奶粉国标比对',
    navigationBarTextStyle: 'black'
  }
}

3、index.jsx

import { Component } from 'react'
import { View,Picker } from '@tarojs/components'
import './index.scss'
import { AtButton ,AtList, AtListItem ,AtToast  } from 'taro-ui'
import Banner from '../../components/banner'
import MilkImage from '../../components/milkimage'
import ConstructTable from '../../components/ConstructTable'


//产品
const procuts=[
]

//图片URL,顺序与产品名称对应
const procutsImageUrl = []

const baseData_dtz_old = []
const baseData_mineral_old = []
const baseData_choose_old = []

const baseData_dtz_new = []
const baseData_mineral_new = []
const baseData_choose_new = []

export default class Index extends Component {

  state = {
    selector: [procuts[0],procuts[1][0]],
    selectorChecked:[], //选择的品牌及产品
    selectorProcuts:'', 
    selectorProcutsIsShow:false, //点击了比对后就显示表格
    isOpened:false,  //请先选择产的提示
    isNewFlag:false, //显示新国标还是老国标 false 老 true 新
    baseData_dtz:[], //数据集送给表格展示
    baseData_vitamin:[],
    baseData_mineral:[],
    baseData_choose:[],
    isoldgb:true, //显示老国标
    isnewgb:false, //显示新国标
    imageurl:procutsImageUrl[0][0],  //用于记录选择的产品序数组下标,然后取图片URL
  }

  componentWillMount () { }
  componentDidMount () { }
  componentWillUnmount () { }
  componentDidShow () { }
  componentDidHide () { }

  //筛选菜单点击确定
  onChange = e => {
    this.setState({
      selectorChecked:[this.state.selector[0][e.detail.value[0]],this.state.selector[1][e.detail.value[1]]],
      selectorProcuts:this.state.selector[1][e.detail.value[1]],
      isOpened:false,
      imageurl:procutsImageUrl[e.detail.value[0]][e.detail.value[1]],
    })

    //如果经过第一次点击对比后以后的切换产品不需要再点对比按钮,由于setState是异步的,所以要用下面的写法将onConstruct放到setState后执行
    if (this.state.selectorProcutsIsShow){
      this.setState({
      selectorChecked:[this.state.selector[0][e.detail.value[0]],this.state.selector[1][e.detail.value[1]]],
      selectorProcuts:this.state.selector[1][e.detail.value[1]],
      isOpened:false,
      imageurl:procutsImageUrl[e.detail.value[0]][e.detail.value[1]],
    },function(){
      this.onConstruct();
    })
    }
  }

//筛选过程两级级联动作
  onColumnChange = e => {
    let {column,value} = e.detail;
    //判断是第几列改变了,如果是第一列变化,那么就要级联调动第二列
    if (column===0) {
      this.setState({
        selector: [procuts[0],procuts[1][value]],
      })
    } else {

    }
  }

//点击对比按钮
  onConstruct = e =>{
    //判断产品是否已经选择
    if(this.state.selectorProcuts===''){
      this.setState({
        isOpened:true
      })
    }
    else{
      this.onChooseData(false) //查询按钮永远查老国标
      this.setState({
        selectorProcutsIsShow:true,
        isOpened:false,
        isoldgb:true,
        isnewgb:false
      })
    }
  }

//对数据选择的处理
  onChooseData = (e)=>{
    //根据选择的品牌及产品名称判断该返回的字段
    if (!e){
        baseData_dtz_old.map((item,index)=>{
          if(item.brandName==this.state.selectorChecked[0] && item.prodcutName==this.state.selectorChecked[1]){
            console.log("item.dataSource",item.dataSource)
            this.setState({
              baseData_dtz:item.dataSource
            })
          }
        })
        baseData_vitamin_old.map((item,index)=>{
          if(item.brandName==this.state.selectorChecked[0] && item.prodcutName==this.state.selectorChecked[1]){
            this.setState({
              baseData_vitamin:item.dataSource
            })
          }
        })
        baseData_mineral_old.map((item,index)=>{
          if(item.brandName==this.state.selectorChecked[0] && item.prodcutName==this.state.selectorChecked[1]){
            this.setState({
              baseData_mineral:item.dataSource
            })
          }
        })
        baseData_choose_old.map((item,index)=>{
          if(item.brandName==this.state.selectorChecked[0] && item.prodcutName==this.state.selectorChecked[1]){
            this.setState({
              baseData_choose:item.dataSource
            })
          }
        })
    }
    else {
        baseData_dtz_new.map((item,index)=>{
            if(item.brandName==this.state.selectorChecked[0] && item.prodcutName==this.state.selectorChecked[1]){
              this.setState({
                baseData_dtz:item.dataSource
              })
            }
          })
          baseData_vitamin_new.map((item,index)=>{
            if(item.brandName==this.state.selectorChecked[0] && item.prodcutName==this.state.selectorChecked[1]){
              this.setState({
                baseData_vitamin:item.dataSource
              })
            }
          })
          baseData_mineral_new.map((item,index)=>{
            if(item.brandName==this.state.selectorChecked[0] && item.prodcutName==this.state.selectorChecked[1]){
              this.setState({
                baseData_mineral:item.dataSource
              })
            }
          })
          baseData_choose_new.map((item,index)=>{
            if(item.brandName==this.state.selectorChecked[0] && item.prodcutName==this.state.selectorChecked[1]){
              this.setState({
                baseData_choose:item.dataSource
              })
            }
          })
    }
  }

//切换新旧国标
  onClickNewOld = (e)=>{
    this.onChooseData(e)
    if(e){
      this.setState({
        isNewFlag:e,
        isoldgb:false,
        isnewgb:true
      })
    }
    else {
      this.setState({
        isNewFlag:e,
        isoldgb:true,
        isnewgb:false
      })
    } 
  }

  render () {
    return (
      <View className='index'>
        <View className='main'>
        {this.state.selectorProcutsIsShow?<MilkImage imageurl={this.state.imageurl}/>:<Banner/>}
          <View className='pick'>
              <View className='page-section'>
                <View>
                  <Picker mode='multiSelector' 
                          range={this.state.selector} 
                          onChange={this.onChange}
                          onColumnChange={this.onColumnChange}
                  >
                    <AtList>
                      <AtListItem
                        title='请选择产品'
                        extraText={this.state.selectorChecked}
                      />
                    </AtList>
                  </Picker>
                </View>
              </View>
              <AtButton className="querybutton" type='primary' onClick={this.onConstruct}>奶粉国标比对</AtButton>
          </View>

          <View>
            <AtToast isOpened={this.state.isOpened} text="请先选择产品"></AtToast>
            {this.state.selectorProcutsIsShow?<View><ConstructTable 
                                                     baseData_dtz={this.state.baseData_dtz}
                                                     baseData_vitamin={this.state.baseData_vitamin}
                                                     baseData_mineral={this.state.baseData_mineral}
                                                     baseData_choose={this.state.baseData_choose}
                                                     onClickNewOld={this.onClickNewOld}
                                                     isoldgb={this.state.isoldgb}
                                                     isnewgb={this.state.isnewgb}
                                                     /></View>:null}
          </View>
        </View>
      </View>
    )
  }
}

4、composition.jsx

import { Component } from 'react'
import { View,Image ,Text } from '@tarojs/components'
import './composition.scss'
import { AtCard  } from 'taro-ui'
import { Current } from '@tarojs/taro'

export default class GbOld extends Component {

  
  state = {
      params:'',
      contentUsefor:'',
      contentLower:'',
      contentUpper:'',
      contentComposition:'',
      contentOther:''
  }
  
  componentWillMount () {
    var params = Current.router.params.name
    switch(params){
        case '蛋白质':
            this.setState({
                params:params,
                contentUsefor:'作用:提供生长发育所需氨基酸;有助于免疫力形成和提高;参与和调节新陈代谢;\n',
                contentLower:'缺乏:生长发育迟缓、智力发育障碍;免疫力降低等;\n',
                contentUpper:'过量:消化不良;腹泻;加重肾脏负担,导致肥胖;\n',
                contentComposition:'配料:脱脂牛奶、生牛乳、脱脂乳粉、全脂乳粉;\n',
                contentOther:'优质蛋白:a-乳白蛋白、a-乳清蛋白、免疫球蛋白、乳铁蛋白、酪蛋白'
            })
            break
        
        case '二十二碳六烯酸(DHA)':
            this.setState({
                params:params,
                contentUsefor:'作用:促进胎儿大脑发育、促进视力发育;\n',
                contentLower:'缺乏:智力低下、弱视;\n',
                contentUpper:'过量:降低免疫能力;\n'
            })
        break                
    }

   }

  componentDidMount () { }

  componentWillUnmount () { }

  componentDidShow () { }

  componentDidHide () { }

  render () {
    return (
      <View className='index'>
        <View className='constructtable'>
                <AtCard
                    className="at-card"
                    // extra='点击营养素名可查看详解'
                    title={this.state.params}
                >
                    <View className='content'><Text>{this.state.contentUsefor}</Text></View>
                    <View className='content'><Text >{this.state.contentLower}</Text></View>    
                    <View className='content'><Text >{this.state.contentUpper}</Text></View>    
                    <View className='content'><Text>{this.state.contentComposition}</Text></View>  
                    <View className='content'><Text>{this.state.contentOther}</Text></View>      
                </AtCard>
            </View>
      </View>  
    )
  }
}

5、gbnew.jsx

import { Component } from 'react'
import { View,Image } from '@tarojs/components'
import './gbnew.scss'



export default class Gbnew extends Component {

  state = {
  }

  componentWillMount () { }

  componentDidMount () { }

  componentWillUnmount () { }

  componentDidShow () { }

  componentDidHide () { }

  render () {
    return (
      <View className='gbnew'>
        <Image className='gbnew' src="https://i.niupic.com/images/2021/09/23/9CyY.jpg" mode='aspectFit'></Image>
      </View>
    )
  }
}

6、gbold.jsx

import { Component } from 'react'
import { View,Image } from '@tarojs/components'
import './gbold.scss'



export default class GbOld extends Component {

  state = {
  }

  componentWillMount () { }

  componentDidMount () { }

  componentWillUnmount () { }

  componentDidShow () { }

  componentDidHide () { }

  render () {
    return (
      <View className='gbold'>
          <Image className='gbold' src="https://i.niupic.com/images/2021/09/23/9Czx.jpg" mode='aspectFit'></Image>
      </View>
    )
  }
}

7、AtTable.js

// 自己简单封装的表格组件,taro 和微信都没有table组件
import { Component } from 'react'
import { View} from '@tarojs/components'
import './AtTable.scss'

//需要传进来的数据示例
const exampledataSource = [
    {
        username: '小红',
        count: '123',
        gb:'321',
        dbd:'30%'
    }
]
//需要传进来的表头数据示例
const examplecolumns = [
    {
        title: '名称',
        dataIndex: 'username',
        width:'20%',
    },
    {
        title: '含量',
        dataIndex: 'count',
        width:'20%',
    },
    {
        title: '标准',
        dataIndex: 'gb',
        width:'40%',
    },
    {
        title: '达标度',
        dataIndex: 'dbd',
        width:'20%',
    },
]

//原理 循环生成表头,循环数据根据表头填入每一列
export default class AtTable extends Component {

    render () {
        return (
            <View className="table">
                <View className="tr bg-header">
                    {
                        this.props.columns.map((item,index)=>{
                            return (<View className="th" style={{ width:item.width}}>
                                    {item.title}
                                    </View>)
                        })
                    }
                </View>
                
                    {
                        this.props.dataSource.map((item,index)=>{
                            return (
                                    <View className="tr bg-line">
                                    {
                                        this.props.columns.map((item2,index2)=>{
                                            if(item2.render){
                                                return (
                                                    <View className="td" style={{ width:item2.width}}>
                                                        {  
                                                            item2.render(item[item2.dataIndex])  //判断表头是不是有render 有就执行render
                                                        }
                                                    </View>
                                                )
                                            }
                                            else {
                                                return (     
                                                    <View className="td" style={{ width:item2.width}}>
                                                        {  
                                                            item[item2.dataIndex]  //根据表头填数据
                                                        }
                                                    </View>
                                                )
                                            }
                                        }
                                        )
                                    }
                                    </View>
                                    )
                        })
                    }
                </View>                

        )
    }
}

8、banner.js

import { Component } from 'react'
import { View,Image,Swiper, SwiperItem  } from '@tarojs/components'
import './banner.scss'


export default class Banner extends Component {

  render () {
    return (
      <Swiper
        className='test-h'
        indicatorColor='#999'
        indicatorActiveColor='#333'
        circular
        indicatorDots
        autoplay>
        <SwiperItem>
          <View className='demo-text-1'><Image className='banner'  src='https://s3.bmp.ovh/imgs/2021/10/ef753b5e66170d46.jpg'></Image></View>
        </SwiperItem>
        <SwiperItem>
          <View className='demo-text-2'><Image className='banner'  src='https://s3.bmp.ovh/imgs/2021/10/a364e41d09535144.jpg'></Image></View>
        </SwiperItem>
      </Swiper>
    )
  }
  }
  

9、ColorFlag.js

// 自己简单封装的表格组件,taro 和微信都没有table组件
import { Component } from 'react'
import { View} from '@tarojs/components'

export default class ColorFlag extends Component {
    // onHandleClick=()=>{
    //     console.log("colorflag:",this.props.record)
    // };

    //根据props判断组件应该显示什么颜色。不能用state来保存值,会引起前端刷新不改变,只能直接使用传过来的props
    getColorNum=(e)=>{
        var background="#30cc00"
        if(e<0){
            background="#FF4949";
        }
        else if(e == 0){
            background="#ffc701";
        }
        else if(e>0 && e<30){
            background="#30cc004b";
        }
        else if(e>=30 && e<50){
            background="#30cc0080";
        }
        else if(e>=50 && e<70){
            background="#30cc00bc";
        }
        else if(e>=70){
            background="#30cc00";
        }
        else if (e =='未标注'){
            background="#ffc701";
        }

        return background
    }

    render(){
        return (
            <View onClick={this.onHandleClick} 
                  style={{width:'18px',height:'18px',borderRadius:'50%',background:this.getColorNum(this.props.record)}}>
            </View>
        )
    }
}

10、ConstructTable.js

import { Component } from 'react'
import { View } from '@tarojs/components'
import { AtCard,AtTag,AtIcon , } from 'taro-ui'
import './ConstructTable.scss'
import AtTable from './AtTable'
import Taro from '@tarojs/taro';
import ColorFlag from './ColorFlag'
//taro 和 微信都没有table 组件 安装 taro3-table https://taro-ext.jd.com/plugin/view/604d7cde39b51f165cbfb11c  适配不好,不好用
// import Table from 'taro3-table';


export default class ConstructTable extends Component {
    //数据放到class中才能使用内部自定义的函数
    //蛋白质、碳水化合物、脂肪
    columns_dtz = [
        {
            title:'营养素',
            dataIndex:'composition',
            width:'20%',
            render:(record)=>{
                return(<View onClick={()=>this.onClickInfo(record)}>{record}</View>) //这里注意一定要用这个胖箭头,否则当组件加载时,会自动执行onClick
            }
        },
        {
            title:'单位',
            dataIndex:'unit',
            width:'20%'
        },
        {
            title:'100千焦含量',
            dataIndex:'content',
            width:'20%'
        },
        {
            title:'标准值',
            dataIndex:'standard',
            width:'30%'
        },
        {
            title:'达标度',
            dataIndex:'reachfor',
            width:'10%',
            render:(record)=>{
                return(<ColorFlag record={record}/>)
            }
        }

    ]

    //维生素
    columns_vitamin = [
        {
            title:'维生素',
            dataIndex:'composition',
            width:'20%',
            render:(record)=>{
                return(<View onClick={()=>this.onClickInfo(record)}>{record}</View>) //这里注意一定要用这个胖箭头,否则当组件加载时,会自动执行onClick
            }
        },
        {
            title:'单位',
            dataIndex:'unit',
            width:'20%'
        },
        {
            title:'100千焦含量',
            dataIndex:'content',
            width:'20%'
        },
        {
            title:'标准值',
            dataIndex:'standard',
            width:'30%'
        },
        {
            title:'达标度',
            dataIndex:'reachfor',
            width:'10%',
            render:(record)=>{
                return(<ColorFlag record={record}/>)
            }
        }
    ]

    //矿物质
    columns_mineral = [
        {
            title:'矿物质',
            dataIndex:'composition',
            width:'20%',
            render:(record)=>{
                return(<View onClick={()=>this.onClickInfo(record)}>{record}</View>) //这里注意一定要用这个胖箭头,否则当组件加载时,会自动执行onClick
            }
        },
        {
            title:'单位',
            dataIndex:'unit',
            width:'20%'
        },
        {
            title:'100千焦含量',
            dataIndex:'content',
            width:'20%'
        },
        {
            title:'标准值',
            dataIndex:'standard',
            width:'30%'
        },
        {
            title:'达标度',
            dataIndex:'reachfor',
            width:'10%',
            render:(record)=>{
                return(<ColorFlag record={record}/>)
            }
        }
    ]

    //可选成分
    columns_choose = [
        {
            title:'可选成分',
            dataIndex:'composition',
            width:'20%',
            render:(record)=>{
                return(<View onClick={()=>this.onClickInfo(record)}>{record}</View>) //这里注意一定要用这个胖箭头,否则当组件加载时,会自动执行onClick
            }
        },
        {
            title:'单位',
            dataIndex:'unit',
            width:'20%'
        },
        {
            title:'100千焦含量',
            dataIndex:'content',
            width:'20%'
        },
        {
            title:'标准值',
            dataIndex:'standard',
            width:'30%'
        },
        {
            title:'达标度',
            dataIndex:'reachfor',
            width:'10%',
            render:(record)=>{
                return(<ColorFlag record={record}/>)
            }
        }
    ]

    
    

  componentWillMount () { 
  }

//切换为旧国标
  onClickOldTag=()=>{
    if(this.props.isoldgb!=true)
    this.props.onClickNewOld(false)
  }

//切换新国标
  onClickNewTag=()=>{
    if(this.props.isnewgb!=true)
    this.props.onClickNewOld(true)
    
  }

//跳转配方解析?id=2&type=test
onClickInfo=(record)=>{   
    console.log("onClickInfo被点击",record)
    var url = '/pages/composition?name=' + record
    Taro.navigateTo({url:url})
}
  
//显示新国标
  onClickGbNew=()=>{
    Taro.navigateTo({url:'/pages/gbnew'})
  }
//显示旧国标
  onClickGbOld=()=>{
    Taro.navigateTo({url:'/pages/gbold'})
  }

  render () {
      return (
            <View className='constructtable'>
                <View className='gboldnew'>

                    <AtTag name="现版国标"
                           active={this.props.isoldgb}
                           onClick={this.onClickOldTag}
                           >现版国标</AtTag>
                    <AtIcon className="helpicon" 
                            value='message' 
                            size='20' 
                            color='#5f6642'
                            onClick={this.onClickGbOld}>    
                    </AtIcon>
                    <AtTag name="新版国标"
                           active={this.props.isnewgb}
                           onClick={this.onClickNewTag}
                           >新版国标</AtTag>
                    <AtIcon className="helpicon" 
                            value='message' 
                            size='20' 
                            color='#5f6642'
                            onClick={this.onClickGbNew}>
                    </AtIcon>

                </View>
                <AtCard
                    className="at-card"
                    extra=''
                    title='点击营养素名查看详解'
                >    
                    <AtTable dataSource={this.props.baseData_dtz} columns={this.columns_dtz}/>  
                    <AtTable dataSource={this.props.baseData_vitamin} columns={this.columns_vitamin}/>  
                    <AtTable dataSource={this.props.baseData_mineral} columns={this.columns_mineral}/>  
                    <AtTable dataSource={this.props.baseData_choose} columns={this.columns_choose}/>  
                </AtCard>    
            </View>                
      )
    }
  }

11、milkimage.js

//奶粉的图片
import { Component } from 'react'
import { View,Image } from '@tarojs/components'
import './milkimage.scss'


export default class MilkImage extends Component {
//  componentWillMount () {
//      console.log("地址",this.props.imageurl)
//   }
  render () {
    return (
        <View className='milkimage1'>
            <Image className='milkimage2' src={this.props.imageurl}></Image>
        </View>
    )}
}

12、pagePicker.js
 

import { Component } from 'react'
import { View, Text, Picker } from '@tarojs/components'
import { AtList, AtListItem } from 'taro-ui'


export default class PagePicker extends Component {
  state = {
    selector: [procuts[0],procuts[1][0]],
    selectorChecked:[],
    selectorProcuts:'',
    selectorProcutsIsShow:false,
  }

//筛选菜单点击确定
onChange = e => {
    this.setState({
      selectorChecked: [this.state.selector[0][e.detail.value[0]],this.state.selector[1][e.detail.value[1]]],
      selectorProcuts:this.state.selector[1][e.detail.value[1]]
    })
  }

//筛选过程两级级联动作
onColumnChange = e => {
    console.log("onColumnChange获取到的值value:",e.detail.value)
    console.log("onColumnChange获取到的值column:",e.detail.column)
    let {column,value} = e.detail;
    //判断是第几列改变了,如果是第一列变化,那么就要级联调动第二列
    if (column===0) {
      this.setState({
        selector: [procuts[0],procuts[1][value]],
      })
    } else {
  
    }
  }


render () {
    return (
          <View className='page-section'>
            <View>
              <Picker mode='multiSelector' 
                      range={this.state.selector} 
                      onChange={this.onChange}
                      onColumnChange={this.onColumnChange}
              >
                <AtList>
                  <AtListItem
                    title='请选择产品'
                    extraText={this.state.selectorChecked}
                  />
                </AtList>
              </Picker>
            </View>
          </View>
    )
  }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值