洪晨的前端随记2021年12月13日

html+css+js

font 标签属性用来选中某些字,单独设置属性

 <!-- 文档声明是html5,声明当前网页的版本 -->
<!doctype html>

<!-- html是根标签(元素),网页中所有的内容都要写在根元素里面 -->
<html>

	<!-- head元素是网页的头部,head中的内容不会在网页中直接出现,主要用来帮助浏览器或搜索引擎来解析网页 -->
	<head>
	
	
		<!-- meta标签用来设置网页的元数据,这里可以通过meta标签来设置网页的字符集,避免乱码问题 -->
		<meta charset="utf-8">
		
		<!-- title中的内容会显示在浏览器的标题栏,搜索引擎会主要根据title中的内容来判断网页的主要内容 -->
		<title>标签的属性</title>
	</head>
	
	<!-- body是html的子元素,表示网页的主体,网页中所有的可见内容都应该写在body里 -->
	<body>
		<!--
			属性,在标签中,(开始标签或自结束标签)还可以设置属性
			属性是一个名值对(x=y)
			属性用来设置标签中的内容如何显示
			属性和标签名或其他属性使用空格隔开
			属性要根据官方文档中的规定来编写
			有些属性有属性值,有些则没有.
			如果有属性值,属性值应该使用引号引起来(单引号,双引号都可以,但是一定要成对出现)
		-->
		
		<h1>这是我的<font color="red">网页<font></h1>
	</body>
</html>

zeal 语言文档查看器

官网位置: https://zealdocs.org/

vscode ayu主体颜色还不错,mirage 主体色还不错
vscode !+tab键, 直接生成html结构,注释快捷键 Ctrl + /
安装live server 插件(类似于热部署功能)
vscode设置自动保存[设置->文本编辑器->文件->auto save->afterDelay,时间是毫秒单位]
<body>
    
    <!-- 
        如果我们需要在网页中书写这些特殊符号,则需要使用html中的实体(转义字符)
        实体的语法:
            &实体名字;
                &nbsp; 空格
                &gt; 大于号
                &lt; 小于号
                &copy; 版权符号
     -->

     <p>
         这里有很多的空格&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;啊
     </p>

     <p>
         a&lt;b&gt;c 
         &copy;honksun
     </p>
</body>
<head>
    <meta charset="UTF-8"/>
    <!-- 
        meta主要用于设置网页中的一些元数据,元数据不是给用户看的
            charset 指定网页的字符集
            name 指定数据的名称
            content 指定数据的内容
     -->
     <!-- 
         keywords 表示网站的关键字,可以同时指定多个关键字,关键字使用,隔开
         <meta name="Keywords" content="网上购物,网上商城,家电,手机,电脑,服装,
         居家,母婴,美妆,个护,食品,生鲜,京东"/>
      -->
     <meta name="keywords" content="这是网页的关键字1,这是网页的关键字2,这是网页的关键字3"/>
     
         <!-- <meta name="description"
          content="京东JD.COM-专业的综合网上购物商城,为您提供正品低价的购物选择、
          优质便捷的服务体验。商品来自全球数十万品牌商家,囊括家电、手机、电脑、服装、居家、
          母婴、美妆、个护、食品、生鲜等丰富品类,满足各种购物需求。"/> 
          description 用于指定网站的描述  
        -->
      <meta name="description" content="这是我的前端学习笔记">
      <!-- 
          http-equiv="refresh" 将页面重定向到另一个网站
          3秒后跳转到百度页面
       -->
      <meta http-equiv="refresh" content="3;url=https://www.baidu.com">
   
    <title>Document</title>
</head>

语义标签

<body>

    <!-- 
       hgroup: 标题组标签 用来标题分组,可以将一组相关的标题同时放入hgroup中 
     -->
    <hgroup>
        <h1>回乡偶书二首</h1>
        <h2>其一</h2>
    </hgroup>

    <!-- 
        em标签: 用于表示语音语调的加重
        在页面中,独占一行的元素称为块元素(block element).
        不会独占一行的元素称为 行内元素(inline element)
     -->
    <p>今天天气<em>真</em>不错</p>
    
    <!-- 
        strong标签: 表示强调,重要内容
     -->
    <p>我<strong>非常非常</strong>的强壮</p>

    <!-- 
        blockquote标签: 表示一个长引用
     -->
    <p>科比说:<blockquote>你见过洛杉矶凌晨的四点吗?</blockquote></p>

    <!-- 
        q标签: 表示一个短引用
     -->
    <p>子曰:<q>吾日三省吾身</q></p>

    <!-- 
        br标签: 表示换行
     -->
    科比<br>
    詹姆斯<br>
    乔丹

    <!-- 
        在网页中一般使用块元素进行网页布局,使用行内元素来包裹文字
        可以在块元素中放置行内元素.
        行内元素中一定不能放入块元素
        p标签中不能放入块元素
        浏览器在解析网页时,会对网页中不规范的内容进行修正.
     -->

     <!-- 
         布局标签
         div 是块元素,没有语义,就是用来表示一个区块,目前使用最多的布局元素
         span 是行内元素,没有语义,一般用于网页中选中文字
      -->
</body>

列表

<body>
    
    <!-- 无序列表 -->
    <ul>
        <li>中国</li>
        <li>新加坡</li>
        <li>澳大利亚</li>
    </ul>

    <!-- 有序列表 -->
    <ol>
        <li>中国</li>
        <li>新加坡</li>
        <li>澳大利亚</li>
    </ol>

    <!-- 定义列表 -->
    <dl>
        <dt>中国</dt>
        <dd>是我的祖国</dd>
    </dl>

    <!-- 
        列表之间可以相互嵌套
     -->

</body>

超链接

    <!-- 
        超链接可以让我们从当前页面跳转到其它页面,
        也可以跳转到当前页面的其它位置
        使用 a标签来定义超链接
            属性
            href 指定跳转的目标路径
                可以是外部网址的一个地址
                也可以是一个内部页面地址
								./ 表示当前文件所在的目录
								../ 表示当前文件的上一级目录
     -->
    <a href="https://www.qq.com">跳转到qq首页</a>
    <br><br>
    <!-- 页面要在同一个文件夹下面 -->
    <a href="01.index.html">内部地址跳转</a>
<body>

    <!-- 
        target 属性,用来指定超链接打开的位置
            可选值
                _self : 默认值,在当前页面中打开超链接
                _blank: 在一个新的页面中打开超链接
     -->
    <a href="01.index.html" target="_blank">超链接3</a>
    <br>
    <a href="#bottom">去底部</a>

    <!-- 输入lorem+tab键,随机生成一段文字 -->
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>
    <p>    Lorem ipsum dolor sit amet consectetur adipisicing elit. Perferendis maxime nostrum beatae quia laudantium nobis consectetur maiores eos error quisquam. Vitae totam natus id necessitatibus eum qui nobis deserunt ullam?</p>

    <!-- 
        可以直接将超链接的href属性设置为 # 号,这样点击超链接以后,
        页面不会发生跳转,而是转到当前页的顶部位置.

        可以跳转到页面的制定位置,只需要将href属性设置 #目标元素的id属性值

        id属性: 唯一不重复的值
            每个标签都可以添加一个id属性
            id属性就是元素的唯一标识,同一个页面不能出现重复的id属性
     -->
    <a id="bottom" href="#">回到顶部</a>

    <br>
    <!-- 可以使用 javascript:; 作为href的属性,此时点击超链接,什么也不会发生 -->
    <a href="javascript:;">这是一个占位符的超链接</a>
</body>

图片标签

<body>

    <!-- 
        src 属性指定外部图片的路径(路径规则和超链接是一样的)
        alt 属性图片的描述,这个描述默认情况下不会显示,有些浏览器会在图片无法加载的时候显示
            搜索引擎会根据alt中的内容来识别图片,如果不写alt,则图片不会被搜索引擎所收录

        img 这种元素属于替换元素

        width 图片的宽度(单位是px像素)
        height 图片的高度(单位是px像素)
            - 宽度和高度中,如果只修改了一个,则另一个会等比例缩放

        在pc端,不建议修改图片大小
        在移动端,可以大图片缩小
     -->
    <img src="../资料/源码和资料/资料/img/img/1.gif" alt="小松鼠" width="" height="">

</body>

內联框架

<body>

    <!-- 
        iframe 內联框架,用于当前页引入一个其它页面
            src 指定要引入网页的路径
            frameborder 指定內联框架的边框
     -->
    <iframe src="./01.index.html" frameborder="0"></iframe>

</body>

音视频

<body>

    <!-- 
        audio 元素用来向页面引用一个外部的音频文件
        音频文件引入后,默认情况下不允许用户进行控制播放停止

        属性
            controls 是否允许用户控制播放
            autoplay 是否允许音频自动播放
                如果设置了autoplay,则音乐会在打开页面时自动播放,
                但是目前来讲,大部分浏览器不会对音频进行自动播放
            loop 音频是否循环播放
     -->
    <audio src="../资料/源码和资料/资料/音视频/audio.mp3" controls></audio>

    <br>
    <!-- 第二种写法,可以有效解决浏览器兼容问题 -->
    <audio controls>
        对不起,您的浏览器不支持播放音频,请升级您的浏览器
        <source src="../资料/源码和资料/资料/音视频/audio.mp3">
        <source src="../资料/源码和资料/资料/音视频/audio.ogg">
        <!-- embed 元素兼容IE8浏览器 -->
        <embed src="../资料/源码和资料/资料/音视频/audio.mp3" type="audio/mp3">
    </audio>

    <!-- video 视频元素 -->
    <video controls>
        <source src="../资料/源码和资料/资料/音视频/flower.webm">
        <source src="../资料/源码和资料/资料/音视频/flower.mp4">
    </video>
</body>

css样式引用的三种方式

style.css

div{
    color: blueviolet;
    font-size: 15px;
}
<head>
    <meta charset="UTF-8">
    <title>Document</title>

    <!-- 第二种方式(内部样式表),将样式编写到head中的style标签里 -->
    <style>
        span{
            color: salmon;
            font-size: 30px;
        }
    </style>

    <!-- 第三种方式,引用外部样式表 -->
    <link rel="stylesheet" href="./style.css">
</head>
<body>
    <!-- 
        第一种方式(内联样式,行内样式)
            在标签内通过style属性来设置元素的样式
     -->
    <p style="color: red; font-size: 20px;">Lorem ipsum dolor sit amet consectetur adipisicing elit. Nam, modi pariatur neque, mollitia reiciendis, adipisci suscipit ullam officiis cum officia totam omnis ipsa voluptatibus. Culpa nisi nobis similique doloremque blanditiis.</p>
    <span>Lorem ipsum dolor sit amet consectetur adipisicing elit. Consectetur sint accusantium eius exercitationem, quis eveniet! Autem dolore dignissimos consequatur ipsa animi harum, architecto iusto error porro mollitia consectetur molestias ullam?</span>
    <div>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Voluptate deserunt ipsum nisi quo pariatur blanditiis modi ad omnis nulla. Non dolores consectetur voluptatibus vel beatae quo! Tenetur eos consectetur beatae.</div>
</body>

常用选择器

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Document</title>

    <style>
        /* 元素选择器 */
        p{
            color: salmon;
        }

        /* id选择器 */
        #id1{
            color: skyblue;
        }

        /* 类选择器 */
        .class1{
            color: brown;
        }

        .class2{
            color: cadetblue;
        }

        /* 通用选择器 */
        *{
            color: chartreuse;
        }
    </style>
</head>
<body>
    <h1>这是标题</h1>
    <p>这是内容</p>
    <p>这是内容</p>
    <!-- id是全局唯一,不可重复 -->
    <p id="id1">这是内容</p>
    <p>这是内容</p>
    <!-- class可以重复,同一个元素可以设置多个class属性 -->
    <p class="class1 class2">这是内容</p>
    <p class="class1">这是内容</p>
</body>
</html>

复合选择器

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Document</title>

    <style>
        /* 交集选择器 */
        div.div{
            color: chartreuse;
        }

        /* 
        并集选择器 
        同时选择多个选择器对应的元素,中间用 , 号隔开
        */
        span,p{
            color: cyan;
        }
    </style>
</head>
<body>
    <div class="div">这是div标签</div>
    <p class="div">这是p标签</p>
    <span>这是span元素</span>
</body>
</html>
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Document</title>

    <style>
        /* 子元素选择器 */
        div > span{
            color: cyan;
        }

        /* 后代选择器 */
        div p{
            color: darkblue;
        }

        /* 
        兄弟选择器
        + 只选择下一个
        ~ 选择下面所有
        */
        span + h6{
            color: darkmagenta;
        }

        span ~ h6{
            color: darkolivegreen;
        }

    </style>
</head>
<body>
    <div>
        <p>这是div中的p元素
            <br>
            <span>这是div中的p元素中的span元素</span>
        </p>

        <span>这是div中的span元素</span>
        <h6>这是div中的h6</h6>
        <h6>这是div中的h6</h6>
        <h6>这是div中的h6</h6>
        <h6>这是div中的h6</h6>
        <h6>这是div中的h6</h6>
    </div>
</body>
</html>

属性选择器

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Document</title>

    <style>
        /* 
        属性选择器
        语法
            [属性名] 选择含有指定属性的元素
            [属性名=属性值] 选择含有指定属性和属性值的元素 
            [属性名^=属性值] 选择属性名以指定属性值开头的元素
            [属性名$=属性值] 选择属性名以指定属性值结尾的元素
            [属性名*=属性值] 选择属性名包含指定属性值的元素
        */
        p[title]{
            color: darkorchid;
        }

        p[title=test]{
            color: darkred;
        }
    </style>
</head>
<body>
    <p title="abc">Lorem ipsum dolor sit amet consectetur adipisicing elit. Suscipit quaerat, mollitia cumque aut praesentium consequatur voluptates corrupti iusto laudantium iure qui quas modi laborum ut voluptas temporibus culpa earum ratione!</p>
    <p title="abcdef">Lorem ipsum dolor sit amet consectetur adipisicing elit. Suscipit quaerat, mollitia cumque aut praesentium consequatur voluptates corrupti iusto laudantium iure qui quas modi laborum ut voluptas temporibus culpa earum ratione!</p>
    <p title="yuoabc">Lorem ipsum dolor sit amet consectetur adipisicing elit. Suscipit quaerat, mollitia cumque aut praesentium consequatur voluptates corrupti iusto laudantium iure qui quas modi laborum ut voluptas temporibus culpa earum ratione!</p>
    <p title="test">Lorem ipsum dolor sit amet consectetur adipisicing elit. Suscipit quaerat, mollitia cumque aut praesentium consequatur voluptates corrupti iusto laudantium iure qui quas modi laborum ut voluptas temporibus culpa earum ratione!</p>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Suscipit quaerat, mollitia cumque aut praesentium consequatur voluptates corrupti iusto laudantium iure qui quas modi laborum ut voluptas temporibus culpa earum ratione!</p>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Suscipit quaerat, mollitia cumque aut praesentium consequatur voluptates corrupti iusto laudantium iure qui quas modi laborum ut voluptas temporibus culpa earum ratione!</p>
</body>
</html>

伪类选择器

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>Document</title>

    <style>
        /* 
        伪类选择器
        first-child 选择第一个子元素
        last-child 选择最后一个子元素
        nth-child(n) 选择第n个子元素
            特殊值
                n 第n个,范围是0到正无穷大
                2n 或 even ,表示选中偶数位子元素
                2n+1 或 odd ,表示选中奇数位子元素
            以上这些伪类都是根据所有子元素进行排序的

        :first-of-type
        :last-of-type
        :nth-of-type()
            这几个伪类和上述功能类似,不同点是在同类型元素中进行排序

        :not() 否定伪类
            将符合条件的元素从选择器中去除
        */
        ul>li:not(:nth-child(3)){
            color: brown;
        }
    </style>
</head>
<body>

    <ul>
        <li>第零个</li>
        <li>第一个</li>
        <li>第二个</li>
        <li>第三个</li>
        <li>第四个</li>
        <li>第五个</li>
    </ul>
</body>
</html>

a元素伪类

<!DOCTYPE html>
<html lang="zh">
<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>
        /* 没访问过的链接 */
        a:link{
            color: brown;
        }
        /* 访问过的链接 
            由于隐私问题,这个visited 伪类只能修改颜色
        */
        a:visited{
            color: burlywood;
        }
        /* 鼠标移入的状态 */
        a:hover{
            color: chartreuse;
        }
        /* 鼠标点击的状态 */
        a:active{
            color: darkblue;
        }
    </style>
</head>
<body>

    <a href="https://www.baidu.com">点击过的链接</a>
    <br><br>
    <a href="https://www.123456.com">没点击过的链接</a>
    
</body>
</html>

伪元素选择器

<!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>
        /* 选中第一个字母 */
        p::first-letter{
            color: red;
        }
        /* 选中第一行文字 */
        p::first-line{
            color: rosybrown;
        }
        /* 鼠标选中的内容 */
        p::selection{
            color: skyblue;
        }
        /* 
            ::before 和 ::after 必须搭配 content 使用
        */
        /* 元素的开始 */
        div::before{
            content: '{';
            color: slateblue;
        }
        /* 元素的结尾 */
        div::after{
            content: '}';
            color: steelblue;
        }
    </style>
</head>
<body>
    <div>少小离家老大回,乡音无改鬓毛衰</div>
    <p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Qui, amet. Sapiente sunt et nesciunt repellat libero vel quam iure quia impedit minus, quae laboriosam dolor iste illum accusantium, dicta commodi!</p>
</body>
</html>

选择器的权重

<!-- 
        选择器的权重
            内联样式        1000
            id选择器        100
            类和伪类选择器   10
            元素选择器      1
            通配选择器      0
            继承选择器      没有优先级

        body{
            background-color: steelblue !important;
        }
       在某一个样式后面添加 !important ,则此时该样式获得最高优先级,甚至超过内联样式 
     -->
RGBA A是透明度,0,1,
0.5 是半透明

盒子模型

<!DOCTYPE html>
<html lang="zh">
<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>
        /* 设置盒子模型content内容 */
        .box1{
            width: 200px;
            height: 200px;
            background-color: steelblue;

            /* 设置盒子模型的边框 */
            border-width: 10px;
            border-color: tan;
            border-style: solid;

        }
        
    </style>
</head>
<body>

    <div class="box1"></div>
    
</body>
</html>
<!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>
        div{
            width: 200px;
            height: 200px;
            background-color: brown;
        }
        .box1{
            /* 
            border的简写
                border-top
                border-right
                border-bottom
                border-left
            */
            border: 5px yellowgreen solid;
        }
    </style>
</head>
<body>
    <div class="box1"></div>
</body>
</html>

内边距

<!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>
        .box1{
            width: 200px;
            height: 200px;
            background-color: yellowgreen;
            border: red 10px solid;

            /* 
            padding 内边距
                padding-top
                padding-right
                padding-bottom
                padding-left
            */
            padding: 50px;
        }

        .inner{
            width: 100%;
            height: 100%;
            background-color: rosybrown;
        }
    </style>
</head>
<body>
    <div class="box1">
        <div class="inner"></div>
    </div>
</body>
</html>

外边距

<!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>
        .box1{
            width: 200px;
            height: 200px;
            background-color: yellowgreen;
            border: red 10px solid;
            /* 
            margin 外边距
            margin-top
            margin-right
            margin-bottom
            margin-left
            */
            margin: 50px;
        }

    
    </style>
</head>
<body>
    <div class="box1">
    </div>
</body>
</html>

垂直方向布局

<!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>
        .outer{
            width: 200px;
            height: 200px;
            background-color: rosybrown;
            /* 
            overflow,设置父元素如何处理溢出的子元素
                可选值
                    visible 默认值,在父元素外部位置,显示子元素内容
                    hidden 溢出的内容将会被裁减,不显示
                    scroll 生成两个滚动条,通过滚动条来查看完整内容
                    auto 根据需要生成滚动条
            overflow-x: ;
            overflow-y: ;
            */
            overflow: auto;
            
        }
    </style>
</head>
<body>
    <div class="outer">
        Lorem ipsum dolor sit amet consectetur adipisicing elit. Fugit ipsam recusandae eligendi laboriosam necessitatibus praesentium quam quia omnis quod ut delectus, explicabo voluptatem molestias eaque, nemo commodi animi blanditiis quo.
    </div>
</body>
</html>

行内元素盒模型

<!DOCTYPE html>
<html lang="zh">
<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>
        a{
            /* 
            display 用来设置元素的显示类型
                可选值
                    inline 将元素设置为行内元素
                    block 将元素设置为块元素
                    inline- block 将元素设置为行内块元素
                    table 将元素设置为一个表格
                    none 元素不在页面中显示,并且不会占据页面的位置
            visibility 用来设置元素的显示状态
                可选值
                    visible 默认值,元素在页面中正常显示
                    hidden 元素在页面中隐藏,不显示,但是会占据页面的位置
            */
            display: inline-block;
            visibility: visible;
            background-color: yellowgreen;
            width: 100px;
            height: 100px;
        }
    </style>
</head>
<body>
    <a href="javascript:;">超链接</a>
</body>
</html>

清除浏览器默认样式

<!DOCTYPE html>
<html lang="zh">
<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>
    <!-- 引用外部充值样式表文件 -->
    <link rel="stylesheet" href="../资料/源码和资料/资料/重置样式表/reset.css">
    <style>
        /* 去除所有标签的默认样式 */
        *{
            margin: 0px;
            padding: 0px;
        }
        /* 去除项目符号 */
        ul{
            list-style: none;
        } 

        .box1{
            width: 100px;
            height: 100px;
            border: 1px black solid;
        }
    </style>


</head>
<body>
    <div class="box1"></div>
    <p>段落1</p>
    <p>段落1</p>
    <p>段落1</p>
    <ul>
        <li>列表项1</li>
        <li>列表项2</li>
        <li>列表项3</li>
    </ul>
</body>
</html>

清除浏览器默认样式外部css文件内容编写

reset.css

/* v2.0 | 20110126
  http://meyerweb.com/eric/tools/css/reset/ 
  License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
	vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
	display: block;
}
body {
	line-height: 1;
}
ol, ul {
	list-style: none;
}
blockquote, q {
	quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}
table {
	border-collapse: collapse;
	border-spacing: 0;
}
/* 去除超链接文字的下划线 */
text-decoration: none;
height: 25px;
/* 要让一个文字在父元素中垂直居中,只需要将父元素的line-height设置为和父元素height值相同即可 */
line-height: 25px;
/* 为了边框和文字宽度一致,需要将h2转换为块元素 */
display: inline-block;
/* 通过margin-top上移元素,盖住上边框 */
margin-top: -1px;
/* 设置文字字体加粗 */
font-weight: bold;
/* 选中li元素(除去最后一个li元素) */
.news-list li:not(:last-child) {
    margin-bottom: 17px;
}
/* 使用伪元素给li元素前面统一加上符号 */
.news-list li::before{
    content: '😶‍🌫️';
    margin-right: 4px;
}

计算盒子模型的尺寸

/* 
box-sizing 用来设置盒子尺寸的计算方式(设置width和height的作用)
	可选值
		border-content 默认值,高度和宽度用来显示内容区的大小
		border-box 高度和宽度用来设置显示可见框的大小
			width 和 height 指定的是 内容区+内边距+边框的总大小
*/
box-sizing: border-box;

轮廓和圆角

/* outline 用来设置元素的轮廓线,用法与border一样
轮廓与边框的不同点是,轮廓不会影响到可见框的大小 */
outline: skyblue 10px solid;
/* box-shadow 用来设置元素的阴影效果,阴影不会影响页面的布局
第一个参数值 水平偏移量
第二个参数值 垂直偏移量 
第三个参数值 阴影的模糊半径 
第四个参数值 阴影的颜色 */
box-shadow: 10px 10px 50px rgba(0, 0, 0, .5);
/* 
border-radius:0px
border-top-left-radius: 
border-top-right-radius: 
border-bottom-right-radius: 
border-bottom-left-radius: 
border-radius: x轴大小 / y轴大小;*/
border-radius: 20px / 40px;
/* 将元素设置成一个圆形 */
border-radius: 50%;

浮动

/* 
通过float属性,使一个元素向其父元素左侧或右侧浮动
元素设置浮动以后,会完全从文档流中脱离,不再占用文档流的位置,
所以元素下边还在文档流中的元素会自动向上移动
注意点:
	浮动元素默认不会从父元素中移出
	浮动元素向左或向右浮动时,不会超过它前面的其它浮动元素
	通过浮动,可以设置一些水平方向的布局            
	浮动元素不会盖住文字,文字会自动环绕在浮动元素的周围
	可以利用浮动属性设置文字环绕图片的效果
脱离文档流的特点: 
	1.块元素不再独占页面的一行
	2.脱离文档流后,块元素的高度和宽度默认都被内容撑开
	3.行内元素脱离文档流后,会变成块元素,和块元素特点一样
元素脱离文档流后,不再区分块元素和行内元素了
*/
float: left;
/* 将a元素转换为块元素,可以实现超链接可以点击的位置撑满父元素 */
display: block;

高度塌陷问题

/*
元素开启BFC的特点:
		1.开启BFC的元素不会被浮动元素所覆盖
		2.开启BFC元素的子元素和父元素的外边距不会重叠
		3.开启BFC的元素可以包含浮动的子元素
开启元素BFC的方法:
	将元素的overflow 设置为一个非 visible 的值
	常用的方法是 overflow:auto;
						 overflow:hidden
*/
/* 
通过clear属性来清除浮动元素对当前元素的影响
clear 可选值:
   left 清除左侧浮动元素对当前元素的影响
   right 清除右侧浮动元素对当前元素的影响
   both 清除两侧浮动元素中影响最大的那一侧
   ......
*/
clear: left;

高度塌陷完美的解决方案 clearfix

<!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>
        .box1{
            border: 10px red solid;
        }

        .box2{
            width: 200px;
            height: 200px;
            background-color: royalblue;
            float: left;
        }

        /* 
        解决高度塌陷的问题最完美的解决方案
        通过伪元素来解决
        */
        .box1::after{
            display: block;
            content: '';
            clear: both;
        }

        /* 解决外边框重叠问题 */
        .clearfix::before{
            content: '';
            display: table;
        }
        
        /* 解决高度塌陷问题 */
        .clearfix::after{
            content: '';
            display: table;
            clear: both;
        }
    </style>
</head>
<body>
    <div class="box1 clearfix">
        <div class="box2"></div>
    </div>
</body>
</html>

定位 position

/*
position属性可选值:
	static 默认值,元素是静止的,没有开启定位
	relative 元素开启相对定位
		元素不会脱离文档流,还会占用文档流的位置
		定位原点是本身位置的左上角
	absolute 元素开启绝对定位
		元素会脱离文档流,不会占用文档流的位置
		定位原点是相对于其包含块进行定位的
			包含块:
				正常情况下,包含块就是离当前元素最近的祖先块元素
				绝对定位的包含块:
					就是离当前元素最近的开启了定位的祖先块元素
					如果所有的祖先元素都没有开启定位,则根元素就是它的包含块
					html 就是根元素,也叫初始包含块
	fixed 元素开启固定定位
		元素会脱离文档流
		固定定位永远参照于浏览器视口进行定位.
		固定定位不会随着浏览器的滚动条进行滚动的.(可应用于 回到顶部按钮固定屏幕位置不动 的设置)
	sticky 元素开启粘滞定位
*/
/*
对于开启了定位的元素,可以通过z-index属性来设置元素的层级
z-index 需要一个整数设置层级,值越大,层级越高,元素越优先显示
如果元素的层级相同,则优先显示靠下的元素
祖先元素的层级再高也不会盖住后代元素
*/
/* transparent 颜色的是透明的 */
border: 2px solid transparent;
/* 将背景颜色值设置到内容区,边框和内边距不再有背景颜色 */
background-clip: content-box;

