网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
.demo {
margin-bottom: 20px;
border: 1px solid #ebedf0;
border-radius: 2px;
padding: 10px;
}
.demo div {
margin-bottom: 10px;
font-size: 14px;
}
.pagination {
box-sizing: border-box;
margin: 0;
padding: 0;
font-size: 14px;
line-height: 1.5;
list-style: none;
display: inline-block;
}
.pagination.hide {
display: none;
}
.pagination li {
position: relative;
display: inline-block;
float: left;
height: 32px;
margin: 0;
padding: 0 15px;
line-height: 30px;
background: #fff;
border: 1px solid #d9d9d9;
border-top-width: 1.02px;
border-left: 0;
cursor: pointer;
transition: color 0.3s, border-color 0.3s;
}
.pagination li:first-child {
border-left: 1px solid #d9d9d9;
border-radius: 4px 0 0 4px;
}
.pagination li:last-child {
border-radius: 0 4px 4px 0;
}
.pagination li:first-child {
box-shadow: none !important;
}
.pagination li.current {
border-color: #1890ff;
color: #1890ff;
border-left: 1px solid #1890ff;
}
.pagination li.current:not(:first-child) {
margin-left: -1px;
}
案例需求
界面中存在id=jsContainer的节点A,系统会随机实例化各种Pagination实例,按照如下要求补充完成Pagination函数。
- 最多连续显示5页,居中高亮显示
current页(如demo1所示):
2.
total <= 1 时,隐藏该组件(如demo2所示):
3. 如果
total<=5,则显示全部页数,隐藏“首页”和“末页”元素(如demo3所示):
4. 当
current居中不足5页,向后(前)补足5页,隐藏“首页”(“末页”)元素(如demo4和demo5所示):
5.
total、current均为正整数,1 <= current <= total
6. 上面效果演示是 new Pagination(document.getElementById('jsContainer'), 16, 9) 执行后的结果
JavaScript实现
function Pagination(container, total, current) {
this.total = total;
this.current = current;
this.html = html;
this.el = document.createElement('ul'); //TODO: 创建分页组件根节点
this.el.className = 'pagination'
if (!this.el) return;
this.el.innerHTML = this.html();
container.appendChild(this.el);
// 分页组件根节点内容为空时,添加hide类名隐藏
if (!this.el.innerHTML) {
this.el.className = 'pagination hide'; //TODO: 判断是否需要隐藏当前元素
}
function html() {
if (this.total <= 1) return '';
let str = ''
//TODO: 生成组件的内部html字符串
if (this.total <= 5) {
for (let i = 1; i <= this.total; i++) {
str += i == this.current ? `<li class="current">${this.current}</li>` : `<li>${i}</li>`
}
} else {
if (this.current <= 3) {
for (let i = 1; i <= 5; i++) {
str += i == this.current ? `<li class="current">${this.current}</li>` : `<li>${i}</li>`
}
str += '<li>末页</li>'
}
if (this.current > 3 && this.current < this.total - 2) {
str += '<li>首页</li>'
for (let i = this.current - 2; i <= this.current + 2; i++) {
str += i == this.current ? `<li class="current">${this.current}</li>` : `<li>${i}</li>`
}
str += '<li>末页</li>'
}
if (this.current >= this.total - 2) {
str += '<li>首页</li>'
for (let i = this.total - 4; i <= this.total; i++) {
str += i == this.current ? `<li class="current">${this.current}</li>` : `<li>${i}</li>`
}
}
}
return str;
}
}
// 测试
new Pagination(document.getElementById('jsContainer'), 16, 20)
这个案例中Pagination是一个构造函数,需要通过new操作符调用,需要注意的是Pagination内的方法(如html方法)需要先挂载到Pagination上(this.html = html)才能被Pagination中的其它成员访问(通过this访问this.html())
知识点:
- new 运算符与构造函数的使用。
2、通过按键实现移动控制
效果演示
有以下HTML和CSS:
HTML结构
<div id="jsContainer">
<table class="game">
<tbody>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td><td></td><td class="current"></td><td></td><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
</tbody>
</table>
</div>
CSS样式
table.game {
font-size: 14px;
border-collapse: collapse;
width: 100%;
table-layout: fixed;
}
table.game td {
border: 1px solid #e1e1e1;
padding: 0;
height: 30px;
text-align: center;
}
table.game td.current{
background: #1890ff;
}
案例需求
界面中存在id=jsContainer的节点A,系统会随机生成class为game的 m行 n列表格(m >= 1, n >= 1),并随机选中一个td节点,请按照如下需求实现bind函数
bind函数为document绑定keydown事件,当系统触发上(键值38)、下(键值40)、左(键值37)、右(键值39)按键时,请找到当前选中的td节点,并根据当前指令切换高亮节点,具体效果参考上面的效果演示。- 在第一列往左移动则到达最后一列;在最后一列往右移动则到达第一列;在第一行往上移动则到达最后一行;在最后一行往下移动则到达第一行;
- 当前界面为系统在
节点A中生成9 * 9表格并随机选中一个td节点后的效果。
JavaScript实现
function bind() {
document.onkeydown = event => {
if (!event) return;
var code = event.keyCode || '';
if (!{ '37': 1, '38': 1, '39': 1, '40': 1 }[code]) return;
event.preventDefault && event.preventDefault();
//TODO: 请实现按键控制
// 当前元素
const nowCode = document.getElementsByClassName('current')[0]
// 当前元素的父节点的所有子字节的集合
const brotherItems = nowCode.parentElement.getElementsByTagName('td')
// 获取当前元素在父元素中的下标
// 通过数组的indexOf方法查找nowCode在brotherItems中的下标
// 因为brotherItems是伪数组,不算真正意义上的数组,不能直接使用indexOf方法,
// 所以这里通过在随便一个数组上使用indexOf([].indexOf),然后通过call改变indexOf方法的this指向,使其指向到brotherItems
// 这样做之后就相当于是在brotherItems身上执行indexOf方法,call方法的第一个参数之后的参数会作为indexOf方法的参数
const index = [].indexOf.call(brotherItems, nowCode)
// 去除类名
nowCode.className = ''
switch (code) {
// 向左移动
case 37:
// previousElementSibling获取上一个兄弟节点
if (nowCode.previousElementSibling) {
// 如果上个兄弟节点存在,则为上个兄弟节点添加class
nowCode.previousElementSibling.className = 'current'
} else {
// 如果上个兄弟节点不存在,则为父节点的最后一个孩子节点添加class
// parentElement获取父节点
// lastElementChild获取最后一个孩子节点
nowCode.parentElement.lastElementChild.className = 'current'
}
return;
// 向右移动
case 39:
// nextElementSibling获取下一个兄弟节点
if (nowCode.nextElementSibling) {
// 如果下个兄弟节点存在,则为下个兄弟节点添加class
nowCode.nextElementSibling.className = 'current'
} else {
// 如果下个兄弟节点不存在,则为父节点的第一个孩子节点添加class
// parentElement获取父节点
// firstElementChild获取第一个孩子节点
nowCode.parentElement.firstElementChild.className = 'current'
}
return;
// 向上移动
case 38:
if (nowCode.parentElement.previousElementSibling) {
// 如果父元素的上个兄弟节点存在,则为父元素上个兄弟节点的所有孩子节点中下标为index的元素添加class
nowCode.parentElement.previousElementSibling.getElementsByTagName('td')[index].className = 'current'
} else {
// 如果父元素的上个兄弟节点不存在,则为父元素的父元素(爷元素)的最后一个节点的所有孩子节点中下标为index的元素添加class
nowCode.parentElement.parentElement.lastElementChild.getElementsByTagName('td')[index].className = 'current'
}
return;
// 向下移动
case 40:
if (nowCode.parentElement.nextElementSibling) {
// 如果父元素的下个兄弟节点存在,则为父元素下个兄弟节点的所有孩子节点中下标为index的元素添加class
nowCode.parentElement.nextElementSibling.getElementsByTagName('td')[index].className = 'current'
} else {
// 如果父元素的下个兄弟节点不存在,则为父元素的父元素(爷元素)的第一个节点的所有孩子节点中下标为index的元素添加class
nowCode.parentElement.parentElement.firstElementChild.getElementsByTagName('td')[index].className = 'current'
}
return;
}
};
}
// 调用测试
bind()
这个案例主要考察了对JavaScript DOMApi的运用,需要注意的是通过DOMApi获取的元素集合是HTMLCollection类型的伪数组对象,它并不能算是真正意义上的数组,数组上的一些方法对它也不适用,这与arguments相似。
知识点:
- previousElementSibling 返回当前元素在其父元素的子元素节点中的前一个元素节点,如果该元素已经是第一个元素节点,则返回 null, 该属性是只读的。
- nextElementSibling 返回当前元素在其父元素的子元素节点中的后一个元素节点,如果该元素已经是最后一个元素节点,则返回 null, 该属性是只读的。
- parentElement 返回当前节点的父元素节点,如果该元素没有父节点,或者父节点不是一个 DOM 元素,则返回 null。
- lastElementChild 返回对象的最后一个子元素,如果没有子元素,则返回 null。
- firstElementChild 只读属性,返回对象的第一个子元素, 如果没有子元素,则为 null。
- call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
结语
这篇文章的所有内容都出自于牛客网的JS篇题库:
牛客网的JS题库非常贴合实际的,在写的过程中自己查漏补缺,收获了很多,强烈将牛客网推荐给大家!
如果本篇文章对你有所帮助,还请客官一件四连!❤️
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新