предисловие
С момента выпуска мини-программы она становится все более и более популярной благодаря своим многочисленным преимуществам, таким как отсутствие установки, уход после использования, легкий доступ, отсутствие регистрации, входа в систему и социального деления. мобильного приложения Стоимость разработки также соответствует привычке пользователя использовать приложение. Мини-программы так привлекательны, как программист, почему бы мне не сделать их самому? Без лишних слов, давайте засучим рукава и просто сделаем это.
Готов к работе
- Инструменты фронтенд-разработки:VSCode
- отладка:Инструменты разработчика WeChat
- Некоторые данные собственного Mock
- Документация по разработке WeChat
Введение в проект: реальный бой в торговом центре 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Ну давай же,адрес проекта, буду обновлять время от времени. В проекте еще много недочетов, надеюсь каждый сможет внести ценные предложения 🐵