字体

<style>
        /* @font-face 可以将服务器中的字体直接提供给用户去使用 */
        @font-face {
            /* 自定义字体的名字 */
            font-family: 'myfont';
            /* 服务器中字体的位置,以下这两种引用方式都可以 */
            src: url(../资料/源码和资料/资料/字体/ZCOOLKuaiLe-Regular.ttf);
            src: url('../资料/源码和资料/资料/字体/ZCOOLQingKeHuangYou-Regular.ttf');

        }
        p{
            /* 设置字体格式 */
            font-family: monospace; 
            font-family: myfont;
          	/* 字体加粗  normal 是默认值,正常值*/
             font-weight: bold;
             /* 斜体 */
             font-style: italic;
          	/* 文字水平对齐方式 */
             text-align: right;
             /* 文字垂直方向对齐方式,也可以解决图片的距离问题 */
             vertical-align: top;
          /* 保留空白 */
            white-space: pre;

            /* 将多出来的文字用省略号代替显示 */
            width: 200px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        }
 </style>

图标字体

/*
下载font awesome 图标字体库: https://fontawesome.com/v5.15/how-to-use/on-the-web/setup/hosting-font-awesome-yourself
*/
    <!-- 引入图标字体css样式 -->
    <link rel="stylesheet" href="../资料/源码和资料/资料/字体/fontawesome-free-5.10.2-web/css/all.css">

</head>
<body>
    <!-- class="fas 图标名" 这个格式是固定的,class 类名分为fas 和 fab -->
    <i class="fas fa-bell"></i>
    <i class="fab fa-accessible-icon"></i>
</body>

<!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>
    <!-- 引用font-awesome css样式文件 -->
    <link rel="stylesheet" href="../资料/源码和资料/资料/字体/fontawesome-free-5.10.2-web/css/all.css">
    <style>
        li{
            list-style: none;
        }

        /* 通过伪元素选择器使用font- awesome图标字体 */
        li::before{
            /* content的编码在 zeal中下载font-awesome文档后查找 */
            content: '\f368';
            margin-right: 10px;
            /* 这两个参数是使用图标的固定写法 */
            font-family: 'Font Awesome 5 Free','Font Awesome 5 Brands';
            font-weight: 900;
        }
    </style>
</head>
<body>
    <ul>
        <li>少小离家老大回</li>
        <li>乡音无改鬓毛衰</li>
        <li>儿童相见不相识</li>
        <li>笑问客从何处来</li>
    </ul>

    <!-- 通过实体的方式使用font-awesome图标字体:格式为 &#x图标编码; -->
    <span class="fas">&#xf7b9;</span>
</body>
</html>

使用阿里的图标字体库

官方网址 https://www.iconfont.cn/

<!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>
    <!-- 引用下载到本地的图标字体样式文件 iconfont.css -->
    <link rel="stylesheet" href="../资料/源码和资料/资料/字体/font_1407860_2y84u0r8ova/iconfont.css">
<style>
    i{
        font-size: 100px !important;
    }

    /* 第三种方式,通过伪元素选择器 */
    p::before{
        content: '\e625';
        font-family: 'iconfont';
        font-size: 100px;
    }
</style>
</head>
<body>
    <!-- 第一种方式 -->
    <i class="iconfont">&#xe61c; </i>
    <!-- 第二种方式,通过字体类引用图标字体 -->
    <i class="iconfont icon-qitalaji"></i>

    <p>
        hello
    </p>
</body>
</html>

行高 line-height

/*
通常可以将行高设置为和高度 height 一样的值,用来实现垂直居中效果
行高还经常用来设置文字之间的行间距
行高指的是 单行的行高
*/

背景图片

<!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>
        .box1{
            width: 500px;
            height: 500px;
            /* 设置背景颜色 */
            background-color: tomato;
            /* 设置背景图片 */
            background-image: url(../资料/源码和资料/code/06_font&background/img/2.jpg);
            /* 设置背景图片的重复方式 no-repeat 表示不重复*/
            background-repeat: no-repeat;
            /* 
            设置背景图片的位置 
            通过方位词设置位置: left right top bottom center
            通过像素设置,水平偏移量 垂直偏移量
            */
            background-position: 0 0;
            padding: 10px;
            border: 10px red double;

            /* 
                设置背景的范围
                background-clip:
                                border-box 默认值,背景会出现在边框的下边
                                padding-box 背景不会出现在边框,只会出现在内容区和内边距
                                content-box 背景只会出现在内容区
                background-origin: 
                                  padding-box 默认值,background-position从内边距开始计算
                                  content-box 背景图片的偏移量从内容区开始计算
                                  border-box 背景图片的偏移量从边框处开始计算
                background-origin 排序必须要在 background-clip 前面
            */
            background-origin: border-box;
            background-clip: content-box;

            /* background-size 设置背景图片的大小 */
            background-size: contain;

            /* 
                设置背景图片是否跟随元素移动
                scroll 默认值,会跟随元素移动
                fixed 固定在页面中,不会跟随元素移动
            */
            background-attachment: scroll;
        }
    </style>
</head>
<body>
    <div class="box1"></div>
</body>
</html>

雪碧图的实现方式

a:link{
    display: block;
    width: 93px;
    height: 29px;
    background-image: url(../资料/源码和资料/资料/图片/按钮/btn.png);
}

/* 
    解决图片闪烁的问题
        可以将多个小图片保存在一个大图中,通过 background-position 来显示相应的图片
        这种方法俗称 雪碧图 css-sprite
*/
a:hover{
    background-position: -93px 0;
}

a:active{
    background-position: -186px 0;
}

线性渐变

/* 线性渐变,颜色沿着一条直线发生变化 */
background-image: linear-gradient(red,yellow);
/* to right 颜色从左向右渐变 */
background-image: linear-gradient(to right ,red,yellow);
/* deg 是偏转角度 */
background-image: linear-gradient(45deg ,red,yellow);
/* turn 表示圈 */
background-image: linear-gradient(0.3turn ,red,yellow);
/* 100px 表示颜色开始渐变过渡的起始位置 */
background-image: linear-gradient(red 100px,yellow 100px);
/* 可以平铺的线性渐变 */
background-image: repeating-linear-gradient(red 50px,yellow 100px);

径向渐变

/* 径向渐变 */
background-image: radial-gradient(red,yellow);

表格

<!-- table 表格 -->
<table>
    <!-- tr 表示行 -->
    <tr>
        <!-- td 表示列,colspan 表示横向合并单元格.rowspan 表示纵向合并单元格 -->
        <td colspan="2"></td>
        <td rowspan="2"></td>
    </tr>
</table>
<table>
    <!-- thead 表示单元格头部 -->
    <thead>
        <tr>
            <!-- th 用来表示头部单元格 -->
            <th>1</th>
            <td>2</td>
            <td>3</td>
        </tr>
    </thead>
    <!-- tbody 表示单元格主体 -->
    <tbody>
        <tr>
            <td>q</td>
            <td>w</td>
            <td>e</td>
        </tr>
    </tbody>
    <!-- tfoot 表示单元格顶部 -->
    <tfoot>
        <tr>
            <td></td>
            <td>合集</td>
            <td>3e</td>
        </tr>
    </tfoot>
</table>

表格的样式

table{
    width: 50%;
    border: 1px black solid;
    /* 指定表格中边框的距离 */
    border-spacing: 1px;
    /* 合并表格中的边框 */
    border-collapse: collapse;
}

td{
    border: solid 1px black;
    height: 50px;
    /* 默认情况下,是垂直居中的,可以通过 vertical-align 和 text-align 来调整 td 中的内容位置*/
    vertical-align: middle;
    text-align: center;
}

/* 隔行变色 */
tr:nth-child(2n){
    background-color: cadetblue;
}

.box1{
    width: 300px;
    height: 300px;
    background-color: coral;
    /* 将元素设置为单元格 td */
    display: table-cell;
    vertical-align: middle;
}
.box2{
    width: 100px;
    height: 100px;
    background-color: cyan;
    margin: 0 auto;
}

表单

<form action="../01/02.列表.html" autocomplete="off">
    <!-- 
        文本框中的name属性值是必须要指定的,
        autocomplete="off"关闭自动补全,
        readonly表单只读,无法修改,数据会提交
        disabled 禁用状态,数据不会提交
        autofocus 自动获取焦点
        -->
    <input type="text" name="username" autocomplete="off" value="洪晨" readonly disabled><br>
    <!-- 密码框 -->
    <input type="password" name="password" autofocus><br>
    <!-- 提交按钮 -->
    <input type="submit" value="登陆">
    <!-- 重置按钮 -->
    <input type="reset">
    <br>
    <!-- 单选框, name属性值一定要相同,才会实现单选效果,
        checked 默认选中效果-->
    男<input type="radio" name="q1" value="boy" checked>
    女<input type="radio" name="q1" value="girl"><br>
    <!-- 多选框,name属性值一定要相同,checked表示默认选中-->
    <input type="checkbox" name="q2" value="1">
    <input type="checkbox" name="q2" value="2">
    <input type="checkbox" name="q2" value="3" checked><br>
    <!-- 下拉列表,selected 默认选中 -->
    <select name="qwer">
        <option value="1">前端</option>
        <option value="2">长沙</option>
        <option value="3" selected>汽车</option>
        <option value="4">买房</option>
    </select><br>
    <!-- 普通按钮 -->
    <input type="button" value="按钮"><br>
    <!-- 按钮元素 -->
    <button type="submit">提交</button>
    <button type="reset">重置</button>
    <button type="button">按钮</button>
    <br>
    <!-- email电子邮件输入框 -->
    <input type="email">
</form>
/* 设置样式过渡效果, width或者height必须要设置为 0px */
transition: height 2s;
/* 创建小三角 */
width: 0px;
height: 0px;
/* transparent 透明色 */
border: 7px solid transparent;
border-top: none;
border-bottom-color: #fff;
/* 首行缩进,也可以用作隐藏文字 */
text-indent: -9999px;

隐藏元素的两种方式

/*方式一,可搭配 transition 使用,设置过渡的效果,*/
height: 0px;
overflow: hidden;
/*方式二*/
display:none;
/* 设置input获取焦点后的样式 */
.search-wrapper .search-inp:focus{
    /* outline 轮廓线 */
    outline: 1px solid #ff6700;
}

设置网站图标

<!-- 设置网站的图标 -->
<link rel="icon" href="../../资料/源码和资料/code/mi/favicon.ico">

压缩css文件

  1. 安装JS & CSS Minifier (Minify) 插件
  2. 按 F1,选择 Minify Document, 就可以压缩文件了

过渡效果

/* 过渡效果 */
transition: all 2s;
/* 过渡时间2秒,分三步骤过渡 */
transition: 2s steps(3);

动画

.box2 {
    background-color: springgreen;
    /* 为 box2 指定动画关键帧名字 */
    animation-name: test;
    /* 动画执行的时间 */
    animation-duration: 2s;
    /* animation-direction 指定动画运行方向 */
    animation-direction: alternate;
    /* 
    animation-iteration-count: 动画执行的次数
        infinite 无限循环次数 */
    animation-iteration-count: infinite; 
    /* animation-play-state: 设置动画的执行状态 */
    animation-play-state: running;
    /* animation-fill-mode: 动画的填充模式 */
    animation-fill-mode: forwards;
    /* 简写模式 */
    animation: run 1s steps(6) infinite;
    
}

/* 动画的关键帧 */
@keyframes test {

    /* 表示动画开始的位置 from 也可以使用 0% 表示*/
    from {
        margin-left: 0px;
    }

    /* 表示动画结束的位置 to 也可以使用 100% 表示*/
    to {
        margin-left: 500px;
    }
}

变形

/* transform 变形用来改变元素的形状或位置,变形不会影响其它元素 */
/* 可以通过这四种属性一起设置元素水平垂直居中,作用域是相对于元素的包含块 */
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);

.box2{
    width: 200px;
    height: 200px;
    background-color: plum;
    transition: all 1s;
}

.box2:hover{
    /* 可以设置浮出效果 */
    transform: translateY(-5px);
    /* 要加上阴影 */
    box-shadow: 0 0 10px rgba(0, 0, 0, .5);
}

旋转

<style>
    html {
        /* 当前网页的视距是800px,人眼距离网页的距离
        做3D效果时,一定要写上 perspective 属性 */
        perspective: 800px;
    }

    body{
        border: 1px red solid;
    }
    .box1 {
        width: 200px;
        height: 200px;
        background-color: palevioletred;
        transition: 2s;
        margin: 100px auto;
    }

    body:hover .box1{
        /* rotate 旋转 */
        /* transform: rotateZ(45deg) translateZ(100px); */
        transform: rotateY(180deg);
        /* 设置是否显示元素的背面,hidden为不显示 */
        backface-visibility: hidden;
    }
</style>
/* 设置3D变形效果 */
transform-style: preserve-3d;
/* 为元素设置透明效果 */
opacity: 0.7;
/* 透明度为0,也可以实现隐藏元素 */
opacity: 0;

缩放

/* scale 缩放 */
transform: scale(2);
/* 设置变形的原点 */
transform-origin: center;

现在vs code中安装 Easy LESS 插件,然后创建 .less 文件

less变量

// 变量 @变量名
// 变量存在优先级问题,遵循就近原则
@a: 100px;
@color: red;
// 创建类名变量
@b: box2;

.box1 {
    // 使用变量
    width: @a;
    height: @a;
    background-color: rebeccapurple;
}

// 使用类名变量
.@{b} {
    width: @a;
    height: @a;
    background-color: @color;
    // url()中使用类名,单引号双引号都可以
    background-image: url('@{b}/1.png');
}

.box1 {

    // 使用子元素选择器
    >.box2 {
        width: 200px;
    }

    // & 表示外层的父元素
    &:hover {
        background-color: @color;
    }
}

.p1 {
    width: 200px;
    height: 200px;
}

// extend() 对当前选择器扩展指定选择器的样式
// 在p1的样式上进行扩展
.p2:extend(.p1) {
    background-color: blanchedalmond;
}

// 对指定样式进行引用
.p3 {
    // p3 直接复制 p1 的样式 (mixin 混合)
    .p1();
}

// 使用类选择器时可以在后面添加一个括号,这时我们实际上就创建了一个mixins
// p4不会在css文件中显示,是拿来给p5引用的
.p4() {
    width: 200px;
    height: 200px;
    color: slateblue;
}

.p5 {
    .p4();
}
// 混合函数,在混合函数中可以直接使用变量
// 可以设置默认值
.test(@w:100px,@h:200px) {
    width: @w;
    height: @h;
    background-color: red;
}

// 使用混合函数
div {
    .test(200px);
}

/* 定义一个混合函数 */
.test(@w:100px,@h:100px,@c:red){
    width: @w;
    height: @h;
    background-color: @c;
}

#warp {
    #inner {
        /* 指定参数传参 */
        .test(@c:pink);
    }
}

/* 匹配模式 @_ */
.triangle(@_,@w,@c){
    width: 0;
    height: 0;
}
.triangle(T,@w,@c){
    
    border-width: @w;
    border-style: solid;
    border-color: transparent transparent @c transparent;
}

span{
    // 取两个颜色的平均值
    color: average(red,blue);
}

// 引入其它的less样式
@import url(
    './index.css'
);
body{
    // 在less中,所有数值均可进行 加 减 乘 除 的运算
    width: 200px - 100px;
    height: 200px;
    background-color: blue;
    // 使用除法
    width: 100vw./750;
		height: 500px./3;
}

less继承

  1. 创建一个混合函数

    .juzhong{
        position: absolute;
        left: 0px;
        right: 0px;
        top: 0px;
        bottom: 0px;
        margin: auto;
    }
    
    .juzhong:hover{
        background-color: yellow !important;
    }
    
  2. 在less中继承该函数

    * {
        margin: 0px;
        // ~"" 避免编译,会将双引号里面的内容完整的输出到css文件中
        padding: ~"cacl(100px+100)";
    }
    
    // 导入juzhong混合函数
    @import url('./mixin/juzhong.less');
    
    #wrap {
        position: relative;
        width: 300px;
        height: 300px;
        border: 1px solid black;
        margin: 0px auto;
    
        .inner {
            // 继承juzhong混合函数, all 表示继承全部的状态
            &:extend(.juzhong all);
    
            &:nth-child(1) {
                width: 100px;
                height: 100px;
                background-color: red;
            }
    
            &:nth-child(2) {
                width: 50px;
                height: 50px;
                background-color: pink;
            }
        }
    }
    

混合函数和继承函数最大的区别就是,继承函数不可以带形参

vscode 设置css对应的less代码位置

设置-->扩展-->easy less configuration -->在setting.json中编辑,添加如下代码

"less.compile": {
        "compress": true, // true => remove surplus whitespace
        "sourceMap": true, // true => generate source maps (.css.map files)
        "out": true // false => DON'T output .css files (overridable per-file, see below)
      }

flex布局

/* 将ul设置为弹性容器,弹性容器的子元素被称为弹性元素 */
display: flex;
/* flex-direction 用来设置弹性元素的排列方向 */
flex-direction: row;
/* 弹性元素的伸展系数 */
flex-grow: 1;
/* 弹性元素的收缩 */
flex-shrink: 2;
flex:none,使项目不能被压缩或放大。
在flex:1 时在尺寸不足时会优先最小化尺寸,flex:auto在尺寸不足时优先最大化内容尺寸。
display: flex;
/* 设置元素自动换行 */
flex-wrap: wrap;
/* flex-flow 是 flex-wrap 和flex-direction 的简写属性 */
flex-flow: row wrap;
/* 设置主轴上的元素如何排列 */
justify-content: center;
/* 元素在辅轴上对齐方式 */
align-items: center;
/* 设置元素辅轴上的空白空间分布 */
align-content: center;
/* 设置flex子元素垂直水平居中对齐 */
align-items: center;
justify-content: center;
/* 弹性元素用来覆盖掉弹性容器的 align-items 的样式 */
align-self: flex-end;
/* 元素的基础长度,指的是元素在主轴上的基础长度 */
flex-basis: 100px;
/* order 决定元素的排列顺序 */
order: 3;

移动端

移动端的网页都会将视口像素默认设置为980像素(css像素)
<!-- 
    将网页的视口设置为完美视口
    width=device-width 宽度为设备宽度
    initial-scale=1.0 缩放率为1倍
    -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
/* 
    100vw 表示移动端视口的宽度
    1vw 表示 1% 的视口宽度
*/
width: 100vw;

rem 换算 px 计算方式

假设设计图宽度为 750px
100vw / 750px = 0.133333333
此时 1px = 0.133333333vw
因为浏览器中规定 font-size 最小值为 12px
所以 10px = 1.333333vm 小于 12px, 浏览器无法显示
再扩大,比如再扩大4倍 40px=5.33333vw=1rem
此时的屏幕宽度为 750px / 40px = 18.75rem,
此后,只需要将设计图的像素 / 40px 进行计算即可.
将 rem单位设置为 font-size: 5.33333333vw;
width: 1rem;
rem(font size of the root element)是指相对于根元素(html元素)的字体大小的单位。

媒体查询

/* 当视口最小宽度为400px时,背景颜色是cyan */
@media only screen and (min-width:400px) and (max-width:900px) {
    body {
        background-color: cyan;
    }
}
// 警告框
alert("这是一个警告框");
// 向body中输出一段内容
document.write("这是一段文字");
console.log("向控制台输出一段内容");
<!-- 引入外部的js文件 -->
<script src="./script.js"></script>
<!-- 可以将js代码写到onclick属性中 -->
<button onclick="alert('这是一个警告框')">点我一下</button>

字符串变量

// 声明变量
var a = 1;
// 声明字符串变脸
var str="helloworld";
// 在字符串中用 \ 表示转义字符
/*
    \n 表示换行
    \t 表示制表符,相当于按了tab键
    \\ 表示 \
*/
var str="子曰:\"学而时习之,不亦说乎\"";

数字变量

// 声明数字类型
var a=123;
// 声明字符串类型
var b="123"
// typeof 用来检查变量的数据类型
console.log(typeof a);
// 用来检查js中可以显示的number的最大值
console.log(Number.MAX_VALUE);

数据类型强制转换

/*
    将其他类型强制转换为 string类型
    方法一:
        调用toString()方法
    方法二:
        调用String()函数
*/
var a = 123;
a = a.toString();
a = 456;
a = String(a);

// 其他类型强制转换为 number 类型
var b = "123";
// 方式一:使用Number()函数
b = Number(b);
b = "780.89hello";
// parseInt 将字符串转换为整数
b = parseInt(b);
// parseFloat 可以将字符串转换为浮点数 
b = parseFloat(b);
var b = 123;
// 0x 开头表示 16进制数字
// 123 的 16进制数
b = 0x123;
// 0 开头表示 8进制数字
b = 070;
// 0b开头表示 2进制数字,但是好多浏览器不支持
b = 0b10;
b="070";
// 将b以10进制的方式转换成整数
b=parseInt(b,10);
/*
    调用Boolean()函数将其他类型转换为boolean值
    数字---》布尔
        除了0和NaN,其余都是true
    字符串---》布尔
        除了空值,其余都是true
    null和undifined,其余都是true
    对象也会转换为true
*/
var b=123;
b=Boolean(b);
// 赋值运算
a=a+5 等价于 a+=5;
// 在javascript中的字符串中使用转义字符输出unicode编码.语法: \u四位unicode编码(十六进制编码)
console.log("\u2620");
<!-- 
    在html中使用unicode编码,这里需要的编码是十进制的
-->
<h1>&#9760;</h1>
/*
    可以通过isNaN()函数来判断一个值是否为 NaN
    === 全等,和相等类似,但是不会做数据类型转换
    !== 不全等
*/

/*
    三元运算符
    条件表达式?语句一:语句二
        条件表达式为true,输出语句一
        条件表达式为false,输出语句二
*/
1>2?console.log("大"):console.log("不大");
/*
    prompt()函数:
    会弹出一个提示框,该提示框中会带有一个文本框
    用户可以在文本框中输入内容
    该函数需要一个字符串作为参数,该字符串将会作为提示框的提示文字 
*/
var b=prompt("请输入一个数字:");

switch case 语句

var a = prompt("请输入一个数字");
        a = Number(a);
        switch (a) {
            case 1:
                alert("星期一");
                break;
            case 2:
                alert("星期二");
                break;
            case 3:
                alert("星期三");
                break;
            case 4:
                alert("星期四");
                break;
            case 5:
                alert("星期五");
                break;
            case 6:
                alert("星期六");
                break;
            case 7:
                alert("星期日");
                break;
            default:
                alert("请输入有效日期数字");
                break;

        }

while循环

var i = 0;
while (i < 10) {
    document.write(i + "<br>");
    i++;
}

// do{}while()是先执行一次,在判断
var b = 10;
do {
    document.write(b + ",你好<br>");
} while (b < 5);

// break 终止循环

for循环

for (var i = 0; i < 10; i++) {
    alert(i);
}

// for循环的死循环
for(;;){
    alert("这是死循环");
}
/*
    可以为循环指定一个label,来标识当前循环
    break 默认终止离它最近的一个循环
*/
// console.time(),开启一个计时器,需要一个字符串作为参数,这个字符串作为计时器的标识
console.time("test");
outer:
for(var a=1;a<5;a++){
    inner:
    for(var b=2;b<5;b++){
        console.log(b);
        break outer; // 终止指定的外层循环
        continue; // 可以用来跳过当次循环,默认也是跳过离它最近的一次循环
    }
}
// 关闭计时器
console.timeEnd("test");
// Math.sqrt()可以对一个数进行开方运算
alert(Math.sqrt(36));

对象

/*
    使用new关键字调用的函数,是构造函数constructor
*/
var obj = new Object();
// 向对象中添加属性值
obj.name = "洪晨";
obj.address = "沈阳市";

// 检查obj对象中有没有 age 属性
console.log("age" in obj);

// 创建特殊的属性名
obj["123"]="特殊属性名";
var a="123"
console.log(obj["123"]);
console.log(obj[a]);

// 删除对象属性名
delete obj.name;
// 读取对象属性
console.log(obj);
/*
    基本数据类型,stirng number boolean值 null undefined 变量值保存在栈内存中
    引用数据类型,object,在栈中保存的是堆中的地址,对象是保存在堆内存中
*/

栈内存

var b=123
变量名 变量值
b 123

堆内存

var obj=new Object();
obj.name="honksun";
变量名 堆内存地址 堆内存
obj 0x123 内存地址 0x123 对象属性
// 使用字面量来创建一个对象
var obj = {};
obj.name = "123";
console.log(obj.name);
var obj2 = { name: "123", age: 25, address: "沈阳市" };
console.log(obj2);

函数

// 是有构造函数创建一个函数,不推荐使用
var fun = new Function("console.log('你好');");
// 调用函数
fun();

// 使用函数声明创建函数
function test() {
    console.log("这是使用函数声明创建的函数");
}

test();

// 使用函数表达式来创建一个函数
var fun3 = function(){
    console.log("nihao");
        };

fun3();
// 创建函数时创建形参
function fun(a, b) {
    console.log(a + b);
}
// 调用函数时传递实参
fun(100, 300);

function fun2(a,b,c){
    var d=a+b+c;
    return d;
}

// 创建变量,接收函数返回值
var result=fun2(1,2,3);
console.log(result);

// 调用函数对象
fun(fun2);
// 调用函数返回值
fun(fun2());

// 创建立即执行的匿名函数,这种函数只能执行一次
(function(){
    console.log("这是一个匿名函数");
})();
function fun() {
    console.log("nihao");
}
var obj = {
    name: "hongchen",
    // 对象中引用外部函数,无需加括号,只需写上函数名即可
    sayHello:fun,
    address:"nihao"
}

枚举,for...in语句

var obj = {
    name: "hongchen",
    age: 28,
    gender: "man",
    address: "shenyang"
}

// for...in 枚举对象中的属性
for (var n in obj) {
    // n 是属性
    // obj[n] 是属性值
    console.log(n+":"+obj[n]);
}

this

/*
    解析器在调用函数时,每次都会向函数内部传递进一个隐含的参数,
    这个隐含参数就是this,this指向一个对象,
    这个对象我们称为函数执行的上下文对象
    根据函数调用的方式不同,this会指向不同的对象
    以函数方式调用,this永远指向window
    以方法方式调用,this就是调用方法的那个对象
*/
function fun(){
    console.log(this);
}

fun();
var name="hongchen";
function fun(){
    console.log(this.name);
}

var obj={
    name:"洪晨",
    sayName:fun
}

obj.sayName();

构造函数

// 创建构造函数,一般是首字母大写
function Person(name, age) {
    // 在构造函数中可以使用this来引用新建的对象
    this.name = name;
    this.age = age;
}
// 向Person的原型属性中添加一个方法
Person.prototype.sayHello = function () {
    alert("我是:" + this.name);
}
// 调用构造函数
var per = new Person("hongchen", 28);
console.log(per.name);
// per.sayHello();

// 通过 instanceof 可以检查一个对象是否是一个类的实例
console.log(per instanceof Person);
Person.prototype.address = "沈阳市";
// 使用 in 关键字检查对象中是否含有某个属性,如果对象中没有但是原型元素中有,也会返回true
console.log("address" in per);
// 使用 hasOwnProperty()检查对象自身中是有含有该属性
console.log(per.hasOwnProperty("address"));
/*
    this的情况
    1.当以函数的方式调用时,this就是window
    2.当以方法的方式调用时,谁调用,this就是谁
    3.当以构造函数方式调用时,this就是新创建的那个对象
*/

