获取商品信息

跳转过来携带商品id

  1. <navigator
  2. :url="`/pages/goods_detail/goods_detail?goods_id=${info.goods_id}`">
  3. onLoad (options) {
  4. const goods_id = options.goods_id
  5. this.getGoodsDetail(goods_id)
  6. },
  7. data() {
  8. return {
  9. goodsDetail: null
  10. }
  11. },
  12. methods: {
  13. async getGoodsDetail(goods_id) {
  14. const res = await this.$u.get('/goods/detail',{goods_id})
  15. console.log(res);
  16. this.goodsDetail = res.message
  17. }
  18. },

页面渲染

轮播图

轮播图 + 图片 组件 会冲突 看文档img-mode是控制轮播图中的图片裁件 bg-color控制背景颜色 十六进制

  1. <!-- 轮播图 -->
  2. <u-swiper
  3. :list="goodsDetail.pics"
  4. name="pics_big_url"
  5. img-mode="aspectFit"
  6. height="500"
  7. bg-color="#fff"
  8. ></u-swiper>

点击轮播图 放大预览被点击的图片 previewImage 小程序api

  1. // 点击轮播图图片
  2. handlepreviewImage (index) {
  3. // console.log(index);
  4. const urls = this.urls // 需要预览的图片 http 链接列表
  5. const current = this.urls[index]// 当前显示图片的 http 链接
  6. // 放大预览图片
  7. uni.previewImage({
  8. current,
  9. urls
  10. })
  11. }
  12. },
  13. computed: {
  14. // 优化 计算属性有缓存 不用每次点击都重新输出新的urls
  15. urls() {
  16. // 预览的图片数组 只能存放
  17. if (this.goodsDetail) {
  18. return this.goodsDetail.pics.map(item => item.pics_big_url)
  19. } else {
  20. return []
  21. }
  22. }
  23. },
  24. }

商品信息

直接渲染 页面有可能会出现undefined 在跟组件上加一个v-if来做渲染

  1. <template v-if="goodsDetail">
  2. <view>
  3. <!-- 轮播图 -->
  4. <u-swiper
  5. :list="goodsDetail.pics"
  6. name="pics_big_url"
  7. img-mode="aspectFit"
  8. height="500"
  9. bg-color="#fff"
  10. @click="handlepreviewImage"
  11. ></u-swiper>
  12. <!-- 商品信息 -->
  13. <view>
  14. <!-- 价格 -->
  15. <view class="goods-price">
  16. <view>
  17. ¥{{ goodsDetail.goods_price }}
  18. </view>
  19. <!-- 分享功能 -->
  20. <view class="share-container">
  21. <u-icon name="share"></u-icon>
  22. <button open-type="share"></button>
  23. </view>
  24. </view>
  25. <!-- 描述 -->
  26. <view class="goods-name">{{ goodsDetail.goods_name }}</view>
  27. </view>
  28. </view>
  29. </template>

分享功能

分享当前页面给微信好友

通过监听生命周期事件onShareAppMessage用户分享时会执行 如果不定义 无法点击小程序右上-分享 button组件open-type="share"可以触发

  1. <button open-type="share"></button>
  2. onShareAppMessage () {},

分享到朋友圈

通过监听生命周期事件onShareTimeline用户分享时会执行 如果不定义 无法点击小程序右上-分享到朋友圈

  1. onShareTimeline () {},

分享图标

利用定位让按钮脱标 宽高跟父元素一样 透明度0 点击图标 = 点击按钮

  1. <!-- 分享功能 -->
  2. <view class="share-container">
  3. <u-icon name="share"></u-icon>
  4. <button open-type="share"></button>
  5. </view>
  6. </view>
  7. <style lang="scss">
  8. .goods-price {
  9. display: flex;
  10. justify-content: space-between;
  11. color: #ea4350;
  12. padding: 10rpx;
  13. .share-container {
  14. position: relative;
  15. // 由内容撑开 icon图标
  16. display: inline-block;
  17. margin-right: 45rpx;
  18. color: #000;
  19. button {
  20. position: absolute;
  21. width: 100%;
  22. height: 100%;
  23. top: 0;
  24. left: 0;
  25. opacity: 0;
  26. }
  27. }
  28. }
  29. </style>

图文详情

由商家在商家后台自定义好,后端直接返回富文本

