在Vue中实现Modal动画

  • transition动画文档:https://cn.vuejs.org/v2/guide/transitions.html

  • transition不需要引入,因其本身是Vue内置的

  • 组件(只展示了相关代码)

  1. index.vue(父组件)
<template>
  <div class="index">
    <div class="product-box">
      <div class="container">
        <span class="product-box-title">手机</span>
        <div class="wrapper">
          <div class="wrapper-left">
            <a href="javascript:;">
              <img src="/imgs/mix-alpha.jpg" />
            </a>
          </div>
          <div class="wrapper-box">
            <div class="wrapper-box-list" v-for="(item,index) in phoneList" :key="index">
              <div class="list-item" v-for="(sub,i) in item" :key="i">
                <span :class="{'new-pro':i%2==0}">新品</span>
                <div class="list-item-img">
                  <img :src="sub.mainImage" />
                </div>
                <div class="list-item-info">
                  <p class="info-name">{{sub.name}}</p>
                  <p class="info-describe">{{sub.subtitle}}</p>
                  <p @click="addCart" class="info-price">{{sub.price}}</p>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <!-- 
    	在父组件定义一个submit事件
    	(组件中不能用click进行事件绑定,需要用子组件传来的名称进行定义,即submit)
     -->
    <Modal title="提示" btnType="3" modalType="middle" :showModal="showModal" v-on:submit="goToCart" v-on:cancel="showModal=false">
      <!-- 
      	插槽的用法:
      	嵌套一个template模板,用v-slot定义插槽的名称(Modal.vue中的<slot name="body"></slot>-->
      <template v-slot:body>
        <p>商品添加成功!</p>
      </template>
    </Modal>
  </div>
</template>

<script>
import Modal from "../components/Modal";
export default {
  name: "index",
  components: {
    Modal
  },
  data() {
    return {
      // 手机商品功能的实现
      phoneList: [],
      // Modal动画是否展示
      showModal:false
    };
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      // 需要后台的真实接口
      this.axios.get("/products", {
          params: {
            categoryId: 100012,
            pageSize: 14
          }
        }).then(res => {
          res.list = res.list.slice(6, 14);
          this.phoneList = [res.list.slice(0, 4), res.list.slice(4, 8)];
        });
    },
    // 添加至购物车
    addCart(){
      this.showModal=true;
      // 调后台接口
      // this.axios.post('/carts',{
      //   productId:id,
      //   selected: true
      // }).then((res)=>{
      // });
    },
    goToCart(){
      this.$router.push('/cart');
    }
  }
};
</script>

<style lang="scss" scope>
@import "../assets/scss/config.scss";
@import "../assets/scss/mixin.scss";
@import "../assets/scss/base.scss";
.index {
  .product-box {
    background-color: $colorJ;
    padding: 30px auto 50px;
    .product-box-title {
      display: block;
      font-size: $fontF;
      color: $colorB;
      padding: 30px 0;
    }
    .wrapper {
      display: flex;
      .wrapper-left {
        margin-right: 16px;
        width: 224px;
        height: 619px;
      }
      .wrapper-box {
        margin-bottom: 51px;
        .wrapper-box-list {
          @include flex();
          margin-bottom: 15px;
          &:last-child {
            margin-bottom: 0;
          }
          .list-item {
            width: 236px;
            height: 302px;
            background-color: $colorG;
            margin-right: 14px;
            text-align: center;
            &:nth-child(4n) {
              margin-right: 0;
            }
            span {
              display: inline-block;
              width: 67px;
              height: 24px;
              line-height: 24px;
              text-align: center;
              color: $colorG;
              // 可通过动态修改class,实现颜色的切换
              &.new-pro {
                background-color: #7ecf68;
              }
              &.kill-pro {
                background-color: #e82626;
              }
            }
            .list-item-img {
              img {
                width: 190px;
                height: 195px;
                object-fit: cover;
              }
            }
            .list-item-info {
              .info-name {
                font-size: $fontJ;
                font-weight: bold;
                color: $colorB;
                line-height: $fontJ;
              }
              .info-describe {
                font-size: $fontK;
                color: $colorD;
                line-height: 13px;
                margin: 6px auto 13px;
              }
              .info-price {
                font-size: $fontJ;
                font-weight: bold;
                color: #f20a0a;
                cursor: pointer;
                &::after {
                  content: " ";
                  @include bgImg(20px, 20px, "/imgs/icon-cart-hover.png");
                  margin-left: 8px;
                  vertical-align: middle;
                }
              }
            }
          }
        }
      }
    }
  }
}
</style> 
  1. Modal.vue(子组件)

    通过在 props 中对 modalType(弹框类型)、title(弹框标题)、btnType(按钮类型)、	
    confirmText(确定文本)、cancelText(取消文本)以及 showModal(弹框是否需要展示)的设置,
    实现动态设置组件的功能,以便于对组件进行复用。
    
