JavaScript基础题目(附答案)

声明:本文是以题目的形式运用js知识点解决问题来提升对js知识点的理解
格式为 题目;方法;原因;缺点(如果方法有缺点的话);实现代码;

文章目录

  • 基础篇
    • 1.分支结构
    • 2.循环
    • 3.函数
    • 4.递归
    • 5.数组
    • 6.字符
    • 7.随机数
    • 8.BOM&DOM
    • 9.正则

基础篇

1.分支结构

1.判断一个字符串是不是纯数字(字符串中不包含小数即以下方法都不能判断含小数的字符串)

方法一:字符转数字的严格模式+if()的隐式类型转换
原因:严格模式下非数字为NaN,NaN在if()的隐式类型转换中为false
缺点:无法判断全是0的数字(因为if()的隐式类型转换中0为false,但实际上0也是数字)

var str1 = "001";
// 方式一:无法判断全是0的数字
if( Number(str1) ){
   	alert("是纯数字");
}else{
  	alert("不是纯数字");
}

方法二:isNaN()+if()的隐式类型转换+if()的隐式类型转换
原因:isNaN()会自动将字符串转换成数值并判断数值是否为NaN

if( isNaN(str1) ){
   	alert("不是纯数字");
}else{
   	alert("是纯数字");
}

方法三:算术运算符的隐士类型转换(除+外)+if()的隐式类型转换
原因:-, *, /, %会将两边的数据作为数值型数据计算,当-,*,/,%两边的数据无法转成数字时,会转成NaN,NaN参与任何运算都是非法的
缺点:无法判断全是0的数字(因为if()的隐式类型转换中0为false,但实际上0也是数字)

if( str1 - 0 ){
   	alert("是纯数字");
}else{
   	alert("不是纯数字");
}

方法四:字符转数字的非严格模式+if()的隐式类型转换
原因:如果是非纯数字的话,数值在转后会造成数值丢失

if( parseInt(str1) == str1 ){
   	alert("是纯数字");
}else{
   alert("不是纯数字");
}

2.判断一个字符是不是空字符

方法一:if()的隐式类型转换
原因:在if()的隐式类型转换中,字符非空为true

var str2 = " ";
if(str2){
    alert("不为空字符");//空格也是字符
}else{
    alert("是空字符");
}

方法二:字符串内容为空的情况下根据字符串为空的属性或者是类型
原因:字符串为空,其值为undefined,同时undefined(类型undefined)的值与null(类型object)相等

if(str==null || str==undefined || str===""){
    console.log("是空字符");
}else{
    console.log("不是空字符");
}

方法三:字符串内容不为空的情况下根据字符串的属性和是字符串的长度
原因:字符串内容不为空其属性为string,长度大于0

if(typeof str == "string" && str.length>0){
    console.log("不是空字符");
}else{
    console.log("是空字符");
}

3.根据输入的月份和当前天数计算是平年的第几天
方法:switch的case穿透
原因:不加break就会引起case穿透,可以利用case穿透做出累加的效果

<script>
    // 月份
    var mouth = 12;
    // 天数
    var day = 31;
    // 平年的第多少天
    var data = 0;
    
    switch(mouth){
        case 12:{
            data += 30;
        }
        case 11:{
            data += 31;
        }
        case 10:{
            data += 30;
        }
        case 9:{
            data += 31;
        }
        case 8:{
            data += 31;
        }
        case 7:{
            data += 30;
        }
        case 6:{
            data += 31;
        }
        case 5:{
            data += 30;
        }
        case 4:{
            data += 31;
        }
        case 3:{
            data += 28; 
        }
        case 2:{
            data += 31;
        }
        case 1:{
            data += day;
            break;      
        }
        default:{
            alert("输入月份错误");
            break;
        }
    }

    console.log(data);
    
</script>

2.循环

1.打印以下图案

	    ***
       *****
      *******
     *********
    ***********
   *************
  ***************

方法:for循环嵌套
原因:第一层for循环控制行,第二层for循环控制列;这个图案分为三个部分,左边是空格,右边是*号1和*号2

for(var i=0;i<7;i++){
    // 空格部分
    for(var j=7;j>i;j--){
        document.write(" ");
    }
    // *号区域1,正常排列,但被空格部分挤往右边,就会看着是往右靠了
    for(var j=0;j<=i;j++){
        document.write("*");
    }
    // *号区域2
    for(var j=0;j<=i+1;j++){
        document.write("*");
    }
    // 换行
    document.write("
"
); }

2.有一个棋盘,有64个方格,在第一个方格里面放1粒芝麻重量是0.00001kg,第二个里面放2粒,第三个里面放4,第四个里面放8,棋盘上放的所有芝麻的重量
方法:for循环嵌套
原因:第一层for循环控制方格,第二层for循环控制方格里面放的芝麻数量

var sum = 0;
for(var i=0;i<64;i++){
    var a = 1;//每当下面的for执行结束,sum加完之后重置a变量
    for(var j=0;j<i;j++){
        a = a * 2;
    }
    // console.log(a);
    sum += a;
}
console.log(sum * 0.00001);

3.函数

1.编写函数,实现任意个任意数字的和
方法:用arguments接收数据,再通过索引遍历处理
原因:arguments用来保存当前函数的所有的实参(不受形参的数量影响)

var sum=0;
function add(){
    for(var i=0;i<arguments.length;i++){
        sum+=arguments[i];
    }
    return sum;
}
console.log(add(1,1,1,1,1));

2.编写一个函数,计算两个数字的和/差/积/商 /余,要求:使用传参的方式
方法:switch分情况处理
原因:因为传入的算术运算符不同要进行的操作也不同,根据传入的算术运算符决定要怎么运算

function compute(n1, n2, sy) {
    switch (sy) {
        case "+": {
            return console.log(n1 + n2);
        }
        case "-": {
            return console.log(n1 - n2);
        }
        case "*": {
            return console.log(n1 * n2);
        }
        case "/": {
            return console.log(n1 / n2);
        }
        case "%": {
            return console.log(n1 % n2);
        }
        default: {
            alert("运算符输入错误");
        }
    }
}
compute(1, 2, "+");
compute(1, 2, "-");
compute(1, 2, "*");
compute(1, 2, "/");
compute(1, 2, "%");

3.编写一个函数,计算任意两个数字之间所能组成的两位数的奇数,数字必须是个位数比如: 计算0,3之间能组成的奇数个是01、21、03、13、23、31
方法:循环遍历然后判断
原因:先确定两个数字之间的范围,再用字符串拼接这些范围内的数字,遍历这些数字,符合条件的输出

function compute(n1, n2) {
    if(n1>n2){
        var temp=0;
        temp=n1;
        n1=n2;
        n2=temp;
    }
    for (var i = 0; i <= n2; i++) {
        for (var j = 0; j <= n2; j++) {
       		//判断奇偶,不要重复的,这里包含了字符,if()的隐式类型转换
            if (("" + i + j) % 2 && i !== j) {
                console.log("" + i + j);
            }
        }
    }
}
compute(3, 0);

4.递归

1.计算n的阶乘
方法:递归
原因:阶乘的计算是一个重复的过程,是有规律可寻的,fn(n) = n * fn(n-1)

function fn(n){
    if(n === 1){
        return 1;
    }else{
        return n * fn(n-1);
    }
}
console.log(fn(10));

2.有一对幼兔,幼兔1个月后长成小兔,小兔1个月后长成成兔并生下一对幼兔,问8个月后有多少对兔子,幼兔、小兔、成兔对数分别是多少?
方法:循环或递归,此处用递归解决总数量
原因:当月成兔和幼兔的数量一样,成兔是上个月的小兔+上个月的成兔,幼兔是上个月的成兔+上个月的小兔,小兔是上个月的幼兔,可以抽象成fn(n) = fn(n-1) + fn(n-2),此时有两个条件fn(1) = 1;fn(2) = 1;

function fn(n){
    if(n === 1 || n === 2){
        return 1;
    }
    return fn(n-1) + fn(n-2);
}
console.log(fn(8));

3.编写一个函数,输入n为偶数时,调用函数求1/2+1/4+…+1/n,当输入n为奇数时,调用函数求1+1/3+…+1/n
方法一:递归
原因:先分两种情况,偶数和奇数.偶数:fn(6)=1/6+1/4+1/2可化为fn(n)=1/n+fn(n-2),此时有一个特殊情况即n=2时值为1/2,同理可得奇数

function fn(n) {
    if (n === 1) {
        return 1;
    } else if (n === 2) {
        return 1 / 2;
    }
    // 奇偶运算的都一样,可以用一个式子返回
    return 1 / n + fn(n - 2);
}
console.log(fn(4));

方法二:循环
原因:与上述原理相同

function fn(n) {
    var sum = 0;
    // 奇数
    if (n % 2) {
        // i的初始值和i += 2 区分奇偶
        for (var i = 1; i <= n; i += 2) {
            sum = sum + 1 / i;
        }
    } else {
        for (var i = 2; i <= n; i += 2) {
            sum = sum + 1 / i;
        }
    }
    return sum;
}
console.log(fn(4));

5.数组

本质操作:索引+长度

1.通过循环制造一个5 x 5的二维数组,这个数组中的数据是hello
方法:二维数组双层循环
原因:在循环外创建一个数组用来装通过外循环创建的数组来实现二维数组,数据填充在二维数组里,然后再新增到一维数组里

var arr1 = new Array();
for (var i = 0; i < 5; i++) {
    var arr2 = new Array();
    for (var j = 0; j < 5; j++) {
        arr2[j] = "hello";
    }
    arr1[i] = arr2;
}
console.log(arr1);

2.编写函数has(arr , n) 判断数组中是否存在n这个元素,返回布尔类型
方法:循环遍历+判断(注意返回值return会结束当前执行语句)
原因:先将数组的每一个数据循环遍历出来再与n比较,如果存在就返回true,不存在就返回false(注意return会结束当前语句,如果在循环里面return false则会结束当前循环)

function has(arr, data) {
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] === data) {
            return true;
        }//不能else然后return false,这样做的话会结束当前执行语句也就是结束循环语句
    }
    return false;
}
var arr = [0, 1, 2, 3, 60];
console.log(has(arr, 60));

3.编写函数norepeat(arr) 将数组的重复元素去掉,并返回新的数组
方法:循环遍历+判断
原因:先新建一个数组,循环遍历原数组,如果原数组的数据在新数组中不存在,则最后新增到新数组

function norepeat(arr) {
    var arrNew = new Array();
    // 循环遍历原数组
    for (var i = 0; i < arr.length; i++) {
        // 判断原数组的数据在新数组中是否存在
        if (!(has(arrNew, arr[i]))) {
            // 最后新增数据放在新数组里
            // arrNew.push(arr[i]);
            arrNew[length++]=arr[i];
        }
    }
    return arrNew;
}
var arr = [1, 1, 1, 2, 3, 3, 4];
console.log(arr);
console.log(norepeat(arr));

4.有一个从小到大排好序的数组。现输入一个数,要求按原来的规律将它插入数组中
方法:循环遍历+判断+赋值覆盖
原因:将数组中的每一个元素与要插入的数比较,找到比要插入的数大的数的位置,从末尾开始往后一个赋值直到要插入的位置,最后将要插入的值赋值在到要插入的位置

function fn(arr, data) {
    // 寻找要插入的位置
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] > data) {
            break;
        }
    }
    // 从要插入的位置往后赋值进行覆盖,i为要插入的位置
    for (var j = arr.length - 1; j >= i; j--) {
        arr[j + 1] = arr[j];
    }
    // 数据插入指定的位置
    arr[i] = data;
}
var arr = [1, 3, 4];
console.log(arr);
fn(arr, 2);
console.log(arr);

6.字符

1.敏感词过滤
方法:先有一个敏感词库,再处理接收到的字符
原因:通过遍历字符将字符中的所有敏感词替换成我们想要替换的字符

(function () {
"use strict"
var worldsList = ["西巴", "啊啊", "坏人"];
var str = "真的西巴,不是啊啊啊,坏人一个西巴啊啊坏人";
console.log(str);
// 循环遍历这个字符中的所有数据
for (var i = 0; i < str.length; i++) {
    // forEach遍历这个数组中的数据
    worldsList.forEach(function (val) {
        str = str.replace(val, "**");
    })
}
console.log(str);
// 完整的敏感词过滤需要用到正则表达式来完善
// 见9.2正则
})();

2.统计每个字符(aabccd)出现的次数,结果显示{a:2, b:1, c:2, d:1},去掉重复的字符,使结果显示abcd
方法:用对象存储数据
原因:新建一个对象,遍历原数据把对象中不存在的字符放入对象中同时值设为1,如果存在字符重复的就让它本身+1,因为用的是对象这种数据类型,其键是没有重复的,所有将其键取出来就能实现去重的效果

(function () {
    "use strict"
    var str = "aabccd";
    var obj = {};
    console.log(str);
    for (var i = 0; i < str.length; i++) {
        // 字符转Boolean
        // 字符:非空为true
        // undefined,null,NaN,都是false
        // 如果obj这个对象中没有str中的数据则为undefined
        if (obj[str[i]]) {
            // 存在,就增加1,表示又出现了一次
            obj[str[i]]++;
        } else {
            // 不存在,设置这个属性,同时值为1,表示第一次出现
            // js中对象的新增属性和数据可以直接通过赋值来增加
            obj[str[i]] = 1;
        }
    }
    console.log(obj);
    // 新建一个字符让其键拼接起来
    var obj2 = "";
    // 遍历对象拿到其键
    for (var j in obj) {
        obj2 += j;
    }
    console.log(obj2);
})();

7.随机数

1.生成随机的十六进制的颜色值
方法:随机数转十六进制
原因:做的时候存在当随机到小于16的数字时,转成16进制不为两位数,即15为f,但是要的结果为0f

(function () {
    "use strict"
    // 限定min-max范围的随机数
    function random(min, max) {
        return Math.round((Math.random()) * (max - min) + min);
    }
    // 方法1:考虑随机数的值
    var str = "";
    for (var i = 0; i < 3; i++) {
        var n = random(0, 255);
        if (n < 16) {
            n = "0" + n.toString(16);
        }
        str += n.toString(16);
    }
    console.log("#" + str);
    
    // 方法2:考虑随机数的转成16进制后的长度
    function createZero(data) {
        return data.length < 2 ? "0" + data : data;
    }
    function randomColor() {
        var r = random(0, 255).toString(16);
        var g = random(0, 255).toString(16);
        var b = random(0, 255).toString(16);
        return "#" + createZero(r) + createZero(g) + createZero(b);
    }
    console.log(randomColor());
})();

