一、永远点不到的方块

示例:https://antmoe.gitee.io/project/2020/04/25/1.html

实现思路:

  1. 获取当前浏览器窗口的宽度和高度

    既然是随机显示,那么位置不能超出当前浏览器的窗口。

  2. 获取div的宽度

  3. 计算宽度高度的最大值

    也就说小方块移动的位置的边界。

  4. 为元素注册click(mouseover)事件

    也就是鼠标点击(悬停)时触发的事件

    click:点击事件

    mouseover:悬停事件

源代码
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
overflow: hidden;
}

.box {
width: 100px;
height: 100px;
background-color: lightsalmon;
text-align: center;
line-height: 100px;
color: #333;
font-size: 14px;
position: fixed;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
cursor: pointer;
}
</style>
</head>

<body>
<div class="box">来点我呀。。</div>
<script>
var box = document.getElementsByClassName('box')[0]
// 1. 获取当前浏览器窗口的宽度和高度
const WIDTH = window.innerWidth
const HEIGHT = window.innerHeight
// 2. 获取DIV元素的宽高
const divStyle = window.getComputedStyle(box)
const divWidth = parseFloat(divStyle.width)
const divHeight = parseFloat(divStyle.height)
// 3. 计算宽度和高度的最大值
const maxWidth = WIDTH - divWidth
const maxHeight = HEIGHT - divHeight
// 4. 为元素注册click事件
box.addEventListener('mouseover', function (event) {
// a. 随机两个坐标值(水平和垂直)
var left = Math.random() * maxWidth
var top = Math.random() * maxHeight
// b. 将随机值设置给div元素
box.style.left = left + 'px'
box.style.top = top + 'px'
})
</script>
</body>

</html>

二、双击图片放大

这个有两种方式实现,

  1. 常规的使用两个div,大图默认是不显示的,当小图被双击后,大图就显示。
  2. 使用css的变形,scale

常规方式

https://antmoe.gitee.io/project/2020/04/25/2.html

常规方式很简单,首先是两个一模一样的div结构

1
2
3
4
5
6
7
8
<!-- 图片默认大小的显示效果 -->
<div class="default">
<img src="https://ae01.alicdn.com/kf/H68f882508c57456486095a78dca17ba9X.jpg">
</div>
<!-- 图片双击放大的显示效果 -->
<div class="scalable">
<img src="https://ae01.alicdn.com/kf/H68f882508c57456486095a78dca17ba9X.jpg">
</div>

接下来js代码就比较简单了,大体思路为:

  1. 获取default与scalable的div。

  2. 获取需要放大显示的img,也就是scalable下的img标签

  3. 为default对象设置双击事件

    小图双击,则大图显示

  4. 为scalable对象设置双击事件

    大图双击,则大图消失

源代码
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.default,
.scalable,
.scalable img {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}

.default {
cursor: pointer;
}

.default img {
display: block;
width: 300px;
border-radius: 20px;
box-shadow: 0 0 25px 5px #d9d9d9;
}

.scalable {
transform: all 3s;
}

.scalable img {
display: block;
height: 700px;
border-radius: 40px;
width: 0;
height: 0;
transition: all 1s;

}
</style>
</head>

<body>
<!-- 图片默认大小的显示效果 -->
<div class="default">
<img src="https://ae01.alicdn.com/kf/H68f882508c57456486095a78dca17ba9X.jpg">
</div>
<!-- 图片双击放大的显示效果 -->
<div class="scalable">
<img src="https://ae01.alicdn.com/kf/H68f882508c57456486095a78dca17ba9X.jpg">
</div>
<script>
var defaultElement = document.getElementsByClassName('default')[0]
var scalableElement = document.getElementsByClassName('scalable')[0]
var scalableImg = scalableElement.firstElementChild
defaultElement.addEventListener('dblclick', function () {
scalableImg.style.width = '900px'
scalableImg.style.height = '600px'
})
scalableElement.addEventListener('dblclick', function () {

scalableImg.style.width = '0px'
scalableImg.style.height = '0px'
})
</script>
</body>

</html>

scale方式

https://antmoe.gitee.io/project/2020/04/25/3.html

与常规方式较为相似,但只需要一个div即可。

当双击时,为img设置变形属性scale即可。

至于判断第一次还是第二次,可以用一个数字变量,用于记录。

源代码
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.default,
.scalable,
.scalable img {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}

.default {
cursor: pointer;

}

.default img {
display: block;
width: 300px;
border-radius: 20px;
box-shadow: 0 0 25px 5px #d9d9d9;
transition: all 1s;
}
</style>
</head>

<body>
<!-- 图片默认大小的显示效果 -->
<div class="default">
<img src="https://ae01.alicdn.com/kf/H68f882508c57456486095a78dca17ba9X.jpg">
</div>
<script>
var defaultElement = document.getElementsByClassName('default')[0]
var imgElement = defaultElement.firstElementChild
var num = 0;
defaultElement.addEventListener('dblclick', function () {
num++
if (num % 2 === 1) {
imgElement.style.transform = 'scale(3)'
} else {
imgElement.style.transform = 'scale(1)'
}

})
</script>
</body>

</html>

三、鼠标经典事件

https://antmoe.gitee.io/project/2020/04/25/4.html

为了测试鼠标事件,需要一个div。

1
<div class="box">来点我呀。。</div>

很简单的一个div即可。

然后简单的获取到他,方便后续测试

1
2
var body = document.body
var box = document.getElementsByClassName('box')[0]
  1. 鼠标悬停

    1
    2
    3
    box.addEventListener('mouseover', function () {
    box.textContent = '在我上面了。'
    })

  2. 鼠标离开

    1
    2
    3
    4
    box.addEventListener('mousedown', function () {
    box.textContent = '选中我了。。'
    flag = true
    })

    上述图中可以看到,鼠标移动到div上,即变化了文字。鼠标离开后文字又变了回来。

  3. 鼠标跟随事件(不包含释放)

    这里需要在引入一个变量用于标志是否触发跟随事件。并且在按下事件中将开关打开。

    1
    2
    3
    4
    5
    6
    7
    var flag = false;
    body.addEventListener('mousemove', function (event) {
    if (flag) {
    box.style.left = event.pageX + 'px'
    box.style.top = event.pageY + 'px'
    }
    })

  4. 鼠标按下事件(没有释放)

    1
    2
    3
    4
    box.addEventListener('mousedown', function () {
    box.textContent = '选中我了。。'
    flag = true
    })

    如上图,当鼠标点击后。开启跟随事件的开关。

  5. 鼠标按键抬起

    1
    2
    3
    4
    5
    box.addEventListener('mouseup', function () {
    box.style.left = event.pageX + 'px'
    box.style.top = event.pageY + 'px'
    flag = false
    })

    当鼠标放开后,div就固定到了鼠标的位置。

四、自定义鼠标右键

https://antmoe.gitee.io/project/2020/04/25/5.html

自定义鼠标右键:在html结构方面可以使用一个无序列表实现。

1
2
3
4
5
6
7
8
<ul id="menu">
<li>剪切</li>
<li>复制</li>
<li>粘贴</li>
<li>段落格式</li>
<li>批注</li>
<li>插入链接</li>
</ul>

在js方面,要做的其实有两点:

  1. 阻止阻止或禁止浏览器窗口提供的默认右键菜单

    1
    2
    3
    body.addEventListener('contextmenu', function (event) {
    event.preventDefault()
    })

    需要注意的是:当页面内无内容时,body是无高度的,因此需要为body设置高度。否则为body绑定事件无法被触发。

    1
    2
    var body = document.body
    body.style.height = window.innerHeight + 'px'
  2. 当右键被点击时显示自己的div,左键时隐藏

    判断点击的是鼠标什么按键,所使用的是event事件的button属性。

    • 鼠标左键

      event.button === 0

    • 鼠标中键

      event.button === 1

    • 鼠标右键

      event.button === 2

源代码
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
box-sizing: border-box;
}

#menu {
list-style: none;
margin: 0;
padding: 10px;
width: 100px;
height: 202px;
border: 1px solid #d9d9d9;
border-radius: 2px;
position: absolute;
display: none;
}

#menu li {
height: 30px;
size: 12px;
color: rgba(0, 0, 0, .5);
line-height: 30px;
}

#menu li:nth-of-type(5) {
border-top: 1px solid #d9d9d9;
border-bottom: 1px solid #d9d9d9;
}
</style>
</head>

<body>
<ul id="menu">
<li>剪切</li>
<li>复制</li>
<li>粘贴</li>
<li>段落格式</li>
<li>批注</li>
<li>插入链接</li>
</ul>
<script>
var body = document.body
body.style.height = window.innerHeight + 'px'
var menu = document.getElementById('menu')
// 1. 阻止或禁止浏览器窗口提供的默认右键菜单
body.addEventListener('contextmenu', function (event) {

event.preventDefault()
})
body.addEventListener('mousedown', function (event) {
if (event.button === 2) {
menu.style.left = event.clientX + 'px'
menu.style.top = event.clientY + 'px'
menu.style.display = 'block'
} else if (event.button === 0) {
menu.style.display = 'none'
}
})
</script>
</body>

</html>

五、 滑动一定量时,固定导航

https://antmoe.gitee.io/project/2020/04/26/1.html

如图,模拟页面中的一个小导航,当页面滚动到一定程度时,将其固定。

  1. 关于滚动事件

    滚动事件可以有两个scrollwheel

    • scroll

      必须为document对象绑定事件

    • wheel

      为document对象,<body>元素和<html>元素绑定该事件

  2. 判断当前滚动的高度

    • 获取当前滚动的高度

      html.scrollTop

    • 获取菜单距顶部的高度

      parseFloat(window.getComputedStyle(menu).top)

源代码
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
box-sizing: border-box;
}

body {
height: 2000px;
}

.menu {
width: 800px;
list-style: none;
padding: 0;
margin: 0;
overflow: hidden;
background-color: #d9d9d9;
position: relative;
top: 300px;

}

.menu li {
width: 100px;
height: 50px;
float: left;
text-align: center;
line-height: 50px;
}

.menu li a {
height: 22px;
display: block;
text-decoration: none;
color: #333;
line-height: 22px;
margin: 14px 0;
border-right: .5px solid #9b9b9b;
}

.menu li:last-of-type a {
border: none;
}
</style>
</head>

<body>
<ul class="menu">
<li><a href="#">最新文章</a></li>
<li><a href="#">大公司</a></li>
<li><a href="#">消费</a></li>
<li><a href="#">娱乐</a></li>
<li><a href="#">前沿技术</a></li>
<li><a href="#">汽车交通</a></li>
<li><a href="#">区块链</a></li>
<li><a href="#">技能Get</a></li>
</ul>
<script>
/*
实现页面滚动的事件:
scroll事件:必须为document对象绑定事件
wheel事件:为document对象,body元素和html元素绑定该事件
*/
var html = document.documentElement
var menu = document.getElementsByClassName('menu')[0]
var menutop = parseFloat(window.getComputedStyle(menu).top)

document.addEventListener('wheel', function () {
// <html>元素的scrollTop属性:表示页面垂直方向的垂直距离
var scrollTop = html.scrollTop
// 获取菜单的top值

if (scrollTop >= menutop) {
// 说明菜单滚动到浏览器窗口的顶部
menu.style.position = 'fixed'
menu.style.top = 0
} else {
menu.style.position = 'relative'
menu.style.top = '300px'
}
})
</script>
</body>

</html>

六、 轮播图

https://antmoe.gitee.io/project/2020/04/26/index.html

静态样式与小米轮播图大体相同。但是左右的按钮只需要各一个即可。

由于图片是出现消失式,所以只需要用透明度+层级控制图片的出现即可。因此js大致逻辑为:当点击右按钮或者左按钮时切换下一张图片。

可以用一个整数变量控制第几个元素。

示例代码
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小米首页轮播图</title>
<style>
* {
box-sizing: border-box;
}

body {
margin: 0;
padding: 0;
}

.container {
width: 1226px;
height: 460px;
background-color: lightcyan;

margin: 100px auto;

position: relative;
}

.container .imgList {
width: 100%;
position: absolute;
}

.container .imgList img {
display: block;
width: 100%;
height: auto;

position: absolute;
left: 0;
top: 0;

opacity: 0;
z-index: 0;

transition: all 1s;
}

.container .slide-controls {
width: 100%;
height: 100%;

position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}

.container .slide-controls .slide-left,
.container .slide-controls .slide-right {
width: 41px;
height: 69px;

position: absolute;
top: 50%;
transform: translateY(-50%);

background-image: url(https://i1.mifile.cn/f/i/2014/cn/icon/icon-slides.png);
cursor: pointer;

z-index: 2;
}

.container .slide-controls .slide-left {
left: 0;
background-position: -84px 0;
}

.container .slide-controls .slide-left:hover {
background-position: 0 0;
}

.container .slide-controls .slide-right {
right: 0;
background-position: -124px 0;
}

.container .slide-controls .slide-right:hover {
background-position: -42px 0;
}

.container .nav {
width: 100px;
height: 20px;

position: absolute;
left: 50%;
right: 0;
bottom: 8px;

transform: translateX(-50%);

z-index: 2;
}

.container .nav .slide-nav {
width: 12px;
height: 12px;
border: 2px solid #fff;
border-color: hsla(0, 0%, 100%, .3);
border-radius: 10px;
background: rgba(0, 0, 0, .4);
cursor: pointer;
margin: 0 4px;
float: left;
z-index: 3;
}

.container .nav .slide-nav:hover {
background: hsla(0, 0%, 100%, .4);
border-color: rgba(0, 0, 0, .4);
}
</style>
</head>

<body>
<!-- 视觉容器 -->
<div class="container">
<!-- 图片列表 -->
<div class="imgList">
<img src="https://ae01.alicdn.com/kf/U1a6b653720d845c682f97d2fcf75c22f6.png" />
<img src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/755aca9487082e7698e16f17cfb70839.jpg" />
<img src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/e5b37cdb85b3b93b5938cc508a10c906.jpg" />
<img src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/e909ef0e50960f61a730380013bc960a.jpg" />
<img src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/6bd4174b8c5aad67a64864a5716ad152.jpg" />
</div>
<!-- 左右切换菜单 -->
<div class="slide-controls">
<div class="slide-left"></div>
<div class="slide-right"></div>
</div>
<!-- 轮播图的导航 -->
<div class="nav">
<div class="slide-nav"></div>
<div class="slide-nav"></div>
<div class="slide-nav"></div>
<div class="slide-nav"></div>
<div class="slide-nav"></div>
</div>
</div>
<script>
// 获取轮播图中所有的图片
var imgList = document.getElementsByClassName('imgList')[0]
var imageElements = imgList.getElementsByTagName('img')
// 获取轮播图中所有的导航器
var navElement = document.getElementsByClassName('nav')[0]
var slideElements = navElement.getElementsByClassName('slide-nav')
// 用来记录当前操作的是第几张图片
var num = 0
// 获取左右切换的按钮
var slideControl = document.getElementsByClassName('slide-controls')[0]
var slideLeft = slideControl.getElementsByClassName('slide-left')[0]
var slideRight = slideControl.getElementsByClassName('slide-right')[0]
// 用于存放nav
var arr = []
for (var i = 0; i < slideElements.length; i++) {
arr.push(slideElements[i])
}
// 控制图片显示及消失
function show(num) {
imageElements[num].style.opacity = 1
imageElements[num].style.zIndex = 1
slideElements[num].style.backgroundColor = 'hsla(0, 0%, 100%, .4)'
slideElements[num].style.borderColor = 'rgba(0, 0, 0, .4)'
}
function hidden() {
for (var i = 0; i < slideElements.length; i++) {
imageElements[i].style.opacity = 0
imageElements[i].style.zIndex = 0
slideElements[i].style.backgroundColor = null
slideElements[i].style.borderColor = null
}
}
// 初始初始化页面
show(0)
// 向右切换按钮的动态效果
slideRight.addEventListener('click', function () {
num++
console.log(num)
hidden()
if (num === imageElements.length) {
num = 0
show(num)
} else {
show(num)
}
})
// 向左切换按钮的动态效果
slideLeft.addEventListener('click', function () {

console.log(num)
hidden()
if (num <= 0) {
num = imageElements.length - 1
show(num)
} else {
show(num - 1)
num--
}
})
// 导航器的动态效果
navElement.addEventListener('click', function (event) {
var target = event.target
num = arr.indexOf(target)
if (target.className === 'slide-nav') {
hidden()
show(num)
}
})

</script>
</body>

</html>

七、 轮播图升级版

https://antmoe.gitee.io/project/2020/04/27/index.html

大致思路如下:

  1. 进入文章后,需要获取所有的图片。并将所有的图片插入到轮播图的图片容器中。
  2. 双击(单击)文章文章的某个图片,将轮播图容器显示来。
  3. 点击右侧或左侧按钮,使图片进行正常的切换。

与上一个轮播图不同的是,显示轮播的容器需要根据用户点击的图片进行动态添加,并且每次退出后应该清除,防止下次进入出现问题。

在判断用户点击的图片时可以用到一个小技巧,先将全部图片插入到一个列表,将点击的对象判断在列表内的索引即可。

1
2
3
4
var imageArr = [];
var imageElement = imageElements[i];
imageArr.push(imageElement);
slideNum = imageArr.indexOf(targetElement);
示例代码
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>双击放大轮播图</title>
<style>
* {
box-sizing: border-box;
}

.article-wapper {
width: 694px;
overflow: hidden;
font-family: PingFang SC, Lantinghei SC, Helvetica Neue, Helvetica,
Arial, Microsoft YaHei, 微软雅黑, STHeitiSC-Light, simsun, 宋体,
WenQuanYi Zen Hei, WenQuanYi Micro Hei, "sans-serif";
word-break: break-word;
margin: 50px auto;
}

.article-wapper h1 {
font-size: 30px;
color: #262626;
letter-spacing: 0;
text-align: justify;
line-height: 42px;
font-weight: 400;
margin-bottom: 20px;
}

.article-wapper .content {
font-size: 16px;
color: #262626;
letter-spacing: 0;
text-align: justify;
line-height: 30px;
}

.article-wapper .content p {
margin-bottom: 26px;
word-wrap: break-word;
}

.article-wapper .content p a {
text-decoration: none;
color: #262626;
border: solid #999;
border-width: 0 0 1px;
padding: 0 0 1px;
word-wrap: break-word;
}

.article-wapper .content p img {
max-width: 690px;
display: block;
border-radius: 5px;
margin: 30px auto;
cursor: pointer;
}

.article-wapper .content h2 {
font-weight: 600;
margin: 30px 0 14px;
font-size: 20px;
line-height: 28px;
position: relative;
color: #4285f4;
}

.image-slide {
width: 100%;
height: 100%;
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.8);
display: none;
}

.image-slide .image-list,
.image-slide .slide-controls {
width: 80%;
height: 80%;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}

.image-slide .image-list img {
width: 850px;
display: block;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);

opacity: 0;
z-index: 0;

transition: all 1s;
}

.image-slide .slide-controls .slide-left,
.image-slide .slide-controls .slide-right {
width: 41px;
height: 69px;

position: absolute;
top: 50%;
transform: translateY(-50%);

background-image: url(https://i1.mifile.cn/f/i/2014/cn/icon/icon-slides.png);
cursor: pointer;

z-index: 2;
}

.image-slide .slide-controls .slide-left {
left: 0;
background-position: -84px 0;
}

.image-slide .slide-controls .slide-left:hover {
background-position: 0 0;
}

.image-slide .slide-controls .slide-right {
right: 0;
background-position: -124px 0;
}

.image-slide .slide-controls .slide-right:hover {
background-position: -42px 0;
}
</style>
</head>

<body>
<div class="article-wapper">
<h1>究竟是谁制造了“瑞幸”之殇?</h1>
<div class="content">
<p>
编者按:本文来自微信公众号<a
href="https://mp.weixin.qq.com/s/yoRSqdXpk4JA-2_Zg0ojig">“品牌几何”(ID:brand-vista)</a>,作者:李刚健,36氪经授权发布。
</p>
<p>几何君有话说:</p>
<p>
这段时间,瑞幸掀起了不小的风波。当它站在风口浪尖之时,周围不断发出了各种不同的声音。今天几何君分享一篇李刚健老师的文章,究竟是谁制造了瑞幸之殇呢?
</p>
<h2 label="一级标题">
01.&nbsp;<span style="letter-spacing: 0px;">美国最具创新精神公司</span>
</h2>
<p>
曾有一家世界上最大的能源公司,连续六年被《财富》杂志评选为“美国最具创新精神公司”,2000年披露的营业额达1010亿美元之巨,拥有约21000名雇员,这家公司叫安然。
</p>
<p>
2001年年初,一家有着良好声誉的投资机构老板吉姆·切欧斯公开对安然的盈利模式表示了怀疑。他指出,虽然安然的业务看起来很辉煌,但实际上赚不到什么钱,也没有人能够说清安然是怎么赚钱的。10月22日,美国证券交易委员会要求公司自动提交某些交易的细节内容。并最终于10月31日开始对安然及其合伙公司进行正式调查。11月8日,安然被迫承认做了假账,虚报数字让人瞠目结舌:自1997年以来,安然虚报盈利共计近6亿美元。11月30日,安然股价跌至0.26美元,市值由峰值时的800亿美元跌至2亿美元。
</p>
<p>
12月2日,安然正式向破产法院申请破产保护,破产清单中所列资产高达498亿美元,成为美国历史上最大的破产企业。
</p>
<p>
<img src="https://img.36krcdn.com/20200427/v2_be0d7fc527eb41b5ac7f88a35ae6d9a0_img_000"
data-img-size-val="1080,730" />
</p>
<h2 label="一级标题">
02.&nbsp;<span style="letter-spacing: 0px;">元气满满的瑞幸?</span>
</h2>
<p>
将近20年以后,有一家中国的咖啡连锁新贵,亏着钱做着生意,也在美国上了市,号称是中国咖啡业的领军品牌,这个公司叫瑞幸。
</p>
<p>
也是年初,卡森·布洛克组织了92名全职和1418名兼职调查员,在全国45个城市2213家瑞幸门店,收集了25000多张小票,进行了10000个小时的门店录像,发布了瑞幸的做空报告。随后,瑞幸发布公告坚决否认报告中的所有指控,认为该报告的论证方式存在缺陷,报告中包含的所谓证据无确凿事实依据,且报告中的指控均基于毫无根据的推测和对事件的恶意解释。
</p>
<p>
直到愚人节后的第一天,安永不敢在年报上签字,瑞幸才不得不自曝,并且迅速找了一个背锅侠。尽管随之股价大跌,瑞幸自己却觉得“元气满满”。
</p>
<p>
之后的口诛笔伐尽管铺天盖地,然而4月3日瑞幸的店门口居然排起了长队,据说是怕优惠券来不及用完的群众。之后经过几周的冷清,4月14号,有记者宣称上海门店挺过寒冬,订单恢复正常。
</p>
<p>
<img src="https://img.36krcdn.com/20200427/v2_1d93ac5c10184d178dcb0b3305c11386_img_000"
data-img-size-val="1080,734" />
</p>
<h2 label="一级标题">
03.&nbsp;<span style="letter-spacing: 0px;">瑞幸算是一个品牌吗?</span>
</h2>
<p>
看上去,尽管从出生之始就一直有人唱衰瑞幸,可是凭着对媒介公关的高明操控,瑞幸每次都能度过难关。也许老陆早就明白一个道理:你们能花多少成本和时间再找那么多人来收集新的证据呢?做空者该赚的也赚完了,我依然还可以讲故事,可以利用消费者的劣根性做游戏。
</p>
<p>
有人问瑞幸算是一个品牌吗?有人说不是,它只是一门生意;也有人说它连生意都不是,只是资本游戏的一个载体。我比较倾向于最后一种理解。说老陆在做游戏,就像是营造了一个他的《西部世界》:真正的目的不是产品本身,而是消费者数据。随着技术的发展,消费者数据就是消费者心智——我可以比你更了解你,"你是真的吗?""如果你分辨不出来,那还重要吗?"。
</p>
<p>
福特用机器人收集数据,老陆用咖啡收集数据(实际上也可以用别的,只不过恰好用咖啡编了点故事,尽管蹩脚,但是中国有智商税,大家都懂的)。老陆把咖啡卖给了普通消费者,把数据作为价值核心通过各种金融手段(公开上市,质押等等)卖给了普通投资者,完美的闭环。本来,两者就是同一群人,而老陆的NB之处在于通过地域使他们没有重合:亏了国外投资者(幸好大部分国内投资者不买美股),让国内消费者赚了便宜。因为老陆知道,这样的分割舆论上更好操控。
</p>
<p>
然而,我们在快意的指责瑞幸的管理团队和那帮无良的保荐承销机构(他们都是精英中的精英)的同时,有没有想过作为一个普通消费者,我们每个人自己的责任吗?
</p>
<p>
<img src="https://img.36krcdn.com/20200427/v2_3851c681585849499fc0e3e4268c61b9_img_000"
data-img-size-val="1080,766" />
</p>
<p>
很多很多年以前,那时我还很年轻,还没有家庭和孩子,任职于一家国际著名的品牌咨询公司。适逢公司旅游,两岸三地的同事共赴普吉岛,享受阳光和沙滩。一位业界德高望重的前辈曾经质问过我:你们穿着那些昂贵的品牌服装,真的觉得适合你们自己本人的气质和价值观吗?因为很多人看起来穿着特别不协调,不是身材尺寸的原因。
</p>
<p>
答案大家也都很清楚:因为那些品牌的价格能体现身份。是的,那时的我们以为价格=身份感,我们却不知道价格背后的品牌态度和价值观才是更深层次的原因,我们搞错了因果关系。也正是我所在的这家公司,因为对转基因产业的反对态度,拒绝了当时和孟山都合作的机会。
</p>
<p>
当下整个中国的消费群体都被“成功学”和“占便宜”的商业逻辑左右,都觉得只有成功才是判断真理的唯一标准,而性价比永远是吸引流量的利器。几乎所有品类的东西都越来越便宜,真正赚钱的只有平台和中介(基本处于垄断的状态),使得几乎所有的生产者(最终也是消费者)都面临苦难的境地(这对中国经济的长期负面因素并不是我能关心和解决的)。
</p>
<p>
<img src="https://img.36krcdn.com/20200427/v2_fc67a520b6a64627ba466a1f4465a876_img_000"
data-img-size-val="777,423" />
</p>
<p>
归根到底,因为我们是这样的消费逻辑:只要商家给我好处,个人数据并不值钱,反正我也不是什么大人物,数据被人拿去最多被骚扰一下,又能怎样呢?我们绝不会因为不喜欢一个品牌,有便宜也不去占,有羊毛不薅是傻子。因此,不断有瑞幸这样的商业模式出现:给你便宜,拿你数据,然后用你的数据编故事(用户运营)说给各级市场的投资者,各怀利益,总有人接棒,最终套现走人,实现一个资本游戏闭环。
</p>
<p>
在这样的情况下,品牌也就完全不需要营造什么价值观(那些泛泛的讲创造美好生活之类的都是空谈,并没有价值观),消费者也不需要认同。这事儿就像皇帝的新衣,人人知道答案,但还是不断发生。至于造假,那都是战术。瑞幸算是倒霉,线下能找到证据,很多线上流量编故事的数据根本无法考证。
</p>
<p>
等到哪一天我徜徉在线上线下的世界里,面对所有的打折一无所动,不再关心什么6.18和双11,只在需要的时候买价值观被自己认同的品牌(当然首先它的产品是可靠的),还会有瑞幸这样的商业模式出现吗?
</p>
<p>
因为品牌有不同的价值观,所以会有不同的溢价。我们愿意因为价值观多付合理的费用吗?
</p>
<p>*图片来源:网络</p>
</div>
</div>
<!-- 放大的轮播图 -->
<div class="image-slide">
<!-- 图片列表 -->
<div class="image-list"></div>
<!-- 左右切换 -->
<div class="slide-controls">
<div class="slide-left"></div>
<div class="slide-right"></div>
</div>
</div>
<script>
// 0.将文章中所有的图片插入到放大后的轮播图中
// 0.1 获取到文章中所有的图片
var contentElement = document.getElementsByClassName("content")[0];
var imageElements = contentElement.getElementsByTagName("img");
// 0.2 将获取到的文章中所有的图片集合转化为数组
var imageArr = [];
// 0.3 获取放大的轮播图的图片容器
var slideElement = document.getElementsByClassName("image-slide")[0];
var listElement = slideElement.getElementsByClassName("image-list")[0];
var slideImageElements = listElement.getElementsByTagName("img");
// 0.4 将文章中所有的图片插入到轮播图中
for (var i = 0; i < imageElements.length; i++) {
// 获取每张图片的文件路径
var imageElement = imageElements[i];
var imageLink = imageElement.getAttribute("src");
// 使用图片文件的链接创建新的图片元素
var newImageElement = document.createElement("img");
newImageElement.setAttribute("src", imageLink);
// 将创建的新图片元素添加到图片容器中
listElement.appendChild(newImageElement);

// 将每个图片元素添加到自定义的数组中
imageArr.push(imageElement);
}
// 定义一个用来用来记录放大图索引值的变量
var slideNum = 0,
prev = 0;
// 获取当前索引值的最大值
var length = slideImageElements.length - 1;
var bodyElement = document.body;
// 1.文章中所有图片的双击放大效果
// 为所有图片绑定dblclick事件 -> 处理函数: 将图片放大
contentElement.addEventListener("dblclick", function (event) {
var targetElement = event.target;
if (targetElement.nodeName === "IMG") {
slideElement.style.display = "block";

// 在轮播图中显示对应的图片
slideNum = imageArr.indexOf(targetElement);

//
slideImageElements[slideNum].style.opacity = 1;
slideImageElements[slideNum].style.zIndex = 1;
// 轮播图
bodyElement.style.overflow = "hidden";
}
});
// 2. 双击轮播图容器时,关闭
slideElement.addEventListener("dblclick", function () {
slideElement.style.display = "none";

bodyElement.style.overflow = "auto";
slideImageElements[slideNum].style.opacity = 0;
slideImageElements[slideNum].style.zIndex = 0;
});
// 3.放大效果中存在轮播图的动态效果
// 获取左右切换的按钮
var slideControl = slideElement.getElementsByClassName(
"slide-controls"
)[0];
var slideLeft = slideControl.getElementsByClassName("slide-left")[0];
var slideRight = slideControl.getElementsByClassName("slide-right")[0];

slideRight.addEventListener("click", function () {
if (slideNum < length) {
slideNum++;
prev = slideNum - 1;
} else if (slideNum === length) {
slideNum = 0;
prev = length;
}
slideImageElements[slideNum].style.opacity = 1;
slideImageElements[slideNum].style.zIndex = 1;

slideImageElements[prev].style.opacity = 0;
slideImageElements[prev].style.zIndex = 0;
});
slideLeft.addEventListener("click", function () {
if (slideNum > 0) {
slideNum--;
prev = slideNum + 1;
} else if (slideNum === 0) {
slideNum = length;
prev = 0;
}
slideImageElements[slideNum].style.opacity = 1;
slideImageElements[slideNum].style.zIndex = 1;

slideImageElements[prev].style.opacity = 0;
slideImageElements[prev].style.zIndex = 0;
});
</script>
</body>

</html>

九、横向轮播图

https://antmoe.gitee.io/project/2020/05/17/1_轮播图切换动画.html

实现静态效果不难,只需要控制其left效果即可。

如果加入动画效果,只能利用定时器.

左右按钮的切换大致相同,只以右按钮为例:

  1. 记录当前图片的索引(全局变量保存)
  2. 判断尺寸
    • 几张图片
    • 每张图片的宽度
  3. 利用定时器完成累加/减
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小米首页轮播图</title>
<style>
* {
box-sizing: border-box;
}

body {
margin: 0;
padding: 0;
}

.container {
width: 1226px;
height: 460px;
background-color: lightcyan;
overflow: hidden;
margin: 100px auto;

position: relative;
}

.container .imgList {
width: 6130px;
position: absolute;
}

.container .imgList img {
display: block;
width: 1226px;
height: auto;
float: left;
}

.container .slide-controls {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}

.container .slide-controls .slide-left,
.container .slide-controls .slide-right {
width: 41px;
height: 69px;

position: absolute;
top: 50%;
transform: translateY(-50%);

background-image: url(https://i1.mifile.cn/f/i/2014/cn/icon/icon-slides.png);
cursor: pointer;

z-index: 2;
}

.container .slide-controls .slide-left {
left: 0;
background-position: -84px 0;
}

.container .slide-controls .slide-left:hover {
background-position: 0 0;
}

.container .slide-controls .slide-right {
right: 0;
background-position: -124px 0;
}

.container .slide-controls .slide-right:hover {
background-position: -42px 0;
}

.container .nav {
width: 100px;
height: 20px;

position: absolute;
left: 50%;
right: 0;
bottom: 8px;

transform: translateX(-50%);

z-index: 2;
}

.container .nav .slide-nav {
width: 12px;
height: 12px;
border: 2px solid #fff;
border-color: hsla(0, 0%, 100%, .3);
border-radius: 10px;
background: rgba(0, 0, 0, .4);
cursor: pointer;
margin: 0 4px;
float: left;
z-index: 3;
}

.container .nav .slide-nav:hover {
background: hsla(0, 0%, 100%, .4);
border-color: rgba(0, 0, 0, .4);
}
</style>
<script type="text/javascript" nonce="e9b48b8ca3e64a6a85e757b4795"
src="//local.adguard.org?ts=1589675716165&amp;type=content-script&amp;dmn=antmoe.gitee.io&amp;css=1&amp;js=1&amp;gcss=1&amp;rel=1&amp;rji=1&amp;stealth=1&amp;uag="></script>
<script type="text/javascript" nonce="e9b48b8ca3e64a6a85e757b4795"
src="//local.adguard.org?ts=1589675716165&amp;name=AdGuard%20Popup%20Blocker&amp;name=AdGuard%20Assistant&amp;name=AdGuard%20Extra&amp;type=user-script"></script>
</head>

<body>
<!-- 视觉容器 -->
<div class="container">
<!-- 图片列表 -->
<div class="imgList">
<img src="https://ae01.alicdn.com/kf/U1a6b653720d845c682f97d2fcf75c22f6.png" />
<img src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/755aca9487082e7698e16f17cfb70839.jpg" />
<img src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/e5b37cdb85b3b93b5938cc508a10c906.jpg" />
<img src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/e909ef0e50960f61a730380013bc960a.jpg" />
<img src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/6bd4174b8c5aad67a64864a5716ad152.jpg" />
</div>
<!-- 左右切换菜单 -->
<div class="slide-controls">
<div class="slide-left"></div>
<div class="slide-right"></div>
</div>
<!-- 轮播图的导航 -->
<div class="nav">
<div class="slide-nav"></div>
<div class="slide-nav"></div>
<div class="slide-nav"></div>
<div class="slide-nav"></div>
<div class="slide-nav"></div>
</div>
</div>
<script>
// NOTE 获取元素对象
var container = document.getElementsByClassName('container')[0]
var imgList = container.getElementsByClassName('imgList')[0]
var rightBtn = document.getElementsByClassName('slide-right')[0]
var leftBtn = document.getElementsByClassName('slide-left')[0]
var nav = container.getElementsByClassName('nav')[0]
var slide_nav = container.getElementsByClassName('slide-nav')
var indexStart
var auto_num
// NOTE 定义全局变量

// TAG 定义单图片的宽度(每次滚动的大小)
var img_width = 1226
// TAG 图片的总个数
var img_num = imgList.childElementCount
// TAG 图片当前的索引 默认为0
var img_index = 0
// TAG 记录上一个nav按钮
var pre_nav_num = 0
// NOTE 定义函数
// TAG 按钮点击时,对应图片获得对应样式
function showNav(num) {
// 显示当前被点击的nav
slide_nav[num].style.background = 'hsla(0, 0%, 100%, .4)'
slide_nav[num].style.borderColor = 'rgba(0, 0, 0, .4)'
// 取消上一次的nav
slide_nav[pre_nav_num].style.borderColor = 'hsla(0, 0%, 100%, .4)'
slide_nav[pre_nav_num].style.background = 'rgba(0, 0, 0, .4)'
}
auto()

// TAG 右按钮 绑定事件
rightBtn.addEventListener('click', function () {
if (img_index < img_num - 1) {
pre_nav_num = img_index
indexStart = -(img_index * img_width)
img_index++
// indexEnd = -(img_index * img_width)
} else {
img_index = 0
indexStart = 1226
// indexEnd = 0
pre_nav_num = 4
}
clearInterval(auto_num)
moveLeft()
// FIXED 延迟10秒似乎不起作用
setTimeout(auto, 5000)
showNav(img_index)
})
// TAG 左按钮 绑定事件
leftBtn.addEventListener('click', function () {
if (img_index == 0) {
img_index = 4
indexStart = -6130
pre_nav_num = 0
} else {
pre_nav_num = img_index
indexStart = -(img_index * img_width)
img_index--
}
// imgList.style.left = -(img_index * img_width) + 'px'

moveRight()
showNav(img_index)
})
// TAG nav绑定事件
nav.addEventListener('click', function (e) {
// TAG 定义一个数组,用于存储nav列表
var nav_list = []
for (var i = 0; i < nav.childElementCount; i++) {
nav_list.push(slide_nav[i])
slide_nav[i].style.borderColor = 'hsla(0, 0%, 100%, .4)'
slide_nav[i].style.background = 'rgba(0, 0, 0, .4)'
}
var target = e.target
if (target.className === 'slide-nav') {
img_index = nav_list.indexOf(target)
slide_nav[img_index].style.borderColor = 'hsla(0, 0%, 100%, .4)'
slide_nav[img_index].style.background = 'rgba(255, 255, 255, 0.4)'
imgList.style.left = -(img_index * img_width) + 'px'
}
})
// BUG 边界切换不完美
function moveLeft() {
if (indexStart <= -(img_index * img_width)) {
clearInterval(t)
} else {
indexStart -= 10
imgList.style.left = indexStart + 'px'
var t = setTimeout(moveLeft, 1)
}
}
function moveRight() {
if (indexStart >= -(img_index * img_width)) {
clearInterval(t)
} else {
indexStart += 10
imgList.style.left = indexStart + 'px'
var t = setTimeout(moveRight, 1)
}
}
function auto() {
auto_num = setInterval(function () {
if (img_index < img_num - 1) {
pre_nav_num = img_index
indexStart = -(img_index * img_width)
img_index++
// indexEnd = -(img_index * img_width)
} else {
img_index = 0
indexStart = 1226
// indexEnd = 0
pre_nav_num = 4
}
// imgList.style.left = -(img_index * img_width) + 'px'
moveLeft()
showNav(img_index);
}, 5000)
}

</script>
</body>

</html>

八、键盘事件

https://antmoe.gitee.io/project/2020/04/28/index.html

在键盘事件中,可以为<html> <body> document 对象绑定。

1
2
3
4
5
6
7
8
9
10
11
var html = document.documentElement
var body = document.body
html.addEventListener("keydown", function (event) {
console.log(event)
})
body.addEventListener("keydown", function (event) {
console.log(event)
})
document.addEventListener("keydown", function (event) {
console.log(event)
})

但是在键盘事件提供的三个事件中只有keydown keyup,可以监控到上下左右按键。

1
2
3
4
5
6
7
8
9
html.addEventListener("keydown", function (event) {
console.log(event)
})
html.addEventListener('keypress', function (event) {
console.log(event)
})
html.addEventListener("keyup", function (event) {
console.log(event)
})

event对象的属性

  • code属性: 前缀 + 键盘信息
  • key属性: 键盘信息
  • keyCode属性: 键盘的Unicode信息
  • which属性: 键盘的Unicode信息
示例代码
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.box {
width: 100px;
height: 100px;
background-color: coral;
position: absolute;
left: 20px;
top: 30px;
}
</style>
</head>

<body>
<div class="box"></div>
<script>
var html = document.documentElement
var body = document.body
var box = document.getElementsByClassName('box')[0]
html.addEventListener("keydown", function (event) {
var style = window.getComputedStyle(box)
var boxLeft = parseFloat(style.left)
var boxTop = parseFloat(style.top)
switch (event.key) {
case 'ArrowUp': // 上
boxTop -= 10
break
case 'ArrowDown': // 下
boxTop += 10
break
case 'ArrowLeft': // 左
boxLeft -= 10
break
case 'ArrowRight': // 右
boxLeft += 10
break
}
// 更新到html
box.style.top = boxTop + 'px'
box.style.left = boxLeft + 'px'

})

</script>
</body>

</html>

九、限制方块滑动位置

https://antmoe.gitee.io/project/2020/04/29/2.html

基于上边的移动方块案例,可以为方块加个限制范围。思路也很简单。

  1. 获取限制容器的宽度及高度

  2. 计算出移动div的可移动最大范围

    1
    const maxLeft = containerWidth - boxWidth,maxTop = containerHeight - boxHeight
  3. 每次移动时,判断是否超过了范围

    • 如果超过

      不移动

    • 没有超过

      移动

    • 移动的距离大于到边界的距离

      移动距离为到边界的距离

示例代码
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
93
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.container {
width: 600px;
height: 500px;
border: 1px solid black;
position: relative;
margin: 100px auto;
}

.box {
width: 100px;
height: 100px;
background-color: coral;
position: absolute;
left: 20px;
top: 30px;
}
</style>
</head>

<body>
<div class="container">
<div class="box"></div>
</div>
<script>
// 获取边框div
var container = document.getElementsByClassName("container")[0]
// 获取边框div的有效样式
var containerStyle = window.getComputedStyle(container)
// 有效宽度
var containerWidth = parseFloat(containerStyle.width)
// 有效高度
var containerHeight = parseFloat(containerStyle.height)
// 获取可移动div对象
var box = document.getElementsByClassName('box')[0]
var boxStyle = window.getComputedStyle(box)
var boxWidth = parseFloat(boxStyle.width)
var boxHeight = parseFloat(boxStyle.height)
// 计算四个方向的边界值
const minLeft = 0, minTop = 0,
maxLeft = containerWidth - boxWidth,
maxTop = containerHeight - boxHeight
document.addEventListener("keydown", function (event) {
var style = window.getComputedStyle(box)
var boxLeft = parseFloat(style.left)
var boxTop = parseFloat(style.top)
switch (event.key) {
case 'ArrowUp': // 上
if ((boxTop - 10) > minTop) {
boxTop -= 10
} else if ((boxTop - 10) <= minTop && (boxTop - 10) > -10) {
boxTop -= boxTop
}
break
case 'ArrowDown': // 下
if ((boxTop + 10) < maxTop) {
boxTop += 10
} else if ((boxTop + 10) >= maxTop && boxTop < maxTop) {
boxTop += maxTop - boxTop
}
break
case 'ArrowLeft': // 左
if ((boxLeft - 10) > minLeft) {
boxLeft -= 10
} else if ((boxLeft - 10) <= minLeft && (boxLeft - 10) > -10) {
boxLeft -= boxLeft
}
break
case 'ArrowRight': // 右
if ((boxLeft + 10) < maxLeft) {
boxLeft += 10
} else if ((boxLeft + 10) >= maxLeft && boxLeft < maxLeft) {
boxLeft += maxLeft - boxLeft
}
break
}
// 更新到html
box.style.top = boxTop + 'px'
box.style.left = boxLeft + 'px'

})

</script>
</body>

</html>

十、组合键提示

https://antmoe.gitee.io/project/2020/04/29/2.html

  1. 定义一个数组,用于存储按下的按键。
  2. 当按键按下去的时候,获取按键并添加到数组。
  3. 当按键松开的时候,从数组中删除按键
示例代码
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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>组合键</title>
<style>
.shortcuts {
width: 240px;
height: 80px;
background-color: rgba(0, 0, 0, .5);
border-radius: 10px;
font-size: 24px;
font-weight: 800;
text-align: center;
line-height: 80px;
color: #fff;
position: fixed;
left: 50%;
bottom: 10px;
transform: translateX(-50%);
opacity: 0;
}
</style>
</head>

<body>
<div class="shortcuts"></div>
<script>
var divElement = document.getElementsByClassName('shortcuts')[0]
// 定义一个数组存储用户按下的按键信息
var keyArr = []
var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
'u', 'v', 'w', 'x', 'y', 'z'
]
document.addEventListener('keydown', function (event) {
var key = event.key
key = letters.indexOf(key) !== -1 ? key.toUpperCase() : key
if (key !== keyArr[keyArr.length - 1] || keyArr.length === 0) {
keyArr.push(key)
}
switch (keyArr.length) {
case 2:
divElement.textContent = keyArr[0] + ' + ' + keyArr[1]
divElement.style.opacity = 1
break
case 3:
divElement.textContent = keyArr[0] + ' + ' + keyArr[1] + ' + ' + keyArr[2]
divElement.style.opacity = 1
break
}
})
document.addEventListener('keyup', function (event) {
var key = event.key
// key = letters.indexOf(key) !== -1 ? key.toUpperCase() : key
// var index = keyArr.indexOf(key)
// if (index !== -1) {
// keyArr.splice(index, 1)
// }
keyArr = []
console.log(keyArr)
divElement.textContent = ''
divElement.style.opacity = 0
})
</script>
</body>

</html>

获取焦点事件

获取焦点即鼠标按上时的事件,类似css中的focus伪类。

  • focus

    获取焦点事件

  • blur

    失去焦点事件

1
2
3
4
5
6
7
var username = document.getElementById('username')
username.addEventListener('focus', function () {
username.value = ''
})
username.addEventListener('blur', function () {
username.value = '请输入你的用户名'
})

加载事件

加载事件可以理解为当页面加载完成后的事件或者页面加载时的事件。

  • load

    当一个资源及其依赖资源已完成加载时,将触发load事件

  • unload

    当文档或一个子资源正在被卸载时, 触发 unload事件。

1
2
3
4
5
// window表示浏览器窗口 window.onload表示页面加载完毕
window.onload = function () {
var username = document.getElementById('username')
console.log(username.value)
}
1
2
3
4
5
// 一定在图片加载完毕后, 执行逻辑
var imgElement = document.getElementById('img')
imgElement.addEventListener('load', function () {
console.log('表示图片已加载完毕...')
})

变化大小事件

变化大小用于监听浏览器窗口的大小变化

1
2
3
window.addEventListener('resize', function () {
console.log(window.innerWidth, window.innerHeight)
})

change事件

顾名思义,即当发生变化时所触发的事件。

1
2
3
4
var city = document.getElementById('city')
city.addEventListener('change', function () {
console.log(city.value)
})

表单提交事件

当表单提交时所触发的事件。

1
2
3
4
5
6
var form = document.getElementById('login')
form.addEventListener('submit', function (event) {
// 完成表单验证的逻辑
console.log('表示表单要提交了...')
event.preventDefault()
})