微信小程序实战(仿小米商城)

您所在的位置:网站首页 仿小米商城项目实战是真的吗还是假的 微信小程序实战(仿小米商城)

微信小程序实战(仿小米商城)

2024-07-16 08:01:35| 来源: 网络整理| 查看: 265

微信小程序,让你一见倾心

image

前言

小程序发布以来,凭借无需安装、用完即走、触手可及、无需注册、无需登录、以及社交裂变等多个优势,一路高歌,变得愈来愈火爆,它革命性的降低了移动应用的开发成本,也正好迎合了用户的使用应用的习惯。小程序魅力如此之大,作为一枚程序猿,我想怎么不自己做一个呢?话不多说,咱撸起袖子就是干

准备工作

前端开发利器:VSCode

调试:微信开发者工具

自己Mock的一些数据

微信开发文档

项目目录结构├── assets                   用到的一些图标文件 ├── lib     ├── weui.wxss            引用了weui├── modules                         ├── showDetail.js        跳转展示商品详情的公共js文件       ├── showcDetail.js      ├── pages                    项目的各个页面     ├── index                商城首页     ├── categories           商品分类页     ├── discovery            发现页     ├── channel              商品频道目录         ├── phone            手机频道         ├── tv               电视频道         ├── computer         电脑频道     ├── cart                 购物车     ├── mine                 个人信息页     ├── goods                商品详情页     ├── selectGoods          商品属性选择页     ├── search               商品搜索页     ├── addr                 收货地址页 ├── template                 使用到的模版文件                    ├── slide                轮播图模版       ├── goods_list           商品展示模版     ├── cover                商品展示模版 ├── util                     使用到的工具类                    ├── mock.js              项目中使用到的一些数据   ├── app.js                   项目逻辑 ├── app.wxss                 项目公共样式表 └── app.json                 项目公共设置功能的展示与实现一、商城首页

image

页面结构分析:

顶部搜索条这里看上去是一个搜索框,但其实,它要实现的仅仅是个页面跳转功能,只要把它的disabled设置为true就可以了,另外要想让它placeholder占位符居中显示的话,微信小程序提供了一个placeholder-class的属性,通过它可以改变placeholder的样式。

轮播图区域这里微信小程序给我们提供了swiper组件,直接用就可以了。但是轮播图在各个页面都可能存在,只是其中所显示的图片不一样而已,所以使用组件化思想,把它写成一个模版,哪里要使用,就引入这个模版即可。

                                                                                                            

使用时,这样引入

    

商城导航区、活动区这里只是个简单的布局,就不赘述了。但是需要注意的是在微信小程序里,强烈推荐使用弹性布局

首页商品展示区这里的商品都是分块展示,很有规律,因此整个商品展示都可以直接用wx:for遍历出来。wxml:

                                                                                                                                                             {{product.header}}                         {{product.description}}                         {{product.meta}}                         {{product.discount}}                                                                 

这里有个细节,每个版块里的商品会分成“新品”、“立减”(即有折扣)、“无折扣”三种,着该怎么去做呢?这里我用了一个巧妙的方法:给每个商品的class里绑定布尔值is_new和on_sale通过三元运算符判断是否给该商品挂载一个类名,再使用伪元素给该商品打上“新品”或“立减”的标签如下:

wxml:

wxss

