京东购物组件开发

1,010 阅读4分钟

前言

  • 最近正在学习微信小程序开发,便合作仿了个京东购物微信小程序,我负责的主要是我的界面,这里分享一下我的学习过程,欢迎一起交流。

image.gif

开发准备

总体架构

| -components        自定义组件
    | -dialogDate    选择出生日期
    | -dialogGender  选择性别
    | -dialogImg     更换头像
    | -dialogName    修改昵称
| -config            数据
    | -config.js
| -images            图标
    | -my 
| -pages             
    | -my            我的界面页
    | -set           账户设置界面页
    | -person        个人信息界面页

项目效果

image.gif

image.png

1fulo-jc8y0.gif

zb3q2-dy6uv.gif

9fusw-yccyx.gif

我的界面

20210828004405.png

  • 这里我的界面需要自定义顶部样式,只需在my.json中添加一行代码就可以了
"navigationStyle": "custom"

头部导航栏渐变

8ewke-izeq7.gif

  • 界面头部导航栏有个下拉渐变的效果,我是通过改变头部导航栏背景的透明度opacity来实现的
  <!-- 头部导航 -->
  <view class="page_nav">
    <view class="nav" style="opacity: {{ num }}"></view> 
    <view class="title">我的</view>
  </view>
onPageScroll(e){
    //  console.log(e.scrollTop);
    this.setData({
      num: (200 - e.scrollTop) / 200
    })
  },
  • onPageScroll监听用户滑动页面事件,参数对象crollTop表示页面在垂直方向已滚动的距离,js数据绑定来改变opacity的值,从而实现页面下拉头部导航栏渐变效果。
.page_nav {
    height: 11vh;
    width: 100%;
    position: fixed;
    background-color: #fff;
}
  • 因为当页面下拉到一定距离时,头部导航栏背景是白色的而不是纯透明的,所以别忘了设置背景颜色。

页面数据

  • 页面的数据放在config.js里,在模块里写好模块接口,module.exports 提供了暴露接口的方法。然后再js中require导出数据。 image.png

image.png

<!-- 主体 -->
<view class="order-box">
    <view class="order-list" wx:for="{{order}}" wx:key="id">
        <view class="order-column" data-id="{{item.id}}">
          <image mode="aspectFill" class="order-imgbox" src="{{item.icon}}"/>
          <view class="order-title">{{item.name}}</view>
        </view>
    </view>
    <view class="border">
        <image class="border" src="../../images/my/border.png"></image>
    </view>
        <view class="viewticket">查看发票</view>
    </view>
  • 页面的主体部分样式差不多,都是用wx:for循环来写。采用了弹性布局,其中flex-wrap: wrap;让弹性盒元素在必要的时候拆行。

账户设置界面

image.png

页面布局

  • 账户设置界面页采用了WeUI组件中的cell组件,很快就写出了页面。
<mp-cells>
    <mp-cell link>
        <view>我的收货地址</view>
        <view class="footer" slot="footer">管理我的地址</view>
    </mp-cell>
    <mp-cell link>
        <view>发票抬头管理</view>
        <view class="footer" slot="footer">管理增票资质</view>
    </mp-cell>
</mp-cells>       

个人信息界面

20210828010733.png

组件声明

  • 页面使用WeUI组件、Vant组件和自定义组件均要声明。其中van-toast文字提示组件是点击用户名的提示,而wx.showToast提示的文字超过一定数量就换行了。
"usingComponents": {
    "mp-cells": "../../miniprogram_npm/weui-miniprogram/cells/cells",
    "mp-cell": "../../miniprogram_npm/weui-miniprogram/cell/cell",
    "dialogName": "../../components/dialogName/dialogName",
    "dialogImg": "../../components/dialogImg/dialogImg",
    "dialogDate": "../../components/dialogDate/dialogDate",
    "dialogGender": "../../components/dialogGender/dialogGender",
    "van-toast": "@vant/weapp/toast/index"
  }

自定义组件

dialogImg

image.png

1fulo-jc8y0.gif

  • 这里不足之处是还只能实现简单的更换头像,没有把头像传到云端保存。
//  dialogImg.js
changeimage() {   
    var _this = this;  
    wx.chooseImage({
        count: 1, // 默认9      
        sizeType: ['original', 'compressed'],  // 指定是原图还是压缩图,默认两个都有      
        sourceType: ['album', 'camera'],      // 指定来源是相册还是相机,默认两个都有    
        success: function(res) {       
        // 返回选定照片的本地文件路径tempFilePath可以作为img标签的src属性显示图片 
        // 然后请求接口把图片传给后端存到服务器即可       
        _this.setData({    
          pic: res.tempFilePaths      
        }) 
        }    
      })
      this.triggerEvent('ImgEvent', this.data.pic);
      // console.log(this.data.pic, '----');
    },
//  person.js
ImgEvent(e) {
    console.log(e.detail);
    this.setData({
      pic : e.detail 
    })
  },
  • 父组件通过this.triggerEvent()获得子组件传递过来的值pic,后面几个组件均是如此。this.triggerEvent('',{},{})的第一个参数是自定义事件名称,这个名称是在页面调用组件时bind的名称,第二个对象就是想要的状态和值。

