day3,弹层创建
- 在index.html中,定义一个class为view的div,展示一张图片,作为点击触发视频播放器弹层的入口
1
2
3<div class="view">
<img>
</div> - 在main.ts中,通过querySelector()获取.view绑定的dom元素,并监听他的点击事件
1
2
3
4
5
6let view = document.querySelector(".view")
view.addEventListener('click',function (){
let dom = document.querySelector('body')
console.log('222')
}) - 根目录下创建一个组件目录,在内部新建有关弹出的组件js,这里我创建了components/popView/index.ts
- 在index.ts中定义popView函数、view类,在函数内返回view的对象实例,并将他导出。
1
2
3
4
5
6
7
8
9
10//index.js
function popView(){
return new view()
}
class view{
constructor(){}
}
export default popView - 为了对popView和view进行约束,防止他传入错误的参数,我们需要定义接口iView和接口iComponents并使用。让popView的参数根据iView定义。iView接口里声明了和创建播放器相关的参数,例如播放器的宽高、位置等,其中content是定义弹出的容器,例如弹出播放器,还是表单等等。iComponents接口对view内需要具备哪些方法,初始化方法init()、模板创建template()。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31//index.ts
//参数的定义
interface iView{
width?:string,
height?:string,
title?:string,
pos?:string,
mask?:boolean,
content?:()=>void
}
//组件的定义
interface iComponents{
//初始化
init(),
template()
}
function popView(options:iView){
return new view(options)
}
class view implements iComponents{
constructor(private settings:iView) {
}
init() {
}
template() {
}
}
export default popView - 先尝试点击后,在body中新增一个dom元素。首先在iComponents接口里新增tempContainer,声明为HTMLElement,然后再template函数中,将他作为虚拟dom进行操作,并挂载到body内。将template写进init(),然后把init()写进构造器,使对象被创建时就会初始化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40//参数的定义
interface iView{
width?:string,
height?:string,
title?:string,
pos?:string,
mask?:boolean,
content?:()=>void
}
//组件的定义
interface iComponents{
tempContainer:HTMLElement
//初始化
init(),
template(),
handel:()=>void
}
function popView(options:iView){
return new view(options)
}
class view implements iComponents{
tempContainer;
constructor(private settings:iView) {
this.init()
}
init() {
this.template()
}
template() {
this.tempContainer = document.createElement('div')
this.tempContainer.innerHTML= `<h1>222</h1>`
document.body.appendChild(this.tempContainer)
}
handel() {
}
}
export default popView - 测试添加dom元素成功,接着为view对象弄上默认值。这里用Object.assign方法,把默认值写在第一个参数,构造器接收的参数写在第二个参数。这样就可以实现,如果构造器有对应参数就进行覆盖。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55//参数的定义
interface iView{
width?:string,
height?:string,
title?:string,
pos?:string,
mask?:boolean,
content?:()=>void
}
//组件的定义
interface iComponents{
tempContainer:HTMLElement
//初始化
init(),
template(),
handel:()=>void
}
function popView(options:iView){
return new view(options)
}
class view implements iComponents{
tempContainer;
constructor(private settings:iView) {
//写好默认值,如果后面有参数,用assign复制就可以覆盖默认值
this.settings = Object.assgin({
width:'100%',
height:'100%',
title:'',
pos:'center',
mask:true,
//定义弹层的容器,是弹出表单还是弹出视频等等
content:()=>{}
},settings)
this.init()
}
init() {
this.template()
}
template() {
this.tempContainer = document.createElement('div')
this.tempContainer.innerHTML=
`
<h1>
222
</h1>
`
document.body.appendChild(this.tempContainer)
}
handel() {
}
}
export default popView - 测试发现没有问题,就开始进行真正的需求,弹出一个窗口。先进行基本的窗口HTML。一部分navbar,一部分content。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39template() {
this.tempContainer = document.createElement('div')
//样式添加
this.tempContainer.style.width = this.settings.width
this.tempContainer.style.height = this.settings.height
this.tempContainer.innerHTML =
`
<div>
<h3>${this.settings.title}</h3>
<i class="iconfont player-icon_close"></i>
</div>
<div>
</div>
`
//挂载
document.body.appendChild(this.tempContainer)
//使pos生效
switch (this.settings.pos) {
case 'left':
this.tempContainer.style.left = 0
this.tempContainer.style.top = (window.innerHeight - this.tempContainer.offsetHeight) + 'px'
break;
case 'right':
this.tempContainer.style.right = 0
this.tempContainer.style.top = (window.innerHeight - this.tempContainer.offsetHeight) + 'px'
break;
default:
this.tempContainer.style.left = (window.innerWidth - this.tempContainer.offsetWidth) / 2 + 'px'
this.tempContainer.style.top = (window.innerHeight - this.tempContainer.offsetHeight) / 2 + 'px'
break;
}
if(this.settings.mask){
this.mask = document.createElement('div')
this.mask.className = styles.mask
this.mask.style.width = '100%'
this.mask.style.height = document.body.offsetHeight + 'px'
document.body.appendChild(this.mask)
}
} - 窗口写好了,但是没有样式,看起来贼奇怪,所有我们在组件所在目录,增加一个index.css,在index.ts中进行导入。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31.popup{
position: fixed;
z-index: 20;
}
.popup-title{
height: 60px;
background-color: #f5f5f5;
display: flex;
justify-content: space-between;
align-items: center;
}
.popup-title h3{
font-size: 18px;
margin-left: 20px;
}
.popup-title i{
font-size: 18px;
margin-right: 20px;
cursor: pointer;
}
.popup-content{
height: calc(100% - 60px);
background-color: white;
}
.mask{
position: absolute;
left: 0;
top: 0;
z-index: 10;
background-color: rgba(0, 0, 0, .5);
} - 但是此时又诞生一个新的问题,ts会提示找不到css模块。所以在组件的目录下,我们还需要创建一个index.css.d.ts文件,帮助ts识别。
1
2
3
4
5declare const styles : {
readonly "popup" : string
readonly "popup-title" : string
}
export default styles - 导入css文件后,需要把相应属性绑定到dom上,所以我们通过$在模板字符串内绑定。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93let styles = require('./index.css')
//参数的定义
interface iView{
width?:string,
height?:string,
title?:string,
pos?:string,
mask?:boolean,
content?:()=>void
}
//组件的定义
interface iComponents{
tempContainer:HTMLElement
//初始化
init(),
template(),
handel:()=>void
}
function popView(options:iView){
return new view(options)
}
class view implements iComponents{
//虚拟dom对象
tempContainer;
//遮罩层对象
mask;
constructor(private settings:iView) {
//写好默认值,如果后面有参数,用assign复制就可以覆盖默认值
this.settings = Object.assign({
width: '100%',
height: '100%',
title: '',
pos: 'center',
mask: true,
content: function () { }
}, this.settings)
// this.settings = {
// width: settings.width || '100%',
// height: settings.height || '100%',
// title: settings.title || '',
// pos: settings.pos || 'center',
// mask: settings.mask !== undefined ? settings.mask : true,
// content: settings.content || (() => console.log('22'))
// };
this.init()
}
init() {
this.template()
// this.settings.mask && this.createMask()
}
template() {
this.tempContainer = document.createElement('div')
//样式添加
this.tempContainer.style.width = this.settings.width
this.tempContainer.style.height = this.settings.height
this.tempContainer.className = styles.popup
this.tempContainer.innerHTML =
`
<div class="${styles['popup-title']}">
<h3>${this.settings.title}</h3>
<i class="iconfont player-icon_close"></i>
</div>
<div class="${styles['popup-content']}">
</div>
`
//挂载
document.body.appendChild(this.tempContainer)
//使pos生效
switch (this.settings.pos) {
case 'left':
this.tempContainer.style.left = 0
this.tempContainer.style.top = (window.innerHeight - this.tempContainer.offsetHeight) + 'px'
break;
case 'right':
this.tempContainer.style.right = 0
this.tempContainer.style.top = (window.innerHeight - this.tempContainer.offsetHeight) + 'px'
break;
default:
this.tempContainer.style.left = (window.innerWidth - this.tempContainer.offsetWidth) / 2 + 'px'
this.tempContainer.style.top = (window.innerHeight - this.tempContainer.offsetHeight) / 2 + 'px'
break;
}
}
//事件操作
handel() {
}
}
export default popView - 这种场景的窗口,一般都会有遮罩层,所有我们在模板创建方法里,增加一个判断,如果遮罩层选项为true,就多增加一个遮罩层。
1
2
3
4
5
6
7if(this.settings.mask){
this.mask = document.createElement('div')
this.mask.className = styles.mask
this.mask.style.width = '100%'
this.mask.style.height = document.body.offsetHeight + 'px'
document.body.appendChild(this.mask)
} - 给了css之后,发现弹出的窗口是全屏的,因为我们默认的长宽是100%的,我们要在main.js里,对popView传参
1
2
3
4
5
6popView({
width:'880px',
height:'556px',
pos:'center',
mask:true,
})