1.效果
2.创建一个Mypopup组件
3.全局组件使用(打开main.js添加以下代码)
import Mypopup from '@/components/Mypopup/Mypopup.vue'
Vue.component('Mypopup',Mypopup)
4.子组件
<template>
<view v-if="newSpecClass=='show'">
<view class="popup spec" :class="newSpecClass" @touchmove.stop.prevent="stopPrevent" @click="toggleSpec">
<view class="mask">view>
<view class="layer attr-content" @click.stop="stopPrevent">
<view class="closeIcon">
<u-icon name="close" color="#666" size="20" @click="close">u-icon>
view>
<view class="a-t">
<image src="https://gd3.alicdn.com/imgextra/i3/0/O1CN01IiyFQI1UGShoFKt1O_!!0-item_pic.jpg_400x400.jpg">
image>
<view class="right">
<text class="price">¥328.00text>
<text class="stock">库存:188件text>
<view class="selected">
已选:
<text class="selected-text" v-for="(sItem, sIndex) in newSpecSelected" :key="sIndex">
{{sItem.name}}
text>
view>
view>
view>
<view v-for="(item,index) in specList" :key="index" class="attr-list">
<text>{{item.name}}text>
<view class="item-list">
<text v-for="(childItem, childIndex) in specChildList" v-if="childItem.pid === item.id"
:key="childIndex" class="tit" :class="{selected: childItem.selected}"
@click="selectSpec(childIndex, childItem.pid)">
{{childItem.name}}
text>
view>
view>
<view class="count">
数量
<view>
<u-number-box v-model="newCartNum" @change="valChange" :min="1">
u-number-box>
view>
view>
<button class="btn" v-if="btnTip==1" @click="toggleSpec">加入购物车button>
<button class="btn" v-else-if="btnTip==2" @click="topay">立即购买button>
view>
view>
view>
template>
<script>
export default {
props: {
//购买数量
cartNum:{
type:Number,
default: 1
},
specSelected: {
type: Array,
default: []
},
// 规格
specList: {
type: Array,
default: []
},
specChildList: {
type: Array,
default: []
},
// 控制弹框显示和隐藏
specClass: {
type: String,
default: 'hide'
},
// btn文字提示
btnTip:{
type: Number,
default: 1,//1加入购物车 2立即支付
}
},
data() {
return {
newCartNum:this.cartNum,
newSpecSelected:this.specSelected,
// specClass: 'none',
newSpecClass:this.specClass
}
},
watch: {
//数量
cartNum:{
handler(newValue, oldValue) {
this.newCartNum = newValue;
console.log("监听cartNum:", "newValue=", newValue, "oldValue=",oldValue,);
}
},
// 当前选中的规格
specSelected:{
immediate: true,
handler(newValue, oldValue) {
this.newSpecSelected = newValue;
console.log("监听newSpecSelected:", "newValue=" + newValue, "oldValue=" + oldValue,);
}
},
// 弹框显示还是隐藏
specClass: {
immediate: true,
handler(newValue, oldValue) {
this.newSpecClass = newValue;
console.log("监听specClass:", "newValue=" + newValue, "oldValue=" + oldValue,);
}
},
// 控制按钮
btnTip: {
immediate: true,
handler(newValue, oldValue) {
// console.log("监听btnTip:", "newValue=" + newValue, "oldValue=" + oldValue);
}
},
// 规格内容
specChildList:{
immediate: true,
handler(newValue, oldValue) {
console.log("监听specChildList:",newValue, oldValue);
}
}
},
created() {
},
onShow() {
console.log('ONSHOWL1')
},
methods: {
// 购买数量
valChange(e) {
this.$emit('cartNumChange',e.value)
},
//选择规格
selectSpec(index, pid) {
console.log('进来没11111111',this.specChildList)
let list = this.specChildList;
list.forEach(item => {
if (item.pid === pid) {
// this.$set(item, 'selected', false);
item.selected = false;
}
})
// this.$set(list[index], 'selected', true);
list[index].selected = true;
this.$forceUpdate()
//存储已选择
/**
* 修复选择规格存储错误
* 将这几行代码替换即可
* 选择的规格存放在specSelected中
*/
this.newSpecSelected = [];
list.forEach(item => {
if (item.selected === true) {
this.newSpecSelected.push(item);
}
})
this.$emit('gaveSpecSelected',this.specChildList)
},
//关闭图标
close() {
this.$emit('closePopup', 'hide')
},
stopPrevent() {},
//规格弹窗开关
toggleSpec() {
if (this.newSpecClass === 'show') {
this.newSpecClass = 'hide';
setTimeout(() => {
this.newSpecClass = 'none';
}, 250);
} else if (this.newSpecClass === 'none') {
this.newSpecClass = 'show';
}
// 回传当前选中数据
let obj = {
specSelected:this.newSpecSelected,
specClass:this.newSpecClass
}
this.$emit('haveSpecSelected',obj)
},
//去购买
topay(){
//关闭弹窗
this.newSpecClass = 'hide';
//去订单页
},
}
}
script>
<style lang="scss">
// 关闭图标
.closeIcon {
display: flex;
justify-content: flex-end;
}
/* 规格选择弹窗 */
.attr-content {
box-sizing: border-box;
padding: 30rpx 30rpx 100rpx 30rpx;
.a-t {
display: flex;
image {
width: 170upx;
height: 170upx;
flex-shrink: 0;
// margin-top: -40upx;
border-radius: 8upx;
}
.right {
display: flex;
flex-direction: column;
padding-left: 24upx;
font-size: 24upx + 2upx;
color: #606266;
line-height: 42upx;
.price {
font-size: 32upx;
color: #fa436a;
margin-bottom: 10upx;
}
.selected-text {
margin-right: 10upx;
}
}
}
.attr-list {
display: flex;
flex-direction: column;
font-size: 28upx + 2upx;
color: #606266;
padding-top: 30upx;
// padding-left: 10upx;
}
.item-list {
padding: 20upx 0 0;
display: flex;
flex-wrap: wrap;
text {
display: flex;
align-items: center;
justify-content: center;
background: #eee;
margin-right: 20upx;
margin-bottom: 20upx;
border-radius: 100upx;
min-width: 60upx;
height: 60upx;
padding: 0 20upx;
font-size: 28upx;
color: #303133;
}
}
}
.selected {
background: #fbebee !important;
color: #fa436a !important;
}
/* 弹出层 */
.popup {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 999;
&.show {
display: block;
.mask {
animation: showPopup 0.2s linear both;
}
.layer {
animation: showLayer 0.2s linear both;
}
}
&.hide {
.mask {
animation: hidePopup 0.2s linear both;
}
.layer {
animation: hideLayer 0.2s linear both;
}
}
&.none {
display: none;
}
.mask {
position: fixed;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
background-color: rgba(0, 0, 0, 0.4);
}
.layer {
position: fixed;
z-index: 99;
bottom: 0;
width: 100%;
min-height: 40vh;
border-radius: 10upx 10upx 0 0;
background-color: #fff;
.btn {
height: 66upx;
line-height: 66upx;
border-radius: 100upx;
background: #fa436a;
font-size: 28upx + 2upx;
color: #fff;
margin: 30upx auto 20upx;
width: 80%;
}
}
@keyframes showPopup {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes hidePopup {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes showLayer {
0% {
transform: translateY(120%);
}
100% {
transform: translateY(0%);
}
}
@keyframes hideLayer {
0% {
transform: translateY(0);
}
100% {
transform: translateY(120%);
}
}
}
// 数量
.count {
display: flex;
justify-content: space-between;
align-items: center;
padding: 26rpx 0 26rpx 21rpx;
border-bottom: 1rpx solid #F6F6F6;
}
style>
5.父组件
<template>
<view>
选中的规格展示
<view>
<text v-for="(sItem, sIndex) in specSelected" :key="sIndex">
{{sItem.name}}
text>
view>
使用组件(传的数据写的太多了,太杂,可以整理以下传一个对象过去,这里我就懒得改了)
<button class="btn" v-if="btnTip==1" @click="buttonClick">选规格button>
<Mypopup
:cartNum="cartNum"
@haveSpecSelected = "haveSpecSelected"
:btnTip="btnTip"
@closePopup="closePopup"
:specClass="specClass"
:specSelected="specSelected"
:specList="specList"
@cartNumChange="cartNumChange"
@gaveSpecSelected='gaveSpecSelected'
:specChildList="specChildList">Mypopup>
view>
template>
<script>
export default {
data() {
return {
cartNum:1,
specList:[{
id: 1,
name: '尺寸',
},
{
id: 2,
name: '颜色',
}
],
specChildList:[
{
id: 1,
pid: 1,
name: 'XS',
},
{
id: 2,
pid: 1,
name: 'S',
},
{
id: 3,
pid: 1,
name: 'M',
},
{
id: 4,
pid: 1,
name: 'L',
},
{
id: 5,
pid: 2,
name: '白色',
},
{
id: 6,
pid: 2,
name: '红色',
}
],
btnTip:1,//控制弹窗按钮 1购物车 2立即购买
specClass: 'show',//控制弹窗显示、隐藏 show显示 hide隐藏
specSelected: [],//选中的规格数据
}
},
methods:{
//购物车数量获取
cartNumChange(val){
console.log('当前值为: ',val);
this.cartNum = val;
},
// 选中的数据
haveSpecSelected(val){
this.specSelected = val.specSelected;
this.specClass = val.specClass;
},
gaveSpecSelected(val){
this.specChildList = val;
},
//关闭弹窗
closePopup(val){
console.log('关闭了弹窗',val)
this.specClass = val;
//及控制弹窗按钮
this.btnTip = 1;//1购物车 2立即购买
},
buttonClick(){
// 规格弹窗控制器
this.specClass = 'show';
this.btnTip = 1;//加入购物车
},
}
}
script>