CSDN话题挑战赛第2期
参赛话题:学习笔记
🖥️ NodeJS专栏:Node.js从入门到精通
🖥️ 博主的前端之路(源创征文一等奖作品):前端之行,任重道远(来自大三学长的万字自述)
🖥️ TypeScript知识总结:TypeScript从入门到精通(十万字超详细知识点总结)
🧑💼 个人简介:大三学生,一个不甘平庸的平凡人🍬
👉 你的一键三连是我更新的最大动力❤️!
🏆分享博主自用牛客网🏆:一个非常全面的面试刷题求职网站,点击跳转🍬
前言
最近博主一直在牛客网刷题巩固基础知识,牛客网不仅具有公司真题、专项练习、面试题库、在线编程等功能,还具有非常强大的AI模拟面试功能,简直是求职者的福音!
牛客网里的题库非常全面的,无论你是前端还是后端,是想要备考还是准备面试又或者是想要提高自己,你都能在牛客网上找到适合自己的题,赶快点击链接去注册登录吧:点我进入牛客网
牛客网 | 牛客网 |
---|---|
![]() | ![]() |
本篇文章所有示例来自于牛客网题库/在线编程/JS篇
,这些都是前端开发中常用的功能,借此记录一下刷题过程,巩固基础!
一、表格排序
描述:
系统会在tbody
中随机生成一份产品信息表单,如html
所示。
请完成 sort
函数,根据参数的要求对表单所有行进行重新排序。
1、type
为id
、price
或者sales
,分别对应第1 ~ 3列
2、order
为asc
或者desc
,asc
表示升序,desc
为降序
3、例如 sort('price', 'asc')
表示按照price
列从低到高排序
4、所有表格内容均为数字,每一列数字均不会重复
5、不要使用第三方插件
方案:
HTML:
<table>
<thead>
<tr>
<th>id</th>
<th>price</th>
<th>sales</th>
</tr>
</thead>
<tbody id="jsList">
<tr>
<td>1</td>
<td>10.0</td>
<td>800</td>
</tr>
<tr>
<td>2</td>
<td>30.0</td>
<td>600</td>
</tr>
<tr>
<td>3</td>
<td>20.5</td>
<td>700</td>
</tr>
<tr>
<td>4</td>
<td>40.5</td>
<td>500</td>
</tr>
<tr>
<td>5</td>
<td>60.5</td>
<td>300</td>
</tr>
<tr>
<td>6</td>
<td>50.0</td>
<td>400</td>
</tr>
<tr>
<td>7</td>
<td>70.0</td>
<td>200</td>
</tr>
<tr>
<td>8</td>
<td>80.5</td>
<td>100</td>
</tr>
</tbody>
</table>
<!-- 测试 -->
<button onclick="sort('price', 'asc')">测试</button>
CSS:
body,
html {
padding: 0;
margin: 0;
font-size: 14px;
color: #000000;
}
table {
border-collapse: collapse;
width: 100%;
table-layout: fixed;
}
thead {
background: #3d444c;
color: #ffffff;
}
td,
th {
border: 1px solid #e1e1e1;
padding: 0;
height: 30px;
line-height: 30px;
text-align: center;
}
function sort(type, order) {
let tb = document.getElementById("jsList");
// console.log(tb.children);
// tb.children是HTMLCollection类型的伪数组,不算真正意义上的数组,不能直接使用Array原型上的sort方法
// 所以这里通过Array.prototype.slice.call将tb.children转换成一个真正的数组
const arr = Array.prototype.slice.call(tb.children)
// 也可以使用以下方法
// const arr = Array.from(tb.children)
// const arr = [...tb.children]
// 排序
arr.sort((a, b) => {
// asc升序,desc降序
if (order === 'asc') {
return parseFloat(a.children[thIndex[type]].innerHTML) - parseFloat(b.children[thIndex[type]].innerHTML)
} else if (order === "desc") {
return parseFloat(b.children[thIndex[type]].innerHTML) - parseFloat(a.children[thIndex[type]].innerHTML)
}
})
arr.forEach((item) => {
tb.appendChild(item)
})
}
// 配置type字段与在tr中的索引的映射关系
const thIndex = {
id: 0,
price: 1,
sales: 2
}
这里使用Array.prototype.slice.call
将伪数组转换为真正的数组的原理是:调用Array
原型上的slice
方法时通过call
方法将this
指向更改为指向原来的伪数组,这样的效果就相当于是在伪数组上使用slice
(伪数组本身不能直接使用slice
方法),slice
方法用于切割原数组,而当slice
方法不传任何参数时就相当于是从原数组开头切割到末尾(相当于原数组的浅拷贝,不会改变原数组)
知识点:
- slice(a,b) 方法用于切割数组,从下标a开始到下标b(包含下标a的元素,不包含下标b的元素),该方法不会改变原数组,只会返回一个浅复制了原数组中的元素的一个新数组。
- call() 方法使用一个指定的
this
值和单独给出的一个或多个参数来调用一个函数。 - sort() 方法对数组的元素进行排序,并返回数组。
二、替换链接
描述:
页面中存在id=jsContainer
的DOM
元素。
该DOM
元素内会给出一段随机文本,可能包含一些链接,比如https://www.baidu.com
,或者 www.baidu.com?from=onlineExam
,如果出现链接文本,请给该链接文本加上链接标签,用户点击后能直接在新窗口中打开该链接。
完成 link
函数,完成该功能
1、container
只有纯文本内容,不包含其他dom
元素
2、识别所有以http://
、https://
或者www.
开始的链接
3、所有www.
开头的链接,默认使用 http
协议
4、所有链接在新窗口打开
方案:
HTML:
<div id="jsContainer">
这里会给出一段随机文本,可能包含一些链接,比如http://www.baidu.com,或者
www.baidu.com?from=onlineExam,如果出现链接文本,请给该链接文本加上链接标签,用户点击后能直接在新窗口中打开该链接。
</div>
<button onclick="link()">测试</button>
CSS:
a {
color: #00bc9b;
}
JavaScript:
function link() {
const elm = document.querySelector('#jsContainer');
let reg = /(https?:\/\/)?(www\.\w+(\.(com|cn))*(\?\w+=\w*(&\w+=\w*)*)?(#\w+)?)/g
elm.innerHTML = elm.innerHTML.replace(reg, function (...args) {
// args[1]表示的是正则第一个括号内匹配的内容,即https?:\/\/匹配到的内容
if (args[1]) {
// args[2]表示正则第二个括号内匹配的内容,即www\.\w+(\.(com|cn))*(\?\w+=\w*(&\w+=\w*)*)?(#\w+)?匹配到的内容
// args[0]代表正则匹配到的字串
return `<a target="_blank" href="${args[1]}${args[2]}">${args[0]}</a>`;
} else {
console.log(args);
return `<a target="_blank" href="http://${args[2]}">${args[0]}</a>`;
}
})
}
正则解析:
/(https?:\/\/)?(www\.\w+(\.(com|cn))*(\?\w+=\w*(&\w+=\w*)*)?(#\w+)?)/g
?
代表前面的字符可选,https?
能匹配到http
和https
。?
前有括号包裹则代表括号内的内容可选,如(https?:\/\/)?
表示https?:\/\/
是可选的。- 如果想匹配特殊字符,如
/
、.
、?
等,需要在前面加\
对其进行转义,即使用:\/
、\.
、\?
\w
是字符组[0-9a-zA-Z_]
的简写形式,即\w
是字母数字或者下划线的中任何一个字符。+
等价于{1,}
,表示出现至少一次。*
等价于{0,}
,表示出现任意次,有可能不出现。- 末尾的
g
代表全局匹配。
这里主要使用的是字符串的replace方法,这个方法很强大,之后博主会出文章对其进行详细讲解,这里先简单说一下:
replace
方法第一个参数能接收一个正则表达式;第二个参数能接受一个方法,该方法的返回值会作为替换字符串替换匹配到的内容,并且如果第一个参数的正则表达式为全局匹配模式(加g
),则该方法将被多次调用,每次匹配都会被调用。
着重要说的就是replace
第二个参数的这个方法,该方法会有以下参数:
这时再看上面js
代码中的args[1]
、args[0]
应该就能理解了。
三、倒计时
描述:
倒计时是web
开发中常见的组件,完成second
和render
两个函数,完成倒计时的显示部分
1、second
函数的输入为整数(时间间隔秒数),返回{day: Int, hour: Int, min: Int, second: Int}
2、render
函数的输入为second
函数的输出,将数据在页面对应的DOM
元素上显示出来,格式如html
所示
3、如果day
为0,隐藏对应的DOM
元素,否则显示(请直接使用已经实现的css
代码)
4、数值不足两位,前面补充0
方案:
HTML:
<div id="jsCountdown">
<span>01天</span>
<span>02:</span>
<span>03:</span>
<span>04</span>
</div>
CSS:
.hide {
display: none;
}
JavaScript:
function second(second) {
// 总的分钟
let min = parseInt(second / 60)
// 总的小时
let hour = parseInt(min / 60)
// 总的天数
let day = parseInt(hour / 24)
// 取余,获得转换后的秒数
second = second % 60
// 取余,获得转换后的分钟
min = min % 60
// 取余,获得转换后的小时
hour = hour % 24
return {
day,
hour,
min,
second
}
}
function render(data) {
const d = document.getElementById("jsCountdown").getElementsByTagName('span')
if (data.day == 0) {
d[0].className = 'hide'
} else {
d[0].innerHTML = `${data.day < 10 ? ('0' + data.day) : data.day}天`
}
d[1].innerHTML = `${data.hour < 10 ? ('0' + data.hour) : data.hour}:`
d[2].innerHTML = `${data.min < 10 ? ('0' + data.min) : data.min}:`
d[3].innerHTML = `${data.second < 10 ? ('0' + data.second) : data.second}`
}
// 测试
render(second(100000))
在second
方法中我们也可以直接使用Date
对象来进行转换获取日、小时、分钟和秒数,但都必须使用UTC
的方法:
function second(second) {
// second * 1000 获取毫秒数
// data为从 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC,即协调世界时)走过second * 1000毫秒后的日期
const data = new Date(second * 1000)
return {
// 需要使用UTC的方法
day: data.getUTCDate() - 1,
hour: data.getUTCHours(),
min: data.getUTCMinutes(),
second: data.getUTCSeconds()
}
}
带有
UTC
的方法表示的是以协调世界时(全球标准时间UTC)为标准,不带UTC
的方法是以本地时间为标准
上面的day
在获取时需要减1(data.getUTCDate() - 1
)是因为当输入的倒计时秒数不够一天的秒数时,getUTCDate()
返回的是1(getUTCDate()
返回一个指定的 Date
对象为一个月中的哪一日(1-31))。
四、双色球机选一注
描述:
双色球由33个红球和16个蓝球组成,1注双色球包括6个不重复的红球和1个蓝球。
实现 randomFn
函数,实现“随机一注”功能,要求如下:
函数返回:
- 以字符串形式输出“随机一注”结果,选中的红蓝球用"
|
“隔开,红球在前,号码间用半角逗号隔开,如"06,10,13,18,23,27|05
” - 红球和蓝球号码排列顺序 需与页面展示的顺序对应
页面交互:
- 将选中的红球和蓝球(页面中对应
DOM
元素)用class="active"
高亮 - 将选中的球按号码从小到大排列,移至所属组的前方,结果如示意图所示
- 每次执行
randomFn
函数,输出符合要求且不完全重复
注意:
1、使用原生JavaScript
操作DOM
元素,不要增加、删除DOM
元素或修改css
2、使用ES5
语法
3、不要使用第三方插件
4、运行浏览器为chrome
浏览器
方案:
HTML:
<div class="main">
<div class="balls red">
<span>红球</span>
<div class="balls-wp">
<b>01</b>
<b>02</b>
<b>03</b>
<b>04</b>
<b>05</b>
<b>06</b>
<b>07</b>
<b>08</b>
<b>09</b>
<b>10</b>
<b>11</b>
<b>12</b>
<b>13</b>
<b>14</b>
<b>15</b>
<b>16</b>
<b>17</b>
<b>18</b>
<b>19</b>
<b>20</b>
<b>21</b>
<b>22</b>
<b>23</b>
<b>24</b>
<b>25</b>
<b>26</b>
<b>27</b>
<b>28</b>
<b>29</b>
<b>30</b>
<b>31</b>
<b>32</b>
<b>33</b>
</div>
</div>
<div class="balls blue">
<span>蓝球</span>
<div class="balls-wp">
<b>01</b>
<b>02</b>
<b>03</b>
<b>04</b>
<b>05</b>
<b>06</b>
<b>07</b>
<b>08</b>
<b>09</b>
<b>10</b>
<b>11</b>
<b>12</b>
<b>13</b>
<b>14</b>
<b>15</b>
<b>16</b>
</div>
</div>
</div>
CSS:
.main .balls {
width: 450px;
padding: 30px 10px 10px;
margin-bottom: 20px;
position: relative;
border-radius: 4px;
}
.main .balls:after {
content: '\20';
clear: both;
display: block;
height: 0;
overflow: hidden;
}
.main .balls span {
position: absolute;
left: 12px;
top: 5px;
font-size: 13px;
}
.main b {
float: left;
width: 30px;
height: 30px;
font-size: 15px;
background: #FFF;
border: 1px solid;
border-radius: 50%;
line-height: 30px;
text-align: center;
margin-right: 8px;
margin-bottom: 8px;
cursor: pointer;
}
.main .red .active {
background: #f56c6c;
color: #FFF;
}
.main .blue .active {
background: #3a8ee6;
color: #FFF;
}
.main .red {
background: #feeff0;
}
.main .red b {
border-color: #f56c6c;
}
.main .blue {
background: #ecf8ff;
}
.main .blue b {
border-color: #3a8ee6;
}
JavaScript:
console.log(randomFn());;
function randomFn() {
return selectBall('red', 6) + '|' + selectBall('blue', 1);
}
// 定义一个复用函数
function selectBall(color, num) {
var wrap = document.querySelector('.' + color + ' .balls-wp');
var balls = wrap.getElementsByTagName('b');
// 存放随机获取到的元素
var choosed = [];
for (var i = 0; i < num; i++) {
// 随机获取元素下标
var index = Math.floor(Math.random() * balls.length);
choosed.push(balls[index]);
// 添加类名
balls[index].classList.add('active');
// 将该元素在父容器中删除,避免下次随机获取元素时还获取到该元素(避免重复)
balls[index].remove();
}
// 排序:升序
choosed.sort(function (a, b) {
// innerText在2016 年才正式进入 HTML 标准,在一些编译器中使用它会导致编译不通过
// 可以使用innerHTML或textContent
return a.innerHTML - b.innerHTML;
});
// 注意这里的循环要到着来,因为后插入的会在新插入的前面
for (var i = num - 1; i >= 0; i--) {
// 将choosed[i]插入到wrap中balls[0]的前面,这时choosed[i]将成为新的balls[0]
wrap.insertBefore(choosed[i], balls[0]);
}
return choosed.map(function (val) {
return val.innerHTML;
}).join(',');
}
知识点:
-
Math 是一个内置对象,它拥有一些数学常数属性和数学函数方法(
Math
不是一个函数对象)。这里用到的Math.floor
返回小于一个数的最大整数,即一个数向下取整后的值;Math.random
返回一个 0 到 1 之间的伪随机数。 -
Element.remove() 方法,把对象从它所属的 DOM 树中删除。
-
Node.insertBefore() 方法在参考节点之前插入一个拥有指定父节点的子节点。
语法:var insertedNode = parentNode.insertBefore(newNode, referenceNode);
insertedNode
:被插入节点 (newNode
)parentNode
:新插入节点的父节点newNode
:用于插入的节点referenceNode
:newNode
将要插在这个节点之前
如果
referenceNode
为null
则newNode
将被插入到子节点的末尾。
结语
这篇文章的所有内容都出自于牛客网的JS篇题库:
牛客网的JS
题库非常贴合实际的,在写的过程中自己查漏补缺,收获了很多,强烈将牛客网推荐给大家!
如果本篇文章对你有所帮助,还请客官一件四连!❤️