toString()方法

function Person(name,age,address){
    this.name=name;
    this.age=age;
    this.address=address
}

// 修改类中的toString()方法
Person.prototype.toString = function(){
    return "Person[name:"+this.name+",age:"+age+",address:"+this.address+"]";
}
var per=new Person("洪晨",28,"沈阳市");
console.log(per);

GC垃圾回收

/* 我们只需要将类设置为null,就可以被GC回收 */
var obj=new Object();
obj=null;

数组

// 创建数组 
var arr = new Array();
// 通过数组索引(数组索引都是0开始)向数组中添加值
arr[0] = 10;
arr[1]="hongchen"
console.log(arr[1]);
// 获取数组的长度 length
console.log(arr.length);
// 修改length的长度
arr.length=1;
console.log(arr);
// 向数组的最后一个位置添加元素
arr[arr.length]="沈阳市";
console.log(arr);
// 使用字面量创建数组
var arr=[];
console.log(arr);

数组的方法

var arr=["科比","乔丹"];
// push()该方法可以向数组的末尾添加一个或多个元素,并返回数组的新长度
arr.push("詹姆斯",1,2);
// pop() 该方法可以删除数组的最后一个元素,并将删除的元素作为返回值返回
arr.pop();
// unshift() 该方法向数组开头添加一个或多个元素,并返回新的数组长度
arr.unshift("NBA");
// shift() 该方法可以删除数组中第一个元素,并将删除的元素作为返回值返回
arr.shift();
var arr=["科比","乔丹","詹姆斯","杜兰特"];
// slice(start,end),该方法可从已有的数组中返回选定的元素
// start:从何处开始
// end:从何处结束
console.log(arr.slice(1,3));
// splice(),该方法删除数组中指定的元素,并可以使用新的元素替换删除的元素位置
arr.splice(0,2,"哈登","库里")
var arr=["nba","cba"];
var arr1=["科比","乔丹"];
// concat() 可以连接两个或多个数组,并作为新的数组返回
var result = arr.concat(arr1);
// join(), 该方法将数组转换为字符串,并用,分割
var result01=result.join();
// reverse() 反转数组,颠倒数组元素的排列顺序
var result2=result.reverse();
// sort() 对数组进行拍排序
result.sort();
// 自定义排序规则
result.sort(function(a,b){ // 回调函数
    // 前面的数值大
    if(a>b){
        return 1; // 交换位置
    }else if(a<b){
        return -1;  // 不交换位置
    }else{
        return 0;
    }

    // 简洁办法
    return a-b; // 升序排序
});

遍历数组

var arr=[1,2,3,4,5];
// 遍历数组
for(i=0;i<arr.length;i++){
    console.log(arr[i]);
}

var arr = [1, 1, 2, 3, 3, 4, 3, 4, 5];
/*
    forEach()遍历数组,回调函数,该方法IE8及以下版本不支持
        第一个参数 value :当前正在遍历的元素
        第二个参数 index :当前正在遍历的元素的索引
        第三个参数 obj :当前正在遍历的数组对象
*/
arr.forEach(function (value, index, obj) {
    console.log(value);
})

去除一维数组中重复的数字练习

var arrList = [1, 2, 3, 4, 3, 3, 4, 5];
for (i = 0; i < arrList.length; i++) {
    for (j = i + 1; j < arrList.length; j++) {
        if (arrList[i] == arrList[j]) {
            arrList.splice(j, 1);
            j--;
        }
    }
}

函数的调用方式

function fun(){
    console.log("hello");
}

// 调用函数的三种方式
fun();
fun.call();
fun.apply();
function fun() {
    // arguments 是一个对应于传递给函数的参数(实参)的类数组对象
    console.log(fun.arguments);
}

fun();

Date()对象

参考w3cschool 方法详解

https://www.w3school.com.cn/jsref/jsref_obj_date.asp

Math()对象

https://www.w3school.com.cn/jsref/jsref_obj_math.asp

String()字符串相关方法

https://www.w3school.com.cn/jsref/jsref_obj_string.asp

正则表达式

/*
    创建正则表达式对象
    var 变量=new RegExp("正则表达式","匹配模式");
        i:表示忽略大小写
        g:全局检索
*/
var reg = new RegExp("a", "i"); // 表示检查字符串中是否含有 a 
// 使用字面量创建正则表达式
var reg2 = /a/i;
// 创建一个正则表达式,用来检查字符串是否有 a或b
var reg = new RegExp("a|b");
/*
    检查字符串中是否含有字母
    [A-z] : 任意字母
    [A-Z] : 任意大写字母
    [a-z] : 任意小写字母
    [0-9] : 任意数字
    [^ab] : 查找任何不在方括号之间的字符。
*/
reg = /[A-z]/;
// 检查字符串中是否含有 abc或aec或adc
reg=/a[bed]c/;
var str = "abcd";
// 使用test()方法可以检查字符串是否符合正则表达式的规则
console.log(reg.test(str));
var str="1a2b3c4d5e6f";
// split(),根据任意字母拆分字符串.方法中可以传递一个正则表达式作为参数
var result=str.split(/[A-z]/);
str="hello abc aec afc";
// search(),搜索字符串中是否含有 abc或aec或afc
result=str.search("a[bef]c");
// 将字符串中符合条件的内容提取出来
str="1a2b3c4d5e6f";
result=str.match(/[A-z]/g);
// replace(),将字符串中指定内容替换成新内容
result=str.replace(/[A-z]/g,"$");
console.log(result);
/*
    量词,可以设置一个内容连续出现的次数
        {n} 表示正好出现n次
        {m,n} 出现m-n次
        {m,} 出现m次以上
        \w 任意字母、数字、_
        \W 除了任意字母、数字、_
        \d 任意数字
        \D 除了任意数字
        \s 空格
        \S 除了空格
        \b 单词边界
        \B 除了单词边界
*/
var reg = /a{3}/;
reg = /(ab){3}/;  // ababab
reg=/ab+c/; // + 至少一次,相当于{m,}
reg=/ab*c/; // * 0个或多个,相当于{0,}
reg=/ab?c/; // ? 0个或1个,相当于{0,1}
reg=/^a/;   // ^ 检查是否以a开头的字符串
reg=/a$/;   // $ 检查是否以a结尾的字符串
reg=/^1[3-9][0-9]{9}$/; // 手机号的正则表达式
reg=/\./;   // 检查字符串中是否含有 . 因为.表示任意字符,所以需要 \.进行转义
reg=/\bchild\b/;    // 检查字符串中是否含有单词 child
var str="    hell  o     ";
// 去除字符串两端的所有空格
str=str.replace(/^\s*|\s*$/g,"")
// 电子邮件正则表达式
reg=/^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/;

DOM对象

<button id="btn">这是一个按钮</button>
<script>
    // 获取button对象
    var btn = document.getElementById("btn");
    // 修改按钮的文字
    btn.innerHTML="button";
    // 绑定一个事件
    btn.onclick=function(){
        alert("good night!");
    };
</script>
<script>
    // onload 事件会在整个页面加载完毕之后才触发
    window.onload = function () {
        // 获取button对象
        var btn = document.getElementById("btn");
        // 修改按钮的文字
        btn.innerHTML = "button";
        // 绑定一个事件
        btn.onclick = function () {
            alert("good night!");
        };
    }
</script>
</head>

<body>
	<button id="btn">这是一个按钮</button>
</body>
// 通过id名获取元素节点
document.getElementById();
// 根据标签名获取一组元素节点对象,返回的是一个类数组对象
document.getElementsByTagName();
// 通过name属性名获取一组元素节点对象
document.getElementsByName();
// innerHTML 用于获取元素内部的html代码,对于自结束标签没有意义
var btn=document.getElementById("btn");
// 返回当前节点的指定标签名后代节点
btn.getElementsByTagName();
// 表示当前节点的所有子节点,包括文本在内的所有节点,标签空白也会被当成文件节点
btn.childNodes;
// 获取当前元素的所有子元素
btn.children;
// 获取当前元素的第一个子节点
btn.firstChild;
// 获取当前元素的第一个子元素
btn.firstElementChild;
// 获取当前元素的最后一个子节点
btn.lastChild;
// 当前节点的父节点
btn.parentNode;
// 当前节点的前一个兄弟节点
btn.previousSibling;
// 当前节点的前一个兄弟元素
btn.previousElementSibling;
// 当前节点的后一个兄弟节点
btn.nextSibling;
// innerText,该属性可以获取到元素内部的文本内容
// checked属性设置或返回checkbox是否被选中,true为选中,false为不选中
// 设置全选状态
items[i].checked = true;
var a;
// 获取body标签
a = document.body;
// 获取html根标签
a = document.documentElement;
// 获取页面中所有的元素
a=document.all;
// 根据元素的class属性值查询一组元素节点对象
a=document.getElementsByClassName("");
/*
	document.querySelector 可以根据一个css选择器来查询一个元素节点对象,
	但是该方法只会返回唯一的一个元素,如果满足条件的元素有多个,那么它只会返回一个
*/
a=document.querySelector("");
// 这个方法就会返回一个数组对象
a=document.querySelectorAll("");
// document.createElement 用于创建一个元素节点对象
var li = document.createElement("li")
// document.createTextNode 用于创建一个文本节点
var text = document.createTextNode("广州")
// appendChild 把新的子节点添加到指定节点中
li.appendChild(text);
li.innerHTML = "广州";
// 使用 innerHTML += 也可以实现添加元素效果
li.innerHTML += "<li>广州</li>"
/*
	推荐方式
		var li =document.createElement("li")
		li.innerHTML="广州";
		city.appendChild(li);

*/
/*
	insertBefore() 在指定的子节点前面插入新的子节点
	语法:
		父节点.insertBefore(新节点,旧节点)

	replaceChild() 替换节点
	语法:
		父节点.replaceChild(新节点,旧节点)

	removeChild() 删除节点
	语法:
		父节点.removeChild(子节点)
	直接查找父节点然后调用删除方法
	li.parentNode.removeChild() 
*/
// 通过js修改css样式,像这种通过style属性修改和读取,都是内联样式的属性值,无法修改和读取样式表中的属性值
   box1.style.width="400px";
   // 修改颜色属性
   box1.style.backgroundColor="red";
   // 读取css样式
   alert(box1.style.width)
var box1 = document.getElementById("box1");
var btn1 = document.getElementById("btn1");
var btn2 = document.getElementById("btn2");
btn1.onclick = function () {
    /*
        获取当前元素的显示样式属性值
        只有IE和Opera支持使用CurrentStyle获取的元素计算后的样式。
        getComputeStyle()方法可以获取当前元素所使用的css属性值。
        alert(box1.currentStyle.width);
        var obj=getComputedStyle(box1,null);
        alert(obj.width);
    */
    // 获取当前元素样式属性值得兼容函数
    function getStyle(obj,name){
        if(window.getComputedStyle){
            // 只有[]这种形式既可以使用字符串也可以变量或表达式创建属性或者读取属性。
            return getComputedStyle(obj,null)[name];
        }else{
            return obj.currentStyle[name]
        };
    };
/*
    clientHeight 返回元素的可见高度。
    clientWidth	返回元素的可见宽度。
    offsetHeight 返回元素的高度。
    offsetWidth	返回元素的宽度。
    offsetParent 返回元素的偏移容器,获取当前元素开启定位的最近的祖先元素
    offsetLeft	返回元素相对于其定位父元素的水平偏移位置。
    offsetTop	返回元素相对于其定位父元素的垂直偏移位置。
    scrollHeight	返回元素的整体高度。
    scrollLeft	返回元素左边缘与视图之间的距离。
    scrollTop	返回元素上边缘与视图之间的距离。
    scrollWidth	返回元素的整体宽度。
    scrollHeight - scrollTop == clientHeight,说明垂直滚动条滚动到底部了
*/
alert(box1.offsetLeft);

<!-- 
    disabled="disabled"设置为表单项不可用状态.
    disabled 设置或返回 checkbox 是否应被禁用。
-->
<input type="checkbox" disabled="disabled"/>已仔细阅读协议
<input type="submit" disabled="true">

事件

// onmousemove	当指针在元素上方移动时,发生此事件。
arr.onmousemove = function (event) {
    /*
        clientX	返回触发鼠标事件时,鼠标指针相对于当前窗口的水平坐标。
        clientY	返回触发鼠标事件时,鼠标指针相对于当前窗口的垂直坐标。
    */
    // 方式一,解决兼容性问题
    if (!event) {
        event = window.event;
    }
    // 方式二,解决兼容性问题
    event = event || window.event;
    var x = event.clientX;
    var y = event.clientY;

    show.innerHTML = "X=" + x + ",y=" + y;
};

鼠标跟随事件

window.onload = function () {
    var box1 = document.getElementById("box1");
    document.onmousemove = function (event) {
        event = event || window.event;
        // 获取滚动条滚动的距离,需要解决兼容性问题
        var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
        var scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
        /*
            pageX	返回触发鼠标事件时鼠标指针相对于文档的水平坐标。
            pageY	返回触发鼠标事件时鼠标指针相对于文档的垂直坐标。
        */
        var left = event.clientX;
        var top = event.clientY;

        box1.style.left = left + screenLeft + "px";
        box1.style.top = top + scrollTop + "px";
    };
};

冒泡事件

s1.onclick = function (event) {
	event = event || window.event;
	alert("span");
	// 取消冒泡事件
	event.cancelBubble = true;
};

事件的委派

/*
    事件的委派
        将事件统一绑定给元素的共同祖先元素,这样后台元素上的事件触发式,会一直冒泡到祖先元素,
        从而通过祖先元素的响应函数来处理事件
*/
u1.onclick=function(event){
    // 解决兼容性问题
    event=event||window.event;
    // target	返回触发事件的元素。
    if(event.target.className=="link"){
        alert("nihao");
    };
    
};

事件的绑定

/*
    addEventListener() 也可以为一个元素同时绑定多个响应函数.(这个方法IE8及以下不支持)
    attachEvent() 只有IE1~10版本支持
    解决兼容性问题
    参数
        obj 要绑定的事件对象
        eventStr 事件的字符串(不加on)
        calllBack 回调函数
*/
function bind(obj,eventStr,calllBack){
    if(obj.addEventListener){
        obj.addEventListener(eventStr,calllBack,false);
    }else{
        obj.attachEvent("on"+eventStr,function(){
            calllBack.call(obj);
        });
    }
};

元素拖拽事件

/*
    onmousedown	当用户在元素上按下鼠标按钮时,发生此事件。
    onmousemove	当指针在元素上方移动时,发生此事件。
    onmouseup	当用户在元素上释放鼠标按钮时,发生此事件。
*/
// 提取公用拖拽函数
function drag(obj) {
    obj.onmousedown = function (event) {
        // 设置box1捕获所有鼠标按下事件,针对IE8及以下
        // if (box1.setCapture) {
        //     box1.setCapture();
        // }
        obj.setCapture && obj.setCapture();

        event = event || window.event;
        // 求出div的偏移量
        var ol = event.clientX - obj.offsetLeft;
        var ot = event.clientY - obj.offsetTop;
        document.onmousemove = function (event) {
            event = event || window.event;
            var left = event.clientX - ol;
            var top = event.clientY - ot;
            obj.style.left = left + "px";
            obj.style.top = top + "px";
        };

        document.onmouseup = function () {
            document.onmousemove = null;
            document.onmouseup = null;
            // 当鼠标松开时,取消对事件的捕获,针对IE8及以下
            obj.releaseCapture && obj.releaseCapture();
        };
        // 在函数的最后直接写return false,可以取消浏览器默认行为(对IE8及以下没用)
        return false;
    };
};

鼠标滚轮事件

// onwheel	当鼠标滚轮在元素向上或向下滚动时,发生此事件。
box1.onwheel = function (event) {
event = event || window.event;
// event.wheelDelta 可以获取鼠标滚轮滚动的方向(火狐浏览器不支持),正值向上,负值向下
// event.detail 可以获取鼠标滚轮滚动的方向(仅支持火狐浏览器),正值向下,负值向上
if (event.wheelDelta > 0 || event.detail < 0) {
    // 向上滚
    box1.style.height = box1.clientHeight - 10 + "px";
} else {
    // 向下滚
    box1.style.height = box1.clientHeight + 10 + "px";
}

// 取消浏览器默认行为,这个是针对addEventListener()起作用
event.preventDefault && event.preventDefault();
// 取消浏览器默认行为,这种方法对 addEventListener()不起作用
return false;
};

// 为火狐浏览器解决鼠标滚轮兼容性问题
bind(box1, "DOMMouseScroll", box1.onwheel);

// 公用绑定函数
function bind(obj, eventStr, calllBack) {
    if (obj.addEventListener) {
        obj.addEventListener(eventStr, calllBack, false);
    } else {
        obj.attachEvent("on" + eventStr, function () {
            calllBack.call(obj);
        });
    }
};

键盘事件

/*
    onkeydown	当用户正在按下键时,发生此事件。
    onkeypress	当用户按了某个键时,发生此事件。
    onkeyup	当用户松开键时,发生此事件。
    keyCode	返回触发 onkeypress 事件的键的 Unicode 字符码,或触发 onkeydown 或 onkeyup 事件的键的 Unicode 键码。
    ctrlKey	返回按键鼠标事件时是否按下了 "CTRL" 键。
*/
document.onkeydown = function (event) {
    // 解决兼容性问题
    event = event || window.event;
    // 判断Ctrl键和某一个键一起是否被按下
    if (event.keyCode == 89 && event.ctrlKey) {
        console.log("一起被按下了");
    }
};

var ip1 = document.getElementById("ip1");
ip1.onkeydown = function (event) {
    event = event || window.event;
    // 使文本框中不能输入数字,数字的keyCode是 48~57
    if(event.keyCode>=48&&event.keyCode<=57){
        // 在文本框中输入内容,属于onkeydown的默认行为,如果取消默认行为,则输入的内容,不会出现在文本框中
        return false;
    }
};

参考网址: https://www.w3school.com.cn/jsref/obj_keyboardevent.asp

// 识别浏览器版本型号
if(/chrome/i.test(navigator.userAgent)){
    console.log("谷歌浏览器");
}else if(/firefox/i.test(navigator.userAgent)){
    console.log("火狐浏览器");
}else if(/msie/i.test(navigator.userAgent)){
    console.log("IE浏览器"); // 但是不支持 IE11 的识别
}else if("ActiveXObject" in window){
    console.log("你是IE11浏览器");
}

history对象

参考文档:

https://www.w3school.com.cn/jsref/api_history.asp

location对象

参考文档:

https://www.w3school.com.cn/jsref/obj_location.asp

定时器

/*
    setInterval()	按照指定的周期(以毫秒计)来调用函数或计算表达式。
    clearInterval()	取消由 setInterval() 设置的 timeout。
    setTimeout()	在指定的毫秒数后调用函数或计算表达式。这个方法只会执行一次
    clearTimeout()	取消由 setTimeout() 方法设置的 timeout。
    () => {} 等价于 function(){},都是匿名函数
*/
var count = document.getElementById("count");
var num = 1;
// 创建并开启一个定时器
var timer = setInterval(function(){
    count.innerHTML=num++;
    // 关闭定时器
    if(num==11){
        clearInterval(timer);
    }
}, 1000);

图片切换练习

<script>
    window.onload = () => {
        // 获取图片元素
        var img1 = document.getElementById("img1");
        // 获取按钮元素
        var btn01 = document.getElementById("btn01");
        var btn02 = document.getElementById("btn02");
        // 存放图片路径
        var imgArr = ["./img/1.jpg", "./img/2.jpg", "./img/3.jpg", "./img/4.jpg", "./img/5.jpg"];
        // 图片索引
        var index = 0;
        // 定义一个定时器
        var timer;
        // 点击按钮开始切换
        btn01.onclick = function () {
            // 关闭上一个定时器,这样可以确保只会开启一个定时器
            clearInterval(timer);
            // 开启一个定时器
            timer = setInterval(() => {
                index++;

                // if (index >= imgArr.length) {
                //     index=0;
                // }
                index = index % imgArr.length;
                img1.src = imgArr[index];
            }, 1000);
        };

        // 点击按钮停止切换
        btn02.onclick = function () {
                clearInterval(timer);
            };


    };
</script>
</head>

<body>
    <img id="img1" src="./img/1.jpg">
    <br><br>
    <button id="btn01">开始</button>
    <button id="btn02">停止</button>
</body>

自定义执行动画的函数

//尝试创建一个可以执行简单动画的函数
/*
 * 参数:
 * 	obj:要执行动画的对象
 * 	attr:要执行动画的样式,比如:left top width height
 * 	target:执行动画的目标位置
 * 	speed:移动的速度(正数向右移动,负数向左移动)
 *  callback:回调函数,这个函数将会在动画执行完毕以后执行
 */
function move(obj, attr, target, speed, callback) {
	//关闭上一个定时器
	clearInterval(obj.timer);

	//获取元素目前的位置
	var current = parseInt(getStyle(obj, attr));

	//判断速度的正负值
	//如果从0 向 800移动,则speed为正
	//如果从800向0移动,则speed为负
	if(current > target) {
		//此时速度应为负值
		speed = -speed;
	}

	//开启一个定时器,用来执行动画效果
	//向执行动画的对象中添加一个timer属性,用来保存它自己的定时器的标识
	obj.timer = setInterval(function() {

		//获取box1的原来的left值
		var oldValue = parseInt(getStyle(obj, attr));

		//在旧值的基础上增加
		var newValue = oldValue + speed;

		//判断newValue是否大于800
		//从800 向 0移动
		//向左移动时,需要判断newValue是否小于target
		//向右移动时,需要判断newValue是否大于target
		if((speed < 0 && newValue < target) || (speed > 0 && newValue > target)) {
			newValue = target;
		}

		//将新值设置给box1
		obj.style[attr] = newValue + "px";

		//当元素移动到0px时,使其停止执行动画
		if(newValue == target) {
			//达到目标,关闭定时器
			clearInterval(obj.timer);
			//动画执行完毕,调用回调函数
			callback && callback();
		}

	}, 30);
}

/*
 * 定义一个函数,用来获取指定元素的当前的样式
 * 参数:
 * 		obj 要获取样式的元素
 * 		name 要获取的样式名
 */
function getStyle(obj, name) {

	if(window.getComputedStyle) {
		//正常浏览器的方式,具有getComputedStyle()方法
		return getComputedStyle(obj, null)[name];
	} else {
		//IE8的方式,没有getComputedStyle()方法
		return obj.currentStyle[name];
	}

}
/* 设置透明度,同时兼容IE8浏览器 */
opacity: 0.5;
/* 兼容IE8透明度设置 */
filter: alpha(opacity=50); 

轮播图练习

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8">
	<title></title>

	<style type="text/css">
		* {
			margin: 0;
			padding: 0;
		}

		/*
			 * 设置outer的样式
			 */
		#outer {
			/*设置宽和高*/
			width: 520px;
			height: 333px;
			/*居中*/
			margin: 50px auto;
			/*设置背景颜色*/
			background-color: greenyellow;
			/*设置padding*/
			padding: 10px 0;
			/*开启相对定位*/
			position: relative;
			/*裁剪溢出的内容*/
			overflow: hidden;
		}

		/*设置imgList*/
		#imgList {
			/*去除项目符号*/
			list-style: none;
			/*设置ul的宽度*/
			/*width: 2600px;*/
			/*开启绝对定位*/
			position: absolute;
			/*设置偏移量*/
			/*
				 * 每向左移动520px,就会显示到下一张图片
				 */
			left: 0px;
		}

		/*设置图片中的li*/
		#imgList li {
			/*设置浮动*/
			float: left;
			/*设置左右外边距*/
			margin: 0 10px;
		}

		/*设置导航按钮*/
		#navDiv {
			/*开启绝对定位*/
			position: absolute;
			/*设置位置*/
			bottom: 15px;
			/*设置left值
				 	outer宽度  520
				 	navDiv宽度 25*5 = 125
				 		520 - 125 = 395/2 = 197.5
				 * */
			/*left: 197px;*/
		}

		#navDiv a {
			/*设置超链接浮动*/
			float: left;
			/*设置超链接的宽和高*/
			width: 15px;
			height: 15px;
			/*设置背景颜色*/
			background-color: red;
			/*设置左右外边距*/
			margin: 0 5px;
			/*设置透明*/
			opacity: 0.5;
			/*兼容IE8透明*/
			filter: alpha(opacity=50);
		}

		/*设置鼠标移入的效果*/
		#navDiv a:hover {
			background-color: black;
		}
	</style>

	<!--引用工具-->
	<script type="text/javascript" src="js/tools.js"></script>
	<script type="text/javascript">
		window.onload = function () {
			//获取imgList
			var imgList = document.getElementById("imgList");
			//获取页面中所有的img标签
			var imgArr = document.getElementsByTagName("img");
			//设置imgList的宽度
			imgList.style.width = 520 * imgArr.length + "px";

			/*设置导航按钮居中*/
			//获取navDiv
			var navDiv = document.getElementById("navDiv");
			//获取outer
			var outer = document.getElementById("outer");
			//设置navDiv的left值
			navDiv.style.left = (outer.offsetWidth - navDiv.offsetWidth) / 2 + "px";

			//默认显示图片的索引
			var index = 0;
			//获取所有的a
			var allA = document.getElementsByTagName("a");
			/* 设置一个定时器 */
			var timer;
			//设置默认选中的效果
			allA[index].style.backgroundColor = "black";

			/* 为每个超链接绑定单击响应函数 */
			for (var i = 0; i < allA.length; i++) {
				/* 为每个超链接添加一个num属性 */
				allA[i].num = i;
				allA[i].onclick = function () {
					/* 关闭自动切换图片 */
					clearInterval(timer);
					index = this.num;
					/* 调用执行动画 */
					move(imgList, "left", (-520 * index), 20, function () { 
						/* 动画执行完毕后,重新开启自动切换函数 */
						changeAuto();
					});
					setA();
				};
			};

			/* 调用自动切换图片函数 */
			changeAuto();
			/* 创建一个函数,用于开启自动切换图片 */
			function changeAuto() {
				timer=setInterval(function () {
					index++;
					index %= imgArr.length;
					move(imgList, "left", (-520 * index), 20, function () {
						setA();
					});
				}, 3000);
			};

			/* 设置所有a链接的背景颜色 */
			function setA() {
				/* 判断当前索引是否是最后一张 */
				if (index >= imgArr.length - 1) {
					/* 将索引设置为0 */
					index = 0;
					/* 通过css切换成第一图片 */
					imgList.style.left = 0;
				}
				for (let i = 0; i < allA.length; i++) {
					/* 将内联样式取消后,会自动填充上样式表中的样式 */
					allA[i].style.backgroundColor = "";
				};

				allA[index].style.backgroundColor = "black";
			};
		};

	</script>
</head>

<body>
	<!-- 创建一个外部的div,来作为大的容器 -->
	<div id="outer">
		<!-- 创建一个ul,用于放置图片 -->
		<ul id="imgList">
			<li><img src="img/1.jpg" /></li>
			<li><img src="img/2.jpg" /></li>
			<li><img src="img/3.jpg" /></li>
			<li><img src="img/4.jpg" /></li>
			<li><img src="img/5.jpg" /></li>
			<li><img src="img/1.jpg" /></li>
		</ul>
		<!--创建导航按钮-->
		<div id="navDiv">
			<a href="javascript:;"></a>
			<a href="javascript:;"></a>
			<a href="javascript:;"></a>
			<a href="javascript:;"></a>
			<a href="javascript:;"></a>
		</div>
	</div>
