mini project

密码生成器

随机的大写字母,小写字母,数字,特殊字符

  • 首先如何获取随机的字符呢

字母:使用fromCharCode静态方法返回由指定的 UTF-16 码元序列创建的字符串。65表示大写字母A,97表示小写字母a

1
2
String.fromCharCode(65 + Math.floor(Math.random() * 26))//A~Z
String.fromCharCode(97 + Math.floor(Math.random() * 26))//a~z

特殊字符:把可用的特殊字符放在字符串中

  • 如何知道选项来调用对应的函数生成密码呢

随机字符生成函数和对应的选项生成映射关系:使用对象的键值对形式

1
2
3
4
5
6
const randomFunc = {
upper: getUp,
lower: getLow,
num: getNumber,
sym: getSymbol
}

对应的选项名和对应选项的布尔值(选项名变量)生成映射关系

1
2
const typesArr = [{ upper }, { lower }, { num }, { sym }]
//ES6简写规则:键和值同名。注意值是变量名代表的值,键即是变量名的字符串形式

使用filter筛选出为真的选项名

1
2
3
4
5
const needArr = typesArr.filter(item => {
// 如果箭头函数写了{},就要写return
return Object.values(item)[0]//返回true的item
})
// Object.values() 方法返回给定对象自己可枚举属性的值数组所以要取对应值需要[]

再用选项名获取对应的随机字符函数来拼接密码

1
2
3
4
5
needArr.forEach(item => {
const key = Object.keys(item)[0]
// 调用需要的字符对应的获取函数
pwd += randomFunc[key]()
})

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
const result = document.querySelector('.result')
const btn = document.querySelector('.btn')
const symbols = ['!', '@', '#', '$', '%', '^', '&', '*', '>', '<']
const icon = document.querySelector('.icon')
btn.addEventListener('click', () => {
const upper = document.getElementById('upper').checked
const lower = document.getElementById('lower').checked
const num = document.getElementById("num").checked
const sym = document.getElementById("sym").checked
const len = +document.getElementById('len').value
console.log('111')
result.innerText = generator(upper, lower, num, sym, len)
})

icon.addEventListener('click', () => {
const pass = result.innerText;
if (!pass) {
return;
}
// 复制到剪切板
navigator.clipboard.writeText(pass);
alert('Password copied to clipboard!')
})
const randomFunc = {
upper: getUp,
lower: getLow,
num: getNumber,
sym: getSymbol
}
function generator(upper, lower, num, sym, len) {
let pwd = ''
console.log('222')
const typesArr = [{ upper }, { lower }, { num }, { sym }]
console.log(typesArr)
const needCount = upper + lower + num + sym
if (needCount === 0) {
return ''
}
// Object.values() 方法返回给定对象自己可枚举属性的值数组[true]
const needArr = typesArr.filter(item => {
// 如果箭头函数写了{},就要写return
return Object.values(item)[0]
})
console.log(needArr)
for (let i = 0; i < len; i += needCount) {
console.log(len)
needArr.forEach(item => {
const key = Object.keys(item)[0]
// 调用需要的字符对应的获取函数
pwd += randomFunc[key]()
})
}
console.log(pwd)
const finalPwd = pwd.slice(0, len)

console.log('333')
return finalPwd
}
function getUp() {
return String.fromCharCode(65 + Math.floor(Math.random() * 26))
}
function getLow() {
return String.fromCharCode(97 + Math.floor(Math.random() * 26))
}
function getNumber() {
return Math.floor(Math.random() * 10)
}
function getSymbol() {
return symbols[Math.floor(Math.random() * 10)]
}
  • 扩展
  1. ASCII 编码:
    • ASCII(American Standard Code for Information Interchange)是一种最初设计用于表示英语字符集的字符编码方案。
    • ASCII 使用 7 位二进制数(0到127)来表示128个字符,包括基本的拉丁字母、数字、标点符号等。
    • ASCII 编码是单字节编码,每个字符占用一个字节。
  2. UTF 编码:
    • UTF(Unicode Transformation Format)是一种更为通用的字符编码方案,旨在表示全球范围内的所有语言的字符。
    • UTF-8、UTF-16、UTF-32 是不同的 UTF 编码方案,使用不同的方式表示字符码点。
    • UTF-8 是一种可变长度编码,UTF-16 是一种使用 2 或 4 字节表示的编码,UTF-32 是一种固定长度编码。
    • UTF 编码兼容 ASCII,即 ASCII 字符的 UTF 编码值与其 ASCII 编码值相同。

关系:

  • 所有的 ASCII 字符在 UTF 编码中有相同的编码值。UTF-8 编码中,ASCII 字符的编码与 ASCII 编码完全相同。
  • UTF 编码扩展了 ASCII,使得它能够表示更广泛的字符集,包括拉丁字母以外的字符。

虽然 ASCII 编码和 UTF 编码有关联,但 UTF 编码是更为通用和灵活的编码方案,而 ASCII 可以看作是 UTF 的一个子集。 UTF 编码的出现主要是为了解决 ASCII 的局限性,使得计算机系统能够更好地处理和交换全球范围内的多语言字符。

编码方式常见的两个概念

码点值(字符码元值): 这是指字符在 Unicode 中的唯一标识符。每个字符都被赋予一个唯一的码点,这是一个整数值。例如,拉丁字母 “A” 在 Unicode 中的码点是 U+0041,U+是UTF编码方式的前缀,0041是16进制,十进制表示就是65。这个码点是字符的抽象标识。编码值(Encoded Value): 这是指字符码元值在特定字符编码方案下的实际存储形式。由于计算机内部处理数据的方式通常是使用字节,所以字符码元值需要以某种方式进行编码以便存储和传输。不同的字符编码方案使用不同的规则将字符码元值映射到字节序列。

有几种常见的 UTF 编码方案,其中最常见的是 UTF-8、UTF-16 和 UTF-32,用于表示 Unicode 字符。

按钮有关联

如果按钮之间有关联,比如有三个按钮选中的话,其中一个按钮就要取消选中。怎么确定三个按钮是否选中状态呢

利用input的id和label的for属性可以关联,label作按钮样式,用css写开启按钮的样式和关闭按钮的样式,开启和关闭通过input类型为checkbox的复选框的选中和未选中状态。

记事本

Element.closest() 方法用来获取:匹配特定选择器且离当前元素最近的祖先元素(也可以是当前元素本身)。如果匹配不到,则返回 null。用这个方法来获取被点击元素的祖先元素

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
const delEls = document.querySelectorAll('.fas.fa-trash')
const notes = document.querySelectorAll('.note')
const add = document.querySelector('.add')
const noteContainer = document.querySelector('.notes')
delEls.forEach(item => {
item.addEventListener('click', (e) => {
const grandparent = e.target.closest('.note')
if (grandparent) {
noteContainer.removeChild(grandparent)
}

})
})
add.addEventListener('click', () => {
const addnote = document.createElement('div')
addnote.classList.add('note')
addnote.innerHTML = `
<div class="select">
<div class="icon">
<i class="fas fa-pen"></i>
<i class="fas fa-trash"></i>
</div>
</div>
<textarea name="texts" id="text" cols="30" rows="10"></textarea>
`
noteContainer.appendChild(addnote)
})


为什么新添加的note无法点击删除图标被删除
在添加新的 note 元素时给该元素绑定了点击事件处理程序。然而,这些事件处理程序是在页面加载时绑定的,对于后来动态添加的元素并不会生效。两种解决方法:

1.事件委托(Event Delegation)通过将点击事件处理程序绑定到 noteContainer(或其父级),然后在事件处理程序中检查点击的元素是否是删除图标,从而实现对动态添加的元素的监听。

1
2
3
4
5
6
7
8
noteContainer.addEventListener('click', (e) => {
if (e.target.classList.contains('fas') && e.target.classList.contains('fa-trash')) {
const grandparent = e.target.closest('.note');
if (grandparent) {
noteContainer.removeChild(grandparent);
}
}
});
  1. 为新添加的 note 元素单独绑定事件处理程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
add.addEventListener('click', () => {
const addnote = document.createElement('div');
addnote.classList.add('note');
addnote.innerHTML = `
<div class="select">
<div class="icon">
<i class="fas fa-pen"></i>
<i class="fas fa-trash"></i>
</div>
</div>
<textarea name="texts" id="text" cols="30" rows="10"></textarea>
`;

// 单独为新添加的 note 元素绑定点击事件处理程序
addnote.querySelector('.fa-trash').addEventListener('click', () => {
noteContainer.removeChild(addnote);
});

noteContainer.appendChild(addnote);
});

轮播图和图片导航

轮播图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<head>
<style>
.box{
height:500px;
width:300px;
<!-- 使用display可以让img在水平方向排列,而且会溢出显示(因为img是替换元素,不同于div,不会溢出显示),可以使用overflow:hidden;来遮住溢出显示,但是可以使用transition过渡效果来实现transform:translateX()。 -->
display:flex;
}
img{
height:500px;
width:300px;
}

</style>
</head>
<body>
<div class="box">
<img/>
<img/>
<img/>
</div>
</body>

图片导航(点击导航栏ul li切换图片):使用子绝父相

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
<head>
<style>
.iphone {
height: 500px;
width: 300px;
background-color: blue;
overflow: hidden;
position: relative;
}

img {
position: absolute;
width: 300px;
height: 400px;
opacity:0;
}
img.show{
opacity:1;
}
nav{
position:absolute;
bottom:0;
margin-top:-5px;
width:100%
}
ul{
list-style-type:none;
display:flex;
padding:0;
margin:0;
}
ul li{
<!-- 让弹性盒模型中的子元素宽度相等-->
flex:1;
<!--水平居中-->
text-align: center;
}

</style>
</head>
<body>
<div class="iphone">
<img class="show"/>
<img/>
<nav>
<ul>
<li class="active"></li>
<li></li>
</ul>
</nav>
</div>
<script>
imgs.forEach((item,idx)=>{
item.addEventListener('click',()={
//去除所有img的show
//去除所有li的active
//添加show
item.classList.add('show')
//对应添加active lis为所有li
lis[idx].classList.add('active')
})

})
</script>
</body>

背景图片模糊

当你直接给 body 的背景图片设置 opacity 时,整个 body 的内容,包括所有的子元素,都会受到这个 opacity 的影响。这是因为 opacity 属性会影响元素及其所有后代元素的可见性。使用 body::before 的方式是一种常见的解决方案,通过创建一个伪元素(:before)来包裹整个页面内容,并为这个伪元素设置 opacity。这样做的效果是只有伪元素及其子元素受到 opacity 的影响,而不会影响到 body 的其他内容。但是这样不方便使用js设置伪元素的opacity,如果要有交互就不要使用这种方法。

可以用一个单独的div来装一个100vh,100vw的背景图片,并设置这个div的position:absolute;不影响后续的元素添加在body。注意:这个div的top,left,bottom,right都要设置才能成功显示,一个都不能少。

css3有一个滤镜属性filter,比opacity有更多效果,比如模糊filter:blur(8px);值越大越模糊,灰度filter:grayscale(100%);全灰