【前端小程序】06 - 购物车页面

1. 添加收货地址按钮

1.1 页面结构与样式

  1. 页面结构:
<view class="cart">
    <!-- 添加收货地址按钮  plain 代表背景透明-->
   <view class="address_btn">
        <button type="warn" plain bindtap="addAddressHandle">
            添加收货地址
        </button>
   </view>
</view>
  1. 页面样式:
.cart {

    .address_btn {
        padding: 20rpx;
        button {
            color: var(--themeColor); 
            width: 60%;
        }
    }
}

1.2 处理添加收货地址事件

    /**
     * 处理添加收获地址事件
     */
    addAddressHandle() {
        wx.chooseAddress({
            success: (result) => {
                console.log(result);
            },
        });
    },
  1. 点击添加收货地址按钮时如果我们没有点击确定,而是点击取消。这时会出现问题:之后再次点击添加收货地址按钮的时候就打不开选择地址的界面了。

1.3 权限演示

  1. 用户获取对小程序所授予获取地址的权限状态scope

假设用户点击 获取地址的提示框的确定按钮 authSetting{scope.address 的值是 true}
假设用户点击获取地址的提示框的取消按钮 scope 的值是 false
假设用户没有调用过选择地址的api scope 的值是 undefined

  1. 查看权限信息:wx.getSetting
wx.getSetting({
            success: (result) => {
                console.log(result);
            },
        });
  1. 解决点击了获取选择地址对话框取消按钮后无法再调起的问题:
addAddressHandle() {
        // 正确获取收货地址的流程
        wx.getSetting({
            success: (result) => {
                // 遇到这种比较特殊的属性名称的时候需要使用 [] 进行获取
                const scopeAddress = result.authSetting["scope.address"]
                if (scopeAddress === true || scopeAddress === undefined) {
                    // 表示曾经用户授予于了获取地址的权限 可以直接调用选择收货地址
                    wx.chooseAddress({
                        success: (result1) => {
                            console.log(result1);
                        }
                    });
                } else {
                    // 曾经用户取消了选择收货地址权限的获取 需要重新让用户为选择收货地址授权
                    wx.openSetting({
                        success: (result2) => {
                            console.log(result2);
                            // 重新选择收货地址
                            wx.chooseAddress({
                                success: (result3) => {
                                    console.log(result3);
                                }
                            });
                        }
                    });
                }
            },
        });
    },
  1. 使用ES7的语法优化以上的操作:
/**
 * 权限设置
 */
export const getSetting = () => {
    return new Promise((resolve, reject) => {
        wx.getSetting({
            success: (result) => {
                resolve(result);
            },
            fail: (error) => {
                reject(error);
            }
        });
    });
}

export const chooseAddress = () => {
    return new Promise((resolve, reject) => {
        wx.chooseAddress({
            success: (result) => {
                resolve(result);
            },
            fail: (error) => {
                reject(error);
            }
        });
    });
}

export const openSetting = () => {
    return new Promise((resolve, reject) => {
        wx.openSetting({
            success: (result) => {
                resolve(result);
            },
            fail: (error) => {
                reject(error);
            }
        });
    });
}
 async addAddressHandle() {
        // 正确获取收货地址的流程

        // 使用ES7优化后的代码
        try {
            const setRes = await getSetting();
            const scopeAddress = setRes.authSetting["scope.address"]
            console.log(scopeAddress);
            // 判断当前权限状态
            if (scopeAddress === false) {
                await openSetting();
            }
            // 调用获取收货地址的 api
            const address = await chooseAddress();
            // 将获取结果存入到缓存中
            wx.setStorageSync("address", address);
        } catch (err) {
            console.log(err);
        }
    },

1.4 获取本地存储中的地址数据

  1. 编写页面结构 :
<view class="cart">
    <!-- 添加收货地址按钮  plain 代表背景透明-->
    <!--  address空对象的boolean类型也是true 需要使用其属性的有无进行判断  -->
   <view class="address_btn" wx:if="{{!address.userName}}">
        <button type="warn" plain bindtap="addAddressHandle">
            添加收货地址
        </button>
   </view>

   <view class="user_info_row" wx:else>
        <view class="user_info">
            <view class="user_name">{{address.userName}}</view>
            <view class="user_address">{{address.all}}</view>
        </view>
        <view class="user_phone">{{address.telNumber}}</view>
   </view>
