Вы купили Ми 8? Не волнуйтесь, просто запустите небольшую программу 😎

внешний интерфейс Апплет WeChat WeUI


предисловие

С момента выпуска мини-программы она становится все более и более популярной благодаря своим многочисленным преимуществам, таким как отсутствие установки, уход после использования, легкий доступ, отсутствие регистрации, входа в систему и социального деления. мобильного приложения Стоимость разработки также соответствует привычке пользователя использовать приложение. Мини-программы так привлекательны, как программист, почему бы мне не сделать их самому? Без лишних слов, давайте засучим рукава и просто сделаем это.

Готов к работе

Введение в проект: реальный бой в торговом центре Xiaomi

Структура каталогов проекта

├── 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                 项目公共设置

Отображение и реализация функций

1. Домашняя страница торгового центра

Анализ структуры страницы:

  • верхняя панель поиска Здесь это выглядит как окно поиска, но на самом деле то, чего он хочет добиться, — это просто функция перехода на страницу, если ееdisabledУстановить какtrueВот и все. Кроме того, если вы хотите, чтобы заполнитель-заполнитель отображался в центре, апплет WeChat предоставляетplaceholder-classсвойство, с помощью которого вы можете изменить стиль заполнителя.

  • Карусельная зона Здесь апплет WeChat предоставляет нам компонент swiper, который можно использовать напрямую. Тем не менее, карусельное изображение может существовать на каждой странице, но изображения, отображаемые в нем, разные, поэтому используйте идею компонентизации и запишите его в виде шаблона, где бы вы ни захотели его использовать, вы можете импортировать этот шаблон.

<template name="slide">
    <view class="section section-swiper">
		<swiper class="slide" indicator-dots="{{true}}" autoplay="{{true}}" interval="2000" duration="1000">
			<block wx:for="{{slides}}" wx:key="{{index}}">
				<swiper-item>
					<image src="{{item.slide_url}}" mode="widthFix" class="slide-image" data-id="{{item.id}}" />
				</swiper-item>
			</block>
		</swiper>
	</view>
</template>

При использовании импортируйте так

<import src="../../../templates/slide/slide.wxml" />
<view class="container">
    <template is="slide" data="{{slides}}"></template>
</view>
  • Зона навигации торгового центра, зона активности Это просто макет, поэтому я не буду вдаваться в подробности. Но следует отметить, что в апплете WeChat настоятельно рекомендуется использоватьГибкая компоновка
  • Главная Зона отображения продуктов Продукты здесь отображаются в блоках, которые очень регулярны, поэтому всю витрину продукта можно использовать напрямую.wx:forТраверс. wxml:
<!-- 首页商品版块 -->
	<view class="section block">
		<block wx:for="{{index_block}}" wx:key="{{item.id}}">
			<view class="section cover">
				<image class="cover-img" src="{{item.img_url}}" data-cid="{{item.id}}" bindtap="showcDetail"/>
			</view>
			<view class="section goods-list">
				<block wx:for="{{item.section}}" wx:key="index" wx:for-item="product">
					<view class="goods-item">
						<image class="goods-img {{product.is_new?'new':''}} {{product.on_sale?'on-sale':''}}" src="{{product.goods_cover}}" data-pid="{{product.id}}" mode="aspectFill" bindtap="showDetail"/>
						<text class="title">{{product.header}}</text>
						<text class="desp">{{product.description}}</text>
						<text class="meta">{{product.meta}}</text>
						<text class="discount">{{product.discount}}</text>
					</view>
				</block>
			</view>
		</block>
	</view><!-- end-section block -->

Вот такая деталь: товары в каждом разделе будут разделены на три категории: «новинки», «моментальные скидки» (то есть со скидками) и «без скидок». Как это сделать? Здесь я использую хитрый метод: дать каждому продуктуclassпривязать логическое значениеis_newиon_saleИспользуйте тернарный оператор, чтобы определить, нужно ли прикреплять имя класса к продукту, а затем используйтепсевдоэлементПометьте этот товар как «Новинка» или «Мгновенная скидка» следующим образом:

wxml:

<image class="goods-img {{product.is_new?'new':''}} {{product.on_sale?'on-sale':''}}" src="{{product.goods_cover}}" data-pid="{{product.id}}" mode="aspectFill" bindtap="showDetail"/>

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 showDetail from "../../modules/showDetail";

2. Страница классификации продуктов

Анализ структуры страницы: Страница классификации продуктов разделена на меню классификации продуктов слева и область отображения классификации продуктов справа. использовать дваscroll-viewВот и все, ставим и влево и вправоscroll-yзаставить их прокручиваться вертикально, кроме того,scroll-viewесть еще одинscroll-into-viewсвойства позволяют нам добиться чего-то вродеaЯкорная функция тега,scroll-into-viewЗначением является идентификатор некоторого дочернего элемента, ноЗдесь есть небольшая дырочка,Идентификатор не может начинаться с цифры
В то время я проверил документ и запустил его, поэтому я взял несколько цифровых идентификаторов для левого меню.Сейчас думаю об этом, я был слишком самодостаточен в то время.Кроме того, если будет слишком много контента, будет сгенерирована полоса прокрутки, как показано на рисунке:

Тоже так некрасиво выглядит. .

**Решение. Добавьте следующий стиль в глобальный стиль.

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

Мммм, красиво! !

Функция классификации продуктов

Логический анализ: зарегистрируйте curIndex (индекс текущего выбранного меню) для страницы.Если текущий индекс совпадает с выбранным индексом меню, он активен Часть кода: wxml:

<view class="main">
    <scroll-view scroll-y class="category-left">
        <view class="cate-nav-list" wx:for="{{cate_nav_list}}" wx:key="{{item.id}}" data-id="{{item.id}}" data-index="{{index}}"
            bindtap="switchCategory">
            <text class="cate-name {{curIndex===index?'on':''}}">{{item.name}}</text>
        </view>
    </scroll-view>
    <scroll-view class="category-right" scroll-y="{{true}}" scroll-into-view="{{toView}}" scroll-with-animation="true">
        <view class="cate-content">
            <view class="cate-list-content" wx:for="{{detail}}" wx:key="{{item.id}}" id="{{item.id}}">
                <view class="banner">
                    <image src="{{item.banner}}"/>
                </view>
                <view class="header">{{item.cate_name}}</view>
                <view class="cate-list">
                    <view class="cate-item"  wx:for="{{item.cate_list}}" wx:key="{{index}}" wx:for-item="cateList">
                        <image src="{{cateList.item_img}}" />
                        <text>{{cateList.item_name}}</text>
                    </view>
                </view>
            </view>
            
        </view>
    </scroll-view>
</view>

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
    });
  }
})

3. Страница обнаружения

Анализ структуры страницы:

На нем показаны некоторые рекламные видеоролики о продукте (в то время я не хотел вырезать слишком много страниц), и я могу сделать это здесь с помощью гибкого макета + видеокомпонента.вот документация

4. Страница сведений о продукте

Анализ структуры страницы: Верхняя часть деталей товара состоит из вайпера, а средняя часть состоит из нескольких ячеек (weui)Нажмите здесь для быстрого просмотрадноОбзор продукта и конфигурация параметровОн состоит из двух частей. Это относительно просто. Привяжите логическое значение к каждому из двух элементов, чтобы контролировать, кто показывает, а кто скрывает.

Конечно, чтобы использовать weui, мы должны импортировать его файл стилей, мы импортируем его в app.wxss, и тогда его можно будет использовать глобально.

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

Ну, официальный сайт weui и адрес на github естественно незаменимы.официальный сайт вуи,официальная документация weui github, чтение кода на github — очень эффективный способ обучения, но найти файл непросто, если папка слишком глубоко вложена, вотАртефакт чтения GitHub

Веуи использовал: Пожалуйста, позвольте мне вставить структуру, скопированную с weui

<view class="weui-cells">
    <view class="weui-cell">
        <view class="weui-cell__bd">
            <view class="title">{{goods.header}}</view>
            <view class="desp">{{goods.description}}</view>
            <view class="meta">{{goods.meta}}</view>
        </view>
    </view>
</view>

Отображение страницы сведений о продукте

логический анализ: Каждый товар переходит на соответствующую страницу сведений через id, но где будет id?Потому что страница сведений открывается одна за другой, поэтому при загрузке страницы сведений о товаре можно получить текущее открытие в onLoad.Параметр запроса вызывается страницей (это часть данных json), потому что для перехода в showDetail используется только идентификатор, поэтому параметры имеют только атрибут 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是唯一的,所以上面筛选出来的数组只有一条数据,这条数据就是要显示的商品数据
    });
  }

