Некоторое время назад, когда во многих местах по всей стране появились новости о том, что Ма Хуатенг использует мини-программы WeChat для проезда на автобусах, популярность мини-программ WeChat возросла. С момента появления мини-программ WeChat тенденция развития была хорошей из-за преимуществ простоты использования без загрузки.
Появление Hema Xiansheng также полно энтузиазма, реализуя быструю доставку, которую можно охарактеризовать как новый формат розничной торговли, который Alibaba полностью реконструировала для офлайн-супермаркетов.
Две столь удобные вещи столкнутся, что произойдет?
Недавно мне довелось изучить апплет WeChat, поэтому я адаптировал апплет WeChat в соответствии с приложением Hema Xiansheng.
В конце статьи есть исходный адрес GitHub, и я продолжу обновлять и улучшать этот апплет в будущем. Если вас также интересует этот апплет WeChat, добро пожаловать на общение и совместное обучение.
Введение в функцию
На основе концепции удобства реализованы основные функции приложения торгового центра.
- Пользователи могут нажимать на разные категории продуктов и переходить на страницу, чтобы увидеть список различных продуктов.
- Нажмите на продукт, чтобы добавить его в корзину, а в корзине вы также можете добавить или уменьшить количество продукта, выбрать все продукты и удалить продукты в корзине.
- На главной странице нажмите кнопку в верхнем левом углу, чтобы добавить адрес доставки по умолчанию.
- Нажмите на иконку сканирования в правом верхнем углу, а также можете отсканировать QR-код (гифка ниже - это эффект симулятора, вы можете открыть картинку только в компьютере для сканирования, а реальная машина может открыть камеру для сканирование).
- Верхняя часть домашней страницы реализует поворот изображения и автоматическое переключение, а нижняя часть реализует прокрутку, которая может скользить по горизонтали для отображения информации о продукте. Давайте сначала взглянем на визуализацию, а затем подробно рассмотрим реализацию каждого пункта.
Страница Введение
Здесь представлена основная информация об интерфейсе апплета, а также несколько переходов по страницам и информация о списке продуктов. Обратите внимание на карусель изображений в верхней части главной страницы и горизонтальную прокрутку внизу.
О работе корзины
Добавить товар в корзину.
Увеличение или уменьшение количества товаров в корзине.Выберите или отмените выбор всех товаров в корзине.Удалить товары из корзины.Добавьте адрес доставки по умолчанию и отсканируйте QR-код.
Новый адрес доставки.
Отсканируйте QR-код (это проверяется симулятором, для сканирования можно добавлять только локальные картинки, реальная машина может открывать камеру и сканировать)Далее идет введение метода реализации.
Подробные функции для достижения
Карусель изображений на главной странице и прокрутка снизу
Апплет WeChat поставляется со своим собственным компонентом, swiper контейнера представления слайдера, который может реализовывать представления слайдера, и каждое представление помещается в элемент swiper. Установите параметр auto:play для автоматического воспроизведения и смены свайпера.
<swiper class="page__bd__scroll" current='{{activeIndex}}' bindchange='swiperTab' autoplay="true" interval="2000" duration="1000">
// interval是自动切换时间间隔,duration是滑动动画时长
// 每一个swiper-item就是一个视图
<swiper-item>
<image class="page__scroll__item" src=""/>
</swiper-item>
<swiper-item>
<image class="page__scroll__item" src=""/>
</swiper-item>
<swiper-item>
<image class="page__scroll__item" src=""/>
</swiper-item>
<swiper-item>
<image class="page__scroll__item" src=""/>
</swiper-item>
<swiper-item>
<image class="page__scroll__item" src=""/>
</swiper-item>
</swiper>
Реализация горизонтальной прокрутки:
Собственный компонент Wechat, scroll-view, может прокручивать область просмотра.Установив имя свойства scroll-x или scroll-y, представление можно прокручивать по горизонтали или вертикали.
// 属性名scroll-x定义了该视图允许横向滚动
<scroll-view scroll-x class="scrollx-section__content">
// 利用循环从后台获取数据,在视图中有多个view,也就是在页面中能看到的多个商品展示。
<block wx:for="{{scrollXList}}" wx:key="index" wx:for-index="index">
<view class="scrollx-section__content__item">
<view class="scrollx-section__item__wrapper">
<view class="view__wrapper__image">
<image src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/12/15/16057cf8f3865280~tplv-t2oaga2asx-image.image" />
</view>
<view class="view__wrapper__intro">
<view class="wrapper__intro__title">
<text>{{item.name}}</text>
<text>{{item.secName}}</text>
</view>
<view class="wrapper__intro__content left">
<text>{{item.leftTitle}}</text>
<text>{{item.leftSecTitle}}</text>
</view>
<view class="wrapper__intro__content right">
<text>{{item.rightTitle}}</text>
<text>{{item.rightSecTitle}}</text>
</view>
<view class="wrapper__intro__price">
<a>¥{{item.price}}</a><a>/{{item.unit}}</a><a id="{{index}}" bindtap="addInCart">+</a>
</view>
</view>
</view>
</view>
</block>
</scroll-view>
О работе корзины
Добавить товар в корзину
На разных страницах вы можете переходить на разные страницы, чтобы ввести список продуктов в соответствии с информацией о классификации.Например, вы можете ввести разные списки продуктов в соответствии с информацией о классификации на главной странице и странице классификации, а также добавить продукты в список покупок. тележка. Если вы хотите получить информацию о списке корзины покупок на главной странице, в интерфейсе классификации продуктов и в нескольких интерфейсах корзины покупок, объем данных одной страницы находится только в этой папке.Что делать, если вы хотите, чтобы несколько страниц работали вместе на одних и тех же данных?
Для данных, которые передаются на нескольких страницах, мы можем установить глобальную переменную в app.js, а затем ввести эти глобальные данные на каждую страницу, чтобы несколько страниц могли совместно использовать одни данные.
// app.js中的全局变量
globalData: {
cardList: [],
goodsSortsChoice: null // 用来标记首页商品分类 用户点击了哪个分类,进而显示不一样的商品列表
}
Здесь я устанавливаю две глобальные переменные. cardList — это данные корзины покупок. Пользователь щелкает элемент, чтобы добавить его в корзину, чтобы добавить элемент в массив. goodsSortsChoice — это токен. На домашней странице и в интерфейсе классификации есть различные вводные сведения о классификации.Этот тег может запоминать, какую категорию пользователь щелкнул в интерфейсе классификации, а затем переходить к интерфейсу отображения продукта, чтобы отображать различную информацию в зависимости от щелчка пользователя.
В интерфейсе списка товаров добавлено событие клика addCount для опции добавления в корзину для каждого товара, при этом, чтобы определить, какой товар кликнул пользователь, к каждому товару нужно добавить индекс. Метод заключается в динамическом связывании data-index="index" для каждого цикла при выводе данных списка продуктов в фоновом режиме, а затем установке id="{{index}}" для каждого "+", чтобы сделать оценку щелчка.
<block wx:for="{{goods}}" wx:key="index" wx:for-index="index">
<view class="weui-cells">
<view class="weui-cell">
<view class="weui-cell__hd">
<image src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/12/15/16057cf8f3865280~tplv-t2oaga2asx-image.image" />
</view>
<view class="weui-cell__bd">
<view class="goodsList__bd__intro">{{item.name}}</view>
<view class="view__bd__price">
<text class="price left">¥{{item.price}}/{{item.unit}}</text>
<text class="add right" bindtap="addInCart" id="{{index}}">+</text>
</view>
</view>
</view>
</view>
</block>
Часть js заключается в реализации метода addInCart для добавления товаров в корзину. Здесь, прежде чем добавить продукт в корзину, необходимо просмотреть существующий массив корзины для суждения.Если продукт уже находится в корзине, количество продукта в корзине напрямую увеличивается на единицу, в противном случае продукт напрямую добавляется в глобальный массив shopping.car.
addInCart: function(e) {
const good = this.data.goods[e.currentTarget.id]; // 根据index,判断用户点击了哪个商品加入购物车
const cart = app.globalData.cardList; // 获取购物车列表
// 设置一个标记,判断用户想加入购物车的商品是否已经存在购物车了
var flag = false;
// some 是es6新增的方法,用于遍历整个数组,如果数组中存在一个及以上元素,就返回true
flag = cart.some((item) => {
return item === good;
})
console.log(flag);
// 如果购物车中没有该元素,就将该商品加入购物车,否则就将该商品的购买数量加一
if(!flag) {
cart.push(good); // 用户选择商品加入购物车后,将该商品加入购物车列表
wx.showToast({
title: '商品已加入购物车',
icon: 'success',
duration: 2000
})
} else {
// 商品已经存在购物车,直接将购买数量加一
this.data.goods[e.currentTarget.id].count ++;
}
},
wx.showToast — это API, поставляемый с WeChat, который может отображать всплывающее окно на странице.
Увеличить или уменьшить количество покупок товаров в корзине
Идея увеличения или уменьшения количества купленных товаров состоит в том, чтобы привязать два события клика addCount и reduceCount соответственно к знакам плюс и минус, а при зацикливании товаров в списке корзины добавить к плюсу и минусу индекс index. знаки минус, чтобы определить, где пользователь щелкнул элемент.
<block wx:for="{{goodsList}}" wx:key="index" data-index="index">
<view class="weui-cell">
<view class="weui-cell__hd">
<icon id="{{index}}" bindtap="selectGoods" type="{{item.type}}" color="#23a3ff"></icon>
</view>
<view class="weui-cell__bd">
<image src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/12/15/16057cf8f3865280~tplv-t2oaga2asx-image.image" />
</view>
<view class="weui-cell__ft right">
<text class="proIntr left">{{item.name}}</text>
<text class="price left">¥{{item.price}}/{{item.unit}}</text>
<view class="count">
<text class="reduce left" bindtap="reduceCount" id="{{index}}">-</text>
<text class="number left">{{item.count}}</text>
<text class="add left" bindtap="addCount" id="{{index}}">+</text>
</view>
</view>
</view>
</block>
js-часть:
// 增加商品数量
addCount:function (e) {
var that = this;
// 根据点击事件获取用户点击了哪一件商品
const goodId = e.currentTarget.id;
that.data.goodsList[goodId].count++;
this.setData({
goodsList: that.data.goodsList
})
// 每一次增减商品数量都要重新计算购物车总钱数
this.sumMoney();
},
// 减少商品数量
reduceCount: function(e) {
var that = this;
const goodId = e.currentTarget.id;
if(that.data.goodsList[goodId].count <= 1) {
that.data.goodsList[goodId].count = 1;
wx.showModal({
title: '数量小于1',
content: '不允许操作',
duration: 2000
})
} else {
that.data.goodsList[goodId].count--;
}
this.setData({
goodsList: that.data.goodsList
})
// 每一次增减商品数量都要重新计算购物车总钱数
this.sumMoney();
},
Расчет общей стоимости корзины
Для выбранного предмета вызовите sumMoney(), чтобы рассчитать общую стоимость. Метод заключается в том, чтобы пройтись по товарам в корзине, получить цену за единицу и количество каждого товара, умножить их и сложить вместе.
// 计算所有商品的钱数
sumMoney: function() {
// count用于记录每件商品的购买数量
var count = 0;
// goods是购物车中的商品,对其进行遍历,计算价格
const goods = this.data.goodsList;
for(let i = 0; i < goods.length; i++) {
count += goods[i].count*goods[i].price;
}
this.setData({
sum: count
})
},
Выбор продукта и инверсия
Когда выбранные и невыбранные продукты отображаются в списке, наиболее важным отличием является то, предшествует ли столбец продукта маленькая синяя галочка или пустая точка.
Поэтому необходимо установить состояние товаров в корзине и изменить стиль интерфейса. Для этого значения состояния необходимо иметь это состояние перед загрузкой интерфейса корзины покупок, поэтому сначала я хочу добавить значение состояния для каждого элемента в фоновых данных. Однако у этого есть большой недостаток, для этого значения состояния он нужен только интерфейсу корзины, а для других интерфейсов он избыточен, добавление еще одного данных в фон означает изменение всех данных о продукте в фоновом режиме, что увеличивает сложность реализации. . Позже я придумал другой способ. Прежде чем загружать интерфейс корзины покупок, сначала перейдите в корзину и добавьте атрибут type="success" к каждой корзине покупок (прелесть настройки параметра type: имена классов Success и Circle являются значением состояния значка компонента WeChat, который может отображать галочку или пустую точку). Метод загрузки корзины покупок просматривает элементы в корзине и добавляет тип статуса:
onLoad: function (options) {
const cardList = app.globalData.cardList;
cardList.map(item => {
item.type = "success";
});
},
Часть отображения внешнего интерфейса:
<icon id="{{index}}" bindtap="selectGoods" type="{{item.type}}" color="#23a3ff"></icon>
Таким образом реализуется метод динамического изменения состояния товара. Мы можем создать метод, который просматривает элементы в корзине и, если все они выбраны, проверяет выбранный вариант.
// 用来判断是否全选
allSelected: function() {
const goods = this.data.goodsList;
// some是es6新增的方法,如果数组中至少有一个符合条件的,就会返回true
var symbol = goods.some(good => {
return good.type === "circle"
})
// 经过symbol标记,如果购物车中有未选中的商品,全选状态就是空心圆
if(symbol) {
this.data.allStatus = "circle"
} else {
// 如果购物车中所有商品都被选中了,全选状态就是一个勾
this.data.allStatus = "success"
}
this.setData({
allStatus: this.data.allStatus
})
},
Назад, чтобы выбрать все и отменить выбор операций. Выделить все – это общий столбец в нижней части страницы. Если поставлена галочка, это означает выбрать все. Во-первых, установите событие щелчка для поля "Выбрать все". Если все текущее состояние выбрано, после нажатия оно станет пустым, и наоборот.
<view class="shopping__ft">
<view class="shopping__ft__hd">
<!-- 给全选按钮一个点击事件selOrUnsel -->
<icon bindtap="selOrUnsel" type="{{allStatus}}" color="#23a3ff"></icon>
全选
</view>
<view class="shopping__ft__bd">
<text>合计:</text>
<text>¥{{sum}}</text>
</view>
<view class="shopping__ft__ft" bindtap="sumMoney">
去结算
</view>
</view>
js-реализация:
selOrUnsel: function() {
// 获得全选按钮和商品列表
const status = this.data.allStatus;
const goods = this.data.goodsList;
// 点击按钮后查看当前全选框的状态,对其进行取反的改变,并且对商品进行全选或反选
if(status === "success") {
// 如果全选按钮之前是选中的,就变成空心圆
this.data.allStatus = "circle";
// 遍历商品列表的每一项进行设置状态属性未未选中
goods.map(good => {
good.type = "circle";
})
} else {
this.data.allStatus = "success";
// 如果点击之前未选中全选按钮,就进行全选。遍历购物车列表改变所有商品的状态值
goods.map(good => {
good.type = "success";
})
}
// 将结果设置回页面上进行显示
this.setData({
goodsList: this.data.goodsList
})
this.setData({
allStatus: this.data.allStatus
})
},
Удалить товары из корзины
В правом верхнем углу интерфейса корзины есть кнопка удаления, с помощью которой можно удалить выбранный товар. Сначала добавьте событие клика delGoods в «Удалить». :
<view class="shopping__hd">
<view class="shopping__hd__content">
<view class="shopping__title">
购物车
<a class="shopping__title__delete right" bindtap="delGoods">删除</a>
</view>
</view>
</view>
js реализует метод delGoods, использует массив для хранения выбранных элементов, которые нужно удалить, затем просматривает массив элементов, которые нужно удалить, и удаляет их один за другим с помощью метода splice.
// 删除商品
delGoods: function() {
const goods = this.data.goodsList;
// 对购物车中所有的元素进行遍历,找出选中的元素,组成selGoods数组
const selGoods = goods.map(good => {
if(good.type === "success") {
return good;
}
})
wx.showModal({
title: "确定要删除所选商品?",
success: (res) => {
// 用户点击确定
if(res.confirm) {
// 对要删除的元素数组进行遍历,逐个用splice方法进行删除
selGoods.map(sel => {
goods.splice(sel);
})
// 删除成功以后从新设置页面的值
this.setData({
goodsList: this.data.goodsList
})
} else if (res.cancel) {
}
}
})
},
Добавить адрес доставки по умолчанию
В левом верхнем углу главной страницы есть маленькая точка, нажмите, чтобы добавить адрес доставки по умолчанию.
Добавление адреса доставки по умолчанию также требует передачи значений на нескольких страницах, потому что отображение адреса по умолчанию и установка адреса по умолчанию находятся в разных интерфейсах. Учитывая, что адрес доставки по умолчанию нужно хранить в личной информации пользователя длительное время, в этот раз мы используем хранилище для хранения данных.
Без дальнейших церемоний, чтобы реализовать функцию, сначала привяжите событие ChooseAddr.
<!-- 我现在是首页 -->
<view class="page__hd__input-left left">
<image src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/12/15/16057cf8f81b6d70~tplv-t2oaga2asx-image.image" bindtap="chooseAddr" />
</view>
Перейти на страницу к интерфейсу отображения адреса доставки по умолчанию, где может отображаться введенный адрес доставки.
chooseAddr: function() {
wx.navigateTo({
url: "../chooseAddress/chooseAddress"
})
},
В интерфейсе, который отображает адрес доставки по умолчанию, в правом верхнем углу есть кнопка для добавления адреса доставки, затем давайте перейдем на страницу, чтобы установить интерфейс адреса доставки по умолчанию.
<!-- 我是显示默认收货地址的界面 -->
<view class="choose-addr__hd">
<text class="choose-addr__title">选择收货地址</text>
<text class="choose-addr__add right" bindtap="addNewAddr">新增地址</text>
</view>
// 我要跳转到设置默认收货地址界面啦
addNewAddr: function() {
wx.navigateTo({
url: "../newAddr/newAddr"
})
},
В интерфейсе настройки адреса доставки по умолчанию установите событие изменения ввода bindinput для каждого поля ввода, чтобы получить содержимое поля ввода.
<view class="newAddr__bd">
<view class="weui-cells weui-cells_form gray-input">
<view class="weui-cell">
<view class="weui-cell__hd">
<text class="weui-label mr60">收货地址</text>
</view>
<view class="weui-cell__bd">
<input bindinput="getAddress" class="weui-input" placeholder="请输入收货地址" />
</view>
</view>
<view class="weui-cell">
<view class="weui-cell__hd">
<text class="weui-label mr94">门牌号</text>
</view>
<view class="weui-cell__bd">
<input bindinput="getNum" class="weui-input" placeholder="门牌号" />
</view>
</view>
</view>
<view class="weui-cells weui-cells_form second-weui-cells">
<view class="weui-cell">
<view class="weui-cell__hd">
<text class="weui-label mr48">联系人</text>
</view>
<view class="weui-cell__bd">
<input bindinput="getName" class="weui-input" placeholder="联系人" />
</view>
</view>
<view class="weui-cell">
<view class="weui-cell__hd">
<label class="weui-label mr44">手机号</label>
</view>
<view class="weui-cell__bd">
<input bindinput="getPhone" class="weui-input" placeholder="请输入手机号" />
</view>
</view>
</view>
</view>
Событие изменения ввода получает содержимое поля ввода:
data: {
address: '',
num: '',
name: '',
phone: ''
},
getAddress: function(e) {
this.setData({
address: e.detail.value
})
},
getNum: function(e) {
this.setData({
num: e.detail.value
})
},
getName: function(e) {
this.setData({
name: e.detail.value
})
},
getPhone: function(e) {
this.setData({
phone: e.detail.value
})
},
Дангданг! Сказав так много, вот и настал момент хранения данных!
wxml, установите событие клика saveInfo, сохраните данные после клика:
<view class="newAddr__hd">
<text class="newAddr__add left" bindtap="backToChooseAddr">返回</text>
<text class="newAddr__title">选择收货地址</text>
<text bindtap="saveInfo" class="newAddr__add right">保存</text>
</view>
WeChat предоставляет API: wx.setStorage может хранить данные в кеше в виде пар ключ (ключ) значение (данные).
Ключ — это указанный ключ в локальном кэше, данные — это содержимое, которое нужно сохранить, а успех — это функция обратного вызова успешного вызова интерфейса.
// 用户点击保存后,对输入的数据进行存储,并反馈存储状态
saveInfo: function() {
wx.setStorage({
key: "name",
data: [{address:this.data.address}, {num: this.data.num}, {name: this.data.name}, {phone: this.data.phone}],
success: function() {
// 数据设置成功后,弹框提示用户信息保存完整,并跳回展示默认地址的界面
wx.showToast({
title: "地址保存成功",
icon: 'success',
duration: 2000
})
setTimeout(function(){
wx.navigateTo({
url: "../chooseAddress/chooseAddress"
})
},1000);
}
})
После успешной установки данных вернитесь к интерфейсу, показывающему адрес по умолчанию. Здесь мы хотим получить данные в кеше.
WeChat предоставляет API: wx.getStorage может асинхронно получать контент, соответствующий указанному ключу, из локального кеша. key — это указанный ключ в локальном кеше, а успех — это функция обратного вызова, вызываемая интерфейсом.
onShow: function () {
var that = this;
wx.getStorage({
key: "name",
success: function(res) {
if(res.data.length > 0) {
that.setData({
address: res.data[0].address,
num: res.data[1].num,
name: res.data[2].name,
phone: res.data[3].phone
})
}
}
})
},
Сканировать QR-код
В правом верхнем углу главной страницы есть изображение для свайпа, нажмите, чтобы отсканировать QR-код.
Привяжите сканирование события клика к этому изображению:
<view class="page__hd__input-right left">
<image bindtap="scan" src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2017/12/15/16057cf8f3b9287a~tplv-t2oaga2asx-image.image" />
</view>
Вызовите собственный API WeChat: wx.scanCode для сканирования QR-кода.
scan: function() {
wx.scanCode({
success: (res) => {
console.log(res)
}
})
},
Фоновые данные
Что касается источника фоновых данных, я используюeasymockСоздавайте фиктивные данные. easymock действительно очень прост в использовании для программистов, которые временно сосредотачиваются на внешнем интерфейсе. Я написал статью раньшеСоздавайте фиктивные данные с помощью Easy MockДобро пожаловать, чтобы передвигаться.
напиши в конце
Возможно, самое важное в написании апплета WeChat — просмотреть документацию. WeChat предоставляет разработчикам подробное введение и использование различных компонентов и API.
прикреплятьДокументация по разработке программы WeChat Mini
Наконец, укажите исходный адрес GitHub: https://github.com/TeanLee/hema.
Если вы думаете, что это неплохо, пожалуйста, начните поощрять это~
Я буду продолжать обновлять этот апплет.Критика, советы и обмен приветствуются: