高仿Element.ui搭建自己的组件(2)

补充sync和self两个事件修饰符

self有点只可意会不能言传啊,就比如我们再有遮罩层的弹窗,我们想点击遮罩层,弹窗消失,但我们却发现点击弹窗,弹窗也消失了,这个时候我们可以给遮罩层事件加上.self,见下文内容。

至于sync,当子组件要修改父组件传递来的值时,往往要通过自定义事件,我们可以搭配update:变量和 :变量.sync的方式来实现

话不多说,直接上代码吧

父组件

<!-- 原本自定义事件改变父组件传递的值 -->
<!-- <test-sync :price='price' @changePrice='changePriceClick'></test-sync> -->
<test-sync :price.sync='price'></test-sync>
data () {
  return {
    price: 200,
    visible: false
  }
}

子组件

<h2>sync语法</h2>
<span>{{price}}</span>
<input type="number" v-model="inputPrice">
<h-button type='info' @click="changePriceClick">点击</h-button>
props: {
  price: {
    type: Number,
    default: 100
  }
},
data () {
  return {
    inputPrice: '',
    showRun: false
  }
},
methods: {
  // 子组件不要去修改父组件传递来的值
  // changePriceClick () {
  //   this.price = 200
  // }
  changePriceClick () {
    this.$emit('update:price', this.inputPrice - 0)
  }
}

补充vue动画和css动画

给要添加动画的内容加上transition 标签,配合name和enter/leave-active来使用

<h2>测试vue动画</h2>
<transition name='testRun'>
  <span v-show="showRun">动画效果</span>
</transition>
<h-button type='primary' @click="showRun = !showRun">动画</h-button>
data () {
  return {
    inputPrice: '',
    showRun: false
  }
},
// vue提供的动画配合css动画
.testRun-enter-active{
  animation: run 0.5s;
}
.testRun-leave-active {
  animation: run .5s reverse;
}
@keyframes run{
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}

搭建dialog组件

  1. 具名插槽(template配合v-slot指定占位符slot的name属性值即可,这样方便我们添加样式等等)
  2. props通信和校验
  3. sync语法

如果以上知识点没问题(参考高仿系列第一篇文章),以及明确了封装组件的一般套路,我们直接看源代码吧

弹窗标题,弹窗宽度,距顶部距离,主体内容,关闭弹窗字体图标,底部按钮,弹窗显示隐藏,弹出动画效果,等等都可以自定义

效果图

在这里插入图片描述

附源代码

/dialog.vue

<template>
  <!-- <div class="hDialog_wrapper">
    <div class="hDialog">
        <div class="hDialog_header">
            <span class="hDialog_title">提示</span>
            <button class="hDialog_headerbtn">
                <i class="one-icon-close"></i>
            </button>
        </div>
        <div class="hDialog_body">
            <span>这是一段信息</span>
        </div>
        <div class="hDialog_footer">
            <h-button>取消</h-button>
            <h-button type="primary">确定</h-button>
        </div>
    </div>
 </div> -->
 <!-- 给整个弹窗加一个动画 -->
 <transition name="showDialog">
     <!-- hDialog_wrapper外层遮罩层 -->
    <div class="hDialog_wrapper" v-show="visible" @click.self="handleClose">
        <!-- hDialog实实在在的弹框 -->
        <div class="hDialog" :style="{width,marginTop}">
            <div class="hDialog_header">
                <!-- 借助具名插槽方便给标题定义样式 -->
                <slot name="title">
                    <span class="hDialog_title">{{title}}</span>
                </slot>
                <button class="hDialog_headerbtn">
                    <i :class="[icon]" @click="handleClose"></i>
                </button>
            </div>
            <div class="hDialog_body">
                <slot name="bodyContent">
                    <div>{{bodyContent}}</div>
                </slot>
            </div>
            <div class="hDialog_footer">
                <slot name="footer">
                    <div>{{footer}}</div>
                </slot>
            </div>
        </div>
    </div>
 </transition>
</template>

<script>
export default {
    name: 'HDialog',
    props: {
        title: {
            type: String,
            default: ''
        },
        width: {
            type: String,
            default: ''
        },
        marginTop: {
            type: String,
            default: ''
        },
        icon: {
            type: String,
            default: ''
        },
        bodyContent: {
            type: String,
            default: ''
        },
        footer: {
            type: String,
            default: ''
        },
        visible: {
            type: Boolean,
            default: false
        }
    },
    methods: {
        // sync修饰符的作用
        handleClose () {
            this.$emit('update:visible', false)
        }
    }
}
</script>

<style lang='scss' scoped>
    .hDialog_wrapper{
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        overflow: auto;
        margin: 0;
        z-index: 2001;
        background-color: rgba(0,0,0,0.5);
        .hDialog{
            position: relative;
            margin: 15vh auto 50px;
            background: #fff;
            border-radius: 2px;
            box-shadow: 0 1px 3px rgba(0,0,0,0.3);
            box-sizing: border-box;
            width: 30%;
            &_header{
            padding: 20px 20px 10px;
            .hDialog_title{
                line-height: 24px;
                font-size: 18px;
                color: #303133;
            }
            .hDialog_headerbtn{
                position: absolute;
                top: 20px;
                right: 20px;
                padding: 0;
                background: transparent;
                border: none;
                outline: none;
                cursor: pointer;
                font-size: 16px;
                .one-icon-close{
                    color:909399
                }
            }
            }
            &_body{
                padding: 30px 20px;
                color: #606266;
                font-size: 14px;
                word-break: break-all;
            }
            &_footer{
                padding: 10px 20px 20px;
                text-align: right;
                box-sizing: border-box;
                ::v-deep .one-button:first-child{
                    margin-right: 20px;
                }
            }
        }
    }
    .showDialog-enter-active{
        animation: show .4s;
    }
    .showDialog-leave-active{
        animation: show .4s reverse; 
    }
    @keyframes show {
        0% {
            opacity: 0;
            transform: translateY(-20px);
        }
        100% {
            opacity: 1;
            transform: translateY(0px);
        }
    }
</style>

/App.vue

<!-- 弹窗标题,弹窗宽度,距顶部距离,主题内容,关闭弹窗等等都可以自定义 -->
<h2>dialog组件</h2>
<h-button @click="visible = true" type='primary'>点击显示dialog</h-button>
<h-dialog width='50%' marginTop='200px' icon='hButton-icon-cha' :visible.sync = 'visible'>
  <!-- 使用v-slot指定名称的插槽 -->
  <template v-slot:title>
    <h3 style="color:red">我是标题</h3>
  </template>
  <template v-slot:bodyContent>
    <div class="bodyContent">
      <span>一个段落</span>
      <h-button type='primary'>一个按钮</h-button>
      <span style="margin-left:20px">一个span</span>
    </div>
    <hr>
    <div class="bodyContent">
      <span>一个段落</span>
      <h-button type='primary'>一个按钮</h-button>
      <span style="margin-left:20px">一个span</span>
    </div>
  </template>
  <template v-slot:footer>
    <h-button type='primary' @click="visible = false">取消</h-button>
    <h-button type='primary' @click="visible = false">确定</h-button>
  </template>
</h-dialog>

/main.js

import Vue from 'vue'
import App from './App.vue'
import HButton from './components/button'
import HDialog from './components/dialog'
import './static/iconfont.css'

Vue.config.productionTip = false
Vue.component(HButton.name, HButton)
Vue.component(HDialog.name, HDialog)

new Vue({
  render: h => h(App)
}).$mount('#app')
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值