Tips
(Part 2) undertake (Part 1). The interface document and Ali icon library have been given in (Part 1). The code pasted in this article may be incomplete. See (Part 2) for the complete code.
Dynamic rendering of product details rotation chart
First, write the structure of the rotation chart in goods_ Modify the code in index.wxml under the detail folder. Then index.wxss changes the style
<!--pages/goods_detail/index.wxml--> <view class="detail_swiper"> <!-- Content of rotation chart --> <swiper autoplay="true" circular="true" indicator-dots="true"> <swiper-item wx:for="{{goodsObj.data.message.pics}}" wx:key="pics_id"> <image mode="widthFix" src="{{item.pics_mid}}"></image> </swiper-item> </swiper> </view>
/* pages/goods_detail/index.wxss */ .detail_swiper swiper{ height: 70vw; text-align: center; } .detail_swiper image{ width: 60%; }
Improve the product profile on the product details page
The rich text tag rich text is used. The data to be rendered is in the data returned by the request interface in the interface document. We use goodsObj to store the returned data.
<!--pages/goods_detail/index.wxml--> <view class="detail_swiper"> <!-- Content of rotation chart --> <swiper autoplay="true" circular="true" indicator-dots="true"> <swiper-item wx:for="{{goodsObj.data.message.pics}}" wx:key="pics_id"> <image mode="widthFix" src="{{item.pics_mid}}"></image> </swiper-item> </swiper> </view> <!-- Product content text --> <!-- commodity price --> <view class="goods_price">¥{{goodsObj.data.message.goods_price}}</view> <view class="goods_name_row"> <!-- Commodity name --> <view class="goods_name">{{goodsObj.data.message.goods_name}}</view> <!-- Collect goods --> <view class="goods_collect"> <!-- The collection icons here are imported from Ali icon library --> <text class="iconfont icon-shoucang"></text> <view class="collect_text">Collection</view> </view> </view> <!-- Graphic details --> <view class="goods_info"> <view class="goods_info_title">Graphic details</view> <view class="goods_info_content"> <!-- Rich text rendering --> <rich-text nodes="{{goodsObj.data.message.goods_introduce}}"></rich-text> </view> </view>
/* pages/goods_detail/index.wxss */ .detail_swiper swiper { height: 70vw; text-align: center; } .detail_swiper image { width: 60%; } .goods_price { padding: 15rpx; font-size: 32rpx; font-weight: 600; color: var(--themColor); } .goods_name_row { display: flex; border-top: 5rpx solid #dedede; border-bottom: 5rpx solid #dedede; padding: 10rpx 0; } .goods_name_row .goods_collect { flex: 1; display: flex; /* The spindle direction becomes the up and down (vertical axis) direction */ flex-direction: column; justify-content: center; align-items: center; border-left: 1rpx solid #000; } .goods_name_row .goods_name { flex: 5; color: #000; font-size: 28rpx; padding: 0 10rpx; /* When the text exceeds a lot, use ellipsis to replace the extra text */ display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } .goods_info {} .goods_info_title { font-size: 32rpx; color: var(--themColor); font-weight: 600; padding: 20rpx; } .goods_info_content {}
The effect is as follows
Product details page - optimize dynamic rendering
When observing the data in goodsObj, we find that some of the data stored inside are not used, which will occupy the performance of the applet. Therefore, we need to process the assignment function of goodsObj, and some iPhones do not recognize the webp image format. Therefore, the returned data is the webp image, which may fail to render on Apple phones. Solve the above two problems:
- Optimize the code of setData in index.js.
- Modify the format of using wx:for to traverse data in index.wxml
- Temporarily modify the image in webp format and use the replace function
// pages/goods_detail/index.js //The method for sending requests is introduced to optimize the import { request } from "../../request/index.js" Page({ /** * Initial data of the page */ data: { //The data returned by the request is in the form of an object goodsObj: {} }, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { //The product id passed when getting the jump page const { goods_id } = options; this.getGoodsDetail(goods_id); }, /** * Get product details data */ async getGoodsDetail(goods_id) { const goodsObj = await request({ url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/detail", data: { goods_id } }); this.setData({ // Optimize the storage data, and only assign and store the data used by the applet goodsObj:{ goods_name:goodsObj.data.message.goods_name, goods_price:goodsObj.data.message.goods_price, // Some iphone phones do not support webp format // Background modification // Or use the replace function for temporary modification, where \. webp is the file to find all. webp, g means select all, and. jpg means replace all with. jpg format. goods_introduce:goodsObj.data.message.goods_introduce.replace(/\.webp/g,'.jpg'), pics:goodsObj.data.message.pics } }) }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
<!--pages/goods_detail/index.wxml--> <view class="detail_swiper"> <!-- Content of rotation chart --> <swiper autoplay="true" circular="true" indicator-dots="true"> <swiper-item wx:for="{{goodsObj.pics}}" wx:key="pics_id"> <image mode="widthFix" src="{{item.pics_mid}}"></image> </swiper-item> </swiper> </view> <!-- Product content text --> <!-- commodity price --> <view class="goods_price">¥{{goodsObj.goods_price}}</view> <view class="goods_name_row"> <!-- Commodity name --> <view class="goods_name">{{goodsObj.goods_name}}</view> <!-- Collect goods --> <view class="goods_collect"> <!-- The collection icons here are imported from Ali icon library --> <text class="iconfont icon-shoucang"></text> <view class="collect_text">Collection</view> </view> </view> <!-- Graphic details --> <view class="goods_info"> <view class="goods_info_title">Graphic details</view> <view class="goods_info_content"> <!-- Rich text rendering --> <rich-text nodes="{{goodsObj.goods_introduce}}"></rich-text> </view> </view>
The effect is normal, and there are only four kinds of data in goodsObj.
Click the rotation chart to preview the large picture
Click the rotation chart in the commodity details to zoom in and preview. The steps are as follows
- Bind the click event to the rotation chart in index.wxml
- Call the api of the applet, previewImage
// pages/goods_detail/index.js //The method for sending requests is introduced to optimize the import { request } from "../../request/index.js" Page({ /** * Initial data of the page */ data: { //The data returned by the request is in the form of an object goodsObj: {} }, //Global variable that defines the large image information array to preview goodsInfo: {}, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { //The product id passed when getting the jump page const { goods_id } = options; this.getGoodsDetail(goods_id); }, /** * Get product details data */ async getGoodsDetail(goods_id) { const goodsObj = await request({ url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/detail", data: { goods_id } }); //Assign a value to the previously defined preview large image array after the request is successful this.goodsInfo=goodsObj.data.message; this.setData({ // Optimize the storage data, and only assign and store the data used by the applet goodsObj: { goods_name: goodsObj.data.message.goods_name, goods_price: goodsObj.data.message.goods_price, // Some iphone phones do not support webp format // Background modification // Or use the replace function for temporary modification, where \. webp is the file to find all. webp, g means select all, and. jpg means replace all with. jpg format. goods_introduce: goodsObj.data.message.goods_introduce.replace(/\.webp/g, '.jpg'), pics: goodsObj.data.message.pics }, }) }, /** * Click the carousel to preview the large picture event */ handlePrevewImage(e) { console.log('preview'); // First build an array of pictures to preview const urls=this.goodsInfo.pics.map(v=>v.pics_mid) // Accept the passed image url const current = e.currentTarget.dataset.url wx.previewImage({ current: current, urls: urls }) }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
<!--pages/goods_detail/index.wxml--> <view class="detail_swiper"> <!-- Content of rotation chart,bindtap Bind a preview big picture event --> <swiper autoplay="true" circular="true" indicator-dots="true" bindtap="handlePrevewImage" data-url="{{item.pics_mid}}"> <swiper-item wx:for="{{goodsObj.pics}}" wx:key="pics_id"> <image mode="widthFix" src="{{item.pics_mid}}"></image> </swiper-item> </swiper> </view> <!-- Product content text --> <!-- commodity price --> <view class="goods_price">¥{{goodsObj.goods_price}}</view> <view class="goods_name_row"> <!-- Commodity name --> <view class="goods_name">{{goodsObj.goods_name}}</view> <!-- Collect goods --> <view class="goods_collect"> <!-- The collection icons here are imported from Ali icon library --> <text class="iconfont icon-shoucang"></text> <view class="collect_text">Collection</view> </view> </view> <!-- Graphic details --> <view class="goods_info"> <view class="goods_info_title">Graphic details</view> <view class="goods_info_content"> <!-- Rich text rendering --> <rich-text nodes="{{goodsObj.goods_introduce}}"></rich-text> </view> </view>
The effect is as follows
Toolbar at the bottom of the item details page
The customer service, sharing and other functions in the bottom navigation bar can respond after clicking. Depending on the openness of the applet, you can find relevant instructions in the documents on the official website. At the same time, the buttons are cleverly hidden at the bottom of these two tags. In fact, when we click customer service and analysis, we click the hidden buttons. We also realized clicking the shopping cart icon to jump to the cart shopping cart page.
Note: navigator is a hyperlink like tag. It jumps in the navigator mode by default, but it cannot jump to tabbar (navigation bar page), so we use open type = "switchtab" to jump.
<!--pages/goods_detail/index.wxml--> <view class="detail_swiper"> <!-- Content of rotation chart,bindtap Bind a preview big picture event --> <swiper autoplay="true" circular="true" indicator-dots="true" bindtap="handlePrevewImage" data-url="{{item.pics_mid}}"> <swiper-item wx:for="{{goodsObj.pics}}" wx:key="pics_id"> <image mode="widthFix" src="{{item.pics_mid}}"></image> </swiper-item> </swiper> </view> <!-- Product content text --> <!-- commodity price --> <view class="goods_price">¥{{goodsObj.goods_price}}</view> <view class="goods_name_row"> <!-- Commodity name --> <view class="goods_name">{{goodsObj.goods_name}}</view> <!-- Collect goods --> <view class="goods_collect"> <!-- The collection icons here are imported from Ali icon library --> <text class="iconfont icon-shoucang"></text> <view class="collect_text">Collection</view> </view> </view> <!-- Graphic details --> <view class="goods_info"> <view class="goods_info_title">Graphic details</view> <view class="goods_info_content"> <!-- Rich text rendering --> <rich-text nodes="{{goodsObj.goods_introduce}}"></rich-text> </view> </view> <!-- Bottom navigation bar --> <view class="btm_tool"> <!-- customer service --> <view class="tool_item"> <view class="iconfont icon-kefu"></view> <view>customer service</view> <!-- Add the function of contacting customer service ,Hidden in the lower layer of customer service, the transparency is 0. Set its height and width to be consistent with that of customer service--> <button open-type="contact"></button> </view> <!-- share --> <view class="tool_item"> <view class="iconfont icon-fenxiang"></view> <view>share</view> <button open-type="share"></button> </view> <!-- Shopping Cart --> <!-- switchTab Allow jump tabBar(Navigation bar) page --> <navigator open-type="switchTab" url="/pages/cart/index" class="tool_item"> <view class="tool_item"> <view class="iconfont icon-gouwuche"></view> <view>Shopping Cart</view> </view> </navigator> <!-- add to cart --> <view class="tool_item btn_cart"> <view class="">add to cart</view> </view> <!-- Buy now --> <view class="tool_item btn_buy"> <view>Buy now</view> </view> </view>
/* pages/goods_detail/index.wxss */ /* Prevent the added fixed navigation bar from blocking part of the page content when the page slides to the bottom, Here, 90rpx is expanded at the bottom of the setup page to fix the navigation bar */ page{ padding-bottom: 90rpx; } .detail_swiper swiper { height: 70vw; text-align: center; } .detail_swiper image { width: 60%; } .goods_price { padding: 15rpx; font-size: 32rpx; font-weight: 600; color: var(--themColor); } .goods_name_row { display: flex; border-top: 5rpx solid #dedede; border-bottom: 5rpx solid #dedede; padding: 10rpx 0; } .goods_name_row .goods_collect { flex: 1; display: flex; /* The spindle direction becomes the up and down (vertical axis) direction */ flex-direction: column; justify-content: center; align-items: center; border-left: 1rpx solid #000; } .goods_name_row .goods_name { flex: 5; color: #000; font-size: 28rpx; padding: 0 10rpx; /* When the text exceeds a lot, use ellipsis to replace the extra text */ display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2; } .goods_info_title { font-size: 32rpx; color: var(--themColor); font-weight: 600; padding: 20rpx; } .btm_tool { /* position Add fixed positioning, fixed in the page */ position: fixed; left: 0; bottom: 0; width: 100%; height: 90rpx; background-color: #fff; display: flex; } .btm_tool .tool_item { border-top: 1rpx solid #ccc; flex:1; display: flex; /* Change the spindle direction to the up and down direction */ flex-direction: column; /* Vertical and horizontal centering */ justify-content: center; text-align: center; font-size: 24rpx; /* Relative positioning of parent style */ position: relative; } .btm_tool .tool_item button{ /* Sub style absolute positioning */ position: absolute; top: 0; left: 0; width: 100%; height: 100%; /* transparency */ opacity: 0; } .btn_cart { flex: 2; background-color: #ffa500; color: #fff; font-size: 28rpx; font-weight: 600; } .btn_buy { flex: 2; background-color: var(--themColor); color: #fff; font-size: 28rpx; font-weight: 600; }
The effect is as follows
Add to cart on product details page
On the product details page, after viewing a product, click Add to the shopping cart to realize the add function. The implementation steps are as follows
- Bind click event first
- Get the shopping cart data in the cache in array format
- Judge whether the current item already exists in the shopping cart
- If it exists, modify the commodity data and add one to the quantity of the commodity in the shopping cart
- Fill (update) the array of the current shopping cart into the cache
- If it does not exist, add a new element directly to the shopping cart array
- Fill the current shopping cart data into the cache
- Pop up some tips
The code is as follows, or in goods_ Modify index.wxml and index.js in the detail folder
<!--pages/goods_detail/index.wxml--> <view class="detail_swiper"> <!-- Content of rotation chart,bindtap Bind a preview big picture event --> <swiper autoplay="true" circular="true" indicator-dots="true" bindtap="handlePrevewImage" data-url="{{item.pics_mid}}"> <swiper-item wx:for="{{goodsObj.pics}}" wx:key="pics_id"> <image mode="widthFix" src="{{item.pics_mid}}"></image> </swiper-item> </swiper> </view> <!-- Product content text --> <!-- commodity price --> <view class="goods_price">¥{{goodsObj.goods_price}}</view> <view class="goods_name_row"> <!-- Commodity name --> <view class="goods_name">{{goodsObj.goods_name}}</view> <!-- Collect goods --> <view class="goods_collect"> <!-- The collection icons here are imported from Ali icon library --> <text class="iconfont icon-shoucang"></text> <view class="collect_text">Collection</view> </view> </view> <!-- Graphic details --> <view class="goods_info"> <view class="goods_info_title">Graphic details</view> <view class="goods_info_content"> <!-- Rich text rendering --> <rich-text nodes="{{goodsObj.goods_introduce}}"></rich-text> </view> </view> <!-- Bottom navigation bar --> <view class="btm_tool"> <!-- customer service --> <view class="tool_item"> <view class="iconfont icon-kefu"></view> <view>customer service</view> <!-- Add the function of contacting customer service ,Hidden in the lower layer of customer service, the transparency is 0. Set its height and width to be consistent with that of customer service--> <button open-type="contact"></button> </view> <!-- share --> <view class="tool_item"> <view class="iconfont icon-fenxiang"></view> <view>share</view> <button open-type="share"></button> </view> <!-- Shopping Cart --> <!-- switchTab Allow jump tabBar(Navigation bar) page --> <navigator open-type="switchTab" url="/pages/cart/index" class="tool_item"> <view class="tool_item"> <view class="iconfont icon-gouwuche"></view> <view>Shopping Cart</view> </view> </navigator> <!-- add to cart --> <!-- Add click event and product response --> <view class="tool_item btn_cart" bindtap="handleCartAdd"> <view>add to cart</view> </view> <!-- Buy now --> <view class="tool_item btn_buy"> <view>Buy now</view> </view> </view>
// pages/goods_detail/index.js //The method for sending requests is introduced to optimize the import { request } from "../../request/index.js" Page({ /** * Initial data of the page */ data: { //The data returned by the request is in the form of an object goodsObj: {} }, //Global variable that defines the large image information array to preview goodsInfo: {}, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { //The product id passed when getting the jump page const { goods_id } = options; this.getGoodsDetail(goods_id); }, /** * Get product details data */ async getGoodsDetail(goods_id) { const goodsObj = await request({ url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/detail", data: { goods_id } }); //Assign a value to the previously defined preview large image array after the request is successful this.goodsInfo = goodsObj.data.message; this.setData({ // Optimize the storage data, and only assign and store the data used by the applet goodsObj: { goods_name: goodsObj.data.message.goods_name, goods_price: goodsObj.data.message.goods_price, // Some iphone phones do not support webp format // Background modification // Or use the replace function for temporary modification, where \. webp is the file to find all. webp, g means select all, and. jpg means replace all with. jpg format. goods_introduce: goodsObj.data.message.goods_introduce.replace(/\.webp/g, '.jpg'), pics: goodsObj.data.message.pics }, }) }, /** * Click the carousel to preview the large picture event */ handlePrevewImage(e) { console.log('preview'); // First build an array of pictures to preview const urls = this.goodsInfo.pics.map(v => v.pics_mid) // Accept the passed image url const current = e.currentTarget.dataset.url wx.previewImage({ current: current, urls: urls }) }, /** * Event triggered when a user item is added to the shopping cart */ handleCartAdd(e) { //Get the cached commodity data and convert it from string format to array format let cart=wx.getStorageSync('cart')||[]; // Determine whether the item already exists in the shopping cart array let index=cart.findIndex(v=>v.goods_id===this.goodsInfo.goods_id); if(index===-1){ //Does not exist, added for the first time this.goodsInfo.num=1; cart.push(this.goodsInfo); }else{ //existence cart[index].num++; } //The shopping cart array is updated to the cache wx.setStorageSync("cart",cart); //Pop up prompt wx.showToast({ title: 'Added successfully', icon:'success', mask:'true' }) }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
Shopping cart content page
After clicking Add to the shopping cart, the goods will be added to the shopping cart, and then click the shopping cart to enter the shopping cart content page. This page corresponds to the cart folder. First, modify the page title and modify the code in the index.json file under the cart folder
{ "usingComponents": {}, "navigationBarTitleText": "Shopping Cart" }
Then start writing the relevant page structure and modify the code in index.wxml.
<!--pages/cart/index.wxml--> <!-- Receiving address container --> <view class="receive_address"> <!-- Receiving address button --> <!-- wx:if Judge whether the user name in the address exists,Show when not present --> <view class="address" wx:if="{{!address.userName}}"> <!-- plain Indicates whether the button is hollow and the background color is transparent --> <!-- Bind the click event to obtain the receiving address --> <button type="primary" plain="true" bindtap="handleChooseAddress">Add receiving address</button> </view> <!-- When the receiving address user name exists, that is, there is a receiving address --> <view wx:else class="user_info_row"> <view class="user_info"> <view> {{address.userName}}</view> <view>{{address.all}}</view> </view> <view class="user_phone"> {{address.telNumber}} </view> </view> </view> <!-- Shopping cart details --> <view class="cart_content"> <view class="cart_title">Shopping Cart</view> <view class="cart_main"> <view class="cart_item"> <!-- Check box structure --> <view class="cart_checkbox"> <checkbox-group bindchange=""> <checkbox></checkbox> </checkbox-group> </view> <!-- Product picture --> <navigator class="cart_image"> <image mode="widthFix" src="http://image2.suning.cn/uimg/b2c/newcatentries/0000000000-000000000178667792_2_800x800.jpg"> </image> </navigator> <!-- Commodity information --> <view class="cart_info"> <view class="goods_name">TCL 65Q960C 65 4 inch Harman Caton artificial intelligence metal ultra thin 64 bit 34 core K+HDR Primary color quantum dot curved surface TV (gray)</view> <view class="goods_price_wrap"> <view class="goods_price">¥999</view> <view class="cart_num_tool"> <view class="num_edit">-</view> <view class="goods_nums">1</view> <view class="num_edit">+</view> </view> </view> </view> </view> </view> </view> <!-- Bottom navigation bar --> <view class="footer_tool"> <!-- Select all --> <view class="all_check_wrap"> <checkbox-group> <checkbox>Select all</checkbox> </checkbox-group> </view> <!-- Total price --> <view class="total_price_wrap"> <view class="total_price"> total:<text class="total_price_number">¥999</text> </view> <view>Including freight</view> </view> <!-- settlement --> <view class="order_pay_wrap">settlement(1)</view> </view>
Style file
/* pages/cart/index.wxss */ page{ padding-bottom: 90rpx; } .address { padding: 20rpx; } .address button { width: 60%; } .user_info_row { display: flex; padding: 20rpx; } .user_info { flex: 5; } .user_phone { flex: 2; text-align: center; justify-content: center; } .cart_title { padding: 20rpx; font-size: 36rpx; color: var(--themColor); border-top: 1rpx solid currentColor; border-bottom: 1rpx solid currentColor; } .cart_item { display: flex; } .cart_item .cart_checkbox { flex: 1; display: flex; justify-content: center; align-items: center; } .cart_item .cart_checkbox checkbox-group { display: flex; } .cart_item .cart_image { flex: 2; display: flex; justify-content: center; align-items: center; } .cart_image image { width: 80%; } .cart_info { flex: 4; display: flex; justify-content: space-around; flex-direction: column; } .cart_info .goods_name { display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2; color: #666; } .cart_info .goods_price_wrap { display: flex; justify-content: space-between; } .goods_price { color: var(--themColor); font-size: 34rpx; } .cart_num_tool { display: flex; } .num_edit { width: 55rpx; height: 55rpx; display: flex; justify-content: center; align-items: center; border: 1rpx solid #ccc; } .goods_nums { width: 55rpx; height: 55rpx; display: flex; justify-content: center; align-items: center; } .footer_tool{ position: fixed; bottom: 0; left: 0; width: 100%; height: 90rpx; background-color: #fff; display: flex; border-top: 1rpx solid #ccc; } .all_check_wrap{ flex: 2; display: flex; justify-content: center; align-items: center; } .total_price_wrap{ flex: 4; padding-right: 15rpx; /* Align text right */ text-align: right; } .total_price_number{ color: var(--themColor); font-size: 34rpx; font-weight: 600; } .order_pay_wrap{ flex: 2; background-color: var(--themColor); color: #fff; font-size: 32rpx; font-weight: 600; display: flex; justify-content: center; align-items: center; }
Now the static display of a shopping cart page is ready
Dynamic data update of shopping cart page
The onShow function in the index.js file needs to get the shopping cart array in the cache, and then update the shopping cart array to data.
// pages/cart/index.js Page({ // Click to get receiving address event // 1. Bind click event // 2. Call the API in the applet, "Wx. Chooseaddress", to obtain the receiving address of the user // Shopping cart page loaded // 1. Obtain the receiving address data in the local storage // 2. If there is storage, set the data to a variable in data handleChooseAddress(e) { wx.chooseAddress({ success: (result) => { // Store the obtained address into the local cache, and splice the address before storage result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo; console.log(result); wx.setStorageSync('address', result) }, }); }, /** * Initial data of the page */ data: { address: {}, //Declare a variable, shopping cart array cart:[] }, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { //Get shopping cart data in cache const cart=wx.getStorageSync('cart') //Get the receiving address information in the cache const address = wx.getStorageSync('address'); //Assign value to data this.setData({ address, cart:cart }) }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
<!--pages/cart/index.wxml--> <!-- Receiving address container --> <view class="receive_address"> <!-- Receiving address button --> <!-- wx:if Judge whether the user name in the address exists,Show when not present --> <view class="address" wx:if="{{!address.userName}}"> <!-- plain Indicates whether the button is hollow and the background color is transparent --> <!-- Bind the click event to obtain the receiving address --> <button type="primary" plain="true" bindtap="handleChooseAddress">Add receiving address</button> </view> <!-- When the receiving address user name exists, that is, there is a receiving address --> <view wx:else class="user_info_row"> <view class="user_info"> <view> {{address.userName}}</view> <view>{{address.all}}</view> </view> <view class="user_phone"> {{address.telNumber}} </view> </view> </view> <!-- Shopping cart details --> <view class="cart_content"> <view class="cart_title">Shopping Cart</view> <view class="cart_main"> <view class="cart_item" wx:for="{{cart}}" wx:key="goods_id"> <!-- Check box structure --> <view class="cart_checkbox"> <checkbox-group bindchange=""> <checkbox></checkbox> </checkbox-group> </view> <!-- Product picture --> <navigator class="cart_image"> <image mode="widthFix" src="{{item.goods_small_logo}}"> </image> </navigator> <!-- Commodity information --> <view class="cart_info"> <view class="goods_name">{{item.goods_name}}</view> <view class="goods_price_wrap"> <view class="goods_price">{{item.goods_price}}</view> <view class="cart_num_tool"> <view class="num_edit">-</view> <view class="goods_nums">{{item.num}}</view> <view class="num_edit">+</view> </view> </view> </view> </view> </view> </view> <!-- Bottom navigation bar --> <view class="footer_tool"> <!-- Select all --> <view class="all_check_wrap"> <checkbox-group> <checkbox>Select all</checkbox> </checkbox-group> </view> <!-- Total price --> <view class="total_price_wrap"> <view class="total_price"> total:<text class="total_price_number">¥999</text> </view> <view>Including freight</view> </view> <!-- settlement --> <view class="order_pay_wrap">settlement(1)</view> </view>
The effect is as follows
The next step is to select the goods added to the shopping cart by default, and the check box is selected. In goods_ Modify index.js in the detail folder.
// pages/goods_detail/index.js //The method for sending requests is introduced to optimize the import { request } from "../../request/index.js" Page({ /** * Initial data of the page */ data: { //The data returned by the request is in the form of an object goodsObj: {} }, //Global variable that defines the large image information array to preview goodsInfo: {}, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { //The product id passed when getting the jump page const { goods_id } = options; this.getGoodsDetail(goods_id); }, /** * Get product details data */ async getGoodsDetail(goods_id) { const goodsObj = await request({ url: "https://api-hmugo-web.itheima.net/api/public/v1/goods/detail", data: { goods_id } }); //Assign a value to the previously defined preview large image array after the request is successful this.goodsInfo = goodsObj.data.message; this.setData({ // Optimize the storage data, and only assign and store the data used by the applet goodsObj: { goods_name: goodsObj.data.message.goods_name, goods_price: goodsObj.data.message.goods_price, // Some iphone phones do not support webp format // Background modification // Or use the replace function for temporary modification, where \. webp is the file to find all. webp, g means select all, and. jpg means replace all with. jpg format. goods_introduce: goodsObj.data.message.goods_introduce.replace(/\.webp/g, '.jpg'), pics: goodsObj.data.message.pics }, }) }, /** * Click the carousel to preview the large picture event */ handlePrevewImage(e) { console.log('preview'); // First build an array of pictures to preview const urls = this.goodsInfo.pics.map(v => v.pics_mid) // Accept the passed image url const current = e.currentTarget.dataset.url wx.previewImage({ current: current, urls: urls }) }, /** * Event triggered when a user item is added to the shopping cart */ handleCartAdd(e) { //Get the cached commodity data and convert it from string format to array format let cart=wx.getStorageSync('cart')||[]; // Determine whether the item already exists in the shopping cart array let index=cart.findIndex(v=>v.goods_id===this.goodsInfo.goods_id); if(index===-1){ //Does not exist, added for the first time this.goodsInfo.num=1; // Add a checked attribute to the product, with the value of true, so that it can be selected in the check box on the shopping cart page this.goodsInfo.checked=true; cart.push(this.goodsInfo); }else{ //existence cart[index].num++; } //The shopping cart array is updated to the cache wx.setStorageSync("cart",cart); //Pop up prompt wx.showToast({ title: 'Added successfully', icon:'success', mask:'true' }) }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
Then add attributes to the checkbox tag in index.wxml under the cart folder.
<!--pages/cart/index.wxml--> <!-- Receiving address container --> <view class="receive_address"> <!-- Receiving address button --> <!-- wx:if Judge whether the user name in the address exists,Show when not present --> <view class="address" wx:if="{{!address.userName}}"> <!-- plain Indicates whether the button is hollow and the background color is transparent --> <!-- Bind the click event to obtain the receiving address --> <button type="primary" plain="true" bindtap="handleChooseAddress">Add receiving address</button> </view> <!-- When the receiving address user name exists, that is, there is a receiving address --> <view wx:else class="user_info_row"> <view class="user_info"> <view> {{address.userName}}</view> <view>{{address.all}}</view> </view> <view class="user_phone"> {{address.telNumber}} </view> </view> </view> <!-- Shopping cart details --> <view class="cart_content"> <view class="cart_title">Shopping Cart</view> <view class="cart_main"> <view class="cart_item" wx:for="{{cart}}" wx:key="goods_id"> <!-- Check box structure --> <view class="cart_checkbox"> <checkbox-group bindchange=""> <checkbox checked="{{item.checked}}"></checkbox> </checkbox-group> </view> <!-- Product picture --> <navigator class="cart_image"> <image mode="widthFix" src="{{item.goods_small_logo}}"> </image> </navigator> <!-- Commodity information --> <view class="cart_info"> <view class="goods_name">{{item.goods_name}}</view> <view class="goods_price_wrap"> <view class="goods_price">{{item.goods_price}}</view> <view class="cart_num_tool"> <view class="num_edit">-</view> <view class="goods_nums">{{item.num}}</view> <view class="num_edit">+</view> </view> </view> </view> </view> </view> </view> <!-- Bottom navigation bar --> <view class="footer_tool"> <!-- Select all --> <view class="all_check_wrap"> <checkbox-group> <checkbox>Select all</checkbox> </checkbox-group> </view> <!-- Total price --> <view class="total_price_wrap"> <view class="total_price"> total:<text class="total_price_number">¥999</text> </view> <view>Including freight</view> </view> <!-- settlement --> <view class="order_pay_wrap">settlement(1)</view> </view>
The effect is as follows
Next is the implementation of select all in the bottom navigation bar and the dynamic update of data. The steps are as follows
1. Get the shopping cart array in the cache in Onshow
2. According to the commodity data in the shopping cart, when all commodities are selected, select all is selected, one is not selected, and the select all button is not selected.
3. Calculate the total price and total quantity only when the commodity is selected.
4. Get shopping cart array in cache
5. Traversal
6. Total price = unit price of goods * quantity of goods
7. Total quantity = cumulative quantity of all commodities
8. Update the calculated price quantity to data.
// pages/cart/index.js Page({ // Click to get receiving address event // 1. Bind click event // 2. Call the API in the applet, "Wx. Chooseaddress", to obtain the receiving address of the user // Shopping cart page loaded // 1. Obtain the receiving address data in the local storage // 2. If there is storage, set the data to a variable in data handleChooseAddress(e) { wx.chooseAddress({ success: (result) => { // Store the obtained address into the local cache, and splice the address before storage result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo; console.log(result); wx.setStorageSync('address', result) }, }); }, /** * Initial data of the page */ data: { address: {}, //Declare a variable, shopping cart array cart:[], // Declare a variable, whether to select all the contents of the shopping cart allChecked:false, // Define total price and total quantity of goods totalPrice:0, totalNum:0 }, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { //Get shopping cart data in cache const cart=wx.getStorageSync('cart') // Calculate whether to select all shopping cart items // The every array method will traverse and receive callback functions, so each callback function will return true, and the return value of the every method will be true // As long as a callback function returns false, it will not execute circularly and return false directly // If it is an empty array, then every returns true, so a ternary expression is used const allChecked=cart.length?cart.every(v=>v.checked):false; //Get the receiving address information in the cache const address = wx.getStorageSync('address'); // Declare total price and total quantity let totalPrice=0; let totalNum=0; cart.forEach(v=>{ if(v.checked){ totalPrice+=v.num*v.goods_price; totalNum+=v.num; } }) //Assign value to data this.setData({ address, cart:cart, allChecked, totalPrice, totalNum }) }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
<!--pages/cart/index.wxml--> <!-- Receiving address container --> <view class="receive_address"> <!-- Receiving address button --> <!-- wx:if Judge whether the user name in the address exists,Show when not present --> <view class="address" wx:if="{{!address.userName}}"> <!-- plain Indicates whether the button is hollow and the background color is transparent --> <!-- Bind the click event to obtain the receiving address --> <button type="primary" plain="true" bindtap="handleChooseAddress">Add receiving address</button> </view> <!-- When the receiving address user name exists, that is, there is a receiving address --> <view wx:else class="user_info_row"> <view class="user_info"> <view> {{address.userName}}</view> <view>{{address.all}}</view> </view> <view class="user_phone"> {{address.telNumber}} </view> </view> </view> <!-- Shopping cart details --> <view class="cart_content"> <view class="cart_title">Shopping Cart</view> <view class="cart_main"> <view class="cart_item" wx:for="{{cart}}" wx:key="goods_id"> <!-- Check box structure --> <view class="cart_checkbox"> <checkbox-group bindchange=""> <checkbox checked="{{item.checked}}"></checkbox> </checkbox-group> </view> <!-- Product picture --> <navigator class="cart_image"> <image mode="widthFix" src="{{item.goods_small_logo}}"> </image> </navigator> <!-- Commodity information --> <view class="cart_info"> <view class="goods_name">{{item.goods_name}}</view> <view class="goods_price_wrap"> <view class="goods_price">{{item.goods_price}}</view> <view class="cart_num_tool"> <view class="num_edit">-</view> <view class="goods_nums">{{item.num}}</view> <view class="num_edit">+</view> </view> </view> </view> </view> </view> </view> <!-- Bottom navigation bar --> <view class="footer_tool"> <!-- Select all --> <view class="all_check_wrap"> <checkbox-group> <checkbox checked="{{allChecked}}">Select all</checkbox> </checkbox-group> </view> <!-- Total price --> <view class="total_price_wrap"> <view class="total_price"> total:<text class="total_price_number">¥{{totalPrice}}</text> </view> <view>Including freight</view> </view> <!-- settlement --> <view class="order_pay_wrap">settlement({{totalNum}})</view> </view>
The effect is as follows
Shopping cart item quantity and selected function optimization
Optimization of selected functions of goods
1. Bind change event
2. Get the modified commodity object
3. The selected status of the commodity object is reversed
4. Refill data and cache
5. Recalculate select all. Total price total quantity
// pages/cart/index.js Page({ /** * Encapsulate a function to recalculate the bottom toolbar, total price and total quantity while setting the commodity status of the shopping cart */ setCart(cart) { let allChecked = true; // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } else { allChecked = false; } }) //Determine whether the array is empty allChecked = cart.length != 0 ? allChecked : false; this.setData({ cart, totalPrice, totalNum, allChecked }); wx.setStorageSync('cart', cart); }, // Click to get receiving address event // 1. Bind click event // 2. Call the API in the applet, "Wx. Chooseaddress", to obtain the receiving address of the user // Shopping cart page loaded // 1. Obtain the receiving address data in the local storage // 2. If there is storage, set the data to a variable in data handleChooseAddress(e) { wx.chooseAddress({ success: (result) => { // Store the obtained address into the local cache, and splice the address before storage result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo; console.log(result); wx.setStorageSync('address', result) }, }); }, // Selected optimization event for a product handleItemChange(e) { //Get the modified product id const goods_id = e.currentTarget.dataset.id; // Get shopping cart array let { cart } = this.data; //Find the item object to be modified in the shopping cart array let index = cart.findIndex(v => v.goods_id === goods_id); // Modify the selected status of the commodity object and invert it cart[index].checked = !cart[index].checked; // Update the data to the data and cache, and recalculate the total price and total quantity by calling the encapsulated function setCart this.setCart(cart); }, /** * Initial data of the page */ data: { address: {}, //Declare a variable, shopping cart array cart: [], // Declare a variable, whether to select all the contents of the shopping cart allChecked: false, // Define total price and total quantity of goods totalPrice: 0, totalNum: 0 }, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { //Get shopping cart data in cache const cart = wx.getStorageSync('cart') // Calculate whether to select all shopping cart items // The every array method will traverse and receive callback functions, so each callback function will return true, and the return value of the every method will be true // As long as a callback function returns false, it will not execute circularly and return false directly // If it is an empty array, then every returns true, so a ternary expression is used const allChecked = cart.length ? cart.every(v => v.checked) : false; //Get the receiving address information in the cache const address = wx.getStorageSync('address'); // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } }) //Assign value to data this.setData({ address, cart: cart, allChecked, totalPrice, totalNum }) }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
<!--pages/cart/index.wxml--> <!-- Receiving address container --> <view class="receive_address"> <!-- Receiving address button --> <!-- wx:if Judge whether the user name in the address exists,Show when not present --> <view class="address" wx:if="{{!address.userName}}"> <!-- plain Indicates whether the button is hollow and the background color is transparent --> <!-- Bind the click event to obtain the receiving address --> <button type="primary" plain="true" bindtap="handleChooseAddress">Add receiving address</button> </view> <!-- When the receiving address user name exists, that is, there is a receiving address --> <view wx:else class="user_info_row"> <view class="user_info"> <view> {{address.userName}}</view> <view>{{address.all}}</view> </view> <view class="user_phone"> {{address.telNumber}} </view> </view> </view> <!-- Shopping cart details --> <view class="cart_content"> <view class="cart_title">Shopping Cart</view> <view class="cart_main"> <view class="cart_item" wx:for="{{cart}}" wx:key="goods_id"> <!-- Check box structure --> <view class="cart_checkbox"> <checkbox-group data-id="{{item.goods_id}}" bindchange="handleItemChange"> <checkbox checked="{{item.checked}}"></checkbox> </checkbox-group> </view> <!-- Product picture --> <navigator class="cart_image"> <image mode="widthFix" src="{{item.goods_small_logo}}"> </image> </navigator> <!-- Commodity information --> <view class="cart_info"> <view class="goods_name">{{item.goods_name}}</view> <view class="goods_price_wrap"> <view class="goods_price">{{item.goods_price}}</view> <view class="cart_num_tool"> <view class="num_edit">-</view> <view class="goods_nums">{{item.num}}</view> <view class="num_edit">+</view> </view> </view> </view> </view> </view> </view> <!-- Bottom navigation bar --> <view class="footer_tool"> <!-- Select all --> <view class="all_check_wrap"> <checkbox-group> <checkbox checked="{{allChecked}}">Select all</checkbox> </checkbox-group> </view> <!-- Total price --> <view class="total_price_wrap"> <view class="total_price"> total:<text class="total_price_number">¥{{totalPrice}}</text> </view> <view>Including freight</view> </view> <!-- settlement --> <view class="order_pay_wrap">settlement({{totalNum}})</view> </view>
The effect is as follows
Next, click the select all button on the shopping cart page to select all products on the page. The steps are as follows
1 select all checkbox to bind event change
2 get the all selected variable allChecked in data
3 directly invert allchecked =! allChecked
4 traverse the shopping cart array so that the selected status of the goods in it changes with the change of allChecked
5 reset the shopping cart array and allChecked back to data, and reset the shopping cart back to the cache
// pages/cart/index.js Page({ /** * Encapsulate a function to recalculate the bottom toolbar, total price and total quantity while setting the commodity status of the shopping cart */ setCart(cart) { let allChecked = true; // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } else { allChecked = false; } }) //Determine whether the array is empty allChecked = cart.length != 0 ? allChecked : false; this.setData({ cart, totalPrice, totalNum, allChecked }); wx.setStorageSync('cart', cart); }, // Click to get receiving address event // 1. Bind click event // 2. Call the API in the applet, "Wx. Chooseaddress", to obtain the receiving address of the user // Shopping cart page loaded // 1. Obtain the receiving address data in the local storage // 2. If there is storage, set the data to a variable in data handleChooseAddress(e) { wx.chooseAddress({ success: (result) => { // Store the obtained address into the local cache, and splice the address before storage result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo; console.log(result); wx.setStorageSync('address', result) }, }); }, // Selected optimization event for a product handleItemChange(e) { //Get the modified product id const goods_id = e.currentTarget.dataset.id; // Get shopping cart array let { cart } = this.data; //Find the item object to be modified in the shopping cart array let index = cart.findIndex(v => v.goods_id === goods_id); // Modify the selected status of the commodity object and invert it cart[index].checked = !cart[index].checked; // Update the data to the data and cache, and recalculate the total price and total quantity by calling the encapsulated function setCart this.setCart(cart); }, //Select all of products handleItemAllChecked(e) { // 1 get the data in data let { cart, allChecked } = this.data; // 2 modify value allChecked = !allChecked; // 3 cycle to modify the selected status of goods in the cart array cart.forEach(v => v.checked = allChecked); // 4 fill the modified value back into the data or cache, and call the encapsulated function this.setCart(cart); }, /** * Initial data of the page */ data: { address: {}, //Declare a variable, shopping cart array cart: [], // Declare a variable, whether to select all the contents of the shopping cart allChecked: false, // Define total price and total quantity of goods totalPrice: 0, totalNum: 0 }, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { //Get shopping cart data in cache const cart = wx.getStorageSync('cart') // Calculate whether to select all shopping cart items // The every array method will traverse and receive callback functions, so each callback function will return true, and the return value of the every method will be true // As long as a callback function returns false, it will not execute circularly and return false directly // If it is an empty array, then every returns true, so a ternary expression is used const allChecked = cart.length ? cart.every(v => v.checked) : false; //Get the receiving address information in the cache const address = wx.getStorageSync('address'); // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } }) //Assign value to data this.setData({ address, cart: cart, allChecked, totalPrice, totalNum }) }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
<!--pages/cart/index.wxml--> <!-- Receiving address container --> <view class="receive_address"> <!-- Receiving address button --> <!-- wx:if Judge whether the user name in the address exists,Show when not present --> <view class="address" wx:if="{{!address.userName}}"> <!-- plain Indicates whether the button is hollow and the background color is transparent --> <!-- Bind the click event to obtain the receiving address --> <button type="primary" plain="true" bindtap="handleChooseAddress">Add receiving address</button> </view> <!-- When the receiving address user name exists, that is, there is a receiving address --> <view wx:else class="user_info_row"> <view class="user_info"> <view> {{address.userName}}</view> <view>{{address.all}}</view> </view> <view class="user_phone"> {{address.telNumber}} </view> </view> </view> <!-- Shopping cart details --> <view class="cart_content"> <view class="cart_title">Shopping Cart</view> <view class="cart_main"> <view class="cart_item" wx:for="{{cart}}" wx:key="goods_id"> <!-- Check box structure --> <view class="cart_checkbox"> <checkbox-group data-id="{{item.goods_id}}" bindchange="handleItemChange"> <checkbox checked="{{item.checked}}"></checkbox> </checkbox-group> </view> <!-- Product picture --> <navigator class="cart_image"> <image mode="widthFix" src="{{item.goods_small_logo}}"> </image> </navigator> <!-- Commodity information --> <view class="cart_info"> <view class="goods_name">{{item.goods_name}}</view> <view class="goods_price_wrap"> <view class="goods_price">{{item.goods_price}}</view> <view class="cart_num_tool"> <view class="num_edit">-</view> <view class="goods_nums">{{item.num}}</view> <view class="num_edit">+</view> </view> </view> </view> </view> </view> </view> <!-- Bottom navigation bar --> <view class="footer_tool"> <!-- Select all --> <view class="all_check_wrap"> <checkbox-group bindchange="handleItemAllChecked"> <checkbox checked="{{allChecked}}">Select all</checkbox> </checkbox-group> </view> <!-- Total price --> <view class="total_price_wrap"> <view class="total_price"> total:<text class="total_price_number">¥{{totalPrice}}</text> </view> <view>Including freight</view> </view> <!-- settlement --> <view class="order_pay_wrap">settlement({{totalNum}})</view> </view>
The final effect is as follows. Each time you click the select all button, all the above commodities will be selected or not selected.
Shopping cart page, addition and subtraction of the quantity of a single item
Click the plus or minus button after a single commodity, the quantity of the commodity will change, and the total quantity and total price will change. The steps are as follows
- The "+" and "-" buttons are bound to the same click event. The key to distinguish is that the "+" sign of the user-defined attribute is defined as "+ 1" and the "-" sign is defined as "- 1".
- Pass the clicked product ID, goods__id .
- Get the shopping cart array in data to get the commodity object to be modified.
- Directly modify the quantity num of the commodity object.
- Reset the cart array back to the cache and data, and call the this. setCart that you encapsulated to calculate the total price and the total quantity.
- When the quantity is reduced to 1, click the minus sign button, and a pop-up window will prompt whether to delete the commodity. The pop-up window will prompt that there is the built-in API of the applet, wx.showModal.
// pages/cart/index.js Page({ /** * Encapsulate a function to recalculate the bottom toolbar, total price and total quantity while setting the commodity status of the shopping cart */ setCart(cart) { let allChecked = true; // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } else { allChecked = false; } }) //Determine whether the array is empty allChecked = cart.length != 0 ? allChecked : false; this.setData({ cart, totalPrice, totalNum, allChecked }); wx.setStorageSync('cart', cart); }, // Click to get receiving address event // 1. Bind click event // 2. Call the API in the applet, "Wx. Chooseaddress", to obtain the receiving address of the user // Shopping cart page loaded // 1. Obtain the receiving address data in the local storage // 2. If there is storage, set the data to a variable in data handleChooseAddress(e) { wx.chooseAddress({ success: (result) => { // Store the obtained address into the local cache, and splice the address before storage result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo; console.log(result); wx.setStorageSync('address', result) }, }); }, // Selected optimization event for a product handleItemChange(e) { //Get the modified product id const goods_id = e.currentTarget.dataset.id; // Get shopping cart array let { cart } = this.data; //Find the item object to be modified in the shopping cart array let index = cart.findIndex(v => v.goods_id === goods_id); // Modify the selected status of the commodity object and invert it cart[index].checked = !cart[index].checked; // Update the data to the data and cache, and recalculate the total price and total quantity by calling the encapsulated function setCart this.setCart(cart); }, //Select all of products handleItemAllChecked(e) { // 1 get the data in data let { cart, allChecked } = this.data; // 2 modify value allChecked = !allChecked; // 3 cycle to modify the selected status of goods in the cart array cart.forEach(v => v.checked = allChecked); // 4 fill the modified value back into the data or cache, and call the encapsulated function this.setCart(cart); }, //Commodity quantity addition and subtraction function handleItemNumEdit(e) { // 1 get the passed parameters const { operation, id } = e.currentTarget.dataset; // 2 get shopping cart array let { cart } = this.data; //3 find the index of the item to be modified const index = cart.findIndex(v => v.goods_id === id); //Determine whether to delete when the commodity quantity is less than 1 if(cart[index].num===1&&operation===-1){ wx.showModal({ title: 'Tips', content: 'Do you want to delete this item?', success:(res)=>{ if (res.confirm) { cart.splice(index,1); this.setCart(cart); } else if (res.cancel) { console.log('The user clicks cancel'); } } }) }else{ // 4. Quantity to be modified cart[index].num += operation; // 5 set back to cache and data this.setCart(cart);} }, /** * Initial data of the page */ data: { address: {}, //Declare a variable, shopping cart array cart: [], // Declare a variable, whether to select all the contents of the shopping cart allChecked: false, // Define total price and total quantity of goods totalPrice: 0, totalNum: 0 }, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { //Get shopping cart data in cache const cart = wx.getStorageSync('cart') // Calculate whether to select all shopping cart items // The every array method will traverse and receive callback functions, so each callback function will return true, and the return value of the every method will be true // As long as a callback function returns false, it will not execute circularly and return false directly // If it is an empty array, then every returns true, so a ternary expression is used const allChecked = cart.length ? cart.every(v => v.checked) : false; //Get the receiving address information in the cache const address = wx.getStorageSync('address'); // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } }) //Assign value to data this.setData({ address, cart: cart, allChecked, totalPrice, totalNum }) }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
<!--pages/cart/index.wxml--> <!-- Receiving address container --> <view class="receive_address"> <!-- Receiving address button --> <!-- wx:if Judge whether the user name in the address exists,Show when not present --> <view class="address" wx:if="{{!address.userName}}"> <!-- plain Indicates whether the button is hollow and the background color is transparent --> <!-- Bind the click event to obtain the receiving address --> <button type="primary" plain="true" bindtap="handleChooseAddress">Add receiving address</button> </view> <!-- When the receiving address user name exists, that is, there is a receiving address --> <view wx:else class="user_info_row"> <view class="user_info"> <view> {{address.userName}}</view> <view>{{address.all}}</view> </view> <view class="user_phone"> {{address.telNumber}} </view> </view> </view> <!-- Shopping cart details --> <view class="cart_content"> <view class="cart_title">Shopping Cart</view> <view class="cart_main"> <view class="cart_item" wx:for="{{cart}}" wx:key="goods_id"> <!-- Check box structure --> <view class="cart_checkbox"> <checkbox-group data-id="{{item.goods_id}}" bindchange="handleItemChange"> <checkbox checked="{{item.checked}}"></checkbox> </checkbox-group> </view> <!-- Product picture --> <navigator class="cart_image"> <image mode="widthFix" src="{{item.goods_small_logo}}"> </image> </navigator> <!-- Commodity information --> <view class="cart_info"> <view class="goods_name">{{item.goods_name}}</view> <view class="goods_price_wrap"> <view class="goods_price">{{item.goods_price}}</view> <view class="cart_num_tool"> <view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{-1}}">-</view> <view class="goods_nums">{{item.num}}</view> <view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{1}}">+</view> </view> </view> </view> </view> </view> </view> <!-- Bottom navigation bar --> <view class="footer_tool"> <!-- Select all --> <view class="all_check_wrap"> <checkbox-group bindchange="handleItemAllChecked"> <checkbox checked="{{allChecked}}">Select all</checkbox> </checkbox-group> </view> <!-- Total price --> <view class="total_price_wrap"> <view class="total_price"> total:<text class="total_price_number">¥{{totalPrice}}</text> </view> <view>Including freight</view> </view> <!-- settlement --> <view class="order_pay_wrap">settlement({{totalNum}})</view> </view>
The effect is as follows
Effect when shopping cart page is empty and settlement button
Check the array length in the cart. If it is 0, it means there are no goods. Otherwise, it is judged that there are goods. You can do this directly by using the block tag in index.wxml.
<!--pages/cart/index.wxml--> <!-- Receiving address container --> <view class="receive_address"> <!-- Receiving address button --> <!-- wx:if Judge whether the user name in the address exists,Show when not present --> <view class="address" wx:if="{{!address.userName}}"> <!-- plain Indicates whether the button is hollow and the background color is transparent --> <!-- Bind the click event to obtain the receiving address --> <button type="primary" plain="true" bindtap="handleChooseAddress">Add receiving address</button> </view> <!-- When the receiving address user name exists, that is, there is a receiving address --> <view wx:else class="user_info_row"> <view class="user_info"> <view> {{address.userName}}</view> <view>{{address.all}}</view> </view> <view class="user_phone"> {{address.telNumber}} </view> </view> </view> <!-- Shopping cart details --> <view class="cart_content"> <view class="cart_title">Shopping Cart</view> <view class="cart_main"> <!-- When cart When the length of the array is not 0, the product information is displayed --> <block wx:if="{{cart.length!==0}}"> <view class="cart_item" wx:for="{{cart}}" wx:key="goods_id"> <!-- Check box structure --> <view class="cart_checkbox"> <checkbox-group data-id="{{item.goods_id}}" bindchange="handleItemChange"> <checkbox checked="{{item.checked}}"></checkbox> </checkbox-group> </view> <!-- Product picture --> <navigator class="cart_image"> <image mode="widthFix" src="{{item.goods_small_logo}}"> </image> </navigator> <!-- Commodity information --> <view class="cart_info"> <view class="goods_name">{{item.goods_name}}</view> <view class="goods_price_wrap"> <view class="goods_price">{{item.goods_price}}</view> <view class="cart_num_tool"> <view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{-1}}">- </view> <view class="goods_nums">{{item.num}}</view> <view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{1}}">+ </view> </view> </view> </view> </view> </block> <!-- When goods cart When the length of the array in is 0, it indicates that there are no products --> <block wx:else> <image mode="widthFix" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.mp.itc.cn%2Fupload%2F20170401%2F2f523043409747a9b68c1bcf6fd353a5_th.jpeg&refer=http%3A%2F%2Fimg.mp.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1637485819&t=36e036c0adbfcb56e7658e4730b87461"> </image> </block> </view> </view> <!-- Bottom navigation bar --> <view class="footer_tool"> <!-- Select all --> <view class="all_check_wrap"> <checkbox-group bindchange="handleItemAllChecked"> <checkbox checked="{{allChecked}}">Select all</checkbox> </checkbox-group> </view> <!-- Total price --> <view class="total_price_wrap"> <view class="total_price"> total:<text class="total_price_number">¥{{totalPrice}}</text> </view> <view>Including freight</view> </view> <!-- settlement --> <view class="order_pay_wrap">settlement({{totalNum}})</view> </view>
The effect is as follows
The premise of the settlement function is that there is a receiving address and goods exist. Then jump to the payment page. wx.showToast is used
And wx.navigateTo's wechat built-in API.
// pages/cart/index.js Page({ /** * Encapsulate a function to recalculate the bottom toolbar, total price and total quantity while setting the commodity status of the shopping cart */ setCart(cart) { let allChecked = true; // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } else { allChecked = false; } }) //Determine whether the array is empty allChecked = cart.length != 0 ? allChecked : false; this.setData({ cart, totalPrice, totalNum, allChecked }); wx.setStorageSync('cart', cart); }, // Click to get receiving address event // 1. Bind click event // 2. Call the API in the applet, "Wx. Chooseaddress", to obtain the receiving address of the user // Shopping cart page loaded // 1. Obtain the receiving address data in the local storage // 2. If there is storage, set the data to a variable in data handleChooseAddress(e) { wx.chooseAddress({ success: (result) => { // Store the obtained address into the local cache, and splice the address before storage result.all = result.provinceName + result.cityName + result.countyName + result.detailInfo; console.log(result); wx.setStorageSync('address', result) }, }); }, // Selected optimization event for a product handleItemChange(e) { //Get the modified product id const goods_id = e.currentTarget.dataset.id; // Get shopping cart array let { cart } = this.data; //Find the item object to be modified in the shopping cart array let index = cart.findIndex(v => v.goods_id === goods_id); // Modify the selected status of the commodity object and invert it cart[index].checked = !cart[index].checked; // Update the data to the data and cache, and recalculate the total price and total quantity by calling the encapsulated function setCart this.setCart(cart); }, //Select all of products handleItemAllChecked(e) { // 1 get the data in data let { cart, allChecked } = this.data; // 2 modify value allChecked = !allChecked; // 3 cycle to modify the selected status of goods in the cart array cart.forEach(v => v.checked = allChecked); // 4 fill the modified value back into the data or cache, and call the encapsulated function this.setCart(cart); }, //Commodity quantity addition and subtraction function handleItemNumEdit(e) { // 1 get the passed parameters const { operation, id } = e.currentTarget.dataset; // 2 get shopping cart array let { cart } = this.data; //3 find the index of the item to be modified const index = cart.findIndex(v => v.goods_id === id); //Determine whether to delete when the commodity quantity is less than 1 if (cart[index].num === 1 && operation === -1) { wx.showModal({ title: 'Tips', content: 'Do you want to delete this item?', success: (res) => { if (res.confirm) { cart.splice(index, 1); this.setCart(cart); } else if (res.cancel) { console.log('The user clicks cancel'); } } }) } else { // 4. Quantity to be modified cart[index].num += operation; // 5 set back to cache and data this.setCart(cart); } }, // Settlement function of commodity page handlePay(e) { //1. Judge the receiving address and whether there is commodity quantity const { address, totalNum } = this.data; if (!address.userName) { wx.showToast({ title: 'Please add shipping address', icon: 'error', duration: 2000, }) return; } if (totalNum===0) { wx.showToast({ title: 'Please add product', icon: 'error', duration: 2000 }) return; } // Jump to wechat payment page wx.navigateTo({ url: '/pages/pay/index', }) }, /** * Initial data of the page */ data: { address: {}, //Declare a variable, shopping cart array cart: [], // Declare a variable, whether to select all the contents of the shopping cart allChecked: false, // Define total price and total quantity of goods totalPrice: 0, totalNum: 0 }, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { //Get shopping cart data in cache const cart = wx.getStorageSync('cart') // Calculate whether to select all shopping cart items // The every array method will traverse and receive callback functions, so each callback function will return true, and the return value of the every method will be true // As long as a callback function returns false, it will not execute circularly and return false directly // If it is an empty array, then every returns true, so a ternary expression is used const allChecked = cart.length ? cart.every(v => v.checked) : false; //Get the receiving address information in the cache const address = wx.getStorageSync('address'); // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } }) //Assign value to data this.setData({ address, cart: cart, allChecked, totalPrice, totalNum }) }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
<!--pages/cart/index.wxml--> <!-- Receiving address container --> <view class="receive_address"> <!-- Receiving address button --> <!-- wx:if Judge whether the user name in the address exists,Show when not present --> <view class="address" wx:if="{{!address.userName}}"> <!-- plain Indicates whether the button is hollow and the background color is transparent --> <!-- Bind the click event to obtain the receiving address --> <button type="primary" plain="true" bindtap="handleChooseAddress">Add receiving address</button> </view> <!-- When the receiving address user name exists, that is, there is a receiving address --> <view wx:else class="user_info_row"> <view class="user_info"> <view> {{address.userName}}</view> <view>{{address.all}}</view> </view> <view class="user_phone"> {{address.telNumber}} </view> </view> </view> <!-- Shopping cart details --> <view class="cart_content"> <view class="cart_title">Shopping Cart</view> <view class="cart_main"> <!-- When cart When the length of the array is not 0, the product information is displayed --> <block wx:if="{{cart.length!==0}}"> <view class="cart_item" wx:for="{{cart}}" wx:key="goods_id"> <!-- Check box structure --> <view class="cart_checkbox"> <checkbox-group data-id="{{item.goods_id}}" bindchange="handleItemChange"> <checkbox checked="{{item.checked}}"></checkbox> </checkbox-group> </view> <!-- Product picture --> <navigator class="cart_image"> <image mode="widthFix" src="{{item.goods_small_logo}}"> </image> </navigator> <!-- Commodity information --> <view class="cart_info"> <view class="goods_name">{{item.goods_name}}</view> <view class="goods_price_wrap"> <view class="goods_price">{{item.goods_price}}</view> <view class="cart_num_tool"> <view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{-1}}">- </view> <view class="goods_nums">{{item.num}}</view> <view class="num_edit" bindtap="handleItemNumEdit" data-id="{{item.goods_id}}" data-operation="{{1}}">+ </view> </view> </view> </view> </view> </block> <!-- When goods cart When the length of the array in is 0, it indicates that there are no products --> <block wx:else> <image mode="widthFix" src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.mp.itc.cn%2Fupload%2F20170401%2F2f523043409747a9b68c1bcf6fd353a5_th.jpeg&refer=http%3A%2F%2Fimg.mp.itc.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1637485819&t=36e036c0adbfcb56e7658e4730b87461"> </image> </block> </view> </view> <!-- Bottom navigation bar --> <view class="footer_tool"> <!-- Select all --> <view class="all_check_wrap"> <checkbox-group bindchange="handleItemAllChecked"> <checkbox checked="{{allChecked}}">Select all</checkbox> </checkbox-group> </view> <!-- Total price --> <view class="total_price_wrap"> <view class="total_price"> total:<text class="total_price_number">¥{{totalPrice}}</text> </view> <view>Including freight</view> </view> <!-- settlement --> <view class="order_pay_wrap" bindtap="handlePay">settlement({{totalNum}})</view> </view>
The final effect is as follows
**
**
Payment page
The pay folder corresponds to the payment page. First, modify the name of the page in index.json, as shown below.
{ "usingComponents": {}, "navigationBarTitleText": "payment" }
Then the page changes
The overall style of the payment page is similar to that of the shopping cart page, so you can copy the code of the previous shopping cart page in large sections. Then make minor modifications.
<!--pages/pay/index.wxml--> <!-- Receiving address container --> <view class="receive_address"> <view class="user_info_row"> <view class="user_info"> <view> {{address.userName}}</view> <view>{{address.all}}</view> </view> <view class="user_phone"> {{address.telNumber}} </view> </view> </view> <!-- Shopping cart details --> <view class="cart_content"> <view class="cart_title">Shopping Cart</view> <view class="cart_main"> <view class="cart_item" wx:for="{{cart}}" wx:key="goods_id"> <!-- Product picture --> <navigator class="cart_image"> <image mode="widthFix" src="{{item.goods_small_logo}}"> </image> </navigator> <!-- Commodity information --> <view class="cart_info"> <view class="goods_name">{{item.goods_name}}</view> <view class="goods_price_wrap"> <view class="goods_price">{{item.goods_price}}</view> <view class="cart_num_tool"> <view class="goods_nums">x{{item.num}}</view> </view> </view> </view> </view> </view> </view> <!-- Bottom navigation bar --> <view class="footer_tool"> <!-- Total price --> <view class="total_price_wrap"> <view class="total_price"> total:<text class="total_price_number">¥{{totalPrice}}</text> </view> <view>Including freight</view> </view> <!-- payment --> <view class="order_pay_wrap">payment({{totalNum}})</view> </view>
/* pages/pay/index.wxss */ page{ padding-bottom: 90rpx; } .address { padding: 20rpx; } .address button { width: 60%; } .user_info_row { display: flex; padding: 20rpx; } .user_info { flex: 5; } .user_phone { flex: 2; text-align: center; justify-content: center; } .cart_title { padding: 20rpx; font-size: 36rpx; color: var(--themColor); border-top: 1rpx solid currentColor; border-bottom: 1rpx solid currentColor; } .cart_item { display: flex; } .cart_item .cart_image { flex: 2; display: flex; justify-content: center; align-items: center; } .cart_image image { width: 80%; } .cart_info { flex: 4; display: flex; justify-content: space-around; flex-direction: column; } .cart_info .goods_name { display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2; color: #666; } .cart_info .goods_price_wrap { display: flex; justify-content: space-between; } .goods_price { color: var(--themColor); font-size: 34rpx; } .cart_num_tool { display: flex; } .goods_nums { width: 55rpx; height: 55rpx; display: flex; justify-content: center; align-items: center; } .footer_tool{ position: fixed; bottom: 0; left: 0; width: 100%; height: 90rpx; background-color: #fff; display: flex; border-top: 1rpx solid #ccc; } .total_price_wrap{ flex: 4; padding-right: 15rpx; /* Align text right */ text-align: right; } .total_price_number{ color: var(--themColor); font-size: 34rpx; font-weight: 600; } .order_pay_wrap{ flex: 2; background-color: var(--themColor); color: #fff; font-size: 32rpx; font-weight: 600; display: flex; justify-content: center; align-items: center; }
// pages/pay/index.js Page({ /** * Encapsulate a function to recalculate the bottom toolbar, total price and total quantity while setting the commodity status */ setCart(cart) { let allChecked = true; // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } else { allChecked = false; } }) //Determine whether the array is empty allChecked = cart.length != 0 ? allChecked : false; this.setData({ cart, totalPrice, totalNum, }); wx.setStorageSync('cart', cart); }, /** * Initial data of the page */ data: { address: {}, //Declare a variable, shopping cart array cart: [], // Declare a variable, whether to select all the contents of the shopping cart allChecked: false, // Define total price and total quantity of goods totalPrice: 0, totalNum: 0 }, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { //Get shopping cart data in cache const cart = wx.getStorageSync('cart') // Calculate whether to select all shopping cart items // The every array method will traverse and receive callback functions, so each callback function will return true, and the return value of the every method will be true // As long as a callback function returns false, it will not execute circularly and return false directly // If it is an empty array, then every returns true, so a ternary expression is used const allChecked = cart.length ? cart.every(v => v.checked) : false; //Get the receiving address information in the cache const address = wx.getStorageSync('address'); // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } }) //Assign value to data this.setData({ address, cart: cart, allChecked, totalPrice, totalNum }) }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
The final modified payment page style is as follows
Next is some related payment logic. For the goods on this page, we must ensure that they have been selected on the shopping cart page, that is, the checkbox is selected as true. Therefore, you need to filter in index.js to filter what really needs to be paid.
// pages/pay/index.js Page({ /** * Encapsulate a function to recalculate the bottom toolbar, total price and total quantity while setting the commodity status */ setCart(cart) { let allChecked = true; // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } else { allChecked = false; } }) //Determine whether the array is empty allChecked = cart.length != 0 ? allChecked : false; this.setData({ cart, totalPrice, totalNum, }); wx.setStorageSync('cart', cart); }, /** * Initial data of the page */ data: { address: {}, //Declare a variable, shopping cart array cart: [], // Declare a variable, whether to select all the contents of the shopping cart allChecked: false, // Define total price and total quantity of goods totalPrice: 0, totalNum: 0 }, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { }, /** * Life cycle function -- monitor the completion of the first rendering of the page */ onReady: function () { }, /** * Life cycle function -- monitor page display */ onShow: function () { //Get shopping cart data in cache let cart = wx.getStorageSync('cart') //Get the receiving address information in the cache const address = wx.getStorageSync('address'); //Filtered shopping cart array (really selected items) cart = cart.filter(v => v.checked); // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { totalPrice += v.num * v.goods_price; totalNum += v.num; }) this.setData({ cart, totalPrice, totalNum, address, }); }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
You can see that there are three items in the shopping cart, and only two items are settled. After jumping to the payment page, there are really only two items.
Now let's click the payment button to make wechat payment. Who or account can wechat payment be realized? At present, only the applet developed by the enterprise account can be implemented, and the developer must be added to the white list in the background of the applet of the enterprise account. For specific details, you need to view the applet development document( Wechat payment).
The overall process is as follows
In fact, the application process is as follows. When clicking the payment button, first judge whether there is a token value in the cache when the user logs in. If not, jump to the authorization page to obtain the token. If there is a token value, go to the step of creating an order. At this time, the index.js code of the payment page is as follows. Because there is no token value, click payment and jump to the auth page for authorization.
// pages/pay/index.js Page({ /** * Encapsulate a function to recalculate the bottom toolbar, total price and total quantity while setting the commodity status */ setCart(cart) { let allChecked = true; // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { if (v.checked) { totalPrice += v.num * v.goods_price; totalNum += v.num; } else { allChecked = false; } }) //Determine whether the array is empty allChecked = cart.length != 0 ? allChecked : false; this.setData({ cart, totalPrice, totalNum, }); wx.setStorageSync('cart', cart); }, /** * Initial data of the page */ data: { address: {}, //Declare a variable, shopping cart array cart: [], // Declare a variable, whether to select all the contents of the shopping cart allChecked: false, // Define total price and total quantity of goods totalPrice: 0, totalNum: 0 }, /** * Life cycle function -- listening for page loading */ onLoad: function (options) { }, /** * Life cycle function -- monitor page display */ onShow: function () { //Get shopping cart data in cache let cart = wx.getStorageSync('cart') //Get the receiving address information in the cache const address = wx.getStorageSync('address'); //Filtered shopping cart array (really selected items) cart = cart.filter(v => v.checked); // Declare total price and total quantity let totalPrice = 0; let totalNum = 0; cart.forEach(v => { totalPrice += v.num * v.goods_price; totalNum += v.num; }) this.setData({ cart, totalPrice, totalNum, address, }); }, // Click payment event handleOrderPay(e) { //Judge whether there is a token in the cache const token = wx.getStorageSync('token'); //If it doesn't exist if (!token) { //Jump to the page to get user login information wx.navigateTo({ url: '/pages/auth/index', }) return; } //Otherwise, there is a token value console.log('Already token Yes'); }, /** * Life cycle function -- listening for page hiding */ onHide: function () { }, /** * Life cycle function -- listen for page unloading */ onUnload: function () { }, /** * Page related event handler -- listen to user drop-down actions */ onPullDownRefresh: function () { }, /** * Handler for bottom pull event on page */ onReachBottom: function () { }, /** * Users click the upper right corner to share */ onShareAppMessage: function () { } })
In the auth folder, first modify the page name in index.json.
{ "usingComponents": {}, "navigationBarTitleText": "to grant authorization" }
Then add a button in the index.wxml code under the folder, and click to authorize.
<!--pages/auth/index.wxml--> <!-- Obtain user authorization and bind click events --> <button type="primary" plain="true" open-type="getUserInfo" bindgetuserinfo="handleGetUserInfo"> Get authorization </button>
The index.wxss style is as follows
/* pages/auth/index.wxss */ button{ margin-top: 40rpx; width: 70%; }
Then write the relevant logic code in index.js. Note that we have customized a token value here because we are not an enterprise wechat.
// pages/auth/index.js // Introduce encapsulated request function import { request } from "../../request/index.js" Page({ //Get user information async handleGetUserInfo(e) { // Print the event obtained after clicking e // console.log(e); // Get the following properties in event e. const { encryptedData, rawData, iv, signature } = e.detail; //Get the code value after the applet is successfully logged in wx.login({ timeout: 10000, success: (result) => { // Check the code value // console.log(result); const code = result.code; wx.setStorageSync('code', code) }, fail: () => {}, complete: () => {} }) const code = wx.getStorageSync('code'); const loginParams = { encryptedData, rawData, iv, signature, code }; //Send a request to get the user's token value const token = await request({ url: "https://api-hmugo-web.itheima.net/api/public/v1/users/wxlogin", data: this.loginParams, method: "post" }); //Store the token in the cache and jump back to the previous page (here we use a custom token because we are not an enterprise wechat account) wx.setStorageSync('token', 'BearereyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1aWQiOjIzLCJpYXQiOjE1NjQ3MzAwNzksImV4cCI6MTAwMTU2NDczMDA3OH0.YPt-XeLnjV-_1ITaXGY2FhxmCe4NvXuRnRB8OMCfnPo'); // Back to previous page wx.navigateBack({ delta: 1 }) } })
After running, click the authorization button, and the data in the cache is as follows:
After clicking the authorization once, click the payment button on the payment page, and the following effects will appear