cc-product-waterfall仿天猫、淘宝购物车店铺商品列表组件

news2025/1/23 8:03:01

cc-product-waterfall仿天猫、淘宝购物车店铺商品列表组件

引言

在电商应用中,购物车体验的优化对于提升用户满意度和转化率至关重要。在本文中,我们将深入探讨如何使用cc-product-waterfall组件,结合uni-number-box和xg-widget,来构建一个仿天猫、淘宝的购物车店铺商品列表。同时,我们将详细解析相关的事件处理函数,以实现如商品过滤、店铺勾选、商品勾选、数量改变以及全选等功能。

组件介绍

cc-product-waterfall

cc-product-waterfall是一个强大的商品列表组件,支持瀑布流布局,非常适合用于展示大量商品。

uni-number-box

uni-number-box是一个数字输入框组件,用户可以通过它方便地修改商品数量。

xg-widget

xg-widget是一套通用的UI组件库,可以帮助我们快速构建出复杂且交互性强的用户界面。

购物车店铺商品列表实现

步骤1:引入必要的组件

首先,确保你的项目中已经引入了cc-product-waterfall、uni-number-box和xg-widget等组件。具体的引入方法可能会根据你使用的框架或库有所不同。

步骤2:构建基本布局

使用cc-product-waterfall构建商品列表,uni-number-box用于商品数量的输入,xg-widget中的checkbox组件用于实现店铺和商品的勾选功能。

步骤3:添加交互功能

通过事件处理函数来实现各种交互功能,包括商品过滤、店铺勾选、商品勾选、数量改变以及全选等。

事件处理详解

过滤选择的商品和未选择的商品

filterCheckedProductfilterUncheckedProduct方法分别用于过滤出已选择和未选择的商品。这两个方法都接受一个商品列表作为参数,然后使用数组的filter方法根据商品的checked属性进行过滤。

示例代码:
使用方法
 
引入uni-number-box xg-widget组件

事件处理如下:
// 过滤选择的商品
filterCheckedProduct(products) {
return products.filter(item => item.checked);
},
// 过滤未选择的商品
filterUncheckedProduct(products) {
return products.filter(item => !item.checked);
},
// 店铺勾选
onShopCheckboxTap(shop) {
shop.checked = !shop.checked;

shop.products.forEach(product => {
product.checked = shop.checked;
});
},
// 商品勾选
onProductCheckboxTap(product) {
product.checked = !product.checked
},
// 数量改变
onNumberBoxChange(product, e) {
product.count = e;
},
// 全选
onCheckAllTap() {
const checked = !this.allChecked;
this.shops.forEach(shop => {
shop.products.forEach(product => {
product.checked = checked;
})
})
}
HTML代码实现部分

<template>
    <view>
        <!-- 空购物车 -->
        <view v-if="isEmptyCart"
            class="bg-color-white border-bottom-left-radius-xl border-bottom-right-radius-xl padding-lg">
            <view class="row-center-center">
                <image class="img-size-xl" src="/static/cart/empty-cart.png" mode="aspectFit"></image>
                <text class="font-size-lg text-color-greyblack">购物车是空的</text>
            </view>
            <view class="row-center-center">
                <text class="empty-button">逛逛秒杀</text>
                <text class="empty-button">看看关注</text>
            </view>
        </view>

        <!-- 非空购物车 -->
        <view v-if="!isEmptyCart">
            <view v-for="(shop, shopIndex) of cartShops" :key="shopIndex"
                class="padding-lg margin-bottom-lg bg-color-white border-radius-xl">
                <!-- 店铺购物车商品 -->
                <!-- 店铺标题 -->
                <view class="" @tap="onShopCheckboxTap(shop)">
                    <label class="row-between-center">
                        <view class="row-center-center">
                            <checkbox class="shop-checkbox" :checked="shop.checked" />
                            <image class="img-size-base border-radius-circle" :src="shop.logo" mode="aspectFit"></image>
                            <text class="font-size-lg">{{shop.name}}</text>
                        </view>
                        <!-- <view class=""></view> -->
                    </label>
                </view>

                <!-- 店铺产品列表 -->
                <view class="row-between-start margin-top-base" v-for="(product, productIndex) of shop.products"
                    :key="productIndex">
                    <view class="product-checkbox" @tap="onProductCheckboxTap(product)">
                        <checkbox :checked="product.checked" />
                    </view>

                    <image class="border-radius-lg product-image" :src="product.image" mode=""></image>
                    <view class="flex-1 column-center-stretch padding-left-lg">
                        <text class="lines-2 font-size-base">{{product.title}}</text>
                        <view class="row-start-center margin-v-side-base">
                            <view
                                class="row-center-center bg-color-grey border-radius-rect-circle padding-side-base padding-v-side-xs">
                                <text v-for="(property, propertyIndex) of product.sku" :key="propertyIndex"
                                    class="font-size-sm">{{property}},</text>
                            </view>
                        </view>

                        <view class="row-between-center">
                            <xg-money camel :size="UNI_FONT_SIZE_XL" :money="product.price"></xg-money>

                            <view class="number-box">
                                <uni-number-box :min="1" :value="product.count"
                                    @change="onNumberBoxChange(product, $event)"></uni-number-box>
                            </view>
                        </view>
                    </view>
                </view>

            </view>
        </view>

        <view class="order-amount-placeholder"></view>
        <view class="row-between-center bg-color-white padding-side-lg order-amount">
            <view class="row-center-center">
                <view class="product-checkbox" @tap="onCheckAllTap">
                    <checkbox :checked="allChecked" />
                </view>
                <text class="font-size-base">全选</text>
                <text class="font-size-lg margin-left-lg">合计:</text>
                <text class="font-size-lg font-weight-bold">¥{{totalAmount.toFixed(2)}}</text>
            </view>

            <view class="bg-color-red border-radius-rect-circle padding-side-lg padding-v-side-base">
                <text class="font-size-lg text-color-white">去结算({{totalCount}})</text>
            </view>
        </view>
    </view>
