【前端学习笔记】JS篇·三

jQuery入门

一、概述

1.JavaScript库

即library,是一个封装好的特定的集合方法和函数)。

简单理解,就是一个JS文件,里面堆我们原生的js代码进行了封装,存放到里面。这样我们就可以快速高效地使用这些封装好的功能。

比如jQuery,就是为了快速方便地操作DOM,里面基本都是函数(方法)。

常见JavaScript库:jQuery、Prototype、YUI、Dojo、Ext JS、移动端的zepto。

2.jQuery

jQuery是一个快速、简洁的JavaScript库,其设计宗旨是"write less, do more",提倡写更少的代码,做更多的事情。

j-JavaScript,Query-查询。意思就是将js的DOM操作做了封装,我们可以快速地查询使用里面的功能。jQuery封装了JavaScript常用的功能代码,优化了DOM操作、事件处理、动画设计和Ajax交互。

优点:

  • 轻量级;
  • 跨浏览器兼容;
  • 链式编程、隐式迭代;
  • 对事件、样式、动画支持,大大简化了DOM操作;
  • 支持插件扩展开发,有着丰富的第三方插件,例如,树形菜单、日期控件、轮播图等;
  • 免费、开源。

二、基本使用

1.下载

官方网址:https://jquery.com

2.使用

  1. 引入

    <!-- jQuery引用 -->
    <script src="jquery.min.js"></script>
    
  2. 使用

3.jQuery入口函数

// 等待页面DOM加载完毕再执行js代码
$(function() {
	...	// 此处是页面DOM加载完成的入口
})

// 或
// 等待页面DOM加载完毕再执行js代码
$(document).ready(function() {
	...	// 此处是页面DOM加载完成的入口
})
  1. 等待DOM结构渲染完毕即可执行内部代码,不必等到所有外部资源加载完成,jQuery帮我们完成了封装;
  2. 相当于原生js中的DOMContentLoaded。

4.jQuery顶级对象$

  1. ** 是 j Q u e r y 的别称 ∗ ∗ ,在代码中可以使用 j Q u e r y 代替 是jQuery的别称**,在代码中可以使用jQuery代替 jQuery的别称,在代码中可以使用jQuery代替。但一般为了方便,通常都直接使用$。

  2. 是 j Q u e r y 的顶级对象,相当于原生 J a v a S c r i p t 中的 w i n d o w 。把元素利用 是jQuery的顶级对象,相当于原生JavaScript中的window。把元素利用 jQuery的顶级对象,相当于原生JavaScript中的window。把元素利用包装成jQuery对象,就可以调用jQuery方法。

    $('div').hide();
    

5.jQuery对象和DOM对象

  1. 用原生JS获取来的对象就是DOM对象;

    var myDiv = document.querySelector('div');
    console.dir(myDiv);
    
  2. 通过jQuery方式获取来的对象就是jQuery对象;

    $('div');
    console.dir('div');
    
  3. jQuery对象只能使用jQuery方法,DOM对象则使用原生的JavaScript属性和方法。

  4. DOM对象与jQuery对象相互转换

    由于原生js比jQuery更大,原生的一些属性和方法jQuery没有给我们封装,因此我们要想使用这些属性和方法需要将jQuery对象转换为DOM对象才行。

    • DOM对象转jQuery对象

      $(DOM对象)
      // 1. 直接通过$获取
      $('video');
      
      // 2. 已经使用原生js获取DOM对象 转换为jQuery对象
      var myvideo = document.querySelector('video');
      $(myvideo);
      
    • jQuery对象转DOM对象

      $('div')[index];	// index为索引号
      $('div').get(index);	// index为索引号
      
      $('video')[0].play();
      $('video').get(0).play();
      

jQuery常用API

一、jQuery选择器

1.jQuery基础选择器

$("选择器")	// 里面选择器直接写CSS选择器即可 但是要加引号
名称用法描述
ID选择器$(“#id”)获取指定ID的元素
全选选择器$(“*”)匹配所有元素
类选择器$(“.class”)获取同一类class的元素
标签选择器$(“div”)获取同一类标签的所有元素
并集选择器$(“div,p,li”)选取多个元素
交集选择器$(“li.current”)交集元素

2.jQuery层级选择器

名称用法描述
子代选择器$(“ul>li”)获取亲儿子层级的元素,不会获取孙子层级的元素
后代选择器$(“ul li”)获取ul下的所有li元素,包括孙子等

3.隐式迭代

遍历内部DOM元素(伪数组形式存储)的过程就叫做隐式迭代

即,给匹配到的所有元素进行循环遍历,执行相应的方法,而不用我们再进行循环。这简化了我们的操作,方便我们调用。

<div>1</div>
<div>2</div>
<div>3</div>
<script>
	// 将3个div的背景颜色都改为粉色
    $("div").css("background", "pink");
</script>

4.jQuery筛选选择器

语法用法描述
:first$(‘li:first’)获取第一个li元素
:last$(‘li:last’)获取最后一个li元素
:eq(index)$(li:eq(2))获取到的li元素中,选择索引号为2的元素(索引号从0开始)
:odd$(‘li:odd’)获取到的li元素中,选择索引号为奇数的元素
:even$(‘li:even’)获取到的li元素中,选择索引号为偶数的元素

5.jQuery筛选方法

语法用法说明
parent()$(“li”).parent();查找父级
parents(‘selector’)$(‘.four’).parents(‘.one’);查找指定祖先
children(selector)$(“ul”).children(‘li’);相当于$(“ul>li”),查找亲儿子
find(selector)$(“ul”).find(“li”);相当于$(“ul li”),查找后代
siblings(selector)$(“.first”).siblings(“li”);查找兄弟节点,不包括自己本身
nextAll([expr])$(“.first”).nextAll();查找当前元素之后所有的同辈元素
prevAll([expr])$(“.last”).prevAll();查找当前元素之前所有的同辈元素
hasClass(class)$(“div”).hasClass(“protected”);检查当前的元素是否含有某个特定的类,如果有,则返回true
eq(index)$(“li”).eq(2);相当于$(“li:eq(2)”)
5.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>
    <!-- jQuery引用 -->
    <script src="jquery.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        ul {
            list-style: none;
        }

        a {
            text-decoration: none;
            color: #333;
        }

        .nav {
            margin: 100px;
        }

        .nav>li {
            float: left;
            width: 80px;
            height: 41px;
            line-height: 41px;
            text-align: center;
        }

        .nav>li>a {
            display: block;
            width: 100%;
            height: 100%;
            color: #333;
        }

        .nav>li>a:hover {
            background-color: #eee;
        }

        .nav li ul {
            display: none;
            font-size: 14px;
            border-left: 1px solid #FECC5B;
            border-right: 1px solid #FECC5B;
        }

        .nav li ul li {
            border-bottom: 1px solid #FECC5B;
        }
    </style>
</head>

<body>
    <ul class="nav">
        <li>
            <a href="#">微博</a>
            <ul>
                <li>私信</li>
                <li>评论</li>
                <li>@我</li>
            </ul>
        </li>
        <li>
            <a href="#">微博</a>
            <ul>
                <li>私信</li>
                <li>评论</li>
                <li>@我</li>
            </ul>
        </li>
        <li>
            <a href="#">微博</a>
            <ul>
                <li>私信</li>
                <li>评论</li>
                <li>@我</li>
            </ul>
        </li>
        <li>
            <a href="#">微博</a>
            <ul>
                <li>私信</li>
                <li>评论</li>
                <li>@我</li>
            </ul>
        </li>
    </ul>
    <script>
        $(function () {
            $(".nav>li").mouseover(function () {
                // $(this) jQuery 当前元素 this不用加引号
                $(this).children("ul").show();
            });
            $(".nav>li").mouseout(function () {
                $(this).children("ul").hide();
            });
        })
    </script>
</body>

</html>

file:///G:/%E5%AD%A6%E4%B9%A0/WEB%E5%89%8D%E7%AB%AF/%E9%BB%91%E9%A9%AC%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/%E6%A1%88%E4%BE%8B/demo25/%E6%96%B0%E6%B5%AA%E4%B8%8B%E6%8B%89%E8%8F%9C%E5%8D%95.html

6.jQuery排他思想

<!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>jQuery排他思想</title>
    <!-- jQuery引用 -->
    <script src="jquery.min.js"></script>
    <style>
        button {
            outline: none;
        }
    </style>
</head>

<body>
    <button>点击</button>
    <button>点击</button>
    <button>点击</button>
    <button>点击</button>
    <button>点击</button>
    <button>点击</button>
    <button>点击</button>
    <button>点击</button>
    <script>
        $(function () {
        	// 隐式迭代
            $('button').click(function () {
                // 当前元素变化背景颜色
                $(this).css('background', 'pink');
                // 其余兄弟去掉背景颜色
                $(this).siblings('button').css('background', '');
            })
        })
    </script>
</body>

</html>
6.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>
    <script src="jquery.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        ul {
            list-style: none;
        }

        a {
            text-decoration: none;
            color: #333;
        }

        .wrapper {
            width: 250px;
            height: 248px;
            margin: 100px auto 0;
            border: 1px solid pink;
            border-right: 0;
            overflow: hidden;
        }

        #left,
        #content {
            float: left;
        }

        #left li {
            background: url(images/lili.jpg) repeat-x;
        }

        #left li a {
            display: block;
            width: 48px;
            height: 27px;
            border-bottom: 1px solid pink;
            line-height: 27px;
            text-align: center;
            color: black;
        }

        #left li a:hover {
            background: url(images/abg.gif) repeat-x;
        }

        #content {
            border-left: 1px solid pink;
            border-right: 1px solid pink;
        }
    </style>
</head>

<body>
    <div class="wrapper">
        <ul id="left">
            <li><a href="#">女靴</a></li>
            <li><a href="#">雪地靴</a></li>
            <li><a href="#">冬裙</a></li>
            <li><a href="#">呢大衣</a></li>
            <li><a href="#">毛衣</a></li>
            <li><a href="#">棉服</a></li>
            <li><a href="#">女裤</a></li>
            <li><a href="#">羽绒服</a></li>
            <li><a href="#">牛仔裤</a></li>
        </ul>
        <div id="content">
            <div><a href="#"><img src="./images/女靴.jpg" alt=""></a></div>
            <div><a href="#"><img src="./images/雪地靴.jpg" alt=""></a></div>
            <div><a href="#"><img src="./images/冬裙.jpg" alt=""></a></div>
            <div><a href="#"><img src="./images/呢大衣.jpg" alt=""></a></div>
            <div><a href="#"><img src="./images/毛衣.jpg" alt=""></a></div>
            <div><a href="#"><img src="./images/棉服.jpg" alt=""></a></div>
            <div><a href="#"><img src="./images/女裤.jpg" alt=""></a></div>
            <div><a href="#"><img src="./images/羽绒服.jpg" alt=""></a></div>
            <div><a href="#"><img src="./images/牛仔裤.jpg" alt=""></a></div>
        </div>
    </div>
    <script>
        $(function () {
            $('#left li').mouseover(function () {
                // 获取鼠标经过的小li的索引号
                var index = $(this).index();
                // console.log(index);
                // 隐藏其他兄弟 让索引图片显示
                $('#content div').eq(index).show();
                $('#content div').eq(index).siblings().hide();
                // 链式编程
                // $('#content div').eq(index).show().siblings().hide();
            })
        })
    </script>
</body>

</html>

file:///G:/%E5%AD%A6%E4%B9%A0/WEB%E5%89%8D%E7%AB%AF/%E9%BB%91%E9%A9%AC%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/%E6%A1%88%E4%BE%8B/demo25/%E6%B7%98%E5%AE%9D%E6%9C%8D%E9%A5%B0%E7%B2%BE%E5%93%81%E6%A1%88%E4%BE%8B.html#

二、jQuery样式操作

1.操作CSS方法

jQuery可以使用CSS方法来修改简单的元素样式,也可以操作类,修改多个样式。

  1. 返回属性值

    $(this).css('color');
    
  2. 修改单一属性值

    $(this).css('color', 'red');
    $('div').css('width', '300px');
    $('div').css('width', 300);	// 值是数字可以不跟单位和引号
    
  3. 以对象的形式设置多组样式

    $(this).css({'color':'white','font-size':'20px'});
    
    $('div').css({
        width: 400,
        height: 400,
        backgroundColor: 'red'	// 复合属性采取驼峰命名法
    });	// 采取对象形式时 属性名可以不加引号
    

2.设置类样式方法

作用等同于以前的classList,可以 类样式。

  1. 添加类

    $('div').addClass('current');
    
  2. 删除类

    $('div').removeClass('current');
    
  3. 切换类

    $('div').toggleClass('current');	// 存在则取消 不存在则添加
    
2.1 案例:tab栏切换
<!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>tab栏切换布局分析</title>
    <script src="jquery.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        li {
            list-style: none;
        }

        .tab {
            width: 978px;
            margin: 100px auto;
        }

        .tab_list {
            height: 39px;
            border: 1px solid #ccc;
            background-color: #f1f1f1;
        }

        .tab_list li {
            float: left;
            height: 39px;
            line-height: 39px;
            padding: 0 20px;
        }

        /* 被选中的tab栏 */
        .tab_list .current {
            background-color: #c81623;
            color: #fff;
        }

        .item {
            display: none;
        }
    </style>
</head>

