基于JavaScript,element-ui组件库中dialog实现。
什么是组件化思想?
这个我学会了再告诉大家吧~
这个demo怎么做:
从构建组件到使用组件,其实就是通过写出一个可复用性强的class,我们想要使用这个组件,就需要利用这个class不断的构造对象实例出来。
步骤为:
- 找出Dialog页面的需求细节
- 基本的打开关闭对话框功能:div.dialog的display属性更改;
- 基本的渲染:div.dialog的transition属性:针对opacity透明度渐进、transform偏移滑入。
- 给这个class赋予更强的复用性,在new的时候允许添加更多参数($root对象形式)params:options。
2.1 针对需求细节1,完成HTML,CSS的雏形
DOM结构
- dialog
- main
+ header
+ title
+ span.close
+ content
+ footer
+ button.cancel
+ button.confirm
2.2 针对需求细节1,写JS写到什么境界呢,你一点击就能弹出dialog来,点击取消键确认键也能有效。至此实现页面需求细节第一点;
根据页面需求细节2继续增加CSS和JS的内容。
根据页面需求细节3 ,添加params,改动JS内容。
在纸上写出DOM结构,一步步实现步骤2.1雏形:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>dialog对话框页面细节</title>
<style>
.container {
max-width: 800px;
margin: 30px auto;
box-shadow: 0 0 2px 0;
border-radius: 4px;
padding: 16px;
}
.button {
padding: 5px;
background-color: transparent;
outline: none;
border: 1px solid #ccc;
border-radius: 2px;
}
.button:hover {
cursor: pointer;
border-color: lightskyblue;
color: lightskyblue;
}
.dialog {
position: fixed;
background-color: rgba(0, 0, 0, 0.3);
left: 0;
right: 0;
top: 0;
bottom: 0;
}
.dialog .main {
background: #fff;
width: 40%;
margin: 100px auto;
border-radius: 6px;
padding: 20px;
}
.dialog .header {
display: flex;
align-items: center;
}
.dialog .title {
margin: 0;
}
.dialog .close {
margin-left: auto;
cursor: pointer;
}
.dialog .footer {
display:flex;
align-items:center;
justify-content: flex-end;
}
.dialog .footer .button {
margin-left: 10px;
}
</style>
</head>
<body>
<div class="container">
<h2>Dialog组件</h2>
<button class="button open-dlg">点我打开对话框。</button>
<div class="dialog">
<div class="main">
<div class="header">
<p>标题</p>
<span class="iconfont icon-close close">❌</span>
</div>
<div class="content">
<p>这是一句话</p></div>
<div class="footer">
<button class="btn-cancel button">取消</button>
<button class="btn-confirm button">确定</button>
</div>
</div>
</div>
</div>
</body>
</html>
一步步实现2.2.
先看怎么使用组件,丰满这个组件的内容:
<script>
class Dialog {
constructor($root) {
}
}
let $ = s => document.querySelector(s)
let dialog = new Dialog($('.dialog'))
$('.open-dlg').onclick = function() {
dialog.show()
}
</script>
在为span.close绑定事件时犯了个错误,这还是我上一篇文章提到的,淦。
DOM节点无法像对象实例那样调用原型方法。
<script>
class Dialog {
constructor($root) {
this.$root = $root
this.$close = $root.querySelector('.close')
this.bind()
}
bind() {
let self = this
this.$close.onclick =function() {
// self.$root.hide()
// self.$root.classList.remove('show')
self.hide()
}
}
show() {
this.$root.classList.add('show')
}
hide() {
this.$root.classList.remove('show')
}
}
let $ = s => document.querySelector(s)
let dialog = new Dialog($('.dialog'))
$('.open-dlg').onclick = function() {
dialog.show()
}
</script>
照着span.close继续绑定;此时按钮生效,需求细节1实现。
<script>
class Dialog {
constructor($root) {
this.$root = $root
this.$close = $root.querySelector('.close')
this.bind()
}
bind() {
let self = this
this.$close.onclick =function() {
// self.$root.hide()
// self.$root.classList.remove('show')
self.hide()
}
this.$root.querySelector('.btn-cancel').onclick = function() {
self.hide()
}
this.$root.querySelector('.btn-confirm').onclick = function() {
self.hide()
}
}
show() {
this.$root.classList.add('show')
}
hide() {
this.$root.classList.remove('show')
}
}
let $ = s => document.querySelector(s)
let dialog = new Dialog($('.dialog'))
$('.open-dlg').onclick = function() {
dialog.show()
}
</script>
步骤3,往CSS和JS添加渐近细节
如果有代码对比插件就好了,不赘述。需要注意利用setTimeOut()将效果异步实现,否则JS引擎会进行优化,将所有渐近细节一步到位,这显然不是我们想要的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>dialog</title>
<style>
.container {
max-width: 800px;
margin: 30px auto;
border-radius: 4px;
box-shadow: 0 0 4px 0px rgba(0, 0, 0, 0.3);
padding: 16px;
}
.button {
padding: 8px 16px;
font-size: 14px;
font-weight: 500;
color: #303030;
border: 1px solid #ccc;
border-radius: 4px;
outline: none;
cursor: pointer;
/* position: relative; */
background-color: transparent;
}
.button:hover {
border-color: lightskyblue;
color: lightskyblue
}
.dialog {
background-color: rgba(0, 0, 0, 0.3);
/* position: absolute; */
position: fixed;
/* width: 100%; */
/* height: 100%; */
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
/*渐近细节*/
opacity: 0;
transition: all .3s;
}
.dialog.show {
display: block;
}
.dialog .main {
width: 40%;
background-color: #fff;
margin: 30px auto;
border-radius: 6px;
padding: 16px;
/*渐近细节*/
transform: translateY(-100%);
transition: all .3s;
}
.dialog .header {
display: flex;
align-items: center;
}
.dialog .header > p {
margin: 0;
}
.dialog .header .close {
margin-left: auto;
cursor: pointer;
}
.dialog .footer {
display: flex;
justify-content: flex-end;
}
.dialog .footer .button {
margin-left: 15px;
}
/*渐近细节*/
.dialog.appear {
opacity: 1;
}
.dialog.appear .main {
transform: translateY(40px);
}
</style>
</head>
<body>
<div class="container">
<h2>Dialog组件</h2>
<button class="button open-dlg">点我打开对话框。</button>
<div class="dialog">
<div class="main">
<div class="header">
<p>标题</p>
<span class="iconfont icon-close close">❌</span>
</div>
<div class="content">
<p>这是一句话</p></div>
<div class="footer">
<button class="btn-cancel button">取消</button>
<button class="btn-confirm button">确定</button>
</div>
</div>
</div>
</div>
<script>
class Dialog {
constructor($root, options) {
this.$root = $root
this.$close = $root.querySelector('.close')
this.options = options
this.bind()
}
bind() {
let self = this
this.$close.onclick =function() {
// self.$root.hide()
// self.$root.classList.remove('show')
self.hide()
}
this.$root.querySelector('.btn-cancel').onclick = function() {
self.hide()
}
this.$root.querySelector('.btn-confirm').onclick = function() {
self.hide()
}
}
show() {
this.$root.classList.add('show')
setTimeout(() => this.$root.classList.add('appear'))
}
hide() {
this.$root.classList.remove('appear')
setTimeout(() => this.$root.classList.remove('show'), 400)
}
}
let $ = s => document.querySelector(s)
let dialog = new Dialog($('.dialog'))
$('.open-dlg').onclick = function() {
dialog.show()
}
</script>
</body>
</html>
实现步骤4 构建组件时传入对象
对使用组件的方法进行修改:
一步步实现2.2.
先看怎么使用组件,丰满这个组件的内容:
<script>
class Dialog {
constructor($root) {
}
}
let $ = s => document.querySelector(s)
let dialog = new Dialog($('.dialog'))
$('.open-dlg').onclick = function() {
dialog.show()
}
</script>
修正为传入onOk()、 onCancel();
<script>
class Dialog {
constructor($root, options) {
}
}
let $ = s => document.querySelector(s)
let dialog = new Dialog(document.querySelector('.dialog'), {
onOk() {
console.log('用户点了ok')
},
onCancel() {
console.log('用户点了取消')
}
})
$('.open-dlg').onclick = function() {
dialog.show()
}
</script>
最后这个组件就彻底成型了。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>dialog</title>
<style>
.container {
max-width: 800px;
margin: 30px auto;
border-radius: 4px;
box-shadow: 0 0 4px 0px rgba(0, 0, 0, 0.3);
padding: 16px;
}
.button {
padding: 8px 16px;
font-size: 14px;
font-weight: 500;
color: #303030;
border: 1px solid #ccc;
border-radius: 4px;
outline: none;
cursor: pointer;
/* position: relative; */
background-color: transparent;
}
.button:hover {
border-color: lightskyblue;
color: lightskyblue
}
.dialog {
background-color: rgba(0, 0, 0, 0.3);
/* position: absolute; */
position: fixed;
/* width: 100%; */
/* height: 100%; */
top: 0;
right: 0;
bottom: 0;
left: 0;
display: none;
/*渐近细节*/
opacity: 0;
transition: all .3s;
}
.dialog.show {
display: block;
}
.dialog .main {
width: 40%;
background-color: #fff;
margin: 30px auto;
border-radius: 6px;
padding: 16px;
/*渐近细节*/
transform: translateY(-100%);
transition: all .3s;
}
.dialog .header {
display: flex;
align-items: center;
}
.dialog .header > p {
margin: 0;
}
.dialog .header .close {
margin-left: auto;
cursor: pointer;
}
.dialog .footer {
display: flex;
justify-content: flex-end;
}
.dialog .footer .button {
margin-left: 15px;
}
/*渐近细节*/
.dialog.appear {
opacity: 1;
}
.dialog.appear .main {
transform: translateY(40px);
}
</style>
</head>
<body>
<div class="container">
<h2>Dialog组件</h2>
<button class="button open-dlg">点我打开对话框。</button>
<div class="dialog">
<div class="main">
<div class="header">
<p>标题</p>
<span class="iconfont icon-close close">❌</span>
</div>
<div class="content">
<p>这是一句话</p></div>
<div class="footer">
<button class="btn-cancel button">取消</button>
<button class="btn-confirm button">确定</button>
</div>
</div>
</div>
</div>
<script>
class Dialog {
constructor($root, options) {
this.$root = $root
this.$close = $root.querySelector('.close')
this.options = options
this.onOk = options.onOk || function(){}
this.onCancel = options.onCancel || function(){}
this.bind()
}
bind() {
let self = this
this.$close.onclick =function() {
// self.$root.hide()
// self.$root.classList.remove('show')
self.hide()
self.onCancel()
}
this.$root.querySelector('.btn-cancel').onclick = function() {
self.hide()
self.onCancel()
}
this.$root.querySelector('.btn-confirm').onclick = function() {
self.hide()
self.onOk();
}
}
show() {
this.$root.classList.add('show')
setTimeout(() => this.$root.classList.add('appear'))
}
hide() {
this.$root.classList.remove('appear')
setTimeout(() => this.$root.classList.remove('show'), 400)
}
}
let $ = s => document.querySelector(s)
let dialog = new Dialog($('.dialog'), {
onOk() {
console.log('用户点了ok')
},
onCancel() {
console.log('用户点了cancel')
}
})
$('.open-dlg').onclick = function() {
dialog.show()
}
</script>
</body>
</html>