</template>

<script>
    // 获取购物车数据来源
    import data from '@/data/cart/cart';

    import mixin from '@/common/mixin';

    const customData = {
        page: 0
    }

    export default {
        mixins: [mixin],
        data() {
            return {
                isEmptyCart: false,
                loadMoreStatus: 'more',

                shops: [],

            };
        },

        computed: {
            // 全选事件
            allChecked() {
                return this.cartShops.filter(item => item.checked).length === this.cartShops.length;
            },

            // 购物车店铺数据
            cartShops() {
                this.shops.forEach(shop => {
                    const uncheckedProducts = this.filterUncheckedProduct(shop.products);

                    shop.checked = (uncheckedProducts.length === 0);
                })

                return this.shops;
            },

            // 计算数量
            totalCount() {
                let count = 0;

                this.cartShops.forEach(shop => {
                    this.filterCheckedProduct(shop.products).forEach(product => {
                        count += parseInt(product.count);
                    })
                })

                return count;
            },
            // 计算金额
            totalAmount() {
                let amount = 0;

                this.cartShops.forEach(shop => {
                    this.filterCheckedProduct(shop.products).forEach(product => {
                        amount += Number(product.price * product.count)
                    })
                })

                return amount;
            }
        },

        async created() {
            this.loadMoreStatus = 'loading';

            // 获取商铺数据
            const shopPromise = data.shops();

            this.shops = await shopPromise;

        },

        methods: {
            // 过滤选择的商品
            filterCheckedProduct(products) {
                return products.filter(item => item.checked);
            },
            // 过滤未选择的商品
            filterUncheckedProduct(products) {
                return products.filter(item => !item.checked);
            },
            // 店铺勾选
            onShopCheckboxTap(shop) {
                shop.checked = !shop.checked;

                shop.products.forEach(product => {
                    product.checked = shop.checked;
                });
            },
            // 商品勾选
            onProductCheckboxTap(product) {
                product.checked = !product.checked
            },
            // 数量改变
            onNumberBoxChange(product, e) {
                product.count = e;
            },
            // 全选
            onCheckAllTap() {
                const checked = !this.allChecked;
                this.shops.forEach(shop => {
                    shop.products.forEach(product => {
                        product.checked = checked;
                    })
                })
            }

        },
    }
</script>

<style lang="scss" scoped>
    .empty-button {
        @include border(1px solid);

        font-size: $uni-font-size-lg;
        border-radius: $uni-border-radius-rect-circle;
        margin: 0 $uni-spacing-col-xl;
        padding: $uni-spacing-row-sm $uni-spacing-col-xl;
    }

    $order-amount-height: 100rpx;

    .product-list {
        /* #ifdef APP-NVUE */

        @include position(fixed, 0 0 $order-amount-height 0);
        /* #endif */

        // width: 500rpx;
    }

    .shop-checkbox {
        transform: scale(0.8);
    }

    .product-checkbox {
        transform: scale(0.75);
    }

    .product-image {
        width: 200rpx;
        height: 200rpx;
    }

    .number-box {
        transform-origin: 100% 50%;
        transform: scale(0.75);
    }

    .order-amount-placeholder {
        height: $order-amount-height;
    }

    .order-amount {
        /* #ifndef APP-NVUE */
        @include position(fixed, none 0 var(--window-bottom) 0);
        /* #endif */
        /* #ifdef APP-NVUE */
        @include position(fixed, none 0 0 0);
        /* #endif */

        height: $order-amount-height;

        /* #ifndef APP-NVUE */
        z-index: 10000;
        /* #endif */
    }
