各种项目

280 阅读6分钟

项目 1 点击切换效果

首次使用 JS 实现点击切换效果(代替 CSS)

  1. 传统基于操作 DOM 方式实现需求的步骤

    1. 想操作哪个元素,就先获取哪个元素

    2. 给某元素绑定某事件,什么时候干什么事,叫做事件绑定,点击的时候干什么,就要给元素点击的时候,绑定要做的事

    3. 在事件触发的时候修改元素的样式等

两大思想:操作 DOM(传统 JS 和 JQuery) 操作数据

VUE 和 REACT 思想: 操作数据

  • 第一步准备视图

  • 第二步准备数据

  • 第三步建立视图与数据的关系

<!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>
        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        .box {
            width: 400px;
            margin: 30px auto;
            cursor: pointer;
            z-index: 99;
        }

        .box>p{
            box-sizing: border-box;
            width: 100px;
            height: 50px;
            line-height: 50px;
            text-align: center;
            border: 1px solid lightcoral;
        }
        .detail{
            background-color: #fff;
            box-sizing: border-box;
            height: 50px;
            line-height: 50px;
            text-align: center;
            border: 1px solid lightcoral;
            z-index: -1;
            height: 300px;
            line-height: 300px;
            display: none;
            margin-top: -1px;
        }    
        
    </style>
</head>

<body>
    <div class="box" id="box">
        <p id="p">购物车</p>
        <div class="detail" id="detail">
            购物车相关信息
        </div>
    </div>
    <script>
        // ======================IMPORT JS========================
        // 第一步 获取元素并存储
        // document.getElementById([ID]):在整个文档中,通过元素的 ID 获取当前这个元素对象
        let box = document.getElementById('box');
        let detail = document.getElementById('detail');

        // 第二步 事件绑定
        // 元素对象.事件 = 方法
        // 元素对象.onxxx = function(){} : 事件绑定,xxx 事件类型(click/mouseover/mousedown/keydown...) 
        // 点击,触发事件,执行方法
        box.onclick = function(){
        // 第三步 触发事件后调用的方法,此处为修改元素某一个样式值
        // 元素对象.style.xxx = xxx : 修改元素某一个样式值
        // 这种当时操作的是元素行内样式
            detail.style.display = 'block';
        }
    </script>
</body>

</html>
    

目前这种方法操作的是修改元素行内样式

点击前

image.png

点击后

image.png

进阶: 点一下显示,点一下又隐藏,所以要增加一个判断来判断当前状况

<!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>
        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        .box {
            width: 400px;
            margin: 30px auto;
            cursor: pointer;
            z-index: 99;
        }

        .box>p{
            box-sizing: border-box;
            width: 100px;
            height: 50px;
            line-height: 50px;
            text-align: center;
            border: 1px solid lightcoral;
        }
        .detail{
            background-color: #fff;
            box-sizing: border-box;
            height: 50px;
            line-height: 50px;
            text-align: center;
            border: 1px solid lightcoral;
            z-index: -1;
            height: 300px;
            line-height: 300px;
            margin-top: -1px;
            /* 去掉了 display */
        }    
        
    </style>
</head>

<body>
    <div class="box" id="box">
        <p id="p">购物车</p>
        <!-- 修改这里了 -->
        <div class="detail" id="detail" style="display: none;">
            购物车相关信息
        </div>
    </div>
    <script>
        // ======================IMPORT JS========================
        // 第一步 获取元素并存储
        // document.getElementById([ID]):在整个文档中,通过元素的 ID 获取当前这个元素对象
        let box = document.getElementById('box');
        let detail = document.getElementById('detail');

        // 第二步 事件绑定
        // 元素对象.事件 = 方法
        // 元素对象.onxxx = function(){} : 事件绑定,xxx 事件类型(click/mouseover/mousedown/keydown...) 
        // 点击,触发事件,执行方法
        box.onclick = function(){
        // 第三步 触发事件后调用的方法,此处为修改元素某一个样式值
        // 元素对象.style.xxx = xxx : 修改元素某一个样式值
        // 这种操作的是元素行内样式,如果我们没有把样式写在行内上,在 JS 中基于.style.xxx 的方式是无法获取到样式的[获取方法在后续讲]

       
            // 1.首先获取detail原有的样式(显示还是隐藏) : 元素.style.xxx 就是获取行内样式(不写 = xxx 就是获取 写 = xxx 就是赋值)
                // 前提是需要在元素行内设置这个样式才能获取到
            let n = detail.style.display ;
            if( n == 'none'){
            // 2.判断
            // 当前是隐藏的,我们让其显示
            detail.style.display = 'block';
            } else{
            // 当前是显示的,我们让其隐藏
            detail.style.display = 'none';
            }
        }
    </script>
