補充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文法
如果以上知識點沒問題(參考高仿系列第一篇文章),以及明确了封裝元件的一般套路,我們直接看源代碼吧
彈窗标題,彈窗寬度,距頂部距離,主體内容,關閉彈窗字型圖示,底部按鈕,彈窗顯示隐藏,彈出動畫效果,等等都可以自定義
效果圖
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxSP9cHW0MmaOFTU61UeFRkYzgnMMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnLwUjN2EjN0ETM4ADNwEjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
附源代碼
/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')