</style>

店铺勾选和商品勾选功能实现

当用户点击店铺或商品的勾选框时,我们需要更新对应的checked状态。onShopCheckboxTap方法用于处理店铺的勾选事件,它会更新店铺及其所有商品的checked状态。onProductCheckboxTap方法用于处理商品的勾选事件,只会更新当前商品的checked状态。这两个方法都使用了JavaScript的逻辑非操作符来实现checked状态的切换。当用户点击全选按钮时,onCheckAllTap方法将会被调用。这个方法会检查当前的全选状态,然后遍历所有的店铺和商品,将它们的checked状态设置为相反的值。这样就可以实现一键全选或全不选的功能

 阅读全文下载完整组件代码请关注微信公众号: 前端组件开发

d848d5658a07453c843277846948c608.png

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1279601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

WebGL笔记:图形缩放的原理和实现

缩放 1 &#xff09;原理 缩放可以理解为对向量长度的改变&#xff0c;或者对向量坐标分量的同步缩放 如下图&#xff0c;比如让向量OA 收缩到点B的位置&#xff0c;也就是从OA变成OB&#xff0c;缩放了一半 2 &#xff09;公式 已知 点A的位置是(ax,ay,az)点A基于原点內缩了…

L1-009:N个数求和

目录 ⭐题目描述⭐ ⭐分析 ⭐程序代码 运行结果 ⭐文案分享⭐ ⭐题目描述⭐ 本题的要求很简单&#xff0c;就是求N个数字的和。麻烦的是&#xff0c;这些数字是以有理数分子/分母的形式给出的&#xff0c;你输出的和也必须是有理数的形式。 输入格式&#xff1a; 输入第一行给出…

GAN:PacGAN-生成对抗网络中两个样本的威力

论文&#xff1a;https://arxiv.org/pdf/1712.04086.pdf 代码&#xff1a;GitHub - fjxmlzn/PacGAN: [NeurIPS 2018] [JSAIT] PacGAN: The power of two samples in generative adversarial networks 发表&#xff1a;2016 一、摘要 1&#xff1a;GAN最重大的缺陷是&#xf…

数据库管理-第121期 我为什么写文章(202301203)

数据库管理-第121期 我为什么写文章&#xff08;202301203&#xff09; 其实呢~大周末我不是太想写文章的&#xff0c;周五HaloDB起了个头还有一堆可以做的事情都计划到下周了&#xff0c;但是昨天发生了一件事情&#xff0c;让我很是不开心&#xff1a;强盗逻辑&#xff0c;白…

部署 Draw.io 思维导图工具

1&#xff09;Draw.io 介绍 提到流程图&#xff0c;大家第一时间可能会想到 Visio&#xff0c;不可否认&#xff0c;VIsio 确实是功能强大&#xff0c;但是软件为收费&#xff0c;并且因为其功能强大&#xff0c;导致安装需要很多的系统内存&#xff0c;并且是不可跨平台使用。…

分治-归并算法——LCR 170. 交易逆序对的总数

文章目录 &#x1f33c;0. 归并排序&#x1f33b;1. 题目&#x1f33c;2. 算法原理&#x1f337;3. 代码实现 &#x1f33c;0. 归并排序 归并排序是典型的分治&#xff0c;将数组分成若干个子数组&#xff0c;数组两两比较&#xff0c;不是很清楚的&#xff0c;可以查看此篇文…

VUE设计与实现共读系列之ref的实现【响应式原理】

前言 我们先顺一下vue使用响应式数据的流程&#xff1a; vue 是通过 ref 和 reactive 来创建响应式值&#xff0c;改变响应式值&#xff0c;视图跟着发生变化。 我们今天就来看一下ref和reactive是如何实现的 准备 首先&#xff0c;打开ref函数的位置 我们可以看到一个被re…

10行代码实现vue路由最简单的登陆拦截

需求&#xff1a;不涉及任何角色权限&#xff0c;基本实现目标&#xff0c;有token就可查看任何页面&#xff0c;否则就去登陆&#xff0c;来一步步实现 1. 创建你的路由页面&#xff0c;此处略了 2. 导航守卫拦截判断思路 // 创建路由 const router createRouter({history…

Python----字典练习