<body>
    <div class="tab">
        <div class="tab_list">
            <ul>
                <li class="current">商品介绍</li>
                <li>规格与包装</li>
                <li>售后保障</li>
                <li>商品评价</li>
                <li>手机社区</li>
            </ul>
        </div>
        <div class="tab_con">
            <div class="item" style="display:block">商品介绍模块内容</div>
            <div class="item">规格与包装模块内容</div>
            <div class="item">售后保障模块内容</div>
            <div class="item">商品评价模块内容</div>
            <div class="item">手机社区模块内容</div>
        </div>
    </div>
    <script>
        $('.tab_list li').click(function () {
            $(this).addClass('current').siblings().removeClass('current');
            // console.log($(this).index());
            var index = $(this).index();
            // $('.tab_con .item').eq(index).css('display', 'block').siblings().css('display', 'none');
            $('.tab_con .item').eq(index).show().siblings().hide();
        })
    </script>
</body>

</html>

file:///G:/%E5%AD%A6%E4%B9%A0/WEB%E5%89%8D%E7%AB%AF/%E9%BB%91%E9%A9%AC%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/%E6%A1%88%E4%BE%8B/demo25/tab%E6%A0%8F%E5%88%87%E6%8D%A2.html

2.2 案例:购物车选中商品添加背景颜色
// 全选
$('.checkall').change(function () {
    // console.log($(this).prop('checked'));
    $('.j-checkbox').prop('checked', $(this).prop('checked'));

    // 选中商品添加背景
    if ($(this).prop('checked')) {
        // 为所有购物车商品添加背景
        $('.cart-item').addClass('check-cart-item');
    } else {
        $('.cart-item').removeClass('check-cart-item');
    }

    getSum();
})
$('.j-checkbox').change(function () {
    // 复选框个数
    // console.log($('.j-checkbox').length);
    // 被选中的复选框个数
    // console.log($('.j-checkbox:checked').length);

    if ($('.j-checkbox:checked').length === $('.j-checkbox').length) {
        $('.checkall').prop('checked', true);
    } else {
        $('.checkall').prop('checked', false);
    }

    // 选中商品添加背景
    if ($(this).prop('checked')) {
        // 为当前选中的购物车商品添加背景
        $(this).parents('.cart-item').addClass('check-cart-item');
    } else {
        $(this).parents('.cart-item').removeClass('check-cart-item');
    }

    getSum();

})

file:///G:/%E5%AD%A6%E4%B9%A0/WEB%E5%89%8D%E7%AB%AF/%E9%BB%91%E9%A9%AC%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/%E6%A1%88%E4%BE%8B/demo25/02-%E8%B4%AD%E7%89%A9%E8%BD%A6/index.html

三、jQuery效果

jQuery为我们封装了许多动画效果,常见如下:

  1. 显示隐藏:show()hide()、toggle()
  2. 滑动:slideDown()、slideUp()、slideToggle()
  3. 淡入淡出:fadeIn()、fadeOut()、fadeToggle()、fadeTo()
  4. 自定义动画:animate()

1.显示隐藏效果

  1. 显示

    show([speed,[easing],[fn]]);
    
    • speed:三种预定速度之一的字符串(‘slow’, ‘normal’, ‘fast’)或表示动画时长的毫秒数值(如:1000);
    • easing:用来指定切换效果,默认为’swing’,可用参数’linear’;
    • fn:回调函数,在动画完成时执行函数,每个元素执行一次。
  2. 隐藏

    hide([speed,[easing],[fn]]);
    
    • speed:三种预定速度之一的字符串(‘slow’, ‘normal’, ‘fast’)或表示动画时长的毫秒数值(如:1000);
    • easing:用来指定切换效果,默认为’swing’,可用参数’linear’;
    • fn:回调函数,在动画完成时执行函数,每个元素执行一次。
  3. 切换

    toggle([speed,[easing],[fn]]);
    
    • speed:三种预定速度之一的字符串(‘slow’, ‘normal’, ‘fast’)或表示动画时长的毫秒数值(如:1000);
    • easing:用来指定切换效果,默认为’swing’,可用参数’linear’;
    • fn:回调函数,在动画完成时执行函数,每个元素执行一次。

2.滑动效果

  1. 下拉滑动

    slideDown([speed,[easing],[fn]]);
    
    • speed:三种预定速度之一的字符串(‘slow’, ‘normal’, ‘fast’)或表示动画时长的毫秒数值(如:1000);
    • easing:用来指定切换效果,默认为’swing’,可用参数’linear’;
    • fn:回调函数,在动画完成时执行函数,每个元素执行一次。
  2. 上拉滑动

    slideUp([speed,[easing],[fn]]);
    
    • speed:三种预定速度之一的字符串(‘slow’, ‘normal’, ‘fast’)或表示动画时长的毫秒数值(如:1000);
    • easing:用来指定切换效果,默认为’swing’,可用参数’linear’;
    • fn:回调函数,在动画完成时执行函数,每个元素执行一次。
  3. 滑动切换

    slideToggle([speed,[easing],[fn]]);
    
    • speed:三种预定速度之一的字符串(‘slow’, ‘normal’, ‘fast’)或表示动画时长的毫秒数值(如:1000);
    • easing:用来指定切换效果,默认为’swing’,可用参数’linear’;
    • fn:回调函数,在动画完成时执行函数,每个元素执行一次。

3.事件切换

hover([over,]out);
  • over:鼠标移动到元素上时触发的函数(相当于mouseenter);
  • out:鼠标溢出元素时要触发的函数(相当于mouseleave)。
$('.nav>li').hover(function () {
    $(this).children('ul').slideDown(200);
}, function () {
    $(this).children('ul').slideUp(200);
})
  • 若只写一个函数,那么鼠标在经过及离开的时候都会触发这个函数。
$('.nav>li').hover(function () {
    $(this).children('ul').slideToggle(200);
})

4.动画队列

  1. 动画或效果队列

    动画或者效果一旦触发就会执行,若多次触发,就会造成多个动画或效果排队执行。

  2. 停止排队

    stop();
    
    • stop()方法用于停止动画或效果;
    • 注意:stop()写到动画或者效果的前面,相当于停止结束上一次的动画。

5.淡入淡出效果

  1. 淡入效果

    fadeIn([speed,[easing],[fn]]);
    
    • speed:三种预定速度之一的字符串(‘slow’, ‘normal’, ‘fast’)或表示动画时长的毫秒数值(如:1000);
    • easing:用来指定切换效果,默认为’swing’,可用参数’linear’;
    • fn:回调函数,在动画完成时执行函数,每个元素执行一次。
  2. 淡出效果

    fadeOut([speed,[easing],[fn]]);
    
    • speed:三种预定速度之一的字符串(‘slow’, ‘normal’, ‘fast’)或表示动画时长的毫秒数值(如:1000);
    • easing:用来指定切换效果,默认为’swing’,可用参数’linear’;
    • fn:回调函数,在动画完成时执行函数,每个元素执行一次。
  3. 淡入淡出切换

    fadeToggle([speed,[easing],[fn]]);
    
    • speed:三种预定速度之一的字符串(‘slow’, ‘normal’, ‘fast’)或表示动画时长的毫秒数值(如:1000);
    • easing:用来指定切换效果,默认为’swing’,可用参数’linear’;
    • fn:回调函数,在动画完成时执行函数,每个元素执行一次。
  4. 调整透明度

    fadeTo(speed,opacity,[easing],[fn]);
    
    • opacity:透明度,必须写,0~1之间(必写);
    • speed:三种预定速度之一的字符串(‘slow’, ‘normal’, ‘fast’)或表示动画时长的毫秒数值(如:1000)(必写);
    • easing:用来指定切换效果,默认为’swing’,可用参数’linear’;
    • fn:回调函数,在动画完成时执行函数,每个元素执行一次。
5.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>
    <script src="jquery.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        body {
            background-color: black;
        }

        ul {
            list-style: none;
        }

        .wrap {
            width: 630px;
            height: 394px;
            background-color: black;
            padding: 10px 0 0 10px;
            border: 1px solid #fff;
            margin: 100px auto;
        }

        .wrap ul li {
            float: left;
            margin: 0 10px 10px 0;
        }

        .wrap li a {
            display: block;
            width: 100%;
        }
    </style>
</head>

<body>
    <div class="wrap">
        <ul>
            <li><a href="#"><img src="images/01.jpg" alt=""></a></li>
            <li><a href="#"><img src="images/02.jpg" alt=""></a></li>
            <li><a href="#"><img src="images/03.jpg" alt=""></a></li>
            <li><a href="#"><img src="images/04.jpg" alt=""></a></li>
            <li><a href="#"><img src="images/05.jpg" alt=""></a></li>
            <li><a href="#"><img src="images/06.jpg" alt=""></a></li>
        </ul>
    </div>
    <script>
        $('.wrap li').hover(function () {
            $(this).siblings().stop().fadeTo(400, 0.5);
        }, function () {
            $(this).siblings().stop().fadeTo(400, 1);
        })
    </script>
</body>

</html>

file:///G:/%E5%AD%A6%E4%B9%A0/WEB%E5%89%8D%E7%AB%AF/%E9%BB%91%E9%A9%AC%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/%E6%A1%88%E4%BE%8B/demo25/%E7%AA%81%E5%87%BA%E6%98%BE%E7%A4%BA.html#

6.自定义动画 animate

animate(params,[speed],[easing],[fn]);
  • paramas:想要更改的样式属性,以对象形式传递,必写。属性名可以不用带引号,如果是复合属性则需要采取驼峰命名法。其余参数都可以省略;
  • speed:三种预定速度之一的字符串(‘slow’, ‘normal’, ‘fast’)或表示动画时长的毫秒数值(如:1000)(必写);
  • easing:用来指定切换效果,默认为**‘swing’(在开头/结尾移动慢,在中间移动快),可用参数’linear’(匀速移动)**;
  • fn:回调函数,在动画完成时执行函数,每个元素执行一次。
<!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>
    <script src="jquery.min.js"></script>
    <style>
        div {
            position: absolute;
            width: 100px;
            height: 100px;
            background-color: pink;
        }
    </style>
</head>

<body>
    <button>动起来</button>
    <div></div>
    <script>
        $(function () {
            $('button').click(function () {
                $('div').animate({
                    left: 500
                }, 1000, 'linear')
            })
        })
    </script>
</body>

</html>
6.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>
    <script src="jquery.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        a {
            text-decoration: none;
        }

        ul {
            list-style: none;
        }

        .king {
            width: 852px;
            margin: 100px auto;
            background: url(images/bg.png) no-repeat;
            /* overflow: hidden; */
            padding: 10px;
        }

        .king ul {
            overflow: hidden;
        }

        .king li {
            position: relative;
            float: left;
            width: 69px;
            height: 69px;
            margin-right: 10px;
        }

        .king .current {
            width: 224px;
        }

        .king img {
            display: block;
        }

        .king .big {
            display: none;
            width: 224px;
        }

        .king .small {
            position: absolute;
            top: 0;
            left: 0;
            width: 69px;
            height: 69px;
            border-radius: 5px;
        }

        .king .current .small {
            display: none;
        }

        .king .current .big {
            display: block;
        }
    </style>
</head>

<body>
    <div class="king">
        <ul>
            <li class="current">
                <a href="#">
                    <img src="images/m1.jpg" alt="" class="small">
                    <img src="images/m.png" alt="" class="big">
                </a>
            </li>
            <li>
                <a href="#">
                    <img src="images/l1.jpg" alt="" class="small">
                    <img src="images/l.png" alt="" class="big">
                </a>
            </li>
            <li>
                <a href="#">
                    <img src="images/c1.jpg" alt="" class="small">
                    <img src="images/c.png" alt="" class="big">
                </a>
            </li>
            <li>
                <a href="#">
                    <img src="images/w1.jpg" alt="" class="small">
                    <img src="images/w.png" alt="" class="big">
                </a>
            </li>
            <li>
                <a href="#">
                    <img src="images/z1.jpg" alt="" class="small">
                    <img src="images/z.png" alt="" class="big">
                </a>
            </li>
            <li>
                <a href="#">
                    <img src="images/h1.jpg" alt="" class="small">
                    <img src="images/h.png" alt="" class="big">
                </a>
            </li>
            <li>
                <a href="#">
                    <img src="images/t1.jpg" alt="" class="small">
                    <img src="images/t.png" alt="" class="big">
                </a>
            </li>
        </ul>
    </div>
    <script>
        $(function () {
            $('.king li').mouseenter(function () {
                // 当前li 宽度变为224px 小图片淡出 大图片淡入
                $(this).stop().animate({
                    width: 224
                }).find('.small').stop().fadeOut().siblings('.big').stop().fadeIn();
                // 当前li的兄弟 宽度变为96px 小图片淡入 大图片淡出
                $(this).siblings().stop().animate({
                    width: 69
                }).find('.small').stop().fadeIn().siblings('.big').stop().fadeOut();
            })
        })
    </script>
</body>

</html>

file:///G:/%E5%AD%A6%E4%B9%A0/WEB%E5%89%8D%E7%AB%AF/%E9%BB%91%E9%A9%AC%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/%E6%A1%88%E4%BE%8B/demo25/%E7%8E%8B%E8%80%85%E8%8D%A3%E8%80%80%E6%89%8B%E9%A3%8E%E7%90%B4.html

四、jQuery属性操作

1.设置或获取元素固有属性值 prop()

所谓元素固有属性就是元素本身自带的属性,比如元素里面的href,比如元素里面的type。

// 获取属性
prop('属性')

// 设置属性
prop('属性', '属性值')
1.1 案例:购物车全选
// 全选
$('.checkall').change(function () {
    // console.log($(this).prop('checked'));
    $('.j-checkbox').prop('checked', $(this).prop('checked'));
})
$('.j-checkbox').change(function () {
    // 复选框个数
    // console.log($('.j-checkbox').length);
    // 被选中的复选框个数
    // console.log($('.j-checkbox:checked').length);

    if ($('.j-checkbox:checked').length === $('.j-checkbox').length) {
        $('.checkall').prop('checked', true);
    } else {
        $('.checkall').prop('checked', false);
    }
})

file:///G:/%E5%AD%A6%E4%B9%A0/WEB%E5%89%8D%E7%AB%AF/%E9%BB%91%E9%A9%AC%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/%E6%A1%88%E4%BE%8B/demo25/02-%E8%B4%AD%E7%89%A9%E8%BD%A6/index.html

2.设置或获取元素自定义属性值 attr()

// 获取属性(类似于原生getAttribute())
attr('属性')

// 设置属性(类似于原生setAttribute())
attr('属性', '属性值')

3.数据缓存 data()

data()方法可以在指定的元素上存取数据,并不会修改DOM元素结构。一旦页面刷新,之前存放的数据都将被移除。

// 附加数据
data('name', 'value')

// 获取数据
data('name')
$('span').data('uname', 'andy');	// 数据存放在元素的内存里面

// 获取H5自定义属性
// <div data-index='2'></div>
console.log($('div').data('index'));

五、jQuery内容文本值

1.普通元素内容 html()

相当于原生的innerHTML

// 获取元素内容
html()

// 设置元素内容
html('内容')

2.普通元素文本内容 text()

相当于原生的innerText,只获取文字,忽略其中的标签。

// 获取元素的文本内容
text()

// 设置元素的文本内容
text('文本内容')

3.表单的值 val()

相当于原生的value

// 获取表单的值
val()

// 设置表单的值
val('内容')
3.1 案例:购物车增减商品数量及修改商品小计
// 增减商品数量
// +
$('.increment').click(function () {
    // 当前商品已选择的数量
    var num = $(this).siblings('.itxt').val();
    num++;
    // 赋值给文本框
    $(this).siblings('.itxt').val(num);

    // 修改商品小计
    var price = $(this).parents('.p-num').siblings('.p-price').text().substr(1); // 单价 去掉开头的¥符号
    var totalPrice = (price * num).toFixed(2); // 总价  // toFixed(2) 保留2位小数
    $(this).parents('.p-num').siblings('.p-sum').text('¥' + totalPrice);
})
// -
$('.decrement').click(function () {
    var num = $(this).siblings('.itxt').val();
    if (num == 1) {
        return false; // 后面代码不必再执行
    }
    num--;
    $(this).siblings('.itxt').val(num);

    var price = $(this).parents('.p-num').siblings('.p-price').text().substr(1);
    var totalPrice = (price * num).toFixed(2);
    $(this).parents('.p-num').siblings('.p-sum').text('¥' + totalPrice);
})
// 用户直接修改文本框的值
$('.itxt').change(function () {
    var num = $(this).val();
    num = positiveInteger(num); // 限制输入为正整数
    // 修改文本框
    $(this).val(num);
    var price = $(this).parents('.p-num').siblings('.p-price').text().substr(1);
    var totalPrice = (price * num).toFixed(2);
    // 修改小计
    $(this).parents('.p-num').siblings('.p-sum').text('¥' + totalPrice);

})

// 正整数
function positiveInteger(value) {
    value = value.replace(/[^\d]/g, '');
    if ('' != value) {
        value = parseInt(value);
    }
    return value;
}

file:///G:/%E5%AD%A6%E4%B9%A0/WEB%E5%89%8D%E7%AB%AF/%E9%BB%91%E9%A9%AC%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/%E6%A1%88%E4%BE%8B/demo25/02-%E8%B4%AD%E7%89%A9%E8%BD%A6/index.html

六、jQuery元素操作

1.遍历元素

jQuery隐式迭代是对同一类元素做同样的操作,若我们需要给同一类元素做不同的操作,就需要用到遍历

  1. 语法1:

    $('div').each(function(index, domEle) {
    	...;
    })
    
    • each()方法遍历匹配的每一个元素,用于遍历DOM对象
    • index:元素的索引号;
    • domEle:每个DOM元素对象
    $(function() {
    	var arr = ['red', 'green', 'blue'];
    	$('div').each(function(index, domEle) {
    		$(domEle).css('color', arr[index]);
    	})
    })
    
  2. 语法2:

    $.each(object, function (index, element) {
    	...;
    })
    
    • $.each()方法可用于遍历任何对象。主要用于数据处理,如数组、对象;
    • index:元素的索引号;
    • element:遍历内容。
    $(function() {
    	var arr = ['red', 'green', 'blue'];
    	$.each(arr, function(i, ele) {
    		console.log(i);
    		console.log(ele);
    	})
    })
    
1.1 案例:购物车计算总件数和总额
// 计算总件数和总额
function getSum() {
    var count = 0; // 总件数
    var money = 0;
    // 遍历所有被勾选的商品条目
    $('.j-checkbox:checked').each(function (index, domEle) {
        count += parseInt($(this).parent().siblings().find('.itxt').val());
        money += parseFloat($(this).parent().siblings('.p-sum').text().substr(1));
    })
    var totalMoney = money.toFixed(2); // 总额
    // 修改勾选件数
    $('.amount-sum em').text(count);
    // 修改勾选总额
    $('.price-sum em').text('¥' + totalMoney);
}

2.创建元素

$('<li></li>');

var li = $('<li></li>');

3.添加元素

  1. 内部添加(父子)

    element.append('内容');
    

    把内容放到匹配元素内部的最后面,类似原生中的appendChild。

  2. 外部添加(兄弟)

    element.after('内容');	// 把内容放到目标元素后
    element.before('内容');	// 把内容放到目标元素前
    

4.删除元素

element.remove();	// 删除匹配的元素(本身)
element.empty();	// 删除匹配的元素里面的子节点
element.html('');	// 清空匹配元素的内容
4.1 案例:购物车删除商品
// 删除商品
$('.p-action a').click(function () {
    $(this).parents('.cart-item').remove();
    getSum();
})
// 删除选中商品
$('.remove-batch').click(function () {
    $('.j-checkbox:checked').parents('.cart-item').remove();
    getSum();

})
// 清理购物车
$('.clear-all').click(function () {
    $('.cart-item').remove();
    getSum();

})

七、jQuery尺寸、位置操作

1.jQuery尺寸

方法说明
width() / height()取得匹配元素宽度和高度值,只算width / height
innerWidth() / innerHeight()取得匹配元素宽度和高度值,包含padding
outerWidth() / outerHeight()取得匹配元素宽度和高度值,包含padding、border
outerWidth(true) / outerHeight(true)取得匹配元素宽度和高度值,包含padding、border、margin
  • 参数为空:获取相应值,返回的是数字型;
  • 参数为数字:修改相应值;
  • 参数可以不必填写单位

2.jQuery位置

  1. offset() 设置或获取元素偏移

    offset()方法设置或返回被选中元素相对于文档的偏移坐标,跟父级没关系。

    console.log($('div').offset());
    console.log($('div').offset().top);	// 获取距离文档顶部的距离
    console.log($('div').offset().left);	// 获取距离文档左侧的距离
    
    // 修改
    $('div').offset({
        top: 200,
        left: 200
    });
    
  2. position() 获取元素偏移

    position()方法用于返回被选元素相对于带有定位的父级偏移坐标,如果父级都没有定位,则以文档为准。

    只能用于获取,不能设置。

    console.log($('div').position());
    
  3. scrollTop / scrollLeft() 设置或获取元素被卷去的头部和左侧

    scrollTop()方法设置或返回被选元素被卷去的头部

    scrollLeft()方法设置或返回被选元素被卷去的左侧

    // 页面滚动事件
    $(window).scroll(function() {
        console.log($(document).scrollTop());	// 获取页面被卷去头部
    })
    
    // 返回顶部
    $(document).scrollTop(0);
    
2.1 案例:jQuery返回顶部
<!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>
    <script src="jquery.min.js"></script>
    <style>
        .w {
            width: 1200px;
            margin: 10px auto;
        }

        .slider-bar {
            position: absolute;
            top: 300px;
            left: 50%;
            margin-left: 600px;
            width: 45px;
            height: 130px;
            background-color: pink;

        }

        span {
            position: absolute;
            bottom: 0;
            display: none;
            cursor: pointer;
        }

        .header {
            height: 150px;
            background-color: skyblue;
        }

        .banner {
            height: 250px;
            background-color: steelblue;
        }

        .main {
            height: 1000px;
            background-color: teal;
        }
    </style>
</head>

<body>
    <div class="slider-bar">
        <span class="goBack">返回顶部</span>
    </div>
    <div class="header w">头部区域</div>
    <div class="banner w">banner区域</div>
    <div class="main w">主体区域</div>
    <script>
        $(function () {
            var bannerTop = $('.banner').offset().top;
            var mainTop = $('.main').offset().top;
            var sliderBarTop = $('.slider-bar').offset().top - bannerTop;
            $(window).scroll(function () {
                // console.log($(document).scrollTop());
                if ($(document).scrollTop() >= bannerTop) {
                    $('.slider-bar').css({
                        position: 'fixed',
                        top: sliderBarTop
                    });
                } else {
                    $('.slider-bar').css({
                        position: 'absolute',
                        top: 300
                    });
                }
                if ($(document).scrollTop() >= mainTop) {
                    $('.goBack').fadeIn();
                } else {
                    $('.goBack').fadeOut();
                }
            })
            // 返回顶部
            $('.goBack').click(function () {
                // 使用animate动画返回顶部
                // animate动画函数scrollTop属性
                $('body,html').animate({	// 元素做动画
                    scrollTop: 0
                });
            })
        })
    </script>
</body>

</html>
2.2 案例:品优购电梯导航
.fixedtool {
    display: none;
    position: fixed;
    top: 100px;
    left: 50%;
    margin-left: -676px;
    width: 66px;
    background-color: #fff;
}

.fixedtool li {
    height: 32px;
    line-height: 32px;
    text-align: center;
    font-size: 12px;
    border-bottom: 1px solid #ccc;
    cursor: pointer;
}

.fixedtool .current {
    background-color: #c81623;
    color: #fff;
}
<!-- 左侧电梯导航 -->
<div class="fixedtool">
    <ul>
        <li class="current">家用电器</li>
        <li>手机通讯</li>
        <li>电脑办公</li>
        <li>精品家具</li>
    </ul>
</div>
$(function () {
    var recomTop = $('.recom').offset().top;
    var flag = true; // 节流阀
    $(window).scroll(function () {
        toggleTool();

        // 页面滚动自动修改左侧导航栏选中(current)
        // each遍历floor区大模块,拿到每个模块元素和索引号
        // 判断条件:被卷去的头部大于等于内容区域每个模块的offset().top
        if (flag) {
            $('.floor .w').each(function (i, ele) {
                if ($(document).scrollTop() >= $(ele).offset().top) {
                    // 利用索引号找到相应的电梯导航li 为其添加current类
                    $('.fixedtool li').eq(i).addClass('current').siblings().removeClass('current');
                }
            })
        }

    })

    $('.fixedtool li').click(function () {
        // 修改背景色
        $(this).addClass('current').siblings().removeClass('current');
        // console.log($(this).index());
        var index = $(this).index();
        var current = $('.floor .w').eq(index).offset().top;
        // 页面动画滚动效果
        $('body,html').stop().animate({
            scrollTop: current
        }, function () {
            flag = true;
        })

        // 当我们点击小li 不需要执行滚动事件中添加类current的操作
        flag = false;
    })

    function toggleTool() {
        if ($(document).scrollTop() >= recomTop) {
            $('.fixedtool').fadeIn();
        } else {
            $('.fixedtool').fadeOut();
        }
    }
})

jQuery事件

一、jQuery事件注册

element.事件(function() {
	...
});

$('div').click(function() {
	// 事件处理程序
})

二、jQuery事件处理

1.on()

1.1 绑定事件

on()方法在匹配元素上绑定一个或多个事件的事件处理函数。

element.on(event,[selector],fn);

$('div').on({
    mouseenter: function() {
        $(this).css('background', 'skyblue');
    },
    click: function() {
        $(this).css('background', 'purple');
    },
    mouseleave: function() {
    	$(this).css('background', 'blue');
	}
})

$('div').on('mouseenter mouseleave', function() {
    $(this).toggleClass('current');
})
  • events:一个或多个用空格分隔的事件类型,如"click"或"keydown";
  • selector:元素的子元素选择器。
1.2 实现事件委派操作

事件委派:把原来加给子元素身上的事件绑定到父元素身上,就是把事件委派给父元素。

$('ul').on('click', 'li', function() {
	alert('helo world');
})	// click绑定在ul身上,但触发对象是ul中的li

在此之前有bind()、live()、delegate()等方法来处理事件绑定或委派事件,新版本请用on替代他们。

1.3 为动态创建的元素绑定事件
$('ol').on('click', 'li', function() {
	alert('hello world');
})	// on可以给未来动态创建的元素绑定事件
var li = '<li></li>';
$('ol').append(li);
1.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>
    <script src="jquery.min.js"></script>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        ul {
            list-style: none;
        }

        a {
            text-decoration: none;
        }

        .box {
            width: 600px;
            /* height: 200px; */
            margin: 100px auto;
            border: 1px solid #000;
            padding: 20px;
            /* text-align: center; */
        }

        .box .txt {
            width: 400px;
            outline: none;
        }

        .box ul li {
            border-bottom: 1px dashed blue;
            display: none;
        }

        .box li a {
            float: right;
        }
    </style>