2.生成四位随机数字字母混合的验证码
方法:随机数作为ASCII码转成为数字或字母
原因:ASCII的范围97 ~ 122(a ~ z), 65 ~ 90 ( A ~ z ),48 ~ 57 ( 0 ~ 9 ),随机出包含数字和字母的一个字符库,再从这个字符库里面随机选出四个数

(function () {
	"use strict"
	// 限定min-max范围的随机数
    function random(min, max) {
        return Math.round((Math.random()) * (max - min) + min);
    }
	// 随机一个大于4位的且每种字符出现次数一致的随机字符库
	var str = "";
	for (var i = 0; i < 30; i++) {
	    str += String.fromCharCode(random(97, 122));
	    str += String.fromCharCode(random(65, 90));
	    str += String.fromCharCode(random(48, 57));
	}
	console.log(str);
	// 从上面的随机字符库中,随机取4位
	var result = "";
	for (var j = 0; j < 4; j++) {
	    // 每一次从str库中随机取出一个数拼接到新字符中
	    result += str[random(0, str.length - 1)];
	}
	console.log(result);
})();

8.BOM&DOM

1.仿进度条
方法:计时器控制元素
原因: 先获取要操作的元素,然后用计时器让其宽增加,直到小于每一次增加的宽度,再强制将其宽度变成与父元素的宽度相同

html

<div class="box">
     <div class="working">div>
 div>

css

.box {
    display: flex;
    width: 200px;
    height: 200px;
    margin: 0px auto;
    border: 1px solid black;
    justify-content: center;
    flex-direction: column;
}
.working {
    width: 0px;
    height: 10px;
    background-color: cadetblue;
}

js

// getElementsByClassName与ID获取的不一样,打印getElementsByClassName得到的是一个HTMLCollection,要用getElementsByClassName("working")[0]的形式。
// var working = document.getElementsByClassName("working")[0];

var working = document.querySelector(".working");

// 非行内只读
// getComputedStyle(working).width = parseInt(getComputedStyle(working).width) + 10 + "px";

// console.log(working.style.width);
// 行内可设置
// working.style.width=parseInt(getComputedStyle(working).width) + 10 + "px";
// console.log(working.style.width);

// 声明计时器
var t;
// 进度条目标宽度
var traget = 200;
// 每次增加的像素,也能理解为进度条的速度
var speed = 3;

// 点击函数
document.onclick = function () {
    // 清除计时器,防止再次点击的时候又开启新的计时器
    clearInterval(t);
    // 开启计时器
    t = setInterval(doing, 30);
}

// 进度条函数
function doing() {
    // 当前宽度
    var now = parseInt(getStyle(working, "width"));
    // 剩下的宽度小于每一次增加的宽度的时候就清除计时器并将目标宽度赋值给行内样式
    if (traget - now < speed) {
        clearInterval(t);
        working.style.width = traget + "px";
    } else {
        working.style.width = now + speed + "px";
    }
}

// 兼容ie非行内样式获取
// 参数1:传入的选择器
// 参数2:要获取的样式
function getStyle(selector, someStyle) {
    return selector.currentStyle ? selector.currentStyle[someStyle] : getComputedStyle(selector)[someStyle];
}

2.仿选项卡
方法:点击事件+this绑定
原因:先获取导航和内容标签,再对其进行关联,因为不知道用户要点击哪一个,所以需要索引遍历到用户选中的区域再继续操作

html

<div class="box">
    <nav>
        <ul>
            <li style="background-color: brown;">1li>
            <li>2li>
        ul>
    nav>

    <div class="content">
        <div class="content-msg">
            <p>内容1p>
        div>
        <div class="content-msg" style="display: none;background-color: cadetblue;">
            <p>内容2p>
        div>
    div>

div>

css

* {
    margin: 0px;
    padding: 0px;
}

.box {
    overflow: hidden;
    width: 500px;
    height: 500px;
    border: 1px solid black;
    margin: 0px auto;
}

nav {
    width: 100%;
    height: 100px;
    background-color: #ccc;
}

nav ul {
    display: flex;
    width: 100%;
    height: 100%;
    list-style: none;
    justify-content: space-around;
}

nav ul>li {
    width: 100%;
    height: 100%;
    text-align: center;
    line-height: 100px;
    border: 1px solid black;
    box-sizing: border-box;
    color: white;
}

.content {
    width: 100%;
    height: 400px;
}

.content-msg {
    width: 100%;
    height: 400px;
    background-color: rgb(172, 206, 158);
    border: 1px solid black;
}

js

// 效果:默认选中1,内容1,切换到2的时候选中的背景颜色要变到2,1的背景颜色变成没有选中,内容也要变成2
var liList = document.querySelectorAll("nav ul>li");
var msgList = document.querySelectorAll(".content-msg");

// 给选择器绑定自定义num属性,用来作为索引,当当前对象改变时其索引不改变
for (var i = 0; i < liList.length; i++) {
    liList[i].num = i;
}

// 上一次点击的索引,默认值赋0
var pre = 0;

