1. 名称:
    shoppingcar
  2. 作者:
    lzjk
  3. 来源:
  4. 浏览:
    36341
  5. 下载:
    13058
  6. 最新更新:
    2016-09-28
  7. 收藏0

效果:<br/>


app配置

{
  "pages":[
    "pages/index/index",
    "pages/components/dishes/dishes",
    "pages/components/take/take"
  ],
  "window":{
    "backgroundColor":"#f4f4f4",//背景色
    "backgroundTextStyle":"light", //背景文本样式
    "navigationBarBackgroundColor": "orange", //导航栏背景色
    "navigationBarTitleText": "美食汇微菜单",//导航栏文本
    "navigationBarTextStyle":"white"//导航栏文本颜色
  }
}

page数组记录中记录了小程序中的页面数量, 其中take页面没有代码.

这里直接借鉴的是app.wxss中的写法

/**app.wxss**/
.container {
  height: 100%;
  box-sizing: border-box;
  background-color: #f4f4f4;
}
.flex-wrap{
    display: flex;
}
.flex-item{
    flex: 1;
}
.flex-wrap.flex-direction-col{
    flex-direction: column;
}
.flex-wrap.flex-direction-row{
    flex-direction: row;
}

定义了最常用的一些样式. 可以很方便的进行样式的组合. 
app.js中就是helloworld的小程序的代码. 没什么好说的.

微菜单页面 index

index.wxml

从页面上来看, 头部是一个swiper, 下面是一些动态排列的view或者button.

<view class="container flex-wrap flex-direction-col">
  <view class="my-swiper">
      <swiper indicator-dots="{{indicatorDots}}"
    autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
    <block wx:for="{{imgUrls}}">
      <swiper-item>
        <image src="{{item}}" class="slide-image" height="150"/>
      </swiper-item>
    </block>
  </swiper>
  </view>

    <!-- 分类导航 -->
  <view class="nav-block wrap">
    <block wx:for="{{navItems}}"> 
      <view class="wrap-item {{item.isSplot ? 'exp' : ''}}">  
        <navigator url="../components/{{item.url}}/{{item.url}}" hover-class="navigator-hover">{{item.name}}</navigator>
      </view>
    </block>
  </view>

</view>

可以看到这个布局非常清晰. class="container flex-wrap flex-direction-col" 利用多个css样式组合, 提高了复用性.

.my-swiper image{
  width: 100%;
}

这里用到了组合选择器</span>文档-组合选择器</a>. 表示匹配所有.my-swiper选择器中的image标签.

<swiper indicator-dots="{{indicatorDots}}"
        autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}">
   <block wx:for="{{imgUrls}}">
      <swiper-item>
        <image src="{{item}}" class="slide-image" height="150"/>
      </swiper-item>
  </block>
</swiper>

这个应该算是swiper作为头部轮播图的模板代码了.

<!-- 分类导航 -->
<view class="nav-block wrap">
    <block wx:for="{{navItems}}"> 
      <view class="wrap-item {{item.isSplot ? 'exp' : ''}}">  
        <navigator url="../components/{{item.url}}/{{item.url}}" hover-class="navigator-hover">{{item.name}}</navigator>
      </view>
    </block>
</view>

分类导航是根据数据动态生成的. 所以也需要列表渲染. 
<view class="wrap-item {{item.isSplot ? 'exp' : ''}}"> 数据绑定时可以进行简单的三元运算
文档-数据绑定.这里的isSplot表示是否要绘制纵向的分割线. 如果item.isSplot为true,则样式为 wrap-item exp, 否则为wrap-item.

.wrap-item.exp{
    border: 1px solid #ddd;
    border-top: 0;
}

类名为exp的所有wrap-item都会绘制边界线.

我们在.wrap-item的样式中可以看到每个item的view都会绘制底部的边界线. 一行排列三个item (width:33%决定的), 那么中间的item和两边的item中间应该还需要纵向的分割线的. 这一点可以看上面的最终效果图.

.wrap-item{
    display: inline-block;
    width: 33%;//占父元素宽的比例
    height: 6rem; 
    line-height: 6rem;
    border-bottom: 1px solid #ddd; //底部的边界线
    background-color: #fff; //背景色
    text-align: center;
}

点击item菜单跳转页面使用了navigator组件.文档-navigator 
hover-class属性指定点击时的样式类.

<navigator url="../components/{{item.url}}/{{item.url}}" hover-class="navigator-hover">{{item.name}}</navigator>

index.js

页面中使用的是假数据. 可以看到轮播图是由imgUrls数组控制的. 而动态菜单是navItems数组控制, 需要绘制纵向分割线的使用isSplot布尔值控制. 指定url将跳转到对于的页面.