</body>

</html>

通过className修改样式表

/* 通过className属性修改样式 */
/* box.className += " b2"; */ /* += 可以在原样式的基础上进行增加,但是注意,前面一定要有一个 空格  */
/* 使用自定义函数修改样式 */
/* addClass(box, "b2"); */
toggleClass(box, "b2");
/* 定义一个函数,用来通过className修改样式 cn是className */
function addClass(obj, cn) {
    /* 如果没有,则添加 */
    if (!hasClass(obj, cn)) {
        obj.className += " " + cn;
    };
};
/* 定义一个函数,判断className中有没有cn */
function hasClass(obj, cn) {
    var reg = new RegExp("\\b" + cn + "\\b");
    return reg.test(obj.className);
};

/* 通过类型删除样式 */
function removeClass(obj, cn) {
    var reg = new RegExp("\\b" + cn + "\\b");
    obj.className = obj.className.replace(reg, "");
};

function toggleClass(obj, cn) {
    if (hasClass(obj, cn)) {
        /* 如果有,则删除元素 */
        removeClass(obj, cn);
    } else {
        /* 如果没有,则添加元素 */
        addClass(obj, cn);
    };
};

JSON

var obj = '{ "name": "洪晨", "age": 28, "address": "沈阳市" }';
var obj2 = { name: "洪晨", age: 28, address: "法库县" };
/* json对象转换为js对象 */
var obj1 = JSON.parse(obj);
console.log(obj1.name);
/* js对象转换成json对象 */
var obj3=JSON.stringify(obj2);
console.log(obj3);
/* eval() 这个函数可以用来执行一段字符串形式的js代码,并将执行结果返回 */
var obj4=eval("("+obj+")");
console.log(obj4);

兼容IE7浏览器使用json

//  json2.js
//  2016-05-01
//  Public Domain.
//  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
//  See http://www.JSON.org/js.html
//  This code should be minified before deployment.
//  See http://javascript.crockford.com/jsmin.html

//  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
//  NOT CONTROL.

//  This file creates a global JSON object containing two methods: stringify
//  and parse. This file is provides the ES5 JSON capability to ES3 systems.
//  If a project might run on IE8 or earlier, then this file should be included.
//  This file does nothing on ES5 systems.

//      JSON.stringify(value, replacer, space)
//          value       any JavaScript value, usually an object or array.
//          replacer    an optional parameter that determines how object
//                      values are stringified for objects. It can be a
//                      function or an array of strings.
//          space       an optional parameter that specifies the indentation
//                      of nested structures. If it is omitted, the text will
//                      be packed without extra whitespace. If it is a number,
//                      it will specify the number of spaces to indent at each
//                      level. If it is a string (such as "\t" or "&nbsp;"),
//                      it contains the characters used to indent at each level.
//          This method produces a JSON text from a JavaScript value.
//          When an object value is found, if the object contains a toJSON
//          method, its toJSON method will be called and the result will be
//          stringified. A toJSON method does not serialize: it returns the
//          value represented by the name/value pair that should be serialized,
//          or undefined if nothing should be serialized. The toJSON method
//          will be passed the key associated with the value, and this will be
//          bound to the value.

//          For example, this would serialize Dates as ISO strings.

//              Date.prototype.toJSON = function (key) {
//                  function f(n) {
//                      // Format integers to have at least two digits.
//                      return (n < 10)
//                          ? "0" + n
//                          : n;
//                  }
//                  return this.getUTCFullYear()   + "-" +
//                       f(this.getUTCMonth() + 1) + "-" +
//                       f(this.getUTCDate())      + "T" +
//                       f(this.getUTCHours())     + ":" +
//                       f(this.getUTCMinutes())   + ":" +
//                       f(this.getUTCSeconds())   + "Z";
//              };

//          You can provide an optional replacer method. It will be passed the
//          key and value of each member, with this bound to the containing
//          object. The value that is returned from your method will be
//          serialized. If your method returns undefined, then the member will
//          be excluded from the serialization.

//          If the replacer parameter is an array of strings, then it will be
//          used to select the members to be serialized. It filters the results
//          such that only members with keys listed in the replacer array are
//          stringified.

//          Values that do not have JSON representations, such as undefined or
//          functions, will not be serialized. Such values in objects will be
//          dropped; in arrays they will be replaced with null. You can use
//          a replacer function to replace those with JSON values.

//          JSON.stringify(undefined) returns undefined.

//          The optional space parameter produces a stringification of the
//          value that is filled with line breaks and indentation to make it
//          easier to read.

//          If the space parameter is a non-empty string, then that string will
//          be used for indentation. If the space parameter is a number, then
//          the indentation will be that many spaces.

//          Example:

//          text = JSON.stringify(["e", {pluribus: "unum"}]);
//          // text is '["e",{"pluribus":"unum"}]'

//          text = JSON.stringify(["e", {pluribus: "unum"}], null, "\t");
//          // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

//          text = JSON.stringify([new Date()], function (key, value) {
//              return this[key] instanceof Date
//                  ? "Date(" + this[key] + ")"
//                  : value;
//          });
//          // text is '["Date(---current time---)"]'

//      JSON.parse(text, reviver)
//          This method parses a JSON text to produce an object or array.
//          It can throw a SyntaxError exception.

//          The optional reviver parameter is a function that can filter and
//          transform the results. It receives each of the keys and values,
//          and its return value is used instead of the original value.
//          If it returns what it received, then the structure is not modified.
//          If it returns undefined then the member is deleted.

//          Example:

//          // Parse the text. Values that look like ISO date strings will
//          // be converted to Date objects.

//          myData = JSON.parse(text, function (key, value) {
//              var a;
//              if (typeof value === "string") {
//                  a =
//   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
//                  if (a) {
//                      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
//                          +a[5], +a[6]));
//                  }
//              }
//              return value;
//          });

//          myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
//              var d;
//              if (typeof value === "string" &&
//                      value.slice(0, 5) === "Date(" &&
//                      value.slice(-1) === ")") {
//                  d = new Date(value.slice(5, -1));
//                  if (d) {
//                      return d;
//                  }
//              }
//              return value;
//          });

//  This is a reference implementation. You are free to copy, modify, or
//  redistribute.

/*jslint
    eval, for, this
*/

/*property
    JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
    lastIndex, length, parse, prototype, push, replace, slice, stringify,
    test, toJSON, toString, valueOf
*/


// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.

if (typeof JSON !== "object") {
    JSON = {};
}

(function () {
    "use strict";

    var rx_one = /^[\],:{}\s]*$/;
    var rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
    var rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
    var rx_four = /(?:^|:|,)(?:\s*\[)+/g;
    var rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
    var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;

    function f(n) {
        // Format integers to have at least two digits.
        return n < 10
            ? "0" + n
            : n;
    }

    function this_value() {
        return this.valueOf();
    }

    if (typeof Date.prototype.toJSON !== "function") {

        Date.prototype.toJSON = function () {

            return isFinite(this.valueOf())
                ? this.getUTCFullYear() + "-" +
                        f(this.getUTCMonth() + 1) + "-" +
                        f(this.getUTCDate()) + "T" +
                        f(this.getUTCHours()) + ":" +
                        f(this.getUTCMinutes()) + ":" +
                        f(this.getUTCSeconds()) + "Z"
                : null;
        };

        Boolean.prototype.toJSON = this_value;
        Number.prototype.toJSON = this_value;
        String.prototype.toJSON = this_value;
    }

    var gap;
    var indent;
    var meta;
    var rep;


    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

        rx_escapable.lastIndex = 0;
        return rx_escapable.test(string)
            ? "\"" + string.replace(rx_escapable, function (a) {
                var c = meta[a];
                return typeof c === "string"
                    ? c
                    : "\\u" + ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
            }) + "\""
            : "\"" + string + "\"";
    }


    function str(key, holder) {

// Produce a string from holder[key].

        var i;          // The loop counter.
        var k;          // The member key.
        var v;          // The member value.
        var length;
        var mind = gap;
        var partial;
        var value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

        if (value && typeof value === "object" &&
                typeof value.toJSON === "function") {
            value = value.toJSON(key);
        }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

        if (typeof rep === "function") {
            value = rep.call(holder, key, value);
        }

// What happens next depends on the value's type.

        switch (typeof value) {
        case "string":
            return quote(value);

        case "number":

// JSON numbers must be finite. Encode non-finite numbers as null.

            return isFinite(value)
                ? String(value)
                : "null";

        case "boolean":
        case "null":

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce "null". The case is included here in
// the remote chance that this gets fixed someday.

            return String(value);

// If the type is "object", we might be dealing with an object or an array or
// null.

        case "object":

// Due to a specification blunder in ECMAScript, typeof null is "object",
// so watch out for that case.

            if (!value) {
                return "null";
            }

// Make an array to hold the partial results of stringifying this object value.

            gap += indent;
            partial = [];

// Is the value an array?

            if (Object.prototype.toString.apply(value) === "[object Array]") {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || "null";
                }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

                v = partial.length === 0
                    ? "[]"
                    : gap
                        ? "[\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "]"
                        : "[" + partial.join(",") + "]";
                gap = mind;
                return v;
            }

// If the replacer is an array, use it to select the members to be stringified.

            if (rep && typeof rep === "object") {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    if (typeof rep[i] === "string") {
                        k = rep[i];
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (
                                gap
                                    ? ": "
                                    : ":"
                            ) + v);
                        }
                    }
                }
            } else {

// Otherwise, iterate through all of the keys in the object.

                for (k in value) {
                    if (Object.prototype.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (
                                gap
                                    ? ": "
                                    : ":"
                            ) + v);
                        }
                    }
                }
            }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

            v = partial.length === 0
                ? "{}"
                : gap
                    ? "{\n" + gap + partial.join(",\n" + gap) + "\n" + mind + "}"
                    : "{" + partial.join(",") + "}";
            gap = mind;
            return v;
        }
    }

// If the JSON object does not yet have a stringify method, give it one.

    if (typeof JSON.stringify !== "function") {
        meta = {    // table of character substitutions
            "\b": "\\b",
            "\t": "\\t",
            "\n": "\\n",
            "\f": "\\f",
            "\r": "\\r",
            "\"": "\\\"",
            "\\": "\\\\"
        };
        JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

            var i;
            gap = "";
            indent = "";

// If the space parameter is a number, make an indent string containing that
// many spaces.

            if (typeof space === "number") {
                for (i = 0; i < space; i += 1) {
                    indent += " ";
                }

// If the space parameter is a string, it will be used as the indent string.

            } else if (typeof space === "string") {
                indent = space;
            }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

            rep = replacer;
            if (replacer && typeof replacer !== "function" &&
                    (typeof replacer !== "object" ||
                    typeof replacer.length !== "number")) {
                throw new Error("JSON.stringify");
            }

// Make a fake root object containing our value under the key of "".
// Return the result of stringifying the value.

            return str("", {"": value});
        };
    }


// If the JSON object does not yet have a parse method, give it one.

    if (typeof JSON.parse !== "function") {
        JSON.parse = function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

            var j;

            function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

                var k;
                var v;
                var value = holder[key];
                if (value && typeof value === "object") {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

            text = String(text);
            rx_dangerous.lastIndex = 0;
            if (rx_dangerous.test(text)) {
                text = text.replace(rx_dangerous, function (a) {
                    return "\\u" +
                            ("0000" + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with "()" and "new"
// because they can cause invocation, and "=" because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with "@" (a non-JSON character). Second, we
// replace all simple value tokens with "]" characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or "]" or
// "," or ":" or "{" or "}". If that is so, then the text is safe for eval.

            if (
                rx_one.test(
                    text
                        .replace(rx_two, "@")
                        .replace(rx_three, "]")
                        .replace(rx_four, "")
                )
            ) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The "{" operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

                j = eval("(" + text + ")");

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

                return (typeof reviver === "function")
                    ? walk({"": j}, "")
                    : j;
            }

// If the text is not JSON parseable, then a SyntaxError is thrown.

            throw new SyntaxError("JSON.parse");
        };
    }
}());

bootstrap

<!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>bootstrap</title>
    <!-- 引入bootstrap样式 -->
    <link rel="stylesheet" href="./bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <style>
        .container-fluid {
            background-color: pink;
        }

        .container {
            background-color: green;
        }

        /* div元素class类型以 col 开头的所有元素 */
        div[class |=col] {
            border: 1px solid;
        }
    </style>
</head>

<body>
    <!-- 流体容器 container-fluid -->
    <div class="container-fluid">
        test
    </div>
    <!-- 固定容器 -->
    <div class="container">
        container
    </div>
    <!-- 珊格布局 默认是一行12列 -->
    <div class="container">
        <div class="row">
            <!-- 一行占十份,一行占两份 -->
            <div class="col-lg-10">10</div>
            <div class="col-lg-2">2</div>
        </div>
    </div>
    <div class="container">
        <div class="row">
            <!-- 珊格组合,当宽度达到 col-md 时,就是使用 col-md-6 将珊格平分6份 -->
            <div class="col-lg-10 col-md-6">10</div>
            <div class="col-lg-2 col-md-6">2</div>
        </div>
    </div>
</body>
<!-- 引入js文件 -->
<script src="./bootstrap-3.3.7-dist/js/jquery.min.js"></script>
<script src="./bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>

</html>

列偏移

<!-- offset 水平偏移量 -->
<div class="col-lg-4 col-lg-offset-4">col-lg-4</div>

bootstrap基本模板

<!doctype html>
<html lang="zh-CN">

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1 user-scalable=no">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>Bootstrap基本模板</title>

    <!-- 引入Bootstrap样式表 -->
    <link rel="stylesheet" href="./bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
    <!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
    <!-- [if lt IE 9]>
      <script src="./js/html5shiv.js"></script>
      <script src="./js/respond.min.js"></script>
    <![endif] -->
</head>

<body>

    <!-- jQuery (Bootstrap 的所有 JavaScript 插件都依赖 jQuery,所以必须放在前边) -->
    <script src="./js/jquery.min.js"></script>
    <!-- 加载 Bootstrap 的所有 JavaScript 插件。你也可以根据需要只加载单个插件。 -->
    <script src="./js/bootstrap.min.js"></script>
</body>

</html>

jQuery

$(function () {
  // click() 鼠标点击事件
  $('#btn').click(function () {
    // .html() 方法来获取任意一个元素的内容
    alert($(this).html());
    // $(A).append(B)的操作,把A追加到B中。
    $('<input />').appendTo('div');
  });

  var arr=[1,2,3,4,5,6,7,8,9];
  // each 遍历数组
  $.each(arr,function(i,n){
    console.log("index="+i+",n="+n);
  });

  var name='   hongchen   ';
  // trim 去掉字符串起始和结尾的空格。
  console.log($.trim(name));
});
/* 
    length 
    jQuery 对象中元素的个数。
    这个函数的返回值与 jQuery 对象的size()属性一致。
  */
console.log($('button').length, $("button").size());

var $buttons = $('button');
/* 
      [index]
      取得第 index 个位置上的元素
      get()
      取得所有匹配的 DOM 元素集合。
  */
console.log($buttons[1].innerHTML, $buttons.get(1).innerHTML);
// 遍历元素列表的所有元素
$buttons.each(function () {
  console.log(this.innerHTML);
});
// .index() 方法,返回值就是这个元素相对于其兄弟元素的下标位置
console.log($('#btn3').index());

基本选择器

/* id选择器, .css 设置样式, 将所有段落的字体颜色设为红色并且背景为蓝色。 */
$('#div1').css({ "background": "blue" });
/* 元素选择器 */
$('div').css('background','red');
/* class类选择器 */
$('.box').css({'background':'pink'});
/* 并集选择 选择所有的div和span元素 */
$('div,span').css({'background':'green'});
/* 交集选择器 选择所有class属性为box的div元素 */
$('div.box').css({'background':'yellow'});

层次选择器

/* 选中ul下所有的的span */
$('ul span').css({'background':'yellow'});
/* 选中ul下所有的子元素span */
$('ul>span').css({'background':'red'});
/* 选中class为box的下一个li */
$('.box+li').css({'background':'green'});
/* 选中ul下的class为box的元素后面的所有兄弟元素 */
$('ul .box~*').css({'background':'orange'});

过滤选择器

//  1. 选择第一个div
$('div:first').css('background','red');
//  2. 选择最后一个class为box的元素
$('div:last').css('background','green');
//  3. 选择所有class属性不为box的div
$('div:not(.box)').css('background','yellow'); // 没有class属性的div元素也会被选中
//  4. 选择第二个和第三个li元素
$('li:gt(0):lt(2)').css('background','orange');
$('li:lt(3):gt(0)').css('background','blue');
//  5. 选择内容为BBBBB的li
$('li:contains("BBBBB")').css('background','pink');
//  6. 选择隐藏的li
console.log($("li:hidden")[0].innerHTML);
//  7. 选择有title属性的li元素
$('li[title]').css('background','purple');
//  8. 选择所有属性title为hello的li元素
$('li[title="hello"]').css('background','coral');

表单选择器

//1. 选择不可用的文本输入框
$("input:disabled").css({ 'background': 'red' });
//2. 显示选择爱好 的个数
console.log($(':checkbox:checked').length);
//3. 显示选择的城市名称
$(':submit').click(function () {
  alert($('option:selected').html());
});

属性

//  1. 读取第一个div的title属性
console.log($('div:first').attr('title'));
//  2. 给所有的div设置name属性(value为atguigu)
$('div').attr('value','atguigu');
//  3. 移除所有div的title属性
$('div').removeAttr('title');
//  4. 给所有的div设置class='guiguClass'
$('div').attr('class','guiguClass');
//  5. 给所有的div添加class='abc'
$('div').addClass('abc');
//  6. 移除所有div的guiguClass的class
$('div').removeClass('guiguClass');
//  7. 得到最后一个li的标签体文本
console.log($('li:last').html());
//  8. 设置第一个li的标签体为"<h1>mmmmmmmmm</h1>"
$('li:first').html('<h1>mmmmmmmmm</h1>');
//  9. 得到输入框中的value值
console.log($(':text').val());
//  10. 将输入框的值设置为atguigu
$(':text').val('atguigu');
//  11. 点击'全选'按钮实现全选
$('button:first').click(function () {
  $(':checkbox').prop("checked", true);
});
//  12. 点击'全不选'按钮实现全不选
$('button:last').click(function () {
  $(':checkbox').prop("checked", false);
});

操作css属性

//  1. 得到第一个p标签的颜色
console.log($('p:first').css("color"));
//  2. 设置所有p标签的文本颜色为red
$('p').css({color:'red'})
//  3. 设置第2个p的字体颜色(#ff0011),背景(blue),宽(300px), 高(30px)
$('p:eq(1)').css({
  color:'#ff0011',
  background:'blue',
  width: '300px',
  height:'30px'
});

修改元素位置

//  1. 点击 btn1
$('#btn1').click(function () {
//   打印 div1 相对于页面左上角的位置
var offset=$('.div1').offset(); // 注意,此时返回的是一个对象
console.log(offset.left,offset.top);
//   打印 div2 相对于页面左上角的位置
offset=$('.div2').offset(); // 注意,此时返回的是一个对象
console.log(offset.left,offset.top);
//   打印 div1 相对于父元素左上角的位置
position=$('.div1').position(); // 注意,此时返回的是一个对象
console.log(position.left,position.top);

//   打印 div2 相对于父元素左上角的位置  
position=$('.div2').position(); // 注意,此时返回的是一个对象
console.log(position.left,position.top);

});
// 2. 点击 btn2
$('#btn2').click(function () {
//   设置 div2 相对于页面的左上角的位置
$('.div2').offset({top:30,left:30});
});

操作滚动

//  1. 得到div或页面滚动条的坐标
$('#btn1').click(function () {
  console.log($('div').scrollTop()); // 得到垂直坐标位置
console.log($(document.documentElement).scrollTop()+$(document.body).scrollTop()); // 兼容IE和其他浏览器
});
//  2. 让div或页面的滚动条滚动到指定位置
$('#btn2').click(function () {
  $('div').scrollTop(220);
  $('html,body').scrollTop(300);  // 兼容IE和其它浏览器
});

元素尺寸

1. 内容尺寸
  height(): height
  width(): width
2. 内部尺寸
  innerHeight(): height+padding
  innerWidth(): width+padding
3. 外部尺寸
  outerHeight(false/true): height+padding+border  如果是true, 加上margin
  outerWidth(false/true): width+padding+border 如果是true, 加上margin

过滤

1. first()
2. last()
3. eq(index|-index)
4. filter(selector)
5. not(selector)
6. has(selector)

var $lis = $('ul>li')
//1. ul下li标签第一个
$lis.first().css('background', 'red')
$lis[0].style.background = 'red'

//2. ul下li标签的最后一个
$lis.last().css('background', 'red')

//3. ul下li标签的第二个
$lis.eq(1).css('background', 'red')

//4. ul下li标签中title属性为hello的
$lis.filter('[title=hello]').css('background', 'red')

//5. ul下li标签中title属性不为hello的
$lis.not('[title=hello]').css('background', 'red')
$lis.filter('[title!=hello]').filter('[title]').css('background', 'red')

//6. ul下li标签中有span子标签的
$lis.has('span').css('background', 'red')

筛选

1. children(): 子标签中找
2. find() : 后代标签中找
3. parent() : 父标签
4. prevAll() : 前面所有的兄弟标签
5. nextAll() : 后面所有的兄弟标签
6. siblings() : 前后所有的兄弟标签

//  1. ul标签的第2个span子标签
$('ul').children('span:eq(1)').css('background','red');
//  2. ul标签的第2个span后代标签
$('ul').find('span:eq(1)').css('background','red');
//  3. ul标签的父标签
$('ul').parent().css('background','red');
//  4. id为cc的li标签的前面的所有li标签
$('#cc').prevAll('li').css('background','red');
//  5. id为cc的li标签的所有兄弟li标签
$('#cc').siblings('li').css('background','red');

文档的操作

1. 添加/替换元素
  * append(content)
    向当前匹配的所有元素内部的最后插入指定内容
  * prepend(content)
    向当前匹配的所有元素内部的最前面插入指定内容
  * before(content)
    将指定内容插入到当前所有匹配元素的前面
  * after(content)
    将指定内容插入到当前所有匹配元素的后面替换节点
  * replaceWith(content)
    用指定内容替换所有匹配的标签删除节点
2. 删除元素
  * empty()
    删除所有匹配元素的子元素
  * remove()
    删除所有匹配的元素
    
//  1. 向id为ul1的ul下添加一个span(最后)  
var $ul1=$('#ul1');
$ul1.append('<span>这是最后面添加的span</span>');
$('<br/><span>这是最后面添加的span22</span>').appendTo($ul1);
//  2. 向id为ul1的ul下添加一个span(最前)
$ul1.prepend('<span>这是最前面添加的prepend</span>');
$('<span>这是最前面添加的prependTo</span><br/>').prependTo($ul1);
//  3. 在id为ul1的ul下的li(title为hello)的前面添加span
$ul1.children('li[title=hello]').before('<span>这是最前面添加的before</span><br/>');
//  4. 在id为ul1的ul下的li(title为hello)的后面添加span
$ul1.children('li[title=hello]').after('<span>这是最后面添加的after</span><br/>');
//  5. 将在id为ul2的ul下的li(title为hello)全部替换为p
$('#ul2>li[title=hello]').replaceWith('<p>这是替换的p标签内容</p>');
//  6. 移除id为ul2的ul下的所有li
$('#ul2').empty();

事件的绑定与解绑

1. 事件绑定(2种):
  * eventName(function(){})
    绑定对应事件名的监听,	例如:$('#div').click(function(){});
  * on(eventName, funcion(){})
    通用的绑定事件监听, 例如:$('#div').on('click', function(){})
  * 优缺点:
    eventName: 编码方便, 但只能加一个监听, 且有的事件监听不支持
    on: 编码不方便, 可以添加多个监听, 且更通用
2. 事件解绑:
  * off(eventName)
3. 事件的坐标
  * event.clientX, event.clientY  相对于视口的左上角
  * event.pageX, event.pageY  相对于页面的左上角
  * event.offsetX, event.offsetY 相对于事件元素左上角
4. 事件相关处理
  * 停止事件冒泡 : event.stopPropagation()
  * 阻止事件默认行为 : event.preventDefault()

  //  1. 给.out绑定点击监听(用两种方法绑定)
  $('.out').click(function () {
    console.log('nihao');
  });

  $('.out').on('click',function () {
    console.log('hhhhhhh');
  })
  //  2. 给.inner绑定鼠标移入和移出的事件监听(用3种方法绑定)
  $('.inner')
  .mouseenter(function () {
    console.log('鼠标进入');
  })
  .mouseleave(function(){
    console.log('鼠标离开');
  });
  $('.inner')
  .on('mouseenter',function () {
    console.log('鼠标进入2');
  })
  .on('mouseleave',function () {
    console.log('鼠标离开2');
  });
  $('.inner').hover(function () {
    console.log('鼠标进入3');
  },function () {
    console.log('鼠标离开3');
  });
  //  3. 点击btn1解除.inner上的所有事件监听
  $('#btn1').click(function () {
    $('.inner').off();
  });
  //  4. 点击btn2解除.inner上的mouseenter事件
  $('#btn2').click(function () {
    $('.inner').off('mouseenter');
  });
  //  5. 点击btn3得到事件坐标
  $('#btn3').click(function (event) {
    console.log(event.clientX,event.clientY);
    console.log(event.pageX,event.pageY);
    console.log(event.offsetX,event.offsetY);
  });
  //  6. 点击.inner区域, 外部点击监听不响应
  $('.inner').click(function (event) {
    event.stopPropagation();  // 停止时间冒泡
  });
  //  7. 点击链接, 如果当前时间是偶数不跳转
  $('#test4').click(function (event) {
    if (Date.now()%2===0) {
      event.preventDefault(); // 阻止事件默认行为
    }
  });
区别mouseover与mouseenter?
	* mouseover: 在移入子元素时也会触发, 对应mouseout
	* mouseenter: 只在移入当前元素时才触发, 对应mouseleave
		hover()使用的就是mouseenter()和mouseleave()

事件委派

 jQuery的事件委托API
  * 设置事件委托: $(parentSelector).delegate(childrenSelector, eventName, callback)
  * 移除事件委托: $(parentSelector).undelegate(eventName)

$('ul').delegate('li', 'click', function () {
  this.style.background = 'red';
});

$('#btn1').click(function () {
  $('ul').append('<li>xxxxxxxx</li>');
});

$('#btn2').click(function () {
  $('ul').undelegate('click');
});

效果

<!--
淡入淡出: 不断改变元素的透明度(opacity)来实现的
1. fadeIn(): 带动画的显示
2. fadeOut(): 带动画隐藏
3. fadeToggle(): 带动画切换显示/隐藏

滑动动画: 不断改变元素的高度实现
1. slideDown(): 带动画的展开
2. slideUp(): 带动画的收缩
3. slideToggle(): 带动画的切换展开/收缩

显示隐藏,默认没有动画, 动画(opacity/height/width)
1. show(): (不)带动画的显示
2. hide(): (不)带动画的隐藏
3. toggle(): (不)带动画的切换显示/隐藏
-->
var $div1=$('.div1');
$('#btn1').click(function () {
  $div1.fadeOut(1000,function () {
    alert('方框淡出完毕!!!')
  });
});

$('#btn2').click(function () {
  $div1.fadeIn();
});

$('#btn3').click(function () {
  $div1.fadeToggle();
});


// 1. 点击btn1, 向上滑动
$('#btn1').click(
  function () {
    $div1.slideUp(3000);
  }
);
//    2. 点击btn2, 向下滑动
$('#btn2').click(
  function () {
    $div1.slideDown(3000);
  }
);
//    3. 点击btn3, 向上/向下切换
$('#btn3').click(
  function () {
    $div1.slideToggle(3000);
  }
);

// 1. 点击btn1, 立即显示
  $('#btn1').click(function () {
    $div1.show();
  });
  // 2. 点击btn2, 慢慢显示
  $('#btn2').click(function () {
    $div1.show(1000);
  });
  // 3. 点击btn3, 慢慢隐藏
  $('#btn3').click(function () {
    $div1.hide(1000);
  });
  // 4. 点击btn4, 切换显示/隐藏
  $('#btn4').click(function () {
    $div1.toggle();
  });

自定义动画

<!--
jQuery动画本质 : 在指定时间内不断改变元素样式值来实现的
1. animate(): 自定义动画效果的动画
2. stop(): 停止动画
-->
var $div1 = $('.div1');

// 1. 逐渐扩大
//       1). 宽/高都扩为200px
$('#btn1').click(function () {
  $div1.animate({
    width: 300,
    height: 300
  }, 1000);
});
//       2). 宽先扩为200px, 高后扩为200px
$('#btn1').click(function () {
  $div1
    .animate({
      width: 300
    }, 1000)
    .animate({
      height: 300
    }, 1000);
});
//     2. 移动到指定位置
//       1).移动到(500, 100)处
$('#btn2').click(function () {
  $div1.animate({
    left: 500,
    top: 100
  }, 1000);
});
//       2).移动到(100, 20)处
$('#btn2').click(function () {
  $div1.animate({
    left: 100,
    top: 20
  }, 1000);
});
//     3.移动指定的距离
//       1). 移动距离为(100, 50)
$('#btn3').click(function () {
  $div1.animate({
    left: '+=100',
    top: '+=50'
  }, 5000);
});
//       2). 移动距离为(-100, -20)
$('#btn3').click(function () {
  $div1.animate({
    left:'-=100',
    top:'-=50'
  },1000);
});
//     4. 停止动画
$('#btn4').click(function () {
  $div1.stop();
});

多库共存

<!--
问题 : 如果有2个库都有$, 就存在冲突
解决 : jQuery库可以释放$的使用权, 让另一个库可以正常使用, 此时jQuery库只能使用jQuery了
API : jQuery.noConflict()
-->
<!--
区别: window.onload与 $(document).ready()
  * window.onload
    * 包括页面的图片加载完后才会回调(晚)
    * 只能有一个监听回调
  * $(document).ready()
    * 等同于: $(function(){})
    * 页面加载完就回调(早)
    * 可以有多个监听回调
-->

插件机制

<!--
1. 扩展jQuery的工具方法
  $.extend(object)
2. 扩展jQuery对象的方法
  $.fn.extend(object)
-->
(function () {
    // 给 $ 添加4个工具方法:
    $.extend({
        // min(a, b) : 返回较小的值
        min: function (a, b) {
            return a < b ? a : b;
        },
        // max(c, d) : 返回较大的值
        max: function (c, d) {
            return c > d ? c : d;
        },
        // leftTrim() : 去掉字符串左边的空格
        leftTrim: function (str) {
            return str.replace(/^\s+/, '');
        },
        // rightTrim() : 去掉字符串右边的空格
        rightTrim: function (str) {
            return str.replace(/\s+$/, '');
        }
    });

    // 给jQuery对象 添加3个功能方法:
    $.fn.extend({
        //     checkAll() : 全选
        checkAll: function () {
            this.prop('checked', true)
        },
        //    unCheckAll() : 全不选
        unCheckAll: function () {
            return this.each(function () {
                this.checked = false;
            });
        },
        //    reverseCheck() : 全反选
        reverseCheck: function () {
            this.each(function () {
                this.checked = !this.checked;
            });
        }
    });

})()

AJAX

express框架

npm init --yes # 初始化node js
npm i express # 安装express框架

创建express服务

// 1.引入express
const express = require('express');
// 2.创建应用对象
const app = express();
// 3.创建路由规则
app.get('/', (request, response) => {
    // 设置响应
    response.send('hello, ajax!!!');
});
// 4.监听端口
app.listen(8000, () => {
    console.log('服务已经启动,端口8000监听中......');
});

启动express服务

E:\前端学习\ajax\代码\2-express框架> node express基本使用.js
// 设置响应头
response.setHeader('Access-Control-Allow-Origin','*');  // 允许跨域
// 设置响应体
response.send('hello, ajax!!!');

自动重启nodeJS服务 nodemon

npm install -g nodemon

原生ajax请求

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

<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>
        #result {
            width: 200px;
            height: 200px;
            border: 5px solid palevioletred;
        }
    </style>
</head>

<body>
    <button>发送请求</button>
    <button id="esc">取消请求</button>
    <div id="result"></div>
    <script>
        var btn = document.getElementsByTagName('button')[0];
        var esc = document.getElementById('esc');
        var xhr = null;
        var isSending=false; // 标识正在发送变量 false 为没有发送
        btn.onclick = function () {
            if (isSending) { // 如果正在发送,则取消该请求,创建一个新的请求
                xhr.abort();
            }
            // 1.创建对象
            xhr = new XMLHttpRequest();

            var result = document.getElementById('result');
            // 超时设置
            // xhr.timeout=2000;
            // // 超时回调
            // xhr.ontimeout=function(){
            //     alert('网络超时,请稍后重试!');
            // };
            // // 网络异常设置
            // xhr.onerror=function(){
            //     alert('网络异常,请检查网络!');
            // };
            // 设置响应体数据的类型,自动将json对象转换为js对象
            // xhr.responseType = 'json';
            // 2.初始化,设置请求方法和url, ?a=100&b=200 传递参数
            // xhr.open('GET', 'http://127.0.0.1:8000/get?a=100&b=200'); // GET请求
            // xhr.open('GET', 'http://127.0.0.1:8000/get'); // GET请求
            // xhr.open('GET', 'http://127.0.0.1:8000/get?t='+Date.now()); // 解决IE浏览器ajax缓存问题
            // xhr.open('POST', 'http://127.0.0.1:8000/post'); // POST请求
            // xhr.open('POST', 'http://127.0.0.1:8000/json');
            // 修改标识变量
            isSending=true;
            xhr.open('get', 'http://127.0.0.1:8000/time'); // GET请求
            // 设置请求头
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            // xhr.setRequestHeader('name','honksun'); // 自定义请求头
            // 3.发送
            // xhr.send('a=100&b=200&c=300'); // post请求设置参数
            xhr.send(); // post请求设置参数
            // 4.事件绑定,处理服务器返回的结果
            xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) { // 4表示服务端返回了所有的结果
                    isSending=false;
                    if (xhr.status >= 200 && xhr.status < 300) { // 2xx 表示成功
                        // 处理结果
                        console.log(xhr.status); // 状态码
                        console.log(xhr.statusText); // 状态字符串
                        console.log(xhr.getAllResponseHeaders()); // 所有响应头
                        console.log(xhr.response); // 响应体
                        result.innerHTML = xhr.response;
                        // 手动将json对象转换为js对象
                        // var data = JSON.parse(xhr.response);
                        // result.innerHTML = data.name;
                        // result.innerHTML=xhr.response.name;
                    }
                };
            };
        };

        esc.onclick = function () {
            // ajax 取消请求
            xhr.abort();
        };
    </script>
</body>

</html>
// 1.引入express
const express = require('express');
const { json } = require('express/lib/response');
// 2.创建应用对象
const app = express();
// 3.创建路由规则
// 接收get请求
app.get('/get', (request, response) => {
    // 设置响应头
    response.setHeader('Access-Control-Allow-Origin', '*'); // 允许跨域
    // 设置响应体
    response.send('hello, ajax!!! --03');
});
// 接收post请求
app.post('/post', (request, response) => {
    // 设置响应头
    response.setHeader('Access-Control-Allow-Origin', '*'); // 允许跨域
    // 设置响应头
    response.setHeader('Access-Control-Allow-Header', '*'); // * 表示可以接收自定义的请求头 
    // 设置响应体
    response.send('hello,POST ajax!!!');
});
// 接收任意请求
app.all('/all', (request, response) => {
    // 设置响应头
    response.setHeader('Access-Control-Allow-Origin', '*'); // 允许跨域
    // 设置响应头
    response.setHeader('Access-Control-Allow-Headers', '*'); // * 表示可以接收自定义的请求头 
    // 设置响应体
    response.send('hello,ALL ajax!!!');
});
// 
app.all('/json', (request, response) => {
    // 设置响应头
    response.setHeader('Access-Control-Allow-Origin', '*'); // 允许跨域
    // 设置响应头
    response.setHeader('Access-Control-Allow-Headers', '*'); // * 表示可以接收自定义的请求头 
    // 将js对象转换为json对象
    var data={name:'honksun'};
    var str=JSON.stringify(data);
    // 设置响应体
    response.send(str);
});
// 4.监听端口
app.listen(8000, () => {
    console.log('服务已经启动,端口8000监听中......');
});

jQuery发送ajax请求

// get请求
$('button').eq(0).click(function () {
    $.get('http://127.0.0.1:8000/jquery-get', { a: 100, b: 200 }, function (date) {
        console.log(date.name);
    }, 'json');
});
// post请求
$('button').eq(1).click(function () {
    $.post('http://127.0.0.1:8000/jquery-get', { a: 100, b: 200 }, function (date) {
        console.log(date);
    });
});
// 通用方法ajax
$('button').eq(2).click(function () {
    $.ajax({
        // url
        url: 'http://127.0.0.1:8000/time',
        // 参数
        data: { a: 300, b: 400 },
        // 类型
        type: 'GET',
        // 响应体类型
        dataType: 'json',
        // 成功回调
        success: function (data) {
            console.log(data);
        },
        // 超时时间
        timeout: 2000,
        // 失败回调
        error: function () {
            console.log('出错了');
        },
        // 头信息
        headers: {
            a: 500,
            b: 700
        }
    });
});

axios发送ajax请求

// https://github.com/axios/axios
const btns = document.querySelectorAll('button');

//配置 baseURL
axios.defaults.baseURL = 'http://127.0.0.1:8000';

btns[0].onclick = function () {
    //GET 请求
    axios.get('/axios', {
        // url 参数
        params: {
            id: 1,
            vip: 7
        },
        // 设置头信息
        headers: {
            name: 'honksun',
            age: 28
        }
    }).then(value => {
        console.log(value);
    });
};

btns[1].onclick = function () {
    // post请求
    axios.post('/axios', {
        username: '洪晨',
        address: "沈阳市"
    }, {
        // url 参数
        params: {
            id: 'post',
            vip: 7
        },
        // 请求头信息
        headers: {
            name: 'honksun',
            age: 28
        }
    });
};

btns[2].onclick = function () {
    axios({
        // 请求方法
        method:'POST',
        // url
        url: '/axios',
        // url参数
        params: {
            id: 006,
            vip: 2
        },
        // 头信息
        headers: {
            name: 'honksun',
            age: 28
        },
        // 请求体
        data: {
            username: '洪晨',
            address: '辽宁省沈阳市'
        }
    }).then(response=>{
        console.log(response);
    });
};

fetch发送ajax请求

//文档地址
//https://developer.mozilla.org/zh-CN/docs/Web/API/WindowOrWorkerGlobalScope/fetch

const btn = document.querySelector('button');

btn.onclick = function(){
    fetch('http://127.0.0.1:8000/fetch?vip=10',{
        // 请求方法
        method:'POST',
        // 请求头信息
        headers:{
            name:'honksun'
        },
        // 请求体
        body:'username=admin&password=123456'
    }).then(response=>{
        // return response.text();
        return response.json();
    }).then(response=>{
        console.log(response);
    });
}

原生jsonp跨域请求

// 获取input元素
var input=document.querySelector('input');
var p=document.querySelector('p');
// 声明handle函数
function handle(data) {
    input.style.border='solid 1px red';
    p.innerHTML=data.msg;
};
input.onblur=function(){
    // 获取input值
    var value=this.value;
    var script=document.createElement('script');
    script.src='http://127.0.0.1:8000/check';
    document.body.appendChild(script);
};

服务端代码

// 用户名检查
app.all('/check', (request, response) => {
    // 设置响应头
    response.setHeader('Access-Control-Allow-Origin', '*'); // 允许跨域
    // 设置响应头
    response.setHeader('Access-Control-Allow-Headers', '*'); // * 表示可以接收自定义的请求头 

    var data = {
        error:1,
        msg:'用户名已经存在'
    }
    var str=JSON.stringify(data)
    // 设置响应体
    response.end(`handle(${str})`);
});

jQuery实现jsonp跨域请求

$('button').eq(0).click(function(){
    // ?callback=? 这是固定必写的格式
    $.getJSON('http://127.0.0.1:8000/jquery-jsonp?callback=?',function (data) {
        $('#result').html(`
            姓名:${data.name},
            年龄:${data.age}
        `);
    });
});

服务器端代码

// jquery- jsonp
app.all('/jquery-jsonp', (request, response) => {
    // 设置响应头
    response.setHeader('Access-Control-Allow-Origin', '*'); // 允许跨域
    // 设置响应头
    response.setHeader('Access-Control-Allow-Headers', '*'); // * 表示可以接收自定义的请求头 

    var data = {
        name:'honksun',
        age:28
    }
    var str=JSON.stringify(data);
    // 接收callback值
    var cb=request.query.callback;
    // 设置响应体
    response.end(`${cb}(${str})`);
});

cors实现跨域请求

在服务器端加上响应头信息

// 设置允许跨域响应头信息
response.setHeader('Access-Control-Allow-Origin','*'); // 允许跨域
response.setHeader('Access-Control-Allow-Headers','*'); // 接收自定义的请求头信息
response.setHeader('Access-Control-Allow-Method','*'); // 任意请求方法

NodeJS

commonJS模块规范

定义一个模块

console.log('hello, node');
// 向外部暴露变量和方法
exports.x='test.js中的x';
exports.fu=function () {  
};

引用模块

/* 引入其它模块(每一个模块就是一个js文件)
在node中,每一个js文件中的js代码都是独立运行在一个函数中,不是全局作用域,
所以,一个模块中的变量和函数无法在其它模块中访问 */
var test=require('./test.js');
console.log(test);

exports 和 module.exports 的区别

exports.name='孙悟空';
exports.age=28;
exports.sayHello=function () {
    console.log('我是孙悟空');
}
/* 
exports 只能通过.的形式向外暴露属性和方法
module.exports 既能通过.的形式,也可以通过{}对象的形式,向外暴露属性和方法
*/
module.exports={
    name:'洪晨',
    age:28,
    sayHello:function () {
     console.log('我来自辽宁省沈阳市');   
    }
};

NPM命令

honksun@honksundeMacBook-Air NodeJS % npm version # 查看版本
{
  npm: '8.1.2',
  node: '16.13.2',
  v8: '9.4.146.24-node.14',
  uv: '1.42.0',
  zlib: '1.2.11',
  brotli: '1.0.9',
  ares: '1.18.1',
  modules: '93',
  nghttp2: '1.45.1',
  napi: '8',
  llhttp: '6.0.4',
  openssl: '1.1.1l+quic',
  cldr: '39.0',
  icu: '69.1',
  tz: '2021a',
  unicode: '13.0',
  ngtcp2: '0.1.0-DEV',
  nghttp3: '0.1.0-DEV'
}

npm install 包名 -g	# 全局安装
npm install 包名 -- save	# 安装包并添加到依赖中
npm install	# 下载当前项目所依赖的包
npm init	# 初始化
npm remove 包名	# 删除一个模块
npm install 文件路径	# 从本地安装
npm install 包名 =registry=地址	# 从镜像源安装
npm config set registry 地址	# 设置镜像源

cnpm使用

官网地址

https://npmmirror.com/

使用方法

# sudo 以管理员权限安装 
sudo npm install -g cnpm --registry=https://registry.npmmirror.com

buffer缓冲区

官网文档地址: http://nodejs.cn/api/buffer.html#static-method-bufferallocunsafesize

var str = 'hello,洪晨';
// 将字符串保存到buffer中
var buf = Buffer.from(str);
console.log(buf.length); // 占用内存的大小
console.log(str.length); // 字符串的长度
// 指定一个buffer长度
var buf2 = Buffer.alloc(5);
// 通过索引下标向buf2中添加数据
buf2[0] = 25;
buf2[1] = 67;
buf2[5] = 37; // Buffer的大小一旦确定,就不能修改了.超过下标索引的数据无法插入
console.log(buf2[1]); // 读取buffer中的值
var buf3=Buffer.from('这是一段字符串');
console.log(buf3.toString()); // buf.toString()将缓冲区数据转换为字符串

同步文件写入

// 引入文件系统模块
var fs=require('fs');
// 打开文件, w 写入权限
var fd=fs.openSync('hello.txt','w');
// 向文件中写入内容
fs.writeSync(fd,'这是同步写入文件的内容222');
// 保存并关闭文件
fs.closeSync(fd);

异步文件写入

// 引入文件系统
var fs=require('fs');
// 打开文件
fs.open('hello.txt','w',function (err,fd) {
    // 判断文件是否出错
    if (!err) { // 如果没错
        // 向文件中写入内容
        fs.write(fd,"这是异步文件写入的内容",function (err) {
            if (!err) { //  如果写入成功
                console.log("写入内容成功");
            };
            // 关闭文件
            fs.close(fd,function (err) {
                if (!err) { // 如果没有错误
                    console.log("文件关闭成功1");
                };
            });
        });
    } else {
        return err;
    };
});

简单方式文件写入

// 引入文件系统
var fs=require('fs');
// 异步的简单写入
fs.writeFile('hello.txt','设置简单的异步方式写入文件内容111',{flag:'w'},function (err) {
    if (!err) { // 如果没有错误
        console.log('文件内容写入成功11');
    };
});

文件系统标志

  • 'a': 打开文件进行追加。 如果文件不存在,则创建该文件。

  • 'ax': 类似于 'a' 但如果路径存在则失败。

  • 'a+': 打开文件进行读取和追加。 如果文件不存在,则创建该文件。

  • 'ax+': 类似于 'a+' 但如果路径存在则失败。

  • 'as': 以同步模式打开文件进行追加。 如果文件不存在,则创建该文件。

  • 'as+': 以同步模式打开文件进行读取和追加。 如果文件不存在,则创建该文件。

  • 'r': 打开文件进行读取。 如果文件不存在,则会发生异常。

  • 'r+': 打开文件进行读写。 如果文件不存在,则会发生异常。

  • 'rs+': 以同步模式打开文件进行读写。 指示操作系统绕过本地文件系统缓存。

    这主要用于在 NFS 挂载上打开文件,因为它允许跳过可能过时的本地缓存。 它对 I/O 性能有非常实际的影响,因此除非需要,否则不建议使用此标志。

    这不会将 fs.open()fsPromises.open() 变成同步阻塞调用。 如果需要同步操作,应该使用类似 fs.openSync() 的东西。

  • 'w': 打开文件进行写入。 创建(如果它不存在)或截断(如果它存在)该文件。

  • 'wx': 类似于 'w' 但如果路径存在则失败。

  • 'w+': 打开文件进行读写。 创建(如果它不存在)或截断(如果它存在)该文件。

  • 'wx+': 类似于 'w+' 但如果路径存在则失败。

流式文件写入

// 引入文件系统
var fs=require("fs");
// 创建一个可写流
var ws=fs.createWriteStream('hello.txt');
// 通过监听流的open和close事件,来监听流的打开和关闭
/* 
on(事件字符串,回调函数)
    - 可以为对象绑定一个事件
once(事件字符串,回调函数)
    - 可以为对象绑定一个一次性事件,该事件在触发一次后自动失效
*/
ws.once('open',function () {
    console.log("可写流已经打开");
});
ws.once('close',function () {
    console.log("可写流已经关闭");
});
// 通过可写流向文件中写入数据
ws.write("这是通过流式文件写入的文本内容!!");
ws.write("科比!!");
ws.write("扎姆斯!!");
// 关闭流
ws.end();

简单方式文件读取

// 引入文件系统
var fs = require('fs');
// 读取文件
fs.readFile('hello.txt', function (err, data) {
    if (!err) { // 如果没错
        // 将数据复制给别的文件
        fs.writeFile('helloCopy.txt', data, function (err) {
            if (!err) {
                console.log('数据复制成功');
            };
        });
    } else {
        console.log(err);
    };
});

流式文件读取

// 引入文件系统
var fs = require('fs');
// 创建一个可读流
var rs = fs.createReadStream('hello.txt');
/* 创建一个可写流 */
var ws = fs.createWriteStream('helloCopy2.txt');
/* 监听可写流 */
ws.once('open', function () {
    console.log('可写流打开了');
});
ws.once('close', function () {
    console.log('可写流关闭了');
});
// 监听可读流
rs.once('open', function () {
    console.log('可读流打开了');
});
rs.once('close', function () {
    console.log('可读流关闭了');
    /* 关闭可写流 */
    ws.end();
});
/* 如果要读取可读流中的数据,需要为可读流绑定一个data事件,data事件绑定完毕后,会自动开始读取数据 */
rs.on('data', function (data) {
    /* 将可读流中的数据写入到可写流中 */
    ws.write(data);
});
// 引入文件系统
var fs = require('fs');
// 创建一个可读流
var rs = fs.createReadStream('hello.txt');
/* 创建一个可写流 */
var ws = fs.createWriteStream('helloCopy2.txt');
/* 监听可写流 */
ws.once('open', function () {
    console.log('可写流打开了');
});
ws.once('close', function () {
    console.log('可写流关闭了');
});
// 监听可读流
rs.once('open', function () {
    console.log('可读流打开了');
});
rs.once('close', function () {
    console.log('可读流关闭了');
});
/* 将可读流中的数据直接写入到可写流中 */
rs.pipe(ws);

fs文件系统模块的其它方法

/* 引入文件系统模块 */
var fs = require('fs');
/* 检查文件是否存在 */
var exists = fs.existsSync('hello.txt');
console.log(exists);
/* 获取文件状态 */
fs.stat('hello.txt', function (err, stat) {
    if (!err) {
        console.log(stat);
    };
});
/* 删除文件 */
var remove = fs.unlinkSync('helloCopy2.txt');
console.log(remove);
/* 读取目录下的目录结构 */
fs.readdir('./', function (err, files) {
    if (!err) {
        console.log(files);
    };
});
/* 截断文件,就是将文件修改为指定大小 */
fs.truncateSync('hello.txt', 15);
/* 创建一个文件夹 */
fs.mkdirSync('test');
/* 删除一个文件夹 */
fs.rmdirSync('test')
/* 重命名文件或文件夹 */
fs.rename('hello.txt', 'test.txt', function (err) {
    if (!err) {
        console.log('重命名成功!!');
    };
});
/* 监视文件的变化 */
fs.watchFile('test.txt', {
    interval: 1000
}, function (curr, prev) {
    console.log('修改前文件信息:' + prev.size);
    console.log('当前文件信息:' + curr.size);
});

MongoDB

安装MongoDB

参考菜鸟教程安装方法: https://www.runoob.com/mongodb/mongodb-osx-install.html

MongoDB默认端口为: http://127.0.0.1:27017/

基本命令

show databases;	# 显示当前所有的数据库
use test;	# 进入数据库
db;	# 查看当前所处的数据库位置
show collections;	# 显示当前数据库下所有的集合
db.students.insert({name:"honksun",age:28});	# 向数据库中插入数据
db.students.find(); # 查询数据

插入文档

// 插入多个文档
db.students.insert([
{name:"洪晨",age:28},
{name:"边昊",age:26}
]);

// 查询文档
db.students.find({});

查询文档

// 查询文档 find 返回的是一个数组,可以加索引
db.students.find({})[0];
// 查询条件是 name=边昊的数据
db.students.find({name:'边昊'});
// 查询集合中符合条件的第一个文档信息,findOne 返回是一个对象
db.students.findOne({name:'边昊'}).name;
// 查询总行数
db.students.find({}).count();

修改文档

db.students.find({});
// 替换文档内容
db.students.update({age:41},{name:"科比",age:41});
// $set 只会修改指定的值,updateMany() 修改多个同时满足条件的文档内容
// {multi:true}/updateMany() 同时修改多个满足条件的内容
db.students.update({name:"边昊"},{$set:{name:"科比"}},{multi:true});
db.students.updateMany({name:"边昊"},{$set:{name:"科比"}});
// $unset 删除指定属性
db.students.update({name:"边昊"},{$unset:{age:28}});

删除文档

// 删除文档
db.students.remove({name:"科比"},{justOne:false});
// 清空集合
db.students.remove({});
// 删除集合
db.students.drop();
// 删除数据库
db.dropDatabase();

练习

//11.向username为sunwukong的文档中,添加一个hobby:{cities:["beijing","shanghai","shenzhen"] , movies:["sanguo","hero"]}
//MongoDB的文档的属性值也可以是一个文档,当一个文档的属性值是一个文档时,我们称这个文档叫做 内嵌文档
db.users.update({username:"sunwukong"},{$set:{hobby:{cities:["beijing","shanghai","shenzhen"] , movies:["sanguo","hero"]}}});
db.users.find();

//12.向username为tangseng的文档中,添加一个hobby:{movies:["A Chinese Odyssey","King of comedy"]}
db.users.update({username:"tangseng"},{$set:{hobby:{movies:["A Chinese Odyssey","King of comedy"]}}})

//13.查询喜欢电影hero的文档
//MongoDB支持直接通过内嵌文档的属性进行查询,如果要查询内嵌文档则可以通过.的形式来匹配
//如果要通过内嵌文档来对文档进行查询,此时属性名必须使用引号 
db.users.find({'hobby.movies':"hero"});

//14.向tangseng中添加一个新的电影Interstellar
//$push 用于向数组中添加一个新的元素
//$addToSet 向数组中添加一个新元素 , 如果数组中已经存在了该元素,则不会添加
db.users.update({username:"tangseng"},{$push:{"hobby.movies":"Interstellar"}});
db.users.update({username:"tangseng"},{$addToSet:{"hobby.movies":"Interstellar"}});
db.users.find();

//15.删除喜欢beijing的用户
db.users.remove({"hobby.cities":"beijing"});

//16.删除user集合
db.users.remove({});
db.users.drop();
//19.查询numbers中num大于5000的文档
db.numbers.find({num:{$gt:500}});
db.numbers.find({num:{$eq:500}});

//20.查询numbers中num小于30的文档
db.numbers.find({num:{$lt:30}});

//21.查询numbers中num大于40小于50的文档
db.numbers.find({num:{$gt:40 , $lt:50}});

//22.查询numbers中num大于19996的文档
db.numbers.find({num:{$gt:19996}});

//23.查看numbers集合中的前10条数据
db.numbers.find({num:{$lte:10}});

//limit()设置显示数据的上限
db.numbers.find().limit(10);
//在开发时,我们绝对不会执行不带条件的查询
db.numbers.find();

//24.查看numbers集合中的第11条到20条数据
/*
    分页 每页显示10条
        1-10     0
        11-20    10
        21-30    20
        。。。
        
        skip((页码-1) * 每页显示的条数).limit(每页显示的条数);
        
    skip()用于跳过指定数量的数据    
    
    MongoDB会自动调整skip和limit的位置
*/
db.numbers.find().skip(10).limit(10);

//25.查看numbers集合中的第21条到30条数据
db.numbers.find().skip(20).limit(10);

db.numbers.find().limit(10).skip(10);
//29.查询工资小于1000或大于2500的员工
db.emp.find({$or:[{sal:{$lt:1000}} , {sal:{$gt:2500}}]});
//31.查询销售部的所有员工
var depno = db.dept.findOne({dname:"销售部"}).deptno;
db.emp.find({depno:depno});
//33.为所有薪资低于1000的员工增加工资400元
/* $inc 在原值基础上自增 */
db.emp.updateMany({sal:{$lte:1000}} , {$inc:{sal:400}});

排序和投影

/*
    sort():排序
        -1: 降序
         1: 生序
*/
db.emp.find({}).sort({sal:-1});
// 投影,显示指定列
db.emp.find({},{ename:1,sal:1});

Mongoose

安装MOngoose

npm install  mongoose --save

Schema和Model

/* 引入Mongoose */
var mongoose = require('mongoose');
/* 链接数据库 */
mongoose.connect('mongodb://127.0.0.1:27017/mongoose_test');
/* 监听数据库连接事件 */
mongoose.connection.once('open', function () {
    console.log('数据库连接成功');
});
/* 创建一个Schema对象 */
var Schema = mongoose.Schema;
var stuSchema = new Schema({
    name: String,
    age: Number,
    gender: {
        type: String,
        default: "female" /* 指定默认值 */
    },
    address: String
});
/* 创建一个model对象 */
var StuModel = mongoose.model('student', stuSchema);
/* 向数据库中插入一个文档 */
StuModel.create({
    name: "洪晨",
    age: 28,
    gender: "male",
    address: "辽宁省沈阳市"
}, function (err) {
    if (!err) {
        console.log('数据插入成功!!!');
    };
});

Model方法

/* 引入Mongoose */
var mongoose = require('mongoose');
/* 链接数据库 */
mongoose.connect('mongodb://127.0.0.1:27017/mongoose_test');
/* 监听数据库连接事件 */
mongoose.connection.once('open', function () {
    console.log('数据库连接成功');
});
/* 创建一个Schema对象 */
var Schema = mongoose.Schema;
var stuSchema = new Schema({
    name: String,
    age: Number,
    gender: {
        type: String,
        default: "female" /* 指定默认值 */
    },
    address: String
});
/* 创建一个model对象 */
var StuModel = mongoose.model('student', stuSchema);
/* 向数据库中插入一个文档 */
StuModel.create([{
    name: "科比",
    age: 41,
    gender: "male",
    address: "美国洛杉矶"
}, {
    name: "詹姆斯",
    age: 37,
    gender: "male",
    address: "美国克利夫兰市"
}], function (err) {
    if (!err) {
        console.log('数据插入成功!!!');
    };
});
/* 查询文件 */
StuModel.find({
    name: '洪晨'
}, function (err, docs) {
    if (!err) {
        console.log(docs);
    };
});
StuModel.find({}, {
    name: 1,
    _id: 0
}, {
    skip: 1,
    limit: 2
}, function (err, docs) {
    if (!err) {
        console.log(docs);
    };
});
/* 修改文件 */
StuModel.updateOne({
    name: "洪晨"
}, {
    $set: {
        age: 27
    }
}, function (err) {
    if (!err) {
        console.log('修改成功!!');
    };
});
/* 删除文档内容 */
StuModel.remove({
    name: '洪晨'
}, function (err) {
    if (!err) {
        console.log('删除成功!!!');
    };
});

Document对象方法

/* 引入Mongoose */
var mongoose = require('mongoose');
/* 链接数据库 */
mongoose.connect('mongodb://127.0.0.1:27017/mongoose_test');
/* 监听数据库连接事件 */
mongoose.connection.once('open', function () {
    console.log('数据库连接成功');
});
/* 创建一个Schema对象 */
var Schema = mongoose.Schema;
var stuSchema = new Schema({
    name: String,
    age: Number,
    gender: {
        type: String,
        default: "female" /* 指定默认值 */
    },
    address: String
});
/* 创建一个model对象 */
var StuModel = mongoose.model('student', stuSchema);
/* 创建一个document对象 */
var stu = new StuModel({
    name: "洪晨",
    age: 28,
    gender: "male",
    address: "辽宁省沈阳市"
});
/* 插入数据库 */
stu.save(function (err) {
    if (!err) {
        console.log("数据插入成功!!!");
    };
});
StuModel.findOne({}, function (err, doc) {
    if (!err) {
        /* 修改doc文档自己 */
        doc.update({
            $set: {
                address: "洛杉矶湖人队"
            }
        }, function (err) {
            if (!err) {
                console.log("修改成功!!!");
            };
        });
        /* doc.age = 42;
        doc.save();
        /* 删除文档 */
        doc.remove(function (err) {
            if (!err) {
                console.log("删除成功!!!");
            };
        });
        /* doc.toJSON()
        doc.toObject() 转换为js对象后,就不能再使用document的方法了 */
    };
});

Grunt

安装Grunt

  1. 项目初始化,创建 package.json 文件

  2. 安装 grunt

    npm i grunt --save-dev
    npm install -g grunt-cli
    
  3. 创建 Gruntfile.js 文件

    module.exports = function (grunt) {
    
        // 初始化配置任务
        grunt.initConfig({
            pkg: grunt.file.readJSON('package.json'),
        });
    
        // 执行任务时加载包含 "uglify" 任务的插件。
        // grunt.loadNpmTasks('grunt-contrib-uglify');
    
        // 默认被执行的任务列表。
        grunt.registerTask('default', ['uglify']);
    
    };
    

合并js文件

安装插件

npm install grunt-contrib-concat --save-dev

配置 Gruntfile.js 文件

module.exports = function (grunt) {

    // 初始化配置任务
    grunt.initConfig({
        // 初始化 grunt-contrib-concat 插件配置, concat 是任务名
        concat: {
            options: {
                /* 文件之间的分隔符 */
                separator: ';',        
            },
            dist: {
                // 源文件,要进行合并的所有文件
                src: ['src/js/*.js'],
                // 指定输出的路径和输出的文件名
                dest: 'build/js/build.js',
            },
        },
    });

    // 执行任务时加载对应任务的插件。
    grunt.loadNpmTasks('grunt-contrib-concat');

    // 默认被执行的任务列表。
    grunt.registerTask('default', []);

};

执行命令

grunt concat

压缩js文件

安装插件

npm install grunt-contrib-uglify --save-dev

配置 Gruntfile.js 文件

uglify: {
            options: {
            	// 压缩文件的注释信息
                banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
                    '<%= grunt.template.today("yyyy-mm-dd") %> */'
            },
            my_target: {
                files: {
                    'build/js/build.min.js': ['build/js/build.js']
                }
            }
        },
        
// 执行任务时加载对应任务的插件。
grunt.loadNpmTasks('grunt-contrib-uglify');

执行压缩命令

grunt uglify

启动默认任务

// 默认被执行的任务列表。要注意任务顺序
grunt.registerTask('default', ['concat','uglify']);

启动默认任务

grunt # 如果默认任务名为 default,则可以不用添加任务名启动

js语法检查

安装插件

npm install grunt-contrib-jshint --save-dev

创建 .jshintrc 文件

{
  "curly": true,
  "eqeqeq": true,
  "eqnull": true,
  "expr" : true,
  "immed": true,
  "newcap": true,
  "noempty": true,
  "noarg": true,
  "regexp": true,
  "browser": true,
  "devel": true,
  "node": true,
  "boss": false,
  
  //不能使用未定义的变量
  "undef": true,
  //语句后面必须有分号
  "asi": false,
  //预定义不检查的全局变量
  "predef": [ "define", "BMap", "angular", "BMAP_STATUS_SUCCESS"]
}

配置 Gruntfile.js 文件

jshint: {
            options: {
                jshintrc: '.jshintrc' //指定配置文件
            },
            build: ['Gruntfile.js', 'src/js/*.js'] //指定检查的文件
        },
            
// 执行任务时加载对应任务的插件。
grunt.loadNpmTasks('grunt-contrib-jshint');

css合并压缩

安装插件

npm install grunt-contrib-cssmin --save-dev

配置 Gruntfile.js 文件

cssmin: {
    options: {
        shorthandCompacting: false,
        roundingPrecision: -1
    },
    build: {
        files: {
            'build/css/build.min.css': ['src/css/*.css']
        }
    }
},

// 执行任务时加载对应任务的插件。
grunt.loadNpmTasks('grunt-contrib-cssmin');

// 默认被执行的任务列表。
grunt.registerTask('default', ['concat', 'uglify', 'jshint', 'cssmin']);

watch插件(自动构建)

安装插件

npm install grunt-contrib-watch --save-dev

配置 Gruntfile.js 文件

module.exports = function (grunt) {

    // 初始化配置任务
    grunt.initConfig({
        // 初始化 grunt-contrib-concat 插件配置, concat 是任务名
        concat: {
            options: {
                /* 文件之间的分隔符 */
                separator: ';',
            },
            dist: {
                // 源文件,要进行合并的所有文件
                src: ['src/js/*.js'],
                // 指定输出的路径和输出的文件名
                dest: 'build/js/build.js',
            },
        },
        pkg: grunt.file.readJSON('package.json'),
        uglify: {
            options: {
                // 压缩文件的注释信息
                banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
                    '<%= grunt.template.today("yyyy-mm-dd") %> */'
            },
            my_target: {
                files: {
                    'build/js/build.min.js': ['build/js/build.js']
                }
            }
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc' //指定配置文件
            },
            build: ['Gruntfile.js', 'src/js/*.js'] //指定检查的文件
        },
        cssmin: {
            options: {
                shorthandCompacting: false,
                roundingPrecision: -1
            },
            build: {
                files: {
                    'build/css/build.min.css': ['src/css/*.css']
                }
            }
        },
        watch: {
            scripts: {
                files: ['src/js/*.js', 'src/css/*.css'],
                tasks: ['concat', 'jshint', 'uglify', 'cssmin'],
                options: {
                    spawn: false
                }
            }
        },
    });

    // 执行任务时加载对应任务的插件。
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-concat');


    // 默认被执行的任务列表。
    grunt.registerTask('default', ['concat', 'uglify', 'jshint', 'cssmin']);
    grunt.registerTask('myWatch', ['default', 'watch']);	

};

执行命令

grunt myWatch # 开发时执行,自动监控文件的修改
grunt # 开发结束后,项目文件合并压缩文件

常用的插件

  • grunt-contrib-clean——清除文件(打包处理生成的)
  • grunt-contrib-concat——合并多个文件的代码到一个文件中
  • grunt-contrib-uglify——压缩js文件
  • grunt-contrib-jshint——javascript语法错误检查;
  • grunt-contrib-cssmin——压缩/合并css文件
  • grunt-contrib-htmlmin——压缩html文件
  • grunt-contrib-imagemin——压缩图片文件(无损)
  • grunt-contrib-copy——复制文件、文件夹
  • grunt-contrib-requirejs——合并压缩requirejs管理的所有js模块文件
  • grunt-contrib-watch——实时监控文件变化、调用相应的任务重新执行

Gulp

  1. 创建 package.json 和 gulpfile.js 两个文件.

  2. 安装 Gulp

    npm install --global gulp-cli
    npm install --save-dev gulp
    npm install gulp-concat gulp-uglify gulp-rename --save-dev # js安装需要的插件
    npm install gulp-less gulp-clean-css --save-dev # css和less需要的插件
    npm install gulp-htmlmin --save-dev # 合并压缩html文件
    npm install gulp-livereload --save-dev # 实时刷新
    npm install gulp-connect --save-dev # 热部署插件
    npm install gulp-load-plugins --save-dev
    
  3. 配置 gulpfile.js 文件

    // 引入对应的插件
    var gulp = require('gulp');
    // $ 表示打包好的gulp插件,使用的方式为 $.concat,$.cleanCss......
    var $ = require('gulp-load-plugins')();
    var concat = require('gulp-concat');
    var uglify = require('gulp-uglify');
    var rename = require('gulp-rename');
    var less = require('gulp-less');
    var cssClean = require('gulp-clean-css');
    var htmlMin = require('gulp-htmlmin');
    var livereload = require('gulp-livereload');
    var connect = require('gulp-connect');
    var open = require('open');
    // 注册任务
    // 合并压缩js文件
    gulp.task('js', function () {
        // 配饰任务的操作
        return gulp.src('./src/js/**/*.js') // 找到目标源文件
            .pipe($.concat('build.js')) // 合并文件
            .pipe(gulp.dest('./dist/js/')) // 临时输出文件到本地
            .pipe(uglify()) // 压缩文件
            .pipe(rename('build.min.js')) // 重命名文件
            .pipe(gulp.dest('./dist/js/')) // 输出文件
            .pipe(livereload()) // 开启实时刷新
            .pipe(connect.reload()); // 开始热部署
    });
    // 注册less文件转换为css文件
    gulp.task('less', function () {
        return gulp.src('./less/*.less') // 找到目标源文件
            .pipe(less()) // 编译less文件为css文件
            .pipe(gulp.dest('./src/css/')) // 输出文件
            .pipe(livereload()) // 开启实时刷新
            .pipe(connect.reload()); // 开始热部署
    });
    // 注册合并压缩css文件
    gulp.task('css', function () {
        return gulp.src('./src/css/*.css') // 找到目标源文件
            .pipe(concat('build.css')) // 合并css文件
            .pipe(cssClean({
                compatibility: 'ie8'
            })) // 压缩css文件,compatibility 设置兼容性
            .pipe(rename({
                suffix: '.min'
            })) // 重命名文件
            .pipe(gulp.dest('./dist/css/')) // 输出文件到指定目录
            .pipe(livereload()) // 开启实时刷新
            .pipe(connect.reload()); // 开始热部署
    });
    // 压缩html文件
    gulp.task('html', function () {
        return gulp.src('./index.html') // 找到目标文件
            .pipe(htmlMin({
                collapseWhitespace: true
            })) // 压缩html,collapseWhitespace:true 去掉空格
            .pipe(gulp.dest('dist/')) // 输出文件到指定位置
            .pipe(livereload()) // 开启实时刷新
            .pipe(connect.reload()); // 开始热部署
    });
    // 注册监视任务
    gulp.task('livereload', function () {
        // 开启监听
        livereload.listen();
        // 确认监听的目标以及绑定相应的任务
        gulp.watch('./src/**/*.*', gulp.parallel('default'));
    });
    // 注册监视任务(全自动热部署)
    gulp.task('connect', function () {
        // 配置服务器选项
        connect.server({
            root: 'dist/',
            livereload: true,
            port: 5000
        });
        // 自动开启链接
        open('http://localhost:5000');
        // 确认监听的目标以及绑定相应的任务
        gulp.watch('./src/**/*.*', gulp.parallel('default'));
    });
    // 注册默认任务
    gulp.task('default', gulp.series('js', 'less', 'css'));
    
  4. 运行任务

    gulp 任务名
    
  • 相关插件
    • gulp-concat : 合并文件(js/css)
    • gulp-uglify : 压缩js文件
    • gulp-rename : 文件重命名
    • gulp-less : 编译less
    • gulp-clean-css : 压缩css
    • gulp-livereload : 实时自动编译刷新
  • 重要API
    • gulp.src(filePath/pathArr) :
      • 指向指定路径的所有文件, 返回文件流对象
      • 用于读取文件
    • gulp.dest(dirPath/pathArr)
      • 指向指定的所有文件夹
      • 用于向文件夹中输出文件
    • gulp.task(name, [deps], fn)
      • 定义一个任务
    • gulp.watch()
      • 监视文件的变化

webpack

  1. 安装

    sudo npm install --save-dev webpack -g
    sudo npm i -g webpack-cli
    # 打包css文件和图片 补充:url-loader是对象file-loader的上层封装,使用时需配合file-loader使用。
    npm install css-loader style-loader --save-dev
    npm install file-loader url-loader --save-dev
    npm install --save-dev webpack-dev-server # 热部署
    
  2. 在js文件中引入css文件

    import '../css/test.css';
    
  3. 创建 webpack.config.js文件

    const path = require('path'); /* node中内置的模块 */
    
    module.exports = {
        mode: 'development',
        /* 打包js文件 */
        entry: './src/js/entry.js',
        /* 输入的源文件 */
        output: {
            filename: 'bundle.js',
            /* 输出文件的名称 */
            path: path.resolve(__dirname, 'dist/js'),
            /* __dirname 根目录,输出文件的位置 */
        },
        /* 配置css文件和图片文件 */
        module: {
            rules: [{
                    test: /\.css$/,
                    use: [
                        'style-loader',
                        'css-loader'
                    ]
                },
                {
                    test: /\.(png|jpg|gif)$/,
                    use: [{
                        loader: 'url-loader',
                        options: {
                            limit: 8192
                        }
                    }]
                }
            ]
        },
        devServer: {
            static: './dist/',
        },
    };
    
  4. 在package.json文件中的script中添加 start 属性

    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "webpack serve --open"
      },
    
  5. 运行 webpack-dev-server 命令

    npm start
    

Promise

语法案例

var btn = document.getElementById('btn');
btn.onclick = function () {
    var p = new Promise((resolve, reject) => {
        setTimeout(() => {
            var n = rand(1, 100);
            if (n <= 30) {
                resolve(n);	// 成功调用 resolve()
            } else {
                reject(n); // 失败调用reject()
            }
        }, 1000);
    });

    p.then((value) => {
        alert("中奖了 "+value);
    }, (reason) => {
        alert("没有中奖 "+reason);
    });
};

fs模块操作

var fs = require('fs');
var p = new Promise((resolve, reject) => {
    fs.readFile('./resource/content.txt', (err, data) => {
        if (err) reject(err);
        resolve(data);
    });
});
p.then(value => {
    console.log(value.toString());
}, reason => {
    console.log(reason);
});

ajax操作

var btn = document.querySelector('#btn');
btn.addEventListener('click', function () {
    var p = new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'https://api.apiopen.top/getJoke');
        xhr.send();
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.response);
                } else {
                    reject(xhr.status);
                };
            };
        };
    });
    p.then(value => {
        console.log(value);
    }, reason => {
        console.error(reason);
    });
});

使用promise封装fs模块

// 封装fs模块
function mineReadFile(path) {
    return new Promise((resolve, reject) => {
        require('fs').readFile(path, (err, data) => {
            if (err) reject(err);
            resolve(data);
        });
    });
};

// 调用 mineReadFile 函数
mineReadFile('./resource/content.txt')
    .then(value => {
        console.log(value.toString());
    }, reason => {
        console.log(reason);
    });

util.promisify 方法

var fs = require('fs');
// promisify 是node中util内置的方法
var mineReadFile = require('util').promisify(fs.readFile);
mineReadFile('./resource/content.txt')
    .then((value) => {
        console.log(value.toString());
    }, (reason) => {
        console.log(reason);
    });

封装ajax请求

// 封装ajax请求
function sendAJAX(url) {
    return new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', url);
        xhr.send();
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.response);
                } else {
                    reject(xhr.status);
                };
            };
        };
    });
};
// 调用sendAJAX函数
sendAJAX('https://api.apiopen.top/getJoke')
    .then((value) => {
        console.log(value);
    }, (reason) => {
        console.log(reason);
    });

自定义Promise对象

class Promise {
    constructor(executor) {
        // 添加属性值
        this.PromiseState = 'pending';
        this.PromiseResult = null;
        // 声明属性
        this.callbacks = [];
        // 保存实例对象的this的值
        var self = this;
        // resolve 函数
        function resolve(data) {
            // 判断状态
            if (self.PromiseState !== 'pending') return;
            // 修改对象的状态(promiseState)
            self.PromiseState = 'resolved';
            // 设置对象结果值(promiseResult)
            self.PromiseResult = data;
            // 调用成功的回调函数
            setTimeout(() => {
                self.callbacks.forEach((item) => {
                    item.onResolved(data);
                });
            });
        };
        // reject 函数
        function reject(data) {
            // 判断状态
            if (self.PromiseState !== 'pending') return;
            // 修改对象的状态(promiseState)
            self.PromiseState = 'rejected';
            // 设置对象结果值(promiseResult)
            self.PromiseResult = data;
            // 调用失败的回调函数
            setTimeout(() => {
                self.callbacks.forEach((item) => {
                    item.onRejected(data);
                });
            });
        };
        // 处理throw抛出的异常
        try {
            // 同步调用执行器函数
            executor(resolve, reject);
        } catch (error) {
            // 修改promise对象状态为失败
            reject(error);
        }

    };

    /* then 方法 */
    then(onResolved, onRejected) {
        var self = this;
        /* 判断回调函数参数 */
        if (typeof onRejected !== 'function') {
            onRejected = reason => {
                throw reason;
            };
        };
        if (typeof onResolved !== 'function') {
            onResolved = value => value;
            /* value=>value 等价于 value=>{ return value} */
        };
        return new Promise((resolve, reject) => {
            /* 封装函数 */
            function callback(type) {
                try {
                    // 获取回调函数执行结果
                    var result = type(self.PromiseResult);
                    // 判断
                    if (result instanceof Promise) {
                        // 如果是 Promise 对象
                        result.then(v => {
                            resolve(v);
                        }, r => {
                            reject(r);
                        });
                    } else {
                        // 结果的对象状态的为成功
                        resolve(result);
                    };
                } catch (error) {
                    reject(error);
                }
            };
            // 调用回调函数
            if (this.PromiseState === 'resolved') {
                setTimeout(() => {
                    callback(onResolved);
                });
            };
            if (this.PromiseState === 'rejected') {
                setTimeout(() => {
                    callback(onRejected);
                });
            };
            // 判断pending状态
            if (this.PromiseState === 'pending') {
                // 保存回调函数
                this.callbacks.push({
                    onResolved: function () {
                        callback(onResolved);
                    },
                    onRejected: function () {
                        callback(onRejected);
                    }
                });
            };
        });

    };
    /* catch 方法 */
    catch (onRejected) {
        return this.then(undefined, onRejected);
    };
    /* resolve 方法 */
    static resolve(value) {
        /* 返回promise对象 */
        return new Promise((resolve, reject) => {
            if (value instanceof Promise) {
                value.then(v => {
                    resolve(v);
                }, r => {
                    reject(r);
                });
            } else {
                /* 状态设置为成功 */
                resolve(value);
            }
        });
    };
    /* 添加reject方法 */
    static reject(reason) {
        return new Promise((resolve, reject) => {
            reject(reason);
        });
    };

    /* 添加all方法 */
    static all(promises) {
        return new Promise((resolve, reject) => {
            /* 声明变量 */
            var count = 0;
            var arr = [];
            /* 遍历数组 promises */
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(v => {
                    /* 代码执行这里,就证明promise状态为resolve */
                    count++;
                    /* 将当前promise对象成功的结果,放到数组中 */
                    arr[i] = v;
                    if (count === promises.length) {
                        resolve(arr);
                    }
                }, r => {
                    reject(r);
                });
            }
        });
    };

    /* 添加race方法 */
    static race(promises) {
        return new Promise((resolve, reject) => {
            for (let i = 0; i < promises.length; i++) {
                promises[i].then(v => {
                    /* 修改返回对象的状态为成功 */
                    resolve(v);
                }, r => {
                    /* 修改返回对象的状态为失败 */
                    reject(v);
                });
            }
        });
    };
};

async && await

/* async 和 await 结合,读取文件操作 */
var fs = require('fs');
var util = require('util');
var mineReadFile = util.promisify(fs.readFile);

async function main() {
    try {
        /* 读取文件内容 */
        var data1 = await mineReadFile('./resource/1.html');
        var data2 = await mineReadFile('./resource/2.html');
        var data3 = await mineReadFile('./resource/3.html');
        console.log(data1 + data2 + data3);
    } catch (error) {
        console.log(error);
    };
};

main();
/* 发送ajax请求 */
function sendAJAX(url) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.responseType = 'json';
        xhr.open("GET", url);
        xhr.send();
        //处理结果
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                //判断成功
                if (xhr.status >= 200 && xhr.status < 300) {
                    //成功的结果
                    resolve(xhr.response);
                } else {
                    reject(xhr.status);
                }
            }
        }
    });
}

//段子接口地址 https://api.apiopen.top/getJoke
var btn = document.getElementById('btn');
btn.onclick = async function () {
    var data = await sendAJAX('https://api.apiopen.top/getJoke');
    console.log(data);
};

axios

创建json-server服务

  1. 安装 json-server

    sudo npm install -g json-server
    
  2. 创建json文件,例如: db.json

    {
        "posts": [
          { "id": 1, "title": "json-server", "author": "typicode" }
        ],
        "comments": [
          { "id": 1, "body": "some comment", "postId": 1 }
        ],
        "profile": { "name": "typicode" }
      }
    
  3. 启动json-server服务

    json-server --watch db.json
    
  4. 安装axios

    npm install axios
    

基本使用语法

// 获取按钮
var btns = document.querySelectorAll('button');
// 发送get请求
btns[0].onclick = function () {
    axios({
        // 请求类型
        method: 'GET',
        // url
        url: 'http://localhost:3000/posts',
    }).then(response => {
        console.log(response);
    });
};
// 发送POST请求
btns[1].onclick = function () {
    axios({
        // 请求类型
        method: 'POST',
        // url
        url: 'http://localhost:3000/posts',
        //  请求体
        data: {
            title: "axios npm 难装",
            author: "fuck you"
        }
    }).then(response => {
        console.log(response);
    });
};
// 发送PUT请求,更新数据
btns[2].onclick = function () {
    axios({
        // 请求类型
        method: 'PUT',
        // url
        url: 'http://localhost:3000/posts/6',
        //  请求体
        data: {
            title: "修改后的数据内容",
            author: "HELLO"
        }
    }).then(response => {
        console.log(response);
    });
};
// 发送DELETE请求,删除数据
btns[3].onclick = function () {
    axios({
        // 请求类型
        method: 'DELETE',
        // url
        url: 'http://localhost:3000/posts/6'
    }).then(response => {
        console.log(response);
    });
};
// 获取按钮
var btns = document.querySelectorAll('button');
// 发送get请求
btns[0].onclick = function () {
    axios.request({
        method:'GET',
        url:'http://localhost:3000/comments'
    }).then(response=>{
        console.log(response);
    });
};
// 发送POST请求
btns[1].onclick = function () {
    axios.post('http://localhost:3000/comments',
    {
      body: "第四条文章的评论",
      postId: 4
    }).then((response)=>{
        console.log(response);
    });
};

取消请求

var btn = document.querySelectorAll('button');
const CancelToken = axios.CancelToken;
// 2.定义一个全局变量
var cancel = null;
btn[0].onclick = function () {
    // 检测上一次请求是否完成
    if (cancel !== null) {
        // 取消上一次请求
        cancel();
    }
    axios({
        method: 'GET',
        url: 'http://localhost:3000/posts',
        // 1.添加配置对象请求
        cancelToken: new CancelToken(function executor(c) {
            // executor 函数接收一个 cancel 函数作为参数
            cancel = c;
        })
    }).then(response => {
        console.log(response);
        // 将cancel值初始化为 null
        cancel = null;
    });
};
btn[1].onclick = function () {
    // 取消请求
    cancel();
};

TypeScript

安装typescript

sudo npm i -g typescript

将ts文件编译成js文件

tsc 文件名.ts

基本类型

