一个完整的基于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>
)
}
}