我们先来提出几个问题,解决了之后,我们也就实现了一个todo。
前面的
icon
用什么来实现。如何实现文字不可点击,前方
icon
可点击的效果?如果有多个元素循环渲染的情况下,我们怎么在点击的时候对单个元素做样式的修改?(React)
这里有几个部分需要来讨论:
首先是整个用什么来实现这个前面的 icon,是使用伪元素,还是使用一个真实的元素?
这里我看飞书直接用的伪元素来实现的,感觉可能是能用 css
解决的问题就没有必要再去用 html
去写了,那么大致实现逻辑如下。
<div class="todo" id="todo">11111</div>
我们使用伪元素实现这个样式的时候,左侧并不会撑开,也就是说,我们需要去给这个 div
一个靠左的 margin 值。然后再去做具体的打勾框。
.todo { pointer-events: none; margin-left: 20px; } .todo:before { content: " "; display: inline-block; line-height: normal; font-size: 16px; border: 1px solid black; border-radius: 4px; background-position: 50%; white-space: normal; width: 16px; height: 16px; margin-right: 8px; margin-left: -24px; box-sizing: border-box !important; position: relative; cursor: pointer; pointer-events: auto; top: 2px; }
那么上面这些代码,就可以得到下图的展示效果:
是不是看起来已经有了完整的样子啦。
这是我们的 todo
状态,我们还需要实现一个 done
的状态,所以还需要额外的 css
去书写,这里需要注意的是,为了交互更加好看,我们在 hover
的时候会让伪元素的样式变蓝。于是增加了如下代码,有了下图所示的效果:
.todo:hover:before { border: 1px solid rgb(100, 149, 237); }
第二个点就是,我们如何实现一个文字不可点击,前方icon
可点击的效果呢?
其实在上面的代码中已经展示出来了,为这个 div
设置pointer-events: none;
,然后给伪元素设置pointer-events: auto;
就可以啦。
这些考虑完之后,我再给你们展示一下点击状态的css
咋写的:
.done { text-decoration: line-through; } .done::before { background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTEwLjU4OSAzLjkwM2wuODA4LjgwOGEuMzUuMzUgMCAwMTAgLjQ5NUw2LjE4IDEwLjQyNWEuMzUuMzUgMCAwMS0uNDk1IDBMMi43MDMgNy40NDRhLjM1LjM1IDAgMDEwLS40OTVsLjgwOC0uODA4YS4zNS4zNSAwIDAxLjQ5NSAwbDEuOTI1IDEuOTI0IDQuMTYzLTQuMTYzYS4zNS4zNSAwIDAxLjQ5NSAweiIgZmlsbD0iIzMzNzBGRiIvPjwvc3ZnPg==); }
那么你给这个 div
再加上 done
的类名,就可以得到下图的效果了:
最后呢,如果我们有多个 div
,我们如何去做类名的处理呢?
答案是监听点击事件,然后在点击的时候更换类名,代码如下:
const div = document.getElementById('todo'); div.addEventListener('click', (target) => { const classArr = target.currentTarget.className.split(' '); if (classArr.length > 1) { target.currentTarget.className = 'todo' } else { target.currentTarget.className = 'todo done' } })
完整代码如下:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div id="todo">11111</div> </body> <script> const div = document.getElementById('todo'); div.addEventListener('click', (target) => { const classArr = target.currentTarget.className.split(' '); if (classArr.length > 1) { target.currentTarget.className = 'todo' } else { target.currentTarget.className = 'todo done' } }) </script> <style> .todo { margin-left: 20px; } .todo:before { content: " "; display: inline-block; line-height: normal; font-size: 16px; border: 1px solid black; border-radius: 4px; background-position: 50%; white-space: normal; width: 16px; height: 16px; margin-right: 8px; margin-left: -24px; box-sizing: border-box !important; position: relative; cursor: pointer; pointer-events: auto; top: 2px; } .todo:hover:before { border: 1px solid rgb(100, 149, 237); } .done { text-decoration: line-through; } .done::before { background-image: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTQiIGhlaWdodD0iMTQiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTEwLjU4OSAzLjkwM2wuODA4LjgwOGEuMzUuMzUgMCAwMTAgLjQ5NUw2LjE4IDEwLjQyNWEuMzUuMzUgMCAwMS0uNDk1IDBMMi43MDMgNy40NDRhLjM1LjM1IDAgMDEwLS40OTVsLjgwOC0uODA4YS4zNS4zNSAwIDAxLjQ5NSAwbDEuOTI1IDEuOTI0IDQuMTYzLTQuMTYzYS4zNS4zNSAwIDAxLjQ5NSAweiIgZmlsbD0iIzMzNzBGRiIvPjwvc3ZnPg==); } </style> </html>
网友评论文明上网理性发言 已有0人参与
发表评论: