先上车
废了废了,中间一堆事耽误了迟迟没有更新
来吧继续阅读组件源码,dialog组件安排上
个人觉得dialog组件的难点在于弹出框的流程,特别是层级的处理
当然其他小的知识点也是不少的,这就是阅读源码的快乐
上源码
源码大致分为三部分阅读,先易后难没毛病
html部分
打开packages/dialog/src/component.vue
<template>
<!--transition组件可以给任何元素和组件添加进入/离开过渡-->
<!--after-enter、after-leave是对应的钩子-->
<transition
name="dialog-fade"
@after-enter="afterEnter"
@after-leave="afterLeave">
<div
v-show="visible"
class="el-dialog__wrapper"
<!-- click.self 只当在 event.target 是当前元素自身时触发处理函数, 即点击弹框背景是触发,点击弹框内部元素不会触发 -->
@click.self="handleWrapperClick">
<div
role="dialog"
<!--亮点:通过改变key值来销毁div-->
:key="key"
aria-modal="true"
:aria-label="title || 'dialog'"
:class="['el-dialog', { 'is-fullscreen': fullscreen, 'el-dialog--center': center }, customClass]"
ref="dialog"
:style="style">
<!--dialog_header包含:标题、关闭按钮-->
<div class="el-dialog__header">
<!--标题-->
<slot name="title">
<span class="el-dialog__title">{
{ title }}</span>
</slot>
<!--关闭按钮-->
<button
type="button"
class="el-dialog__headerbtn"
aria-label="Close"
v-if="showClose"
@click="handleClose">
<i class="el-dialog__close el-icon el-icon-close"></i>
</button>
</div>
<!--中间的内容-->
<div class="el-dialog__body" v-if="rendered"><slot></slot></div>
<!--底部内容-->
<div class="el-dialog__footer" v-if="$slots.footer">
<slot name="footer"></slot>
</div>
</div>
</div>
</transition>
</template>
总结:
1、亮点:通过改变key值来销毁div(铁子们还知道vue中key的其他用法吗?)
2、vue内置transition
组件及其钩子函数的灵活运用
3、@click.self
指触发元素自身时生效
script部分
还是packages/dialog/src/component.vue
<script>
// Popup用来对dialog弹框的流程控制,是下一小节分析的重点
import Popup from 'element-ui/src/utils/popup';
// migrating.js 主要目的是在浏览器控制台输出element ui 已经移除的一些属性
import Migrating from 'element-ui/src/mixins/migrating';
// emitter.js 中有两个方法,dispatch是用于派发事件,而broadcast用于广播到子组件以及子孙指定组件
import emitter from 'element-ui/src/mixins/emitter';
export default {
name: 'ElDialog',
mixins: [Popup, emitter, Migrating],
props: {
title: {
type: String,
default: ''
},
modal: {
type: Boolean,
default: true
},
modalAppendToBody: {
type: Boolean,
default: true
},
appendToBody: {
type: Boolean,
default: false
},
lockScroll: {
type: Boolean,
default: true
},
closeOnClickModal: {
type: Boolean,
default: true
},
closeOnPressEscape: {
type: Boolean,
default: true
},
showClose: {
type: Boolean,
default: true
},
width: String,
fullscreen: Boolean,
customClass: {
type: String,
default: ''
},
top: {
type: String,
default: '15vh'
},
beforeClose: Function,
center: {
type: Boolean,
default: false
},
destroyOnClose: Boolean
},
data() {
return {
closed: false,
key: 0
};
},
watch: {
// 监听visible来控制弹框的打开与关闭
visible(val) {
if (val) {
/* 组件打开时的流程 */
this.closed = false;
// 执行组件外部绑定的open方法,如 <el-dialog @open=openDialog />
this.$emit('open');
// 给弹框绑定scroll事件,滚动时触发updatePopper,通过emitter.js中broadcast向子孙组件广播 让他们更新 Popper
this.$el.addEventListener('scroll', this.updatePopper);
// 然后dialog 滚动到顶部
this.$nextTick(() => {
this.$refs.dialog.scrollTop = 0;
});
// appendToBody属性用来控制Dialog自身是否插入至body元素上
if (this.appendToBody) {
document.body.appendChild(this.$el);
}
} else {
/* 组件关闭时的流程 */
// 移除scroll事件
this.$el.removeEventListener('scroll', this.updatePopper);
// 执行组件外部绑定的open方法,如 <el-dialog @close=closeDialog />
if (!this.closed) this.$emit('close');
// 如果设置destroyOnClose,该属性用来控制关闭时销毁Dialog中的元素,通过改变key值来销毁组件
if (this.destroyOnClose) {
this.$nextTick(() => {