</head>

<body>
    <div class="box" id="weibo">
        <span>微博发布</span>
        <textarea name="" class="txt" id="" cols="30" rows="10"></textarea>
        <button class="btn">发布</button>
        <ul></ul>
    </div>
    <script>
        $(function () {
            // 发布
            $('.btn').on('click', function () {
                if ($('.txt').val()) {
                    var li = $('<li></li>');
                    li.html($('.txt').val() + "<a href='javascript:;'>删除</a>");
                    $('.txt').val('');
                    $('ul').prepend(li);
                    li.stop().slideDown();
                }
            });

            // 删除
            $('ul').on('click', 'a', function () {
                $(this).parent('li').stop().slideUp(function () {
                    $(this).remove();
                });
            })
        })
    </script>
</body>

</html>

file:///G:/%E5%AD%A6%E4%B9%A0/WEB%E5%89%8D%E7%AB%AF/%E9%BB%91%E9%A9%AC%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/%E6%A1%88%E4%BE%8B/demo25/%E5%BE%AE%E5%8D%9A%E5%8F%91%E5%B8%83.html

2.off()

2.1 解绑事件

off()方法可以移除通过on()方法添加的事件处理程序。

$('div').off();	// 解除div身上的所有事件
$('div').off('click');	// 解除div身上绑定的点击事件
$('ul').off('click', 'li');	// 解绑事件委托

3.one()

如果有的事件只触发一次,可以使用one()来绑定事件。使用与on()类似。

4.trigger()

有些事件我们希望它自动触发,比如轮播图自动播放功能。可以利用定时器自动触发,不必使用鼠标点击。

element.click();	// 第一种简写形式
$('div').click();

element.trigger('type');	// 第二种自动触发模式
$('div').trigger('click');

element.triggerHandler('type');	// 第三种自动触发模式	// 不会触发元素的默认行为
$('div').triggerHandler('click');

三、jQuery事件对象

只要有事件触发,就会有事件对象产生。

element.on(events, [selector], function(event) {
	...
})
  1. 阻止默认行为

    // 1.
    event.preventDefault();
    
    // 2.
    return false;
    
  2. 阻止冒泡

    event.stopPropagation();
    

jQuery其他方法

一、jQuery拷贝对象

在jQuery中,如果想要把某个对象拷贝(合并)给另一个对象使用,可以使用**$.extend()**方法。

$.extend([deep], target, object1, [objectN]);
  • deep:true 深拷贝,false 浅拷贝(默认);
  • target:拷贝到的目标;
  • object1:被拷贝的第一个对象;
  • objectN:被拷贝的第N个对象。
var targetObj = {};
var obj = {
	id: 1,
	name: 'andy'
};
$.extend(targetObj, obj);

注:浅拷贝是把被拷贝的对象复杂数据类型中的地址拷贝给目标对象,修改目标对象会影响背靠背对象深拷贝则是完全克隆(拷贝的对象,而不是地址),修改目标对象不会影响被拷贝的对象

二、多库共存

问题概述:

jQuery使用 作为标识符,随着 j Q u e r y 的流行,其他 j s 库也会用 作为标识符,随着jQuery的流行,其他js库也会用 作为标识符,随着jQuery的流行,其他js库也会用作为标识符,一起使用就会引起冲突。

解决方案:

  1. 把里面的$符号统一改为jQuery,如jQuery(‘div’);

  2. jQuery变量规定新的名称:$.noConflict(),var xx = $.noConflict(); 用户自定义标识符。

    var suibian = jQuery.noConflict();	// 让jQuery释放对$控制权 由用户自己决定
    console.log(suibian('span'));
    

三、jQuery插件

jQuery功能有限,想要更加复杂的特效效果,需要借助jQuery插件完成。

注:插件依赖jQuery,因此使用时需要先引入jQuery文件,再引入插件文件。

1.jQuery插件常用网站

  1. jQuery插件库:http://www.jq22.com/
  2. jQuery之家:http://www.htmleaf.com/

2.jQuery插件使用步骤

  1. 引入相关文件(jQuery文件及插件文件);
  2. 复制相关html、css、js(调用插件)。

四、综合案例:toDoList

image-20220104175645829

image-20220104204713684

<!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>ToDoList——最简单的待办事项列表</title>
    <link rel="stylesheet" href="css/index.css">
    <script src="js/jquery.min.js"></script>
    <script src="js/index.js"></script>
</head>

<body>
    <header>
        <section>
            <label for="title">ToDoList</label>
            <input type="text" id="title" name="title" placeholder="添加ToDo">
        </section>
    </header>
    <section>
        <h2>正在进行<span id="todocount"></span></h2>
        <ol id="todolist" class="demo-box">

        </ol>

        <h2>已经完成<span id="donecount"></span></h2>
        <ul id="donelist">
            <li>
                <input type="checkbox">
                <p>123</p>
                <a href="#"></a>
            </li>
        </ul>
    </section>
    <footer>
        Copyright &copy: 2022 todolist.cn
    </footer>
</body>

</html>
body {
    margin: 0;
    padding: 0;
    font-size: 16px;
    background-color: #cdcdcd;
}

header {
    height: 50px;
    background-color: #333;
}

section {
    margin: 0 auto;
}

label {
    float: left;
    width: 100px;
    line-height: 50px;
    color: #ddd;
    font-size: 24px;
    cursor: pointer;
    font-family: "Helvetica Neue", Arial, Helvetica, sans-serif;
}

header input {
    float: right;
    width: 60%;
    height: 24px;
    margin-top: 12px;
    text-indent: 10px;
    border-radius: 5px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    -ms-border-radius: 5px;
    -o-border-radius: 5px;
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.24), 0 1px 6px rgba(0, 0, 0, 0.45) inset;
    border: none;
    outline: none;
}

h2 {
    position: relative;
}

span {
    position: absolute;
    top: 2px;
    right: 5px;
    display: inline-block;
    height: 20px;
    line-height: 22px;
    text-align: center;
    color: #666;
    font-size: 14px;
    padding: 0 5px;
    border-radius: 20px;
    -webkit-border-radius: 20px;
    -moz-border-radius: 20px;
    -ms-border-radius: 20px;
    -o-border-radius: 20px;
    background-color: #e6e6fa;
    ;
}

ol,
ul {
    padding: 0;
    list-style: none;
}

li {
    position: relative;
    height: 32px;
    line-height: 32px;
    background-color: #fff;
    margin-bottom: 10px;
    padding: 0 45px;
    border-radius: 3px;
    -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
    -ms-border-radius: 3px;
    -o-border-radius: 3px;
    border-left: 5px solid #629a9c;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.07);
}

/* 完成勾选框 */
li input {
    position: absolute;
    top: 2px;
    left: 10px;
    width: 20px;
    height: 20px;
    cursor: pointer;
}

/* 删除按钮 */
li a {
    position: absolute;
    top: 4px;
    right: 5px;
    display: inline-block;
    width: 14px;
    height: 12px;
    border-radius: 14px;
    border: 6px double #FFF;
    background: #CCC;
    line-height: 14px;
    text-align: center;
    color: #FFF;
    font-weight: bold;
    font-size: 14px;
    cursor: pointer;
}

ul li {
    /* 已完成中的li调整透明度 */
    opacity: 0.5;
}

footer {
    color: #666;
    font-size: 14px;
    text-align: center;
}

@media screen and (max-device-width: 620px) {
    section {
        width: 96%;
        padding: 0 2%;
    }
}

@media screen and (min-width: 620px) {
    section {
        width: 600px;
        padding: 0 10px;
    }
}
$(function () {
    load();
    $('#title').on('keydown', function (event) {
        // console.log(event);
        if (event.key == 'Enter' && $(this).val() != '') {
            // 读取本地存储数据
            var local = getData();
            local.push({
                title: $(this).val(),
                done: false
            });
            // 存储到本地存储
            setData(local);
            // 清空输入框
            $(this).val('');
            // 渲染加载list数据
            load();
        }
    })

    // 删除
    $('#todolist, #donelist').on('click', 'a', function () {
        // 获取本地存储
        var data = getData();

        // 修改数据
        var index = $(this).attr('id');
        data.splice(index, 1);
        console.log(data);

        // 保存到本地存储
        setData(data);
        // 重新渲染
        load();
    })

    // 复选框
    $('#todolist, #donelist').on('click', 'input', function () {
        // 获取本地存储数据
        var data = getData();
        // 修改数据
        var index = $(this).siblings('a').attr('id');
        data[index].done = $(this).prop('checked');
        // 保存到本地存储
        setData(data);
        // 重新渲染
        load();
    })

    // 读取本地存取的数据
    function getData() {
        var data = localStorage.getItem('todolist');
        if (data !== null) {
            // 字符串格式转对象格式
            return JSON.parse(data);
        } else {
            return [];
        }
    }

    // 保存本地存储数据
    function setData(data) {
        localStorage.setItem('todolist', JSON.stringify(data));
    }

    // 加载list
    function load() {
        // 读取本地存储数据
        var data = getData();
        var todoCount = 0; // 未完成事项个数
        var doneCount = 0; // 已完成事项个数
        // console.log(data);
        // 加载前先清空
        $('ol, ul').empty();
        $.each(data, function (i, ele) {
            if (ele.done == false) {
                // 未完成
                $('ol').prepend("<li><input type='checkbox'><p>" + ele.title + "</p><a href='javascript:;' id='" + i + "'></a></li>");
                todoCount++;
            } else {
                // 已完成
                $('ul').prepend("<li><input type='checkbox' checked><p>" + ele.title + "</p><a href='javascript:;' id='" + i + "'></a></li>");
                doneCount++;
            }
        })
        $('#todocount').text(todoCount);
        $('#donecount').text(doneCount);
    }
})

file:///G:/%E5%AD%A6%E4%B9%A0/WEB%E5%89%8D%E7%AB%AF/%E9%BB%91%E9%A9%AC%E5%89%8D%E7%AB%AF%E5%9F%BA%E7%A1%80/%E6%A1%88%E4%BE%8B/demo25/toDoList/index.html

数据可视化项目

一、概述

1.目的

借助图形化手段,清晰有效地传达与沟通信息。

2.使用场景

  • 通用报表;
  • 移动端图标;
  • 大屏可视化;
  • 图编辑&图分析;
  • 地理可视化。

3.常见数据可视化库

  • D3.js 目前Web端评价最高的Javascript可视化工具库(入手难);
  • ECharts.js 百度出品的开源JavaScript数据可视化库;
  • Highcharts.js 国外的前端数据可视化库,非商用免费;
  • AntV 蚂蚁金服全新一代数据可视化解决方案……

二、ECharts简介

EChaets是一个使用JavaScript实现的开源可视化库,可以流畅地运行在PC和移动设备上,兼容目前绝大部分的浏览器。底层依赖矢量图形库ZRender。提供直观、交互丰富、可高度个性化定制的数据可视化图表。

官网:https://echarts.apache.org/zh/index.html

三、ECharts基本使用

  1. 下载并引入echarts.js文件
  2. 准备一个具备大小的DOM容器
  3. 初始化echarts实例对象
  4. 指定配置项和数据(option):根据具体需求修改配置选项
  5. 将配置项设置给echarts实例对象
<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <title>ECharts基本使用</title>
    <!-- 引入刚刚下载的 ECharts 文件 -->
    <script src="js/echarts.min.js"></script>
</head>

<body>
    <!-- 为 ECharts 准备一个定义了宽高的 DOM -->
    <div id="main" style="width: 600px;height:400px;"></div>
    <script type="text/javascript">
        // 基于准备好的dom,初始化echarts实例
        var myChart = echarts.init(document.getElementById('main'));

        // 指定图表的配置项和数据
        var option = {
            title: {
                text: 'ECharts 入门示例'
            },
            tooltip: {},
            legend: {
                data: ['销量']
            },
            xAxis: {
                data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
            },
            yAxis: {},
            series: [{
                name: '销量',	// 系列名称 用于tooltip显示legend图例筛选变化
                type: 'bar',	// 图表类型 line 折线 bar 柱形
                data: [5, 20, 36, 10, 10, 20]	// 数据
            }]
        };

        // 使用刚指定的配置项和数据显示图表。
        myChart.setOption(option);
    </script>
</body>

</html>

image-20220106221520612

相关配置说明:

  • title:标题组件
  • tooltip:提示框组件(鼠标经过时提示)
  • legend:图例组件
  • toolbox:工具栏
  • grid:直角坐标系内绘图网格
  • xAxis:直角坐标系grid中的x轴
  • yAxis:直角坐标系grid中的y轴
  • series:系列列表,每个系列通过type决定自己的图表类型
  • color:调色盘颜色列表(数组)

image-20220111210716520

配置项手册:https://echarts.apache.org/zh/option.html#title

面向过程与面向对象

一、面向过程与面向对象

1.面向过程

面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候再一个个依次调用。

2.面向对象

面向对象是把事务分解成一个个对象,然后由对象之间分工与合作。

3.面向过程与面向对象对比

面向过程面向多项
优点性能比面向对象好, 适合跟硬件联系很紧密的东西,例如单片机就采用面向过程编程易维护、易服用、易拓展,由于面向对象有封装、继承、多态性的特性,可以设计出低耦合的系统,使系统更加灵活、易于维护
缺点不易维护、不易复用、不易拓展性能比面向过程差

二、对象与类

1.对象

对象是由属性和方法组成的:是一个无序键值对的集合,指的是一个具体的事物。

  • 属性:事物的特征,在对象中用属性来表示(常用名词);
  • 方法:事物的行为,在对象中用方法来表示(常用动词)。
1.1 创建对象
// 复习
// 字面量创建对象
var ldh = {
	name: '刘德华',
    age: 18
}
console.log(ldh);

// 构造函数创建对象
function Star(name, age) {
    this.name = name;
    this.age = age;
}
var ldh = new Star('刘德华', 18);	// 对象实例化
console.log(ldh);

2.类

2.1 创建类

语法:

// 使用class关键字
class name {
	// class body
}
// 使用定义的类创建实例
var xx = new name();
class Star {
	// 类的共有属性放到constructor构造函数中
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}
}
// 利用类创建对象
var ldh = new Star('刘德华', 18);
console.log(ldh);

2.2 类创建添加属性和方法
// 1. 创建类
class Star {
	// 类的共有属性放到constructor构造函数中
	constructor(name, age) {
		this.name = name;
		this.age = age;
	}
	// 方法与方法之间不需要添加逗号
	sing(song) {
		console.log(this.name + '唱' + song);
	}
}
// 2. 利用类创建对象
var ldh = new Star('刘德华', 18);
console.log(ldh);
ldh.sing('冰雨');	// 刘德华唱冰雨

注意:

  1. 通过class关键字创建类,类名习惯首字母大写;
  2. 类里面的constructor函数,可以接受传递过来的参数,同时返回实例对象;
  3. constructor函数只要new生成实例时就会自动调用,即使我们不写这个函数,类也会自动生成这个函数;
  4. 多个函数方法之间不需要添加逗号分隔。
2.3 类的继承

语法:

// 父类
class Father {
	// ...
}

// 子类
class Son extends Father {
	// ...
}
class Father {
	constructor(surname) {
		this.surname = surname;
	}
	say() {
		console.log('您的姓是' + this.surname);
	}
}

class Son extends Father{
	// 继承父类的属性和方法
}
var damao = new Son('金');
damao.say();	// 您的姓是金

子类用super关键字访问父类的方法:

// 父类
class Father {
	constructor(x, y) {
		this.x = x;
		this.y = y;
	}
	sum() {
		console.log(this.x + this.y);
	}
}
// 子类继承父类
class Son extends Father {
	constructor(x, y) {
		super(x, y);	// 使用super调用父类的构造函数
	}
}
var son = new Son(1, 2);
son.sum();	// 3

注意:

  1. 继承中,若实例化子类输出一个方法,先看子类存不存在该方法,若有就先执行子类的方法,若无,就去父类中查找该方法(就近原则);

  2. 若子类想要继承父类的方法,同时在自己内部脱战自己的方法,就利用super调用父类的构造函数(super必须在子类this之前调用);

    // 父类有加法方法
    class Father {
    	constructor(x, y) {
    		this.x = x;
    		this.y = y;
    	}
    	sum() {
    		console.log(this.x + this.y);
    	}
    }
    // 子类继承父类加法方法,同时扩展减法方法
    class Son extends Father {
    	constructor(x, y) {
    		super(x, y);
    		this.x = x;
    		this.y = y;
    	}
    	substract() {
    		console.log(this.x - this.y);
    	}
    }
    var son = new Son(5, 3);
    son.substract();	// 2
    son.sum();	// 8
    
  3. 时刻注意this的指向问题,类里面的共有的属性和方法一定要加this使用;

    • constructor中的this指向的是new出来的实例对象
    • 自定义的方法,一般也指向的new出来的实例对象
    • 绑定事件之后this指向的就是触发事件的事件源
  4. 在ES6中类没有变量提升,所以必须先定义类,才能通过类实例化对象

3.面向对象版tab栏切换

3.1 insertAdjacentHTML
element.insertAdjacentHTML(position, text);
  • position是相对于元素的位置,必须是以下字符串之一:

    beforebegin:元素自身的前面

    afterbegin:插入元素内部的第一个子节点之前;

    beforeend:插入元素内部的最后一个子节点之后;

    afterend:元素自身的后面。

  • 以前的做法:动态创建元素creatElement,innerHTML赋值,在appendChild追加到父元素里面。

  • 现在的高级做法:利用innerAdjacentHTML()直接把字符串格式元素添加到父元素中。

  • appendChild不支持追加字符串的子元素,insertAdjacentHTML支持追加字符串的元素。

3.2 实现
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>面向对象 Tab</title>
    <link rel="stylesheet" href="./styles/tab.css">
    <link rel="stylesheet" href="./styles/style.css">
</head>

<body>

    <main>
        <h4>
            Js 面向对象 动态添加标签页
        </h4>
        <div class="tabsbox" id="tab">
            <!-- tab 标签 -->
            <nav class="fisrstnav">
                <ul>
                    <li class="liactive"><span>测试1</span><span class="iconfont icon-guanbi"></span></li>
                    <li><span>测试2</span><span class="iconfont icon-guanbi"></span></li>
                    <li><span>测试3</span><span class="iconfont icon-guanbi"></span></li>
                </ul>
                <div class="tabadd">
                    <span>+</span>
                </div>
            </nav>

            <!-- tab 内容 -->
            <div class="tabscon">
                <section class="conactive">测试1</section>
                <section>测试2</section>
                <section>测试3</section>
            </div>
        </div>
    </main>

    <script src="js/tab.js"></script>
</body>

</html>
* {
    margin: 0;
    padding: 0;
}

ul li {
    list-style: none;
}

main {
    width: 960px;
    height: 500px;
    border-radius: 10px;
    margin: 50px auto;
}

main h4 {
    height: 100px;
    line-height: 100px;
    text-align: center;
}

.tabsbox {
    width: 900px;
    margin: 0 auto;
    height: 400px;
    border: 1px solid lightsalmon;
    position: relative;
}

nav ul {
    overflow: hidden;
}

nav ul li {
    float: left;
    width: 100px;
    height: 50px;
    line-height: 50px;
    text-align: center;
    border-right: 1px solid #ccc;
    position: relative;
}

nav ul li.liactive {
    border-bottom: 2px solid #fff;
    z-index: 9;
}

#tab input {
    width: 80%;
    height: 60%;
}

nav ul li span:last-child {
    position: absolute;
    user-select: none;
    font-size: 12px;
    top: -18px;
    right: 0;
    display: inline-block;
    height: 20px;
}

.tabadd {
    position: absolute;
    /* width: 100px; */
    top: 0;
    right: 0;
}

.tabadd span {
    display: block;
    width: 20px;
    height: 20px;
    line-height: 20px;
    text-align: center;
    border: 1px solid #ccc;
    float: right;
    margin: 10px;
    user-select: none;
}

.tabscon {
    width: 100%;
    height: 300px;
    position: absolute;
    padding: 30px;
    top: 50px;
    left: 0px;
    box-sizing: border-box;
    border-top: 1px solid #ccc;
}

.tabscon section,
.tabscon section.conactive {
    display: none;
    width: 100%;
    height: 100%;
}

.tabscon section.conactive {
    display: block;
}
var that;
class Tab {
    constructor(id) {
        that = this;
        // 获取元素
        this.main = document.querySelector(id);
        this.ul = this.main.querySelector('.firstnav ul');
        this.tabscon = this.main.querySelector('.tabscon');
        this.add = this.main.querySelector('.tabadd');
        this.init();
    }
    // 初始化
    init() {
        this.updateNode();
        // 添加绑定事件
        for (var i = 0; i < this.lis.length; i++) {
            this.lis[i].index = i; // 索引号
            this.lis[i].onclick = this.toggleTab;
            this.remove[i].onclick = this.removeTab;
            this.spans[i].ondblclick = this.editTab;
            this.sections[i].ondblclick = this.editTab;
        }
        this.add.onclick = this.addTab;
    }
    // 更新
    updateNode() {
        this.lis = this.main.querySelectorAll('li');
        this.sections = this.main.querySelectorAll('section');
        this.remove = this.main.querySelectorAll('.icon-guanbi');
        this.spans = this.main.querySelectorAll('.firstnav li span:first-child');

    }
    // 清除所有li和section的类
    clearClass() {
        for (var i = 0; i < this.lis.length; i++) {
            this.lis[i].className = '';
            this.sections[i].className = '';
        }
    }
    // 切换
    toggleTab() {
        that.clearClass();
        this.className = 'liactive';
        that.sections[this.index].className = 'conactive';
    }
    // 添加
    addTab() {
        that.clearClass();
        // insertAdjacentHTML() 直接把字符串格式元素添加到父元素中
        var li = '<li class="liactive"><span>新选项卡</span><span class="iconfont icon-guanbi"></span></li>'
        var section = '<section class="conactive">新选项卡</section>';
        that.ul.insertAdjacentHTML('beforeend', li);
        that.tabscon.insertAdjacentHTML('beforeend', section);
        that.init();
    }
    // 删除
    removeTab(e) {
        // 阻止冒泡 防止触发tab切换
        e.stopPropagation();
        var index = this.parentNode.index;
        // console.log(index);
        that.lis[index].remove();
        that.sections[index].remove();
        that.init();
        // 当删除的不是选中状态的tab时 选中状态不改变
        if (document.querySelector('.liactive')) {
            return;
        } else {
            // 当删除的是选中状态的tab时 自动显示前一个tab
            index--;
            that.lis[index] && that.lis[index].click();
        }
    }
    // 修改
    editTab() {
        var str = this.innerHTML;
        // 禁止选中文字
        window.getSelection ? window.getSelection().removeAllRanges() : document.getSelection.empty();
        // 生成文本框
        this.innerHTML = '<input type="text" />'
        var input = this.children[0];
        input.value = str;
        input.select(); // 使文本框的文字处于选定状态
        // 当我们离开文本框(失去焦点)/按下回车 将文本框的值赋给span
        input.onblur = function () {
            this.parentNode.innerHTML = this.value;
        }
        input.onkeyup = function (e) {
            if (e.key == 'Enter') {
                this.blur(); // 不用加on
            }
        }
    }

}
new Tab('#tab');

http://localhost:8080/demo27/index.html

三、私有属性

class Person {
    // 公有属性
    name;

    // 私有属性
    #age;
    #weight;

    // 构造方法
    constructor(name, age, weight) {
        this.name = name;
        this.#age = age;
        this.#weight = weight;
    }
}

// 实例化
const girl = new Person('小红', 18, '45kg')
console.log(girl)