var app = getApp()
Page({
  data: {
    imgUrls: [
'http://img02.tooopen.com/images/20150928/tooopen_sy_143912755726.jpg',
'http://img06.tooopen.com/images/20160818/tooopen_sy_175866434296.jpg',
'http://img06.tooopen.com/images/20160818/tooopen_sy_175833047715.jpg'
    ],
    indicatorDots: true,
    autoplay: true,
    interval: 3000,
    duration: 1000,
    navItems:[
      {
        name:'堂食',
        url:'dishes'
      },
      {
        name:'外卖',
        url:'take',
        isSplot:true
      },
      {
        name:'外带',
        url:'out'
      },
      {
        name:'订单',
        url:'bill'
      },
      {
        name:'帐单',
        url:'bill',
        isSplot:true
      },
      {
        name:'报表',
        url:'bill'
      }
    ]
  },
  onLoad: function () {
    console.log('onLoad')
  }
})

点菜页面 dishes

这个页面效果现在在一些小型电商app中可以看到. 在左边栏选择,内容区对应改变显示响应的内容

dishes.wxml

左边栏</p>

<!-- left aside -->
<view class="aside flex-wrap flex-direction-col">
    <block wx:for="{{navList}}">
        <text class="type-nav {{curNav == item.id ? 'selected' : ''}}" bindtap="selectNav" data-index="{{index}}" data-id="{{item.id}}">{{item.name}}</text>
    </block>
</view>

左边栏是一个固定宽度的列表. 利用列表渲染填充数据. 
左边栏的样式

.aside{
    width:4rem; //屏幕宽度的1/5
    border-right: 1px solid #ddd;//右边界线
    font-size: .85rem;
}

小程序有两种推荐自适应单位: rpx, rem.

规定屏幕宽为750rpx, 20rem. 所以1rem = (750/20)rpx. 
文档-尺寸单位

左边栏列表项的样式&nbsp;
class="type-nav {{curNav == item.id ? 'selected' : ''}}"

.type-nav{ //未选中样式
    position: relative; //相对自己定位
    padding:.7rem .3rem; //上下0.7rem,左右0.3rem
    text-align: center; //文本居中
    border-bottom: 1px solid #ddd; //底部边界线
    z-index: 10; //设置元素的堆叠顺序
}
.type-nav.selected{ //选中样式
    margin-right: -1px; //这个应该消除右侧1px的边界线
    padding-left:-1px; //右侧margin改变,左侧padding改变,是的文本位置不变
    color: #333;//文本颜色
    background-color: #fff; //背景色
}

利用三元运算改变对应的样式, 这种方式用的很多. 大多数情况可以用作对用户操作的反馈, 包括修改选中和未选中状态.

内容区</p>

<!-- content -->
<view class="content flex-item">
    <block wx:for="{{dishesList[curIndex]}}">
        <view class="dish flex-wrap flex-direction-row" catchtap="selectDish" data-dish="{{item.id}}">
            <view class="flex-item">
                <text class="title">{{item.name}}</text>
                <p>¥{{item.price}}</p>
            </view>
            <view class="add-btn"><icon type="{{item.status ? 'success' : 'circle'}}" color="orange" size="30"></icon></view>
        </view>
    </block>
</view>

这里也是利用列表渲染绘制页面.

<view class="dish flex-wrap flex-direction-row" catchtap="selectDish" data-dish="{{item.id}}">1

前面文章里面有提到有两种绑定事件的方式: bind和catch. 
data-dish属性指定的值将封装到catch事件的event对象中. 
每个菜单条目的样式</p>

.dish{
    margin-left: 1rem;
    padding: 1rem;
    border-bottom: 1px solid #ddd; //底部边界线
}

右侧的选择按钮, 我以为是用radio做的, 现在发现使用的是icon组件.文档-icon

<icon type="{{item.status ? 'success' : 'circle'}}" color="orange" size="30"></icon></view>

根据item的状态修改icon的类型. success和circle都是内置类型.

底部购物车和加载框</p>

<!-- cart -->
<view class="cart">
    <text class="total">购物车:{{cartTotal}}</text>
</view>

<loading hidden="{{hidden}}">玩命加载中…&lt;/loading>

采用数据绑定, 这样可以很方便的修改购物车的数量.

dishes.js