// 遍历选中的元素
for (var i = 0; i < liList.length; i++) {
    liList[i].onclick = function () {
        // 当前选中的元素
        // console.log(this)

        // 点击时上一个变成默认样式
        liList[pre].style.background="none";
        // 当前选中元素变红this指向liList[i]
        this.style.background = "brown";
        
        // 点击时上一个内容变成隐藏
        msgList[pre].style.display="none";
        // 当前选中元素显示this指向msgList[i]
        msgList[this.num].style.display = "block";

        // 把当前点击的设置为上一个点击的
        pre=this.num;
    }
}

3.校验密码强度(只考虑组成类型)
方法:字符串遍历比较
原因:获取输入框中的内容,然后逐位判断,如果有数字/字符串/特殊字符其中一个则为弱,并将结果输出到页面,有两个为中,都要为强

html

<input type="text" id="txt"><span>span>

js

var msg = document.getElementById("txt");
var result = document.querySelector("span");

// 如何获取到输入框中的内容
msg.oninput = function () {
    // console.log(msg.value);

    // 定义初始变量为0,如果出现一种则为1,这个变量不能是全局变量,如果是全局变量则修改值的时候变量不为初始值
    var a = 0;
    var b = 0;
    var c = 0;

    for (var i = 0; i < msg.value.length; i++) {
        // 这里逐位判断字符串用了隐式类型转换,所以能直接判断,比较字母是比较的是ASCII码
        if (msg.value[i] >= 0 && msg.value[i] <= 9) {
            // console.log("数字");
            a = 1;
        }
        if ((msg.value[i] >= 'a' && msg.value[i] <= 'z') || (msg.value[i] >= 'A' && msg.value[i] <= 'Z')) {
            // console.log("字母");
            b = 1;
        }
        if (!((msg.value[i] >= 0 && msg.value[i] <= 9) || (msg.value[i] >= 'a' && msg.value[i] <= 'z') || (msg
                .value[i] >= 'A' && msg.value[i] <= 'Z'))) {
            // console.log("特殊字符");
            c = 1;
        }
    }

    switch (a + b + c) {
        case 1: {
            result.innerHTML = "弱";
            break;
        }
        case 2: {
            result.innerHTML = "中";
            break;
        }
        case 3: {
            result.innerHTML = "强";
            break;
        }
        default: {
            result.innerHTML = "";
        }
    }

}

4.仿聊天框
方法:点击事件,键盘事件
原因:可以通过点击按钮执行函数,也能通过键盘触发函数

html

<div class="box">
    <div class="msg">
    div>
    <div class="form">
        <textarea id="txt">textarea>
        <input type="button" id="btn" value="发送">
    div>
div>

css

.box {
    width: 300px;
    height: 400px;
    border: solid 1px black;
    margin: 0 auto;
}
.box .msg {
    height: 300px;
    border-bottom: solid 1px black;
    overflow: auto;
}
.msg div {
    padding: 6px;
    border-radius: 6px;
    margin: 6px;
    max-width: 200px;
    clear: both;
}
.msg div:nth-child(2n) {
    background: #99f;
    float: left;
}
.msg div:nth-child(2n-1) {
    background: #6f6;
    float: right
}

js

// 获取要插入的区域
var msg = document.querySelector(".msg");
// 获取发送按钮
var btn = document.querySelector("#btn");

// 点击时发送
btn.onclick = function () {
    sent();
}

// 键盘回车时发送
document.onkeydown = function (key) {
    // 获取事件对象兼容
    var key = key || window.event;

    // 获取事件对象键码兼容
    var keycode = key.keyCode || key.witch;

    // 只用回车发送,不加组合键就有第一次发送后第二次发送空字符的bug,因为回车执行了发送函数,再回车
    if (keycode == 13 && key.ctrlKey) {
        sent();
    }

}

// 发送消息的方法
function sent() {
    // 获取文本域
    var text = document.querySelector("#txt");

    // 文本域内容为空就结束这个函数
    if (text.value === "") {
        return;
    }

    // 新创建一个元素,将文本内容放在里面再插入到msg里
    var data = document.createElement("div");
    data.innerHTML = text.value;
    msg.appendChild(data);

    // 最后清空元素
    text.value = "";

    // 显示当前对话框,出现滚动条时可视区域始终为显示框底部即滚动条滚动的距离为页面总高度
    msg.scrollTop = msg.scrollHeight;
}

5.自定义下拉列表
方法:点击事件,鼠标移动事件,自定义对象索引
原因:点击显示框出现下拉列表,选则下拉列表的元素后下拉列表隐藏,把选中的元素填入到显示框

html

<div class="box">
    <span>span>
    <ul class="list">
        <li>北京li>
        <li>上海li>
        <li>广州li>
        <li>深圳li>
        <li>杭州li>
    ul>
div>

css