/* 声明一个number类型的变量 */
let a: number;
/* 对a进行赋值 */
a = 100;
/* 如果变量的声明和赋值是同时进行的,TS可以自动对变量进行类型检测 */
let c = true;
/* 声明函数的参数类型 */
function sum(a: number, b: number): number { /* 声明函数返回值的类型 */
    return a + b;
};
/* 可以使用 | 来连接多个类型(联合类型) */
let d: string | number;
d = 'hello';
d = 345;
/* 类型断言 */
let e: unknown;
let f = 'hello';
/* 断言语法 */
f = e as string;
f = <string>e;
/* void 用来表示空,以函数为例,就表示没有返回值的函数 */
function fn(): void {
};
/* never 表示永远不会有返回结果 */
function fn1(): never {
    throw new Error('出错了');
};
/* [propName: string]: any 表示任意类型的属性 */
let g: { name: string, [propName: string]: any };
g = { name: 'hongchen', age: 28 };
/* 设置函数结构的类型声明 */
let h: (a: number, b: number) => number;
h = function (n1, n2) {
    return 10;
};
/* 声明数组类型 */
let i: string[];
let j: number[];
/* 元组:固定长度的数组 */
let k: [number, number];
/* enum 枚举 */
enum Gender {
    male = 0,
    famale = 1
};
let l: { name: string, gender: Gender };
l = {
    name: 'hongchen',
    gender: Gender.male
};
/* 类型的别名 */
type myTy = 1 | 2 | 3 | 4 | 5;
let m: myTy;

编译选项

tsc 01.ts -w # -w 监视单个ts文件变化,自动更新js文件

创建 tsconfig.json 文件

{
    /* 
        include,指定需要编译的ts文件 
        src下的所有文件,  
        **:任意目录,   
        *:任意文件
    */
    "include": [
        "./src/**/*"
    ],
    /* exclude 排除需要编译的文件 */
    "exclude": [
        "./src/hello/**/*"
    ],
    // compilerOptions 编译器的选项
    "compilerOptions": {
        // target : 用来指定ts被编译的ES版本
        "target": "ES6",
        // module : 指定使用模块化的规范
        "module": "ES6",
        // lib:指定项目中需要使用的库, 一般情况下不需要修改
        // "lib": []
        // outDir:编译后的js文件存放的目录位置
        "outDir": "./dist",
        // 是否允许编译器编译js文件,默认是false
        "allowJs": false,
        // 是否检查js符合语法规范
        "checkJs": false,
        // 是否移除注释
        "removeComments": false,
        // 是否生成编译后的js文件
        "noEmit": false,
        // 当有错误时不生成js文件
        "noEmitOnError": false,
        // 设置编译后的js文件是否启动严格检查模式
        "alwaysStrict": true,
        // 不允许隐式的any类型
        "noImplicitAny": false,
        // 不允许不明确类型的this
        "noImplicitThis": false,
        // 严格检查空值
        "strictNullChecks": false
    }
}
tsc
tsc -w

webpack打包ts代码

npm init --yes
cnpm i -D webpack webpack-cli typescript ts-loader
cnpm i -D html-webpack-plugin
cnpm i -D webpack-dev-server
cnpm i -D clean-webpack-plugin # 先清空目标目录,再重新生成
cnpm i -D @babel/core @babel/preset-env babel-loader core-js # 解决代码兼容性问题

创建 webpack.config.js 文件

const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {
    CleanWebpackPlugin
} = require('clean-webpack-plugin');

module.exports = {
    mode: 'development',
    //   入口文件
    entry: './src/index.ts',
    //   输出打包后的文件位置
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'index.bundle.js',
        environment: {
            arrowFunction: false // 关闭webpack自带的 ()=> 箭头函数
        }
    },
    // 指定webpack打包时要使用的模块
    module: {
        // 指定要加载的规则
        rules: [{
            // test 指定的是要生效的文件
            test: /\.ts$/,
            // 需要使用的模块
            use: [
                // 配置loader
                {
                    // 指定加载器
                    loader: 'babel-loader',
                    // 设置babel
                    options: {
                        // 设置预定义环境
                        presets: [
                            [
                                // 指定环境的插件
                                '@babel/preset-env',
                                // 配置信息
                                {
                                    // 要兼容的浏览器的版本
                                    targets: {
                                        "chrome": "88",
                                        "ie": "6"
                                    },
                                    // 指定corejs版本
                                    "corejs": "3",
                                    // 指定使用corejs的方式,usage:按需加载
                                    "useBuiltIns": "usage"
                                }
                            ]
                        ]
                    }
                },
                'ts-loader'
            ],
            // 要排除的文件
            exclude: /node-modules/
        }]
    },
    plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            template: "./src/index.html"
        }),
    ],

    // 设置引用模块
    resolve: {
        // 以 ts,js 后缀名的文件都可以作为引用模块
        extensions: [".ts", ".js"]
    }
};

创建 tsconfig.json 文件

{
    "compilerOptions": {
        "module": "ES6",
        "target": "ES6",
        "strict": true
    }
}

修改 package.json 文件

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build":"webpack", // 在 scripts 处添加此行代码
    "start": "webpack serve --open"
  },

执行打包命令

npm run build

类的基础

/* abstract 表示该类是抽象类,抽象类是专门给别的类继承用的 */
abstract class Animal {
    /* 类的属性 */
    name: string;
    age: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.age = age;
    };
    /* 类的方法 */
    sayHello() {
        console.log('hello');
    };
    /* 抽象方法,子类必须对该方法进行重写 */
    abstract sayBye(): void;
};
/* 子类Dog继承父类Animal */
class Dog extends Animal {
    address: string;
    constructor(name: string, age: number, address: string) {
        /* super 就表示当前类的父类
        如果在子类中写了构造函数,在子类构造函数中必须对父类的构造函数进行调用 */
        super(name, age); /* 调用父类的构造函数 */
        this.address = address;
    };
    /* 重写方法 */
    sayHello(): void {
        console.log('这是dog类中的sayhello');

    };
    /* 添加方法 */
    run() {
        console.log(`${this.name}` + "在奔跑!!!");

    };
    /* 从写父类的抽象方法 */
    sayBye() {
        console.log('bye bye');

    }
};

接口

/* 接口用来定义一个类的结构,用来定义一个类中应该包含哪些属性和方法
同时接口也可以当成类型声明去使用
接口可以重名,使用重名的接口,接口属性和方法会进行汇总
接口可以在定义类的时候去限制类的结构
接口中所有的属性都不能有实际的值,只定义对象的结构
在接口中,所有的方法都是抽象方法 */
interface myInterface {
    name: string;
    age: number
};
interface myInterface {
    gender: string,
    sayHello(): void;
};

const person: myInterface = {
    name: "honksun",
    age: 28,
    gender: "male",
    sayHello() {
        console.log('hello');

    },
};

class Person implements myInterface {
    name: string;
    age: number;
    gender: string;
    constructor(name: string, age: number, gender: string) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    };
    sayHello(): void {
        console.log(`${this.name}` + " say hello");

    };
};

var honksun = new Person('honksun', 28, "male");
honksun.sayHello();

属性的封装

class Person {
    /*
        public :公共属性,可以在任意位置访问和修改
        private : 私有属性,只能在类内部进行访问和修改
        protected : 受保护的属性,只能在当前类和当前类的子类中访问和修改
    */
    private _name: string;
    private _age: number;
    constructor(name: string, age: number) {
        this._name = name;
        this._age = age;
    };

    /* 定义方法,用来获取属性值 */
    getName() {
        return this._name;
    };
    /* 定义方法,用来设置属性值 */
    setName(value: string) {
        this._name = value;
    };
    /* TS中设置getter和setter方法 */
    get age() {
        return this._age;
    };
    set age(value: number) {
        this._age = value;
    };
};
/* 类的简写语法 */
class Test {
    constructor(
        public name: string,
        private age: number,
        protected gender: string
    ) { };
};


let x = new Person("honksun", 28);
x.age = 40;
console.log(x.age);

泛型

/* 在定义函数或类时,如果遇到类型不明确,就可以使用泛型 */
function fn<T>(a: T): T {
    return a;
};
// 泛型可以同时指定多个
function fn2<T, K, L>(a: T): T {
    return a;
}
// 调用具有泛型的函数
fn(10);
fn<string>("hello");

Vue2

vs code插件

Vue 3 Snippets

搭建Vue开发环境

  1. 下载Vue.js,在html文件中引入

  2. 在浏览器中安装 vue-devtools 开发工具

  3. 在全局配置中配置 阻止 vue 在启动时生成生产提示.

    Vue.config.productionTip = false; // 阻止 vue 在启动时生成生产提示.
    

初始Vue

<div id="root">
    <h1>hello,{{name}}</h1>
    <hr>
    <h1>指令语法</h1>
    <!-- v-bind: 可以简写为 : -->
    <a v-bind:href="url">百度</a>
</div>
<!-- 引入vue -->
<script src="../js/vue.js"></script>
<script>
    Vue.config.productionTip = false;
    const x = new Vue({
        el: "#root", /* 元素选择器 */
        data: { /* date中存储数据,供 el 所指定的容器使用 */
            name: 'honksun',
            url: 'https://www.baidu.com/'
        },
    });
</script>

数据绑定

<div id="root">
    单向数据绑定: <input type="text" v-bind:value="name"><br>
    双向数据绑定: <input type="text" v-model:value="name"><br>
    <!-- 简写方式 -->
    单向数据绑定: <input type="text" :value="name"><br>
    双向数据绑定: <input type="text" v-model="name"><br>
</div>
<!-- 引入vue -->
<script src="../js/vue.js"></script>
<script>
    Vue.config.productionTip = false;
    const x = new Vue({
        el: "#root", /* 元素选择器 */
        data: { /* date中存储数据,供 el 所指定的容器使用 */
            name: 'honksun',
        },
    });
</script>

Object.defineProperty()

let number = 28;
let person = {
    name: 'honksun',
    gender: "male"
};

/* Object.defineProperty()方法,向对象中追加属性 */
Object.defineProperty(person, 'age', {
    // value: 28,
    // enumerable: true,    /* 控制属性是否可以枚举,默认值是false */
    // writable:true,   /* 控制属性是否可以修改,默认值是false */
    // configurable: true   /* 控制属性是否可以被删除,默认值是false */
    /* 当读取person中的age属性时,get函数(getter)就会被调用,且返回值就是age的值 */
    get: function () {
        return number
    },
    /* 当设置person中的age属性时,set函数(setter)就会被调用,且会收到具体修改的值 */
    set(value) {
        number = value;
    }
});

鼠标事件

<div id="root">
    <h2>hello,{{name}}</h2>
    <!-- v-on:click 鼠标点击事件 -->
    <button v-on:click='showInfo'>点我提示信息</button>
    <!-- 简写方式 -->
    <button @click='showInfo'>点我提示信息2</button>
    <!-- 传入参数 -->
    <button @click='showInfo2($event,666)'>点我提示信息3</button>
</div>
<script src="../js/vue.js"></script>
<script>
    new Vue({
        el: "#root",
        data: {
            name: 'honksun'
        },
        /* 事件的回调 */
        methods: {
            showInfo() {
                alert('hello')
            },
            showInfo2(event, number) {
                console.log(event, number);
            },
        },
    });
</script>

事件修饰符

<div id="root">
    <h2>hello,{{name}}</h2>
    <a href="http://baidu.com" @click='showInfo'>baidu</a>
    <!-- .once 事件只触发一次 -->
    <button @click.once='showInfo'>点击</button>
</div>
<script src="../js/vue.js"></script>
<script>
    new Vue({
        el: "#root",
        data: {
            name: 'honksun'
        },
        /* 事件的回调 */
        methods: {
            showInfo(e) {
                e.preventDefault(); /* 阻止默认行为 */
                e.stopPropagation();    /* 阻止事件冒泡 */
                alert('hello')
            },
        },
    });
</script>

键盘事件

<div id="root">
    <h2>hello,{{name}}</h2>
    <!-- 键盘事件 -->
    <input type="text" placeholder="按下回车键,输出内容" @keyup.enter='showInfo'>
    <!-- 系统键组合按键,@keyup.ctrl.y -->
    <input type="text" placeholder="按下回车键,输出内容" @keyup.ctrl.y='showInfo'>
    <!-- 使用自定义别名按键 -->
    <input type="text" placeholder="按下自定义回车键,输出内容" @keyup.huiche='showInfo'>
</div>
<script src="../js/vue.js"></script>
<script>
    /* 自定义别名按键 */
    Vue.config.keyCodes.huiche = 13,
        new Vue({
            el: "#root",
            data: {
                name: 'honksun'
            },
            /* 事件的回调 */
            methods: {
                showInfo(e) {
                    console.log(e.target.value);
                },
            },
        });
</script>

计算属性

<div id="root">
    姓: <input type="text" v-model='firstName'> <br><br>
    名: <input type="text" v-model='lastName'> <br><br>
    全名: <span>{{fullName}}</span>
</div>
<script src="../js/vue.js"></script>
<script>
    const vm = new Vue({
        el: "#root",
        data: {
            firstName: '洪',
            lastName: "晨"
        },
        /* 计算属性 */
        computed: {
            fullName: {
                get() {
                    return this.firstName + ' - ' + this.lastName;
                },
                set(value) {
                    const arr = value.split('-');
                    this.firstName = arr[0];
                    this.lastName = arr[1];
                }
            },
        },
    });
</script>

监视属性

<div id="root">
    <h2>今天天气很{{info}}</h2>
    <button @click='changeWeather'>天气切换</button>
    <hr>
    <h3>a的值是:{{number.a}}</h3>
    <button @click='number.a++'>a自增</button>
    <h3>b的值是:{{number.b}}</h3>
    <button @click='number.b++'>b自增</button>

</div>
<script src="../vue.js"></script>
<script src="../js/vue.js"></script>
<script>
    Vue.config.productionTip = false
    const vm = new Vue({
        el: "#root",
        data: {
            isHot: true,
            number: {
                a: 1,
                b: 2
            },
        },
        computed: {
            info: {
                get() {
                    return this.isHot ? "炎热" : "死冷";
                },
            },
        },
        methods: {
            changeWeather() {
                this.isHot = !this.isHot;
            },
        },
        /* 第二种监视属性的方法 */
        /* 监视属性 */
        watch: {
            /* 被监视的属性名 */
            isHot: {
                /* 打开页面,立即监视属性 */
                immediate: true,
                handler(newValue, oldValue) {
                    console.log(newValue, oldValue);
                },
            },
            // 简写方式
            isHot(newValue, oldValue) {
                console.log(newValue, oldValue);
            },
            /* 深度监视,监视多级结构中所有属性的变化 */
            number: {
                /* 开启深度监视 */
                deep: true,
                handler(newValue, oldValue) {
                    console.log("number发生了变化");
                },
            }
        },
    });
    /* 第二种监视属性的方法 */
    // vm.$watch('isHot', {
        //     /* 打开页面,立即监视属性 */
        //     immediate: true,
        //     handler(newValue, oldValue) {
        //         console.log('$watch '+newValue, oldValue);
        //     },
        // });
</script>

绑定样式

<div id="root">
	<!-- 绑定class样式:字符串写法 类名不确定,要动态获取。 -->
	<div class="basic" :class="mood" @click="changeMood">{{name}}</div><br><br>
	<!-- 绑定class样式:数组写法 要绑定多个样式,个数不确定,名字也不确定。 -->
	<div class="basic" :class="classArr">{{name}}</div><br><br>
	<!-- 绑定class样式:对象写法 要绑定多个样式,个数确定,名字也确定,但不确定用不用。 -->
	<div class="basic" :class="classObj">{{name}}</div><br><br>
	<!-- 操作style样式 -->
	<div class="basic" :style="myStyle">{{name}}</div><br><br>
</div>
</body>

<script type="text/javascript">
Vue.config.productionTip = false

const vm = new Vue({
	el: '#root',
	data: {
		name: '尚硅谷',
		mood: "normal",
		classArr: ['atguigu1', 'atguigu2', 'atguigu3'],
		classObj: {
			atguigu1: true,
			atguigu2: false
		},
		myStyle: {
			fontSize: '40px'
		}
	},
	methods: {
		changeMood() {
			const arr = ['happy', 'sad', 'normal'];
			const index = Math.floor(Math.random() * 3);
			this.mood = arr[index];
		}
	},
})
</script>

条件渲染

<!-- v-show -->
<h2 v-show="false">hello,nba-all-star</h2>
<!-- v-if v-else-if v-else -->
<h3 v-if="n===1">kobe</h3>
<h3 v-else-if="n===2">james</h3>
<h3 v-else>durent</h3>
<!-- template 不会影响页面结构,但是只能和v-if配合使用 -->
<template v-if="n===5">
	<h2>科比</h2>
	<h2>乔丹</h2>
	<h2>詹姆斯</h2>
</template>

列表渲染

<ul>
	<!-- v-for 遍历数组,一定要写key值,并且key值唯一的 -->
	<li v-for="(p,index) in persons" :key="index">
		{{p.name}}-{{p.age}}
	</li>
</ul>
<ul>
	<!-- v-for 遍历对象,一定要写key值,并且key值唯一的 -->
	<li v-for="(value,attribute) in car" :key="attribute">
		{{value}}-{{attribute}}
	</li>
</ul>

列表过滤

<div id="root">
	<h2>人员列表</h2>
	<input type="text" placeholder="请输入名字" v-model="keyWord">
	<ul>
		<li v-for="(p,index) of filPersons" :key="index">
			{{p.name}}-{{p.age}}-{{p.sex}}
		</li>
	</ul>
</div>

<script type="text/javascript">
	Vue.config.productionTip = false

	new Vue({
		el: '#root',
		data: {
			keyWord: '',
			persons: [
				{ id: '001', name: '马冬梅', age: 19, sex: '女' },
				{ id: '002', name: '周冬雨', age: 20, sex: '女' },
				{ id: '003', name: '周杰伦', age: 21, sex: '男' },
				{ id: '004', name: '温兆伦', age: 22, sex: '男' }
			],
			// filPersons: []
		},
		/* watch侦听实现 */
		watch: {
			keyWord: {
				immediate: true,
				handler(val) {
					this.filPersons = this.persons.filter((p) => {
						return p.name.indexOf(val) !== -1
					});
				},
			},
		},
		/* computed 计算属性方式,常用方式 */
		computed: {
			filPersons() {
				return this.persons.filter((p) => {
					return p.name.indexOf(this.keyWord) !== -1;
				});
			},
		},
	});
</script>

列表排序

<div id="root">
	<h2>人员列表</h2>
	<input type="text" placeholder="请输入名字" v-model="keyWord">
	<button @click="sortType = 2">年龄升序</button>
	<button @click="sortType = 1">年龄降序</button>
	<button @click="sortType = 0">原顺序</button>
	<ul>
		<li v-for="(p,index) of filPerons" :key="p.id">
			{{p.name}}-{{p.age}}-{{p.sex}}
			<input type="text">
		</li>
	</ul>
</div>

<script type="text/javascript">
	Vue.config.productionTip = false

	new Vue({
		el: '#root',
		data: {
			keyWord: '',
			sortType: 0, //0原顺序 1降序 2升序
			persons: [
				{ id: '001', name: '马冬梅', age: 30, sex: '女' },
				{ id: '002', name: '周冬雨', age: 31, sex: '女' },
				{ id: '003', name: '周杰伦', age: 18, sex: '男' },
				{ id: '004', name: '温兆伦', age: 19, sex: '男' }
			]
		},
		computed: {
			filPerons() {
				const arr = this.persons.filter((p) => {
					return p.name.indexOf(this.keyWord) !== -1;
				});
				/* 判断是否需要排序 */
				if (this.sortType) {	/* 需要排序 */
					arr.sort((p1, p2) => {
						return this.sortType === 1 ? p2.age - p1.age : p1.age - p2.age;
					});
				};
				return arr;
			},
		},
	});
</script>

Vue.set()和 vm.$set()

addSex() {
	Vue.set(this.student, 'sex', '男');
},
addFriend() {
	this.student.friends.unshift({ name: 'honksun', age: 28 });
},
updateFirstFriendName() {
	this.student.friends[0].name = '洪晨';
},
addHobby() {
	this.student.hobby.push("开车");
},
updateHobby() {
	this.student.hobby.splice(0, 1, 'kaiche');
},
removeSmoke() {
	this.student.hobby = this.student.hobby.filter((h) => {
		return h !== '抽烟';
	});
}

v-model 收集表单数据