解析富文本

  • <rich-text :nodes=""> 原生小程序
    • 适合简单的场景
  • v-htmlvue语法
  • <u-parse :html="">uview组件
    • 适合复杂场景 如:图文详情
      1. <!-- vue语法 -->
      2. <view v-html="goodsDetail.goods_introduce"></view>
      3. <!-- uview 组件 -->
      4. <u-parse :html="goodsDetail.goods_introduce"></u-parse>
      5. <!-- 小程序原生组件 -->
      6. <rich-text :nodes="goodsDetail.goods_introduce"></rich-text>

      底部-提交订单栏

      uview模板

  1. <template>
  2. <view class="navigation">
  3. <view class="left">
  4. <view class="item">
  5. <u-icon name="server-fill" :size="40" :color="$u.color['contentColor']"></u-icon>
  6. <view class="text u-line-1">客服</view>
  7. </view>
  8. <view class="item">
  9. <u-icon name="home" :size="40" :color="$u.color['contentColor']"></u-icon>
  10. <view class="text u-line-1">店铺</view>
  11. </view>
  12. <view class="item car">
  13. <u-badge class="car-num" :count="9" type="error" :offset="[-3, -6]"></u-badge>
  14. <u-icon name="shopping-cart" :size="40" :color="$u.color['contentColor']"></u-icon>
  15. <view class="text u-line-1">购物车</view>
  16. </view>
  17. </view>
  18. <view class="right">
  19. <view class="cart btn u-line-1">加入购物车</view>
  20. <view class="buy btn u-line-1">立即购买</view>
  21. </view>
  22. </view>
  23. </template>
  24. <script>
  25. export default {
  26. };
  27. </script>
  28. <style lang="scss" scoped>
  29. .navigation {
  30. display: flex;
  31. margin-top: 100rpx;
  32. border: solid 2rpx #f2f2f2;
  33. background-color: #ffffff;
  34. padding: 16rpx 0;
  35. .left {
  36. display: flex;
  37. font-size: 20rpx;
  38. .item {
  39. margin: 0 30rpx;
  40. &.car {
  41. text-align: center;
  42. position: relative;
  43. .car-num {
  44. position: absolute;
  45. top: -10rpx;
  46. right: -10rpx;
  47. }
  48. }
  49. }
  50. }
  51. .right {
  52. display: flex;
  53. font-size: 28rpx;
  54. align-items: center;
  55. .btn {
  56. line-height: 66rpx;
  57. padding: 0 30rpx;
  58. border-radius: 36rpx;
  59. color: #ffffff;
  60. }
  61. .cart {
  62. background-color: #ed3f14;
  63. margin-right: 30rpx;
  64. }
  65. .buy {
  66. background-color: #ff7900;
  67. }
  68. }
  69. }
  70. </style>

封装组件 引入到页面中

  1. <!-- 提交订单栏 -->
  2. <view class="submit-bar">
  3. <SubmitBar></SubmitBar>
  4. </view>
  5. <script>
  6. import SubmitBar from './components/submit_bar.vue'
  7. export default {
  8. components: {
  9. SubmitBar,
  10. }
  11. }
  12. </script>
  13. <style lang="scss">
  14. .submit-bar{
  15. position: fixed;
  16. bottom: 0;
  17. left: 0;
  18. // 块级元素加定位之后 变成行内块 - 宽度不是100%
  19. width: 100%;
  20. }
  21. page {
  22. padding-bottom: 102rpx;
  23. }
  24. </style>
  1. <template>
  2. <view class="navigation">
  3. <view class="left">
  4. <view class="item">
  5. <u-icon name="server-fill" :size="40" :color="$u.color['contentColor']"></u-icon>
  6. <view class="text u-line-1">客服</view>
  7. </view>
  8. <view class="item">
  9. <u-icon name="home" :size="40" :color="$u.color['contentColor']"></u-icon>
  10. <view class="text u-line-1">店铺</view>
  11. </view>
  12. <view class="item car">
  13. <u-badge class="car-num" :count="9" type="error" :offset="[-3, -6]"></u-badge>
  14. <u-icon name="shopping-cart" :size="40" :color="$u.color['contentColor']"></u-icon>
  15. <view class="text u-line-1">购物车</view>
  16. </view>
  17. </view>
  18. <view class="right">
  19. <view class="cart btn u-line-1">加入购物车</view>
  20. <view class="buy btn u-line-1">立即购买</view>
  21. </view>
  22. </view>
  23. </template>
  24. <script>
  25. export default {
  26. };
  27. </script>
  28. <style lang="scss" scoped>
  29. .navigation {
  30. display: flex;
  31. // 更改布局
  32. justify-content: space-around;
  33. margin-top: 100rpx;
  34. border: solid 2rpx #f2f2f2;
  35. background-color: #ffffff;
  36. padding: 16rpx 0;
  37. .left {
  38. display: flex;
  39. font-size: 20rpx;
  40. // 位移
  41. transform: translateX(-30rpx);
  42. .item {
  43. margin: 0 30rpx;
  44. &.car {
  45. text-align: center;
  46. position: relative;
  47. .car-num {
  48. position: absolute;
  49. top: -10rpx;
  50. right: -10rpx;
  51. }
  52. }
  53. }
  54. }
  55. .right {
  56. display: flex;
  57. font-size: 28rpx;
  58. align-items: center;
  59. .btn {
  60. line-height: 66rpx;
  61. padding: 0 30rpx;
  62. border-radius: 36rpx;
  63. color: #ffffff;
  64. }
  65. .cart {
  66. background-color: #ed3f14;
  67. margin-right: 30rpx;
  68. }
  69. .buy {
  70. background-color: #ff7900;
  71. }
  72. }
  73. }
  74. </style>

使用vuex

  1. export default {
  2. namespaced:true,
  3. state: {
  4. // 商品数组
  5. goodsArr: []
  6. }
  7. };