.goods-img.new:before{      /*新品标签样式*/   position: absolute;  left: 0;  top: 0;  width: 100rpx;  height: 40rpx;  line-height: 40rpx;  content: "新品";  color: #fff;  font-size: 9pt;  text-align: center;  background: #8CC64A; }.goods-img.on-sale:before{   /*立减标签样式*/   position: absolute;  left: 0;  top: 0;  width: 100rpx;  height: 40rpx;  line-height: 40rpx;  content: "立减";  font-size: 9pt;  color: #fff;  text-align: center;  background: #ec6055; }

逻辑分析:首页只是些商品,所以逻辑层只要根据每个商品的id来跳到对应商品的详情页即可,很显然这个方法在多个页面都要使用的,所以使用模块化思想,创建一个modules文件夹,把方法写在单独的js文件里,并向外输出

const showDetail=(e)=>{    const id=e.currentTarget.dataset.pid; //获取每个商品的id     wx.navigateTo({        url: `/pages/goods/show?id=${id}`     }) };export default showDetail;

哪里要使用,就用import引入

import showDetail from "../../modules/showDetail";二、商品分类页

image

页面结构分析:商品分类页分为左侧的商品分类菜单和右边的商品分类展示区,用两个scroll-view就可以了,左右两边都设置scroll-y让它们垂直方向滚动,此外,scroll-view还有一个scroll-into-view属性能让我们实现类似a标签的锚点功能,scroll-into-view的值是某个子元素的id,但是此处有一个小坑,这个id不能以数字开头

image

当时查了一下文档就开做了,于是乎给左侧菜单取了些数字id,现在想起来当时我太自以为然了 ,此外如果内容太多,是会产生滚动条的,如图:

image

这样看起来也太丑了。。

**解决办法:给全局样式加入下面的样式

//隐藏滚动条::-webkit-scrollbar{     height: 0;  width: 0;  color: transparent; }

嗯,beautiful !!

商品分类功能

逻辑分析:给页面注册个curIndex(当前选中菜单的下标),如果当前下标和选中的菜单下标相同,则处于激活状态部分代码:wxml:

                          {{item.name}}                                                                                                                 {{item.cate_name}}                                                                                        {{cateList.item_name}}                                                                              

js:

const app=getApp(); Page({  /**    * 页面的初始数据    */   data: {     cate_nav_list:[       {name:"新品",id:"new"},       {name:"手机",id:"phone"},       {name:"电视",id:"tv"},       {name:"电脑",id:"laptop"},       {name:"家电",id:"appliance"},       {name:"路由",id:"router"},       {name:"智能",id:"smart"},       {name:"儿童",id:"kids"},       {name:"灯具",id:"lignts"},       {name:"电源",id:"adapter"},       {name:"耳机",id:"headset"},       {name:"音箱",id:"voicebox"},       {name:"生活",id:"life"},       {name:"服务",id:"service"},       {name:"米粉卡",id:"card"}     ],     curIndex:0,  //初始化当前下标为0     toView:"new", //默认显示“新品展示”     detail:[]   },   switchCategory(e){    const curIndex=e.currentTarget.dataset.index?e.currentTarget.dataset.index:0;  //获取每个菜单的id     //更新数据     this.setData({       toView:e.currentTarget.dataset.id,       curIndex     });   },   onLoad: function (options) {    const detail=app.globalData.category; //获取分类展示数据     this.setData({       detail     });   } })三、发现页

页面结构分析:

image

里面展示了一些商品宣传视频(当时还是不太想切太多的页面)这里用弹性布局+video组件就搞定了。这里是文档

四、商品详情页

image

页面结构分析:商品详情顶部由一个swiper组成,中间部分由一些cells组成(weui)点击这里快速查看底部是商品的概述及参数配置两部分组成,这个还是比较简单的, 给两个元素分别绑定一个布尔值来控制谁显示谁隐藏。

当然,要使用weui必须引入它的样式文件,我们在app.wxss里引入,然后全局都可以使用了

@import "./lib/weui.wxss";

嗯,weui的官网和github地址自然少不了。weui官网 、weui github官方文档,在github上阅读代码是一个非常有效的学习方式,但是文件夹嵌套太深找个文件也不容易,这里奉上github阅读神器

使用到的weui:请容许我贴一段weui抄来的结构

                          {{goods.header}}             {{goods.description}}             {{goods.meta}}              商品详情页的显示

逻辑分析:每个商品通过id来跳转到相应的详情页,但是这个id会在哪里呢因为先这个详情页是通过一个个商品来打开的,所以在商品详情页加载时,可以在 onLoad 中获取打开当前页面所调用的 query 参数(是条json数据),因为在showDetail里只用了id来跳转,所以options只有id属性

onLoad: function (options) {    console.log(options); //{id:"4"}     const id=options.id; //获取options里的id     const goods=app.globalData.goodsDetail.filter(item=>{      return item.id==id;  //通过id来筛选显示对应的商品     });    this.setData({      goods:goods[0] //因为id是唯一的,所以上面筛选出来的数组只有一条数据,这条数据就是要显示的商品数据     });   }商品图片预览实现

微信小程序为我们提供了wx.previewImage()方法来实现图片的预览,实现方法如下:

previewImage(e){    const index=e.currentTarget.dataset.index;  //获取swiper里的图片的下标     const slide=this.data.goods.goods_slides; //获取商品轮播图     const imgList=[]; //定义一个数组来存放轮播图的url     slide.map(item=>{         imgList.push(item.slide_url); //用js的map方法把图片的url地址取出来放到数组里     });     wx.previewImage({        current: imgList[index], // 当前显示图片的链接,不填则默认为 urls 的第一张         urls: imgList     })   }五、商品属性选择

image

页面结构:整个商品属性页的结构是由一些cells组成,所以用weui最合适(插一段:原生的radio真的是很丑,不过weui对它做了改进)一开始想有weui就简单多了,直接用form表单的bindsubmit处理就可以了,奈何在weui里使用bindsubmit,取不到radio的值,折腾了很久,还是取不到,但是换成原生的radio竟可以取到!!

image

这个不行,那就换一种吧,用weui radiogroup里的bindchange事件吧,虽然繁琐了些,但是还是能解决问题的。。话不多说,看代码(感觉写了一些很累赘的代码。。)

selectVersion(e) {    const version = e.detail.value;    const memory = version.split(",")[0];    const price = version.split(",")[1];     wx.setStorageSync('memory', memory);     wx.setStorageSync('price', price);    this.setData({       memory,       price     });   },   selectColor(e) {    let color = e.detail.value;    let cover_img=this.data.goods_attrSelect[0].goods_slides[0].slide_url;     wx.setStorageSync('color', color);     wx.setStorageSync('cover', cover_img);    this.setData({       color,       cover_img     });   },   colorHasSelected(e) {    const curcIndex = e.currentTarget.dataset.index ? e.currentTarget.dataset.index : 0;    console.log(curcIndex);    this.setData({       curcIndex     });   },   versionHasSelected(e) {    const curvIndex = e.currentTarget.dataset.index ? e.currentTarget.dataset.index : 0;    console.log(curvIndex);    this.setData({       curvIndex     });   }对应商品的属性页的跳转

逻辑分析:在商品详情页中,通过当前商品的id跳转

toSelect(e){    const id=e.currentTarget.dataset.id;     wx.navigateTo({       url:`../selectGoods/selectGoods?id=${id}`     });  }

在商品的属性选择页里,同样是通过id筛选显示不同商品的属性选择信息

onLoad: function (options) {    const id = options.id;    console.log(id);    const goods_attrSelect = app.globalData.goodsDetail.filter(item => {      return item.id == id;     }); }商品属性的联动选择

既然是商品,没有属性选择怎么行呢?兴致一来二话不说就是写。但是这里有一个难点:用户的选择多样性,难道你会把所有用户可能做出的选择都列出来吗?天哪,商品这么多,这是要累死我吗?no,no,no,这种方法不可取。哪还有什么解决办法呢?当时一想到的就是用数据缓存,嗯,这种方法可行,但是用缓存存取用户选择的值的话,这里有一个很大的问题:微信小程序里的数据缓存将data存储在本地缓存中指定的key中,会覆盖掉原来该key对应的内容,无论是wx.setStorage(异步接口)还是wx.setStorageSync(同步接口),这样的话,无论用户选择了多少个商品,只要key值一样,缓存数据永远只有一条!!!我此时的内心是痛苦的。

image

有什么方法能让数据缓存不覆盖原来的值,而是加上去?说实话,这里卡了我好久。废话不多说,直接上代码

submit(e) {    const pre_item = wx.getStorageSync('attr_item');    const temp = {      'goods_name': wx.getStorageSync('goods_name'),      'memory': wx.getStorageSync('memory'),      'price': wx.getStorageSync('price'),      'color': wx.getStorageSync('color'),      'select_num': wx.getStorageSync('select_num'),      'cover': wx.getStorageSync('cover'),      'selected': false,      'isTouchMove': false     }     wx.setStorageSync('attr_item', [temp, ...pre_item]); //把获取到的pre_item和temp的数据缓存存入attr_item     wx.showToast({      title: '已加入购物车',      icon: 'success',      duration: 3000,       success() {         setTimeout(() => {           wx.navigateBack({            url: "../goods/show"           });         }, 1000)       }     });   }商品数量的加减操作

实现思路:分别绑定一个事件来操作商品数量的加减,最后将用户选择的数量设置到数据缓存里。实现代码:

 data: {    select_num: 1  //默认选择为数量为1   }, minusCount(e) {    //用户减操作     let select_num = this.data.select_num;     select_num--;    if (select_num  5) {      return;     }    this.setData({       select_num     });     wx.setStorageSync('select_num', select_num);   }六、购物车操作

image

页面结构分析:购物车列表用一个弹性布局就搞定。底部的操作栏用固定定位 + 弹性布局就搞定。

                                            购物车还是空的         到小米商城逛逛                                                                                                                {{item.goods_name}} {{item.memory}}                     {{item.color}}                     {{item.select_num}}×                     {{item.price}}                     删除                                                                                                 全选                  合计:            {{totalPrice}}元                  结算     

底部操作栏样式

.user-operation{    width: 100%;    height: 100rpx;    line-height: 100rpx;    display: flex;    flex-direction: row;    justify-content: space-between;    align-items: center;    position: fixed;    left: 0;    bottom: 0; }.select-all,.total-price,.btn-primary.pay{    flex: 1;  //三个盒子等分所有设备宽度    font-size: 12pt;    text-align: center; }加入购物车操作

逻辑分析:之前解决数据缓存问题,是为加入购物车功能做铺垫。在商品属性的级联选择中,已经获得了用户的所有要加入购物车的数据,这时候,把数据取出来在绑定到购物车页面上就可以了。

实现代码:

data: {    cart_list: [],   //初始化一个空数组用来存放购物车列表   },   goIndex() {  //如果购物车为空,则让用户去首页     wx.switchTab({      url: "../index/index"     })  },onShow: function () {    const attr_item = wx.getStorageSync('attr_item'); //获取数据缓存里将要加入购物车的数据     let cart_list = this.data.cart_list;     cart_list = [...attr_item]; //把缓存里的数据加到购物车列表里     const select_num = cart_list.map(item => { //获取用户每次选择的数量       return item.select_num;     })    let goods_sum=select_num.reduce(function(prev,cur){       return prev+cur;  //用es6的reduce()方法把用户每次选择的数量相加     });     wx.setStorageSync('goods_sum', goods_sum);  //再次存入缓存     this.setData({   //更新购物车列表       cart_list     });   }购物车全选、反选、计算总价功能

这是一个很经典的问题,凡事涉及到购物车的操作,这个功能都是少不了的。

data: {    cart_list: [],    totalPrice: 0,   }, selectList(e) {    let selectAllStatus = this.data.selectAllStatus;    const index = e.currentTarget.dataset.index;    let cart_list = this.data.cart_list;    // console.log(cart_list[index].selected);     const selected = cart_list[index].selected;     cart_list[index].selected = !selected;    console.log(selected);    //购物车列表里的条目只要有一个取消,全选就取消     const symbol = cart_list.some(cart => {  //这里用es6的some()函数       return cart.selected === false;     });    if (symbol) {  //如果找到false,全选就取消       this.data.selectAllStatus = false;     } else {      this.data.selectAllStatus = true;     }    this.setData({  //更新数据       cart_list,      selectAllStatus: this.data.selectAllStatus     });    this.getTotalPrice();   },   getTotalPrice() {  //定义一个计算总价的方法     let cart_list = this.data.cart_list;    let totalPrice = 0;    for (let i = 0; i  startX) //右滑           v.isTouchMove = false         else //左滑           v.isTouchMove = true       }     })    //更新数据     this.setData({      cart_list: this.data.cart_list     })   },   getAngle(start, end) {    let X = end.X - start.X,       Y = end.Y - start.Y    //返回角度 /Math.atan()返回数字的反正切值     return 360 * Math.atan(Y / X) / (2 * Math.PI);   },   delCartItem(e) {    const index=e.currentTarget.dataset.index;  //获取购物车要删除商品的下标     this.data.cart_list.splice(index, 1);     wx.clearStorageSync("select_num");    this.setData({      cart_list: this.data.cart_list     });   }七、商品的匹配及搜索功能实现

image

页面结构分析:先把搜索提示框固定定位到搜索栏下方,如果搜索到商品,则用商品展示模版输出该数据

                                                          搜索              {{item.header}}     

逻辑分析:我的实现思路是:

如果匹配到商品,搜索框下方就要让搜索提示框显示;

当用户输入搜索的内容为空,搜索提示框隐藏

用户点击搜索按钮,则把所有匹配到的商品列表显示出来,注意要模糊搜索,不区分大小写,提高用户体验;

用户点击匹配到的商品条目,则搜索该商品

实现方法:

filter()+indexOf()+toLowerCase();

代码如下:

import showDetail from "../../modules/showDetail";const app=getApp(); Page({  /**    * 页面的初始数据    */   data: {    goods_list:[],    search_list:[],    is_hidden:true   },   searchInput(e){    let search_list=this.getList(e.detail.value); //获取用户的输入值     if(e.detail.value==""){ //如果用户没输入,搜索提示列表置空,并且让搜索提示框隐藏       search_list=[];        this.data.is_hidden=true;     }else{      this.data.is_hidden=false;     }      //更新数据     this.setData({       search_list,      is_hidden:this.data.is_hidden     });   },   search(e){     //按关键字筛选商品,如果关键字匹配到商品名称,则返回该商品列表     const keywords=wx.getStorageSync('keywords');     wx.showLoading({      title: '请稍等',     });     setTimeout(()=>{      this.setData({        goods_list:this.getList(keywords),        is_hidden:true  //如果搜索到了商品,就让搜索框隐藏       });       wx.hideLoading();     },500);   },   showDetail,   showItemDetail(e){    //按关键字筛选商品,如果关键字匹配到商品名称,则返回该商品列表       const header=e.currentTarget.dataset.header.toLowerCase();        console.log(header);       wx.showLoading({        title: '请稍等',       })       setTimeout(()=>{         wx.hideLoading()        this.setData({          goods_list:this.getList(header),          is_hidden:true         });       },500)   }, /**    * attr:需要匹配筛选的数据    */   getList(attr){  //定义一个获取商品标题的方法     return app.globalData.phone.goods_list.filter(item=>{      return item.header.toString().toLowerCase().indexOf(attr)>-1;     });   } })八、收货地址页

image

实现思路:用数据缓存和数据绑定来控制input的disabled实现实时编辑代码如下:

// pages/address/address.jsPage({  data: {    receiverName: "",    mobile: "",    addressDetail: "",    postCode: "",    isDisabled: false,    isComplete: false,    buttonTitle: "保存"   },   formSubmit(e) {    const addrInfo = e.detail.value;    let {receiverName,mobile,addressDetail,postCode}=addrInfo; //把data里的数据结构出来     if(receiverName==""||mobile==""||addressDetail==""||postCode==""){      this.data.isComplete=false;       wx.showModal({        title:"提示",        content:"请完善信息",        showCancel:false       });      }else if(!/^[1][3,4,5,7,8]\d{9}$/.test(mobile)){ //判断手机号格式       wx.showModal({        title:"提示",        content:"手机号格式不规范",        showCancel:false       });      }else if(!/^[0-9]{6}$/.test(postCode)){       wx.showModal({        title:"提示",        content:"邮政编码不规范",        showCancel:false       });      }else{      this.data.isComplete=true;       wx.setStorageSync('addrInfo', addrInfo);            }    this.setData({        isDisabled: true,        isComplete: this.data.isComplete       });   },   updateAddr(e){    this.setData({      isDisabled:false,      isComplete:false,      buttonTitle: "保存"     });   },  /**    * 生命周期函数--监听页面加载    */   onLoad: function (options) {         let addrInfo=wx.getStorageSync("addrInfo");    console.log(addrInfo);    let {receiverName,mobile,addressDetail,postCode}=addrInfo;    this.setData({       receiverName,       mobile,       addressDetail,       postCode,      isDisabled: true,      isComplete:true,      buttonTitle: "修改"     });   } })总结:

在做这个项目的时候遇到了很多问题,中途因为一个问题都要卡很久,但是现在想想,经历过肯定是能学到东西的,之前对于一些东西想都不敢想,但是没关系,只要你想做,那就去做吧,去网上查资料,多去社区问问大牛,你总是能学到东西的。对于这个项目,很多功能都还没完善,比如商品评论,生成订单等等,但是我会不定时的更新,有时间的话,我会用mpvue或者wepy改写,又能学到新技术

作者:云中玉卷链接:https://www.jianshu.com/p/906c95d6ccb4



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