获取商品信息
跳转过来携带商品id
<navigator
:url="`/pages/goods_detail/goods_detail?goods_id=${info.goods_id}`">
onLoad (options) {
const goods_id = options.goods_id
this.getGoodsDetail(goods_id)
},
data() {
return {
goodsDetail: null
}
},
methods: {
async getGoodsDetail(goods_id) {
const res = await this.$u.get('/goods/detail',{goods_id})
console.log(res);
this.goodsDetail = res.message
}
},
页面渲染
轮播图
轮播图 + 图片 组件 会冲突 看文档
img-mode
是控制轮播图中的图片裁件bg-color
控制背景颜色 十六进制
<!-- 轮播图 -->
<u-swiper
:list="goodsDetail.pics"
name="pics_big_url"
img-mode="aspectFit"
height="500"
bg-color="#fff"
></u-swiper>
点击轮播图 放大预览被点击的图片
previewImage
小程序api
// 点击轮播图图片
handlepreviewImage (index) {
// console.log(index);
const urls = this.urls // 需要预览的图片 http 链接列表
const current = this.urls[index]// 当前显示图片的 http 链接
// 放大预览图片
uni.previewImage({
current,
urls
})
}
},
computed: {
// 优化 计算属性有缓存 不用每次点击都重新输出新的urls
urls() {
// 预览的图片数组 只能存放
if (this.goodsDetail) {
return this.goodsDetail.pics.map(item => item.pics_big_url)
} else {
return []
}
}
},
}
商品信息
直接渲染 页面有可能会出现undefined 在跟组件上加一个
v-if
来做渲染
<template v-if="goodsDetail">
<view>
<!-- 轮播图 -->
<u-swiper
:list="goodsDetail.pics"
name="pics_big_url"
img-mode="aspectFit"
height="500"
bg-color="#fff"
@click="handlepreviewImage"
></u-swiper>
<!-- 商品信息 -->
<view>
<!-- 价格 -->
<view class="goods-price">
<view>
¥{{ goodsDetail.goods_price }}
</view>
<!-- 分享功能 -->
<view class="share-container">
<u-icon name="share"></u-icon>
<button open-type="share"></button>
</view>
</view>
<!-- 描述 -->
<view class="goods-name">{{ goodsDetail.goods_name }}</view>
</view>
</view>
</template>
分享功能
分享当前页面给微信好友
通过监听生命周期事件
onShareAppMessage
用户分享时会执行 如果不定义 无法点击小程序右上-分享 button组件open-type="share"
可以触发
<button open-type="share"></button>
onShareAppMessage () {},
分享到朋友圈
通过监听生命周期事件
onShareTimeline
用户分享时会执行 如果不定义 无法点击小程序右上-分享到朋友圈
onShareTimeline () {},
分享图标
利用定位让按钮脱标 宽高跟父元素一样 透明度0 点击图标 = 点击按钮
<!-- 分享功能 -->
<view class="share-container">
<u-icon name="share"></u-icon>
<button open-type="share"></button>
</view>
</view>
<style lang="scss">
.goods-price {
display: flex;
justify-content: space-between;
color: #ea4350;
padding: 10rpx;
.share-container {
position: relative;
// 由内容撑开 icon图标
display: inline-block;
margin-right: 45rpx;
color: #000;
button {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
opacity: 0;
}
}
}
</style>
图文详情
由商家在商家后台自定义好,后端直接返回富文本
解析富文本
<rich-text :nodes="">
原生小程序- 适合简单的场景
v-html
vue语法<u-parse :html="">
uview组件
<template>
<view class="navigation">
<view class="left">
<view class="item">
<u-icon name="server-fill" :size="40" :color="$u.color['contentColor']"></u-icon>
<view class="text u-line-1">客服</view>
</view>
<view class="item">
<u-icon name="home" :size="40" :color="$u.color['contentColor']"></u-icon>
<view class="text u-line-1">店铺</view>
</view>
<view class="item car">
<u-badge class="car-num" :count="9" type="error" :offset="[-3, -6]"></u-badge>
<u-icon name="shopping-cart" :size="40" :color="$u.color['contentColor']"></u-icon>
<view class="text u-line-1">购物车</view>
</view>
</view>
<view class="right">
<view class="cart btn u-line-1">加入购物车</view>
<view class="buy btn u-line-1">立即购买</view>
</view>
</view>
</template>
<script>
export default {
};
</script>
<style lang="scss" scoped>
.navigation {
display: flex;
margin-top: 100rpx;
border: solid 2rpx #f2f2f2;
background-color: #ffffff;
padding: 16rpx 0;
.left {
display: flex;
font-size: 20rpx;
.item {
margin: 0 30rpx;
&.car {
text-align: center;
position: relative;
.car-num {
position: absolute;
top: -10rpx;
right: -10rpx;
}
}
}
}
.right {
display: flex;
font-size: 28rpx;
align-items: center;
.btn {
line-height: 66rpx;
padding: 0 30rpx;
border-radius: 36rpx;
color: #ffffff;
}
.cart {
background-color: #ed3f14;
margin-right: 30rpx;
}
.buy {
background-color: #ff7900;
}
}
}
</style>
封装组件 引入到页面中
<!-- 提交订单栏 -->
<view class="submit-bar">
<SubmitBar></SubmitBar>
</view>
<script>
import SubmitBar from './components/submit_bar.vue'
export default {
components: {
SubmitBar,
}
}
</script>
<style lang="scss">
.submit-bar{
position: fixed;
bottom: 0;
left: 0;
// 块级元素加定位之后 变成行内块 - 宽度不是100%
width: 100%;
}
page {
padding-bottom: 102rpx;
}
</style>
<template>
<view class="navigation">
<view class="left">
<view class="item">
<u-icon name="server-fill" :size="40" :color="$u.color['contentColor']"></u-icon>
<view class="text u-line-1">客服</view>
</view>
<view class="item">
<u-icon name="home" :size="40" :color="$u.color['contentColor']"></u-icon>
<view class="text u-line-1">店铺</view>
</view>
<view class="item car">
<u-badge class="car-num" :count="9" type="error" :offset="[-3, -6]"></u-badge>
<u-icon name="shopping-cart" :size="40" :color="$u.color['contentColor']"></u-icon>
<view class="text u-line-1">购物车</view>
</view>
</view>
<view class="right">
<view class="cart btn u-line-1">加入购物车</view>
<view class="buy btn u-line-1">立即购买</view>
</view>
</view>
</template>
<script>
export default {
};
</script>
<style lang="scss" scoped>
.navigation {
display: flex;
// 更改布局
justify-content: space-around;
margin-top: 100rpx;
border: solid 2rpx #f2f2f2;
background-color: #ffffff;
padding: 16rpx 0;
.left {
display: flex;
font-size: 20rpx;
// 位移
transform: translateX(-30rpx);
.item {
margin: 0 30rpx;
&.car {
text-align: center;
position: relative;
.car-num {
position: absolute;
top: -10rpx;
right: -10rpx;
}
}
}
}
.right {
display: flex;
font-size: 28rpx;
align-items: center;
.btn {
line-height: 66rpx;
padding: 0 30rpx;
border-radius: 36rpx;
color: #ffffff;
}
.cart {
background-color: #ed3f14;
margin-right: 30rpx;
}
.buy {
background-color: #ff7900;
}
}
}
</style>
使用vuex
export default {
namespaced:true,
state: {
// 商品数组
goodsArr: []
}
};
导入模块
import Vue from 'vue';
import Vuex from 'vuex';
// 引入模块
import cart from './modules/cart';
Vue.use(Vuex); //vue的插件机制
//Vuex.Store 构造器选项
const store = new Vuex.Store({
modules: {
cart,
},
});
export default store;
挂载到vue实例中
import Vue from 'vue'
import App from './App'
import uView from "uview-ui"
// 引入
import store from './store';
Vue.use(uView)
Vue.config.productionTip = false
// 挂载到原型上
Vue.prototype.$store = store;
App.mpType = 'app'
const app = new Vue({
store,
...App
})
// http拦截器,此为需要加入的内容,如果不是写在common目录,请自行修改引入路径
import httpInterceptor from '@/common/http.interceptor.js'
// 这里需要写在最后,是为了等Vue创建对象完成,引入"app"对象(也即页面的"this"实例)
Vue.use(httpInterceptor, app)
app.$mount()
组件中的生命周期需要使用vue的语法
created () {
console.log(this.$store);
}
加入购物车
- 传入商品信息 到提交订单栏
- 提交订单栏 加入购物车绑定点击事件
- 获取到当前商品的信息 提交mutaions传递商品对象
- mutations业务
- 判断当前商品是否存在于购物车
- 存在 找到数组元素 执行增加计算
- 不存在 数组新增元素
```jsx
加入购物车
methods: { handleCartAdd() { // 提交mutations this.$store.commit(“cart/cartAddMutations”,{ …this.goodsDetail, count:1, checked:true }) } },
```jsx
export default {
namespaced:true,
state: {
// 商品数组
goodsArr: []
},
mutations: {
cartAddMutations (state,goods) {
const index = state.goodsArr.findIndex(item => item.goods_id === goods.goods_id)
if (index !== -1) {
// 存在 找到该商品修改信息
state.goodsArr[index].count++
// console.log('商品数量',state.goodsArr[index].count);
} else {
// 不存在 购物车数组加入新元素
state.goodsArr.push(goods)
// console.log('添加新元素',state.goodsArr);
}
}
}
};
使用vuex提供的辅助函数
mapMutations
来简化代码
import {mapMutations} from 'vuex'
methods: {
...mapMutations('cart', ['cartAddMutations']),
handleCartAdd () {
this.cartAddMutations({
...this.goodsDetail,
count: 1,
checked: true
})
}
}
数据持久化,通过本地存储 来管理购物车数据
小程序中的本地存储,可以存储任意类型,不需要转成json
- 存
uni.setStorageSync('名称',数据)
- 取
uni.getStorageSync('名称')
export default {
namespaced:true,
state: {
// 商品数组 先取本地数据,没有才是空数组
goodsArr: uni.getStorageSync('cart') ||[]
},
mutations: {
cartAddMutations (state,goods) {
const index = state.goodsArr.findIndex(item => item.goods_id === goods.goods_id)
if (index !== -1) {
// 存在 找到该商品修改信息
state.goodsArr[index].count++
console.log('商品数量',state.goodsArr[index].count);
} else {
// 不存在 购物车数组加入新元素
state.goodsArr.push(goods)
console.log('添加新元素',state.goodsArr);
}
// 修改数据之后都需要存储
uni.setStorageSync('cart',state.goodsArr)
}
}
};
购物车图标
商品数量显示计算属性,来计算总的购买数量
getters
getters: {
// 购物车商品的总数量
goodsTotalCount(state) {
return state.goodsArr.reduce((sum,item) => item.count + sum,0)
}
}
<u-badge
class="car-num"
:count="goodsTotalCount"
type="error"
:offset="[-3, -6]"
></u-badge>
import { mapMutations, mapGetters } from 'vuex'
computed: {
...mapGetters('cart',['goodsTotalCount'])
},
点击跳转
跳转到tabbar页面 需要添加
open-type=""
属性
<navigator
class="item car"
url="/pages/cart/cart"
open-type="switchTab"
>
<u-badge
class="car-num"
:count="goodsTotalCount"
type="error"
:offset="[-3, -6]"
></u-badge>
<u-icon
name="shopping-cart"
:size="40"
:color="$u.color['contentColor']"
></u-icon>
<view class="text u-line-1">购物车</view>
</navigator>