</view>
  1. 编写页面样式:
 .user_info_row {
        display: flex;
        padding: 20rpx;     
        .user_info {
            flex:5;
        }

        .user_phone {
            flex:3;
            text-align: right;
        }
    }
  1. 首先在data中定义一个变量保存在缓存中获取到的地址信息,需要在onShow生命周期函数中进行获取设置数据。
/**
     * 生命周期函数--监听页面显示
     */
    onShow: function() {
        const address = wx.getStorageSync("address");
        this.setData({
            address
        });
    },

2.将缓存中的购物车商品数据显示到页面上

  1. 回到了商品详情页面,第一次添加商品的时候手动添加了属性

num = 1 ;
checked = true;

设置购物车复选框为选中状态
  1. onShow中获取缓存中的购物车数组。
  const cart = wx.getStorageSync("cart");
  1. 将购物车数据填充到data变量中。

3. 底部工具栏的功能

3.1 全选功能

  1. onshow中获取缓存中的购物车数组。

  2. 根据购物车中的商品数量,所有的商品都被选中 checked=true 全部就被选中。

  3. 数组的 every()方法的使用 : 会遍历会接受一个回调函数,那么每一个回调函数都会返回true,那么every()方法的返回值为true只要有一个回调函数返回false那么久不再循环执行,直接返回false。假如是一个空数组调用了every()方法返回值就是true

        // 获取缓存中的购物车数据
        const cart = wx.getStorageSync("cart");
        // 使用every函数遍历数组中的 checked 属性
        const allChecked = cart.length ? cart.every(v => v.checked) : false;
全选功能

3.2 计算总价格和总数量

  1. 都需要商品被选中我们才能拿来计算。

  2. 获取购物车数组。

  3. 遍历。

  4. 判断商品是否被选中。

  5. 总价格 += 商品单价 * 商品数量。

  6. 总数量 += 商品数量。

  7. 将计算后的价格和数量设置回data中。

计算总价格和总数量

3.3 复选框的选中与取消选中

  1. 绑定change 事件,并传递当前的商品id
   <checkbox-group bindchange="checkboxChangeHandle" data-id="{{item.goods_id}}">
  1. 获取到被修改的商品对象。

  2. 商品对象的选中状态取反。

        // 1. 接收传递过来的 商品 id
        const goods_id = e.currentTarget.dataset.id;
        // 2. 获取缓存中的购物车数据 
        const { cart } = this.data; // 在data中解构出 cart
        // 3. 查询该商品id对应的索引 
        const index = cart.findIndex(v => v.goods_id === goods_id);
        // 4 根据索引修改该商品的选中状态 
        cart[index].checked = !cart[index].checked;
  1. 重新填充回data中和缓存中。

  2. 重新计算全选。总价格 总数量。

  3. 将选中和取消选中、计算合计价格、合计数量 设置购物车到data和缓存中抽取为一个方法:

/**
     * 
     * @param {抽取处理 合计价格 合计数量设置购物车到data和缓存中的操作} cart 
     */
    setCart(cart) {
        // 使用every函数遍历数组中的 checked 属性
        // const allChecked = cart.length ? cart.every(v => v.checked) : false;
        let allChecked = true; // 事先将其设置为true 到后面循环的时候发现有false的时候再将其设置为 false
        let totalNum = 0;
        let totalPrice = 0;
        cart.forEach(v => {
            if (v.checked) {
                totalNum += v.num;
                totalPrice += v.goods_price * v.num;
            } else {
                allChecked = false;
            }
        });

        // 再对其值进行把关 
        allChecked = cart.length != 0 ? allChecked : false;
        this.setData({
            cart,
            allChecked,
            totalNum,
            totalPrice
        });
        // 重新将cart对象设置到缓存中 
        wx.setStorageSync("cart", cart);
    },

