本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
el-dialog中展示的内容过多时,无法完全展示出来,需要更改el-dialog或者添加滚动条才能展示出来。最近有个需求就是,为了尽可能多的展示内容,在用户的操作下,直接让el-dialog充满整个窗口,就是el-dialog全屏,当然,也得能够还原。
思路
那怎么才能够让el-dialog变大还原呢?无非就是通过更改样式来实现,在用户的操作下,根据不同的值将el-dialog的样式进行更改。
代码
- 首先,创建一个普通的
el-dialog弹窗,然后在上面添加即将实现的全屏指令v-fullScreen:
<el-dialog
:visible.sync="visible"
width="500px"
title="弹窗表单"
v-fullScreen
>
<div style="height: 500px;">
表单内容
</div>
</el-dialog>
效果:
因为还没开始编写指令,所以只是一个普通的弹窗。
- 然后,创建书写指令的
js文件,然后,将基础的指令代码写上:
const fullScreenDirective = Vue => {
Vue.directive('fullScreen', {
bind: function (el, binding, vnode) {}
})
}
export default fullScreenDirective
因为我打算将所有的变大还原操作都在指令内部完成,不接收任何参数,因此只使用bind这个钩子就行了。
bind是在组件挂载指令时就会触发的,且只触发一次,可以在这里面将最大化和还原的逻辑都写上。
- 接着,获取
el-dialog中的header元素,把改变窗口大小的图标按钮加到header尾部,需要注意的是,header尾部还有一个关闭按钮,不要与之重叠,详细看下面的代码和注释:
const fullScreenDirective = Vue => {
Vue.directive('fullScreen', {
bind: function (el, binding, vnode) {
// el是挂载指令的dom元素,在这个指令里面就是`.el-dialog__wrapper`
const header = el.querySelector('.el-dialog__header')
if (!header) return
// 将header的paddingRight变大,然后将全屏按钮`float:right`,这样可以保证全屏按钮在header右侧,且不会与关闭按钮重叠
header.style.paddingRight = '43px'
// 创建全屏按钮,并设定样式
const fullScreenBtn = document.createElement('button')
fullScreenBtn.type = 'button'
fullScreenBtn.style = 'float:right;padding:0;background: 0 0;border:0;outline:0;cursor:pointer;font-size:16px;'
const fullScreenIcon = document.createElement('i')
fullScreenIcon.className = 'el-icon el-icon-full-screen'
fullScreenBtn.append(fullScreenIcon)
// 将全屏按钮添加到header中
header.append(fullScreenBtn)
}
})
}
export default fullScreenDirective
效果:
可以看到,按钮已经添加上去了。因为个人不喜欢写太多的全局
class,所以指令里的样式都是写在style上。
- 给按钮添加点击事件,这个比较简单,通过
addEventListener即可,代码如下:
fullScreenBtn.addEventListener('click', () => {})
关键是点击之后根据全屏标志将el-dialog的大小进行变大或者还原,那么,可以先定义一个全屏标志还表示来表示当前el-dialog是变大还是还原:
let isFullScreen = false
接下来,确定怎么设定样式让el-dialog全屏或者还原的。首先,确定要更改的dom元素是.el-dialog,也就是用户能看到的白色区域。然后,样式要怎么去改?
个人的方案是:
最大化时,通过
position:absolute,然后将top、bottom、left、right都设置为零,达到全屏的目的,但是因为.el-dialog本身设置了width,宽度无法全屏,要将width:100%即可;位置上,.el-dialog设置了margin-top,要将其置为零;
然后就是还原,因为高度的变大是position:absolute下top、bottom都为零的原因,所以将position设置为realtive即可还原高度,宽度的话,需要先使用一个变量记录原来的宽度,还原时将width设置回去即可;位置上,同样也是使用一个变量记录原本margin-top,还原时设置回去即可。 此时代码如下:
const fullScreenDirective = Vue => {
Vue.directive('fullScreen', {
bind: function (el, binding, vnode) {
// 是否全屏的标志
let isFullScreen = false
// 获取要改变带下的dom元素
const dialog = el.querySelector('.el-dialog')
const header = el.querySelector('.el-dialog__header')
if (!header || !dialog || !vnode) return
header.style.paddingRight = '43px'
// 从el-dialog组件实例中获取原本的width和margin-top
const { width, top } = vnode.componentInstance
const fullScreenBtn = document.createElement('button')
fullScreenBtn.type = 'button'
fullScreenBtn.style = 'float:right;padding:0;background: 0 0;border:0;outline:0;cursor:pointer;font-size:16px;'
const fullScreenIcon = document.createElement('i')
fullScreenIcon.className = 'el-icon el-icon-full-screen'
fullScreenBtn.append(fullScreenIcon)
// 全屏按钮点击事件
fullScreenBtn.addEventListener('click', () => {
// 更改全屏标志
isFullScreen = !isFullScreen
// 根据标志对弹窗的大小进行处理
handleFullScreen(dialog, isFullScreen, top, width)
return false
})
header.append(fullScreenBtn)
}
})
}
在上面的代码中,定义了handleFullScreen函数来处理弹窗大小的改变,接收四个参数,分别是要改变大小的dom元素dialog,全屏标志isFullScreen、原本的margin-top、原本的宽度width,实现代码如下,主要是对样式进行操作:
function handleFullScreen (dialog, isFullScreen, marginTop, width) {
if (!dialog) return false
if (isFullScreen) {
dialog.style.marginTop = '0'
dialog.style.position = 'absolute'
dialog.style.top = '0px'
dialog.style.bottom = '0px'
dialog.style.left = '0px'
dialog.style.width = '100%'
} else {
dialog.style.marginTop = marginTop
dialog.style.width = width
dialog.style.position = 'relative'
}
}
至此,就是实现了点击全屏按钮的功能:
header被双击时,也要能够改变弹窗的大小,方便用户的操作。基本代码与全屏按钮一样,不再赘述:
// header添加阴影,方便用户区分弹窗的`header`和`body`
header.style.boxShadow = '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)'
// 监听双击事件,与全屏按钮一样的逻辑操作:
header.addEventListener('dblclick', () => {
isFullScreen = !isFullScreen
handleFullScreen(dialog, isFullScreen, top, width)
return false
})
效果:
完整代码
function handleFullScreen (dialog, isFullScreen, marginTop, width) {
if (!dialog) return false
if (isFullScreen) {
dialog.style.marginTop = '0'
dialog.style.position = 'absolute'
dialog.style.top = '0px'
dialog.style.bottom = '0px'
dialog.style.left = '0px'
dialog.style.width = '100%'
} else {
dialog.style.marginTop = marginTop
dialog.style.width = width
dialog.style.position = 'relative'
}
}
const fullScreenDirective = Vue => {
Vue.directive('fullScreen', {
bind: function (el, binding, vnode) {
let isFullScreen = false
const dialog = el.querySelector('.el-dialog')
const header = el.querySelector('.el-dialog__header')
if (!header || !dialog || !vnode) return
header.style.paddingRight = '43px'
header.style.boxShadow = '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)'
const { width, top } = vnode.componentInstance
const fullScreenBtn = document.createElement('button')
fullScreenBtn.type = 'button'
fullScreenBtn.style = 'float:right;padding:0;background: 0 0;border:0;outline:0;cursor:pointer;font-size:16px;'
const fullScreenIcon = document.createElement('i')
fullScreenIcon.className = 'el-icon el-icon-full-screen'
fullScreenBtn.append(fullScreenIcon)
fullScreenBtn.addEventListener('click', () => {
isFullScreen = !isFullScreen
handleFullScreen(dialog, isFullScreen, top, width)
return false
})
header.append(fullScreenBtn)
header.addEventListener('dblclick', () => {
isFullScreen = !isFullScreen
handleFullScreen(dialog, isFullScreen, top, width)
return false
})
}
})
}
export default fullScreenDirective