console.log(girl.name)
console.log(girl.#age)	// 报错

image-20230202111155809

访问私有属性:

class Person {
    // 公有属性
    name;

    // 私有属性
    #age;
    #weight;

    // 构造方法
    constructor(name, age, weight) {
        this.name = name;
        this.#age = age;
        this.#weight = weight;
    }

    // 访问私有属性
    intro() {
        console.log(this.#age)
    }
}

// 实例化
const girl = new Person('小红', 18, '45kg')
// console.log(girl)

// console.log(girl.name)
// console.log(girl.#age)   // 报错
girl.intro()

构造函数和原型

一、构造函数和原型

1.概述

在典型的OOP语言(如Java)中,都存在类的概念。类就是对象的模板,对象就是类的实例。但在ES6之前,JS中并没有引入类的概念。

在ES6之前,对象不是基于类创建的,而是用一种称为构造函数的特殊函数来定义对象和他们的特征。

创建对象三种方式:

  • 对象字面量

    var obj = {};
    
  • new Object()

    var obj = new Object();
    
  • 自定义构造函数

    function Star(uname, age) {
    	this.uname = uname;
    	this.age =age;
    	this.sing = function() {
    		console.log('我会唱歌');
    	}
    }
    var ldh = new Star('刘德华', 18);	// 实例化
    console.log(ldh);
    ldh.sing();
    

2.构造函数

构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,总是与new一起使用。

我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数中。

注意:

  • 构造函数用于创建某一类对象,其首字母要大写;
  • 构造函数要和new一起使用才有意义。

new的执行过程:

  • 在内存中创建一个新的空对象;
  • 让this指向这个新对象;
  • 执行构造函数代码,给新对象添加属性和方法;
  • 返回这个新对象(构造函数中不需要return)。

JavaScript构造函数中可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的this上添加。

  • 静态成员:在构造函数本身上添加的成员称为静态成员,只能由构造函数本身来访问
  • 实例成员:在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象来访问
function Star(uname, age) {
	this.uname = uname;
	this.age =age;
	this.sing = function() {
		console.log('我会唱歌');
	}
}
var ldh = new Star('刘德华', 18);	// 实例化
// uname age sing都是实例成员 只能通过实例化对象来访问
console.log(ldh.uname);
ldh.sing();

Star.sex = '男';	// 静态成员 在构造函数本身上添加的成员
console.log(Star.sex);	// 静态成员只能通过构造函数来访问
// console.log(ldh.sex);	// 错误 不能通过对象来访问

3.构造函数的问题

构造函数存在浪费内存的问题。→ 构造函数原型

image-20220116195209132

同一个方法却开辟了两个不同的存储空间。

4.构造函数原型 prototype

构造函数通过原型分配的函数所有对象所共享的。

JavaScript规定,每一个构造函数都有一个prototype(原型)对象

我们可以把那些不变的方法,直接定义在prototype对象上,这样所有对象的实例就都可以共享这些方法

function Star(uname, age) {
	this.uname = uname;
	this.age =age;
}
Star.prototype.sing = function() {
	console.log('我会唱歌');
}
var ldh = new Star('刘德华', 18);	// 实例化
var zxy = new Star('张学友', 18);
ldh.sing();
zxy.sing();

5.对象原型 __proto__

每个对象都会有一个__proto__属性,指向构造函数的prototype原型对象。正是因为对象有__proto__存在,我们才可以使用构造函数prototype原型对象的属性和方法。

  • __proto__对象原型和原型对象prototype是等价的(前者指向后者);

    console.log(ldh.__proto__ == Star.prototype);	// true
    

    image-20220116201311902

  • __proto__对象原型的意义在于为对象的查找机制提供方向,但它是一个非标准属性,在实际开发中,我们不可以使用该属性,它只是内部指向原型对象prototype。

6.构造函数 constructor

对象原型(__proto__)和构造函数(prototype)原型对象中都有一个constructor属性。constructor我们称为构造函数,因为它指回构造函数本身。

constructor主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。

function Star(uname, age) {
	this.uname = uname;
	this.age =age;
}
//Star.prototype.sing = function() {
//	console.log('我会唱歌');
//}
//Star.prototyep.movie = function() {
//	console.log('我会演电影')
//}
// 对象形式书写 结构更加清晰
// 但覆盖了原来的对象(没有constructor)
Star.prototype = {
    constructor: Star,	// 手动指回原来的构造函数
    sing: function() {
        console.log('我会唱歌');
    },
    movie: function() {
        console.log('我会演电影');
    }
}
var ldh = new Star('刘德华', 18);	// 实例化

7.构造函数、实例、原型对象之间的关系

image-20220116203400930

8.原型链

image-20220116203622053

JavaScript成员查找按照原型链进行:

  • 当访问一个对象的属性(包括方法)时,首先查找对象自身是否拥有该属性;
  • 若没有,则查找它的原型(__proto__指向的prototype原型对象);
  • 若还没有就查找原型对象的原型(原型对象prototype.__proto__,即Object原型对象prototype);
  • 还没有就查找Object原型对象的原型(返回null)。

9.扩展内置对象

可以通过原型对象,对原来的内置对象进行扩展自定义方法。

比如,给数组增加自定义求偶数和的功能。

console.log(Array.prototype);
Array.prototype.sum = function() {
	var sum = 0;
	for (var i = 0; i < this.length; i++) {
		sum += this[i];
	}
	return sum;
}
var arr = [1, 2, 3];
console.log(arr.sum());
var arr1 = new Array(11, 22, 33);
console.log(arr1.sum());

注意:数组和字符串内置对象不能通过给原型对象覆盖的操作进行(Array.prototype= {} ),只能用Array.prototype.xxx = function() {} 的方式来追加扩展。

二、继承

ES6之前没有提供extends继承。

我们可以通过构造函数+原型对象模拟实现继承,称为组合继承

1.call()

调用函数,并且修改函数运行时this的指向。

fun.call(thisArg, arg1, arg2, ...);
  • thisArg:当前调用函数的this的指向对象;
  • arg1,arg2,…:传递的其他参数。

2.借用构造函数继承父类型属性

核心原理:通过call()把父类型的this指向子类型的this,实现子类型继承父类型属性。

// 父构造函数
function Father (uname, age) {
	this.uname = uname;
	this.age = age;
	// this指向父构造函数的实例对象
}
// 子构造函数
function Son (uname, age) {
	// this指向子构造函数的实例对象
	// 借用父构造函数继承父类型属性
	Father.call(this, uname, age);	// 将this指向Son
}

3.借用原型对象继承父类方法

// 父构造函数
function Father (uname, age) {
	this.uname = uname;
	this.age = age;
	// this指向父构造函数的实例对象
}
Father.prototype.money = function() {
    console.log(10000000);
}
// 子构造函数
function Son (uname, age) {
	// this指向子构造函数的实例对象
	// 借用父构造函数继承父类型属性
	Father.call(this, uname, age);	// 将this指向Son
}
// 借用原型对象继承父类方法
//Son.prototype = Father.prototype;	// 这样赋值会有问题 (由于是直接修改地址 当我们给Son的原型对象添加方法时,会影响到Father原型对象)
Son.prototype = new Father();
// 利用对象的形式修改了原型对象 别忘了利用constructor指回原来的构造函数
Son.prototype.constructor = Son;

image-20220116212821091

4.类的本质

ES6之前,通过构造函数+原型来实现面向对象编程,而在ES6中,我们可以通过类实现面向对象编程。

三、ES5中的新增方法

1.数组方法

  1. 迭代(遍历)方法
    1. forEach()

      array.forEach(function(currentValue, index, arr))
      
      • currentValue:数组当前项的值
      • index:数组当前项的索引
      • arr:数组对象本身
    2. map()

    3. filter()

      array.filter(function(currentValue, index, arr))
      

      filter()方法创建一个新数组,新数组中氮元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组

      • currentValue:数组当前项的值
      • index:数组当前项的索引
      • arr:数组对象本身
    4. some()

      array.some(function(currentValue, index, arr))
      

      some()方法用于监测数组中的元素是否满足指定条件,即查找数组中是否存在满足条件的元素返回值为布尔值,若存在,则返回true,反之返回false(找到第一个满足条件的元素就退出循环)。

      • currentValue:数组当前项的值
      • index:数组当前项的索引
      • arr:数组对象本身
    5. every()

2.字符串方法

  1. trim()

    str.trim()
    

    trim()方法会从一个字符串的两端删除空白字符。trim()方法并不影响字符串本身,它返回的是一个新的字符串。

3.对象方法

  1. Object.defineProperty()

    定义对象中新属性或修改原有的属性。

    Object.defineProperty(obj, prop, descriptor)
    
    • obj:必须,目标对象
    • prop:必须,需定义或修改的属性的名字
    • descriptor:必须,目标属性所拥有的的特性

    descriptor说明:以对象形式{}书写

    • value:设置属性的值,默认为undefined
    • writable:值是否可以重写,true | false,默认为false
    • enumerable:目标属性是否可以被枚举,true | false,默认为false(不允许遍历)
    • configurable:目标属性是否可以被删除或是否可以再次修改特性,true | false,默认为false

函数进阶

一、函数的定义和调用

1.函数的定义方式

  1. 自定义函数(命名函数)

    function fn() {
    	...函数体
    };
    
  2. 函数表达式(匿名函数)

    var fun = function() {
    	...函数体
    }
    
  3. 利用new Function(‘参数1’, ‘参数2’, …, ‘函数体’)

    var fn = new Function('参数1', '参数2', ..., '函数体')
    
    • 所有函数都是Function的实例(对象);
    • 函数也属于对象。

    image-20220418155746626

2.函数的调用方式

  1. 普通函数

    function fn() {
    	// 函数体...
    }
    // 调用
    fn();
    fn.call()
    
  2. 对象的方法

    var o = {
    	sayHi: function() {
    		// 函数体...
    	}
    }
    o.sayHi();
    
  3. 构造函数

    function Star() {};
    // 创建实例
    new Star();
    
  4. 绑定事件函数

    btn.onclick = function() {};
    
  5. 定时器函数

    setInterval(function() {},1000);
    
  6. 立即执行函数

    (function() {
    	// 函数体
    })()
    // 立即执行函数将自动调用
    

二、this

this的指向,是当我们调用函数的时候确定的。

调用方式的不同决定了this的指向不同。一般指向我们的调用者

调用方式this指向
普通函数调用window
构造函数调用实例对象,原型对象里面的方法也指向实例对象
对象方法调用该方法所属的对象
事件绑定方法绑定事件的对象
定时器函数window
立即执行函数window

1.改变函数内部的this指向

JavaScript为我们专门提供了一些函数方法来帮我们更优雅地处理函数内部this的指向问题,常用的有bind()、call()、apply()三种。

1.1 call()

call()方法调用一个对象。简单理解为调用函数的方式,它还可以改变函数的this指向。

fun.call(thisArg, arg1, arg2, ...);
var o = {
	name: 'andy'
}

function fn(a, b) {
	console.log(this);	// 指向o
    console.log(a + b);	// 3
};
fn.call(o, 1, 2);

主要应用

// call的主要作用是实现继承
// 核心原谅你:通过call()把父类型的this指向子类型的this,实现子类型继承父类型属性

// 父构造函数
function Father (uname, age) {
	this.uname = uname;
	this.age = age;
	// this指向父构造函数的实例对象
}
// 子构造函数
function Son (uname, age) {
	// this指向子构造函数的实例对象
	// 借用父构造函数继承父类型属性
	Father.call(this, uname, age);	// 将this指向Son
}
1.2 apply()

apply()方法调用一个函数。单理解为调用函数的方式,它还可以改变函数的this指向。

fun.apply(thisArg, [argsArray]);
  • thisArg:在fun函数运行时指定的this值
  • argsArray:传递的值,必须包含在数组里面
  • 返回值就是函数的返回值,因为它就是调用函数
var o = {
	name: 'andy'
}

function fn(arr) {
	console.log(this);	// o
	console.log(arr);	// 'pink'	// 字符串
};
fn.apply(o, ['pink']);	// 参数必须是数组(伪数组)

主要应用

// 利用apply借助数学内置对象求数组最大值
var arr = [1, 66, 3, 99, 4];
var max = Math.max.apply(Math, arr);
console.log(max);
1.3 bind()

bind()方法不会调用函数,但是能改变函数内部的this指向。

fun.bind(thisArg, arg1, arg2, ...);
  • thisArg:在fun函数运行时指定的this值
  • arg1, arg2, …:传递的参数
  • 返回由指定的this值和初始化参数改造的原函数拷贝
var o = {
	name: 'andy'
};
function fn(a, b) {
	console.log(this);
	console.log(a + b);
}
var f = fn.bind(o, 1, 2);
f();	// o	// 3

主要应用

// 若有的函数我们不需要立即调用,但是又想改变这个函数内部的this指向,此时使用bind

var btn = document.querySelector('.btn');
btn.onclick = function() {
    this.disabled = true;
    setTimeout(function() {
        // 如果没有特殊指向,setInterval和setTimeout的回调函数中this的指向都是window,因为js的定时器方法是定义在window下的
        this.disabled = false;  // this指向的是window
    })

    // 赋值变量解决
    var that = this;
    setTimeout(function() {
        that.disabled = false;  // this指向的是调用者btn
    })

    // 利用bind解决
    setTimeout(function() {
        this.disabled = false;  // this指向的是调用者btn
    }.bind(this), 300);

    // 箭头函数
    setTimeout(() => {
        this.disabled = false;   // this指向的是调用者btn
    }, 300);

}

2.总结

  1. 相同点

    都可以改变函数内部的this指向。

  2. 区别点

    • call和apply会调用函数,并且改变函数内部的this指向;
    • call和apply传递的参数不一样,call传递参数采用arg1, arg2, ...的形式,apply则必须采用数组[argArr]的形式;
    • bind不会调用函数,只是改变函数内部的this指向。
  3. 主要应用场景

    • call经常做继承;
    • apply通常跟数组有关,比如借助数学对象实现求数组内最大值/最小值;
    • bind通常用于不想调用函数,但是想改变this指向时,如改变定时器内部的this指向。

三、严格模式

1.什么是严格模式

JavaScript除了提供正常模式外,还提供了严格模式(Strict Mode)。ES5的严格模式是采用具有限制性JavaScript辩题的一种方式,即在严格的条件下运行JS代码。

严格模式在IE10以上版本的浏览器中才被支持,旧版本浏览器中会被忽略。

严格模式对正常的JavaScript语义做了一些更改:

  1. 消除了JavaScript语法的一些不合理、不严谨之处,减少了一些怪异行为;
  2. 消除代码运行的一些不安全之处,保证代码运行的安全;
  3. 提高编译器效率,增加运行速度;
  4. 禁用了在ECMAScript的未来版本中可能会定义的一些语法,为未来新版本的JavaScript做好铺垫。比如一些保留字,如:class, enum, export, extends, import, super 不能做为变量名。

2.开启严格模式

严格模式可以应用到整个脚本或个别函数中。

因此在使用时,我们可以将严格模式分为为脚本开启严格模式为函数开启严格模式两种情况。

2.1 为脚本开启严格模式

在所有语句之前放一个特定语句:"use strict";'use strict';

<!-- 为整个脚本(script标签)开启严格模式 -->
<script>
	'use strict';
	// 下面的js代码都会按照严格模式执行
	// ...
</script>

<script>
	// 防止代码污染
    // 有的script基本是严格模式,有的script脚本是正常模式,这样不利于文件合并,所以可以将整个脚本文件放在一个立即执行的匿名函数之中。这样创建一个作用域而不影响其他script脚本文件
	(function() {
		'use strict';
		// 下面的js代码都会按照严格模式执行
		// ...
	})();
</script>
2.2 为函数开启严格模式

"use strict";'use strict';生命放在函数体所有语句之前。

<!-- 为某个函数开启严格模式 -->
<script>
	function fn() {
		'use strict';
		// 下面的代码按照严格模式执行
	}
	function fn1() {
		// 里面的代码还按照普通模式执行
	}
</script>

3.严格模式中的变化

严格模式对JavaScript的语法和行为,都做了一些改变。

3.1 变量规定
  1. 在正常模式中,如果一个变量没有声明就赋值,则默认为全局变量。严格模式禁止这种用法,变量都必须先用var进行声明;
  2. 严禁删除已经声明的变量。如,delete x;这种语法是错误的。
3.2 this指向
  1. 以前在全局作用域函数中的this指向window对象;

  2. 严格模式下,全局作用域中函数的this指向是undefined

  3. 以前构造函数时不加new也可以当普通函数调用,this指向全局对象;

    function Star() {
    	this.sex = '男';
    }
    Star();
    console.log(window.sex);
    
  4. 严格模式下,若构造函数不加new调用,由于this在全局作用域中指向的是undefined,this会报错;

  5. new实例化的构造函数指向创建的对象实例。

    function Star() {
    	this.sex = '男';
    }
    var ldh = new Star();
    console.log(ldh.sex);
    
  6. 定时器this还是指向window;

  7. 事件、对象还是指向调用者。

3.3 函数
  1. 函数不能有重名的参数;

  2. 函数必须声明在顶层。新版本的JavaScript会引入“块级作用域”(ES6中已引入),为了与新版本接轨,不允许在非函数的代码块内声明函数。

    'use strict';
    if (true) {
    	function f() {
    	
    	}	// 语法错误
    	f();
    }
    
    for (var i = 0; i < 5; i++) {
    	function f2() {
    	
    	}	// 语法错误
    	f2();
    }
    
    function f3() {	// 合法
    	function f4() {
    		// 合法
    	}
    }
    

四、高阶函数

高阶函数是对其他函数进行操作的函数,它接收函数作为参数,或将函数作为返回值输出

<!-- 接收函数作为参数 -->
<script>
	// 声明
	function fn(callback) {
		callback && callback();
	}
	// 调用
	fn(function() {
		alert('hi');
	})
</script>
<!-- 将函数作为返回值输出 -->
<script>
	function fn() {
		return function() {}
	}
	fn();
</script>

函数也是一种数据类型,同样可以作为参数传递给另外一个函数使用。最典型的就是作为回调函数

五、闭包

1.变量作用域

变量根据作用域的不同分为:全局变量和局部变量。

  1. 函数内部可以使用全局变量;
  2. 函数外部不可以使用局部变量;
  3. 当函数执行完毕,本作用域内的局部变量会销毁。

2.什么是闭包

闭包(closure)指有权访问另一个函数作用域中变量的函数

简单理解就是,一个作用域可以访问另外一个函数内部的局部变量。

function fn() {
	var num = 10;
	function fn1() {
		console.log(num);	// fn1这个函数作用域访问了另一个函数fn里面的局部变量num → 产生了闭包
	}
	fu1();
}
fn();

3.闭包的作用

闭包的主要作用:延伸了变量的作用范围。

function fn() {
	var num = 10;
	// function fun() {
	//	console.log(num);
	//}
	// return fun;
    return function() {
        console.log(num);
    }
}
var f = fn();
f();

4.闭包的应用

4.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>点击li输出当前li索引号</title>
</head>
<body>
    <ul class="nav">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <script>
        // 1. 动态添加属性
        var lis = document.querySelector('.nav').querySelectorAll('li');
        for(var i = 0; i < lis.length; i++) {
            lis[i].index = i;   // 动态添加属性
            lis[i].onclick = function() {
                console.log(this.index);
            }
        }
        // 2. 利用闭包方式得到当前li索引号
        for(var i = 0; i < lis.length; i++) {
            // 利用for循环创建4个立即执行函数
            // 立即执行函数也称为小闭包,因为立即执行函数里面的任何一个函数都可以使用它的i这变量
            (function(i) {
                lis[i].onclick = function() {
                    console.log(i);
                }
            })(i);
        }
    </script>
</body>
</html>
4.2 3秒后打印li内容
<!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>3s后打印所有li元素内容</title>
</head>
<body>
    <ul class="nav">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    <script>
        // 1. 普通实现
        var lis = document.querySelector('.nav').querySelectorAll('li');
        setTimeout(() => {
            for (var i = 0; i < lis.length; i++) {
                console.log(lis[i].innerHTML);
            }
        }, 3000);
        // 2. 闭包实现
        for(var i = 0; i < lis.length; i++) {
            (function(i) {
                setTimeout(function() {
                    console.log(lis[i].innerHTML);
                }, 3000);
            })(i)
        }
    </script>
</body>
</html>
4.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>
</head>
<body>

    <script>
        // 打车起步价13(3公里内),之后每多一公里加5元,用户输入公里数就可以计算打车价格
        // 若有拥堵情况,总价格多收取10元拥堵费
        var car = (function() {
            var start = 13; // 起步价
            var total = 0;  // 总价
            return {
                // 正常的总价
                price: function(n) {
                    if (n <= 3) {
                        total = start;
                    }
                    else {
                        total = start + (n - 3) * 5;
                    }
                    return total;
                },
                // 拥堵费用
                yd: function(flag) {
                    return flag ? total + 10 : total;
                }
            }
        })();
        console.log(car.price(5));  // 23
        console.log(car.yd(true));  // 33

        console.log(car.price(1));  // 13
        console.log(car.yd(false));  // 13
    </script>
</body>
</html>

六、递归

1.什么是递归

如果一个函数在内部调用其本身,那么这个函数就是递归函数。

递归函数的作用和循环效果相同。

由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件return

var num = 1;
function fn() {
	console.log('我要打印6句话');
	if (num == 6) {	// 退出条件
		return;
	}
	num++;
	fn();
}
fn();

2.浅拷贝和深拷贝

2.1 浅拷贝
  1. 浅拷贝只是拷贝一层,更深层次对象级别的数据**只拷贝引用(地址)**→修改数据将影响原对象;
  2. Object.assign(target,...source)ES6新增方法可以进行浅拷贝。
var obj = {
    id: 1,
    name: 'andy',
    msg:{
        age: 18
    }
};
var o = {};
// 浅拷贝
for (var k in obj) {
    // k:属性名 obj[k]:属性值
    o[k] = obj[k];
}
// 或
// Object.assign(o, obj);
console.log(o);
o.msg.age = 20;
console.log(obj);
2.2 深拷贝
  1. 深拷贝拷贝多层,每一级别的数据都会拷贝。
  2. 使用递归进行深拷贝:
var obj = {
    id: 1,
    name: 'andy',
    msg:{
        age: 18
    },
    color:['pink','red']
};
var o = {};

// 深拷贝
function deepCopy(newObj, oldObj) {
    for (var k in oldObj) {
        // 判断属性值属于哪种数据类型(简单数据类型/复杂数据类型)
        // 1. 获取属性值 oldObj[k]
        var item = oldObj[k];
        // 2. 判断这个值是否是数组
        // 注意:数组也属于对象,因此要先判断数组!
        if (item instanceof Array) {
            newObj[k] = [];
            deepCopy(newObj[k], item);
        }
        // 3. 判断这个值是否是对象
        else if (item instanceof Object) {
            newObj[k] = {};
            deepCopy(newObj[k], item);
        }
        // 4. 属于简单数据类型
        else {
            newObj[k] = item;
        }
    }
}
deepCopy(o, obj);
console.log(o);
o.msg.age = 20;
console.log(obj);

image-20220419145546997

正则表达式

一、概述

1.什么是正则表达式

正则表达式(Regular Expression)是用于匹配字符串中字符组合的模式。在JavaScript中,正则表达式也是对象

正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本,例如验证表单:用户名表单只能输入英文字母、数字或者下划线,昵称输入框中可以输入中文(匹配)。此外,正则表达式还常用于过滤掉页面内容中的一些敏感词(替换),或从字符串中获取我们想要的特定部分(提取)等。

2.特点

  1. 灵活性、逻辑性和功能性非常强;
  2. 可以迅速地用极简单的方式达到字符串的复杂控制;
  3. 对于刚接触的人来说,较为晦涩难懂,在实际开发中,一般都是直接复制写好的正则表达式。但还是要求会使用正则表达式并且根据实际情况对其做出修改,如用户名:/^[a-z0-9_-]{3,16}$/

二、在JavaScript中的使用

1.创建正则表达式

在JavaScript中,可以通过两种方式创建正则表达式:

1.1 通过调用RegExp对象的构造函数创建
var 变量名 = new RegExp(/表达式/);
1.2 通过字面量创建
var 变量名 = /表达式/;

三、正则表达式中的特殊字符

1.正则表达式组成

一个正则表达式可以由简单的字符构成,比如/abc/,也可以是简单和特殊字符的组合,比如/ab*c/

其中,特殊字符也被称为元字符,在正则表达式中是具有特殊意义的专用符号,如^$+等。

特殊字符非常多,可以参考:

  • MDN:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Regular_Expressions
  • jQuery手册:正则表达式部分
  • 正则测试工具:https://tool.oschina.net/regex
  • 菜鸟正则表达式在线测试工具:https://c.runoob.com/front-end/854/

2.边界符

正则表达式中的边界符(位置符)用来提示字符所处的位置,主要有两个字符:

边界符说明
^表示匹配行首的文本(要求以谁开始)
$表示匹配行尾的文本(要求以谁结束)

如果^和$在一起,表示必须是精确匹配

var reg1 = /abc/;	// 正则表达式中不需要加引号 不管是数字型还是字符串型
// 只要包含abc就符合
console.log(reg1.test('abc'));	// true
console.log(reg1.test('abcd'));	// true
console.log(reg1.test('aabcd'));	// true

var reg2 = /^abc/;
// 以abc开头
console.log(reg2.test('abc'));	// true
console.log(reg2.test('abcd'));	// true
console.log(reg2.test('aabcd'));	// false

var reg3 = /^abc$/;
// 精确匹配 要求必须是abc字符串才符合规范
console.log(reg3.test('abc'));	// true
console.log(reg3.test('abcd'));	// false
console.log(reg3.test('aabcd'));	// false

3.字符类

字符类[]表示有一系列字符可供选择,只要匹配其中一个就符合。所有可供选择的字符都放在方括号内。

var reg = /[abc]/;
// 只要包含有a/b/c其中一个就符合
console.log(reg.test('andy'));	// true
console.log(reg.test('baby'));	// true
console.log(reg.test('color'));	// true
console.log(reg.test('red'));	// false

var reg1 = /^[abc]$/;
// a/b/c三选一
console.log(reg1.test('aa'));	// false
console.log(reg1.test('a'));	// true
console.log(reg1.test('abc'));	// false

[-],方括号内部范围符-

var reg2 = /^[a-z]$/;
// 26个小写英文字母任意一个
console.log(reg2.test('a'));	// true
console.log(reg2.test('b'));	// true
console.log(reg2.test(1));	// false
console.log(reg2.test('A'));	// false

字符组合

var reg3 = /^[a-zA-Z]$/;
// 26个英文字母任意一个(大写小写均可)
console.log(reg2.test('a'));	// true
console.log(reg2.test('b'));	// true
console.log(reg2.test(1));	// false
console.log(reg2.test('A'));	// true

[^]方括号内部^取反符

// 中括号内部的^表示取反!
var reg4 = /^[^a-zA-Z]$/;
// 不包含26个英文字母
console.log(reg2.test('a'));	// false
console.log(reg2.test('b'));	// false
console.log(reg2.test(1));	// true
console.log(reg2.test('A'));	// false

4.量词符

量词符用来设定某个模式出现的次数

量词说明
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次
var reg = /^a$/;

// * 相当于 >=0 可以出现0次或很多次
var reg1 = /^a*$/;
console.log(reg1.test(''));	// true
console.log(reg1.test('a'));	// true
console.log(reg1.test('aaaaaa'));	// true

// + 相当于 >=1
var reg2 = /^a+$/;
console.log(reg2.test(''));	// false
console.log(reg2.test('a'));	// true
console.log(reg2.test('aaaaaa'));	// 

// ? 相当于 1||0
var reg3 = /^a?$/;
console.log(reg3.test(''));	// true
console.log(reg3.test('a'));	// true
console.log(reg3.test('aaaaaa'));	// false

// {n} 相当于 =n
var reg4 = /^a{6}$/;
console.log(reg4.test(''));	// false
console.log(reg4.test('a'));	// false
console.log(reg4.test('aaaaaa'));	// true
console.log(reg4,test('aaaaaaa'));	// false

// {n,} 相当于>=n
var reg5 = /^a{6,}$/;
console.log(reg5.test(''));	// false
console.log(reg5.test('a'));	// false
console.log(reg5.test('aaaaaa'));	// true
console.log(reg5.test('aaaaaaa'));	// true

// {n,m} 相当于>=n <=m
var reg6 = /^a{1,6}$/;
console.log(reg6.test(''));	// false
console.log(reg6.test('a'));	// true
console.log(reg6.test('aaaaaa'));	// true
console.log(reg6.test('aaaaaaa'));	// false

5.优先级

()表示优先级。

var reg = /^(abc){3}$/;
// abc重复3次
console.log(reg.test('abc'));	// false
console.log(reg.test('abcabcabc'));	// true
console.log(reg.test('abcccccccc'));	// false

也可以表示对内容的范围选择,捕获等。

(123|132|321|312)表示不论123/132/321/312都可以匹配;

(123)?表示出现1次或不出现123

6.预定义类

预定义类指的是某些常见模式的简写方式

预定义类说明
\d匹配0-9之间的任一数字,相当于[0-9]
\D匹配所有0-9以外的字符,相当于[^0-9]
\w匹配任意的字母、数字和下划线,相当于[A-Za-z0-9]
\W除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_]
\s匹配空格(包括换行符、制表符、空格符等),相当于[\t\r\n\v\f]
\S匹配非空格的字符,相当于[^\t\r\n\v\f]
// 座机号码验证:两种格式010-12345678	或 0530-1234567
// 正则里面的或者符号→|
var reg = /^\d{3}-\d{8} | \d{4}-\d{7}$/;

7.通配符

表达式说明
.表示匹配除换行符\n之外的任何单字符
*表示零次或多次
.*表示任意字符出现零次或多次
.*??跟在*+后面时,表示懒惰模式,也称非贪婪模式,即匹配尽可能少的字符。意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复
例如:a.*?b,匹配以a开始b结束的字符串,若将其应用于aabab,匹配的结果会是aab
.+?+表示一次或多次
例如:a.+?b,匹配以a开始b结束的字符串,且ab之间至少有一个字符,若将其应用于ababccaab。将匹配到abab
let str = 'ababccaab'
let reg1 = /a.+?b/
let reg2 = /a.+b/
let result1 = reg1.exec(str)
let result2 = reg2.exec(str)
// let result = str.match(reg)
console.log(result1)
console.log(result2)

image-20230201162358154

四、常用正则表达式

1.校验数字的表达式

  • 数字:^[0-9]\*$
  • n位的数字:^\d{n}$
  • 至少n位的数字:^\d{n,}$
  • m-n位的数字:^\d{m,n}$
  • 零和非零开头的数字:^(0|[1-9][0-9]\*)$
  • 非零开头的最多带两位小数的数字:^([1-9][0-9]\*)+(\.[0-9]{1,2})?$
  • 带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})$
  • 正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
  • 有两位小数的正实数:^[0-9]+(\.[0-9]{2})?$
  • 有1~3位小数的正实数:^[0-9]+(\.[0-9]{1,3})?$
  • 非零的正整数:^[1-9]\d\*$ 或 ^([1-9][0-9]\*){1,3}$ 或 ^\+?[1-9][0-9]\*$
  • 非零的负整数:^\-[1-9][]0-9"\*$ 或 ^-[1-9]\d\*$
  • 非负整数:^\d+$ 或 ^[1-9]\d\*|0$
  • 非正整数:^-[1-9]\d\*|0$ 或 ^((-\d+)|(0+))$
  • 非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d\*\.\d\*|0\.\d\*[1-9]\d\*|0?\.0+|0$
  • 非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d\*\.\d\*|0\.\d\*[1-9]\d\*))|0?\.0+|0$
  • 正浮点数:^[1-9]\d\*\.\d\*|0\.\d\*[1-9]\d\*$ 或 ^(([0-9]+\.[0-9]\*[1-9][0-9]\*)|([0-9]\*[1-9][0-9]\*\.[0-9]+)|([0-9]\*[1-9][0-9]\*))$
  • 负浮点数:^-([1-9]\d\*\.\d\*|0\.\d\*[1-9]\d\*)$ 或 ^(-(([0-9]+\.[0-9]\*[1-9][0-9]\*)|([0-9]\*[1-9][0-9]\*\.[0-9]+)|([0-9]\*[1-9][0-9]\*)))$
  • 浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d\*\.\**d\*|0\.\d\*[1-9]\d\*|0?\.0+|0)$