相关链接&#xff1a;Python---字典的增、删、改、查操作_python中字典的增删改查-CSDN博客 Python---字典---dict-CSDN博客 Python---引用变量与可变、非可变类型-CSDN博客 重点&#xff1a; 字典中的 key &#xff08;就是键&#xff09;可以是很多数据类型&#xff08;…

对比ProtoBuf和JSON的序列化和反序列化能力

1.序列化能力对比验证 在这里让我们分别使用PB与JSON的序列化与反序列化能力&#xff0c;对值完全相同的一份结构化数据进行不同次数的性能测试。 为了可读性&#xff0c;下面这一份文本使用JSON格式展示了需要被进行测试的结构化数据内容: {"age" : 20,"name…

SpringAMQP入门案例——接收消息

依赖 <!--SpringAMQP起步依赖--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> yml配置文件 自行修改 spring:rabbitmq:host: 192.168.220.130 # …

Spring MVC学习随笔-控制器(Controller)开发详解:接受客户端(Client)请求参数

学习视频&#xff1a;孙哥说SpringMVC&#xff1a;结合Thymeleaf&#xff0c;重塑你的MVC世界&#xff01;&#xff5c;前所未有的Web开发探索之旅 第三章、SpringMVC控制器开发详解 3.1 核心要点 &#x1f4a1; 1. 接受客户端&#xff08;client&#xff09;请求参数[讲解] 2…

Linux脚本awk命令

目录 一. awk命令简介 1. awk版本 2. awk与vim的区别 3. awk与sed的区别 4. awk工作原理 5. awk格式 6. awk常用选项 二. awk基础用法 1. awk基础用法 2. BEGIN和END语句块 3. 指定分隔符 4. 首尾关键字 三. awk内置变量 1. FS变量 2. OFS变量 3. RS变量 4. NF…

【Unity动画】为一个动画片段添加事件Events

动画不管播放到那一帧&#xff0c;我们都可以在这里“埋伏”一个事件&#xff08;调用一个函数并且给函数传递一个参数&#xff0c;参数在外部设置&#xff0c;甚至传递一个物体&#xff09;&#xff01; 嗨&#xff0c;亲爱的Unity小伙伴们&#xff01;你是否曾想过为你的动画…

语言模型文本处理基石:Tokenizer简明概述

编者按&#xff1a;近年来&#xff0c;人工智能技术飞速发展&#xff0c;尤其是大型语言模型的问世&#xff0c;让 AI 写作、聊天等能力有了质的飞跃。如何更好地理解和利用这些生成式 AI&#xff0c;成为许多开发者和用户关心的问题。 今天&#xff0c;我们推出的这篇文章有助…

【小沐学Python】网络爬虫之lxml

文章目录 1、简介2、安装3、基本功能3.1 lxml.etree3.2 解析HTML网页3.3 读取并解析HTML文件3.4 提取所有a标签内的文本信息3.5 树迭代3.6 序列化3.7 元素以字典的形式携带属性3.8 元素包含文本 4、代码测试4.1 lxml解析网页4.2 使用xpath获取所有的文本4.3 使用xpath获取 clas…

TA-Lib学习研究笔记(二)——Overlap Studies上

TA-Lib学习研究笔记&#xff08;二&#xff09;——Overlap Studies 1. Overlap Studies 指标 [BBANDS, DEMA, EMA, HT_TRENDLINE, KAMA, MA, MAMA, MAVP, MIDPOINT, MIDPRICE, SAR, SAREXT, SMA, T3, TEMA, TRIMA, WMA]2.数据准备 get_data函数参数&#xff08;代码&#x…

mongoose学习记录

mongoose安装和连接数据库 npm i mongoose导入mongoose const mongoose require(mongoose) mongoose.set("strictQuery",true)连接数据库 mongoose.connect(mongodb:127.0.0.1:27017/test)设置回调 mongoose.connection.on(open,()>{console.log("连接成…

利用段落检索和生成模型进行开放域问答12.2

利用段落检索和生成模型进行开放域问答 摘要引言2 相关工作3 方法 摘要 事实证明&#xff0c;开放域问答的生成模型具有竞争力&#xff0c;无需借助外部知识。虽然很有希望&#xff0c;但这种方法需要使用具有数十亿个参数的模型&#xff0c;而这些模型的训练和查询成本很高。…

还在Wins 11怀念10的右键单击菜单?别担心,可通过注册表来实现

到目前为止&#xff0c;Windows 11最令人讨厌的新“功能”是右键单击任何内容时会出现截断的上下文菜单。以前版本的Windows显示了你的所有选项&#xff0c;包括可以打开文件的不同程序&#xff0c;而新菜单仅限于少数选项&#xff0c;不一定是你想要的。 例如&#xff0c;当我…