若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
若:<input type="checkbox"/>
		1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
		2.配置input的value属性:
				(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
				(2)v-model的初始值是数组,那么收集的的就是value组成的数组
备注:v-model的三个修饰符:
				lazy:失去焦点再收集数据
				number:输入字符串转为有效的数字
				trim:输入首尾空格过滤

过滤器

Moment.js 和 Day.js 可以用来格式化时间,需要传递时间戳.

<div id="root">
	<h2>显示格式化后的时间</h2>
	<!-- 使用过滤器 -->
	<h3>{{time | timeFormat}}</h3>
	<!-- 过滤器传参,同时也可以多个过滤器串联使用 -->
	<h3>{{time | timeFormat('YYYY-MM-DD') | mySlice}}</h3>
</div>
</body>

<script type="text/javascript">
	Vue.config.productionTip = false;
	// 配置全局过滤器
	Vue.filter('mySlice', function (value) {
		return value.slice(0, 4);
	});
	new Vue({
		el: '#root',
		data: {
			time: 1645518515442
		},
		// 局部过滤器
		filters: {
			timeFormat(value, str = 'YYYY-MM-DD HH:mm:ss') {
				return dayjs(value).format(str);
			},
		},
	});
</script>

内置指令

v-text指令:
		1.作用:向其所在的节点中渲染文本内容。
		2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
v-html指令:
		1.作用:向指定节点中渲染包含html结构的内容。
		2.与插值语法的区别:
					(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
					(2).v-html可以识别html结构。
		3.严重注意:v-html有安全性问题!!!!
					(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
					(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
v-cloak指令(没有值):
		1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
		2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
v-once指令:
			1.v-once所在节点在初次动态渲染后,就视为静态内容了。
			2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
v-pre指令:
		1.跳过其所在节点的编译过程。
		2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。

自定义指令

<div id="root">
	<h2>{{name}}</h2>
	<h2>当前的n值是:<span v-text="n"></span> </h2>
	<!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> -->
	<h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
	<button @click="n++">点我n+1</button>
	<hr />
	<input type="text" v-fbind:value="n">
</div>
</body>

<script type="text/javascript">
	Vue.config.productionTip = false

	//定义全局指令
	/* Vue.directive('fbind',{
		//指令与元素成功绑定时(一上来)
		bind(element,binding){
			element.value = binding.value
		},
		//指令所在元素被插入页面时
		inserted(element,binding){
			element.focus()
		},
		//指令所在的模板被重新解析时
		update(element,binding){
			element.value = binding.value
		}
	}) */

	new Vue({
		el: '#root',
		data: {
			name: 'honksun',
			n: 1
		},
		/* 自定义指令 */
		directives: {
			/* 函数式自定义指令 */
			big(element, binding) {
				element.innerText = binding.value * 10;
			},
			/* 函数式自定义指令 */
			/* 'big-number'(element, binding) {
				element.innerText = binding.value * 10;
			}, */
			/* 对象式自定义 */
			fbind: {
				/* 指令于元素成功绑定时 */
				bind(element, binding) {
					element.value = binding.value;
				},
				/* 指令所在元素被插入页面时 */
				inserted(element, binding) {
					element.focus();
				},
				/* 指令所在模版被重新解析时 */
				update(element, binding) {
					element.value = binding.value;
				},
			},
		},
	});
</script>

生命周期函数

<div id="root">
	<h2 v-if="a">你好啊</h2>
	<h2 :style="{opacity}">欢迎学习Vue</h2>
</div>
</body>

<script type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

	new Vue({
		el: '#root',
		data: {
			a: false,
			opacity: 1
		},
		/* 在Vue完成模版的解析并把初始的真实DOM元素放入页面后(挂在完毕)调用mounted */
		mounted() {
			setInterval(() => {
				this.opacity -= 0.01;
				if (this.opacity <= 0) this.opacity = 1;
			}, 50);
		},
	});
</script>
常用的生命周期钩子:
		1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
		2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

非单文件组件

<div id="root">
	<!-- 3.使用组件 -->
	<info></info>
</div>
</body>

<script type="text/javascript">
	Vue.config.productionTip = false;

	// 1.创建一个组件
	const info = Vue.extend({
		template: `
		<div>
			<h2>姓名是:{{name}}</h2>
			<h2>年龄是:{{age}}</h2>
		</div>
		`,
		// 组件中的data一定要写成函数式的
		data() {
			return {
				name: 'honksun',
				age: 28
			}
		}
	});
	// 全局注册组件,一定要写在组件下面
	// Vue.component('info',info);

	new Vue({
		el: '#root',
		// 局部注册组件
		components: {
			info: info
		}
	});
</script>

单文件组件

  1. 具体功能组件.vue
  2. App.vue 汇总所有功能组件
  3. main.js 注册App.vue 组件
  4. 在index.html 页面引入 main.js 文件

脚手架

安装

npm install -g @vue/cli

创建项目

vue create 项目名称

进入项目目录,启动项目

cd vue_test_copy
npm run serve

Vue CLI 配置文件

vue.config.js

module.exports = {
  // 关闭语法检查
  lintOnSave: false
}

ref属性

1. 被用来给元素或子组件注册引用信息(id的替代者)
2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
3. 使用方式:
  1. 打标识:<h1 ref="xxx">.....</h1>或 <School ref="xxx"></School>
  2. 获取:this.$refs.xxx

props 属性

组件传值

<SchoolName name="软件学院" :phone="12345678"></SchoolName>

接收值

props:{
    name:{
      type:String,
      required:true // 参数必传
    },
    phone:{
      type:Number,
      default:9999 // 默认值
    }
  }
  // 简单接收参数
  props:['name','phone']

  props:{
    name:String,
    phone:Number
  }

mixin 混入

  1. 创建一个外部混入文件

    export const mixin={
        methods:{
            showName(){
              alert(this.name)
            }
          }
    }
    
  2. 引入混合文件并使用

    <div>
      <h2 @click="showName">自己的测试代码</h2>
      <h3>学校的名字:{{ name }}</h3>
      <h3>学校的号码:{{ phone }}</h3>
    </div>
    </template>
    
    <script>
    // 引入外部混合
    import {mixin} from '../js/mixin'
    export default {
      name:'SchoolName',
      data() {
        return {
          name:"NBA",
          phone:1234
        };
      },
      // 使用外部混合
      mixins:[mixin]
    };
    </script>
    

插件

  1. 新建一个plugins.js文件

    export default {
        /* install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。 */
        install(Vue, a, b, c) {
            console.log('插件实现的方法');
        }
    }
    
  2. 在 main.js中使用

    /* 引用插件 */
    import plugins from '../plugins'
    /* 使用插件 */
    Vue.use(plugins)
    

scoped样式

  1. 作用:让样式在局部生效,防止冲突。

  2. 写法:<style scoped>

# 查看组件所有的版本号
npm view less-loader versions
# @ 指定安装的版本
npm install less-loader@7
# 随机生成ID
npm i nanoid

统计符合条件的数组中的项目个数

doneTotal() {
  /* reduce 按条件统计数组中符合条件的个数 */
  return this.todos.reduce((pre, todo) => {
    /* pre 从0开始 */
    return pre + (todo.done ? 1 : 0);
  }, 0);
},

webStorage

  1. 存储内容大小一般支持5MB左右(不同浏览器可能还不一样)

  2. 浏览器端通过 Window.sessionStorage 和 Window.localStorage 属性来实现本地存储机制。

  3. 相关API:

​ 1. xxxxxStorage.setItem('key', 'value');

​ 该方法接受一个键和值作为参数,会把键值对添加到存储中,如果键名存在,则更新其对应的值。

​ 2. xxxxxStorage.getItem('person');

​ 该方法接受一个键名作为参数,返回键名对应的值。

​ 3. xxxxxStorage.removeItem('key');

​ 该方法接受一个键名作为参数,并把该键名从存储中删除。

​ 4. xxxxxStorage.clear()

​ 该方法会清空存储中的所有数据。

  1. 备注:

​ 1. SessionStorage存储的内容会随着浏览器窗口关闭而消失。

​ 2. LocalStorage存储的内容,需要手动清除才会消失。

​ 3. xxxxxStorage.getItem(xxx)如果xxx对应的value获取不到,那么getItem的返回值是null。

​ 4. JSON.parse(null)的结果依然是null。

组件的自定义事件

适用于 : 子组件 ===》父组件

  1. 父组件

    <template>
      <div>
        <h2>{{ msg }}</h2>
        <!-- 通过父组件给子组件绑定一个自定义事件实现:子组件给父组件传值 -->
        <MySchool v-on:honksun="demo"></MySchool>
        <!-- 子组件使用原生事件 -->
        <MySchool @click.native="show"></MySchool>
      </div>
    </template>
    
    <script>
    import MySchool from "./components/MySchool.vue";
    export default {
      name: "App",
      data() {
        return {
          msg: "hello",
        };
      },
      components: { MySchool },
      methods: {
        /* ...params 表示将name以外的参数放到 params 数组中 */
        demo(name, ...params) {
          this.msg = name;
        },
        show() {
          alert(123);
        },
      },
    };
    </script>
    
  2. 子组件

    <template>
      <div>
        <h3>学校的名字是:{{ name }}</h3>
        <h3>学校的地址是:{{ address }}</h3>
        <button @click="sendName">将学校名字发送给app</button>
        <button @click="unbind">解绑事件</button>
      </div>
    </template>
    
    <script>
    export default {
      name: "MySchool",
      data() {
        return {
          name: "蓝翔",
          address: "山东",
        };
      },
      methods: {
        sendName() {
          /* 触发student组件实例身上的honksun事件,并传递多个参数值 */
          this.$emit("honksun", this.name);
        },
        /* 解绑事件 */
        unbind() {
          /* 解绑单个事件 */
          this.$off("honksun");
          /* 解绑多个事件 */
          this.$off(["honksun", "demo", "demo1"]);
          /* 解绑所有事件 */
          this.$off();
        },
      },
    };
    </script>
    

全局事件总线

  1. 在 main.js 中创建全局事件总线

    new Vue({
      render: h => h(App),
      /* 创建全局组件总线 */
      beforeCreate() {
        Vue.prototype.$bus = this;
      }
    }).$mount('#app')
    
  2. 在需要数据的组件上绑定一个事件

    mounted() {
      /* 绑定一个school事件 */
      this.$bus.$on("school", (data) => {
        console.log("收到的学校名字是:" + data);
      });
    },
    /* 销毁前解绑自己的绑定之间,千万不要解绑所有 */
    beforeDestroy() {
      this.$bus.$off("school");
    },
    
  3. 在提供数据的组件上触发这个事件

    methods: {
      sendSchoolName() {
        /* 触发名为school的事件 */
        this.$bus.$emit("school", this.name);
      },
    },
    

消息订阅于发布

  1. 安装第三方插件库

    sudo npm i pubsub-js -g
    
  2. 订阅消息

    <template>
      <div>
        <h1>{{ name }}</h1>
        <h1>收到的学校名字为:{{ schoolName }}</h1>
      </div>
    </template>
    
    <script>
    import pubsub from "pubsub-js";
    export default {
      name: "MyStudentS",
      data() {
        return {
          name: "kobe",
          schoolName: "",
        };
      },
      mounted() {
        /* 订阅消息 */
        this.pubId = pubsub.subscribe("SchoolName", (msgName, data) => {
          this.schoolName = data;
        });
      },
      beforeDestroy() {
        /* 取消订阅 */
        pubsub.unsubscribe(this.pubId);
      },
    };
    </script>
    
  3. 发布消息

    <template>
      <div>
        <h3>学校的名字是:{{ name }}</h3>
        <h3>学校的地址是:{{ address }}</h3>
        <button @click="sendName">发布消息</button>
      </div>
    </template>
    
    <script>
    import pubsub from "pubsub-js";
    export default {
      name: "MySchool",
      data() {
        return {
          name: "蓝翔",
          address: "山东",
        };
      },
      methods: {
        sendName() {
          /* 发布消息 */
          pubsub.publish("SchoolName", this.name);
        },
      },
    };
    </script>
    

$nextTick

this.$nextTick(function () {
  this.$refs.inputFocus.focus();
});

用法: 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

动画效果

<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>
    <!-- 将要实现动画的标签用 transition 包裹起来
    可以指定名称,css样式要用名称去指定 appear 页面加载时自动播放-->
    <transition name="demo" :appear="true">
      <h2 v-show="isShow">hello</h2>
    </transition>
  </div>
</template>

<script>
export default {
  name: "MySchool",
  data() {
    return {
      isShow: true,
    };
  },
};
</script>

<style>
h2 {
  background-color: moccasin;
}
/* vue中动画进入的效果
如果transition中指定了name属性,则调用方式是demo-enter-active
如果没指定name属性,默认调用是v-leave-active,v- 开头*/
.demo-enter-active {
  animation: test 1s linear;
}
/* vue中动画离开的效果 */
.demo-leave-active {
  animation: test 1s reverse;
}
@keyframes test {
  from {
    transform: translateX(-100%);
  }
  to {
    transform: translateX(0px);
  }
}
</style>

过渡效果

<template>
  <div>
    <button @click="isShow = !isShow">显示/隐藏</button>
    <!-- transition-group 同时指定多个标签的样式,key值是必填项 -->
    <transition-group name="demo2" :appear="true">
      <h2 v-show="isShow" key="1">你好啊</h2>
      <h2 v-show="isShow" key="2">hello2</h2>
    </transition-group>
  </div>
</template>

<script>
export default {
  name: "MySchool2",
  data() {
    return {
      isShow: true,
    };
  },
};
</script>

<style scoped>
h2 {
  background-color: moccasin;
  /* 执行过渡效果 */
  transition: 1s linear;
}
/* 进入的起点 */
.demo2-enter {
  transform: translateX(-100%);
}
/* 进入的重点 */
.demo2-enter-to {
  transform: translateX(0);
}
/* 离开的起点 */
.demo2-leave {
  transform: translateX(0);
}
/* 离开的终点 */
.demo2-leave-to {
  transform: translateX(-100%);
}
</style>

第三方动画库 animate

  1. 安装

    npm install animate.css
    
  2. 使用

    <template>
      <div>
        <button @click="isShow = !isShow">显示/隐藏</button>
        <!-- 使用animate.css设置动画效果 -->
        <transition
          name="animate__animated animate__bounce"
          enter-active-class="animate__wobble"
          leave-active-class="animate__backOutDown"
          :appear="true"
        >
          <h2 v-show="isShow">hello3</h2>
        </transition>
      </div>
    </template>
    
    <script>
    import "animate.css";
    export default {
      name: "MySchool",
      data() {
        return {
          isShow: true,
        };
      },
    };
    </script>
    
    <style scoped>
    h2 {
      background-color: moccasin;
    }
    </style>
    

配置代理服务器

解决浏览器请求跨域问题

在 vue.config.js 文件中配置代理规则

const {
  defineConfig
} = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  /* 关闭错误提示 */
  lintOnSave: false,
  /* 配置代理服务器 */
  devServer: {
    proxy: {
      /* 请求的代理前缀 */
      '/stu': {
        target: 'http://localhost:5050',
        /* 目标服务器地址 */
        pathRewrite: {
          '^/stu': ''
        },
        /* 重写路径,将前缀去掉 */
        ws: true,
        /* 用于支持web socket */
        changeOrigin: true /* 用于控制请求头中的host值 */
      },
    }
  }
})

在请求路径中要添加代理规则的前缀

methods: {
  getStudents() {
    /* 在端口后面加上代理的前缀 */
    axios.get("http://localhost:8080/stu/students").then(
      (response) => {
        console.log("请求成功,获取到的数据", response.data);
      },
      (error) => {
        console.log("请求失败", error.message);
      }
    );
  },
}
// GitHub 免费接口
http://api.github.com/search/users?q=xxx
mounted() {
    this.$bus.$on("userList", (dataObj) => {
      /* es6中合并对象 */
      this.info = { ...this.info, ...dataObj };
    });
  },

插槽

默认插槽

<div class="contaner">
  <Category title="美食">
    <img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="" />
  </Category>
  <Category title="游戏">
    <ul>
      <li v-for="(game, index) in games" :key="index">{{ game }}</li>
    </ul>
  </Category>
  <Category title="电影">
    <video
      controls
      src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"
    ></video>
  </Category>
</div>
<div class="category">
  <h3>{{ title }}分类</h3>
  <!-- 插槽 -->
  <slot>这里设置默认值,当没有传递具体结构时,会显示</slot>
</div>

具名插槽

<Category title="美食">
  <img
    slot="center"
    src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg"
    alt=""
  />
  <a slot="footer" href="http://www.baidu.com">百度首页</a>
</Category>
<div class="category">
  <h3>{{ title }}分类</h3>
  <!-- 插槽 -->
  <slot name="center">这里设置默认值,当没有传递具体结构时,会显示1</slot>
  <slot name="footer">这里设置默认值,当没有传递具体结构时,会显示2</slot>
</div>

作用域插槽

<Category title="游戏">
  <!-- 接收插槽传递过来的数据,{plans} es6中的结构赋值语法 -->
  <template scope="{games}">
    <ol>
      <li v-for="(game, index) in games" :key="index">{{ game }}</li>
    </ol>
  </template>
</Category>
<template>
  <div class="category">
    <h3>{{ title }}分类</h3>
    <!-- 将数据传递给插槽使用者 -->
    <slot :games="games">这是插槽的默认内容</slot>
  </div>
</template>

<script>
export default {
  name: "Category",
  props: ["title"],
  data() {
    return {
      /* 数据在子组件身上 */
      games: ["红色警戒", "穿越火线", "劲舞团", "超级玛丽"],
    };
  },
};
</script>

Vuex

  1. 安装并配置vuex环境

    # vue2建议使用这个版本
    npm install vuex@3.6.2
    
  2. 配置store文件

    //引入Vue核心库
    import Vue from 'vue'
    //引入Vuex
    import Vuex from 'vuex'
    //应用Vuex插件
    Vue.use(Vuex)
    
    //准备actions对象——响应组件中用户的动作
    const actions = {}
    //准备mutations对象——修改state中的数据
    const mutations = {}
    //准备state对象——保存具体的数据
    const state = {}
    
    //创建并暴露store
    export default new Vuex.Store({
        actions,
        mutations,
        state
    })
    
  3. 在 main.js 中引入store

    import Vue from 'vue'
    import App from './App.vue'
    /* 引入配置好的store */
    import store from './store/index'
    
    Vue.config.productionTip = false
    
    new Vue({
      render: h => h(App),
      /* 使用store */
      store,
      /* 创建全局总线事件 */
      beforeCreate() {
        Vue.prototype.$bus = this;
      }
    }).$mount('#app')
    

使用案例

Index.js

//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)

//准备actions对象——响应组件中用户的动作
const actions = {
    jiaOdd(context, value) {
        if (context.state.sum % 2) {
            context.commit('JIA', value)
        }
    },
    jiaWait(context, value) {
        setTimeout(() => {
            context.commit('JIA', value);
        }, 500);
    },
}
//准备mutations对象——修改state中的数据
const mutations = {
    JIA(state, value) {
        state.sum += value;
    },
    JIAN(state, value) {
        state.sum -= value;
    },
    ADD_PERSON(state, value) {
        state.personList.unshift(value)
    }
}
//准备state对象——保存具体的数据
const state = {
    sum: 0,
    personList: [{
        id: "001",
        name: 'kobe'
    }]
}
/* getters 用于对state中的数据进行加工 */
const getters = {
    bigSum(state) {
        return state.sum * 10
    }
}

//创建并暴露store
export default new Vuex.Store({
    actions,
    mutations,
    state,
    getters
})

Count.vue

<template>
  <div>
    <!-- 取出在vuex中state保存的值 -->
    <h1>当前求和为:{{ sum }}</h1>
    <!-- 读取vuex中getters的值 -->
    <h3>当前求和放大10倍后为:{{ bigSum }}</h3>
    <select v-model="n">
      <option :value="1">1</option>
      <option :value="2">2</option>
      <option :value="3">3</option>
    </select>
    <!-- <button @click="increment">+</button>
    <button @click="decrement">-</button> -->
    <!-- 使用 mapMutations 生成的方法,需要调用时传递参数 -->
    <button @click="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <!-- <button @click="incrementOdd">当前求和为奇数再加</button>
    <button @click="incrementWait">等一等再加</button> -->
    <!-- 使用 mapActions 生成的方法,需要调用时传递参数 -->
    <button @click="incrementOdd(n)">当前求和为奇数再加</button>
    <button @click="incrementWait(n)">等一等再加</button>
    <h3>下面组件的总人数是:{{ personList.length }}</h3>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
export default {
  name: "Count",
  data() {
    return {
      n: 1,
    };
  },
  methods: {
    // increment() {
    //   /* commit 直接调用 mutations 中的函数 */
    //   this.$store.commit("JIA", this.n);
    // },
    // decrement() {
    //   this.$store.commit("JIAN", this.n);
    // },
    /* 使用 mapMutations 生成方法 ===> this.$store.commit */
    ...mapMutations({ increment: "JIA", decrement: "JIAN" }),
    /* incrementOdd() {
      this.$store.dispatch("jiaOdd", this.n);
    },
    incrementWait() {
      this.$store.dispatch("jiaWait", this.n);
    }, */
    /* 使用 mapActions 生成方法 ===> this.$store.dispatch */
    ...mapActions({ incrementOdd: "jiaOdd", incrementWait: "jiaWait" }),
  },
  computed: {
    /* 借助 mapState 生成计算属性,从state中读取数据 */
    /* ...mapState({ sum: "sum" }) (对象写法) */
    ...mapState(["sum", "personList"]) /* 数组写法 */,
    /* 借助 mapGetters 生成计算属性,从 getters 中读取数据 */
    ...mapGetters(["bigSum"]),
  },
};
</script>
<style scoped>
button {
  margin-left: 5px;
}
</style>

Person.vue

<template>
  <div>
    <h1>人员列表</h1>
    <input type="text" placeholder="请输入名字" v-model="name" />
    <button @click="add">添加人员</button>
    <ul>
      <li v-for="p in personList" :key="p.id">{{ p.name }}</li>
    </ul>
  </div>
</template>

<script>
import { nanoid } from "nanoid";
import { mapState } from "vuex";
export default {
  name: "Person",
  data() {
    return {
      name: "",
    };
  },
  computed: {
    ...mapState(["personList"]),
  },
  methods: {
    add() {
      const personObj = { id: nanoid(), name: this.name };
      this.$store.commit("ADD_PERSON", personObj);
      this.name = "";
    },
  },
};
</script>

Vuex 命名空间+模块化

Person.js

import axios from "axios"
import {
    nanoid
} from "nanoid"

export default {
    /* 命名空间 */
    namespaced: true,
    actions: {
        addPersonHong(context, value) {
            if (value.name.indexOf('洪') === 0) {
                context.commit('ADD_PERSON', value)
            } else {
                alert("添加的人必须姓洪!")
            }
        },
        addPersonServer(context) {
            /* 免费API */
            axios.get('https://api.uixsj.cn/hitokoto/get?type=social').then((response) => {
                context.commit('ADD_PERSON', {
                    id: nanoid(),
                    name: response.data
                })
            }, (error) => {
                alert(error.message)
            })
        }
    },
    mutations: {
        ADD_PERSON(state, value) {
            state.personList.unshift(value)
        }
    },
    state: {
        personList: [{
            id: "001",
            name: 'kobe'
        }]
    },
    getters: {
        firstName(state) {
            return state.personList[0].name
        }
    }
}

Count.js

export default {
    /* 命名空间 */
    namespaced: true,
    actions: {
        jiaOdd(context, value) {
            if (context.state.sum % 2) {
                context.commit('JIA', value)
            }
        },
        jiaWait(context, value) {
            setTimeout(() => {
                context.commit('JIA', value);
            }, 500);
        },
    },
    mutations: {
        JIA(state, value) {
            state.sum += value;
        },
        JIAN(state, value) {
            state.sum -= value;
        }
    },
    state: {
        sum: 0
    },
    getters: {
        bigSum(state) {
            return state.sum * 10
        }
    }
}

Index.js

//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
import sumOptions from './count'
import personOptions from './person'
//应用Vuex插件
Vue.use(Vuex)

//创建并暴露store
export default new Vuex.Store({
    modules: {
        countAbout: sumOptions,
        personAbout: personOptions
    }
})

Count.vue

<template>
  <div>
    <!-- 取出在vuex中state保存的值 -->
    <h1>当前求和为:{{ sum }}</h1>
    <!-- 读取vuex中getters的值 -->
    <h3>当前求和放大10倍后为:{{ bigSum }}</h3>
    <select v-model="n">
      <option :value="1">1</option>
      <option :value="2">2</option>
      <option :value="3">3</option>
    </select>
    <!-- <button @click="increment">+</button>
    <button @click="decrement">-</button> -->
    <!-- 使用 mapMutations 生成的方法,需要调用时传递参数 -->
    <button @click="increment(n)">+</button>
    <button @click="decrement(n)">-</button>
    <!-- <button @click="incrementOdd">当前求和为奇数再加</button>
    <button @click="incrementWait">等一等再加</button> -->
    <!-- 使用 mapActions 生成的方法,需要调用时传递参数 -->
    <button @click="incrementOdd(n)">当前求和为奇数再加</button>
    <button @click="incrementWait(n)">等一等再加</button>
    <h3>下面组件的总人数是:{{ personList.length }}</h3>
  </div>
</template>

<script>
import { mapState, mapGetters, mapMutations, mapActions } from "vuex";
export default {
  name: "Count",
  data() {
    return {
      n: 1,
    };
  },
  methods: {
    /* 使用 mapMutations 生成方法 ===> this.$store.commit */
    ...mapMutations("countAbout", { increment: "JIA", decrement: "JIAN" }),
    /* 使用 mapActions 生成方法 ===> this.$store.dispatch */
    ...mapActions("countAbout", {
      incrementOdd: "jiaOdd",
      incrementWait: "jiaWait",
    }),
  },
  computed: {
    /* 借助 mapState 生成计算属性,从state中读取数据 */
    /* ...mapState({ sum: "sum" }) (对象写法) */
    ...mapState("countAbout", ["sum"]) /* 数组写法 */,
    ...mapState("personAbout", ["personList"]) /* 数组写法 */,
    /* 借助 mapGetters 生成计算属性,从 getters 中读取数据 */
    ...mapGetters("countAbout", ["bigSum"]),
  },
};
</script>
<style scoped>
button {
  margin-left: 5px;
}
</style>

Person.vue

<template>
  <div>
    <h1>人员列表</h1>
    <h2>列表中的第一个人的名字是:{{ firstName }}</h2>
    <input type="text" placeholder="请输入名字" v-model="name" />
    <button @click="add">添加人员</button>
    <button @click="addHong">添加一个姓洪的人</button>
    <button @click="addContent">添加段子人</button>
    <ul>
      <li v-for="p in personList" :key="p.id">{{ p.name }}</li>
    </ul>
  </div>
</template>

<script>
import { nanoid } from "nanoid";
export default {
  name: "Person",
  data() {
    return {
      name: "",
    };
  },
  computed: {
    personList() {
      return this.$store.state.personAbout.personList;
    },
    firstName() {
      return this.$store.getters["personAbout/firstName"];
    },
  },
  methods: {
    add() {
      const personObj = { id: nanoid(), name: this.name };
      this.$store.commit("personAbout/ADD_PERSON", personObj);
      this.name = "";
    },
    addHong() {
      const personObj = { id: nanoid(), name: this.name };
      this.$store.dispatch("personAbout/addPersonHong", personObj);
      this.name = "";
    },
    addContent() {
      this.$store.dispatch("personAbout/addPersonServer");
    },
  },
};
</script>

App.vue

<template>
  <div class="contaner">
    <Count></Count>
    <Person></Person>
  </div>
</template>

<script>
import Count from "./components/Count.vue";
import Person from "./components/Person.vue";
export default {
  name: "App",
  components: { Count, Person },
  mounted() {
    console.log(this.$store);
  },
};
</script>

vue-router

安装

npm i vue-router@3.5.2

main.js

import Vue from 'vue'
import App from './App.vue'
/* 引入VueRouter */
import VueRouter from 'vue-router'
/* 引入路由器 */
import router from './router/index'
/* 使用VueRouter */
Vue.use(VueRouter)

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  router: router
}).$mount('#app')

配置路由规则

import VueRouter from "vue-router";
import About from '../pages/About'
import Home from '../pages/Home'
import Message from '../pages/Message'
import News from '../pages/News'
import Detail from '../pages/Detail'
const router = new VueRouter({
    mode: 'history', /* history模式会去掉路径中的 #  */
    routes: [{
            name: 'guanyu',
            path: '/about',
            component: About,
            meta: {
                isAuth: true,
                title: '关于'
            }
        },
        {
            /* 一级路由 */
            name: 'zhuye',
            path: '/home',
            component: Home,
            meta: {
                title: "主页"
            },
            children: [
                /* 二级路由,前面不需要加 / */
                {
                    name: 'xinwen',
                    path: 'news',
                    component: News,
                    /* 是否需要路由守卫的校验 */
                    meta: {
                        isAuth: true,
                        title: "新闻"
                    },
                    /* 组件独享路由 */
                    /* beforeEnter: (to, from, next) => {
                        if (to.meta.isAuth) { // 需要路由守卫的校验
                            if (localStorage.getItem('school') === 'honksun') {
                                next()
                            }
                        } else {
                            next()
                        }
                    } */
                },
                {
                    name: 'xiaoxi',
                    path: 'message',
                    component: Message,
                    /* 是否需要路由守卫的校验 */
                    meta: {
                        isAuth: true,
                        title: "消息"
                    },
                    children: [{
                        name: 'xijie', // 路由命名,可以简化路径
                        path: 'detail/:id/:title', // 使用params传递参数时必须使用占位
                        component: Detail,
                        /* props 函数写法,该函数中所有的对象都会传给 Detail 组件 */
                        props($route) {
                            return {
                                id: $route.params.id,
                                title: $route.params.title
                            }
                        }
                    }]
                }
            ]
        }
    ]
});

/* 创建全局前置路由守卫 */
/* router.beforeEach((to, from, next) => {
    if (to.meta.isAuth) { // 需要路由守卫的校验
        if (localStorage.getItem('school') === 'honksun') {
            next()
        }
    } else {
        next()
    }
}); */

/* 创建全局后置路由守卫 */
// router.afterEach((to, from) => {
//     /* 修改标签页title */
//     document.title = to.meta.title
// });

export default router;

路由query传递参数

Message.vue

<template>
  <div>
    <ul>
      <li v-for="item in messageList" :key="item.id">
        <!-- 跳转路由并携带query参数 -->
        <!-- <router-link
          :to="{
            path: '/home/message/detail',
            query: {
              id: item.id,
              title: item.title,
            },
          }"
        >
          {{ item.title }}
        </router-link> -->
        <!-- 跳转路由并携带params参数,路由路径不能用path -->
        <router-link
          :to="{
            name: 'xijie',
            params: {
              id: item.id,
              title: item.title,
            },
          }"
        >
          {{ item.title }} </router-link>&nbsp;
        <!-- 编程式路由导航,用于 a标签以外的标签实现路由跳转功能 -->
        <button @click="handlePush(item)">push查看</button>&nbsp;
        <button @click="handleReplace(item)">replace查看</button>
      </li>
    </ul>
    <hr />
    <router-view></router-view>
  </div>
</template>

<script>
export default {
  name: "Message",
  data() {
    return {
      messageList: [
        { id: "001", title: "消息001" },
        { id: "002", title: "消息002" },
        { id: "003", title: "消息003" },
      ],
    };
  },
  methods: {
    handlePush(item) {
      /* 路由跳转的方式和路径 */
      this.$router.push({
        name: "xijie",
        params: {
          id: item.id,
          title: item.title,
        },
      });
    },
    handleReplace(item) {
      this.$router.replace({
        name: "xijie",
        params: {
          id: item.id,
          title: item.title,
        },
      });
    },
  },
};
</script>

Detail.vue

<template>
  <ul>
    <!-- 接收路由query参数 -->
    <!-- <li>消息的编号:{{ $route.query.id }}</li>
    <li>消息的title:{{ $route.query.title }}</li> -->
    <!-- 接收路由params参数 -->
    <li>消息的编号:{{ id }}</li>
    <li>消息的title:{{ title }}</li>
  </ul>
</template>

<script>
export default {
  name: "Detail",
  props: ["id", "title"],
};
</script>

缓存路由组件

<!-- 缓存路由组件, include 要缓存的组件名 -->
<keep-alive include="News">
  <router-view></router-view>
</keep-alive>

组件内路由守卫

<template>
  <div><h2>我是About的内容</h2></div>
</template>

<script>
export default {
  name: "About",
  /* 组件内路由守卫 */
  /* 通过路由规则,进入该组件时 */
  beforeRouteEnter(to, from, next) {
    if (to.meta.isAuth) {
      // 需要路由守卫的校验
      if (localStorage.getItem("school") === "honksun") {
        next();
      }
    } else {
      next();
    }
  },
  /* 通过路由规则,离开组件时 */
  // beforeRouteLeave(to, from, next) {},
};
</script>

小技巧随记

/* 清空Vue组件中data()的数据 清空数据 */
Object.assign(this._data, this.$options.data());

css深度选择器

<style scoped>
/* 
css深度选择器,用于vue父组件sytle中添加scoped作用域后,去影响子组件的样式
>>> 原生css语法 
/deep/  less语法 
*/
 >>>.el-carousel__button {
  width: 5px;
  height: 5px;
  border-radius: 50%;
}
</style>
vue elementUI tree树形控件获取父节点ID的实例
	修改源码:
		情况1: element-ui没有实现按需引入打包
          node_modules\element-ui\lib\element-ui.common.js    25382行修改源码  去掉 'includeHalfChecked &&'
          // if ((child.checked || includeHalfChecked && child.indeterminate) && (!leafOnly || leafOnly && child.isLeaf)) {
          if ((child.checked || child.indeterminate) && (!leafOnly || leafOnly && child.isLeaf)) {
    情况2: element-ui实现了按需引入打包
          node_modules\element-ui\lib\tree.js    1051行修改源码  去掉 'includeHalfChecked &&'
          // if ((child.checked || includeHalfChecked && child.indeterminate) && (!leafOnly || leafOnly && child.isLeaf)) {
          if ((child.checked || child.indeterminate) && (!leafOnly || leafOnly && child.isLeaf)) {

在vue-cli 的 package.json 文件中, 添加如下参数, 可以配置指定主机名, 端口号和浏览器自动打开

"scripts": {
  "dev": "vue-cli-service serve --host localhost --open --port 8496",
 }
--host 
	配置主机地址
--open
	自动打开浏览器
--port
	指定端口号

在 vue.config.js 文件中,配置修改静态网站标签页title

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  transpileDependencies: true,
  chainWebpack(config){
    //修改htmlWebpackPlugin,可以修改网站静态title
    config.plugin('html').tap(args => {
      args[0].title = '测试用例demo';
      return args;
    })
  }
})

jest 好用的report插件

https://www.npmjs.com/package/jest-html-reporters

posted @ 2021-12-13 13:58  HonkSun  阅读(76)  评论(0)    收藏  举报