补充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组件
- 具名插槽(template配合v-slot指定占位符slot的name属性值即可,这样方便我们添加样式等等)
- props通信和校验
- 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')