Реализация предварительного просмотра изображения продукта

Апплет WeChat предоставляет нам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
	})
  }

Пять, выбор атрибута продукта

Структура страницы: структура всей страницы атрибутов продукта состоит из нескольких ячеек, поэтому наиболее подходящим является weui (вставьте абзац: родное радио действительно уродливое, но weui улучшил его) В начале намного проще иметь weui, просто используйте форму напрямуюbindsubmitС этим можно справиться, но с помощью bindsubmit в weui значение радио не получить.После долгого метания его все равно не получить, но можно получить заменой на родное радио! !
Это не работает, тогда измените его, используйте weuiradiogroupвнутренний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
    });
  }

Перейти на страницу свойств соответствующего продукта

Логический анализ: на странице сведений о продукте перейдите по идентификатору текущего продукта.

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

На странице выбора атрибутов продукта информация о выборе атрибутов различных продуктов также отображается с помощью фильтрации идентификаторов.

onLoad: function (options) {
    const id = options.id;
    console.log(id);
    const goods_attrSelect = app.globalData.goodsDetail.filter(item => {
      return item.id == id;
    });
}

Связывание выбора атрибутов продукта

Поскольку это товар, как это можно сделать без выбора атрибута? Заинтересованы в том, чтобы писать, не говоря ни слова. Но здесь есть трудность: из-за разнообразия выбора пользователей, перечислите ли вы все варианты выбора, которые могут сделать пользователи? Боже, с таким количеством продуктов, неужели это меня утомит 😱? нет, нет, нет, этот метод не рекомендуется. Где еще есть решение? В то время я думал об использовании кеша данных.Ну, этот метод реализуем, но если вы используете кеш для доступа к выбранным пользователем значениям, здесь возникает большая проблема:Кэш данных в апплете WeChat хранит данные в ключе, указанном в локальном кеше, который перезапишет исходное содержимое, соответствующее ключу, будь то wx.setStorage (асинхронный интерфейс) или wx.setStorageSync (синхронный интерфейс)., в этом случае независимо от того, сколько элементов выберет пользователь, пока значение ключа одинаково, всегда будут только одни кэшированные данные! ! ! Мое сердце сейчас болит.

Есть ли способ сделать так, чтобы кеш данных не перезаписывал исходное значение, а добавлял его к нему? Честно говоря, я застрял здесь надолго. Не говорите ерунды, сразу переходите к коду

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 < 1) {
      return;
    }
    this.setData({
      select_num
    });
    wx.setStorageSync('select_num', select_num);
  },
  addCount(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);
  }

6. Работа с корзиной

Анализ структуры страницы: список корзины покупок может быть выполнен с гибким макетом. Панель действий внизу имеет фиксированное позиционирование + гибкую компоновку.

<view wx:if="{{cart_list==''}}">
    <view class="empty-cart">
        <view class="cart-icon">
            <image src="../../assets/icons/cart_empty.png" mode="aspectFill" />
        </view>
        <view class="prompt">购物车还是空的</view>
        <button type="warn" class="btn-warn" style="background: #ff6700;" bindtap="goIndex">到小米商城逛逛</button>
    </view>
</view>
<view wx:else>
    <view class="cart-box">
        <view class="cart-list" wx:for="{{cart_list}}" wx:key="{{index}}">
            <view class="cart-item {{item.isTouchMove? 'touch-move-active': ''}}" bindtouchstart="touchstart" bindtouchmove="touchmove" data-index="{{index}}">
                <view class="cart-content">
                    <icon type="{{item.selected?'success':'circle'}}" class="" color="#ff6700" size="20" bindtap="selectList" data-index="{{index}}"
                    />
                    <image src="{{item.cover}}"
                        mode="aspectFill" />
                    <text class="item-title">{{item.goods_name}} {{item.memory}}</text>
                    <text class="item-num">{{item.color}}</text>
                    <text class="item-price">{{item.select_num}}×</text>
                    <text class="item-price">{{item.price}}</text>
                    <view class="del-cart-item" catchtap="delCartItem">删除</view>
                </view>
            </view>
        </view>
    </view>
    <view class="user-operation">
        <view class="select-all">
            <icon wx:if="{{selectAllStatus}}" type="success" class="total-select" color="#ff6700" bindtap="selectAll" />
            <icon wx:else type="circle" class="total-select" color="#ff6700" size="20" bindtap="selectAll" />
            <text>全选</text>
        </view>
        <view class="total-price">合计:
            <text>{{totalPrice}}元</text>
        </view>
        <view class="btn-primary pay" bindtap="checkOut">结算</view>
    </view>
</view>

Стиль нижней панели действий

.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 < cart_list.length; i++) {
      if (cart_list[i].selected) {
        totalPrice += parseInt(cart_list[i].select_num) * parseInt(cart_list[i].price);  //注意这里要用parseInt()把数量和价格取出来
      }
    }
    //更新总价
    this.setData({
      totalPrice
    });
  },
  selectAll(e) {
    let selectAllStatus = this.data.selectAllStatus;
    selectAllStatus = !selectAllStatus;
    let cart_list = this.data.cart_list;
    for (let i = 0; i < cart_list.length; i++) {
      cart_list[i].selected = selectAllStatus; //全选为true,则所有购物车列表为true,全选为false,则所有购物车列表为false
    }
    //更新数据
    this.setData({
      cart_list,
      selectAllStatus
    });
    this.getTotalPrice();
  }

удалить действие корзины

data: {
    startX: 0, //开始坐标
    startY: 0,
  },
//滑动事件处理
  touchmove(e) {
    let
      index = e.currentTarget.dataset.index, //获取当前索引
      startX = this.data.startX, //获取开始X坐标
      startY = this.data.startY, //获取开始Y坐标
      touchMoveX = e.changedTouches[0].clientX, //滑动变化坐标
      touchMoveY = e.changedTouches[0].clientY, //滑动变化坐标
      //获取滑动角度
      angle = this.getAngle({
        X: startX,
        Y: startY
      }, {
        X: touchMoveX,
        Y: touchMoveY
      });
    this.data.cart_list.forEach(function (v, i) {
      v.isTouchMove = false
      
      if (Math.abs(angle) > 30) return;//用户滑动超过30度,删除按钮就不出来 
      if (i == index) {
        if (touchMoveX > 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
    });
  }

7. Сопоставление товаров и реализация функции поиска

Анализ структуры страницы: сначала закрепите поле поиска в нижней части панели поиска, если продукт ищется, используйте шаблон отображения продукта для вывода данных.

<import src="../../templates/goods_list/goods_list.wxml" />
<view class="weui-search-bar">
    <view class="weui-search-bar__form">
        <view class="weui-search-bar__box">
            <icon class="weui-icon-search_in-box" type="search" size="14"></icon>
            <input type="text" class="weui-search-bar__input" placeholder="搜索" placeholder-class="plac" bindinput="searchInput" />
        </view>
    </view>
    <view class="weui-search-bar__cancel-btn" bindtap="search">搜索</view>
</view>
<view class="search-list {{is_hidden?'hidden':''}}">
    <block wx:for="{{search_list}}" wx:key="{{item.id}}">
        <text class="search-item" bindtap="showItemDetail" data-header="{{item.header}}">{{item.header}}</text>
    </block>
</view>
<template is="goods_list" data="{{goods_list}}"></template>

логический анализ: Моя идея реализации такова:

  • Если продукт соответствует, окно поиска должно отображаться под окном поиска;
  • Когда содержимое поиска, введенное пользователем, пусто, окно запроса поиска скрыто.
  • Когда пользователь нажимает кнопку поиска, отображается список всех подходящих продуктов.нечеткий поиск,нечувствительный к регистру, чтобы улучшить пользовательский опыт;
  • Когда пользователь нажимает на соответствующую запись продукта, продукт ищется

Выполнение:

  • 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;
    });
  }
})

8. Страница адреса доставки

Идея реализации: используйте кеш данных и привязку данных для управления отключением ввода, чтобы реализовать редактирование в реальном времени. код показывает, как показано ниже:

// pages/address/address.js
Page({
  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, и изучу новые технологии 😄

Наконец:

Кодить непросто, если вам это нравится, простоstarНу давай же,адрес проекта, буду обновлять время от времени. В проекте еще много недочетов, надеюсь каждый сможет внести ценные предложения 🐵