导入模块

  1. import Vue from 'vue';
  2. import Vuex from 'vuex';
  3. // 引入模块
  4. import cart from './modules/cart';
  5. Vue.use(Vuex); //vue的插件机制
  6. //Vuex.Store 构造器选项
  7. const store = new Vuex.Store({
  8. modules: {
  9. cart,
  10. },
  11. });
  12. export default store;

挂载到vue实例中

  1. import Vue from 'vue'
  2. import App from './App'
  3. import uView from "uview-ui"
  4. // 引入
  5. import store from './store';
  6. Vue.use(uView)
  7. Vue.config.productionTip = false
  8. // 挂载到原型上
  9. Vue.prototype.$store = store;
  10. App.mpType = 'app'
  11. const app = new Vue({
  12. store,
  13. ...App
  14. })
  15. // http拦截器,此为需要加入的内容,如果不是写在common目录,请自行修改引入路径
  16. import httpInterceptor from '@/common/http.interceptor.js'
  17. // 这里需要写在最后,是为了等Vue创建对象完成,引入"app"对象(也即页面的"this"实例)
  18. Vue.use(httpInterceptor, app)
  19. app.$mount()

组件中的生命周期需要使用vue的语法

  1. created () {
  2. console.log(this.$store);
  3. }

加入购物车

  • 传入商品信息 到提交订单栏
  • 提交订单栏 加入购物车绑定点击事件
  • 获取到当前商品的信息 提交mutaions传递商品对象
  • mutations业务
    • 判断当前商品是否存在于购物车
    • 存在 找到数组元素 执行增加计算
    • 不存在 数组新增元素 ```jsx加入购物车

methods: { handleCartAdd() { // 提交mutations this.$store.commit(“cart/cartAddMutations”,{ …this.goodsDetail, count:1, checked:true }) } },

  1. ```jsx
  2. export default {
  3. namespaced:true,
  4. state: {
  5. // 商品数组
  6. goodsArr: []
  7. },
  8. mutations: {
  9. cartAddMutations (state,goods) {
  10. const index = state.goodsArr.findIndex(item => item.goods_id === goods.goods_id)
  11. if (index !== -1) {
  12. // 存在 找到该商品修改信息
  13. state.goodsArr[index].count++
  14. // console.log('商品数量',state.goodsArr[index].count);
  15. } else {
  16. // 不存在 购物车数组加入新元素
  17. state.goodsArr.push(goods)
  18. // console.log('添加新元素',state.goodsArr);
  19. }
  20. }
  21. }
  22. };

使用vuex提供的辅助函数 mapMutations 来简化代码

  1. import {mapMutations} from 'vuex'
  2. methods: {
  3. ...mapMutations('cart', ['cartAddMutations']),
  4. handleCartAdd () {
  5. this.cartAddMutations({
  6. ...this.goodsDetail,
  7. count: 1,
  8. checked: true
  9. })
  10. }
  11. }

数据持久化,通过本地存储 来管理购物车数据

小程序中的本地存储,可以存储任意类型,不需要转成json

    • uni.setStorageSync('名称',数据)
    • uni.getStorageSync('名称')
      1. export default {
      2. namespaced:true,
      3. state: {
      4. // 商品数组 先取本地数据,没有才是空数组
      5. goodsArr: uni.getStorageSync('cart') ||[]
      6. },
      7. mutations: {
      8. cartAddMutations (state,goods) {
      9. const index = state.goodsArr.findIndex(item => item.goods_id === goods.goods_id)
      10. if (index !== -1) {
      11. // 存在 找到该商品修改信息
      12. state.goodsArr[index].count++
      13. console.log('商品数量',state.goodsArr[index].count);
      14. } else {
      15. // 不存在 购物车数组加入新元素
      16. state.goodsArr.push(goods)
      17. console.log('添加新元素',state.goodsArr);
      18. }
      19. // 修改数据之后都需要存储
      20. uni.setStorageSync('cart',state.goodsArr)
      21. }
      22. }
      23. };

      购物车图标

      商品数量显示

      计算属性,来计算总的购买数量getters

  1. getters: {
  2. // 购物车商品的总数量
  3. goodsTotalCount(state) {
  4. return state.goodsArr.reduce((sum,item) => item.count + sum,0)
  5. }
  6. }
  1. <u-badge
  2. class="car-num"
  3. :count="goodsTotalCount"
  4. type="error"
  5. :offset="[-3, -6]"
  6. ></u-badge>
  7. import { mapMutations, mapGetters } from 'vuex'
  8. computed: {
  9. ...mapGetters('cart',['goodsTotalCount'])
  10. },

点击跳转

跳转到tabbar页面 需要添加open-type=""属性

  1. <navigator
  2. class="item car"
  3. url="/pages/cart/cart"
  4. open-type="switchTab"
  5. >
  6. <u-badge
  7. class="car-num"
  8. :count="goodsTotalCount"
  9. type="error"
  10. :offset="[-3, -6]"
  11. ></u-badge>
  12. <u-icon
  13. name="shopping-cart"
  14. :size="40"
  15. :color="$u.color['contentColor']"
  16. ></u-icon>
  17. <view class="text u-line-1">购物车</view>
  18. </navigator>