</body>

</html>


简洁版 JS

    <script>
        // 基于 id 可以不获取直接使用
        // let box = document.getElementById('box');
        // let detail = document.getElementById('detail');
       box.onclick = function(){
           let n = detail.style.display;
           if(n === 'none'){
            detail.style.display = 'block';
           }else{
            detail.style.display = 'none';
           }
       }

    </script>

项目 2 判断逻辑的案例训练 (判断数字正负)

需求: 判断一个数字是正数负数

实现效果:

image.png


<body>
    <input type="text" id="numInp">
    <button id="submit">计算结果</button>
    <!-- IMPORT JS -->
    <script>
        // 第一步 获取元素 想操作谁就先获取谁
        let numInp = document.getElementById('numInp');
        let submit = document.getElementById('submit');
        // 第二步 事件绑定 谁触发事件就绑给谁
        submit.onclick = function () {
            // 第三步 行为

            // 1.获取文本框中的内容: 元素.value
            let n = numInp.value;
            // 2. 获取的结果是字符串,需要转换为数字
            n = Number(n);
            // 3. 验证是否为有效数字
            if (!isNaN(n)) {
                // 有效数字 进入
                //4. 接下来根据输入的内容进行相关验证.输出对应的结果
                if (n > 0) {
                    console.log('输入的是正数');
                } else if (n < 0) {
                    console.log('输入的是负数');
                } else {
                    console.log('当前输入的是零');
                }
            } else {
                console.log('当前输入的是非法数字');
            }
        }
    </script>
</body>

项目 3 奇偶行变色(隔行变色) 仅用作练习JS

1. 隔行变色

<!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>
    <style>
        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        #newsBox {
            margin: 20px auto;
            box-sizing: border-box;
            width: 300px;
            padding: 20px;
            border: 2px solid lightblue;
        }

        #newsBox li {
            line-height: 35px;
            border-bottom: 1px dashed lightcoral;
        }

        #newsBox li:nth-last-child(1) {
            border-bottom: none;
        }

        /* 基于 CSS 实现 */
        /* #newsBox li:nth-child(even){
            background-color: lightgray;
        }
        #newsBox li:hover{
            background-color: #bfa;
        } */
    </style>
</head>