<template>
  <transition name="slide">
    <div class="modal" v-show="showModal">
      <!-- 遮罩 -->
      <div class="mask"></div>
      <!-- 会话 -->
      <div class="modal-dialog">
        <div class="dialog-header">
          <span>{{title}}</span>
          <a href="javascript:;" class="icon-close" v-on:click="$emit('cancel')"></a>
        </div>
        <div class="dialog-body">
          <slot name="body"></slot>
        </div>
        <div class="dialog-footer">
            <!-- 子组件点击“确定”以后向父组件传递,父组件用emit进行传递;在这里点击“确定”之后,调用父组件的submit -->
          <a href="javascript:;" v-if="btnType==1" @click="$emit('submit')" class="btn btn-default btn-margin">{{confirmText}}</a>
          <a href="javascript:;" v-if="btnType==2" @click="$emit('cancel')" class="btn btn-default btn-margin btn-gray">{{cancelText}}</a>
          <div v-if="btnType==3" class="btn-margin">
              <a href="javascript:;" @click="$emit('submit')" class="btn btn-default btn-margin">{{confirmText}}</a>
              <a href="javascript:;" @click="$emit('cancel')" class="btn btn-default btn-margin btn-gray">{{cancelText}}</a>
          </div>
        </div>
      </div>
    </div> 
  </transition>
</template>

<script>
export default {
  name: "modal",
  props: {
    // 弹框类型:小small、中middle、大large、表单form
    modalType: {
      type: String,
      default: "form"
    },
    // 弹框标题
    title: String,
    // 按钮类型:1、 确定按钮 2、取消按钮 3、确定取消
    btnType: String,
    // 确定文本
    confirmText: {
      type: String,
      default: "确定"
    },
    // 取消文本
    cancelText: {
      type: String,
      default: "取消"
    },
    // 弹框是否需要展示
    showModal: Boolean
  }
};
</script>

<style lang="scss" scope>
@import "../assets/scss/mixin.scss";
@import "../assets/scss/config.scss";
@import "../assets/scss/modal.scss";
</style>
  • 样式文件
  1. modal.scss

    对modal动画进行设置
    
.modal{
  @include position(fixed);
  z-index: 10;
  transition: all .5s linear;
  .mask{
    @include position(fixed);
    background-color: $colorI;
    opacity: 0.5;
  }
  // slide-enter需要放在slide-enter-active、slide-leave-active下面
  &.slide-enter-active{
    top: 0;
  }
  &.slide-leave-active{
    top: -100%;
  }
  &.slide-enter{
    top: -100%;
  }
  .modal-dialog{
    @include position(absolute,40%,50%,660px,auto);
    background-color: $colorG;
    transform: translate(-50%,-50%);
    .dialog-header{
      height: 60px;
      line-height: 60px;
      background-color: $colorJ;
      span{
        font-size: $fontI;
        padding: 22px 26px;
        box-sizing: border-box;
        color: $colorB;
      }
      .icon-close{
        @include positionImg(absolute,23px,25px,16px,16px,'/imgs/icon-close.png');
        transition: all .2s linear;
        &:hover{
          transform: scale(1.4);
        }
      }
    }
    .dialog-body{
      padding: 42px 40px;
      font-size: $fontJ;
    }
    .dialog-footer{
      height: 80px;
      line-height: 80px;
      text-align: center;
      background-color: $colorJ;
    }
  }
}
  1. button.scss

    对项目中的所有提示框按钮的样式进行设置;
    直接在App.vue中引入,就不需要在相应组件进行引入。
    