.box {
    width: 300px;
    height: 40px;
    line-height: 40px;
    margin: 0 auto;
    text-indent: 4px;
}
.box span {
    display: block;
    width: 300px;
    height: 40px;
    border: solid 1px black;
    cursor: pointer
}
.box ul {
    margin: 0;
    padding: 0;
    list-style: none;
    border: solid 1px black;
    border-top: none;
    width: 300px;
    text-indent: 8px;
    display: none;
}
.box ul li.hover {
    background: #66f;
    color: #fff
}

js

var ospan = document.querySelector(".box span");
var oul = document.querySelector(".list");
var ali = oul.children;

// 记录下拉菜单的显示状态:0表示要显示,1表示要隐藏
var flag = 0;
// 默认选中的索引
var index = 0;
// 设置默认项
setDefault();

function setDefault() {
    // 根据索引,设置要显示的内容
    ospan.innerHTML = ali[index].innerHTML;
    // 及选中的状态
    var em = document.createElement("em");
    em.innerHTML = "√";
    ali[index].appendChild(em);
}

for (var i = 0; i < ali.length; i++) {
    // 提前给每个li添加索引
    // 方便修改每次选中
    ali[i].index = i;

    // 鼠标进入,显示样式
    ali[i].onmouseover = function () {
        this.className = "hover";
    }
    // 鼠标离开,隐藏样式
    ali[i].onmouseout = function () {
        this.className = "";
    }

    // 点击
    ali[i].onclick = function () {
        // 先取消默认选中
        ali[index].lastElementChild.remove();
        // 修改默认索引,为点击的元素的索引
        // this.index的index为ali[i].index = i中的index
        index = this.index;

        // 修改默认项
        setDefault()

        // 隐藏下拉菜单
        oul.style.display = "none";
        // 同时更新下拉菜单的状态
        flag = 0;
    }
}

ospan.onclick = function (eve) {
    var e = eve || window.event;
    // 阻止span的事件冒泡
    stopBubble(e);

    // 判断状态,决定下拉菜单的显示或隐藏,同时更新状态
    if (flag === 0) {
        oul.style.display = "block";
        flag = 1;
    } else {
        oul.style.display = "none";
        flag = 0;
    }
}

// 点击空白隐藏,有事件冒泡的影响
document.onclick = function () {
    oul.style.display = "none";
    flag = 0;
}

// 阻止冒泡的兼容
function stopBubble(e) {
    if (e.stopPropagation) {
        e.stopPropagation()
    } else {
        e.cancelBubble = true;
    }
}

6.阻止用户复制页面上的文字
方法:禁用默认事件
原因:默认事件是默认存在的,禁用默认事件就只能触发自己写的事件

html

<p>wefwefp>

js

// 阻止用户复制页面上的文字
// 复制的方式有:
// 选中:
//     1.快捷键复制;
//     2.右键复制
//     3.左键拖拽复制
// 不能选中:
// 控制台复制

// 阻止默认事件的兼容
function stopeDefault(e) {
    if (e.preventDefault) {
        e.preventDefault();
    } else {
        e.returnValue = false;
    }
}

// 禁用ctrl+c(键码67)快捷键
document.onkeydown = function (eve) {
    // 事件对象的兼容
    var e = eve || window.event;
    // 键码的兼容
    var code = e.keyCode || which;

    if (code == 67 && e.ctrlKey) {
        stopeDefault(e);
        console.log("不能通过ctrl+c复制");
    }

    // 禁用控制台
    if(code==123){
        stopeDefault(e);
        console.log("不能通过控制台复制");
    }

}

// 禁用右键
document.oncontextmenu = function (eve) {
    var e = eve || window.event;
    stopeDefault(e);
}

// 禁用拖拽
document.onmousemove = function (eve) {
    var e = eve || window.event;
    stopeDefault(e);
}    

7.跟着鼠标移动的元素
方法:鼠标移动事件+获取坐标
原因:一般的思路是将鼠标的坐标值给第一个元素的left和top,再从后面遍历

html

<div>1div>
<div>2div>
<div>3div>
<div>4div>
<div>5div>
<div>6div>

css

div {
    position: absolute;
    width: 20px;
    height: 20px;
    text-align: center;
    color: white;
    line-height: 20px;
    background-color: cadetblue;
    left: 0px;
    top: 0px;
}

js

// 一连串跟随鼠标移动的元素
var oMove = document.querySelectorAll("div");

// 鼠标移动的时候通过遍历来让其出现
document.onmousemove = function (eve) {
    var e = eve || window.event;
    // 第一个要获取鼠标的页面坐标
    oMove[0].style.left = e.pageX + "px";
    oMove[0].style.top = e.pageY + "px";
    // 从最后开始,当前的位置值为上一个的位置值
    for (var i = oMove.length - 1; i > 0; i--) {
        oMove[i].style.left = oMove[i - 1].offsetLeft + "px";
        oMove[i].style.top = oMove[i - 1].offsetTop + "px";
    }
}

8.元素拖拽
方法:鼠标事件和网页窗口尺寸
原因:鼠标按下的时候就是拖拽

html

<div>div>

css

div {
    position: absolute;
    width: 100px;
    height: 100px;
    background-color: cornflowerblue;
    left: 0px;
    top: 0px;
}

js

// 拖拽效果
var oMove = document.querySelector("div");

// 获取页面宽高,防止移动超过页面右下
var maxW = document.documentElement.clientWidth;
var maxH = document.documentElement.clientHeight;

// 鼠标按下的同时移动就是拖拽
oMove.onmousedown = function (eve) {
    div = eve || window.event;

    // 移动的时候获取鼠标的位置再给元素
    document.onmousemove = function (eve) {
        var indexDiv = eve || window.event;
        // 元素移动的数值应该是相对于页面的坐标-鼠标与选中元素之间的距离
        var l = indexDiv.pageX - div.offsetX;
        var r = indexDiv.pageY - div.offsetY;

        // 处理左上超出范围的问题
        if (l <= 0) {
            l = 0;
        }
        if (r <= 0) {
            r = 0;
        }
        // 处理右下超出范围的问题,offsetWidth是选中块的宽高
        if (l > maxW - oMove.offsetWidth) {
            l = maxW - oMove.offsetWidth;
        }
        if (r > maxH - oMove.offsetHeight) {
            r = maxH - oMove.offsetHeight;
        }

        oMove.style.left = l + "px";
        oMove.style.top = r + "px";

    }

    // 鼠标抬起必须清除鼠标移动
    // 这里对象为document是为了超出指定区域外也能结束鼠标移动
    document.onmouseup = function () {
        document.onmousemove = null;
        document.onmouseup = null;
    }

}

9.随着鼠标移动的提示框
方法:鼠标移动事件+坐标
原因:显示框与鼠标的距离,在结构中插入一个空元素,借助这个空元素对上下节点进行操作

html

<div class="box">
    <div class="news">
        <h2>新闻1的标题h2>
        <span>span>
        <p>这是新闻1 的内容区域p>
    div>
    <div class="news">
        <h2>新闻2的标题h2>
        <span>span>
        <p>这是新闻2的内容p>
    div>
div>

css

.box {
    width: 500px;
    border: solid 1px black;
    margin: 0 auto;
}
.box .news {
    height: 80px;
    margin: 10px 0;
    background: #ccc;
    position: relative;
}
.news h2 {
    margin: 0;
    line-height: 80px;
}
.news p {
    position: absolute;
    margin: 0;
    width: 300px;
    background: #efefef;
    left: 0;
    top: 0;
    z-index: 1;
    display: none;
}
.news span {
    width: 500px;
    height: 80px;
    position: absolute;
    left: 0;
    top: 0;
    z-index: 2;
}

js

var ah2 = document.querySelector(".box").querySelectorAll("span");

for (var i = 0; i < ah2.length; i++) {
    ah2[i].onmouseover = function () {
        this.nextElementSibling.style.display = "block";
    }
    ah2[i].onmouseout = function () {
        this.nextElementSibling.style.display = "none";
    }
    ah2[i].onmousemove = function (eve) {
        var e = eve || window.event;
		// 这个也能用
        // this.nextElementSibling.style.left = e.offsetX + "px";
        // this.nextElementSibling.style.top = e.offsetY + "px";

        this.nextElementSibling.style.left = e.pageX - this.parentNode.offsetLeft + "px";
        this.nextElementSibling.style.top = e.pageY - this.parentNode.offsetTop + "px";
    }
}

9.正则

1.表单验证
方法:用正则对各种数据进行格式的校验
原因:通过正则能够筛选出符合规则的数据

html

<div class="box">
    用户名:<input type="text" id="userName"><span>span>
    密码:<input type="text" id="passWord1"><span>span>
    重复密码:<input type="text" id="passWord2"><span>span>
    手机号:<input type="text" id="tel"><span>span>
    邮箱:<input type="text" id="email"><span>span>
    <input type="submit" id="submit"><span>span>
div>

css

.box {
    display: flex;
    width: 500px;
    height: 500px;
    border: 1px solid black;
    margin: 0 auto;
    flex-direction: column;
    justify-content: space-evenly;
}
span {
    color: red;
}

js

// 1. 用户名 用户名仅支持中文、 字母、 数字、“ - ”“_” 的组合, 4 - 20 个字符
// 2. 密码的规则 数字字母特殊字符, 一种类型, 弱。 两种类型为中, 三种类型为强
// 3. 重复密码 跟第一次输入 密码一致
// 4. 手机号的验证 第一位必须为1, 后面再加10位数字
// 5. 邮箱 数字大小写字母_ - 3 到12位 @ 数字字母 2 到9位.字母2到5位
// 6. 提交按钮的时候, 判断所有输入数据是否符合。 符合跳转, 否, 不跳

// 判断每个输入框是否输入正确的初始值
var btn1 = 0;
var btn2 = 0;
var btn3 = 0;
var btn4 = 0;
var btn5 = 0;

