一、回车发布评论
描述:
- 用户在input框输入文本,记录输入的字数
- 记录input框的文本,获取当前时间,插入DOM对应元素
- 按下回车,发布评论
- 发布评论之后,清空input框内容
分析:
用到文本和鼠标事件
用到键盘事件并指定回车键
让评论信息模块显示,把拿到的数据渲染到对应标签内部,并清空文本域
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>评论回车发布</title>
// CSS样式部分
<style>
.wrapper {
min-width: 400px;
max-width: 800px;
display: flex;
justify-content: flex-end;
}
.avatar {
overflow: hidden;
width: 48px;
height: 48px;
margin-right: 20px;
border-radius: 50%;
background: url(./images/avatar.jpg) no-repeat center / cover;
}
.wrapper textarea {
flex: 1;
height: 30px;
padding: 10px;
border-color: transparent;
outline: none;
resize: none;
background: #f5f5f5;
border-radius: 4px;
transition: all 0.5s;
}
.wrapper textarea:focus {
height: 50px;
border-color: #e4e4e4;
background: #fff;
}
.wrapper button {
width: 70px;
margin-left: 10px;
border: none;
color: #fff;
background: #00aeec;
border-radius: 4px;
cursor: pointer;
}
.wrapper .total {
margin-right: 80px;
margin-top: 5px;
color: #999;
opacity: 0;
transition: all 0.5s;
}
.list {
display: flex;
min-width: 400px;
max-width: 800px;
}
.list .item {
display: flex;
width: 100%;
}
.list .item .info {
flex: 1;
border-bottom: 1px dashed #e4e4e4;
padding-bottom: 10px;
}
.list .item p {
margin: 0;
}
.list .item .name {
color: #fb7299;
font-size: 14px;
font-weight: bold;
}
.list .item .text {
padding: 10px 0;
color: #333;
font-size: 13px;
}
.list .item .time {
color: #999;
font-size: 12px;
}
</style>
</head>
// HTML代码部分
<body>
<div class="wrapper">
<i class="avatar"></i>
<textarea
id="tx"
placeholder="发一条友善的评论"
rows="2"
maxlength="200"
></textarea>
<button>发布</button>
</div>
<div class="wrapper">
<span class="total">0/200字</span>
</div>
<div class="list">
<div class="item" style="display: none">
<i class="avatar"></i>
<div class="info">
<p class="name">清风徐来</p>
<p class="text">
大家都辛苦啦,感谢各位的努力,能圆满完成真是太好了
</p>
<p class="time">2099-10-10 20:29:21</p>
</div>
</div>
</div>
// JS代码部分
<script>
// 1.获取DOM元素
const tarea = document.querySelector('#tx')
const total = document.querySelector('.total')
const btn = document.querySelector('.wrapper button')
// 2.添加获得焦点事件 让total显示
tarea.addEventListener('focus', function () {
total.style.opacity = 1
})
// 3.添加失去焦点事件 让total隐藏
tarea.addEventListener('blur', function () {
total.style.opacity = 0
})
// 4.添加键盘弹起事件
tarea.addEventListener('keyup', function (e) {
// 4.1 DOM元素插入输入的文本
total.innerHTML = `${tarea.value.length}/200字`
// 4.2 判断弹起的按键是否是回车键
if (e.key === 'Enter') {
// publishComment()
btn.click()
}
})
// 5.封装评论的函数
function publishComment() {
// 5.1 让评论item显示
document.querySelector('.list .item').style.display = 'flex'
// 5.2 改变评论内容
document.querySelector('.list .text').innerHTML = tarea.value
// 5.3 清空文本域
tarea.value = ''
// 5.4 让total重置
total.innerHTML = `0/200字`
}
//6.添加点击事件,调用内容评论函数,点击评论发布内容
btn.addEventListener('click', publishComment)
//说明:监听事件第二个参数为函数,调用时不需要加小括号,否则就是拿到函数返回值
</script>
</body>
</html>
知识补充:字符串的属性方法.trim()
.trim() 是string字符串提供的一个属性方法
作用:用于清除字符串左右两边的空字符串
温馨提示:只清除字符串左右两边,中间的不清除
如果是多个空字符串,则清空为一个空字符串
后面会补充详细的字符串方法。
二、排他思想
描述:
如果有同一组元素,我们想要某一个元素实现某种样式, 需要用到循环的排他思想算法:
1.所有元素全部清除样式(干掉其他人)
2. 给当前元素设置样式 (留下我自己)
3. 注意顺序不能颠倒,首先干掉其他人,再设置自己
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.box {
display: flex;
}
.box div {
width: 100px;
height: 40px;
background-color: skyblue;
margin: 20px;
text-align: center;
line-height: 40px;
}
</style>
</head>
<body>
<div class="box">
<div>div1</div>
<div>div2</div>
<div>div3</div>
<div>div4</div>
</div>
<script>
// 需求 点击某个div div背景色变成红色
// 1 获取所有div
const divs = document.querySelectorAll('.box > div')
// 2 循环绑定事件
for (let i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', function () {
//2.1把其余的div背景色去掉 对当前点击的div设置
// 先干掉所有人-> 让所有的div背景色清空
for (let j = 0; j < divs.length; j++) {
divs[j].style.backgroundColor = ''
}
// 2.2再对自己设置
// divs[i].style.backgroundColor = '#f00'
this.style.backgroundColor = '#f00'
})
}
</script>
</body>
</html>
三、实现TAB栏切换
描述:鼠标经过或点击导航栏任意一个导航快,内容区的内容随之改变
分析:
- 循环为每个小 li 注册事件,在注册事件之前同时为点击的小 li 添加自定义属性 index 用来保存索引号。
- 用排他思想,鼠标经过小 li 后首先循环通过改变 className 去掉所有按钮背景色(干掉其他人),然后为点击的按钮添加 class 增加背景色(留下我自己)。
- 循环将下面显示区的 display 属性设置为 none ,然后获取你当前点击的 li 的 index 属性值,这个索引和下面的 div 是对应的,最终将这个 index 对应的 div 的 display 属性设置为 block就可以了。还是排他思想。
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>tab栏切换</title>
// CSS样式模块
<style>
* {
margin: 0;
padding: 0;
}
.tab {
width: 590px;
height: 340px;
margin: 20px;
border: 1px solid #e4e4e4;
}
.tab-nav {
width: 100%;
height: 60px;
line-height: 60px;
display: flex;
justify-content: space-between;
}
.tab-nav h3 {
font-size: 24px;
font-weight: normal;
margin-left: 20px;
}
.tab-nav ul {
list-style: none;
display: flex;
justify-content: flex-end;
}
.tab-nav ul li {
margin: 0 20px;
font-size: 14px;
}
.tab-nav ul li a {
text-decoration: none;
border-bottom: 2px solid transparent;
color: #333;
}
.tab-nav ul li a.active {
border-color: #e1251b;
color: #e1251b;
}
.tab-content {
padding: 0 16px;
}
.tab-content .item {
display: none;
}
.tab-content .item.active {
display: block;
}
</style>
</head>
//HTML模块
<body>
<div class="tab">
<div class="tab-nav">
<h3>每日特价</h3>
<ul>
<li><a class="active" href="javascript:;">精选</a></li>
<li><a href="javascript:;">美食</a></li>
<li><a href="javascript:;">百货</a></li>
<li><a href="javascript:;">个护</a></li>
<li><a href="javascript:;">预告</a></li>
</ul>
</div>
<div class="tab-content">
// 图片可以切换为你自己的图片库的内容
<div class="item active"><img src="./images/tab00.png" alt="" /></div>
<div class="item"><img src="./images/tab01.png" alt="" /></div>
<div class="item"><img src="./images/tab02.png" alt="" /></div>
<div class="item"><img src="./images/tab03.png" alt="" /></div>
<div class="item"><img src="./images/tab04.png" alt="" /></div>
</div>
</div>
//JS模块
<script>
// 需求 点击tab栏进行对应内容切换
// 1 获取相关元素
const lis = document.querySelectorAll('.tab-nav li')
const divs = document.querySelectorAll('.tab-content div')
// 2 循环绑定事件
for (let i = 0; i < lis.length; i++) {
lis[i].addEventListener('mouseenter', function () {
// 2-1 让点击的菜单加active 其他移除 排他思想
document.querySelector('.tab-nav a.active').classList.remove('active')
this.querySelector('a').classList.add('active')
// 2-2 对应的内容显示 其他内容隐藏 排他思想
document.querySelector('.tab-content div.active').classList.remove('active')
divs[i].classList.add('active')
})
}
</script>
</body>
</html>
四、事件委托
我们还需要了解DOM事件流(event flow)存在三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段。这里就先不展开说了,后续会对事件进行详细讲解。
描述:事件委托就是利用了冒泡的原理,不在当前元素上绑定事件,而是给他的祖先元素绑定事件,事件触发后最终会冒泡到祖先元素上。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<ul>
<li>111</li>
<li>222</li>
<li>333</li>
<li>444</li>
<li>555</li>
</ul>
<script>
// 事件委托、事件委派、事件代理 - 利用冒泡
// 给元素祖先绑定事件,将来子元素触发事件 会冒泡到祖先元素,
//1 提高代码执行效率 2 对动态生成的子元素也生效
const ul = document.querySelector('ul')
ul.addEventListener('click', function (e) {
console.log('ul')
console.log(e.target) // 真正触发的元素
e.target.style.backgroundColor = 'red'
})
// 直接操作儿子缺点 无法获取后面动态生成的元素
</script>
</body>
</html>
五、实现TAB栏切换(事件委托版)
分析:
- 给 a 元素的祖先元素注册点击事件,采取事件委托方式
- 如果点击的是A,则进行排他思想,删除添加类
- 注意判断的方式 利用了e.target.tagName
- 因为没有索引号了,所以这里就是用了自定义属性,给5个链接添加了序号
- 下面的大盒子获取索引的方式 e.target.dataset.id,然后进行排他思想
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>tab栏切换</title>
<style>
* {
margin: 0;
padding: 0;
}
.tab {
width: 590px;
height: 340px;
margin: 20px;
border: 1px solid #e4e4e4;
}
.tab-nav {
width: 100%;
height: 60px;
line-height: 60px;
display: flex;
justify-content: space-between;
}
.tab-nav h3 {
font-size: 24px;
font-weight: normal;
margin-left: 20px;
}
.tab-nav ul {
list-style: none;
display: flex;
justify-content: flex-end;
}
.tab-nav ul li {
margin: 0 20px;
font-size: 14px;
}
.tab-nav ul li a {
text-decoration: none;
border-bottom: 2px solid transparent;
color: #333;
}
.tab-nav ul li a.active {
border-color: #e1251b;
color: #e1251b;
}
.tab-content {
padding: 0 16px;
}
.tab-content .item {
display: none;
}
.tab-content .item.active {
display: block;
}
</style>
</head>
<body>
<div class="tab">
<div class="tab-nav">
<h3>每日特价</h3>
<ul>
<li><a class="active" href="javascript:;" data-id="0">精选</a></li>
<li><a href="javascript:;" data-id="1">美食</a></li>
<li><a href="javascript:;" data-id="2">百货</a></li>
<li><a href="javascript:;" data-id="3">个护</a></li>
<li><a href="javascript:;" data-id="4">预告</a></li>
</ul>
</div>
<div class="tab-content">
<div class="item active"><img src="./images/tab00.png" alt="" /></div>
<div class="item"><img src="./images/tab01.png" alt="" /></div>
<div class="item"><img src="./images/tab02.png" alt="" /></div>
<div class="item"><img src="./images/tab03.png" alt="" /></div>
<div class="item"><img src="./images/tab04.png" alt="" /></div>
</div>
</div>
<script>
// 需求 点击tab栏进行对应内容切换
// 1 获取相关元素
const tab_nav = document.querySelector('.tab-nav')
const divs = document.querySelectorAll('.tab-content div')
// 2 绑定事件
tab_nav.addEventListener('click', function (e) {
if (e.target.tagName === 'A') {
// 2-1 让点击的菜单加active 其他移除
document.querySelector('.tab-nav a.active').classList.remove('active')
// console.log(this) // this 永远绑定的事件源 e.target -> 真正触发的元素
e.target.classList.add('active')
// 2-2 对应的内容显示 其他内容隐藏
document
.querySelector('.tab-content div.active')
.classList.remove('active')
divs[e.target.dataset.id].classList.add('active')
}
})
</script>
</body>
</html>