.btn{
  display: inline-block;
  text-align: center;
  font-size: $fontI;
  color: $colorG;
  border: none;
  cursor: pointer;
  background-color: $colorA;
}
.btn-gray{
  background-color: #B0B0B0;
}
.btn-margin{
  margin-right: 21px;
  &:last-child{
    margin-right: 0;
  }
}
.btn-buy{
  width: 110px;
  line-height: 30px;
}
.btn-pay{
  width: 130px;
  line-height: 35px;
}
.btn-like{
  width: 142px;
  height: 54px;
}
.btn-default{
  width: 160px;
  line-height: 40px;
}
.btn-success{
  width: 200px;
  line-height: 54px;
}
.btn-account{
  width: 202px;
  line-height: 50px;
}
.btn-join{
  width: 300px;
  line-height: 54px;
}
.btn-request{
  width: 332px;
  line-height: 42px;
}
.btn-login{
  width: 348px;
  line-height: 50px;
}
  1. mixin.scss

    对项目中使用较多的样式进行针对设计,在style可使用 @include flex() 等方法进行设置
    
// flex布局复用
@mixin flex($hov:space-between,$col:center){
  display: flex;
  justify-content: $hov;
  align-items: $col;
}
@mixin bgImg($w:0,$h:0,$img:'',$size:contain){
  display: inline-block;
  width: $w;
  height: $h;
  background: url($img) no-repeat center;
  background-size: $size;
}
@mixin position($pos:absolute,$top:0,$left:0,$w:100%,$h:100%){
  position: $pos;
  top: $top;
  left: $left;
  width: $w;
  height: $h;
}
@mixin positionImg($pos:absolute,$top:0,$right:0,$w:0,$h:0,$img:''){
  position: $pos;
  top: $top;
  right: $right;
  width: $w;
  height: $h;
  background: url($img) no-repeat center;
  background-size: contain;
}
  1. config.scss

    样式规范表,字体大小与颜色可根据项目自行定义
    
$min-width:1226px;  //容器安全区域宽度

// 常规字体大小设置
$fontA: 80px;
$fontB: 38px;
$fontC: 28px;
$fontD: 26px; 
$fontE: 24px; 
$fontF: 22px;
$fontG: 20px; 
$fontH: 18px; 
$fontI: 16px; 
$fontJ: 14px; 
$fontK: 12px; 

// 常规配色设置
$colorA: #FF6600 !default; 
$colorB: #333333 !default;
$colorC: #666666 !default; 
$colorD: #999999 !default; 
$colorE: #cccccc !default; 
$colorF: #d7d7d7 !default; 
$colorG: #ffffff !default;
$colorH: #e5e5e5 !default; 
$colorI: #000000 !default; 
$colorJ: #F5F5F5 !default; 
  • 结果展示

    Modal动画:点击商品价格旁的“购物车”后,提示框会淡入页面;点击“取消”或“×”,均会使提示框淡出页面。
    点击“购物车”,会将商品添加至购物车内,但这里没有后台接口,因此只做了跳转至cart(购物车页面)路由;
    点击“确定”也可跳转至cart路由;
    点击“取消”或“×”,均可回到当前页面;
    

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
你可以使用Vue的transition组件来实现点击按钮弹出弹框的动画效果。具体实现步骤如下: 1. 在Vue组件添加一个按钮,并为其绑定一个点击事件。 2. 在Vue组件定义一个data属性,用于控制弹框的显示和隐藏状态。 3. 使用Vue的transition组件包裹弹框内容,并设置name属性。 4. 在transition组件使用v-if指令控制弹框的显示和隐藏。 5. 在transition组件使用CSS样式定义弹框的进入和离开动画效果。 以下是一个简单的示例代码: ```html <template> <div> <button @click="showModal = true">点击弹出弹框</button> <transition name="modal"> <div class="modal-mask" v-if="showModal"> <div class="modal-wrapper"> <div class="modal-container"> <!-- 弹框内容 --> <h3>这是一个弹框!</h3> <p>点击右上角的X可以关闭弹框。</p> </div> </div> </div> </transition> </div> </template> <script> export default { data() { return { showModal: false } } } </script> <style> .modal-mask { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; } .modal-wrapper { display: inline-block; background-color: #fff; border-radius: 4px; padding: 20px; } .modal-enter-active, .modal-leave-active { transition: opacity 0.3s; } .modal-enter, .modal-leave-to { opacity: 0; } </style> ``` 在上面的示例代码,当点击按钮时,showModal属性的值会变为true,弹框就会显示出来,同时触发进入动画效果。当点击弹框右上角的X按钮关闭弹框时,showModal属性的值会变为false,弹框就会隐藏起来,同时触发离开动画效果。你可以根据自己的需求修改样式或动画效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值