data: {
        hidden:false,
        curNav:1,//当前选中的左边栏id
        curIndex:0,//当前选中的左边栏的索引
        cart:[], //购物车数组
        cartTotal:0, //购物车商品数量
        navList:[ //左边栏的数据
            {
                id:1,
                name:'热销菜品'
            },
            {
                id:2,
                name:'热菜'
            },
            {
                id:3,
                name:'凉菜'
            },
            {
                id:4,
                name:'套餐'
            }
        ],
        dishesList:[ //使用二维数组,将左边栏和内容区形成对应关系
            [
                {
                    name:"红烧肉&quot;,
                    price:38,
                    num:1,
                    id:1
                },
                {
                    name:"宫保鸡丁",
                    price:58,
                    num:1,
                    id:29
                },
                {
                    name:"水煮鱼&quot;,
                    price:88,
                    num:1,
                    id:2
                }
            ],
            [
                {
                    name:"小炒日本豆腐",
                    price:18,
                    num:1,
                    id:3
                },
                {
                    name:"烤鱼",
                    price:58,
                    num:1,
                    id:4
                }
            ],
            [
                {
                    name:"大拌菜&quot;,
                    price:18,
                    num:1,
                    id:5
                },
                {
                    name:"川北凉粉",
                    price:8,
                    num:1,
                    id:6
                }
            ],
            []
        ],
        dishes:[]
    },

这里利用二维数组将左边栏和内容区进行关联. 我们在左边栏选中不同的item, 对应右变量也会改变是因为在wxml中content区域配置了dishesList[curIndex]的数据绑定.

<block wx:for="{{dishesList[curIndex]}}">

设置左边栏的选中事件

selectNav (event) {
        let id = event.target.dataset.id,
            index = parseInt(event.target.dataset.index);
            self = this;
        this.setData({
            curNav:id,
            curIndex:index
        })
    },

这里用到了ES6新引入的关键字let. 深入浅出ES6(十四):let和const

获得wxml中设置的data-id, data-index属性的值. 然后修改当前选中的左边栏item的id和index.

选择菜品

// 选择菜品
    selectDish (event) {
        let dish = event.currentTarget.dataset.dish; //选择的菜品的id
        let flag = true; //true表示可以被添加到购物车中
        let cart = this.data.cart; //购物车数组

        if(cart.length > 0){ //购物车中有商品时
            cart.forEach(function(item,index){//遍历购物车
                if(item == dish){//购物车如果有该商品
                    cart.splice(index,1); //删除该商品
                    flag = false;//不能被添加到购物车中
                }
            })
        }
        if(flag) cart.push(dish); //添加到购物车
        this.setData({
            cartTotal:cart.length //购物车商品数量
        })
        this.setStatus(dish) //修改状态
    },
    //修改菜品选中状态
    setStatus (dishId) {
        let dishes = this.data.dishesList;//菜品的二维数组
        for (let dish of dishes){
            dish.forEach((item) => { //双重循环遍历
                if(item.id == dishId){ //修改对应id的状态
                    item.status = !item.status || false
                }
            })
        }

        this.setData({
            dishesList:this.data.dishesList
        })
    },

购物车的逻辑相对复杂一点. 这里用了一个boolean值flag表示可以被添加到购物车中. 默认情况下菜品可以被添加到购物车中, 但是当购物车中已经拥有该菜品,则需要从购物车中删除该菜品. 同时不管是添加到购物车还是从购物车中移除, 都需要修改对应菜品的的status. 
因为这个小程序都是采用的MVVM. 使用setData将数据从逻辑层推到视图层显示出来, 确实节省了很多工作.

这段代码中用到了一些JavaScript的语法. 需要慢慢学习.

显示对话框</p>

onLoad () {
        this.loadingChange()
    },
    loadingChange () {
        setTimeout(() => {
            this.setData({
                hidden:true
            })
        },2000)
    },

页面加载时显示对话框,2000ms之后关闭对话框.

这个demo基本上就全部分析完成了. 从这个demo中真的学到了很多知识. 只是纸上得来终觉浅,绝知此事要躬行</code>,要抓紧时间弄到相关的知识,熟练运用才是目的.

the end.


共0 条评论
  1. 加载评论

评论内容:

发表评论
  1. 全部组件分类
  2. 瀑布流
  3. 示例
  4. 提示组件(ToolTip)
  5. 下拉刷新、上拉加载
  6. Toast
  7. 选项卡(tab)
  8. 图表
  9. 卡片切换
  10. 菜单
  11. 筛选
  12. 星级评分
  13. 选择器
  14. 滑动删除
  15. 手势密码
  16. Switch
  17. 搜索
  18. 游戏
  19. 弹幕
  20. 懒加载
  21. 布局
  22. 应用模仿
  23. Emoji
  24. 转盘抽奖
  25. 插件
  26. UI库
  27. 动画
  28. 下拉列表
  29. SnackBar
  30. HTML解析
  31. 日历
  32. 点餐小程序
  33. 购物效果
  34. 框架
  35. 渲染引擎
  36. 商城
  37. 吸顶停留
  38. 会议
  39. 分享
  40. 其他
最新评论