// 用户名
var userName = document.getElementById("userName");
var span1 = userName.nextElementSibling;
var regName = /^[\u2E80-\u9FFF\w-]{4,20}$/;
userName.oninput = function () {
    if (regName.test(this.value)) {
        span1.innerHTML = "√";
        btn1 = 1;
    } else {
        span1.innerHTML = "×";
        btn1 = 0;
    }
}

// 密码
var passWord1 = document.getElementById("passWord1");
var span2 = passWord1.nextElementSibling;
var regpassWord1A = /[0-9]/; // 数字
var regpassWord1B = /[a-z]/; // 字母
var regpassWord1C = /\W|_/; // 特殊字符
passWord1.oninput = function () {
    var A = 0;
    var B = 0;
    var C = 0;
    if (regpassWord1A.test(this.value)) {
        A = 1;
    }
    if (regpassWord1B.test(this.value)) {
        B = 1;
    }
    if (regpassWord1C.test(this.value)) {
        C = 1;
    }

    switch (A + B + C) {
        case 1: {
            span2.innerHTML = "差";
            btn2 = 1;
            break;
        }
        case 2: {
            span2.innerHTML = "中";
            btn2 = 1;
            break;
        }
        case 3: {
            span2.innerHTML = "强";
            btn2 = 1;
            break;
        }
        default: {
            span2.innerHTML = "";
            btn2 = 0;
            break;
        }
    }

    // 输入密码和重复密码后又修改密码
    if (passWord2.value !== "") {
        if (this.value !== passWord2.value) {
            passWord2.nextElementSibling.innerHTML = "×";
            btn3 = 0;
        } else {
            passWord2.nextElementSibling.innerHTML = "√";
            btn3 = 1;
        }
    }
}

// 重复密码
var passWord2 = document.getElementById("passWord2");
// 验证输入的重复密码是否与原密码相同
passWord2.oninput = function () {
    if (this.value === passWord1.value) {
        passWord2.nextElementSibling.innerHTML = "√";
        btn3 = 1;
    } else {
        passWord2.nextElementSibling.innerHTML = "×";
        btn3 = 0;
    }
    if (this.value === "") {
        passWord2.nextElementSibling.innerHTML = "请输入密码";
    }
}

// 手机号
var tel = document.getElementById("tel");
var regTel = /^1\d{10}$/;

tel.oninput = function () {
    if (regTel.test(tel.value)) {
        tel.nextElementSibling.innerHTML = "√";
        btn4 = 1;
    } else {
        tel.nextElementSibling.innerHTML = "×";
        btn4 = 0;
    }
}

// 邮箱
var email = document.getElementById("email");
var regEmail = /^\w{3,12}@[\da-zA-z]{2,9}\.[a-zA-Z]{2,5}$/;

email.oninput = function () {
    if (regEmail.test(email.value)) {
        email.nextElementSibling.innerHTML = "√";
        btn5 = 1;
    } else {
        email.nextElementSibling.innerHTML = "×";
        btn5 = 0;
    }
}

// 提交按钮
// 但每一个输入框输入正确的时候标记1,默认标记0,当标记值为5时候触发跳转
var bottom = document.getElementById("submit");

bottom.onclick = function () {
    var result = btn1 + btn2 + btn3 + btn4 + btn5;

    // 提交时定位用户名输入规范
    if (btn1 === 0) {
        span1.innerHTML = "请按照规范输入";
    }
    // 提交时定位密码输入规范
    if (btn2 === 0) {
        span2.innerHTML = "请按照规范输入";
    }
    // 提交时定位重复密码输入规范
    if (btn3 === 0) {
        passWord2.nextElementSibling.innerHTML = "请按照规范输入";
    }
    // 提交时定位手机号输入规范
    if (btn4 === 0) {
        tel.nextElementSibling.innerHTML = "请按照规范输入";
    }
    // 提交时定位邮箱输入规范
    if (btn5 === 0) {
        email.nextElementSibling.innerHTML = "请按照规范输入";
    }
    // 全部输入规范
    if (result === 5) {
        bottom.nextElementSibling.innerHTML = "√";
    } else {
        bottom.nextElementSibling.innerHTML = "×";
    }

}

2.敏感词过滤
方法:new方式创建正则
原因:通过敏感词库遍历原数据达到完全过滤的效果

// 用正则通过内容检索将替换敏感词库中的内容替换成自定义内容

var badList = ["西巴", "死杂种", "滚蛋"];

var str = "你个死杂种去死吧,西巴啊你,滚蛋吧西巴西巴aaa死杂种西巴";

// let reg = /西巴/g;
// var result = str.replace(reg, "**");
// console.log(result);

// 正则的new创建方式可以表示变量
// new的RegExp的第一个参数是变量,第二个参数是修饰符
for (let i = 0; i < badList.length; i++) {
    // 使用()表示一个值
    let reg = new RegExp("(" + badList[i] + ")+", "g");
    // 每一次替换都是在原基础上替换
    str = str.replace(reg, "**");
    console.log(str);
}
console.log(str);

持续更新中(2021/09/06)

你可能感兴趣的:(js初学者的填坑之路,javascript)