2.校验字符的表达式

  • 汉字:^[\u4e00-\u9fa5]{0,}$
  • 英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
  • 长度为3-20的所有字符:^.{3,20}$
  • 由26个英文字母组成的字符串:^[A-Za-z]+$
  • 由26个大写英文字母组成的字符串:^[A-Z]+$
  • 由26个小写英文字母组成的字符串:^[a-z]+$
  • 由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
  • 由数字、26个英文字母或者下划线组成的字符串:^\w+$^\w{3,20}$
  • 中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
  • 中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
  • 可以输入含有^%&',;=?KaTeX parse error: Expected group after '^' at position 9: \"等字符:`[^̲%&',;=?\x22]+`
  • 禁止输入含有~的字符:[^~]+

3.特殊需求表达式

  • Email地址:^\w+([-+.]\w+)\*@\w+([-.]\w+)\*\.\w+([-.]\w+)\*$
  • 域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+\.?
  • InternetURL:[a-zA-z]+://[^\s]\*^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]\*)?$
  • 手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
  • 电话号码(“XXX-XXXXXXX”、“XXXX-XXXXXXXX”、“XXX-XXXXXXX”、“XXX-XXXXXXXX”、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
  • 国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
  • 电话号码正则表达式(支持手机号码,3-4位区号,7-8位直播号码,1-4位分机号): ((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)
  • 身份证号(15位、18位数字),最后一位是校验位,可能为数字或字符X:(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)
  • 帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
  • 密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
  • 强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在 8-10 之间):^(?=.\*\d)(?=.\*[a-z])(?=.\*[A-Z])[a-zA-Z0-9]{8,10}$
  • 强密码(必须包含大小写字母和数字的组合,可以使用特殊字符,长度在8-10之间):^(?=.\*\d)(?=.\*[a-z])(?=.\*[A-Z]).{8,10}$
  • 日期格式:^\d{4}-\d{1,2}-\d{1,2}
  • 一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
  • 一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
  • 钱的输入格式:
    1. 有四种钱的表示形式我们可以接受:“10000.00” 和 “10,000.00”, 和没有 “分” 的 “10000” 和 “10,000”:^[1-9][0-9]\*$
    2. 这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]\*)$
    3. 一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]\*)$
    4. 这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧。下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
    5. 必须说明的是,小数点后面至少应该有1位数,所以"10."是不通过的,但是 “10” 和 “10.2” 是通过的:^[0-9]+(.[0-9]{2})?$
    6. 这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
    7. 这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})\*(.[0-9]{1,2})?$
    8. 1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})\*)(.[0-9]{1,2})?$
    9. 备注:这就是最终结果了,别忘了"+“可以用”*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
  • xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
  • 中文字符的正则表达式:[\u4e00-\u9fa5]
  • 双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
  • 空白行的正则表达式:\n\s\*\r (可以用来删除空白行)
  • HTML标记的正则表达式:<(\S\*?)[^>]\*>.\*?|<.\*? /> ( 首尾空白字符的正则表达式:^\s*|\s*KaTeX parse error: Undefined control sequence: \s at position 4: 或(^\̲s̲\*)|(\s\*) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
  • 腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
  • 中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
  • IPv4地址:((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}
  • 金额校验:(^[1-9]{1}[0-9]*$)|(^[0-9]+\.[0-9]{2}$);

五、RegExp对象方法

1.exec()

exec()方法用于检索字符串中正则表达式的匹配,如果字符串中有匹配的值,则返回该匹配值构成的数组,且该数组还有继承的属性:

  • index:表示第一个匹配的字符在原字符串中的位置
  • input:表示原字符串
// 声明一个字符串
let str = '<a href="http://www.atguigu.com">尚硅谷</a>'

// 提取url与标签文本
const reg = /<a href="(.*)">(.*)<\/a>/;

const result = reg.exec(str)   // 检索字符串中正则表达式的匹配
console.log(result)

image-20230201163407073

说明:

数组第一个元素是与正则表达式相匹配的文本;

第二个元素是与RegExp对象的第一个子表达式(分组小括号里面的)相匹配的文本;

第三个元素是与RegExp对象的第二个子表达式相匹配的文本,以此类推……

获取url参数:

/**
 *   获取url中的参数
 * @param key  待匹配的关键字
 * @param url  被匹配查询的url
 */
export function getUrlQuery(key, url) {
    let str = url || window.location.href //默认获取浏览器地址栏中的url
    let reg = decodeURIComponent((new RegExp('[?|&|/]' + key + '=([^&;]+?)(&|#|;|$)').exec(str) || [, ''])[1].replace(/\+/g, '%20')) || null
    return reg
}

2.test()

test()正则对象方法,用于监测字符串是否符合该规则(测试正则表达式),该对象会返回true或false,其参数是测试字符串。

regexObj.test(str);
  • regexObj:正则表达式;
  • str:需要测试的字符串;
  • 检测str文本是否符合我们写的正则表达式规范。

校验手机号

let regPhone = /^1[3456789]\d{9}$/;
if (this.utils.isNone(this.account)) {
	this.$Message.info("请输入手机号码");
	return false;
} 
else if (!regPhone.test(this.account)) {
	this.$Message.info("手机号码格式有误");
	return false;
}

六、支持正则表达式的String对象方法

1.replace()

replace()方法可以实现替换字符串操作,用来替换的参数可以是一个字符串或是一个正则表达式。

stringObject.replace(regexp/substr, replacement);
  • regexp/substr:需要被替换的字符串正则表达式
  • replacement:替换为的字符串;
  • 返回值是一个替换完毕的新字符串。

正则表达式参数:

/表达式/[switch]

switch(也称为修饰符),表示按照什么模式来匹配:

  • g:全局匹配;
  • i:忽略大小写;
  • gi:全局匹配且忽略大小写;
  • s:使.可以匹配任意字符,ES9引入了新的修饰符sdotAll模式),此先.只能匹配除\n以外的任意字符。

敏感词过滤

<textarea name="" id="message"></textarea>
<button>提交</button>
<div></div>

<script>
	var text = document.querySelector('textarea');
	bar btn = document.querySelector('button');
	var div = document.querySelecor('div');
	
	btn.onclick = function() {
		div.innerHTML = text.value.replace(/激情|gay/g,'**');
	}
</script>

去除首尾空格

  1. jquery

    • trim()
  2. js

    • 去除首尾空格:replace(/^\s*|\s*/g, '')

    • 去除首部空格:replace(/^\s*/g,'')

    • 去除尾部空格:replace(/\s*$/g,'')

    • trim() trimStart() trimEnd()

      方法说明
      trim删除字符串的头尾空白符,空白符包括:空格、制表符tab、换行符等
      trimStart删除字符串头部空白符
      trimEnd删除字符串尾部空白符
      let str = '          i love u       '
      
      console.log(str)
      console.log(str.trim())
      console.log(str.trimStart())
      console.log(str.trimEnd())
      

      image-20230201175235382

2.search()

用于检索字符串中指定的子字符串,或检索与正则表达式相匹配的子字符串。→ 判断是否存在某个子串

若找到任何匹配的子串,则返回该子串在原字符串中第一次出现的位置;若没有找到任何匹配的子串,返回-1。

var str1 = 'hello 123 world 456';
var reg1 = /d+/; 
console.log(str1.search(reg1));//6
console.log(str1.search("world"));//10
var str2 = 'hello world';
var reg2 = /d+/;
console.log(str2.search(reg2));//-1
console.log(str2.search("nihao"));//-1

3.split()

用于把一个字符串按符合匹配条件的方式分割成一个字符串数组。不改变原字符串

var str="How 1are 2you 3doing 4today?";
var a=str.split(" ");
var b=str.split(" ",2);
var c=str.split(/d/);
var d=str.split(/d/,3);
console.log(a);//["How", "1are", "2you", "3doing", "4today?"]
console.log(b);//["How", "1are"]
console.log(c);//["How ", "are ", "you ", "doing ", "today?"]
console.log(d);//["How ", "are ", "you "]

4.match()

match()方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。

这个方法的行为在很大程度上有赖于 regexp 是否具有全局标志g

  • 如果 regexp 没有标志g,那么 match() 方法就只能在 stringObject 中执行一次匹配,与exce的完全一致。
  • 如果 regexp 有标志g,它将找到全部符合正则子字符串,并返回一个数组;如果没有找到任何匹配的文本,无论有没有g,match() 将返回 null。
var str = "Hello45647 123 world!Hello 1423 world! ssfsdf";
var reg1 = /\d+/;
var result1 = str.match(reg1);
console.log(result1)
var reg2 = /\d+/g;
var result2 = str.match(reg2);
console.log(result2)

image-20230201164851320

5.matchAll()

matchAll() 方法返回一个包含所有匹配正则表达式的结果及其分组捕获组的迭代器

var str = "Hello45647 123 world!Hello 1423 world! ssfsdf";
var reg = /\d+/g;
var result = str.matchAll(reg);
console.log(result)
// 1. 遍历 -------------------
for(let v of result) {
    console.log(v)
}

// 2. 拓展运算符 --------------
console.log(...result)

// 3. Array.from() -----------
var arr = Array.from(result)    // 将类数组转换为真正的数组
console.log(arr)

七、断言

断言可以帮助我们查找某些内容时,对内容前和内容后的信息作为判断(但并不包括这些内容)(把内容前或后的信息作为判断依据但结果不包括这些内容,所以也被称为零宽断言

var str = "我是小明我是小王我是小绿"
var reg = /我是(?=)小明/
console.log(str.replace(reg, '我不是')	// 将后面跟着'小明'的'我是'替换为'我不是'
  1. 断言的写法
    • VVV(?=XXX) 零宽正先行断言(正向断言):只有在断言XXX在VVV的后边时,才会继续匹配
    • VVV(?!XXX) 零宽负先行断言(正向断言):只有在断言XXX不在VVV的后边时,才会继续匹配
    • (?<=XX)VVV 零宽正后发断言(反向断言):只有在断言XX在VVV的前边时,才会继续匹配
    • (?<!XX)VVV 零宽负后发断言(反向断言):只有在断言XX不在VVV的前边时,才会继续匹配
  2. 注意
    • 断言不占用字符串,不被包括在内容中;
    • 断言一定要写在括号()中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值