<body>
    <!-- ul#newsBox>li*5{我是第$个li} -->
    <div id="newsBox">
        <li>我是第1个</li>
        <li>我是第2个</li>
        <li>我是第3个</li>
        <li>我是第4个</li>
        <li>我是第5个</li>
    </div>

    <!-- IMPORT JS -->
    <script>
        // 第一步 获取元素
        let newsBox = document.getElementById('newsBox');
        // [context].getElementsByTagName([tagname]):在指定的 context 范围之内,通过标签名获取一组元素(也叫元素集合 HTMLCollection)
        // 元素集合和数组很相似,也是一数字索引作为属性名,有 length 属性存储长度,但是不是数组,属于'类数组'
        let newsList = newsBox.getElementsByTagName('li');
        console.dir(newsList); // 见图 1-1

        // 第二步 判断是奇数行还是偶数行,然后确定颜色
        // 因为要重复判断,所以循环
        // 循环所有获取的 li,判断每一个 li 的奇偶行让其有不同背景颜色
        //循环
        for (let i = 0; i < newsList.length; i++) {
            // 第一轮 i = 0 操作第一个 li newsList[0]
            // 第二轮 i = 1 操作第一个 li newsList[1]
            // 第三轮 i = 2 操作第一个 li newsList[2] ...
            // => newsList[i] 当前本轮循环我们要操作的这个li
            let curLi = newsList[i]
            // 判断
            // i=0(索引偶数) 第一个 li 是奇数行
            // i=1(索引奇数) 第二个 li 是奇数行
            // => 当前索引是偶数,则这个 li 是奇数行,否则是偶数行
            // 偶数判断标准: 能被 2 整除(除以 2 余数为 0) n%2 == 0 为 true
            if (i % 2 === 0) {
                // 索引是偶数,代表奇数行
                curLi.style.backgroundColor = '#BFA';
            } else {
                // 索引是奇数,代表偶数行
                curLi.style.backgroundColor = '#DDD';
            }
        }
    </script>
</body>

</html>


图 1-1

  • [context].getElementsByTagName([tagname]):在指定的 context 范围之内,通过标签名获取一组元素(元素集合 HTMLCollection)

  • 元素集合和数组很相似,也是一数字索引作为属性名,有 length 属性存储长度,但是不是数组,属于'类数组'

image.png

效果:

image.png

简洁版代码

    <script>
        
        let newsBox = document.getElementById('newsBox');
       
        let newsList = newsBox.getElementsByTagName('li');
        console.dir(newsList); 
        for (let i = 0; i < newsList.length; i++) {
            let curLi = newsList[i];
            if (i % 2 === 0) {
                curLi.style.backgroundColor = '#BFA';
            } else {
                curLi.style.backgroundColor = '#DDD';
            }
        }

    </script>
    
    // 更简洁高级的三元运算符
    
     for (let i = 0; i < newsList.length; i++) {
            let curLi = newsList[i];
            curLi.style.backgroundColor = i % 2 === 0 ? '#BFA' : '#DDD';


2. 鼠标滑过变色

  • var 和 let 的区别后续补充

  • this : 在事件绑定方法中 this 代表当前操作元素 .还有很多其他情况

        let newsBox = document.getElementById('newsBox');   
        let newsList = newsBox.getElementsByTagName('li');
        // 1.实现奇偶行变色
        for (let i = 0; i < newsList.length; i++) {
            let curLi = newsList[i]
            curLi.style.backgroundColor = i % 2 === 0 ? '#DDD' : '#BFA' ;
            let origin = curLi.style.backgroundColor
            // 2. 循环的时候给每个 LI 绑定 mouseover/mouseout 事件
            curLi.onmouseover = function(){
                // this : 当前操作的这个 li
                this.style.backgroundColor = 'lightblue';
            }
            curLi.onmouseout = function(){
                // 鼠标离开恢复到当前颜色
                // 思考题 如何知道当前的原色? 有很多种方法
                this.style.backgroundColor = origin;
            }

        }

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>隔行变色</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        #box {
            margin: 10px auto;
            box-sizing: border-box;
            width: 500px;
        }

        #box li {
            line-height: 50px;
            border-bottom: 1px dashed rgb(250, 118, 118);
        }

        #newsBox li:nth-last-child(1) {
            border-bottom: none;
        }
    </style>
</head>

<body>
   
    <div id="box">
        <li>我是第1个</li>
        <li>我是第2个</li>
        <li>我是第3个</li>
        <li>我是第4个</li>
        <li>我是第5个</li> 
    </div>

    <!-- IMPORT JS -->
    <script>
        
        var box = document.getElementById('box');
        var boxList = box.getElementsByTagName('li');
        // 1.实现奇偶行变色
        for (var i = 0; i < boxList.length; i++) {
            // boxList[i] 当前循环要操作的li
            boxList[i].style.backgroundColor = i % 2 === 0 ? '#DDD' : '#BFA' ;
            // 设置自定义属性来存储每一个LI的背景颜色
            boxList[i].myorigin = boxList[i].style.backgroundColor;
            // 2. 循环的时候给每个 LI 绑定 mouseover/mouseout 事件
            boxList[i].onmouseover = function(){
                // this : 当前操作的这个 li
                this.style.backgroundColor = 'lightblue';
            }
            boxList[i].onmouseout = function(){
                // 鼠标离开恢复到当前颜色
                // 自定义属性
                this.style.backgroundColor = this.myorigin;
            }

        }

    </script>
</body>

</html>

boxList

理解元素对象与元素对象集合

摘自珠峰视频

image.png

image.png

image.png

项目 4 选项卡案例

需求:点击选项卡,页卡改变

第一次写 使用 var 效果未能实现

<!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>
        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        #tabBox {
            box-sizing: border-box;
            width: 500px;
            margin: 20px auto;
        }

        #navBox {
            display: flex;
            position: relative;
            top: 1px;
        }

        #navBox li {
            box-sizing: border-box;
            margin-right: 10px;
            line-height: 35px;
            padding: 0 10px;
            border: 1px solid #999;
        }

        #navBox li.active {
            border-bottom-color: #fff;
        }

        #tabBox>div {
            display: none;
            box-sizing: border-box;
            padding: 10px;
            height: 150px;
            border: 1px solid #999;
        }

        #tabBox>div.active {
            /* 加了空格就成后代选择器 就不是交集选择器*/
            display: block;
        }
    </style>
</head>

<body>
    <div id="tabBox">
        <ul id="navBox">
            <li class="active">编程</li>
            <li>读书</li>
            <li>运动</li>
        </ul>
        <div class="active">编程使我快乐</div>
        <div>读书使我幸福</div>
        <div>运动使我健康</div>
    </div>
    <!-- IMPORT JS -->
    <script>
        // 第一步 获取元素 操作谁就获取谁
        var tabBox = document.getElementById('tabBox');
        var tabList = tabBox.getElementsByTagName('div');
        var navBox = document.getElementById('navBox');
        var navList = navBox.getElementsByTagName('li');

        // 第二步 循环三个 li,给每个 li 都绑定点击事件
        for (var i = 0; i < navList.length; i++) {
            // navList[i] : 当前循环下我们要操作的那个 li(i变量存储的值是我们需要获取指定元素的索引)
            navList[i].onclick = function (){
                console.log(i);    //=> 3
                changeTab(i);
            }
        }
        // 封装函数 实现选项卡的切换
        // clickIndex: 创建函数的时候,还不知道点的是谁,所以定义一个入口(存储点击这一项的索引),执行方法的时候把点击这一项的索引传递进来即可
        function changeTab(clickIndex) {
            // 1. 先让所有的 li 和 div 都没有选中的样式 => 重复 => 循环
            for(var i = 0; i < navList.length; i++){
                navList[i].className = '';
                tabList[i].className = '';
            }
            // 2. 点击的是谁,就给谁加
            navList[clickIndex].className = 'active';
            tabList[clickIndex].className = 'active';
        }
    </script>
</body>

</html>

changeTab 函数有效

image.png

页面执行效果: 点击无效

image.png

原因: 点击每个 li 索引都显示为 3

image.png

解析:

只有 JS 代码加载完成才能看到页面,只有看到页面用户才能点击

加载到循环代码时 i=0 , i<3 , i++ ;

i=0 navList[0].onclick = function(){...} 绑定事件的时候方法没有执行,点击第一个 li 的时候它才执行. i++ =>1

i=1 navList[1].onclick = function(){...} 绑定事件的时候方法没有执行,点击第二个 li 的时候它才执行. i++ =>2

i=2 navList[2].onclick = function(){...} 绑定事件的时候方法没有执行,点击第三个 li 的时候它才执行. i++ =>3

3<3 不通过,循环结束 i 已经是 3 了

...页面加载完成,用户看到页面

用户点击某一个页卡,接下来开始执行绑定的方法,方法中遇到一个 i,但是此时 i 已经是循环结束后的 3 了.

所以报错

修正:

解决方案一 自定义属性解决办法


 解决办法一: 自定义属性解决办法

        for (var i = 0; i < navList.length; i++) {
 // navList[i] : 当前循环下我们要操作的那个 li(i变量存储的值是我们需要获取指定元素的索引)
 // 在循环给每一个 li 绑定点击事件的时候,给每一个 li(元素对象)设置一个自定义属性myIndex,属性值存储的是当前 li 的索引
 
            navList[i].myIndex = i ;
            navList[i].onclick = function (){
// 我想用的是点击这个 li 的索引,但是 i 不是
// this是当前点击的这个元素li,this.myIndex 获取的就是之前绑定在元素自定义属性上的索引值i       
                changeTab(i);
            }
        }

修改后的循环解读:

加载到循环代码时  i=0 , i<3 , i++ ;

i=0 
    navList[0].myIndex = [0]
    navList[0].onclick = function(){...}  i++ =>1
i=1 
    navList[1].myIndex = [1]
    navList[1].onclick = function(){...}  i++ =>2
...

解决方案二: 闭包

闭包 : 人为写一个闭包

        for (var i = 0; i < navList.length; i++) {
            navList[i].onclick = (function (i){
                return function(){
                    changeTab(i);
                }
            })(i)

解决方案三:

ES6 中的 let 解决方案

let 也能实现闭包

        for (let i = 0; i < navList.length; i++) {
            navList[i].onclick = function (){
                changeTab(i);
            }
        }

项目 5 点击实现页面改变颜色

写法一 使用 switch case

<!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>
    <style>
        *{
            margin: 0;
            padding: 0;
            list-style: none;
        }
        html,body{
            height: 100%;
            overflow: hidden;
        }
        button{
            padding: 40px;
            line-height: 10px;
        }
    </style>
</head>
<body style="background-color: white;">
    <button id="changeBtn">点我变颜色 白红绿蓝白红...</button>
    <!-- IMPORT JS -->
    <script>
        let body = document.body;
        let changeBtn = document.getElementById('changeBtn');
        changeBtn.onclick = function(){
            // 首先获取当前的背景色
            // 元素.style.xxx 只能获取行内样式
            // 颜色在样式中使用 16 进制模式,JS 获取到的是 RGB 的值;写的是单词颜色,获取到的是单词
            let bg = body.style.backgroundColor
            // 判断背景色在不同情况下变不同颜色
            switch (bg){
                case 'white':
                    body.style.backgroundColor = 'red';
                    break;
                case 'red':
                body.style.backgroundColor = 'green';
                break;
                case 'green':
                body.style.backgroundColor = 'blue';
                break;
                default:
                body.style.backgroundColor = 'white';
            }
        }
    </script>
</body>
</html>

写法二 更高级的写法 变换更多颜色 使用数组

  1. 更多颜色

  2. 不用担心颜色的格式是否是 RGB 等等

  3. 不用担心元素.style 只能获取和更改行内样式

  4. 避免冗余

<!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>
    <style>
        * {
            margin: 0;
            padding: 0;
            list-style: none;
        }

        html,
        body {
            height: 100%;
            overflow: hidden;
        }

        button {
            padding: 40px;
            line-height: 10px;
        }
    </style>
</head>

<body style="background-color: white;">
    <button id="changeBtn">点我变色</button>
    <!-- IMPORT JS -->
    <script>
        let body = document.body;
        let changeBtn = document.getElementById('changeBtn');
        let ary = ['white', 'red', 'yellow', 'orange', '#bfa',  'pink', 'yellowgreen', '#999'];
        let i = 0;
        // 从数组中拿值,只需 ary[数字索引]
        //点击按钮实现功能
        changeBtn.onclick = function () {
            i++; // 每次点击,基于累加后的 i 作为索引,在数组中拿到不同的颜色样式值
            // 边界判断 如果索引自增后大于数组最大索引,我们让其从 0 开始即可
            i > ary.length - 1 ? i = 0 : null;
            body.style.backgroundColor = ary[i];
        }
    </script>
</body>

</html>


开关灯案例

不适用 switch 加第三方值 state 做逻辑判断

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <button>开灯</button>
    <button>关灯</button>
    <h1>sdgfsdgsgfsdgsdgfsdgsdgsd</h1>
    <h1>sdgfsdgsgfsdgsdgfsdgsdgsd</h1>
    <h1>sdgfsdgsgfsdgsdgfsdgsdgsd</h1>
    <h1>sdgfsdgsgfsdgsdgfsdgsdgsd</h1>
    <h1>sdgfsdgsgfsdgsdgfsdgsdgsd</h1>
</body>

</html>
<script>
    var btn1 = document.getElementsByTagName('button')[0];
    var btn2 = document.getElementsByTagName('button')[1];
    var body = document.getElementsByTagName('body')[0];
    btn1.style.display = 'none';

    btn1.onclick = function () {
        btn1.style.display = 'none';
        btn2.style.display = 'block';
        body.style.color = 'black';
        body.style.backgroundColor = 'white';
    }

    btn2.onclick = function () {
        btn1.style.display = 'block';
        btn2.style.display = 'none';
        body.style.color = 'white'
        body.style.backgroundColor = 'black'
    }

    // 事件都要用一个函数来包行为
    // 事件的默认值都是 null
</script>


项目 6 点击弹出索引(4.选项卡案例) 自定义属性结合函数底层运行机制理解

是否能实现点击目标按钮就弹出对应按钮索引的效果 ?

如果不能,请说明原因并修改

<body>
    <button value="按钮1">按钮1</button>
    <button value="按钮2">按钮2</button>
    <button value="按钮3">按钮3</button>
    <button value="按钮4">按钮4</button>
    <button value="按钮5">按钮5</button>
    <script>
        var btnList = document.getElementsByTagName('button');
        for (let i = 0; i < btnList.length; i++) {
            btnList[i].onclick = function () {
                alert(i);
            }
        }
    </script>
</body>

答: 不能,点击任何按钮都只会弹出'5' . 原因与项目4选项卡案例相同

图解要点:

  1. btnList获得的值是一个对象类型值(元素集合), 里面有五个botton,每个button各自也是对象.

image.png

image.png

  1. for循环 , i依次循环 , 到5为止

image.png

同时,分别给每个 按钮 btnList[i] 添加了 onclick 属性,属性值是函数 , 所以要另开辟五个堆内存 , 将函数体代码字符串存储起来.里面的i都是字符串 , 不是变量 .

image.png

  1. 点击第二个BUTTON : 把之前赋值给onclick属性对应的函数CCCFFF111执行 , 函数执行,开辟一个全新的私有栈内存.在自身找变量 , 没有, 去外边找, 得到 i = 5

image.png

image.png

解决 :

在循环开始后点击开始前给每个BUTTON 绑上各自的索引 , 让函数不用去找最外边的5 .

image.png

image.png

代码: image.png

<body>
    <button value="按钮1"></button>
    <button value="按钮2"></button>
    <button value="按钮3"></button>
    <button value="按钮4"></button>
    <button value="按钮5"></button>
    <script>
        var btnList = document.getElementsByTagName('button');
        for (let i = 0; i < btnList.length; i++) {
            btnlist[i].myIndex = i;
            btnList[i].onclick = function () {
                alert(this.myIndex);
            }
        }
    </script>
</body>

项目 7 字符串方法项目

7.1 时间字符串的处理

题目

方案一 : 一路REPLACE 利用REPLACE一次只替换一个字符的特性

      let time = '2019-7-24 12:6:23';
      // '2019年07月24日 12时06分23秒'
      time = time.replace('-','年').replace('-','月').replace('','日 ').replace(':','时').replace(':','分')+'秒';
      console.log(time); //=>'2019年7月24日 12时6分23秒'

方案二: 获取年月日时分秒这几个值后,再拼

获取值的方法: 基于split和正则拆分
let time = '2019-7-24 12:6:23';
let ary = time.split(/(?: |-|:)/g);
console.log(ary); // => (6) ['2019', '7', '24', '12', '6', '23']
拼接
time = ary[0]+'年'+ary[1]+'月'+ary[2]+'日';   // => 2019724日
加上补零的方法
time = ary[0]+'年'+addZero(ary[1])+'月'+addZero(ary[2])+'日';

个位数设虚位补零方法:

    let addZero = val => {
        if(val.length < 2){
            val = '0' + val
        }
        return val
    }

简化:
    let addZero = val => {
        val = val.length < 2 ? '0' + val : val
        return val
    }
再简化:
    let addZero = val => {
        return val.length < 2 ? '0' + val : val 
    }
箭头函数return只有一行,则简化:
    let addZero = val => val.length < 2 ? '0' + val : val 

7.2 实现一个方法 queryURLParameter 获取一个URL地址问号后面传递的参数信息

实际应用:

通过列表中的信息进入同一个详情页,不同的信息在同一个详情页中同样结构不同内容

浏览器是如何区分不同信息的呢? 通过URL传递的不同参数来区分

普通情况:

 let url = 'http://www.lorem.cn/index.html?lx=1&name=cola&favorite=aaa#box';
     // #后面是哈希值 哈希路由通过不同的哈希值展示不同的内容渲染不同信息
     /* 
      * 结果:{
          lx:1,
          name:'cola',
          favorite:'aaa',
          HASH:'box'
        }
      */
     // 第一步 获取问号和#后面的值 
     let askIndex = url.indexOf('?'),
        wellIndex = url.indexOf('#'),
        askText = url.substring(askIndex+1,wellIndex);
        wellText = url.substring(wellIndex+1)
        console.log(askText,wellText); // => 'lx=1&name=cola&favorite=aaa' 'box'

    // 第二步 问号后面值的详细处理
    // 拆
    let askAry = askText.split('&');
    console.log(askAry); // =>  ['lx=1', 'name=cola', 'favorite=aaa']
    // 循环放入对象
    let result ={};
    askAry.forEach(item=>{
        // item: 当前从数组中循环的这一项 eg: 'lx=1'
        // 再拆
        let key = item.split('=')[0],
            value = item.split('=')[1];
            // 将拆的内容依次放入对象中
            result[key]=value;
    });
    console.log(result); // => {lx: '1', name: 'cola', favorite: 'aaa'}
    // 处理哈希值
    result['HASH'] = wellText;
    console.log(result);  // => {lx: '1', name: 'cola', favorite: 'aaa', HASH: 'box'}

图解:

image.png 封装成方法:

 <script>
        /* 
            queryURLParams: 获取URL地址中问号传参的信息和哈希值
                @params
                    url[string] 要解析的URL字符串
                @return
                    [object] 包含参数和哈希值信息的对象
            by Ark on 2019/07/24 16:29:00
        */
        // 考虑更多的细节: ? 和 # 不一定都存在
        function queryURLParams(url) {
            //第一步 获取 ? 和 # 后面的信息
            let askIn = url.indexOf('?'),
                wellIn = url.indexOf('#'),
                askText = '',
                wellText = '';

            wellIn === -1 ? wellIn = url.length : null;
            // # 如果不存在 就让url末尾新增一位,放wellIn ;否则,啥也不做 [null只是占位, 什么都不做, 也没有赋值给wellIn]
            if (askIn >= 0) {
                // ? 存在
                askText = url.substring(askIn + 1, wellIn);
                // substring参数 (n,m) 从n开始,截取到m,不包括m
                // 如果 # 存在, 那就截取到 wellIn 前一位为止;
                // 如果wellIn不存在,那也截取到了原索引为url.length的前一位,也就是原索引为url.length - 1 ,正好实现了截取到末尾的功能
            };
            wellText = url.substring(wellIn + 1);
            // #存在,则截取#后面到字符串末尾 ; #不存在,wellIn = url.length ,索引在url.length + 1时是没有字符串的 所以什么都没截取到

            // 第二步 截取每一部分信息
            let result = {};
            wellText !== '' ? result['HASH'] = wellText : null;
            if (askText !== '') {
                let ary = askText.split('&');
                ary.forEach(item => {
                    let itemAry = item.split('=');
                    result[itemAry[0]] = itemAry[1];
                })
            }
            return result;

        };
        let url = 'https://www.yuque.com/login?goto=https%3A%2F%2Fwww.yuque.com%2Fdashboard&wewrwe=232342342&sdsd=123123';
        let paramsObj = queryURLParams(url);
        console.log(paramsObj); // => {goto: 'https%3A%2F%2Fwww.yuque.com%2Fdashboard', wewrwe: '232342342', sdsd: '123123'}
        
 </script>

正则:

         function queryURLParams(url){
             let result = {};
             let reg1 = /([^?=&#]+)=([^?=&#]+)/g,
                reg2 = /#(\.)+/;
                // _ 表示大正则捕获的内容,此处不需要,习惯性的用_占个位
                url.replace(reg1,(_,x,y)=>{
                    result[x] = y;
                });
                url.replace(reg2,(_,x)=>{
                    result["HASH"] = x;
                });

             return result;
         }
         let url1 = 'https://www.yuque.com/login?goto=https%3A%2F%2Fwww.yuque.com%2Fdashboard&wewrwe=232342342&sdsd=123123';
        let paramsObj1 = queryURLParams(url1);
        console.log(paramsObj1);  // => {goto: 'https%3A%2F%2Fwww.yuque.com%2Fdashboard', wewrwe: '232342342', sdsd: '123123'}

7.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>
</head>

<body>
  <input type="text" id="codeInp">
  <br>
  <span id="codeBox"></span>
  <button id="changeCode">看不清,换一张</button>

  <!-- IMPORT JS -->
   <script>
       let codeInp = document.getElementById('codeInp'),
       codeBox = document.getElementById('codeBox'),
       changeCode = document.getElementById('changeCode');
       /* 
            queryCode: 获取到四位随机的验证码, 然后放到指定的盒子中
              @ params 
              @ return
            by Ark on 2019/07/24
       */
        // 多次使用,所以封装成方法
       function queryCode(){
           // 准备获取范围的字符串
            let area = '0123456789qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM';
            
            let result = '';
            for (let i = 0; i < 4; i++) {
               // 每次循环都获取一个随机的数字索引
               let ran = Math.round(Math.random()*61);
               // 再根据获取的索引从范围字符串中找到对应的字符, 把找到的字符拼接到最后的结果当中
               result += area.charAt(ran);
            }
            // 把结果放到盒子里
            codeBox.innerHTML = result;
       }
       // 第一次加载页面需要执行方法, 让其显示在页面中
       queryCode();
       // 点击看不清按钮,需要重新执行方法生成新的验证码
       changeCode.onclick = queryCode; // 不能加小括号,加了小括号相当于把执行结果给点击事件.其实要的是点击事件调用方法.

       // 文本框失去焦点的时候, 验证用户输入的内容和验证码是否相同, 并给予相关提示; 如果不一样需要重新生成验证码(防止对方一直试 试出来)
       // onblur 文本框失去焦点事件
       codeInp.onblur = function (){
           // 获取用户和验证码内容 (表单元素用 .value ; 非标单元素用 .innerHTML)
           let val = codeInp.value,
                code = codeBox.innerHTML;
            if(val.toLowerCase() === code.toLowerCase()){
                alert('温馨提示: 输入成功!')
            }else{
                alert('温馨提示: 验证码输入有误,请重试!');
                // 错误后 让文本框清空
                codeInp.value = '';
                //重新生成验证码
                queryCode();
            }
       };

   </script>
</body>

</html>