使用Web Component 开发Dialog组件
这回灵感一直在,虽然这回只是做了外形,事件交互那些都没添加,不过给了我很大的动力。话不多说,搞起来。 看图看图
效果图
html
<!-- 方法1 -->
<hd-dialog title="这个是title" content="这个是内容" width="80%" top="10%" visible="open"></hd-dialog>
<!-- 方法2 -->
<hd-dialog showClose="close" visible="open">
<div slot="title">这个是title2</div>
<div slot="content">这个是内容2</div>
<div slot="footer">这个是footer2</div>
</hd-dialog>
dialog.js
// <hd-dialog></hd-dialog>
class HdDialog extends HTMLElement {
constructor() {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
this.shadowDom = shadowRoot;
this.data()
this._style()
this._html()
this.render()
}
// 初始化数据
data() {
this.state = {
title: '', // 标题
width: '50%', // 弹窗宽度
visible: 'close', // 是否显示Dialog close || open
top: '20vh', // Dialog距离顶部的高度
mask: 'open', // 是否需要遮罩层
showClose: 'open',
}
}
// 样式引入
_style() {
// 在shadowRoot创建css
let dialogCss = document.createElement('style')
let width = this.getAttribute('width')
let top = this.getAttribute('top')
dialogCss.textContent = `
.hd__dialog {
position: fixed;
z-index: 31;
top: ${top ? top : '20vh'};
left: 50%;
width: ${width ? width : '50%'};
background-color: #fff;
transform: translateX(-50%);
border-radius: 2px;
box-shadow: 0 1px 3px rgba(0,0,0, .3);
box-sizing: border-box;
}
.hd__dialog_mask {
position: fixed;
width: 100%;
height: 100%;
background-color: #000;
opacity: .5;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: 30;
}
.hd__dialog-header {
width: 100%;
padding: 12px;
border-bottom: 1px solid #ebeef5;
box-sizing: border-box;
position: relative;
}
.hd__dialog-close {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
}
.close-icon {
position: relative;
width: 2px;
height: 15px;
background: #909399;
transform: rotate(45deg);
display: inline-block;
margin-right: 10px;
}
.close-icon:after {
position: absolute;
top: 0;
left: 0;
content: "";
width: 2px;
height: 15px;
background: #909399;
transform: rotate(270deg);
margin-right: 10px;
}
.hd__dialog-content {
width: 100%;
padding: 12px;
box-sizing: border-box;
position: relative;
}
.hd__dialog-footer {
width: 100%;
padding: 12px;
border-top: 1px solid #ebeef5;
box-sizing: border-box;
position: relative;
}
.footer-wrap {
width: 100%;
display: flex;
justify-content: flex-end;
gap: 12px;
}
.el-hide {
display: none;
}
`
this.shadowRoot.appendChild(dialogCss)
}
// html
_html() {
let container = document.createElement('div')
container.classList.add('hd__dialog')
this.getAttrVisible()
if(this.state.visible !== 'open') {
container.classList.add('el-hide')
}
this.getAttrMask()
if(this.state.mask === 'open' && this.state.visible === 'open') {
// 创建content
let mask = document.createElement('div')
mask.classList.add('hd__dialog_mask')
this.shadowRoot.appendChild(mask);
}
// 创建header
let header = document.createElement('div')
header.classList.add('hd__dialog-header')
header.innerHTML = this._htmlHeader()
container.appendChild(header)
// 创建content
let content = document.createElement('div')
content.classList.add('hd__dialog-content')
content.innerHTML = this._htmlContent()
container.appendChild(content)
// 创建footer
let footer = document.createElement('div')
footer.classList.add('hd__dialog-footer')
footer.innerHTML = this._htmlFooter()
container.appendChild(footer)
console.log('container--', container)
this.shadowRoot.appendChild(container);
}
render() {
this.getAttrShowClose()
let closeBox = this.shadowRoot.querySelector('.hd__dialog-close')
if(this.state.showClose === 'close') {
closeBox.classList.add('el-hide')
}
}
// header的元素内容
_htmlHeader() {
let title = this.getAttribute('title')
let innerHTML = `
<slot name="title">
<div>${title}</div>
</slot>
<div class="hd__dialog-close">
<span class="close-icon"></span>
</div>
`
return innerHTML;
}
// content的元素内容
_htmlContent() {
let content = this.getAttribute('content')
let innerHTML = `
<slot name="content">
<div>${content}</div>
</slot>
`
return innerHTML;
}
// footer的元素内容
_htmlFooter() {
let innerHTML = `
<slot name="footer">
<div class="footer-wrap">
<hd-button size="mini">取消</hd-button>
<hd-button size="mini" type="primary">确认</hd-button>
</div>
</slot>
`
return innerHTML;
}
// 获取属性 hideClose 显示关闭图标
getAttrShowClose() {
let close = this.getAttribute('showClose')
let atrrAll = ['close', 'open']
if(close && atrrAll.includes(close)) {
this.state.showClose = close
} else {
this.state.showClose = 'open'
}
}
// 获取属性 mask 遮罩层
getAttrMask() {
let mask = this.getAttribute('mask')
let atrrAll = ['close', 'open']
if(mask && atrrAll.includes(mask)) {
this.state.mask = mask
} else {
this.state.mask = 'open'
}
}
// 获取属性 mask 遮罩层
getAttrVisible() {
let visible = this.getAttribute('visible')
let atrrAll = ['close', 'open']
if(visible && atrrAll.includes(visible)) {
this.state.visible = visible
} else {
this.state.visible = 'close'
}
}
// 当监听的值发送变化时
attributeChangedCallback(attrName, oldVal, newVal) {
if(attrName === 'visible') {
this.state.visible = newVal
this._html()
}
}
}
customElements.define('hd-dialog',HdDialog);
小结
好啦! 就写这么多了 要下班了。我现在很兴奋, 我正有很多的鬼点子,不过我需要时间。把它们叫出来。对的 我要更多的时间去弄他们。 提前祝大家国庆快乐。