dialogName

image.png

9fusw-yccyx.gif

getInputValue(e){
      //  console.log(e.detail)
      this.setData({
         name: e.detail
      }) 
    },
     /*
     * 内部私有方法建议以下划线开头
     * triggerEvent 用于触发事件
     */
    _cancelEventName(){
      //触发取消回调
      this.triggerEvent("cancelEvent")
    },
    _confirmEventName(){
      //触发成功回调
      this.triggerEvent("confirmEvent");
      this.triggerEvent('myevent', this.data.name);
      console.log(this.data.name, '----');
    }
  • bindinput='getInputValue'获取输入框内容,打印的结果如下,e.detail.value为输入的值,e.detail.cursor则是输入的字符长度。输入的值通过点击确认按钮传到父组件,然后显示出来,建议多使用console.log()跟进一下数据传递。
//  person.js
// 获取dialogName传的值
  myevent(e) {
    console.log(e.detail);
    if (e.detail.cursor < 3 ) {
      // wx.showToast({
      //   title: '不符合昵称要求,请重新输入',
      //   icon: 'none',
      // }) 
      Toast({
        message: '不符合昵称要求,请重新输入',
        duration: 2000
      })
    } else {
      this.setData({
        name : e.detail.value
      })
      app.globalData.name = this.data.name;// 当页面修改数据后,更新globalData的数据
    }
    // console.log(this.data.name);
    // console.log(app.globalData.name);
  },
  onShow: function () {
    this.setData({
      name: app.globalData.name
    })
  },
  • 多个页面共用同一个数据昵称,并修改昵称后,各页面同步更新昵称。因为小程序里globalData存储的是全局对象,所以多个页面使用到的数据就放到globalData里可实现同步。

image.png

dialogGender

20210828011326.png

<!-- wxml -->
<van-popup show="{{isShow}}" round position="bottom" custom-style="height:50%" 
bind:click-overlay="_cancelEventGender">
  <view class="container"> 
  
        <view class="header">
            <view class="title">性别</view>
            <image class="x" src="../../images/my/dialog-cancle.png" bindtap="_cancelEventGender"/>
        </view>
        
        <view class="content">
            <van-picker show-toolbar="{{false}}"
                columns="{{ columns }}"
                default-index="{{ 2 }}"
                bind:change="onChange"
            ></van-picker>
        </view>
        
        <view class="footer">
            <button class="btn1" catchtap="_cancelEventGender" style="width:350rpx">取消</button>
            <button class="btn2" catchtap="_confirmEventGender" style="width:350rpx">确认</button>
        </view>
    </view>
</van-popup>


// .js
data: {
    isShow: false,
    columns: [
      '男','女','保密'
    ],
    value: ''
  },
    onChange(e) {
      console.log(e.detail);
      this.setData({
        value: e.detail.value
      })
    },

dialogDate

20210828012300.png

<van-datetime-picker
    type="date"
    value="{{ currentDate }}"
    item-height="46"
    min-date="{{ minDate }}"
    max-date="{{ maxDate }}"
    bind:input="onInput"
    formatter="{{ formatter }}"
    show-toolbar="{{ false }}"
    visible-item-count="5"
    />
  • van-datetime-picker 日期组件设置选择日期范围时,并不是直接date里minDate到maxDate,小程序显示的范围实际都往后推一个月。这里的组件范围是1900年01月01日到2030 年12月28日。onInput是当值发生变化时触发,获取选择的日期。
  • new Date()获取时间,getFullYear()从date对象以四位数字返回年份,getMonth()从date对象返回月份 (0 ~ 11),getDate()从date对象返回一个月中的某一天 (1 ~ 31)。
data: {
    isShow: false,
    minDate: new Date(1900, 0, 1).getTime(),
    maxDate: new Date(2030, 11, 28).getTime(),
    currentDate: new Date().getTime(),
    formatter(type, value) {
      if (type === 'year') {
        return `${value}年`;
      } 
      if (type === 'month') {
        return `${value}月`;
      }
      return `${value}日`;
    },
  },

  /**
   * 组件的方法列表
   */
  methods: {
    onInput(event) {
      // console.log(event);
      var time = event.detail
      var date = new Date(time)
      // console.log(date);
      let year = date.getFullYear()
      let month = date.getMonth() + 1
      let day = date.getDate()
      console.log(year, month, day);
      if (month >= 1 && month <= 9) { month = `0${month}` }
      if (day >= 1 && day <= 9) { day = `0${day}` }
      this.currentDate = `${year}${month}${day}日`
      this.setData({
        currentDate: event.detail,
      });
    },
    hideDialog(){
      this.setData({
        isShow: false
      })
    },
    //展示弹框
    showDialog(){
      this.setData({
        isShow: true
      })
    },
    _cancelEventDate() {
      this.triggerEvent("cancelEvent")
    },
    _confirmEventDate() {
      this.triggerEvent("confirmEvent");
      this.triggerEvent("dateEvent", this.currentDate);
      console.log(this.currentDate, '---------');
    }
  }

源码

本项目源码

结语

  • 如果你觉得看完对你有些许帮助,就不妨点个👍吧!如果文章有哪里不对的地方,欢迎指正交流。

image.gif