3.4 反选

  1. 复选框绑定一个change事件。

  2. 获取data中的选中状态 allchecked;

  3. 直接取反 allchecked = !allchecked;

  4. 遍历购物车数组让里面商品选中状态跟随allchecked改变而改变。

  5. 将购物车数组 和 allchecked重新设置会data中 和 缓存中。

3.5 商品数量的编辑功能

  1. "+" "-" 按钮绑定同一个点击事件区分的关键 自定义属性。

    "+" "+1"
    "-" "-1"

<!-- 根据传递不同的操作符判断执行不同的操作  data-opt -->
<view class="edit_btn" bindtap="editGoodsNum" data-id="{{item.goods_id}}" data-opt="{{-1}}">-</view>
<view class="edit_btn" bindtap="editGoodsNum" data-id="{{item.goods_id}}" data-opt="{{1}}">+</view>
  1. 传递被点击的商品 id opt操作参数。

  2. 获取data中的购物车数组,来获取需要被修改的对象。

  3. 直接修改商品对象的数量num

  4. cart数组 重新设置会缓存中和data中 。

    /**
     * 
     * @param {购物车视频编辑事件} e 
     */
    editGoodsNum(e) {
        // 获取传递过来的商品id 和 按钮操作参数
        let { id, opt } = e.currentTarget.dataset;
        // 根据商品id在 cart数组中查找 对应的商品索引
        let { cart } = this.data;
        const index = cart.findIndex(v => v.goods_id === id);
        // 根据index修改数组中的指定商品信息 
        cart[index].num += opt;
        // 将修改后的购物车数组重新设置到缓存中和data中
        this.setCart(cart);
    },

3.6 删除商品

  1. 当购物车的数量某个商品数量为 1 的同时用户点击 "-" ,弹窗提示(showModel)询问用户是否需要删除。

  2. 将弹窗的请求的组件封装到,promise中通过ES7的去Promise简化操作。

/**
 * 简化模态框提示操作
 */
export const showModal = ({ content }) => {
    return new Promise((resolve, reject) => {
        wx.showModal({
            title: '提示',
            content: content,
            /* 这里需要使用箭头函数的形式 */
            success: (res) => {
                resolve(res);
            },
            fail: (err) => {
                reject(err);
            }
        });
    })
}
  1. 编辑购物车商品代码:

    /**
     * 
     * @param {购物车商品编辑事件} e 
     */
    async editGoodsNum(e) {
        // 获取传递过来的商品id 和 按钮操作参数
        let { id, opt } = e.currentTarget.dataset;
        // 根据商品id在 cart数组中查找 对应的商品索引
        let { cart } = this.data;
        const index = cart.findIndex(v => v.goods_id === id);

        /**
         * 如果当前商品的数量是 1 且用户的操作是进行减 1 操作 
         */
        if (cart[index].num === 1 && opt === -1) {
            const res = await showModal({ content: "您确定要删除当前商品吗?" });
            // 点击确定的时候
            if (res.comfirm) {
                cart.splice(index, 1);
                this.setCart(cart);
            }
        } else {
            // 根据index修改数组中的指定商品信息 
            cart[index].num += opt;
            this.setCart(cart);
        }
        // 将修改后的购物车数组重新设置到缓存中和data中
        this.setCart(cart);
    },

3.7 结算按钮功能

  1. 判断有没有收货地址信息。

  2. 判断用户有没有选购商品。

  3. 经过以上验证即可跳转到支付页面进行支付。

   /**
     * 处理结算逻辑
     */
    async handlePay() {
        const { address, totalNum } = this.data;

        if (!address.userName) {
            await showToast({ title: "您还未填写自己的地址信息!" });
            return;
        }

        if (totalNum == 0) {
            await showToast({ title: "您还未选择商品!" });
            return;
        }

        wx.navigateTo({
            url: '/pages/pay/index'
        });
    },
  1. 其中的 showToast 进行了抽取,使用ES7的Promise操作简化了操作:

/**
 * 简化页面提示
 */
export const showToast = ({ title }) => {
    return new Promise((resolve, reject) => {
        wx.showToast({
            title: title,
            icon: 'none',
            mask: true,
            success: (res) => {
                resolve(res)
            },
            fail: (err) => {
                reject(err);
            }
        });
    })
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容