JavaScript

JavaScript

javascript初识

  • 阶段介绍及学习方法

    • 前端课程的阶段:1 h4/h5 css2/css3 ----布局 pc端 移动端 2 js编程 3 es6—javascript2015 nodejs—》利用js的内核编写的一个后端框架 4 vue react框架 5 小程序
    • 学习方法:1 理解逻辑 2 记忆—》程序方法 单词 背 3–》练 4–》作业 尽量去做 先看视频 然后逐个去自己练习
    • 网站组成—》前端和后端 后端指服务器 数据库 前端 网页 app 构成 html结构 css样式 js行为
  • 什么是js

    • JavaScript 是一种具有面向对象能力的、解释型的程序设计语言。更具体一点,它是基于对象和事件驱动并具有相对安全性的客户端脚本语言 *
      • 面向对象—后续详解
      • 解释型— 解释型 和 编译型
        • 编译型语言— C 当程序构建完成后—》编译器进行编译 —》机器语言–》然后执行。优点:执行速度快。缺点:需要在不同的平台下安装编译器(跨平台性比较差)
        • 解释型—不需要安装编译器,当程序被可以执行的浏览器来调用执行时 直接从头逐行进行编译和执行。优点:跨平台性强(只要浏览器支持 就可以执行),缺点:慢一些 js python php
        • 基于对象—js中内置了很多对象 来帮助你构建程序
        • 事件驱动—人机交互的事件来进行驱动程序的执行
  • JavaScript 的历史

    • 95年js诞生—主要作用 做表单的提交验证
    • 97年js的标准化—ECMA 欧洲计算机制造商协会 js1.1为蓝本进行标准的制定ECMA-262 。 javascript名称是 netscape公司可以用,欧洲计算机制造商协会 ECMAscript,实际是同一种语言,但是一般用es来说明js的版本。
    • 目前我们学习的 es3和es5 下一代 ES6 最新 ES11
  • js的组成 *

    • ECMA—标准,语法 解释器
    • DOM— Document Object Model 文档对象模型
    • BOM— Browser Object Model 浏览器对象模型
  • js的引入

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <script>
            // 内部引入js
            alert('内部使用js')
        </script>
        <!-- 外链js -->
        <script src="myjs.js"></script>
    </head>
    <body>
        <!-- 行间js -->
        <button onclick="alert('我被点击了!')">按钮</button>
    </body>
    </html>
    
  • JavaScript 注释

    • // 单行注释 ctrl + /
    • /* 多行注释 */ alt+ shift + a
  • js入门三部曲

    • 找(谁):要进行操作的元素----标签

    • 加(干什么):给找的元素添加 事件

    • 做(结果):事件触发之后的结果–执行的代码—写在一个函数中(函数就是包含代码的一个代码块)

      <script>
          // 找  找该div
          // alert(document.getElementById('box'));
          // 加   做--结果函数
          document.getElementById('box').onclick = function(){//函数
          alert('上课不要带耳机');
      }
      </script>
      
  • window.onload = function(){}

    • 当文档结构和所有资源都加载完毕之后,再执行onload事件函数中的代码
    <script>
        window.onload = function(){
        document.getElementById('box').onclick = function(){//函数
            alert('上课不要带耳机');
        }
    }
    </script>
    
  • 鼠标一些事件

    • 单击 onclick 左键
    • 鼠标移入 onmouseover/ onmouseenter over方法会冒泡
    • 鼠标移出 onmouseout/onmouseleave
    • 鼠标移动 onmousemove
    • 鼠标按下 onmousedown 左右键
    • 鼠标抬起 onmouseup 左右键
    • 双击 ondblclick 左键
    • 鼠标右键 oncontextmenu
    <script>
        window.onload = function(){
        // 双击
        // document.getElementById('box').ondblclick = function(){
        //     alert('双击');
        // }
    
        // 鼠标移入元素时触发  一次
        // document.getElementById('box').onmouseenter = function(){
        //     console.log('鼠标移入')
        // }
    
        // 鼠标移出元素时触发  一次
        // document.getElementById('box').onmouseleave = function(){
        //     console.log('鼠标移出出出')
        // }
    
        // 鼠标在元素上移动  不停的触发
        // document.getElementById('box').onmousemove = function(){
        //     console.log('动动动');
        // }
    
        // document.getElementById('box').onclick = function(){
        //     console.log('鼠标点击');
        // }
    
        // document.getElementById('box').onmousedown = function(){
        //     console.log('鼠标按下');
        // }
    
        // document.getElementById('box').onmouseup = function(){
        //     console.log('鼠标抬起');
        // }
    
        document.getElementById('box').oncontextmenu = function(){
            console.log('右键菜单')
        }
    }
    </script>
    
    
    <script>
        window.onload = function(){
        // over方法会冒泡
        // document.getElementById('box').onmouseover = function(){
        //     console.log('来了,老弟!')
        // }
        // enter不会冒泡
        document.getElementById('box').onmouseenter = function(){
            console.log('来了,老弟!')
        }
    }
    </script>
    
  • 变量

    • 在内存的栈当中划分一个单元格,并起名字,将需要的数据,元素等存储到该命名单元格中,方便以后使用。

    • 变量的使用分为两步 1 变量的声明 2 变量的赋值

    • 一次性声明值相同的多个变量 连等

    • 一次性声明多个值不同的变量 用,隔开

    • 一个变量,自始至终都存储同一类型的数据

      <script>
          window.onload = function(){
          // 双击
          // document.getElementById('box').ondblclick = function(){
          //     alert('双击');
          // }
      
          // 变量存储box元素  然后利用变量来进行后续程序的编写
          // var oBox = document.getElementById('box');
          // console.log(oBox)
      
          // var a;  //声明变量a
          // console.log(a); // undefined  未赋值
          // // 赋值  =叫赋值符号   从右向左运算赋值
          // a = 10;
          // console.log(a);
      
          // var a = 10;//声明并赋值
      
          // 声明多个相同值的变量
          var a = b = c = 10;
      
          // 声明多个变量值不同  用,隔开
          var x = 10, y = 20, z = 30;
      
      }
      </script>
      
    • 变量的命名规则 *

      • 见名知意,驼峰命名
      • 变量名可以使用 字母,数字,下划线, $ 来组成,但是不能以数字开头
      • 不能使用保留字和关键字
      • 变量命名不能重复,后声明的会覆盖先声明的同名变量
        • 关键字—指程序中已经在使用的有意义的一些单词不能做为变量名
        • 保留字—在当前程序版本中没有用到的单词,但是在后续版本中可能会变为关键字的单词
  • JavaScript 操作元素内容

    • 表单元素

      • 获取内容: 元素. value;
      • 设置内容: 元素 .value = ‘新内容’
      <script>
          window.onload = function(){
          var oIn = document.getElementById('txt');
          var oTxt = document.getElementById('txt2');
          var oSel = document.getElementById('sel');
          // 获取表单元素的内容
          console.log(oIn.value);
          console.log(oTxt.value);
          console.log(oSel.value);
      
          // 设置表单元素的内容
          oIn.value = '没有手机。。。';
          oTxt.value = '没啥想说的...';
          oSel.value = 'cn';//将默认选中 进行修改
      }
      </script>
      
    • 闭合标签

      • 获取内容:元素.innerText / 元素 .innerHTML
        • innerText 不识别html标签 innerHTML识别html标签
      • 设置内容 : 元素.innerText = ‘新内容’ / 元素 .innerHTML=‘新内容’
    <script>
            window.onload = function(){
                var oDiv = document.getElementById('box');
                // 获取
                // console.log(oDiv.innerText);
                // console.log(oDiv.innerHTML);
    
                // 设置
                //oDiv.innerText = '除却巫山不是云';
                // oDiv.innerHTML = '除却巫山不是云';
    
                // oDiv.innerText = '除却巫山不是云';
                // oDiv.innerHTML = '除却巫山不是云';
    
                // 先获取原有内容,然后加上新内容,最后赋值给元素内容
                //  3赋值给div《---   1获取原内容 2+
                oDiv.innerHTML = oDiv.innerHTML + ',除却巫山不是云'
            }
        </script>
    
  • js操作标签的属性

    • 主要操作的是元素的固有属性(w3c 规定) 如:src href alt title id 。。。。但是 class 比较特殊,style我们另行讨论
      • 获取属性值:元素.属性名 class需要用className来获取
      • 设置属性值:元素.属性名 = ‘新属性值’
    <script>
        window.onload = function(){
        // 获取元素
        var oDiv = document.getElementById('box');
        // 获取属性值
        console.log(oDiv.id);//'box'
        console.log(oDiv.title);//'haha'
        // console.log(oDiv.class);//undefined
        console.log(oDiv.className);//'div1'
        // 自定义属性无法通过该方法来获取和设置
        console.log(oDiv.aaa);//undefined
    
        // 设置属性值
        oDiv.id = 'bbox';
        oDiv.title = 'heihei';
        oDiv.className = 'div2';
    }
    </script>
    
  • .操作符和[]操作符

    • 二者是等价的,凡是用.的地方都可以改写为[],但写法不同 如 div的id , oDiv.id 点后边直接跟已知的属性名

    • 中括号中 要写属性名,必须是字符串形式 就是用引号包裹,凡是写在[]中不带引号的都当做变量

    • 为什么要使用[]当你需要改变的属性或其他存储在一个变量中时 只能[]

      <script>
          window.onload = function(){
          var oDiv = document.getElementById('box');
          //.操作符后边是已知的属性名
          console.log(oDiv.id)
          // 当使用[]时  内部属性名必须用引号包裹
          // console.log(oDiv['id']);
          var a = 'id';
          console.log(oDiv[a]);
      }
      </script>
      
  • js操作行间样式

    • 获取:目前我们获取行间样式,未来可以获取非行间样式 元素.style.样式名
    • 设置:(js中凡是由程序对元素进行css样式的设置,都写在行间,具有最高权重) 元素.style.样式名 = ‘新样式值’
    • 凡是复合属性的分支属性 如font 下的font-size 带-的,在js中 去杠变驼峰
    • cssText方法 元素 .style.cssText = ‘属性:值;属性2:值;属性3:值;。。。。。’ 直接替换原有所有属性

js数据类型

  • js是一种弱语言,数据类型也是弱类型。js的数据类型分为6类

    • 基本5类:Number数字 String字符串 Boolean布尔 null空对象 undefined未赋值
    • 引用类型(复杂类型)Object----object对象 array数组 function函数
    • js中万物皆对象
  • typeof 打印数据类型

    • typeof 数据或变量 或 typeof(数据或变量)
  • Number数字类型

    • 整数,浮点数,负数

    • 8进制:以0开头,后续的数字不超过7,识别为8进制。但是打印时自动转换为10进制

    • 16 进制:以0x开头

    • 特殊数字类型 :NaN Not a Number 不是一个数字, Infinity 无限, 小数存储近似值

      <script>
              // 整数
              var num = 10;
              console.log(num);
              // typeof  打印数据类型的
              console.log( typeof num);
              // 浮点数
              var num1 = 3.1415926;
              // 负数
              var num2 = -12.34;
      
              // 8进制  0 1 2 3 4 5 6 7 
              var num3 = 017;//8进制   15
              var num4 = 094;//10进制  94
      
              console.log(num3);
              console.log(num4);
              // 16进制  0 1 2 3 4 5 6 7 8 9 A B C D E F  10
              var num5 = 0x1F4C;//8012
              console.log(num5);
      
              // 特殊数字类型
              console.log('你' - 10);//NaN   Not a Number    不是一个数字
              console.log(10 / 0);//Infinity  无限
              console.log(0.1 + 0.2);//0.30000000000000004
              console.log(0.07 * 100);//7.000000000000001
              // 计算机最终存储数据时都是2进制来存储的,所以对于某些小数  是存储了一个近似值
          </script>
      
  • string类型

    • 字符串:文本,数字都作为字符串。用单引号或双引号包裹。

    • 字符串长度方法:str.length;

    • 通过下标获取字符串中的某个字符:str.charAt(下标) str[下标] ie7+

    • 通过表单的value获取的内容都为字符串

      <script>
          window.onload = function(){
          var str = 'abc';
          var str1 = '123';
          var phone = '15412341234';
          console.log(typeof str1);
      
          var oIn = document.getElementById('txt');
          var oBtn = document.getElementById('btn');
          oBtn.onclick = function(){
              console.log(typeof oIn.value);
          }
      
          var str = 'abcdefghijk';
          console.log(str.length);
          // 任何的下标都是以0开始的,第一个字符的下标是0
          //       a  b   c   d  e  f  g
          // 下标  0  1   2   3  4  5  6
          console.log(str.charAt(4));
          console.log(str[4]);
      }
      </script>
      
  • boolean 布尔值

    • 一个共两个 true 真 false 假
    • 非0的实数为真 0 为假 非空的字符串为真 空字符串为假
  • null 和 undefined

    • null 空对象—也属于对象 所以typeof null 得到的结果是 object
    • undefined 未赋值-- js特有的 数据类型 undefined
    <script>
        // boolean
        var bl = true;
        var bl1 = false;
        console.log( typeof bl);
    
        console.log( 10 > 20);//false
    
        // null
        var a = null;
    
        var oDiv = document.getElementById('box');
        console.log(oDiv);
        console.log( typeof oDiv);
    
        // undefined
        var b;
    
        console.log(b, typeof b);//undefined "undefined"
    
    </script>
    
  • 基本类型和引用类型的区别—null空对象 实际上是一个空对象指针

    • 基本类型都是存储在栈中,因为基本类型的数据都比较简单,而且小
    • 引用类型,由于数据复杂,而且比较大,不能直接存储在栈区,所以,引用类型的数据是存储在堆区,而在栈区,变量名对应存储的的是该数据的堆区地址,从而通过该地址去访问堆区的引用类型的数据。
    • null 是一个空对象指针 它一般存储 0x00的一个地址指针,实际上没有这么一个地址,所以它是一个空对象指针
  • object类型— object array function

    • object 创建方式 实例化创建 和字面量创建

      • 以{键1:值1,键2:值2,。。。。。}

      • 获取某一个键的值

        ​ obj.name 对象名.键名

        ​ 修改某一个键的值

        ​ obj.age = 30 对象名.键名 = ‘ 新键值’

        ​ 添加一个新的键值对

        ​ obj.work = ‘player’ 对象名.新键名 = ‘键值’

      <script>
              // 对象类型  object
              // 创建方式2种  实例化对象   字面量创建
              // 实例化对象创建
              var obj = new Object();//没有具体属性的空对象  不是null
              console.log(obj, typeof obj);
      
              // 字面量创建对象
              var obj = {
                  name:'joth',
                  age:20,
                  sex:'male',
              }
      
              // 获取某一个键的值
                  console.log(obj.name);
              // 修改某一个键的值
                  console.log(obj);
                  obj.age = 21;
                  console.log(obj);
              // 添加一个新的键值
                  obj.work = 'eater';
                  console.log(obj);
          </script>
      
    • function函数

      • 声明函数包裹代码块—声明时函数内部的代码是不执行的

      • 调用函数来执行—通过函数名来调用执行

      • 当使用函数名 加() 代表调用执行 不加 直接写函数名 代表函数本身

        <script>
            function aa(){//函数的声明  这只是定义了函数  函数内部的代码并不执行
                console.log('aa');
            }
        
            // 函数需要调用执行---通过函数名来调用
            aa();
        </script>
        
    • 数组Array

      • 用[数据项1,数据项2,数据项3,。。。。。]

      • 数组中可以存储任意类型的数据,但是 同一个数组存储同一类数据

      • 数组长度 数组.length

      • 可以通过下标 访问数据组中的某一项对应的数据 下标从0开始

        <script>
                // 实例化对象创建数组
                var arr = new Array();
                console.log(arr, typeof arr);
        
                // 字面量创建数组
                var arr = ['a',10,false,[1,2,3],{name:'rose',age:18},null, undefined]
                // 数组中可以存储任意类型的数据,但是 数组最好是 同一个数据存储同一类数据
                var arr2 = [1,2,3,4,5,6]
                var arr3 = ['aaa','bbb','ccc']
        
                // 有长度
                console.log(arr2.length);
                // 可以通过下标  访问数据组中的某一项对应的数据  下标从0开始
                console.log(arr2[0]);//1
                console.log(arr2[3]);//4
            </script>
        
    • 通过typeof返回的值

      • 数字返回----number
      • 字符串返回—string
      • 布尔值返回—boolean
      • null返回—object
      • undefined返回—undefined
      • object返回----object
      • function返回—function
      • array返回—object
  • 数据类型的转换—强制数据转换

    • 其他类型转换为数字

      • Number(其他类型):只能是 纯数字字符串,空字符串和布尔值可以转换其他数据均不能转换为数字

        <script>
            var str = '12';
            console.log(str);
            console.log(Number(str));
            var str = '100px';
            console.log(Number(str));//NaN
            console.log(Number('a123'));//NaN
            console.log(Number(''));//0   ''===>false===>0
            console.log(Number(false));//0
            console.log(Number(true));//1
            console.log(Number(null));//0  null ===> false ===>0
            console.log(Number(undefined));//NaN
            console.log(Number(070));//  56
            console.log(Number(090));// 90
        
        	// 引用类型的转换
                console.log(Number(function aaa(){console.log(111)}));//NaN
                console.log(Number([1,2,3]));//NaN
                console.log(Number([10]));//10  数组只有一个数据,且该数据是数字或纯数字字符串是 可以转换为数字
                console.log(Number([]));//0  空数组 可以转换为0
                console.log(Number({}));//NaN  不是空对象  空对象是  null
                console.log(Number({name:'joth',age:20}));//NaN
        </script>
        
      • parseInt和parseFloat

        • parseInt 将非空字符串转为整型数字,parseFloat 将非空字符串转为浮点型数字

        • 尽可能多的去识别数字字符串,当遇到不是数字字符时 结束 然后返回数字

        • parseInt转换带小数的字符串时 会将小数部分直接舍弃

        • parseInt 有第二个参数,用来说明以什么进制来识别要转换的内容,最后输出10进制的值

        • parseFloat 在转换时 有小数则保留小数

          <script>
                  console.log(parseInt(false));//NaN
                  console.log(parseInt(''));//NaN
                  console.log(parseInt(null));//NaN
                  console.log(parseInt(undefined));//NaN
          
                  console.log(parseInt('100px'));//100
                  console.log(parseInt('100px32'));//100
                  console.log(parseInt('a123'));//NaN
          
                  // 取整
                  console.log(parseInt('12.976'));//12
                  console.log(parseInt(12.14));//12
          
                  // parseInt的第二个参数  用来说明数据的进制 2 - 32
                  console.log(parseInt('070',10));//  统一用10进制来识别要转换的数据  得到70
                  console.log(parseInt('01101',2));//  统一用2进制来识别要转换的数据  得到13
                  console.log(parseInt('1fd3',16));//  统一用16进制来识别要转换的数据  得到8147
          
                  // parseFloat   转换为保留小数的数字
                  console.log(parseFloat('12.976'));//12.976
                  console.log(parseFloat('12.111'));//12.111
                  console.log(parseFloat('12'));//12
          
                  console.log(parseFloat('asdf'));//NaN
          
                  // 当转换完成  它不是一个数字  那么  就返回true
                  console.log(parseFloat('asdf') == NaN);//false
                  // NaN 不等于NaN
              </script>
          
      • 如果要判断 不是一个数字然后返回为真,不能使用 某个数据转换==NaN 的方式

      • NaN不等于NaN

      • isNaN用来判断不是一个数字则返回真

        • 确定不是一个数字

        • isNaN 本身没有做任何判断 它去调用了Number方法 如果该数据Number可以转换为数字 那么就是一个数字则返回false 如果Number不能转换,那么就不是一个数字则返回true

          console.log(isNaN('aaa'));//true
          console.log(isNaN('123'));//false
          
    • 其他类型数据转字符串

      • String(数据或变量)

        • 将其他类型转换为字符串,可以是任意类型
      • 数据或变量.toString(radix);

        • 除了null 和 undefined 报错 其他转换和String一样
        • toString在将数字转换为数字字符串时 可以指定进制,转换为相应进制的字符串
        <script>
                var num = 10;
                var b = false;
                var n = null;
                var n1 = NaN;
                var un = undefined;
                var arr = [];
                var arr1 = [10];
                var arr2 = [1,2,3];
                var obj = {};
                var obj1 = {
                    name:'joth',
                    age:20
                }
        
                var fn = function(){
                    console.log('aaa')
                }
        
                // String()
                console.log(String(num));//'10'
                console.log(String(b));//'false'
                console.log(String(n));//'null'
                console.log(String(n1));//'NaN'
                console.log(String(un));//'undefined'
                console.log(String(arr));//''
                console.log(String(arr1));//'10'
                console.log(String(arr2));//'1,2,3'
                console.log(String(obj));//'[object Object]'
                console.log(String(obj1));//'[object Object]'
                console.log(String(fn));// 
        
                // toString()
        
                console.log(num.toString());//'10'
                console.log(b.toString());//'false'
                // console.log(n.toString());//报错
                console.log(n1.toString());//NaN
                // console.log(un.toString());//报错
                console.log(obj1.toString());
        
                // 转换为各种进制的字符串
                var num2 = 18;
                console.log(num2.toString(2));//10010''   18的二进制字符串
                console.log(num2.toString(8));//'22'   18的8进制字符串
                console.log(num2.toString(16));//'12'   18的16进制字符串
        
                // 例如  我现在计算了一个颜色  14673456   ===》  
                var nn = 14673456;
                console.log('#' + nn.toString(16));
            </script>
        
    • 其他类型转换为布尔值

      • js中 null ,undefined 空字符串 false NaN 0 为假之外 其他所有数据都为真,包括[] {}.空数组和空对象 都是null 而定义的[] {} 实际上都不是空对象
      • 其他类型通过Boolean()的方法转换为布尔值
      <script>
              
              var str = '';
              var num2 = 0;
              var b = false;
              var n = null;
              var n1 = NaN;
              var un = undefined;
      
              var num = 10;
              var arr = [];
              var arr1 = [10];
              var arr2 = [1,2,3];
              var obj = {};
              var obj1 = {
                  name:'joth',
                  age:20
              }
      
              var fn = function(){
                  console.log('aaa')
              }
      
              // Boolean
              console.log(Boolean(str));//false
              console.log(Boolean(num2));//false
              console.log(Boolean(b));//false
              console.log(Boolean(n));//false
              console.log(Boolean(n1));//false
              console.log(Boolean(un));//false
      
              console.log(Boolean(arr));//true
      
              console.log(Boolean(obj));//true
      
              console.log(arr);
              console.log(obj);
          </script>
      
  • 运算符

    • 算术运算符

      • 一元运算符 ++自增 --自减

        • ++在前 先自增再进行其他运算 ++在后 先进行其他运算 再自增 --同理
      • 二元运算符 + - * / %(取余) 求模

        • 加法
          • 当加号两端有字符串数据类型,就将其他类型转换为字符串 进行字符串连接
          • 当加号两端出现非引用类型和非字符串类型的数据时,利用Number转换为数字进行运算,如果转换不了 则返回NaN
          • 当加号两端出现了对象类型时,先使用toString将对象转换为字符串,再进行字符串连接
        • 减法,隐式转换—通过Number将可以转换的数据转换为数字进行减法
        • 乘法和除法 同理于减法
        • 取余运算 除法获取余数
        <script>
                // var a = 10;
        
                // var b = a++;
                // console.log(a, b);//  11  10
        
                // var a = 10; 
                // var b = --a;
                // console.log(a, b);//9 9
                var a = 10;
                var b = 10;
        
                console.log(a++ + --a + b-- + b++ + a--); //49  
                 //           10 + 10  + 10  + 9  + 10
                 //                            b10   a9
                console.log(a);//9   
                console.log(b);//10  
        
                // +  
                console.log('a' + 10);//'a10'
                console.log('12' + '13');//'1213'
        
                console.log(10 + true);//11
                console.log(10 + undefined);//NaN
        
                console.log(['1'] + 10);//
                console.log([1,2,3] + 10);//
        
                // -
                console.log('100' - 10);//90
                console.log(true - 10);//
                console.log('aaa' - 10);//NaN
                console.log('100px' - 10);//NaN
        
                var n = 17;
                console.log(n % 3);//2
        
                var n = 10;
                console.log(n % 5);//0
        
                console.log(1 % 13);//1
            </script>
        
    • 赋值运算符

      • = 赋值 += -= *= /= %=

      • a = a + 5 <==> a += 5 等价

        <script>
                var a = 10;
        
                // a = a + 5;   
                a += 5;
                console.log(a);//15
        
                // oDiv.innerHTML = oDiv.innerHTML + 'aaa';
                // oDiv.innerHTMl += 'aaa';
        
                var a = 13;
                a %= 5;
                console.log(a);//3
            </script>
        
    • 比较运算符

      • > < >= <= ==等于 !=不等于 =全等 ! 不全等 返回布尔值

      • == 进行隐式转换 然后进行值比较 === 将数据类型和值一起比较都要相等

        <script>
                console.log(10 > 2);//true
        
                console.log(10 == '10');//true  
                console.log(10 === '10');//false
        
                console.log(10 != '10');//false
                console.log(10 !== '10');//true
        
                console.log('100' > '12');//false
                // '1'  '2' 比较第一位的字符串的ASCII码
                // 33 > 34  false
        
                // 'a'  --->  97  ---> 1100001  所以英文适合编程
                // 
            </script>
        
    • 逻辑运算符

      • 与 && 或 || 非 !
      • 与运算见假则假,或运算见真则真,非运算直接取反
      • 短路运算 短路与和短路或
        • 短路与 当第一项数据转换为布尔值时,为假,则返回第一项数据,否则返回第二项数据
        • 短路或 当第一项数据转换为布尔值时,为真,则返回第一项数据,否则返回第二项数据
      <script>
              console.log(false && true);//false
      
              console.log(10 > 3 && 12 > 100);//false
              //           true   &&     false   ==>false
      
              console.log(10 > 3 || 12 > 100);//true
      
              // var a = 0;
              // console.log(a && ++a);//0
      
              // 短路运算
              // 短路与
              // 当第一项数据转换为布尔值时,为假,则返回第一项数据,否则返回第二项数据
              console.log('' && 10);//''
              console.log('aaa' && 10);//10
      
              // 短路或
              // 当第一项数据转换为布尔值时,为真,则返回第一项数据,否则返回第二项数据
              console.log('' || 10);//10
              console.log('aaa' || 10);//'aaa'
      
              console.log(!false);//true
      
              console.log(!(10 > 100));//true
          </script>
      
    • 三目运算符

      • ?: 判断表达式? 当条件为真时返回的值 : 当条件为假时返回的值
    • 运算符的优先级

      • 一元运算符 》算术运算符》比较运算符》逻辑运算符》三目运算符》赋值运算符
      • 可以通过()来提升优先级
  • 隐式数据类型转换

    • ±*/% 在进行计算时 会隐式转换
    • 流程控制语句

  • 程序设计的三大结构:

    • 顺序结构 : 程序自上而下 顺序执行。

    • 条件选择结构(分支结构)

      • 根据条件的真假来执行不同的代码块
      • if 当只有一个满足条件时的代码块时 可以写为 if() …条件为真执行… {}可以省略
      • 如果有两个分支 则不能省略{} 为真执行第一个{}中的代码,为假执行 else后边的{}中的代码

      在程序设计中 最好不要出现if的嵌套 干脆最好别用if 一般两分支 直接用三目 多分支 switch

      <script>
              // 如果明天下雨  我去看电影
              // if(下雨){看电影}
              // var rain = true;
              // if(rain){console.log('watch movie')};
      
              // 当只有一个条件满足的情况时  后续的{}可以省略
              // if(rain) console.log('watch movie');
      
              // 如果明天不下雨  我去踢球
              // if(不下雨){踢球}
              // if(!rain) console.log('play football');
      
              // if() ..是当()内的值或表达式结果为true时执行...
              // var rain = false;
      
              // if(!rain) console.log('watch movie');
      
              var rain = true;
              
              if(rain){
                  // 当条件为真时执行的代码块
                  console.log('watch movie!');
              }else{
                  // 当条件为假时执行的代码块
                  console.log('paly football');
              }
      
              // 多分支   ifelse 嵌套
              // 成绩   小于60   一顿暴打    60-70   奖励黄冈试卷   70 - 80 奖励三年高考  80-90 100元 90--100  奖励ipad
              var g = 100;
      
              if(g >= 90 && g <=100){
                  console.log('iPad');
              }else if(g >=80 && g < 90){
                  console.log('$100');
              }else if(g >= 70 && g < 80){
                  console.log('三年高考');
              }else if(g >= 60 && g < 70){
                  console.log('huanggang test');
              }else if(g < 60 && g >= 0){
                  console.log('一顿暴打')
              }else{
                  console.log('成绩有误');
              }
              // 在程序设计中  最好不要出现if的嵌套  干脆最好别用if  一般两分支  直接用三目  多分支  switch
      
      • switch case; 多分支

        • case判断必须是一个常量值,不能使用表达式
        • 每个case 配对一个break 当匹配到该case执行完成后,就中断
        <script>
                var like = '100';
        
                switch(like){//case判断必须是一个常量值,不能使用表达式
                    case '1':
                        console.log('eat');
                    break;
                    case '2':
                        console.log('sleep');
                    break;
                    case '3':
                        console.log('play mGame');
                    break;
                    case '4':
                        console.log('play code');
                    break;
                    default:
                        console.log('fa dai');
                }
        
                // 成绩   小于60   一顿暴打    60-70   奖励黄冈试卷   70 - 80 奖励三年高考  80-90 100元 90--100  奖励ipad
                // 100  90-99  80-89  70-79 60 -69  
                // 10   9         8    7     6       default
                var g = 42;
        
                switch(parseInt(g / 10)){
                    case 10:
                        console.log('满分出国游');
                    break;
                    case 9:
                        console.log('$300');
                    break;
                    case 8:
                        console.log('$100');
                    break;
                    case 7:
                        console.log('黄冈试卷');
                    break;
                    case 6:
                        console.log('三个补习班');
                    break;
                    default:
                        console.log('竹板炒肉');
                }
            </script>
        
    • DOM 元素获取

      • 1阶段—标签 目前—元素 未来DOM–节点
      • 添加id getElementById(‘id’) 通过id来获取元素
      • 通过标签名获取元素 getElementsByTagName 得到是一个HTMLCollection(类似于数组的元素集合) 可以使用某些数组的特性 但不能使用数组的方法
        • 当标签获取元素后 可以通过下标得到其中的某一个元素
        • 使用length可以获取元素集合的长度
      • 通过类名获取元素 getElementsByClassName 得到的和标签获取是一样的用法也一样
        • 不兼容ie8-
      <script>
              window.onload = function(){
                  // 通过标签获取元素
                  // var oDiv  object  一个对象   aLi  array   sClass  string   bDown   boolean
                  // var aLi = document.getElementsByTagName('li');//整个文档下的所有li
                  // console.log(aLi);//获取到的是一个类似于数组的元素集合
      
                  // // 先获取父级元素  再在父级元素中获取子元素
                  // var oList = document.getElementById('list');
                  // var aLi = oList.getElementsByTagName('li');
      
                  // var aLi = document.getElementById('list').getElementsByTagName('li');
                  // 当标签获取元素后 可以通过下标得到其中的某一个元素
                  // var oUl = document.getElementsByTagName('ul')[1];
      
                  var aLi1 = document.getElementsByTagName('ul')[0].getElementsByTagName('li');
                  var aLi2 = document.getElementsByTagName('ul')[1].getElementsByTagName('li');
                  console.log(aLi1);
                  console.log(aLi2);
      
                  var aP = document.getElementsByClassName('p1');
                  console.log(aP)
      
                  // aLi1.style.background = 'pink';  //因为aLi1是一个元素集合  设置背景颜色  要针对元素也就是元素集合中的每个元素
                  aLi1[0].style.background = 'pink';//通过下标获取每个元素,但是当元素很多时  不可能人为1个1个的去  获取设置  需要交给程序来进行  循环遍历每个元素去添加样式
                  aLi1[1].style.background = 'pink';
                  aLi1[2].style.background = 'pink';
                  aLi1[3].style.background = 'pink';
              }
          </script>
      
    • 循环结构(循环遍历,迭代)

      • for(循环变量初始值;边界判断条件;循环变量自增){} 最常用

        <script>
                for(var i = 0; i < 10; i++){
                    console.log(i);
                }
        
                // 1  i = 0    i< 10  true  打印0  i++  i==>1
                // 2  i = 1    1 < 10  true  dy1   i++  i==>2
                // 3  i = 2   2 < 10   true  dy2   i++  i==>3
                // .....
                // 10  i = 9  9< 10  true   dy 9   i++  i==>10;
                // 11  i = 10  10 < 10  false  exit 
        
                // 其他写法
                // var j = 0;
                // for(;j < 10;){
                //     console.log(j);
                //     j++;
                // }
        
                // 循环嵌套
                for(var i = 0; i < 5; i++){    
                    for(var j = 0; j < 4; j++){
                        console.log('j:' + j);
                    }
                    console.log('i:' + i);
                }
        
                // 1 i = 0   j 0-->4  dyj 0 1 2 3    dyi 0  i++  i==>1
                // 2 i = 1   j 0---4  dyj 0 1 2 3    dyi 1  i++  i==>2
                // ....
        
                // 通过二重循环打印  * 构成的矩形
                for(var i = 0; i < 4; i++){//外层循环控制行数并打印  换行
                    for(var j = 0; j < 10; j++){//内层循环  每行循环之后  内存循环5次 打印5个*
                        document.write('*');
                    }
                    document.write('
        '
        ); } </script>
        • 循环嵌套 二重
        <script>
            //圆点组成直角三角形
                for(var i = 0; i < 6; i++){
                    for(var j = 0; j < i + 1; j++){
                        document.write('●');
                    }
                    document.write('
        '
        ); } // 1 i = 0 j < 1 j 0 i++ i = 1 // 2 i = 1 j < 2 j 0 1 i++ i = 2 // 3 i = 2 j < 3 j 0 1 2 i++ i = 3 // .... //圆点组成等腰三角形 var n = 10; for(var i = 0; i < n; i++){//行 // 第一个内层循环 循环空格 for(var k = n - 1 - i; k >=0; k--){ oDiv.innerHTML += '  ' } // 第二个内层循环 循环打印圆 for(var j = 0; j < i * 2 + 1; j++){ oDiv.innerHTML += '●'; } oDiv.innerHTML += '
        '
        ; } </script>
        • for循环遍历 元素集合和数组的要求:
          • 1-每一个数据或元素都要有下标 2- 数组或元素集合要有长度
        <script>
                window.onload = function(){
                    var aLi = document.getElementsByTagName('li');
                    // aLi[0] aLi[1]
                    // console.log(aLi);
        
                    for(var i = 0; i < aLi.length; i++){
                        aLi[i].style.background = 'pink';
                    }
        
                    // 希望  奇数行 粉色  偶数行  purple紫色
                }
            </script>
        
        	var arr = ['a','b','c','d','e','f','g'];
                // 数组的每一项数据都有下标   数组可以通过length求长度
                for(var i = 0; i < arr.length; i++){
                    console.log(arr[i]);
                }
        
      • for in 常用 专门用来循环对象

        • 语法 for(var key in 对象){}
        // 对象类型的遍历
                var obj = {
                    name:'joth',
                    age:20,
                    sex:'male'
                }
        
                console.log(obj.length);//undefined
                // 对象类型的数据  没有长度  而且  每个键值对 没有下标   它的数据访问 键名  不能用for循环
        
                // for in  专门用来循环  对象的
                for(var key in obj){
                    console.log(key + '---' + obj[key]);
                }
        
      • while(){} 偶尔

      • do {} while() 基本没用

        • 这两循环的()中都只放边界条件
        • do while 至少执行1次
        <script>
                // var i = 0; 
                // while(i < 4){
                //     console.log(i);
                //     i++;
                // }
        
                // var i = 0;
                // do{
                //     console.log(i);
                //     i++
                // }while(i < 4);
        
                // var i = 11;
                // while(i < 10){//完全不满足条件  就直接结束了
                //     console.log(i);
                //     i++;
                // }
        
                // var i = 11;
                // do{
                //     console.log(i);
                //     i++;
                // }while(i < 10);//后判断  即便不符合条件  那么也要执行一次
                
                // var i = 4;
                // while(i > 0){//死循环
                //     console.log('haha');
                //     i++;
                // }
            </script>
        
      • 循环当中的 continue 和 break;

        • continue 跳过本次循环
        • break 中断整个后续循环
        <script>
                // 打印前100个自然数中的所有偶数
                // for(var i = 1; i <= 100; i++){
                //     if(i % 2 == 1){//当 满足条件  就跳过该次循环  那么该次循环中的后续代码就都不执行了 直接进入下一次循环
                //         continue;
                //     }
                //     console.log(i);
                // }
        
                // 当i达到50的时候  就中断整个循环 后续的循环都不再执行
                // for(var i = 1; i <=100; i++){
                //     if(i > 50){
                //         break;
                //     }
                //     console.log(i);
                // }
        
                // 计算前100个自然数中的所有素数:  只能被1和它本身整除的数叫素数  1既不是素数也不是合数
                for(var i = 2; i <= 100; i++){
                    var flag = true;// 当flag为真  就说明是素数
                    for(var j = 2; j < i; j++){
                        if(i % j == 0){
                            flag = false;
                            break;
                        }
                    }
        
                    if(flag){
                        console.log(i);
                    }
                }
        
                //1 i = 2  flag = true    dy  2
                //2 i = 3  flag = true    dy  3
                //3 i = 4  flag = true   4 % 2 == 0  flag = false;  flag 为假  不打印
                //4 i = 5  flag = true   5 % 2  3  4  flag = true   dy 5
                //5 i = 6  falg = true   6 % 2 == 0   falg = false  break;  flag 假  不打印
                // ....
            </script> 
        

        函数高级

  • 作用域及作用域链

    • 作用域
      • 变量或函数的有效使用范围,有全局作用域与局部作用域两种。
      • 什么是全局作用域,我如果将一个变量或函数声明在其他任何一函数之外,则称之为全局变量或函数
      • 全局变量和函数,可以在整个代码中的任意位置被访问和修改,导致 全局变量的污染 所以在使用全局变量时 要慎重 全局函数比较多(一些工具类的函数,在任何地方都可以被使用)
      • 局部作用域 局部变量和局部函数 在函数内部声明的变量或函数,该变量或函数只能在当前函数的范围内使用,在函数外部的任何地方 都无法再访问或修改该变量或函数了
    • 作用域链
      • 就是js的一种查找机制,当函数中使用某个变量或函数时,先在函数的局部作用域查找,如果没有就向上到父级函数作用域去查找,一级一级向上查找,直到全局作用域,如果都没有 报错 is not defined
        <script>
            // 全局作用域
            // var a = 10;//全局作用域下声明的变量   全局变量
    
            // function fn(){
            //     console.log(a + 10);
            // }
            // fn()
    
            // function fnn(){
            //     a = 'aaa';//使用了全局变量a  导致了全局变量的污染
            //     console.log(a);
            // }
            // fnn();
            // fn();
    
    
            // 局部作用域
            // function fn(){
            //     var a = 100;//函数fn作用域下的局部声明的变量  局部变量  它的作用域  使用范围就是函数fn内部
            //     console.log(a);
            // }
            // fn();
            // console.log(a);//a is not defined( 程序报错---a压根就没有 没有声明)       undefined(是js的一种数据类型  表明变量已经声明了但没有赋值)
    
            // function aa(){
            //     function fn(){
            //         console.log('fn');
            //     }
            //     fn();
            // }
            // aa();
    
            // fn();//局部函数fn  在aa范围以外 不能调用
    
            var a = 10;//全局变量
    
            function fn(){
                var a = 100;//在函数内部重新声明了一个a  这时在fn函数内使用a都是使用局部变量
                a++;
                console.log(a);
            }
    
            function fnnn(){
                var ccc = 10;
                
                function fnn(){
                    a++;//该函数中没有声明过局部变量a  这时就使用全局变量a
                    console.log(a);
                }
            }
    
            fn();//101
            fnn();//11
        </script>
    
  • 预解析(变量提升)

    • 当浏览器在执行js代码之前,会进行一个预解析的操作,包含且不至以下两步

      • 1,先找到所有的var定义的变量,给变量赋初值 undefined,找到所有的function定义的函数,将其存入到内存中
      • 2,开始进行逐行的代码的执行
      • 预解析 程序还没开始执行 然后会悄悄的找你整个代码中的所有的var 找到之后将你定义的 变量名预先存储到 内存栈中 var a 当程序开始真正执行 时再做a=10;
      • 函数在执行预解析时 找到所有声明的函数 function 将函数所有的代码块 全部预先存储到内从中,所以 函数 先调用再声明是没用问题的 也就是声明的过程在程序执行之前 已经帮你做好了
      • 函数内部可以看作是一个小的区域,有自己的预解析
          <script>
              // 变量的预解析
              console.log(a);//undefined  没有报错
              var a = 10;
      
              // 函数预解析后  在任何位置都可以调用函数
              fn();
      
              function fn(){
                  console.log('fn');
              }
          </script>
      
  • 函数返回值

    • 函数在调用执行后 希望在函数外部使用函数计算后的结果,这时函数就要通过返回值的形式来将结果返回出函数。

      • 函数的返回值 使用return来进行
      • 函数一次只能返回一个数据
      • 函数执行return之后的代码将不再执行
      • 函数的默认返回值(你不写return)为undefined
          <script>
              // 我要在1-100的和的基础上 乘以一个值  目的这个1-100的和 我需要使用
              // function sum(num){
              //     var result = 0;
              //     for(var i = 0; i <= num; i++){
              //         result += i;
              //     }
              //     // console.log(result);
              //     // 当函数外部需要使用函数的计算结果
              //     return result;//将结果返回出去  5050
              // }
      
              // // console.log(sum(100));
      
              // var he = sum(100);// 声明一个变量  用来存储 函数返回的结果
              // console.log(he)
      
              // 函数没有写明return 返回值  默认就返回  undefined
              // function fn(){
              //     var a = 10;
              // }
      
              // console.log(fn());
              // return之后的代码将不再执行 ,所以 return可以作为函数中断来使用
              // function fn(){
              //     console.log('111');
              //     return;//直接写一个return的作用是中断函数的执行
              //     console.log('222');
              // }
      
              // fn();
      
              // 函数一次只能返回一个数据,但当我想返回多个时  该怎么办?
              // function fn(){
              //     var a = 10;
              //     var b = 20;
      
              //     return a, b;
              // }
      
              // console.log(fn());
      
              // 当你想返回多个值时 return只能返回一个数据  利用 数组或对象来返回
              // function fn(){
              //     var a = 10;
              //     var b = 20;
              //     return [a, b];//返回数据的形式
              // }
      
              // // console.log(fn());
              // var aa = fn()[0];
              // var bb = fn()[1];
              // console.log(aa, bb);
      
              function fn(){
                  var a = 10;
                  var b = 20;
                  return {num1: a, num2: b};
              }
      
              var obj = fn();
              console.log(obj);
              console.log(obj.num1, obj.num2);
          </script>
      
  • 获取非行间样式

    • 标准浏览器:getComputedStyle(元素).样式属性名
    • ie8-:元素 .currentStyle.样式属性名
    • 将获取非行间样式封装为一个函数 参数传递 el:要获取样式的元素 attr 要获取的样式属性名
    function getStyle(el, attr){//el传入要获取样式的元素  attr  要获取样式的属性名
        return el.currentStyle ?  el.currentStyle[attr] : getComputedStyle(el)[attr];
        // if(el.currentStyle){
        //     return el.currentStyle[attr];
        // }else{
        //     return getComputedStyle(el)[attr];
        // }
    }
    
  • 函数封装及复用—购物车

        <script>
            window.onload = function(){
                var aLi = document.getElementsByTagName('li');
    
                for(var i = 0; i < aLi.length; i++){
                    shopCar(aLi[i]);
                }
                /* 
                    // 通过循环将shopCar函数调用执行了 5遍
                    shopCar(aLi[0]);
                    shopCar(aLi[1]);
                    shopCar(aLi[2]);
                    shopCar(aLi[3]);
                    shopCar(aLi[4]);
                 */
    
                function shopCar(el){
                    var add = el.getElementsByTagName('button')[1];//增加按钮
                    var reduce = el.getElementsByTagName('button')[0];//减少按钮
                    var oSpan = el.getElementsByTagName('span')[0];//数量span
                    var oEm = el.getElementsByTagName('em')[0];//单价
                    var oI = el.getElementsByTagName('i')[0];//小计
    
                    add.onclick = function(){
                        var n = parseInt(oSpan.innerHTML);//获取数量转换为数字
                        n++;//每点击一次 数量增加1
                        oSpan.innerHTML = n;//将增加后的数量 显示到span中去
                        calc();
                    }
    
                    reduce.onclick = function(){
                        var n = parseInt(oSpan.innerHTML);//获取数量转换为数字
                        n--;//每点击一次 数量增加1
                        if(n <= 0){
                            n = 0;
                        }
                        oSpan.innerHTML = n;//将增加后的数量 显示到span中去
                        calc();
                    }
    
                    function calc(){
                        var count = parseInt(oSpan.innerHTML);//获取数量
                        var price = parseFloat(oEm.innerHTML);//获取单价
    
                        oI.innerHTML = (count * price).toFixed(2);//计算小计  四舍五入保留2位小数
                    }
                }
                // 完善  显示总数量和总价
            }
        </script>
    

定时器与匀速运动函数封装

  • 定时器

    • 延时定时器
      • setTimeout(function(){} 延时回调函数,延时时间(毫秒表示))
      • 回调函数:当时间到了 就执行一次(唯一1次)
      • 1000ms = 1s
    • 间隔型定时器
      • setInterval(function(){} 回调函数,间隔时间(毫秒))
      • 回调函数: 每隔一段时间 调用一次
        <script>
            // 延时定时器
            setTimeout(function(){
                console.log('哈哈哈');
            },2000)
    
            // 间隔定时器
            setInterval(function(){
                console.log('呵呵呵');
            },1000)
        </script>
    
  • 清除定时器

    • 清除延时定时器: clearTimeout(定时器名称)
    • 清除间隔定时器: clearInterval(定时器名称)
  • 异步和同步问题

    • 异步 asyn:程序执行时几件一起做

      • 回调函数—方法中的函数参数
      • 事件驱动函数
    • 同步syn:程序执行时 一件一件排序去做

    • js是单线程语言,所以在主线程中 执行代码时 直接先执行同步代码,当遇到异步代码时,就将异步代码存放到任务队列去,然后继续执行同步代码,当主线程中的所有同步代码执行完成之后,再去轮询任务队列,将准备完毕的异步代码调回主线程来进行执行。

      <script>
              window.onload = function(){
                  var aLi = document.getElementsByTagName('li');
      
                  for(var i = 0; i < aLi.length; i++){
                      aLi[i].onclick = function(){//事件驱动函数是一个异步函数
                          console.log(i);//4
                      }
                  }
              }
      
              for(var i = 0; i < 4; i++){
                  setTimeout(function(){//凡是回调函数  都为异步执行
                      console.log(i);
                  },0)
              }
          </script>
      
  • 匀速运动函数封装

    • 运动时 定时器中的时间 小于 1000/25即可----帧频
    //运动基础
    oBtn.onclick = function(){
        clearInterval(timer);//每次点击将上次的定时器清除,目的防止多次点击 叠加后速度变快
        timer = setInterval(function(){
            var cur = parseInt(getStyle(oDiv, 'left'));//当前div的left值
            //在当前值上 加上  步长  存放在speed中
            var speed = cur + 7;
    
            // 边界限定
            if(speed >= 800){
                speed = 800;//手动修正该值 强制为  目标值
                clearInterval(timer);//清除定时器
            }
    
            oDiv.style.left = speed + 'px';//给div赋值  改变div的left值
        },20)
    }
    
    //封装函数
    function linearMove(el,step,target,attr){//el要运动的元素  step步长 每次移动多少像素  target 运动的目标值  attr是要进行运动的属性
        clearInterval(timer);
        step = parseInt(getStyle(el, attr)) > target ? -step : step;//当当前值小于目标值  则  step 赋值为step   否则 当前值大于目标值  则 step赋值为 -step
        timer = setInterval(function(){
            var cur = parseInt(getStyle(el, attr));//获取当前属性值
            var speed = cur + step;//当前值加步长 计算本次移动到的位置
            // 当step 是正值  那么元素运动到大于等于目标值时  判断条件为真  需要停止
            // 当step 是负值  那么元素运动到小于等于目标值时  判断条件为真  需要停止
            if((step > 0 && speed >= target)  || (step < 0 && speed <= target)){
                speed = target;
                clearInterval(timer);
            }
            el.style[attr] = speed + 'px';
        }, 20)
    }
    
    • 数学对象 Math

    • 数学对象就是指 在程序中进行一些相对的数学运算:

      • Math.abs() 求绝对值
      • Math.sin(弧度值) cos() tan() 三角函数 弧度 = 角度 * Math.PI/180;
      • Math.ceil() 向上取整
      • Math.floor() 向下取整
      • Math.round() 四舍五入
      • Math.sqrt() 平方根
      • Math.pow() x的y次幂
      • Math.min() 一组数据中的最小值
      • Math.max() 一组数据中的最大值
          <script>
              console.log(Math.abs(-100));
              console.log(Math.sin(30 * Math.PI / 180));//Math下的三角函数中使用的不是角度 而是 弧度  弧度 = 角度*pi/180;
              console.log(Math.ceil(2.134));//  3
              console.log(Math.ceil(-2.534));// -2
      
              console.log(Math.floor(2.134));//  2
              console.log(Math.floor(-2.534));// -3
      
              console.log(Math.round(2.134));// 2 
              console.log(Math.round(2.534));// 3
      
              console.log(Math.sqrt(81));// 9 
              console.log(Math.pow(9,3));// 729
      
              console.log(Math.max(1,2,3,4,5,6,7,8,9,100));// 100
              
              console.log(Math.min(1,2,3,4,5,6,7,8,9,100));
              console.log(Math.max);
      
      
              console.log(Math.random());
          </script>
      
    • 最重要的一个 random 随机数(0 — 1 之间 的随机浮点数,包含0,不包含1)

      • 当要计算某个区间的随机整数 (max - min + 1)* Math.random() + min; 再向下取整
      <script>
              // 3-24 之间的随机数
              // Math.floor((max - min + 1) * Math.random() + min);
              var n = Math.floor((24 - 3 + 1) * Math.random() + 3);
              console.log(n)
          </script>
      

时间对象与字符串对象

  • js中的对象

    • js中的对象的分类:(万物皆对象)
      • 原生对象:Number,String,Boolean,null,Object,Array,Function,Error,RegExp,Date,Math,global
      • 内置对象:Math,global(内置对象也属于原生对象)
      • 宿主对象:DOM,BOM
      • 全局对象:window
    • 对象的创建方式
      • 实例化创建对象 var arr = new Array() 真正的创建数组对象
      • 字面量创建 var arr = [] 并不是正真的创建对象,将一个变量 暂时的包装成为一个数组对象
  • 日期时间对象

        <script>
            // 创建一个日期时间对象
            var oDate = new Date();   //data 数据
            console.log(oDate);
    
            // 获取  年  月  日  周几  时  分  秒
            var y = oDate.getFullYear();
            var m = oDate.getMonth() + 1;//  0-- 11 
            var d = oDate.getDate();
            var w = oDate.getDay();
            var h = oDate.getHours();
            var mi = oDate.getMinutes();
            var s = oDate.getSeconds();
    
            var week = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'];
    
            console.log(y + '年' + toDouble(m) + '月' + toDouble(d) + '日' + week[w] + toDouble(h) + ':' + toDouble(mi) + ':' + toDouble(s))
            
    
            function toDouble(num){
                return num < 10 ? '0' + num : '' + num;
            }
        </script>
    
    • 时间戳 获取从1970年1月1日 0:0:0 到当前日期时间的毫秒数

      • oDate.getTime(); 获取时间戳
      • 设置时间
          <script>
              // 时间戳
              var oDate = new Date();
              // console.log(oDate.getTime());
      
              // 设置日期时间
              // 设置一个完整的日期时间
              // var oDate1 = new Date('2020-10-1 0:0:0');
              // var oDate1 = new Date('2030,10,1,0:0:0');
              // var oDate1 = new Date(2030,10 - 1,2,0,0,0);
              // console.log(oDate1);
      
              // oDate.setFullYear(2030);
              // // setMonth  setDate  setMinutes  setHours
              // console.log(oDate)
              // 几种不同的时间日期的输出格式
              console.log(oDate.toString());//打印oDate   Tue Jul 21 2020 11:39:59 GMT+0800 (中国标准时间)
              console.log(oDate.toLocaleDateString());//2020/7/21
              console.log(oDate.toLocaleString());//2020/7/21 上午11:39:59
              console.log(oDate.toLocaleTimeString());//上午11:39:59
              
          </script>
      
    • momentjs 时间格式化插件

          <script>
              // var now = moment();
              // console.log(now);//Moment对象
      
              var now = moment().format('YYYY年 MM月 DD日 星期d hh:mm:ss');
              console.log(now);
      
              //设置一个日期成为moment对象
              var end = moment('2030-10-01',['YYYY-MM-DD']);
              console.log(end);
              // 通过对象方式来设置moment对象
              var time = moment({
                  year:'2030',
                  month:'9',
                  day:'12',
                  hour:'14',
                  minute:'45',
                  second:'55'
              })
              console.log(time);
      
              // 获取时间戳
              var oDate = new Date();
              console.log(oDate.getTime());
              console.log(moment().valueOf());
      
              // moment对象和原生  时间转换
              // 原生日期时间转换为  moment对象
              console.log(moment(oDate))
              // moment对象转换为原生日期时间
              console.log(moment().toDate());
      
              // moment的获取年月日等
              console.log(moment().year());
              console.log(moment().month() + 1);
      
              // get方法来获取
              console.log(moment().get('year'));
      
              // set方法来设置
              console.log(moment().set('year',2030).toDate());
      
              // isBefore()查询一个日期是否在另一个日期之前
              console.log(moment('2020-7-19').isBefore(moment()));
              // isAfter()查询一个日期是否在另一个日期之后
              console.log(moment('2020-7-19').isAfter(moment()));
              // isSame()查询一个日期是否和另一个日期相同
              // isBetween()查询一个日期是否在两个日期之间
              console.log(moment().isBetween('2020-7-1','2020-7-25'));
              // isLeapYear()//测试是否为闰年
              console.log(moment().isLeapYear());
          </script>
      
  • 字符串对象

    • 实例化创建

      • var str = new String(‘aaaa’); 创建了一个字符串对象
    • 字面量创建

      • var str = ‘aaaaa’; 将变量暂时的包装成为一个字符串对象
    • 字符串方法

      • length: 获取字符串的长度
      • charAt(下标):通过下标获取对应字符
      • charCodeAt(下标);通过下标 获取对应字符的ASCII码
      • indexOf(‘字符串1’);在当前字符串中,查找是否存在字符串1 如果存在 返回下标值 不存在则返回 -1 当被查找的字符串由多个字符构成 则返回查找到的第一字符的下标
      • lastIndexOf(‘字符串’);在当前字符串中 最后一次出现字符串的下标值
          <script>
              var str = 'A0abcdefg';
      
              console.log(str.charAt(0));//'a'
              console.log(str.charCodeAt(0));//97  ASCII码   0---48   a---97   A---65
      
              var str = 'abcdefghijklmn';
              console.log(str.indexOf('e'));// 4
              console.log(str.indexOf('z'));// -1
      
              console.log(str.indexOf('ijk'));// 8  返回的是i的下标
      
              console.log(str.indexOf('ijl'));// -1
              var str = 'abcabcabcabc';
              console.log(str.indexOf('a'));//0
              console.log(str.lastIndexOf('a'));// 9
          </script>
      
      • substring(起始下标,结束下标);从起始下标(包含起始)开始到结束下标(不包含)截取一段字符串
        • 如果只有起始 就从起始截取完
        • 如果起始大于结束下标 互换位置
        • 如果下标有负数就转换为0
      • slice(起始下标,结束下标);从起始下标(包含起始)开始到结束下标(不包含)截取一段字符串
        • 如果只有起始 就从起始截取完
        • 不支持互换位置
        • 如果起始下标有负不支持
        • 结束下标为负数 则该下标变为 str.length + (-3);
      • substr(起始下标,截取个数);从起始下标开始向后截取3个字符 包含起始下标对应的字符
        • 如果只有起始 就从起始截取完
        • 如果起始下标为负数 则转换为 str.length + (-3);
          <script>
              var str = 'abcdefghijklmn';
              console.log(str.length);
              // substring()
              console.log(str.substring(3,7));//defg
              console.log(str.substring(3));//从3开始截取完defghijklmn
              console.log(str.substring(8,2));//如果起始大于结束  会自动互换位置cdefgh
              console.log(str.substring(-3,3));//如果某个值为负数  会自动转换为0  abc
              console.log('--------------------------------------------------');
              // slice()
              console.log(str.slice(3,7));//defg
              console.log(str.slice(3));//从3开始截取完defghijklmn
              console.log(str.slice(8,2));//'' 不支持下标互换位置
              console.log(str.slice(-3,3));//'' 起始不支持负数
              console.log(str.slice(3,-3));//defghijk  当结束下标为负数时 转换  str.length + (-3); 3-11
              console.log('--------------------------------------------------');
              // substr()
              console.log(str.substr(3,3));//def
              console.log(str.substr(3));//defghijklmn
              console.log(str.substr(-3,3));//起始为负数  str.length + (-3)  从下标为11开始向后截取3个
          </script>
      
      • toLowerCase() 转小写 toUpperCase() 转大写
      • split(‘分隔符’) :将一个字符串 通过某种分割符 分割为一个数组
      • replace(要被替换的字符串,新字符串):将某几个字符串替换为新的字符串
      • trim() 删除字符串两端的空格
      // toLowerCase()  toUpperCase()
      var str = 'aBcDEfGH';
      console.log(str.toLowerCase());
      console.log(str.toUpperCase());
      console.log('--------------------------------------------------');
      // split 字符串方法  将一个字符串 通过某种分割符  分割为一个数组
      var str = 'a-b-c-d';
      var arr = str.split('-');
      console.log(arr);
      var str = 'abcd';
      var arr1 = str.split('');
      console.log(arr1);
      
      //http://item.taobo.com/item.html?a=1&b=2&c=&d=xxx&e   获取参数  得到
      //{a:“1”,b:“2”,c:“”,d:“xxx”,e:undefined}
      /* 
                  var str = 'http://item.taobo.com/item.html?a=1&b=2&c=&d=xxx&e'
                  var arr = str.split('?');//[http://item.taobo.com/item.html,a=1&b=2&c=&d=xxx&e]
                  nArr = arr[1].split('&'); //['a=1','b=2','c=','d=xxx','e']
                  循环遍历nArr  取出每一项  在拆分 然后对应放到一个对象中去  
      
              */
      console.log('--------------------------------------------------');
      // replace();
      var str = '13412340987';
      console.log(str.replace(str.substr(3,4),'****'));
      console.log('--------------------------------------------------');
      // trim(); 删除字符串两端的空格
      var str = '             abcd             ';
      console.log(str);
      console.log(str.trim());
      

    数据对象

  • 数组对象的创建

    • 实例化创建 new Array()

    • 字面量创建 var arr = [];

    • arr.length 获取数组的长度 (读) 可写 就是修改长度来修改数组的数据项

          <script>
              var arr = [1,2,3,4,5,6];
              console.log(arr.length);
      
              arr.length = 3;
              console.log(arr);
      
              arr.length = 0;//清空数组
              console.log(arr);
          </script>
      
  • 数组的方法

    • 数组的添加和删除

      • 数组尾部添加:push() 将任意个数据添加到数组的尾部,并返回数组的长度
      • 数组尾部删除:pop() 从数组的尾部删除一个数据,并返回该删除的数据
      • 数组头部添加:unshift()将任意个数据添加到数据的头部,并返回数组长度
      • 数组头部删除:shift()从数组的头部删除一个数据,并返回该删除的数据
    • 数组的截取,删除,替换,插入

      • splice(起始索引值,count,任意个新数据?)
        • 从起始索引开始(包含)截取 count个数组的数据项 将截取的数据项组成一个新数组返回。
          <script>
              var arr = [1,2,3,4,5];
              arr.push(100,101,102);//尾部添加
              console.log(arr);
      
              var str = arr.pop();//尾部删除  并将删除的数据  返回 存储到 str中
              console.log(arr, str);
      
              arr.unshift(-3,-2,-1,0);//头部添加
              console.log(arr);
      
              var str1 = arr.shift();//头部删除
              console.log(arr, str1);//头部删除  并将删除的数据  返回 存储到 str中
      
              // splice  截取(删除)
              var arr = [1,2,3,4,5,6,7];
              // var delArr = arr.splice(3,2);
              // console.log(arr, delArr);
              // 在任意位置添加
              // arr.splice(4,0,'a','b','c');
              // console.log(arr);
      
              // 替换
              arr.splice(3,2,'a','b');
              console.log(arr);
          </script>
      
    • 数组的排序

      • 排序算法

        • 冒泡排序法

          • 对数组中的相邻数据进行两两比较,将比较大的数据值 换位到后边
              <script>
                  var arr = [12,34,76,123,45,2,65,79,1,344,443,556,28];
                  // 冒泡排序
                  function bubbleSort(arr){
                      for(var i = 0; i < arr.length; i++){//外层循环控制比较次数
                          for(var j = 0; j < arr.length - i; j++){
                              if(arr[j] > arr[j + 1]){
                                  var temp = arr[j];
                                  arr[j] = arr[j + 1];
                                  arr[j + 1] = temp;
                              }
                          }
                      }
                      return arr;
                  }
          
                  console.log(bubbleSort(arr));
              </script>
          
        • 选择排序法

          • 每次用顺序固定位置上的值和所有后续的值进行比较 将最小的值 移动到顺序的固定位置上
              <script>
                  var arr = [12,34,76,123,45,2,65,79,1,344,443,556,28];
                  // 选择排序
                  function selectSort(arr){
                      for(var i = 0; i < arr.length; i++){//控制比较次数  控制顺序的固定位置
                          for(var j = i + 1; j < arr.length; j++){
                              if(arr[i] > arr[j]){
                                  var temp = arr[i];
                                  arr[i] = arr[j];
                                  arr[j] = temp;
                              }
                          }
                      }
                      return arr;
                  }
          
                  console.log(selectSort(arr));
              </script>
          
        • 递归–快速排序法

          • 递归---- 函数调用函数本身来进行循环计算(再通过边界条件返回值 进行运算的方式。 先通过调用函数本身 进行 递的过程就是展开 每层递开的函数一直展开到边界条件时,得到值,再进行归的运算 得到最终结果。)
          • 快速排序
             <script>
                 // 快速排序法  是采用了二分法的理念来进行排序
                 // 取到数组中中间索引对应的值, 建立两个数组  一个左数组  一个右数组
                 // 进行值的比较  比中间这个值小的  放到左数组  比中间值大的放到右数组
                 // 进行递归   对左数组  和右数组  继续以上快排函数进行继续操作
                 // 最后  将  左数组  中间值  和右数组  链接为一个新数组
                 var arr = [12,34,76,123,45,2,65,79,1,344,443,556,28];
          
                 function qSort(arr){
                     if(arr.length <= 1){//当数组中的长度为  1  就代表该数组中只有一个数
                         return arr;//直接返回该数组
                     }
                     var mIndex = Math.floor(arr.length / 2);//求中间下标
                     var mVal = arr.splice(mIndex,1);//截取出中间下标对应的值
                     var lArr = [];//左数组
                     var rArr = [];//右数组
                     for(var i = 0; i < arr.length; i++){//循环截取掉中间值的剩余的数据项
                         if(arr[i] > mVal){//如果该值 比 中间值大
                             rArr.push(arr[i]);  //添加到右数组
                         }else{
                             lArr.push(arr[i]);  //否则 添加到左数组
                         }
                     }
                     return qSort(lArr).concat(mVal,qSort(rArr));//返回  进行递归  然后 连接  左数组连接中间值 和  右数组
                 }
          
                 console.log(qSort(arr));
             </script>
          
      • js提供的排序方法

        • sort(function(a,b){return a - b})
        • sort的底层原理 就是 冒泡排序
        • 当a - b 正值则 ab互换 负值则不变
        • 当b - a 正值则 ab互换 负值则不变
            <script>
                // var arr = [12,34,76,123,45,2,65,79,1,344,443,556,28];
                // var nArr = arr.sort(function(a, b){
                //     // return a - b;//正序
                //     return b - a; //倒序
                // })
                // console.log(nArr);
        
                var arr3 = [
                    {"date":"2018-08-01", "DIU": 1209, "country": "US"},
                    {"date":"2018-08-02", "DIU": 680, "country": "GB"},
                    {"date":"2018-08-01", "DIU": 2311, "country": "CN"},
                    {"date":"2018-08-02", "DIU": 879, "country": "US"},
                    {"date":"2018-08-03", "DIU": 1525, "country": "CN"},
                    {"date":"2018-08-02", "DIU": 1525, "country": "CN"}
                ];
        
                // 时间字符串  转换为时间戳
                // var str = "2018-08-01";
                // console.log(Date.parse(str));
        
                var arr = arr3.sort(function(a, b){
                    if(a.date == b.date){
                        return b.DIU - a.DIU;
                    }
                    return Date.parse(b.date) - Date.parse(a.date);
                })
        
                console.log(arr);
        
        
                // 中文('zh') 文字的拼音的首字母  姓名 如何排序 
                var arr2 = [
                    { name: '武丽昕', num: 78 },
                    { name: '汤文博', num: 38 },
                    { name: '卢文博', num: 58 },
                    { name: '邓钧键', num: 97 },
                    { name: '刘继昂', num: 56 },
                    { name: '栗军安', num: 78 },
                    { name: '屈晓月', num: 98 },
                    { name: '付秋萍', num: 79 }
                ];
        
                var arr4 = arr2.sort(function(a, b){
                    return a.name.localeCompare(b.name, 'zh');
                })
        
                console.log(arr4);
            </script>
        
    • 数组去重

      • 时间复杂度去重

            <script>
                // 时间复杂度   二重循环  那么时间上就用的比较多一点点  用时间换空间
        
                var arr = [1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,9,9,9];
                
                function removal(arr){
                    for(var i = 0; i < arr.length; i++){
                        for(var j = i + 1; j < arr.length; j++){
                            if(arr[i] == arr[j]){
                                arr.splice(j,1);
                                j--;//重置下标  下次比较 对补位到该下标的值进行判断
                            }
                        }
                    }
                    return arr;
                }
        
                /* 
                    1st   0 1   1  1  相等  将第1个的1 给删除  然后 下标为2的1 补位到了下标为1的位置上
                    2nd   0 1   j++  j 2  这时  1 和第2个位置上的2来比较,漏掉了 补位到下标1上这个1
                */
        
                console.log(removal(arr));
            </script>
        
      • 空间复杂度去重

            <script>
                // 空间复杂度   减少循环  用单循环  但是 需要建立 一个空对象 一个空数组 这样导致 内存空间占用多一点点   用空间换时间
        
                var arr = [1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,9,9,9];
        
                function removal2(arr){
                    var nArr = [];//用来存储去重的数据  得到去重后的数组
                    var json = {};//对象  用来记录已经放入到nArr中的值
                    for(var i = 0; i < arr.length; i++){
                        if(!json[arr[i]]){
                            nArr.push(arr[i]);
                            json[arr[i]] = true;
                        }
                    }
                    console.log(json);
                    return nArr;
                }
        
                /* 
                    var obj = {
                        name:'joth';
                    }
                    var aa = 'name';
                    obj[aa] <==> obj.name
        
                    json[arr[0]]  <==>  json['1']  <==>  json.1
                   1   nArr = []  json = {}  i = 0   json['1']--false  nArr = [1]  json = {'1' : true}
                   2   nArr = [1] json = {'1': true} i = 1;  json['1']--true  不执行了
                   3   nArr = [1] json = {'1': true} i = 2;  json['1']--true  不执行了
                   4   nArr = [1] json = {'1': true} i = 3;  json['2']--false  nArr = [1,2] json = {'1':true,'2': true}
                   5
                */
        
                console.log(removal2(arr));
            </script>
        
    • 数组的其他方法

      • arr.join(‘连接符’):将数组通过连接符 连接成为一个字符串 split反向操作
      • arr.concat(数值或数组):将数组和其他数组或数组进行拼接返回一个新数组。
      • arr.reverse():反转数组顺序
      • arr.indexOf(值,起始下标?):判断数组是否包含值 如果包含则返回值的下标 不包含则返回-1。 可选参数 起始下标,代表从第几个下标开始 查找 默认为0
      • arr.slice(起始下标,结束下标): 从起始下标 (包含) 获取到结束下标,返回获取的值的数组。不影响原数组
      • Array.isArray(arr);// 判断对象是否为数组
          <script>
              var arr = ['a','b','c','d','e','f','g','h'];
      
              // join
              // var str = arr.join('-');
              // console.log(str);'a-b-c-d-e'
      
              // concat();
              // arr2 = arr.concat('哈哈',[1,2,3]);
              // console.log(arr2);
      
              // reverse
              // console.log(arr.reverse());
      
              // indexOf()
              console.log(arr.indexOf('c'));//2
              console.log(arr.indexOf('c',4));//-1
      
              // slice()  用法和字符串slice方法 相同
              console.log(arr.slice(1,4));
              console.log(arr.slice(3,-2));
      
              // Array.isArray(arr);//  判断对象是否为数组
              var obj = {};
              console.log(typeof arr);//'object'
              console.log(typeof obj);//'object'
              console.log(Array.isArray(arr));//true
              console.log(Array.isArray(obj));//false
          </script>
      
    • 数组的其他迭代方法

      • every(function(value,index){}):当遍历数组中的每个值如果都 满足return的条件,那么返回true 有1个不满足则返回false
      • some(function(value,index){}):当遍历数组中的每个值如果有 满足return的条件,那么返回true 1个满足都没有则返回false
      • filter(function(value,index){});过滤 将满足条件的数组项过滤出来 返回形成新数组
      • map(function(value,index){});将数组中的值遍历可以进行操作 运算 然后返回为一个新数组
      • forEach(function(value,index){}):遍历数组中的值,然后没有返回值 只进行遍历 类似for循环
          <script>
              var arr = [1,2,3,4,5,6,7,8];
              var arr2 = [1,3,5,7,9];
              // every
              var aa = arr.every(function(v,i){
                  
                  return v < 10;
              })
              console.log(aa);//true
      
              // some
              var bb = arr.some(function(v,i){
                  return v % 2 == 0;
              })
              console.log(bb);//true
      
              // filter
      
              var nArr = arr.filter(function(v,i){
                  return v % 2 == 0;
              })
              console.log(nArr);//[2,4,6,8]
      
              // map
              var arr3 = arr.map(function(val,i){
                  return val * val
              })
              console.log(arr3);
      
              // for(var i = 0; i < arr.length; i++){
              //     console.log(arr[i]);
              // }
              //forEach  相当于数组专用的for循环
              arr.forEach(function(v,i){
                  console.log(i, v);
              })
          </script>
      

      DOM 操作

  • DOM—Document Object Model 文档对象模型

    • html文档 所有的关于html标签构建为一个树形模型,然后所有的标签,都被称之为DOM树上的节点,通过DOM的方式给这些对象添加js的API(属性和方法)。标签—》元素—》节点
  • 获取子节点

    • 父节点.childNodes;获取父元素下的所有节点

      • 节点包括:元素节点,属性节点(html没有,XML才有),文本节点
      • nodeType 返回节点类型 1代表元素节点 2 代表属性节点 3 代表文本节点
      • nodeName 节点名称
      • nodeValue 只针对文本节点的内容获取。元素节点无法使用该方法获取内容
    • 父节点.children; 获取父元素下的所有子元素节点

          <script>
              window.onload = function(){
                  var oUl = document.getElementsByTagName('ul')[0];
                  // console.log(oUl.children.length);//4
                  console.log(oUl.childNodes.length);// ie 4  chrome 9
                  // nodeType  节点类型  nodeName  节点名称  nodeValue
                  console.log(oUl.childNodes[0].nodeType);//3
                  console.log(oUl.childNodes[1].nodeType);//1
                  console.log(oUl.childNodes[2].nodeType);//3
                  console.log(oUl.childNodes[3].nodeType);//1
      
                  console.log(oUl.childNodes[0].nodeName);//#text 文本节点
                  console.log(oUl.childNodes[1].nodeName);//LI li元素节点
      
                  console.log(oUl.childNodes[0].nodeValue);//hahaha 
                  console.log(oUl.childNodes[1].nodeValue);//null
                  var aLi = [];
                  for(var i = 0; i < oUl.childNodes.length; i++){
                      if(oUl.childNodes[i].nodeType == 1){
                          aLi.push(oUl.childNodes[i]);
                      }
                  }
                  console.log(aLi);
      
                  console.log(oUl.children)
              }
          </script>
      
  • 获取父节点

    • 子元素.parentNode:获取父元素

    • 子元素.offsetParent:获取距离子元素最近的有定位属性的父元素,如果所有的父元素都没有定位属性,则获取body

          <script>
              window.onload = function(){
                  var oDiv4 = document.getElementById('div4');
      
                  console.log(oDiv4.parentNode.id);//'div3'
      
                  console.log(oDiv4.offsetParent);//
              }
          </script>
      
          <script>
              window.onload = function(){
                  var oDiv4 = document.getElementById('div4');
      
                  // oDiv4 距离  body的top值是多少
                  // 获取元素和定位父级直接的定位top值  offsetTop
                  // console.log(oDiv4.offsetTop);
      
                  function getTop(el){
                      var iTop = 0;
                      while(el.offsetParent){
                          iTop += el.offsetTop;
                          el = el.offsetParent;
                      }
                      return iTop;
                  }
      
                  /* 
                      1  oDiv4    while(oDiv4.offsetParent)  while(oDiv3)  iTop += 20  el = oDiv3
                      2  oDiv3    while(oDiv3.offsetParent)  while(oDiv1)  iTop += 50  el = oDiv1
                      3  oDiv1    while(oDiv1.offsetParent)  while(body)  iTop += 100  el = body
                      4  body     while(body.offsetParent)   while(null); exit
                   */
      
                  console.log(getTop(oDiv4));
              }
          </script>
      
  • 获取其他节点(都有兼容性)

    • firstChild 和 firstElementChild 获取父元素下的第一个子节点

      • firstChild 在chrome ff 获取第一个子节点为文本节点 在ie8- 获取第一个元素节点
      • firstElementChild 在chrome ff 获取第一个元素节点 ie8- undefined
    • lastChild 和 lastElementChild 获取父元素下的最后一个子元素(兼容性同上)

    • nextSibling 和 nextElementSibling 获取当前元素的下一个兄弟节点(兼容性同上)

    • previousSibling 和previousElementSibling 获取当前元素的上一个兄弟节点(兼容性同上)

          <script>
              window.onload = function(){
                  var oUl = document.getElementsByTagName('ul')[0];
      
                  console.log(oUl.firstChild);//chrome ff 标准浏览器  文本节点  ie 8- 元素节点
                  console.log(oUl.firstElementChild);//chrome ff  第一个元素子节点  ie下undefind
      
                  // function getFchild(el){
                  //     if(el.firstElementChild){
                  //         return el.firstElementChild;
                  //     }else{
                  //         return el.firstChild;
                  //     }
                  // }
      
                  var fChild = oUl.firstElementChild || oUl.firstChild;
                  // 短路或   当第一项为真 则返回第一项   第一项为假  则返回第二项
                  // 在chrome中 第一项为 真  返回第一项  而在ie中  第一项得到的值 undefined 为假  所以会返回  firstChild
      
                  var lChild = oUl.lastElementChild || oUl.lastChild;
      
                  lChild.style.background = 'red';
      
                  var oLi = document.getElementById('li1');
      
                  var nSb = oLi.nextElementSibling || oLi.nextSibling;
      
                  nSb.style.background = 'green';
      
                  var pSb = oLi.previousElementSibling || oLi.previousSibling;
      
                  pSb.style.background = 'pink';
              }
          </script>
      
  • 操作节点

    • 创建节点:

      • 创建元素节点 createElement(‘标签名’);
      • 创建文本节点 createTextNode(‘文本内容’);
    • 添加节点:在父元素的最后追加节点 appendChild(节点/元素)

    • 插入节点:在父节点中 的某个子节点之前插入一个新节点 父节点.insertBefore(要插入的节点,目标节点) 在目标节点之前插入

    • 删除节点:

      • removeChild :从父节点删除一个子节点
      • remove:删除当前节点
    • 替换节点:父节点.replaceChild(新节点,要被替换的节点)

    • 克隆节点:cloneNode(布尔值) 复制一个节点 将复制的节点返回,参数默认为false 则不克隆节点内的内容,返回空节点。 当参数为true 则将节点及节点内容全部复制

         <script>
             window.onload = function(){
                 var oUl = document.getElementById('list');
                 // oUl.innerHTMl += '
    • 中秋节
    • ';
      // 创建一个li var oLi = document.createElement('li'); var txt = document.createTextNode('中秋节'); // 将创建文本节点追加到创建的元素节点 oLi.appendChild(txt); //将创建的元素节点 追加到父节点 oUl.appendChild(oLi);
              // 插入节点
              var oLi = document.createElement('li');
              oLi.innerHTML = '情人节';
              oUl.insertBefore(oLi,oUl.children[1]);
      
              // 删除节点
              // 从父节点中 删除一个子节点
              // oUl.removeChild(oUl.children[3]);
              oUl.children[3].remove();// 删除本身
      
              // 替换元素
              var oLi = document.createElement('li');
              oLi.innerHTML = '乞巧节';
              oUl.replaceChild(oLi,oUl.children[4]);
      
              // 克隆
              var cLi = oUl.children[0].cloneNode(true);
              console.log(cLi);
              oUl.appendChild(cLi);
          }
      
      
      
      
  • 获取标签的方法和设置/获取属性的新方法

    • 之前的获取标签的方法

      • getElementById 通过id获取元素
      • getElementsByTagName 通过标签名获取元素集合
      • getElementsByClassName 通过类名获取元素集合 ie8+
    • 新的方法 ie9+

      • querySelector(‘选择器’) 通过选择器获取单个元素,当元素有多个时 获取第0个
      • querySelectorAll(‘选择器’)通过选择器获取元素集合
          <script>
              window.onload = function(){
                  // getElementById('box');
                  // var oBox = document.querySelector('#box');
                  // console.log(oBox);
      
                  // var oDiv = document.querySelector('div');//获取div中的第0个
                  // console.log(oDiv);
      
                  var aDiv = document.querySelectorAll('div');
                  console.log(aDiv);
      
                  var aDiv1 = document.querySelectorAll('.div1');
                  console.log(aDiv1);
              }
          </script>
      
    • 设置和获取属性值的新方法

      • 之前元素.属性名 来获取 元素.属性名 = 新属性值 来设置(缺点:不能获取/设置标签中定义的自定义属性)
      • 新的属性的获取和修改 (可以获取/修改 标签中的自定义属性)
        • getAttribute(‘属性名’) 获取属性名对应的属性值
        • setAttribute(‘属性名’,‘新的属性值’) 设置属性名对应的属性值
          <script>
              window.onload = function(){
                  var oA = document.querySelector('#box');
      
                  console.log(oA.title);
                  oA.title = 'abc1';
                  
                  console.log(oA.index);
      
                  console.log(oA.getAttribute('index'));
                  console.log(oA.getAttribute('target'));
                  oA.setAttribute('index','888');
              }
          </script>
      
  • 表格的操作

    • 表格操作API 表头 oTab.tHead 表尾 oTab.tFoot 表体 oTab.tBodies[下标]

    • rows 获取行 cells 获取单元格

          <script>
              window.onload = function(){
                  var oTab = document.getElementById('tab');
                  console.log(oTab.tHead);
                  console.log(oTab.tFoot);
                  console.log(oTab.tBodies[0]);
      
                  // 行
                  console.log(oTab.tBodies[0].rows[0]);
                  // 单元格
                  console.log(oTab.tBodies[0].rows[0].cells[1].innerHTML);
              }
          </script>
      

BOM

  • Browser Object Model 浏览器对象模型—和浏览器相关的一些API,BOM 的核心是 window

  • 系统弹窗

    • alert(‘内容’)警告弹窗

    • confirm(‘内容’)带有确定的弹窗,返回值 点确定返回 true 取消返回false

    • prompt(‘标题’,‘默认内容’)可以输入内容的弹窗,当点击确定时 有内容就返回内容没有填写内容就返回空 点取消返回null

          <script>
              // alert('123123');
              // 带有确认和取消的弹窗
              // var isOk = confirm('are you ok?');
              // console.log(isOk);
      
              var str = prompt('请开始你的表演','才艺名称');
              console.log(str);
          </script>
      
  • open()和close();

    • open

      • 行间使用 οnclick=”window.open(‘http://www.ujiuye.com’)”
      • js代码中使用 open(url,target,窗口宽高,是否替换当前浏览器中记录的位置)
    • close

      • 行间用法同上
      • js中使用 close();
          <script>
              window.onload = function(){
                  var oBtn = document.getElementsByTagName('button');
      
                  oBtn[0].onclick = function(){
                      open('aaa.html','_blank');
                  }
              }
          </script>
      
          <script>
              window.onload = function(){
                  document.getElementsByTagName('button')[0].onclick = function(){
                      close();
                  }
              }
          </script>
      
  • location 窗口加载信息

    console.log(location.hash);//哈希值
    console.log(location.host);//域名+端口
    console.log(location.hostname);//主域名
    console.log(location.href);//路径地址
    console.log(location.origin);//来源
    console.log(location.protocol);//协议
    console.log(location.port);//端口
    console.log(location.search);//传参
    
    • 其他功能

      • window.location.reload() 刷新当前页面
      • window.location = ‘新地址’ 跳转页面
      document.getElementsByTagName('button')[0].onclick = function(){
                      window.location.reload();//刷新页面
                  }
                  document.getElementsByTagName('button')[1].onclick = function(){
                      window.location = 'http://www.163.com';//  跳转页面
                  }
      
  • history 历史记录

    • history.go(下标) 跳到历史记录中的对应下标的页面
    • history.back()后退一个历史记录中的页面
    • history.forward()前进到一个历史记录中的页面
    • history.length 返回历史记录中记录的地址的数量
  • navigator 导航 反馈浏览器和操作系统的信息

        <script>
            window.onload = function(){
                var oDiv = document.getElementsByTagName('div')[0];
                oDiv.innerHTML = '浏览器代号:' + navigator.appCodeName + '
    '
    + '浏览器名称:' + navigator.appName + '
    '
    + '浏览器版本:' + navigator.appVersion + '
    '
    + '是否启用cookie:' + navigator.cookieEnabled + '
    '
    + '浏览器代理:' + navigator.userAgent + '
    '
    + '浏览器语言:' + navigator.language + '
    '
    + '浏览器语言:' + navigator.systemLanguage + '
    '
    + '当前系统:' + navigator.platform + '
    '
    } </script>
  • body 位置属性

    • client系列宽度获取

      • 元素.clientWidth/元素.clientHeight:元素的可视宽高 (width/height + padding)
      • document.documentElement.clientWidth/document.documentElement.clientHeight:浏览器可视区的宽高
      • 元素.clientTop/元素.clientLeft 元素的上边框宽 和左边框宽
          <script>
              window.onload = function(){
                  var oBox = document.getElementById('box');
                  var oDiv = document.getElementById('div1');
                  // 元素的可视宽
                  console.log(oBox.clientWidth);//100
                  console.log(oDiv.clientWidth);//240  width + 左右padding
      
                  // 浏览器可视区的宽高
                  console.log(document.documentElement.clientHeight);
                  console.log(document.documentElement.clientWidth);
      
                  // 上边框和左边框 
                  console.log(oDiv.clientTop);//5
                  console.log(oDiv.clientLeft);//5
              }
          </script>
      
    • offset系列

      • offsetTop:当前元素和定位属性父级之间的top值,如果没有定位属性父级 则和body来计算
      • offsetLeft:当前元素和定位属性父级之间的left值,如果没有定位属性父级 则和body来计算
      • offsetWidth:占位宽 (width内容宽 + padding + border)
      • offsetHeight:占位高(height + padding + border)
      • offsetParent上个章节
          <script>
              window.onload = function(){
                  var oDiv = document.getElementsByTagName('div')[0];
      
                  console.log(oDiv.offsetTop);//100
                  console.log(oDiv.offsetLeft);//50
                  console.log(oDiv.offsetWidth);//130
                  console.log(oDiv.offsetHeight);//130
              }
          </script>
      
  • scrollTop系列

    • 滚动条事件 window.onscroll
    • 获取滚动条卷走的高度/宽度:
      • document.doucmentElement.scrollTop || document.body.scrollTop
      • document.doucmentElement.scrollLeft || document.body.scrollLeft
    • 元素.scrollTop/元素.scrollLeft;元素的滚动条卷走的宽高
    • 元素.scrollWidth/元素. scrollHeight: 有滚动条的元素的 内部实际内容的宽高
        <script>
            window.onload = function(){
                window.onscroll = function(){
                    var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
                    console.log(scrollTop);
                }
            }
        </script>
    
    //元素的滚动
        <script>
            window.onload = function(){
                var oBox = document.getElementById('box');
                // 所有的或 卷走宽高和实际内容的宽高  都写父盒子
                oBox.onscroll = function(){
                    console.log(oBox.scrollTop);
                    console.log(oBox.scrollHeight);//1002  1000+2border
                }
            }
        </script>
    
  • 懒加载

    • 当加载图片数量过多时,一次性加载会比较慢,我才用一开始将直接出现在浏览器可视区的图片加载进来,然后后续图片先不加载,等到用户滚动页面将可视区外的图片滚动到了可视区内时再对进入可视区范围的图片进行加载。实现:先将每张图片的src地址给到一个标签中的自定义属性 _src中。当图片进入了可视区的范围是 将_src 中的地址 给到真正的src 上进行图片加载
  • 当窗口尺寸发生变化的事件 onresize

事件

  • 事件对象

    • 当事件触发时,关于触发事件的对象(鼠标,键盘按键)的一些具体的属性,例如当点击事件发生时 鼠标在可视区的点击位置,在元素中的点击位置,点击的目标是谁等

    • 事件对象是window的一个属性,window.event window可以被省略

    • 在ie chrome中 可以使用event 但是在ff中 要使用事件对象 需要进行传参 ev来使用事件对象

          <script>
              window.onload = function(){
                  var oDiv = document.getElementById('box');
                  oDiv.onclick = function(ev){
                      // console.log(event.target);//目标  当前触发事件的对象  (谁被点击了)
                      // console.log(event.type);// 触发了什么事件
                      // console.log(event.pageX);// 鼠标点击相对于整个文档的left值
                      // console.log(event.pageY);// 鼠标点击相对于整个文档的top值
                      // console.log(event.clientX);// 鼠标点击相对于浏览器可视区的left值
                      // console.log(event.clientY);// 鼠标点击相对于浏览器可视区的top值
                      // console.log(event.offsetX);// 鼠标点击相对于元素的left值
                      // console.log(event.offsetY);// 鼠标点击相对于元素的top值
                      // event  ie 和 chrome  可以使用   ff 不能使用
                      // ff 进行事件函数的传参 传ev  ff下要使用传参进来的ev
                      var ev = ev || event;//事件对象的兼容  
                      // console.log(ev);
                      // console.log(ev.target);//chrome  ff
                      // console.log(ev.srcElement);//ie
                      var target = ev.target || ev.srcElement;
                      console.log(target);
                  }
              }
          </script>
      
  • 事件的绑定与取消

    • 后写的按钮的点击事件函数会覆盖先写的

    • 给同一个按钮的同一个事件上绑定多个事件处理函数

    • chrome ff 下事件绑定 addEventListener(‘事件’,事件处理函数,布尔值?(setCapture)是否捕获)----使用事件时 不带 on onclick --》 click setCapture 默认为false (冒泡事件流) 如果为true 就使用 捕获事件流

    • ie attachEvent(‘事件’,事件处理函数)

          <script>
              window.onload = function(){
                  var oBtn = document.getElementById('btn');
      
                  // oBtn.onclick = function(){
                  //     console.log(1);
                  // }
      
                  // oBtn.onclick = function(){
                  //     console.log(222222);
                  // }
      
                  // 后写的按钮的点击事件函数会覆盖先写的
      
                  
                  // 给同一个按钮的同一个事件上绑定多个事件处理函数
                  // oBtn.addEventListener('click',function(){
      
                  // },false);
                  function fn1(){
                      console.log(1);
                  }
      
                  function fn2(){
                      console.log(22222);
                  }
                  // oBtn.addEventListener('click',fn1,false);//给按钮的点击事件 绑定第一个函数
                  // oBtn.addEventListener('click',fn2,false);//给按钮的点击事件 绑定第二个函数
      
                  // ie中的事件绑定
                  // oBtn.attachEvent('onclick',fn1);
                  // oBtn.attachEvent('onclick',fn2);
      
                  if(oBtn.addEventListener){//元素对象可以使用该方法  就为真  不能使用就为假
                      oBtn.addEventListener('click',fn1,false);
                      oBtn.addEventListener('click',fn2,false);
                  }else{
                      oBtn.attachEvent('onclick',fn1);
                      oBtn.attachEvent('onclick',fn2);
                  }
              }
          </script>
      
      //事件绑定的函数封装
              function bindEvent(el,oEvent,fn){
                  if(el.addEventListener){
                      el.addEventListener(oEvent, fn, false);
                  }else{
                      el.attachEvent('on' + oEvent, fn);
                  }
              }
      
    • 事件取消绑定

      • addEventListener 对应的事件取消绑定 removeEventListener(‘事件’,函数);
      • attachEvent 对应的事件取消绑定 detachEvent(‘事件’,函数);
          <script>
              window.onload = function(){
                  var oBtn = document.getElementsByTagName('button');
                  function fn1(){
                      console.log('我有点击事件了')
                  }
                  // oBtn[1].onclick = function(){
                  //     oBtn[0].addEventListener('click',fn1,false);
                  // }
      
                  // oBtn[2].ondblclick = function(){
                  //     oBtn[0].removeEventListener('click',fn1);
                  // }
      
                  // oBtn[1].onclick = function(){
                  //     oBtn[0].attachEvent('onclick',fn1);
                  // }
      
                  // oBtn[2].ondblclick = function(){
                  //     oBtn[0].detachEvent('onclick',fn1);
                  // }
                  // 事件绑定函数
                  function bindEvent(el,oEvent,fn){
                      if(el.addEventListener){
                          el.addEventListener(oEvent, fn, false);
                      }else{
                          el.attachEvent('on' + oEvent, fn);
                      }
                  }
                  // 取消绑定函数
                  function removeEvent(el, oEvent, fn){
                      if(el.removeEventListener){
                          el.removeEventListener(oEvent,fn);
                      }else{
                          el.detachEvent('on' + oEvent,fn);
                      }
                  }
      
                  oBtn[1].onclick = function(){
                      bindEvent(oBtn[0],'click', fn1);
                  }
      
                  oBtn[2].ondblclick = function(){
                      removeEvent(oBtn[0], 'click', fn1);
                  }
              }
          </script>
      
  • DOM事件流

    • 事件发生时会在元素节点与根节点之间按照特定的顺序传播,路径所经过的所有节点都会收到该事件,这个传播过程即 DOM 事件流。(如:当你点击了一个元素时,该事件不会只在该元素上触发,而会通过某种顺序,在DOM树中进行传播,如果传播到的节点有该事件的处理函数,则该函数被触发)

    • DOM事件流 分为三个阶段

      • 1 事件捕获阶段:从根节点向目标节点进行事件的传播
      • 2 目标确定阶段:真正触发该事件的元素
      • 3 事件冒泡阶段:从目标节点向根节点进行事件的传播
      • P.S. chrome ff 都具有 捕获和冒泡两种事件流 (先捕获再冒泡) 而 ie 只有冒泡事件流
      //冒泡事件流
          <script>
              window.onload = function(){
                  var oDiv1 = document.getElementById('div1');
                  var oDiv2 = document.getElementById('div2');
                  var oDiv3 = document.getElementById('div3');
      
                  oDiv3.onclick = function(){
                      console.log('div3');
                  }
      
                  oDiv1.onclick = function(){
                      console.log('div1');
                  }
                  document.body.onclick = function(){
                      console.log('body');
                  }
                  document.onclick = function(){
                      console.log('document');
                  }
              
              //div3-->div1-->body-->document
              }
          </script>
      
      //捕获事件流
          <script>
              window.onload = function(){
                  var oDiv1 = document.getElementById('div1');
                  var oDiv2 = document.getElementById('div2');
                  var oDiv3 = document.getElementById('div3');
      
                  oDiv3.addEventListener('click',function(){
                      console.log('div3')
                  },true)
      
                  oDiv1.addEventListener('click',function(){
                      console.log('div1');
                  },true)
      
                  document.addEventListener('click',function(){
                      console.log('document');
                  },true)
              
              // document-->div1-->div3
              }
          </script>
      
    • 取消冒泡

      • 标准浏览器 ev.stopPropagation()
      • ie浏览器 ev.cancelBubble = true;
      • 兼容:ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;
          <script>
              window.onload = function(){
                  var oDiv1 = document.getElementById('div1');
                  var oDiv2 = document.getElementById('div2');
                  var oDiv3 = document.getElementById('div3');
      
                  oDiv3.onclick = function(ev){
                      var ev =ev || event;
                      console.log('div3');
                      ev.stopPropagation ? ev.stopPropagation() : ev.cancelBubble = true;
                  }
      
                  oDiv1.onclick = function(){
                      console.log('div1');
                  }
                  document.body.onclick = function(){
                      console.log('body');
                  }
                  document.onclick = function(){
                      console.log('document');
                  }
              }
          </script>
      
  • 事件的默认行为

    • 当事件触发时,本身默认就能执行某些操作,就称之为事件的默认行为。

    • 取消事件默认行为

      • 1 当采用事件驱动时:在事件驱动函数中 代码的最后写 return false;
      • 2 当采用addEventListener绑定事件时:ev.preventDefaut();
      • 3 当采用attachEvent绑定事件时:ev.returnValue = false;
          <script>
              window.onload = function(){
                  // 事件驱动方式
                  // document.oncontextmenu = function(){
                  //     console.log(1);
                  //     return false;
                  // }
                  // addEventListener 绑定
                  // document.addEventListener('contextmenu',function(ev){
                  //     var ev = ev || event;
                  //     console.log(11);
                  //     // return false;
                  //     ev.preventDefault();
                  // },false)
      
                  // ie 事件绑定  attachEvent
                  document.attachEvent('oncontextmenu',function(ev){
                      var ev = ev || event;
                      console.log('ie');
                      ev.returnValue = false;
                  })
              }
          </script>
      
  • 键盘事件

    • 键盘事件:onkeydown按键按下 onkeyup按键抬起

    • 键盘按键确定: ev.keyCode ===> 按键值

    • 专门的三个方法来进行 组合键的使用

      • ev.altKey ev.ctrlKey ev.shiftKey
          <script>
              window.onload = function(){
                  var oIn = document.getElementById('txt');
                  var oDiv = document.getElementsByTagName('div')[0];
      
                  document.onkeydown = function(ev){
                      var ev = ev || evnet;
                      // 根据键值 来判断按下了哪个键
                      // 希望ctrl+enter来发送
                      // if(ev.keyCode == 13 && ev.keyCode == 17){
                      //     oDiv.innerHTML = oIn.value;
                      // }
                      // 专门的三个方法来进行  组合键的使用
                      if(ev.keyCode == 13 && ev.ctrlKey){
                          oDiv.innerHTML = oIn.value;
                      }
                  }
              }
          </script>
      
    • 上下左右按键控制div的移动完美版

          <script>
              window.onload = function(){
                  var oDiv = document.getElementById('box');
                  var il,ir,id,iu;
      
                  setInterval(function(){
                      if(il) oDiv.style.left = oDiv.offsetLeft - 10 + 'px';
                      if(iu) oDiv.style.top = oDiv.offsetTop - 10 + 'px';
                      if(ir) oDiv.style.left = oDiv.offsetLeft + 10 + 'px';
                      if(id) oDiv.style.top = oDiv.offsetTop + 10 + 'px';
                  },20)
      
      
                  document.onkeydown = function(ev){
                      var ev = ev || evnet;
                      switch(ev.keyCode){
                          case 37:// 左
                              il = true;
                          break;
                          case 38:// 上
                              iu = true;
                          break;
                          case 39:// 右
                              ir = true;
                          break;
                          case 40:// 下
                              id = true;
                          break;
                      }
                  }   
                  document.onkeyup = function(ev){
                      var ev = ev || event;
                      switch(ev.keyCode){
                          case 37:// 左
                              il = false;
                          break;
                          case 38:// 上
                              iu = false;
                          break;
                          case 39:// 右
                              ir = false;
                          break;
                          case 40:// 下
                              id = false;
                          break;
                      }
                  }
              }
          </script>
      
  • 滚轮事件

    • 滚轮事件
      • chrome ie: onmousewheel 可以使用事件驱动也可以事件绑定来使用
      • ff: DOMMouseScroll 只能使用事件绑定的方式来使用
    • 滚轮上下滚动的取值判断
      • chrome ie : ev.wheelDelta -120代表向下滚 120代表向上滚
      • ff: ev.detail 3代表向下滚 -3代表向上滚
        <script>
            window.onmousewheel = document.onmousewheel = function(ev){
                var ev = ev || event;
                console.log(ev.wheelDelta);//下  -120  上  120
            }
    
            document.addEventListener('DOMMouseScroll',function(ev){
                console.log(ev.detail);//下3  上 -3
            })
        </script>
    
    
    
    //兼容
        <script>
            function bindEvent(el, oEvent, fn){
                if(el.addEventListener){
                    el.addEventListener(oEvent, fn, false);
                }else{
                    el.attachEvent('on' + oEvent, fn);
                }
            }
    
            function iScroll(ev){
                var ev = ev || event;
                var bDown = false;//  当bDown无论在任何浏览器  只要它的值为真就说明滚轮在向下滚动  为假则滚轮在向上滚动
                // if(ev.wheelDelta){//wheelDelta能否使用  如果支持该属性就说明 chrome  ie  那么就使用该属性
                //     if(ev.wheelDelta < 0) bDown = true;//如果当前的wheelDelta 取值小于0  那么说明滚轮是在chrome向下滚动  将bDown赋值为 true
                // }else{
                //     // 否则  不能使用wheelDelta  说明是ff浏览器  使用ev.detail
                //     if(ev.detail > 0) bDown = true;//如果当时使用ev.detail 取值大于0  那么说明滚轮是在火狐浏览器中向下滚动  将bDown赋值为 true
                // }
                // 三目写法
                bDown = ev.wheelDelta ? ev.wheelDelta < 0 : ev.detail > 0;
    
                if(bDown){
                    console.log('我向下滚');
                }else{
                    console.log('我向上滚');
                }
            }
    
            bindEvent(document, 'mousewheel', iScroll);// chrome ie
            bindEvent(document, 'DOMMouseScroll', iScroll);// ff
        </script>
    
    • 事件委托

    • 将事件添加到父元素上,当事件发生时,父元素会找到对应触发事件的子元素去处理,后期添加的子元素,依然有这个事件。

          <script>
              window.onload = function(){
                  var oUl = document.getElementsByTagName('ul')[0];
                  // var aLi = oUl.getElementsByTagName('li');
                  var oBtn = document.getElementsByTagName('button')[0];
      
                  // for(var i = 0; i < aLi.length; i++){
                  //     aLi[i].onclick = function(){
                  //         console.log(this.innerHTML)
                  //     }
                  // }
      
                  // oBtn.onclick = function(){
                  //     var oLi = document.createElement('li');
                  //     oLi.innerHTML = 'new';
                  //     oUl.appendChild(oLi);
      
                  //     for(var i = 0; i < aLi.length; i++){
                  //         aLi[i].onclick = function(){
                  //             console.log(this.innerHTML)
                  //         }
                  //     }
                  // }
      
                  // 事件委托
                  oUl.onclick = function(ev){
                      var ev = ev || event;
                      // 寻找到点了那个子元素li 触发事件的对象
                      // console.log(ev.target);
                      var target = ev.target || ev.srcElement;//找到真正触发事件的子元素  兼容
                      console.log(target.innerHTML);
                  }
      
                  oBtn.onclick = function(){
                      var oLi = document.createElement('li');
                      oLi.innerHTML = 'new';
                      oUl.appendChild(oLi);
                  }
              }
          </script>
      

js动画特效

  • 拖拽效果:

    • 鼠标在元素上按下:onmousedown 需要计算一个按下的位置记录(鼠标点击的位置和元素定位的左上角的差值)

    • 鼠标按下的同时 进行鼠标移动:onmousemove

    • 最后鼠标抬起:onmouseup

    • 鼠标移动和释放要写给document

    • 文字被选中:在mousedown的最后取消默认事件 return false ie:setCapture 设置事件捕获releaseCapture 释放事件捕获

          <script>
              window.onload = function(){
                  var oDiv = document.getElementById('box');
                  var disX = 0;
                  var disY = 0;
                  // 鼠标按下
                  oDiv.onmousedown = function(ev){
                      var ev = ev || event;
                      disX = ev.clientX - oDiv.offsetLeft;
                      disY = ev.clientY - oDiv.offsetTop;
      
                      // 鼠标开始移动  将鼠标的位置  赋值给div的left和top  使div跟着移动
                      document.onmousemove = function(ev){
                          var ev = ev || event;
                          oDiv.style.top = ev.clientY - disY + 'px';
                          oDiv.style.left = ev.clientX - disX + 'px';
                      }
                      document.onmouseup = function(){
                          if(oDiv.releaseCapture) oDiv.releaseCapture();
                          document.onmousemove = null;
                          document.onmouseup = null;
                      }
                      if(this.setCapture) this.setCapture();
                      return false;
                  }
              }
          </script>
      
    • 拖拽区域限定

          <script>
              window.onload = function(){
                  var oDiv = document.getElementById('box');
                  var disX = 0;
                  var disY = 0;
                  // 鼠标按下
                  oDiv.onmousedown = function(ev){
                      var ev = ev || event;
                      disX = ev.clientX - oDiv.offsetLeft;
                      disY = ev.clientY - oDiv.offsetTop;
      
                      // 鼠标开始移动  将鼠标的位置  赋值给div的left和top  使div跟着移动
                      document.onmousemove = function(ev){
                          var ev = ev || event;
                          var t = ev.clientY - disY;
                          var l = ev.clientX - disX;
                          // 判断t 和 l 不能超过 可视区的宽/高- 该元素的宽/高
                          // 0 就限制范围  50 类似吸附效果
                          if(t <= 50){
                              t = 0;
                          }else if(t >= document.documentElement.clientHeight - oDiv.offsetHeight - 50){
                              t = document.documentElement.clientHeight - oDiv.offsetHeight;
                          }
      
                          if(l <= 50){
                              l = 0;
                          }else if(l >= document.documentElement.clientWidth - oDiv.offsetWidth - 50){
                              l = document.documentElement.clientWidth - oDiv.offsetWidth;
                          }
      
                          oDiv.style.top = t + 'px';
                          oDiv.style.left = l + 'px';
                      }
                      document.onmouseup = function(){
                          document.onmousemove = null;
                          document.onmouseup = null;
                      }
                      return false;
                  }
              }
          </script>
      
    • 碰撞检测

      if(oDiv.offsetLeft + oDiv.offsetWidth > oBigBox.offsetLeft && oDiv.offsetLeft < oBigBox.offsetLeft + oBigBox.offsetWidth && oDiv.offsetTop + oDiv.offsetHeight > oBigBox.offsetTop && oDiv.offsetTop < oBigBox.offsetTop + oBigBox.offsetHeight){
                              oBigBox.style.background = 'green';
                          }else{
                              oBigBox.style.background = '';
                          }
      
  • 缓冲运动框架

    • 回顾匀速运动框架:特点 步长是固定

    • 缓冲运动:步长(速度 ) 通过公式来进行计算 (目标值 - 当前值)/ 运动系数(6–10) 运动系数越小 速度就越快

    • 运动到最后时 速度不够 1 那么我们需要将小数取得1 向上取整

          <script>
              function getStyle(el, attr){
                  return el.currentStyle ? el.currentStyle[attr] : getComputedStyle(el, false)[attr];
              }
              window.onload = function(){
                  var oDiv = document.getElementById('box');
                  var oBtn = document.getElementsByTagName('button')[0];
                  var timer = null;
      
                  oBtn.onclick = function(){
                      clearInterval(timer);
                      timer = setInterval(function(){
                          var cur = parseInt(getStyle(oDiv, 'left'));
                          var speed = (800 - cur) / 10;
                          speed = Math.ceil(speed);
                          if( cur == 800){
                              clearInterval(timer);
                          }
                          oDiv.style.left = cur + speed + 'px';
                      },20)
                  }
              }
          </script>
      
    • 缓冲来回运动封装

          <script>
              function getStyle(el, attr){
                  return el.currentStyle ? el.currentStyle[attr] : getComputedStyle(el, false)[attr];
              }
              window.onload = function(){
                  var oDiv = document.getElementById('box');
                  var aBtn = document.getElementsByTagName('button');
                  // var timer = null;
      
                  aBtn[0].onclick = function(){
                      bufferMove(oDiv, 'left', 50);
                  }
      
                  aBtn[1].onclick = function(){
                      bufferMove(oDiv, 'left', 1200);
                  }
      
                  function bufferMove(el, attr, target){
                      clearInterval(timer);//防止多次点击  定时器累加
                      timer = setInterval(function(){
                          var cur = parseInt(getStyle(el, attr)); //每次定时器执行  获取元素的当前属性的值  转换为数字
                          var speed = (target - cur)/10;  //通过公式计算速度
                          speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                          if(cur == target){
                              clearInterval(timer);
                          }
                          el.style[attr] = cur + speed + 'px';
                      },20)
                  }
              }
          </script>
      
    • 多物体缓冲运动

      • 问题: 多物体共用一个定时器,导致新的元素触发运动函数时 就将上个元素在运行的定时器给清除了,然后给自己开启同一个定时器
      • 解决每个元素对象给一个定时器
      function bufferMove(el, attr, target){
          clearInterval(el.timer);//防止多次点击  定时器累加
          el.timer = setInterval(function(){
              var cur = parseInt(getStyle(el, attr)); //每次定时器执行  获取元素的当前属性的值  转换为数字
              var speed = (target - cur)/10;  //通过公式计算速度
              speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
              if(cur == target){
                  clearInterval(el.timer);
              }
              el.style[attr] = cur + speed + 'px';
          },20)
      }
      
      
      function getStyle(el, attr){
          return el.currentStyle ? el.currentStyle[attr] : getComputedStyle(el, false)[attr];
      }
      
    • 使用多种属性(left,top,width,height,opacity)

      function bufferMove(el, attr, target){
          clearInterval(el.timer);//防止多次点击  定时器累加
          el.timer = setInterval(function(){
              if(attr == 'opacity'){
                  var cur = parseInt(getStyle(el, attr) * 100);//如果是透明度 则乘以100  从小数转换为整数方便后续计算
              }else{
                  var cur = parseInt(getStyle(el, attr));//其他属性
              }
              var speed = (target - cur) / 10;
              speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
              if(target == cur){
                  clearInterval(el.timer);
              }
              if(attr == 'opacity'){
                  el.style.opacity = (cur + speed) / 100;
                  el.style.filter = 'alpha(opacity=' + (cur + speed) + ')';
              }else{
                  el.style[attr] = cur + speed + 'px';
              }
          },20)
      }
      
      
      function getStyle(el, attr){
          return el.currentStyle ? el.currentStyle[attr] : getComputedStyle(el, false)[attr];
      }
      
    • 多属性同时运动

      • 利用对象一次性传递多个属性和目标值 键值对
      • 运动结束条件,要做大的修改:
        • 原先的终止条件时 多个属性中的某一个达到就清除了定时器,会导致有某些属性并没有到达目标值
        • 需要一值,当在变化时,赋值为true 当有存在某个属性没有到达目标值 就将该值赋值为false 知道所有属性都到达了目标值,那么 该值没有发生改变 就是初始赋值的true这时,再进行清除定时器。
      function bufferMove(el, json){
          clearInterval(el.timer);//防止多次点击  定时器累加
          el.timer = setInterval(function(){
              var flag = true;
              for(var attr in json){
                  if(attr == 'opacity'){
                      var cur = parseInt(getStyle(el, attr) * 100);//如果是透明度 则乘以100  从小数转换为整数方便后续计算
                  }else{
                      var cur = parseInt(getStyle(el, attr));//其他属性
                  }
                  var speed = (json[attr] - cur) / 10;
                  speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                  if(json[attr] != cur){
                      flag = false;
                  }
                  if(attr == 'opacity'){
                      el.style.opacity = (cur + speed) / 100;
                      el.style.filter = 'alpha(opacity=' + (cur + speed) + ')';
                  }else{
                      el.style[attr] = cur + speed + 'px';
                  }
              }
      
              if(flag){
                  clearInterval(el.timer);
              }
          },20)
      }
      
      
      function getStyle(el, attr){
          return el.currentStyle ? el.currentStyle[attr] : getComputedStyle(el, false)[attr];
      }
      
    • 链式运动

      • 先走一个属性和值 再走另一个
      • 解决方法:回调函数— 传参传递一函数,该函数在你所有的本函数所有操作执行完成之后,再被调用执行
      function bufferMove(el, json, fn){
          clearInterval(el.timer);//防止多次点击  定时器累加
          el.timer = setInterval(function(){
              var flag = true;
              for(var attr in json){
                  if(attr == 'opacity'){
                      var cur = parseInt(getStyle(el, attr) * 100);//如果是透明度 则乘以100  从小数转换为整数方便后续计算
                  }else{
                      var cur = parseInt(getStyle(el, attr));//其他属性
                  }
                  var speed = (json[attr] - cur) / 10;
                  speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                  if(json[attr] != cur){
                      flag = false;
                  }
                  if(attr == 'opacity'){
                      el.style.opacity = (cur + speed) / 100;
                      el.style.filter = 'alpha(opacity=' + (cur + speed) + ')';
                  }else{
                      el.style[attr] = cur + speed + 'px';
                  }
              }
      
              if(flag){
                  clearInterval(el.timer);
                  if(fn) fn.call(el);  //强制将函数的this对象指向参数对象
                  // 我要喊这个el元素来执行这个函数,这样这个函数就被这个el元素调用了 这时这个函数中的this就指向了el
              }
          },20)
      }
      

面向对象的编程

  • 面向对象的编程 不是一个程序,是一个编程的思维。

    • 首先我们之前的编程思想叫 面向过程的编程—在编写程序时 是按照事物发展的逻辑来进行编写
    • 面向对象的编程:四个特点
      • 抽—抽象:抽象就是将一些事物的共性和相似点抽离出来,并将这些属性归为一个类,这个类只考虑这些事物的共性和相似之处,并且会忽略与当前业务和目标无关的那些方面,只将注意力集中在与当前目标有关的方面。
      • 风—封装:封装是为了隐藏内部实现细节,是保证软件部件具有优良的模块性的基础。封装的目标就是要实现软件部件**“高内聚,低耦合”**,防止程序之间的相互依赖性带来的变动影响。
      • 机—继承:在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法(Override,重写方法)使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。
      • 多—多态:多态是运行时刻接口匹配的对象相互替换的能力。指程序定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译期并不确定,而是在程序运行期间才确定(称之为动态绑定),即一个引用变量指向的是哪个类的实例对象,在编译期间并不确定,在运行阶段才能决定,因此,这样就可以使得引用变量绑定到各种不同的类实现上,从而实现不同的行为。多态性增强了软件的灵活性和扩展性。
  • 创建对象的方式

    • 实例化对象 var obj = new Object();

    • 字面量创建 var obj = {}

    • 工厂模式创建对象

      • 工厂模式创建 创建对象的函数和创建好的对象之间是没有联系的,我们希望创建对象的函数和创建的对象之间 形成一种对象和类的关系。
          <script>
              function createPerson(name, age, sex){
                  // 先创建一个空对象  原料
                  var obj = {};
                  // 给空对象创建属性,然后将形参获取的值 赋值给该属性   加工
                  obj.name = name;
                  obj.age = age;
                  obj.sex = sex;
                  // 将创建的对象返回   出厂
                  return obj;
              }
      
              var person1 = createPerson('joth', 18, 'male');
              var person2 = createPerson('rose', 22, 'female');
              var person3 = createPerson('tom', 34, 'male');
      
              console.log(person1,person2,person3);
              //在面向对象中---创建的对象  都应该有一个共同的类  如每个人 应该属于 人类
      
              // instanceof  判断对象是够属于某个类
      
              console.log(person1 instanceof createPerson);//false
              // 我们虽然可以通过createPerson函数来批量创建人,但是我们缺少了一个人类 的类
              // 理论上 我们需要人  --》隶属于   人类
              console.log(person1 instanceof Object);//true
              // 所有js中万物皆对象  所有对象  都有一个自己的类  然后这些个类  又都属于 Object类
              var arr = [];
              var str = new String('aaa');
              console.log(arr instanceof Array);// arr属于数组类
              console.log(str instanceof String);//str属于字符串类
              console.log(arr instanceof Object);
              console.log(str instanceof Object);
      
              // arr-->属于Array类---> 属于Object类
          </script>
      
    • 构造函数创建(constructor)

      面向对象中 理论是应该由类来创建隶属于类的对象,但是js中没有类,所以我们使用构造函数来模拟类,即便到了es6中,有了Class关键字来创建类,这个类依然是由构造函数模拟的

      • 构造函数的命名 首字母就大写

      • 构造函数中不再创建空对象 也不在返回该对象 所有的属性都写给this 在定义构造函数时this对象是为空

      • 当你创建对象是 对象构造函数使用操作符 new 就可以进行对象的创建

        • new操作符的主要作用:

          ​ 1.隐式创建了一个空对象

          ​ 2.空对象的__proto__指向构造函数的原型prototype

          ​ 3.this指向了这个空对象,添加属性和方法

          ​ 4.隐式的返回该空对象

          <script>
              // 构造函数Person(类)  首字母大写就是为了和一般函数做个区别  约定俗成首字母大写的都是构造函数
              function Person(name, age, sex){
      
                  // var obj = {};
                  // 属性
                  this.name = name;
                  this.age = age;
                  this.sex = sex;
                  // 方法(函数)
                  this.eat = function(){
                      console.log('吃饭饭');
                  }
                  
                  // return obj;
              }
      
              var person1 = new Person('joth', 18, 'male');
              var person2 = new Person('rose', 22, 'female');
              console.log(person1);
      
              console.log(person1 instanceof Person);//true  某个人  属于  人类
              person1.eat();
              person2.eat();
      
              console.log(person1.eat == person2.eat);//false;
              // 两个对象中的方法不相等---》  函数本事对象  栈区存的是地址  两个函数的地址是不同的 所以不相等
              // 这个两个函数的功能一样的 如果现在创建100 人  那么就有这样功能相同的的函数100个  浪费了内存空间
              // 希望所有对象  都共用1个这样的函数
              // 原型  prototype
          </script>
      
    • 原型和原型创建对象

      • 原型prototype
        • 每个函数在声明时 都会有一个对应的原型对象,我们会将一些共用的属性和方法添加多原型对象上 来实现共享,当通过该构造函数创建对象后,对象会有一个属性叫_proto_ 来链接这个构造函数的原型对象,从而可以访问该原型对象上共享的属性和方法。
        • 如果单纯使用构造函数来创建对象那么不能有共用的属性和方法。如果单纯使用原型来创建对象 那么就没有值不同的属性 那么我们应该结合二者的特点
          <script>
              //构造函数
              function Person(){}
              // 原型对象上添加属性和方法  原型创建对象
              Person.prototype.name = 'joth';
              Person.prototype.age = 22;
              Person.prototype.sex = 'male';
              Person.prototype.eat = function(){
                  console.log('吃饭饭');
              }
      
              // 实例化对象
              var person1 = new Person();
              var person2 = new Person('rose', 22, 'female');
      
              console.log(person1.eat == person2.eat);//true 说明是使用了同一个地址指向的函数  说明该函数共用
              console.log(person1.name,person2.name);
              // 由于共用 所以 所有对象的属性都相同
              console.log(Person.prototype);
              console.log(Person.prototype.constructor);
          </script>
      
    • 混合创建

      • 将值不同的属性和方法写在构造函数中,将需要共享的属性和方法写在原型对象上
          <script>
              // 混合创建
              // 将值需要变化的属性和方法写在构造函数中
              function Person(name, age, sex){
                  this.name = name;
                  this.age = age;
                  this.sex = sex;
              }
              // 将所有对象共用的属性和方法写在构造函数的原型对象上
              Person.prototype.eat = function(){
                  console.log(this.name + '吃饭饭');
              }
      
              var person1 = new Person('joth', 18, 'male');
              var person2 = new Person('王凯辉', 22, 'male');
      
              console.log(person1.name, person2.name);
              person1.eat();
              person2.eat();
              console.log(person1 instanceof Person);//true
              console.log(person2 instanceof Person);//true
      
              console.log(person1.eat == person2.eat);//true
          </script>
      
  • 通过面向对象的方法来编写程序

    • 面向对象程序初学三部曲:

      • 1 使用面向过程来编写程序
      • 2 更改结构— onload中的所有非赋值内容提取到函数中,可以有全局变量,函数中尽量不要嵌套函数,所有程序的开始由init函数开始执行
      • 3 改写为面向对象的方式—在onload之后创建构造函数,然后所有在onload中的赋值操作就是构造函数的属性,调用函数就是调用该对象下的方法。所有的函数都是构造函数原型上的方法,修改函数中的this指向,尽量将this指向构造函数创建的对象。最后在onload中实例化对象执行
    • 面向对象改写选项卡

    • 动态混合创建对象

    • 首先判断构造函数中是否有该方法(函数) 没有 再向原型对象中添加

        <script>
            // function Person(name){
            //     this.name = name;
            //     this.eat = function(){
            //         console.log('吃肉肉');
            //     }
            // }
    
            // Person.prototype.eat = function(){
            //     console.log('吃饭饭');
            // }
    
            // var person1 = new Person('joth');
            // person1.eat();
    
            // console.log(person1);
    
            // 在构造函数下和原型上都有该该方法,当调用时 执行构造函数下的方法  原型上的该方法就是冗余
    
            // 动态创建对象(使用比较少)
            function Person(name){
                this.name = name;
                this.eat = function(){
                    console.log('吃肉肉');
                }
                // 判断有没有eat方法(方法就是函数)有就不在原型上添加  没有 就在原型上添加
                if(typeof this.eat != 'function'){
                    Person.prototype.eat = function(){
                        console.log('吃饭饭');
                    }
                }
            }
    
            var person1 = new Person('joth');
            person1.eat();
            console.log(person1);
        </script>
    
  • 命名空间

    • 当多人协作开发时,如果直接在全局定义变量时,可能会变量或函数冲突,也可能变量名函数名不够了我们就使用命名空间方式来解决。
    • 就是将你在开发时的所有的变量 函数 都写在一个对象中,以后在使用时 通过对象来调用
  • call与apply的使用

    • call和apply的作用是:改变函数中的this指向。

      • 强制将函数中的this指向这两个方法中的第一个参数
      • 区别:call(要指向的对象,参数1,参数2,。。。。) apply(要指向的对象,[参数1,参数2,。。。。])
          <script>
              function fn(a, b){
                  console.log(this, a + b);
              }
      
              fn(1,2);// window  3
      
              var obj = {
                  m: 10,
                  n: 22
              }
      
              // fn.call(obj, obj.m, obj.n);// obj 32
              fn.apply(obj,[obj.m, obj.n]);//obj 32
          </script>
      
  • 面向对象的继承

    • 原型链继承

      • 原型链:在多个构造函数的原型中 原型的__ptoto__属性链接到另一个构造函数的原型就称之为原型链 如:

        • 当创建一个arr = new Array()
        • arr._proto_ 链接到 Array.prototype 。然后 由于万物皆对象 所以 Array.prototype._proto__链接到了 Object.prototype。最后Object的原型的_proto_ 链接到了null
      • 原型链继承,就是将子类的原型上的__proto__属性指向父类的一个实例化对象,从而将父类的构造函数中的属性和方法和父类原型上的属性和方法全部继承给子类的原型

        • 问题1:所有实例化的对象中的属性的值不能被改变,因为所有的属性和方法都被继承到了Children的原型上 都变为了共享的属性和方法 改变某个实例上的方法或属性就改变了原型上该方法或属性,那么就导致所有实例化的对象的该属性或方法都发生变化
        • 问题2:子类原型的constructor不再指向子类的构造函数,而指向父类的构造函数
          • 解决方法:手动将constructor 改回来
            <script>
                // 父类  父构造函数
                function Person(name, age, sex){
                    this.name = name;
                    this.age = age;
                    this.sex = sex;
                    this.arr = [1,2,3];
                }
        
                Person.prototype.eat = function(){
                    console.log('吃饭饭');
                }
        
                // 子类  子构造函数
                function Children(){}
        
                // 原型链继承
                Children.prototype = new Person('joth', 18, 'male');
                Children.prototype.constructor = Children;//手动修改原型对应的构造函数  解决问题2
        
                // Children具有了 Person的属性
        
                var children1 = new Children();
                var children2 = new Children();
                // 问题1  所有实例化的对象中的属性的值不能被改变
                console.log(children1.name, children2.name);
                console.log(children1.arr, children2.arr);
                children1.eat();
                children2.eat();
        
                // 改变一个实例化对象中的属性和方法  就会使所有的实例对象中的该属性或方法被改变
                // 因为所有的属性和方法都被继承到了Children的原型上  都变为了共享的属性和方法
                children1.arr.push(100);
                console.log(children1.arr, children2.arr);
                console.log(Children);
                console.log(Children.prototype);
        
                // 问题2 Children的原型的constructor不指向Children了 根据你的原型链 指向  父类的构造函数
                console.log(children1 instanceof Children);true
                console.log(children1.__proto__.constructor);//Person
            </script>
        
    • 对象冒充继承

      • 在构造函数内,使用call或apply 来进行构造函数中的属性和方法的继承。
      • 问题:不能继承父类的原型上的属性和方法。
    • 组合继承

      • 对象冒充+原型链 = 组合继承
      • 将父类的构造函数的属性和方法通过对象冒充来继承给子类的构造函数,将父类的原型上的属性和方法采用原型链继承的方式继承给子类的原型
          <script>
              // 父类  父构造函数
              function Person(name, age, sex){
                  this.name = name;
                  this.age = age;
                  this.sex = sex;
                  this.arr = [1,2,3];
              }
      
              Person.prototype.eat = function(){
                  console.log('吃饭饭');
              }
      
              // 子类的组合继承
              // 将父类的构造函数的属性和方法通过对象冒充来继承给子类的构造函数,将父类的原型上的属性和方法采用原型链继承的方式继承给子类的原型
              function Children(name, age, sex){
                  Person.call(this ,name, age, sex);
              }
      
              // 原型链继承
              Children.prototype = new Person();
              // 手动修改该原型的构造函数
              Children.prototype.constructor = Children;
      
              var children1 = new Children('tom', 8, 'male');
              var children2 = new Children('lily', 12, 'female');
      
              console.log(children1.name,children2.name);
              children1.arr.push(100);
              console.log(children1.arr,children2.arr);
              children1.eat();
              children2.eat();
              // 由于我们采用了两次继承  那么在构造函数中的属性和方法被继承了2次  对象冒充时继承一次  原型链继承时又继承了一次  原型链继承时 我们没有传参  所以所有属性值都是undefined  由于构造函数中的属性比原型上的同名属性级别高  所有访问的是构造函数中的属性
              console.log(children1)
          </script>
      
    • 寄生式组合继承

      • 创建一个空构造函数做为中间宿主
          <script>
              function inherit(Parent, Child){;//parent 父类  child  子类
                  // 建立中间宿主构造函数
                  function Super(){}
                  Super.prototype = Parent.prototype;
                  // 原型链继承中间宿主构造函数
                  Child.prototype = new Super();
                  // 手动修改子类的原型的构造函数
                  Child.prototype.constructor = Child;
              }
      
             
      
              // 父类  父构造函数
              function Person(name, age, sex){
                  this.name = name;
                  this.age = age;
                  this.sex = sex;
                  this.arr = [1,2,3];
              }
      
              Person.prototype.eat = function(){
                  console.log('吃饭饭');
              }
      
              // 子类的寄生式组合继承
              // 对象冒充继承
              function Children(name, age, sex){
                  Person.call(this,name, age, sex)
              }
      
              // 封装带有中间宿主的原型链继承的函数
              inherit(Person, Children);
      
              var children1 = new Children('tom', 8, 'male');
              console.log(children1);
          </script>
      
    • 原型和原型链

      • 原型:每个函数在声明后都会有一个默认的原型对象prototype,在构造函数中,将需要共享的属性和方法创建在构造函数的原型对象上。
      • 原型链:构造函数的原型都有一个_proto__的属性,通过该属性链接到父构造函数的原型对象上,形成链式结构,最终链接到Object的原型对象,Object的原型的_proto 属性链接到null。

正则与闭包

  • 正则表达式

    • 是对字符串操作的一种逻辑公式,就是用事先定义好的一些特殊字符,及这些特定字符的组合,组成一个‘规则字符串’,这个规则字符串用来表达对字符串的一种过滤逻辑。简单的说就是规定文本检索的内容,通常被用来检索、替换文本。
    • 正则表达式的创建方法
        <script>
            // 实例化创建  new RegExp(‘检索字符/正则表达式’,’修饰符’);
            var reg = RegExp(/\d+/,'g')
    
            // 字面量创建
            var reg = /\d+/g
        </script>
    
    • 正则表达式的修饰符

      • g: global 全局(正则有个非贪婪模式 当我匹配到要检测的内容之后 就结束 后续还有没有 不再检测,如果加了g 全局 就要求检测整个字符串)
      • i: ignore 不区分大小写
          <script>
              // g  glogal 全局匹配
              var str = 'my name is joth,my age is 18,my school is csyz';
              var reg = /my/g;
              var nStr = str.replace(reg,'your');
              console.log(nStr);
      
              // i ignore  不区分大小写
              var str = 'hello Hello HELLO hEllo hello heLLo hellO';
              var reg = /hello/gi;
              var arr = str.match(reg);
              console.log(arr);
          </script>
      
    • 字符串和正则的检索方法

      • 字符串的检索方法

        • replace(要被替换的字符串或正则表达式,新字符串):根据正则替换原有字符串
        • split(分割字符串或正则表达式):根据某个字符串或正则将原字符串拆分为一个数组
        • search(正则):找到对应的字符串 返回下标 如果找不到就 返回-1 等同于 indexOf
        • match(正则):查找到匹配正则的字符串 返回数组(当非全局模式下只匹配找到的第一个字符串,形成数组中会包含关于该字符串及数组的信息,如果是全局则将所有匹配的字符串形成一个数组返回)
                var str = 'a1b2c3d4e5f6g7h8i9j';
                // 字符串检索方法
                // replace  根据正则替换原有字符串
                var reg = /\d/g;
                var nStr = str.replace(reg,'*');
                console.log(nStr);
        
                // split  根据某个字符串或正则将原字符串拆分为一个数组
                var reg = /\d/g;
                var arr = str.split(reg);
                console.log(arr);
        
                // search  找到对应的字符串 返回下标  如果找不到就 返回-1  等同于 indexOf
                var reg = /18/;
                console.log(str.search(reg));
        
                // match 查找到匹配正则的字符串  返回数组(当非全局模式下只匹配找到的第一个字符串,形成数组中会包含关于该字符串及数组的信息,如果是全局则将所有匹配的字符串形成一个数组返回)
                var reg = /\d/;
                var reg1 = /\d/g;
                console.log(str.match(reg));
                console.log(str.match(reg1));
        
      • 正则的检索方法

        • test(str):测试字符串和正则是否匹配 如果匹配返回真 不匹配返回假
        • exec(str):类似于不写修饰符g的match
            <script>
                var str = 'a1b2c3d4e5f6g7h8i9j';
                // 字符串检索方法
                // replace
                var reg = /\d/g;
                var nStr = str.replace(reg,'*');
                console.log(nStr);
        
                // split  将数字做为一个拆分的分隔符
                var reg = /\d/g;
                var arr = str.split(reg);
                console.log(arr);
        
                // search  找到对应的字符串 返回下标  如果找不到就 返回-1  等同于 indexOf
                var reg = /18/;
                console.log(str.search(reg));
        
                // match 查找到匹配正则的字符串  返回数组(当非全局模式下只匹配找到的第一个字符串,形成数组中会包含关于该字符串及数组的信息,如果是全局则将所有匹配的字符串形成一个数组返回)
                var reg = /\d/;
                var reg1 = /\d/g;
                console.log(str.match(reg));
                console.log(str.match(reg1));
        
                // 正则检索方法
                // test  测试  如果匹配返回真  不匹配返回假
                var str = 'aabbcc';
                var reg = /aabdbcc/;
                console.log(reg.test(str));
        
                // exec
                var str = 'a1b2c3d4';
                var reg = /\d/;
                var reg1 = /\d/g;
                console.log(reg.exec(str));
                
                console.log(reg1.exec(str));//1
                console.log(reg1.lastIndex);//2  下一次匹配的起始索引
                console.log(reg1.exec(str));//2
                console.log(reg1.lastIndex);//4
                console.log(reg1.exec(str));//3
                console.log(reg1.lastIndex);//6
                console.log(reg1.exec(str));//4
                console.log(reg1.lastIndex);//8
                console.log(reg1.exec(str));//null
                console.log(reg1.lastIndex);//0
            </script>
        
  • 正则对象字符

        <script>
            // . 匹配除换行符以外的任意字符
            var str = '\nas23@4de';
            var reg = /./g;
            console.log(str.match(reg));//["a", "s", "2", "3", "@", "4", "d", "e"]
    
            // []  匹配一个区间范围的字符串如:[0-9]  [0-9a-z] [0-9a-zA-Z]
            var str = '23sDr43s45wSdf345sd43rsr';
            var reg = /[0-9]/g;
            var reg1 = /[a-zA-Z]/g;
            console.log(str.match(reg));//["2", "3", "4", "3", "4", "5", "3", "4", "5", "4", "3"]
    
            // [^]  匹配非区间范围的字符串 如:[^0-9]  [^0-9a-z] [^0-9a-zA-Z]
            var str = '23srwW4lkj5#wErlkj@';
            var reg = /[^0-9a-z]/g;
            console.log(str.match(reg));//["W", "#", "E", "@"]
    
            // \d 匹配数字  等价于 [0-9]  
            var str = '23sDr43s45wSdf345sd43rsr';
            var reg = /\d/g;
            var reg1 = /[^\d]/g;
            console.log(str.match(reg));
            console.log(str.match(reg1));
            
            // \D 匹配非数字字符串 ==》 [^\d]等价于[^0-9]
            var str = '23sDr43s45wSdf345sd43rsr';
            var reg = /\D/g;
            console.log(str.match(reg));
    
            // \w 匹配数字 字母 下划线 
            var str = '132wAw_s#@3cD';
            // var str1 = 'asdflkj1sadlkfjsfd';
            // var reg1 = /\d/g;
            var reg = /\w/g;
            // console.log(reg1.test(str1));//true  只要字符串包含该类型字符 就返回真
            console.log(str.match(reg));
    
            // \W 匹配非数字 字母 下划线 
            var str = '132wAw_s#@3cD';
            var reg = /\W/g;
            console.log(str.match(reg));//["#", "@"]
    
            // \s 匹配空白字符、空格、制表符和换行符
            var str = 'aa bb cc dd';
            var reg = /\s/g;
            console.log(str.replace(reg,'*'));//aa*bb*cc*dd
    
            // \S 匹配非空白字符串
    
            
    
            // ^以什么开始   $以什么结尾
            var str = '5671346575672341238aaa';
            var str2 = '123454563453468323458'
            var reg = /^1\d+8$/
            console.log(reg.test(str));//false  包含1开头8结尾的数字字符串  要求时必须用1 开头 用8 结束
            console.log(reg.test(str2));//true
    
            // \b  匹配单词边界
            var str = 'this is his apple';
            var reg = /\bis\b/g;
            console.log(str.replace(reg,'IS'));
    
            // \B  匹配非单词边界
            var str = 'this is his apple';
            var reg = /\Bis\b/g;
            console.log(str.replace(reg,'IS'));
    
    
            // ?  匹配0个或1个
            var str = '123123123';
            var str1 = 's123123123';
            var str2 = 'asdf123123123';
            var reg = /^[a-z]?\d+$/;
            console.log(reg.test(str));//true
            console.log(reg.test(str1));//true
            console.log(reg.test(str2));//false
    
    
            // *  匹配0个或多个
            var str = '123123123';
            var str1 = 's123123123';
            var str2 = 'asdf123123123';
            var reg = /^[a-z]*\d+$/;
            console.log(reg.test(str));//true
            console.log(reg.test(str1));//true
            console.log(reg.test(str2));//true
    
            // +  连续匹配一个或多个
            var str = '23sDr43s45w7Sdf345sd43rsr';
            var reg = /\d/g;
            var reg1 = /\d+/g;
            console.log(str.match(reg));
            console.log(str.match(reg1));
    
            // (a|b|c)  分组匹配  就在分组中的任意一个  | 代表或
            var str = 'a123123123';
            var str1 = 'z123123123';
            var reg = /^(a|b|c)\d+$/;
            console.log(reg.test(str));
            console.log(reg.test(str1));
    
            // (abc)+
            var str = 'abc12313123';
            var str1 = 'abcabcabc12312123';
            var reg = /^(abc)+\d+$/
            console.log(reg.test(str));
            console.log(reg.test(str1));
    
            // {}  个数取值范围  {0,1}匹配0次或1次  {m,n}匹配m次到n次  {n} 必须匹配n次
            var str = 'aa1111';
            var str1 = 'aaa1';
            var str2 = 'aaaa123123'
            var str3 = 'a123123'
            var reg = /^a{2,4}\d+$/;
            console.log(reg.test(str));
            console.log(reg.test(str1));
            console.log(reg.test(str2));
            console.log(reg.test(str3));
    
            // 注册  判断 手机号码是否符合规则  邮箱是否符合规则
            
        </script>
    
    
        <script>
            // 分组  $1 $2....自动对每个分组进行了编号
            var str = '07-31-2020';
            var reg = /^(\d\d)-(\d\d)-(\d\d\d\d)$/;
            console.log(reg.exec(str));
            console.log(RegExp.$1,RegExp.$2,RegExp.$3);
            console.log(str.replace(reg,'$3年$1月$2日'));
    
            // 座机号码 正则表达式 区号-电话号
    
            // 前瞻后顾
            // 正向预肯定查找  ?=   匹配后边确定的内容之前的字符串(后边是什么的字符串被匹配)
            var path1 = 'path/hello.html';
            var path2 = 'path/nodata.html';
            var path3 = 'path/index.html';
    
            var reg = /\w+(?=\.html$)/
            console.log(path1.match(reg));
            console.log(path2.match(reg));
            console.log(path3.match(reg));
    
            var str = '中国人';
            var str1 = '美国佬';
            var str2 = '日本人';
    
            var reg = /.+(?=人$)/;
            console.log(str.replace(reg,'亚洲'));
            console.log(str1.replace(reg,'亚洲'));
            console.log(str2.replace(reg,'亚洲'));
    
    
            // 反向预肯定查找  ?<=  匹配前边确定的内容之后的字符串   (前边是什么的  字符串被匹配)
            var path1 = 'path/hello.html';
            var path2 = 'path/nodata.html';
            var path3 = 'path/index.html';
    
            var reg = /(?<=path\/)\w+/
            console.log(path1.match(reg));
            console.log(path2.match(reg));
            console.log(path3.match(reg));
    
            var str = '中国人';
            var str1 = '美国佬';
            var str2 = '日本人';
    
            var reg = /(?<=日本).+/
            console.log(str1.replace(reg,'鬼子'));
            console.log(str2.replace(reg,'鬼子'));
    
            // 正向预否定查找  ?!  匹配后边不是确定的内容之前的字符串  (后边不是什么的字符被匹配)
            var str = 'a,1,b,2,c,3,'   //  a=1=b=2=c=3  
            // 把字符串改成 a=1,b=2,c=3,
            var reg = /,(?![a-z]|$)/g;// 匹配逗号  后边是非字母或是没有字符的这样的,
            console.log(str.replace(reg,'='));
    
            var str = 'abc';
            var str1 = 'abb9';
            var str2 = 'abcd';
    
            var reg = /.+(?![a-z]|$)/;
            console.log(str.replace(reg,'欧美'));
            console.log(str1.replace(reg,'欧美'));
            console.log(str2.replace(reg,'欧美'));
    
            // 反向预否定查找  ?
            var str = 'a,1,b,2,c,3,'  
            var reg = /(?<!\d),/g//匹配逗号   前边不是数字的逗号
            console.log(str.replace(reg,'='));
        </script>
    
  • 匿名函数

    • 函数分类:

      • 事件驱动的处理函数
      • 普通函数 function aa(){}
      • 表达式定义函数 var aa = function(){}
        • 普通函数可以先调用后声明,表达式定义函数只能先声明再调用 为什么?
      • 构造函数
      • 匿名函数及匿名函数的自执行
        • 当遇到某个函数在整个程序中只需要执行一次时 将其定义为一个匿名函数自执行。不会造成全局变量的污染
        • (匿名函数)() 在使用匿名函数的自执行时 最好在开始时打一个; 保证和上边代码分隔
          <script>
              // 当你直接定义一个没有名字的函数时 提示错误了  而且也无法调用执行
              // function(){
              //     console.log('匿名');
              // }
              //匿名函数的自执行  (匿名函数)()
              // (function(){
              //     console.log('匿名');
              // })()
      
              function fn(){
                  console.log('fn');
              }
              console.log(fn)
              fn()
              
              ;(function(){
                  console.log('匿名');
              })()
      
      
              
      
              // fn()()();
      
              // ;(function fn(){
              //     console.log('fn');
              // })()
      
              // function fn(){
              //     return function(){
              //         return function(){
              //             console.log('123');
              //         }
              //     }
              // }
      
              // fn()()();
      
      
      		// 匿名函数的传参
              var result = (function(a){
                  return a * a;
              })(15)
      
              console.log(result);
          </script>
      
  • 闭包

    • 什么是闭包:可以读取其他函数内部的变量的函数(函数套函数,子函数可以访问父函数中的内部变量) 本质上闭包就是将内部函数和外部函数链接起来的桥梁。

      • 优点:防止全局变量污染
      • 缺点:内存泄漏— 当子函数一直需要使用父函数中的变量时 会造成父函数的垃圾回收没有被执行,一直会占用内存
         <script>
             // function fnn(){
             //     console.log(a);
             // }
      
             // window.onload = function(){
             //     var a = 10;
      
             //     function fn(){
             //         console.log(a)
             //     }
             // }
      
             function a(){
                 var aaa = 100;
                 console.log(aaa);
             }
      
             a();
             // 因为返回的内层函数  要用到父级函数中的变量a  所以导致 父级函数执行完成后  里边变量a 不能被系统做垃圾回收  他会一直存在  需要手动回收
             function fn(){
                 var a = 10;
                 return function(b){
                     console.log(a + b)
                 }
             }
      
             var fnn = fn();
      
             fnn(8);
             fnn(24);
         </script>
      
    • 闭包模拟私有属性

      • 在js中构造函数中 this.属性 就是公有属性 var 声明的属性 就是私有属性
      • 访问和修改私有属性 需要 设置接口 就是返回两个函数 一个set 一个get
          <script>
              // public 公有  private  私有
              function Person(name){
                  this.name = name;   //公有
                  var money = 500;  //私有
      
                  // 设置私有属性的接口
                  return {
                      name: this.name,
                      get:function(){
                          return money;
                      },
                      set:function(cash){
                          money += cash;
                      }
                  }
              }
      
              var person1 = new Person('joth');
              console.log(person1.name);
      
              console.log(person1.get());//通过接口访问和修改私有属性
              person1.set(500);
              console.log(person1.get());
          </script>
      

      ajax

  • json数据和对象的区别:json 是一种轻量级的数据交换格式。具有对象结构的字符串数据,在json中所有的键和字符串的值 都要用双引号包裹

  • get和post:

    • get:数据传输量比较小1M 所有数据参数都是直接显示在url中传输,有缓存,安全性较差。get一般用来从服务器获取数据。
    • post:数据传输量理论无限大,实际根据不同的浏览器有 不同的限制,所有的数据参数都在消息中传输,没有缓存,相对比较安全。一般用来向服务器发送数据。
  • ajax的步骤

    • 创建ajax对象
    • 通过open设置和服务器交互的信息(连接服务器的设置)
    • 通过send发送数据开始和服务器交互
    • 注册事件
    • 更新界面(渲染数据)
    //get
    window.onload = function(){
                var oDiv = document.getElementsByTagName('div')[0];
    
                // get方式
                // 创建ajax对象
                var oAjax = new XMLHttpRequest(); // ie6 不支持该对象   ie6下 var oAjax = ActiveXObject('Microsoft.XMLHTTP');
                // 服务器连接设置
                oAjax.open('GET','./mytxt.txt',true);  //最后一个参数  async:是否为异步操作  默认为true  异步  如果设置为false  则为同步
                // get 方式  如果有数据需要发送  那么  我们需要将url地址变为url?page=1&fl=1
                // 发送数据开始和服务器交互
                oAjax.send();
    
                oAjax.onreadystatechange = function(){//注册ajax事件  当ajax的状态发生变化
                    // console.log(oAjax.readyState);//  2  3  4
                    if(oAjax.readyState == 4){//  当状态变为4  表白 整个ajax已经和服务器完成了交互
                        if(oAjax.status == 200){//200代表访问成功并回传了对应的数据  404 找不到  http 状态码
                            oDiv.innerHTML = oAjax.responseText;//将获取到的服务器返回的数据(数据类型为字符串)显示到div中
                        }else{
                            alert('Error:' + oAjax.status);// 提示错误状态码
                        }
                    }
                }
            }
    
    //post
    
    window.onload = function(){
                var oDiv = document.getElementsByTagName('div')[0];
    
                // post方式
                // 创建ajax对象
                var oAjax = new XMLHttpRequest(); // ie6 不支持该对象   ie6下 var oAjax = ActiveXObject('Microsoft.XMLHTTP');
                // 服务器连接设置
                oAjax.open('post','./mytxt.txt',true);  //最后一个参数  async:是否为异步操作  默认为true  异步  如果设置为false  则为同步
                // 发送数据开始和服务器交互
                oAjax.setRequestHeader('Content-type','appliction/x-www-form-urlencoded');//请求头数据类型的设置
                oAjax.send();
                // post如果要发送数据  则是在 send中来发送 如  oAjax.send('user=aaa&pass=123123')
    
                oAjax.onreadystatechange = function(){//注册ajax事件  当ajax的状态发生变化
                    // console.log(oAjax.readyState);//  2  3  4
                    if(oAjax.readyState == 4){//  当状态变为4  表白 整个ajax已经和服务器完成了交互
                        if(oAjax.status == 200){//200代表访问成功并回传了对应的数据  404 找不到  http 状态码
                            oDiv.innerHTML = oAjax.responseText;//将获取到的服务器返回的数据(数据类型为字符串)显示到div中
                        }else{
                            alert('Error:' + oAjax.status);// 提示错误状态码
                        }
                    }
                }
            }
    
  • eval和JSON.parse/JSON.stringify

    • eval(‘具有js格式的字符串’):将具有js格式(包括函数,数组等,不包含Json格式) 的字符串转换为js来使用或执行
    • JSON.parse(‘具有js数据类型,如数组,对象,json的字符串’):将具有js数据类型的字符串转换为js的数据,不支持js代码
    • JSON.stringify (对象,数组等数据类型):将js的数据如对象 数组,转换为字符串形式。是JSON.parse 的反向操作。
    • 一般我们需要将文本类型的数据 解析为数组或对象时 都采用JSON.parse而不用eval
        <script>
            // var str = 'function aa(){console.log("aaa")};aa();';
            // eval(str);//将字符串转换为js代码
            // /* 
            //     function aa(){
            //         console.log('aaa');
            //     };
            //     aa();
            // */
    
            // var str1 = '["a","b","c","d"]';
            // var json = '{"name":"joth","age":18,"sex":"male"}';
            // console.log(str1.length);
            // var arr = eval(str1);
            // console.log(arr, arr.length);
            // console.log(eval(json));//json  eval不支持
    
    
            //JSON.parse
            // var str = 'function aa(){console.log("aaa")};aa();';
            // var str1 = '["a","b","c","d"]';
            // var json = '{"name":"joth","age":18,"sex":"male"}';
    
            // // console.log(JSON.parse(str));//JSON.parse 不支持js代码字符串  必须是某种数据
            // console.log(JSON.parse(str1));
            // console.log(JSON.parse(json));//json格式转换为对象
    
            //JSON.stringify
            var obj = {
                name: 'joth',
                age: 18,
                sex: 'male'
            }
            var arr = ['a','b','c'];
    
            console.log(JSON.stringify(obj));
            console.log(JSON.stringify(arr));
        </script>
    
  • artTemplate

    • 模板的构建 采用
    • 所有要显示的数据 都采用{{键名}}的方式来进行绑定
    • 如果需要进行判断操作 {{if 需要判断的键名}} 。。。。。{{else}}。。。。{{/if}}
    • 如果需要遍历数据来进行渲染
      • {{each 需要遍历的键名 item数据项 i 数据的下标}} …{{/each}}
    • 在你的主体的js代码中 进行 模板和数据的绑定 var html = template(‘模板的id’,数据名)
      • 当绑定执行时 就已经生成了完整的html代码
    • 最后将 绑定好的结果渲染到 页面的元素中
        <script src="./template-web.js"></script>
        <!-- 建立模板   id的作用是最后将模板和数据关联起来-->
        <script type="text/html" id="temp">
            <h4>{{title}}</h4>
            {{if count}}
            <ul>
                {{each list item i}}
                <li>{{i}}----{{item}}</li>
                {{/each}}
            </ul>
            一共保存有<span>{{count}}</span>本书。
            {{else}}
            <span>当前没有数据</span>
            {{/if}}
        </script>
        <script>
            window.onload = function(){
                var oDiv = document.getElementById('box');
    
                var data = {
                    title: '世界名著书目',
                    list: ['西游记','三个火枪手','茶花女','巴黎圣母院','挪威森林','三体']
                }
                // 给data对象添加属性 count  值为  list的长度
                data.count = data.list.length;
                var html = template('temp',data);
                oDiv.innerHTML = html;
            }
        </script>
    

Touch

  • touch的基本事件

    • ontouchstart 触碰开始(手指按到了屏幕上)

    • ontouchmove 开始移动(手指在屏幕上滑动)

    • ontouchend 触碰结束(手指离开)

          <script>
              window.onload = function(){
                  var oDiv = document.getElementById('box');
      
                  oDiv.addEventListener('touchstart',function(){
                      console.log('手指按下');
                  })
      
                  oDiv.addEventListener('touchmove',function(){
                      console.log('手指滑动');
                  })
      
                  oDiv.addEventListener('touchend',function(){
                      console.log('手指离开')
                  })
              }
          </script>
      
    • touch事件必须使用addEventListener

          <script>
              window.onload = function(){
                  var oDiv = document.getElementById('box');
      
                  oDiv.addEventListener('touchstart',function(){
                      console.log('手指按下');
                  })
      
                  oDiv.onmousedown = function(){
                      console.log('鼠标按下');
                  }
              }
          </script>
      
    • pc端事件比移动端慢300ms

    • 点透问题

      • 由于pc端事件比移动端慢300ms 当点击上层元素消失后 点击事件就传到下层元素上
      • 解决:下层不要放有点击特效的元素
          <script>
              window.onload = function(){
                  var oDiv = document.getElementById('box');
      
                  oDiv.addEventListener('touchstart',function(){
                      this.style.display = 'none';
                  })
              }
          </script>
      
  • touch事件对象

    • 记录手指列表
      • ev.touches: 在当前移动端上的所有手指
      • ev.targetTouches:在当前要控制的元素上的所有手指列表
      • ev.changedTouches:在当前元素上进行触碰事件的手指列表(一般用这个)
    • 手指事件对象下的属性
      • clientX/clientY 手指按下后在 可视区的相对位置
      • pageX/pageY 手指按下后在 页面文档中的相对位置
      • screenX/screenY 手指按下后在 屏幕中的相对位置
      • radiusX: 旋转半径
      • radiusY: 旋转半径
      • rotationAngle: 旋转角度
      • identifier:标识符
        <script>
            window.onload = function(){
                var oDiv = document.getElementById('box');
    
                oDiv.addEventListener('touchstart',function(ev){
                    console.log(ev);
                    var touch = ev.changedTouches[0];//当前手指列表中的第一个指头
    
                    console.log(touch);
                })
            }
        </script>
    
  • DOMContentLoaded

    • 该事件和window的onload事件是近亲,但是区别是:
      • onload事件是要将页面上的所有文档结构及资源(图片,视频等)全部加载完成后执行内部的js代码
      • DOMContentLoaded事件是只需要文档结构加载完毕,不需要等待资源加载完成就可以执行内部的js代码
      • 所以DOMContentLoaded 比onload 要先执行
    //rem计算js
    ;(function(doc, win){
        var docEl = doc.documentElement,//根元素 html
            //orientationchange事件在设备的纵横方向改变时触发
            resizeEv = 'orientationchange' in win ? 'orientationchange' : 'resize',//设备尺寸发生变化
            dW = 750,//设计稿宽度---改  你的设计稿是多少 这就写多少
            reCalc = function(){
                var clinetW = docEl.clientWidth;//设备可视区的宽
                if(!clinetW) return;
                if(clinetW >= dW){
                    // 当设备可视区宽大于了设计稿的宽
                    docEl.style.fontSize = '100px';
                    docEl.style.width = dW + 'px';//将设计稿的宽给到 html
                    docEl.style.margin = '0 auto';//居中
                }else{
                    docEl.style.fontSize = 100 * (clinetW / dW) + 'px';
                }
            }
    
        if(!doc.addEventListener) return;//如果文档不支持事件绑定  就不支持就返回不执行
        win.addEventListener(resizeEv, reCalc, false);
        doc.addEventListener('DOMContentLoaded', reCalc, false);//页面结构加载完成后执行reCalc函数
    })(document, window)
    // 使用方法  用设计稿的元素的宽/100;
    
  • Touch.js

    • webkit内核浏览器专用

    • 语法:touch.on(元素(元素对象或 字符串选择器),事件,事件处理函数)

    • 事件:

      • tap : 手指单击
      • doubletap:手指双击
      • hold: 手指长按
      • pinch:缩放(2个手指)
      • rotate:旋转
      • swipe:滑动
      • drag:拖拽
          <script>
              window.onload = function(){
                  var oDiv = document.getElementById('box');
                  touch.on(oDiv, 'tap', function(){
                      console.log('我被单击了');
                  })
      
                  touch.on(oDiv, 'doubletap', function(){
                      console.log('我被双击了');
                  })
      
                  touch.on(oDiv, 'hold', function(){
                      console.log('我被压了500年');
                  })
              }
          </script>
      
    • touchJs事件委托

      • 语法:touch.on(父元素(元素对象或 字符串选择器),事件,目标元素(字符串选择器),事件处理函数)

            <script>
                window.onload = function(){
                    var oList = document.getElementById('list');
        
                    touch.on(oList,'tap','li',function(){
                        console.log(this.innerHTML);
                    })
                }
            </script>
        
  • touch事件对象

    • ev.originEvent:原生touch事件
    • ev.type:事件名称
    • ev.fingersCount:操作的手指头数
    • ev.position:事件在文档中的相对位置,不同事件可能产生的位置不同
    • ev.rotation:旋转角度
    • ev.scale:缩放比例—pinch事件
    • ev.direction:向上滑 向左滑—swipe事件
    • ev.distance:两点间的位移(滑动距离)—swipe事件
    • ev.distanceX:X轴上的滑动距离—swipe事件
    • ev.distanceY:Y轴上的滑动距离—swipe事件
    • ev.angle:rotate事件触发的旋转的角度----rotate事件
    • ev.duration:touchstart 与 touchend 之间的时间戳(按了多久)

jQuery基础

  • jq是一个js库,是极大简化了原生js开发(操作dom,遍历元素,ajax,动画–运动框架)

    • jq是一个库 目前开发架构 M module数据层 V view视图层 C controller控制层
  • jQuery 与 $ 的关系:$是jQuery的简写

  • onload和ready的区别

    • 1-onload事件时指文档结构和资源全部加载完毕后再执行onload中的js代码,而ready只需要文档结构加载完毕,就可以执行。跟接近DOMContentLoaded事件。
    • 2- onload函数一个页面只能有1个,后写的会覆盖先写的,ready可以存在多个
    • 3-$(document).ready(function(){})有个简写 $(function(){})
        <script>
            // 原生使用onload  文档结构和资源
            // window.onload = function(){
            //     console.log($('#box'));
            // }
            // window.onload = function(){
    
            // }
            //jq使用  ready  文档结构
            // $(document).reday(function(){//  当做window.onload来使用 但实际上它的等待加载 类似 DOMContentLoaded
    
            // })
            // // 简写 
            // $(function(){
    
            // })
    
            // 可以重复多个
    
            // window.onload = function(){
            //     var oDiv = document.getElementById('box');
            //     console.log(oDiv);
            // }
    
            window.onload = function(){
                var oDiv = document.getElementById('abox');
                console.log(oDiv);
            }
    
            $(document).ready(function(){
                console.log($('#box'));
            })
    
            $(function(){
                console.log($('#abox'));
            })
        </script>
    
  • jq中获取的元素 不再是DOM。原生方式获取的元素为DOM 而jq中 获取到的DOM被jq进行包装形成一个jq对象。

    • jq中:init [div#abox, context: document, selector: “#abox”]
    • 原生:
    • 原生的DOM–原生js使用和jq对象–jq使用的互相转换
      • 原生DOM–》jq对象 直接用$包裹 $(oDiv)
      • jq对象–》原生DOM 获取第下标个 $(’#box’)[0] $(’#box’).get(0)
  • $的权限让出

    • jQuery.noConflict()
        <script>
            $(function(){
                jQuery.noConflict();//让出$使用权
                $('欢迎光临!');//aaa.js
                // jQuery('#box').html('我的零食店!');//$被让出,那么我们可以使用jQuery来继续操作jq代码
                // 如果让出之后,我还是希望使用$来继续操作jq  那么需要做一个闭包
    
                ;(function($){//将jq的jQuery  传给匿名函数的形参$  这时在该匿名函数中$又代表 jQuery
                    $('#box').html('我的零食店!')
                })(jQuery)
            })
        </script>
    
  • jq选择器— css中怎么写 这就怎么写

    • 基本选择器
      • #box id选择器 .div类选择器 div标签选择器 ul,ol,li多个选择
    • 层次选择器
    • 过滤选择器—基本过滤选择器 属性过滤选择器
        <script>
            $(function(){
                // 层次选择器
                console.log($('ul li'));//ul下的所有li  包含ol下的li
                console.log($('ul>li'));//第一层级(子级)下的li  不包含ol下的li  ol下的li 叫  后代
                console.log($('#lili+li'));//id为lili的下一个兄弟
                console.log($('#lili~li'));//id为lili下的所有的兄弟
    
                // 过滤选择器
                // 基本过滤选择器
                console.log($('li:first'));//li的第一个
                console.log($('li:last'));//li最后一个
                console.log($('li:not(.li1)'));//选择所有不带class为li1的li  包含后代
                console.log($('li:odd'));//选择所有下标奇数li  下标是从0开始  0被算作偶数
                console.log($('li:even'));//选择所有下标偶数li  下标是从0开始  0被算作偶数
                console.log($('li:eq(8)'));//选择下标为5的li
                console.log($('li:gt(8)'));//选择下标大于8的li
                console.log($('li:lt(8)'));//选择下标小于8的li
    
                // 属性过滤选择器
                console.log($('li[name]'));//选择有name属性的li  无论属性的值是什么
                console.log($('li[name=joth]'));//选择name属性的值是某个固定值的li
                console.log($('li[name!=joth]'));//选择name属性值不等于joth的li  没有name属性的也被包含了
                console.log($('li[name^=j]'));//选择name属性的值以j开头的li
                console.log($('li[name$=e]'));//选择name属性的值以e结尾的li
                console.log($('li[name*=o]'));//选择name属性的值包含o的li
            })
        </script>
    
    • 表单选择器

          <script>
              $(function(){
                  // 表单选择器
                  console.log($('input'));//input标签
                  console.log($(':input'));//基本上就是所有表单元素
                  console.log($(':checked'));//选择被选中的表单元素  checkbox  radio  select
                  // 按表单类型选择
                  console.log($(':text'));//选择所有type为text的文本框
                  console.log($(':password'));//类型为密码的文本框
                  console.log($(':checkbox'));//选择所有的多选框
                  console.log($('textarea'));// 文本域标签
                  console.log($(':submit'));//为提交按钮的表单元素
              })
          </script>
      
  • 节点遍历操作

    • 获取子元素:

      • $(‘父元素’).children() —获取该父元素下的所有子元素 不包含后代节点
      • $(‘父元素选择器’).children(‘子选择器’) —获取该父元素下的所有符合子元素选择器的子元素
    • 获取兄弟节点

      • $(’.div1’).prev() $(’.div1’).prevAll() $(’.div1’).next() $(’.div1’).nextAll() $(’.div1’).siblings() $(’.div1’).siblings(‘选择器’)
    • 获取父节点

      • console.log($(’#link’).parent());//获取该元素的父节点
      • console.log($(’#link’).parents());//获取该元素的所有祖先节点
      • console.log($(’#link’).parents(‘div’));//获取该元素的祖先节点中的div
          <script>
              $(function(){
                  // 子节点
                  console.log($('#box').children());
                  console.log($('#box').children('span'));
      
                  // 兄弟节点
                  console.log($('.div1').prev());//该元素的上一个兄弟节点
                  console.log($('.div1').prevAll());//该元素的之前的所有兄弟节点
      
                  console.log($('.div1').next());//该元素的下一个兄弟节点
                  console.log($('.div1').nextAll());//该元素的之后的所有兄弟节点
      
                  console.log($('.div1').siblings());//该元素的所有兄弟节点
                  console.log($('.div1').siblings('p'));//该元素的所有p兄弟节点
      
                  // 获取父节点
                  console.log($('#link').parent());//获取该元素的父节点
                  console.log($('#link').parents());//获取该元素的所有祖先节点
                  console.log($('#link').parents('div'));//获取该元素的祖先节点中的div
      
                  
              })
          </script>
      
    • 过滤节点

      • find 查找后代节点
      • filter 通过选择器 过滤找到某个节点
      • not 将某个指定选择器的节点过滤掉 将剩余的节点返回
          <script>
              $(function(){
                  console.log($('ul').find('span'));
                  console.log($('li').filter('.li1'));//过滤选取
                  console.log($('li').filter('.aaa'));
                  console.log($('li').not('.li1'));//过滤排除
              })
          </script>
      
  • jq属性操作

    • 原生 setAttribute getAttribute removeAttribute
    • jq中获取和设置 一般都是一个方法 区别在于当该方法中的参数1个 就基本上为获取 两个就基本上为设置(对象参数要另说)
    • jq 获取:attr(‘属性名’) 设置:attr(‘属性名’,‘属性值’) 对象设置:attr({属性名1:属性值1,属性名2:属性值2,。。。}) 删除属性 removeAttr(‘属性名’)
    • 对于表单元素中的checkbox radio select等被选中的属性来说 也就是:
      • 单一属性名 就可以起作用的属性
      • 属性值为true/false的属性
      • 不再使用attr来获取和设置 而使用 prop() 来进行操纵 移除 removeProp()
        <script>
            $(function(){
                // 获取属性值
                console.log($('#box').attr('title'));
                // 设置
                $('#box').attr('title','bbbbox');
                // 对象参数设置
                $('#box').attr({name:'joth',age:18,sex:'male'});
                // 删除属性
                $('#box').removeAttr('title');
    
    
                // 表单元素checkbox的checkd属性
                // console.log($(':checkbox').attr('checked'));
                // 获取
                console.log($(':checkbox').prop('checked'));//false
    
                // 设置
                $(':checkbox').prop('checked',true);
    
            })
        </script>
    
  • jq操作class

    • addClass 是添加类(在当前已有类的基础上追加)
    • removeClass 移出样式
    • hasClass 判断是否有该class 有返回true 没有 返回flas
    • is() 等同于 hasClass
    • toggleClass 切换类 有就删除 没有就添加
        </style>
        <!-- <script>
            window.onload = function(){
                var oDiv = document.getElementById('box');
                var oBtn = document.getElementsByTagName('button')[0];
                var flag = true;
    
                oBtn.onclick = function(){
                    if(flag){
                        oDiv.className = 'blue';
                    }else{
                        oDiv.className = 'red';
                    }
                    flag = !flag;
                }
            }
        </script> -->
        <script src="./jquery.min.js"></script>
        <script>
            $(function(){
                $('button').click(function(){
                    if($('#box').hasClass('red')){
                        $('#box').removeClass('red').addClass('blue');
                    }else{
                        $('#box').removeClass('blue').addClass('red');
                    }
                })
            })
    
            
        </script>
    
        <script>
            $(function(){
                $('button').click(function(){
                    $('#box').toggleClass('blue');
                })
            })
        </script>
    
        <script>
            $(function(){
                console.log($('#box').hasClass('one'));
                console.log($('#box').is('one'));
    
                $('#box').addClass('one');
                $('#box').addClass('tow');
    
                $('#box').removeClass('on');
            })
        </script>
    
  • jq操作样式

    • 获取样式:获取非行间样式
      • $(‘选择器’).css(‘样式属性名’)
    • 设置样式:设置行间样式
      • $(‘选择器’).css(‘样式属性名’,‘样式属性值’)
      • $(‘选择器’).css({属性名1:属性值1,属性名2:属性值2.。。。})
        • width:100 或 width:‘100px’ 都可以
        <script>
            $(function(){
                //  获取样式
                console.log($('#box').css('width'));//'100px'
                // 设置
                $('#box').css('border','10px solid #000');
                // 对象设置
                $('#box2').css({width:100,height:'100px',background:'blue'});
            })
        </script>
    
  • html 文本及值的相关操作

    • 原生的获取元素和表单内容
      • innerHTML innerText 表单 value
      • jq html() text() val()
        <script>
            $(function(){
                // 获取内容
                console.log($('#box').html());
                console.log($('#box').text());
                console.log($(':text').val());
    
                // 设置内容
                $('#box').html('奔流到海不复回');
                // $('#box').text('奔流到海不复回');
                $(':text').val('妙哉!妙哉!');
                
            })
        </script>
    
  • $下的常用方法

    • $.each(对象或数组,function(index/key, item/value){})没有返回值 等价于原生的forEach
    • $.map(对象1.6+数组,function(item/value,index/key){return}) 形参先是数据或值 后是下标或键 必须有return 新对象或新数组 等价于原生的map
        <script>
            var arr = ['a','b','c','d','e'];
            $.each(arr,function(i,item){
                console.log(i + '---' + item.toUpperCase());
            })
    
            var nArr = $.map(arr,function(item, i){
                return item.toUpperCase();
            })
            console.log(nArr);
    
            var obj = {
                name:'joth',
                age:'eighteen',
                sex:'male'
            }
    
            $.each(obj,function(key,value){
                console.log(key + '---' + value.toUpperCase());
            })
        </script>
    
    • 深拷贝和浅拷贝

      • 深浅拷贝主要针对于引用类型来说的,当赋值引用类型时 会直接进行传址,导致多个变量指向同一地址 共享使用,当某个对象修改了内容会导致所有对象都使用修改后的数据这就是浅拷贝。如果要深拷贝,需要将每一项数据都进行克隆拷贝到一个新对象中。

                function deepClone(obj){
                    // 判断是不是array  创建的对象 就不同 []  {}
                    var cloneObj = Array.isArray(obj) ? [] : {};
                    if(obj && typeof obj == 'object'){//参数存在 且参数类型为object
                        for(var key in obj){//进行循环
                            if(obj.hasOwnProperty(key)){//如果当前要进行遍历的 属性是对象的构造函数创建的属性则返回true  继续向下进行  不是则返回false就不进行下边的复制操作了
                                if(obj[key] && typeof obj[key] == 'object'){//如果obj的某个属性又是对象
                                    cloneObj[key] = deepClone(obj[key]);// 递归调用复制函数继续进行forin的循环赋值  如果在循环中再次出现对象属性  继续递归调用 直到所有的属性都是基本类型时
                                }else{
                                    // 如果属性值为基本类型  则直接 复制
                                    cloneObj[key] = obj[key];
                                }
                            }
                        }
                    }
                    return cloneObj;
                }
        
    • $.extend()

      • $.extend(obj,obj1,obj2,obj3) 将obj1-3对象中的内容 全部复制给 obj 改变了原本的obj
      • $.extend({},obj,obj1,obj2,obj3)假设不想改变obj 希望返回一个新对象 将obj -obj3的内容全部复制给 该新的空对象 并且将该对象返回
      • $.extend(true,{},obj) 深拷贝
         <script>
             var obj = {
                 a:10
             }
      
             var obj1 = {
                 b : 20
             }
      
             var obj2 = {
                 c: 30
             }
      
             var obj3 = {
                 d:40
             }
      
             // $.extend(obj,obj1,obj2,obj3);
             // console.log(obj);
      
             var objAll = $.extend({},obj,obj1,obj2,obj3);
             console.log(obj, objAll)
      
             
             var obj = {
                 name:'joth',
                 age:18,
                 sex:'male',
                 body:{
                     weight:'65kg',
                     height:'174cm',
                     eyes:{
                         left:'1.0',
                         right:'1.2'
                     }
                 },
                 eat:function(){
                     console.log('吃饭饭');
                 }
             }
             // jq的浅拷贝
             // var nObj = $.extend({},obj);
             // obj.body.eyes.right = '1.0';
             // console.log(obj, nObj)
      
             // jq的深拷贝
             var nObj = $.extend(true,{},obj);
             obj.body.eyes.right = '1.0';
             console.log(obj, nObj)
         </script>
      

      jQuery 进阶

  • BOM 操作

    • 元素的宽高

      • 原生元素的宽高

        • 元素.style.width/元素.style.height 行间样式
        • 非行间元素的宽高 getComputedStyle currentStyle
        • 元素 占位宽高 offsetWidth/offsetHeight width + 左右padding+ 左右border
        • 元素 可视宽高 clientWidth/clientHeight width + 左右padding
        • 浏览器可视区宽高:doucment.doucmentElement.clientWidth/clinetHeight
        • 文档宽高: document.body.offsetWidth/offsetHeight
      • jq中元素的宽高获取和设置

        • 内容宽高: width()/height()
        • 可视宽高:innerWidth()/innerHeight()
        • 占位宽高:outerWidth()/outerHeight()
        • 整个宽高 :outerWidth(true)/outerHeight(true)
        • 浏览器可视区宽高:$(window).height()
        • 文档宽高: $(document).height()
            <script>
                $(function(){
                    // 内容宽
                    console.log($('#box').width());//100
                    // 可视宽
                    console.log($('#box').innerWidth());//160
                    // 占位宽
                    console.log($('#box').outerWidth());//180
                    // 整个宽   width+ padding+ border+ margin
                    console.log($('#box').outerWidth(true));//280
        
                    // 设置宽高
                    // $('#div1').width(100).height(100);
                    $('#div1').innerWidth(100).innerHeight(100);
                    $('#div1').outerWidth(100).outerHeight(100);
                    $('#div1').outerWidth(100,true).outerHeight(100,true);
        
                    // 浏览器可视区的宽高
                    console.log($(window).height());
        
                    // 文档的宽高
                    console.log($(document).height());
                    
                })
            </script>
        
    • 元素的位置

      • 原生的元素位置
        • offsetTop、 offsetLeft—到有定位属性的父级的距离
      • jq中的元素的位置
        • position() 返回对象{top,left} 到有定位属性的父级的距离
        • offset() 返回对象{top,left} 到文档的距离
          <script>
              $(function(){
                  console.log($('#box').position());
                  console.log($('#box').offset());
      
                  console.log($('#box').position().top)
              })
          </script>
      
    • 滚动条

      • 滚动条事件: $(window).scroll()
      • 滚动条卷走的宽高 获取和设置 scollTop() scollWidth()
      //jd楼层
          <script>
              $(function(){
                  // 窗口滚动条滚动
                  $(window).scroll(function(){
                      // 遍历所有的div版块
                      $('#box div').each(function(i, el){
                          // 如果  滚动条卷走的高度  大于等于了  某个版块的到文档顶部的top值
                          if($(window).scrollTop() >= $(el).offset().top){
                              // 找到index值相等的li  给该li加上样式on  然后将该li的所有兄弟移除样式on
                              $('#menu ul li').eq($(this).index()).addClass('on').siblings().removeClass('on');
                          }else{//如果 滚动条卷走的高度 小于了 某个版块到文档顶部的top值  那么将该div对应的li的样式  移除
                              $('#menu ul li').eq($(this).index()).removeClass('on');
                          }
                      })
                  })
                  // 隐式迭代
                  $('#menu ul li').click(function(){
                      // 当点击了某个li
                      // 计算该li的index值对应的div的到文档顶部的top值
                      var iTop = $('#box div').eq($(this).index()).offset().top;
                      // 该被点击的li获得样式on  将该li的兄弟移除样式on
                      $(this).addClass('on').siblings().removeClass('on');
                      // 将滚动条卷走的高度设置给刚刚计算的top值 也就是将滚动条定位到该li对应的版块的位置
                      $(window).scrollTop(iTop);
      
                  })
              })
          </script>
      
  • jq中DOM 操作

    • 创建节点:用$(‘标签’)

    • 添加节点:

      • append 父元素添加一个节点
      • appendTo 将一个节点添加到父元素
    • 插入节点

      • 元素.insertBefore(目标) 将一个元素插入到目标元素之前
      • 目标.before(元素) 在目标元素之前插入一个元素
      • 元素.insertAfter(目标) 将一个元素插入到目标元素之后
      • 目标.after(元素) 在目标元素之后插入一个元素
    • 替换节点

      • 要被替换的元素.replaceWith(元素) 后边的替换前边的
      • 元素.replaceAll(要被替换的元素) 前边的替换后边的
    • 复制节点

      • clone() 返回复制的节点–不带节点上的事件
      • clone(true) 返回复制的节点–带节点上的事件
    • 删除节点

      • remove() 删除某个节点,并将删除的节点返回,不保留节点上的事件
      • detach() 删除某个节点,并将删除的节点返回 ,会保留节点上的事件
          <script>
              $(function(){
                  // 创建节点
                  var oLi = $('
    • 火影忍者
    • '
      ); console.log(oLi); // 添加节点 // $('ul').append(oLi);//给ul添加一个li // oLi.appendTo($('ul'));//将一个li添加到ul中 // 插入元素 // 之前插入 // oLi.insertBefore($('ul li:eq(2)')); // $('ul li:eq(2)').before(oLi); // 之后插入 // oLi.insertAfter($('ul li:eq(2)')); // $('ul li:eq(2)').after(oLi); // 替换 // $('ul li:eq(3)').replaceWith(oLi); // oLi.replaceAll($('ul li:eq(3)')); // 复制 // var cloneLi = null; // $('ul li').click(function(){ // cloneLi = $(this).clone(true); // $('ul').append(cloneLi); // }) // 删除 // $('ul li').click(function(){ // console.log($(this).html()); // }) // // var oLi = $('ul li').eq(0).remove();//不带事件的 // var oLi = $('ul li').eq(0).detach();//带事件的删除 // $('ul').append(oLi); }) </script>
  • jQuery 中的事件

    • 事件驱动时 事件都不带on
    • 事件对象 ev jq中已经兼容了 但是任然需要传参
        <script>
            $(function(){
                // $(document).contextmenu(function(){
                //     console.log('right');
                // })
    
                // 事件对象
                $(document).click(function(ev){
                    console.log(ev);
    
                    /* 
                        ev.clientX/ev.clientY  鼠标和浏览器可视区的x  y轴的距离
                        ev.delegateTarget: 事件绑定的目标
                        ev.currentTarget:当前触发事件的目标
                        ev.offsetX/ev.offsetY: 鼠标和触发事件的元素的X Y轴的距离  
                        ev.pageX/pageY: 鼠标和当前文档的X  Y轴的距离
                        ev.screenX/screenY: 鼠标在屏幕上X Y轴的距离
                        ev.originalEvent: 原生的事件对象上的属性
                        ev.which: 确定鼠标的那个键(事件  mousedown)  1左键  2中滚轮按下  3右键
    
                    */
                })
    
                $(document).mousedown(function(ev){
                    console.log(ev.which);
                })
            })
        </script>
    
    • jq事件绑定

      • on(‘事件’,事件函数)
      • 一次绑定多个事件—触发同一个事件处理函数
        • on(’ 事件1 事件2 事件3。。。’,事件处理函数)
      • 对象形式的事件绑定—多个事件对应多个事件处理函数
        • on({‘事件1’:事件处理函数,‘事件2’:事件处理函数,。。。。。})
      • 自定义事件及触发—到了4阶段vue 中 父子组件传递数据
        • 触发自定义事件 元素.trigger(‘自定义事件’)
      • 事件委托
        • 被委托的元素.on(‘事件’,‘目标元素’,事件处理函数)
      • 事件取消绑定
        • off(‘事件名’)
      • 事件的命名空间
        • on(‘事件.xx’,事件处理函数) 当消息绑定时 off(‘事件.xx’) 取消对应事件
      • 只执行一次的事件绑定
        • one(‘事件’,事件处理函数) 当事件绑定后 触发一次之后就 取消绑定
      • 合成事件
        • hover(function(){鼠标移入函数},function(){鼠标移出函数})
          <script>
              $(function(){
                  // 事件绑定
                  // $('ul li').on('click',function(){
                  //     console.log($(this).html());
                  // })
      
                  // 给一个元素 绑定多个事件 触发同一个事件处理函数
                  // $('ul li').on('click mouseenter contextmenu',function(){
                  //     console.log('各种事件触发了该函数');
                  // })
      
                  // 对象参数的数据绑定--- 多个事件对应多个事件处理函数
                  // $('ul li').on({
                  //     'click':function(){
                  //         console.log('单击');
                  //     },
                  //     'mouseenter':function(){
                  //         console.log('鼠标移入');
                  //     },
                  //     'contextmenu':function(){
                  //         console.log('右键点击');
                  //     }
                  // })
                  // 自定义事件
                  // $('ul li').on('haha',function(){
                  //     console.log('事件哈哈被触发');
                  // })
      
                  // $('ul li').trigger('haha');
      
                  // 事件委托
                  // $('ul li').click(function(){
                  //     console.log($(this).html());
                  // })
                  // $('button').click(function(){
                  //     $('ul').append($('
    • 哈哈哈
    • '));
      // }) // $('ul').on('click','li',function(ev){ // console.log(ev); // console.log(ev.currentTarget);// 事件触发的目标 被点击的li // console.log(ev.delegateTarget);//事件绑定的目标 ul // console.log($(this).html()); // }) // $('button').click(function(){ // $('ul').append($('
    • 哈哈哈
    • '));
      // }) // 取消事件绑定 // $('#btn').on('click',function(){ // console.log('点击触发了') // }) // $('#offbtn').click(function(){ // $('#btn').off('click'); // }) // $('#btn').on('click',function(){ // console.log('点击触发了') // }) // $('#btn').on('click',function(){ // console.log('第二个点击触发了') // }) // $('#offbtn').click(function(){ // $('#btn').off('click'); // }) // 事件的命名空间 // $('#btn').on('click.a',function(){ // console.log('点击触发了') // }) // $('#btn').on('click.b',function(){ // console.log('第二个点击触发了') // }) // $('#offbtn').click(function(){ // $('#btn').off('click.b'); // }) // 只绑定一次的事件绑定 // $('#btn').one('click',function(){ // console.log('我真的还想再点500次'); // }) // 模拟绑定一次 // $('#btn').on('click',function(){ // console.log('我真的还想再点500次'); // $(this).off('click'); // }) // 合成事件 /* onmouseover---onmouseout 冒泡 onmouseenter--- onmouseleave 不会冒泡 合成事件使用 */ $('ul li').hover(function(){ // 鼠标移入触发 $(this).css('background','red'); },function(){ // 鼠标移出触发 $(this).css('background',''); }) }) </script>

      jQuery 动画与 ajax

  • jQuery 中的动画

    • jq中的固定动画效果 参数(duration–持续时间,easing–运动效果 linear swing ,callback—当动画执行完毕之后的回调函数)

      • duration 默认时间 normal 400ms fast 200ms slow 600ms
      • 显示隐藏 show/hide toggle()显示/隐藏 切换
      • 淡入淡出 fadeIn/fadeOut fadeToggle()淡入淡出切换
      • 滑出滑入 slideDown/slideUp slideToggle()滑出滑入切换
          <script>
              $(function(){
                  // show/ hide
                  // $('button:eq(0)').click(function(){
                  //     $('div').show(800);
                  // })
                  // $('button:eq(1)').click(function(){
                  //     $('div').hide(800);
                  // })
                  // 隐藏显示切换
                  // $('button:eq(0)').click(function(){
                  //     $('div').toggle(800);
                  // })
      
                  // 淡入淡出
                  // $('button:eq(0)').click(function(){
                  //     $('div').fadeIn(800);
                  // })
                  // $('button:eq(1)').click(function(){
                  //     $('div').fadeOut(800);
                  // })
      
                  // 淡入淡出的切换
                  // $('button:eq(0)').click(function(){
                  //     $('div').fadeToggle(800);
                  // })
      
                  // 滑出滑入
                  // $('button:eq(0)').click(function(){
                  //     $('div').slideDown(800);
                  // })
                  // $('button:eq(1)').click(function(){
                  //     $('div').slideUp(800);
                  // })
                  // 滑出滑入切换
                  // slideToggloe()
                  
              })
          </script>
      
    • jq的自定义动画

      • animate({属性:目标值,属性2:目标值,。。。},duration–动画持续时间,easing,callback–动画执行完成后的回调函数)
      • 基本自定义动画
      • 累加动画
      • 多属性动画
      • 链式动画
          <script>
              $(function(){
                  // 基本动画
                  // $('button').click(function(){
                  //     $('div').animate({width:300},600,function(){
                  //         console.log('我到了,你呢?');
                  //     })
                  // })
      
                  // 累加动画
                  // $('button').click(function(){
                  //     $('div').animate({width: '+=50'},600,function(){
                  //         console.log('一步一步向前走');
                  //     })
                  // })
      
                  // 多属性一起运动
                  // $('button').click(function(){
                  //     $('div').animate({width:300,height:300},600,function(){
                  //         console.log('我到了,你呢?');
                  //     })
                  // })
      
                  // 链式运动
                  // $('button').click(function(){
                  //     $('div').animate({width:300},600)
                  //             .animate({height:300},400)
                  //             .animate({opacity:.5},200)
                  // })
                  $('button').click(function(){
                      $('div').animate({width:300},600,function(){
                          $(this).animate({height:300})
                      })
                              
                  })
              })
          </script>
      
    • 动画队列

      • 将一个非动画的操作插入到动画队列 :
        • .queue(function(next){ 要插入的操作; next(); })
          <script>
              $(function(){
                  $('button').click(function(){
                      // $('div').animate({width:400},1000)
                      //         .css({background:'yellow'})//将css的设置  插入动画队列中  按照动画队列的顺序来执行
                      //         .animate({height:400},1000);
                      // 动画队列  将一个非动画的操作加入到动画队列中  使用  queue
                      $('div').animate({width:400},1000)
                              .queue(function(next){
                                  $(this).css({background:'yellow'});
                                  // queue插入动画队列后  要继续执行动画队列  需要一个参数next  然后在最后  调用next方法
                                  next();//继续执行后续动画队列中的动画
                              })
                              .animate({height:400},1000);
                  })
              })
          </script>
      
    • 判断是否处于动画状态

      • 为了防止动画出现累积情况
        • .is(’:animated’) 如果当前元素在执行动画 那么返回true 没有执行 返回 false
    • 停止动画和完成动画

      • stop(clearQueue,gotoEnd):对当前动画进行停止
        • 参数clearQueue是否清除动画队列—当当前动画停止后,后续的动画队列中的动画是否还继续执行 默认false 不清除动画队列
        • 参数gotoEnd 当前动画停止后 是直接停止在当前的状态下 还是 跳转到动画执行完成时的状态 默认false 不跳转动画最终状态
      • finish()
        • 跳转到该元素上的所有动画队列都执行完成的状态
          <script>
              $(function(){
                  $('button').eq(0).click(function(){
                      $('div').animate({width:400},800).animate({height:400},800)
                  })
      
                  $('button').eq(1).click(function(){
                      $('div').stop(true,true)
                  })
      
                  $('button').eq(2).click(function(){
                      $('div').finish();
                  })
              })
          </script>
      
  • jq中的ajax

    • 原生的ajax

      • 创建ajax对象 var oAjax = new XMLHttpRequest()
      • 使用open设置和服务器的交互信息 oAjax.open(method,url,true)
      • 发送数据 oAjax.send()
      • 注册ajax事件 oAjax.onreadystatechange = function(){}
      • 更新页面 oAjax.readyState == 4 oAjax.status == 200
      • 返回 responseText— text 字符串—》 JSON.parse()
    • get和post区别

      • get在url地址中传递数据 , post在消息中传递数据
      • get传递数据大小不超过2k psot传递数据理论大小无限 不同浏览器有限制
      • get有缓存 相对不安全 post没有缓存
      • 服务器端的获取方式不同
    • jq中的ajax

      • $.ajax({
        url: ‘’, // 请求的地址*
        cache: 布尔值 , // 是否缓存,get 请求如果 url 没有发生变化,则会走缓存
        type: ‘’, // 请求的方式(get/post),默认为 get*
        timeout: ‘’, // 设置请求超时时间,单位毫秒
        data: ‘’, // 发送到后端的数据*
        dataType: ‘’, // 预期服务器返回的数据类型,有 xml, html, script, json, jsonp,
        text*
        success: function(data) {}, // 成功的回调*
        error: function(err) {}, // 失败的回调
        complete: function() {}, // 请求完成后调用的函数,请求成功或失败均调用
        });
          <script>
              $(function(){
                  $.ajax({
                      type:'get',
                      url:'./mydata.json',
                      success:function(res){
                          show(res);
                      }
                  })
      
                  function show(arr){
                      $.each(arr,function(i,item){
                          $('ul').append($('
    • + item.href + '">' + item.title + '
    • '
      )); // $('ul').append($(`
    • ${item.title}
    • `));
      }) } }) </script>
    • get 和post方法

      • $.get(url,data,success)
      • $.post(url,data,success)
          <script>
              //jq的 data传递数据支撑字符串  对象  'page=1&count=10'  {page:1,count:10}
              $.get('./mydata.json',function(res){
                  console.log(res);
              })
              // post  和get 效果一样
              // $.post('./mydata.json',{page:1},function(res){
              //     console.log(res);
              // })
          </script>
      
    • 跨域jsonp

      • 什么是跨域: 当两个地址中 协议、主域名、名称、端口其中某一项只要不相等 就是两个域名,浏览器为了安全性着想 不允许两个域名不同的地址间进行数据交互
      • 为了解决跨域问题 有人提出偏方—jsonp jsonp 和ajax 一毛钱关系都没有。jsonp是前端跨域的一个方法 跨域有很多方法 jsonp只是其中的一种方法。
      • 原生的跨域使用
        • 利用script标签的 src 链接url 后代返回的数据 采用函数调用执行的形式 将数据作为函数调用时的实参 传递过来 在前端页面上建立该函数 用形参接收数据
        • script 的src要动态创建
      • jq的jsonp
        • 在$.ajax({})的对象参数中 不写type 写dataType:‘jsonp’;

jQuery 插件与 Zepto

  • jq的插件

    • jq插件分为两种

      • 类级别插件(工具级) 直接挂载在JQuery($)对象下 $.extend({ 方法名:function(){})
      <script>
              // 类级别插件  将字符串开头 或者结尾的空格取消
              var str = '                  hello                ';
              var arr = [1,1,1,2,2,2,3,3,3,3,4,4,4,5,5,5,6,6,6,7,7,7,8,8];
              // console.log(str.trim());
              $.extend({
                  startTrim:function(str){
                      var reg = /^\s+/;
                      str = str.replace(reg,'');
                      return str;
                  },
      
                  endTrim:function(str){
                      var reg = /\s+$/;
                      str = str.replace(reg,'');
                      return str;
                  },
      
                  removal:function(arr){
                      var json = {};
                      var nArr = [];
                      $.each(arr,function(i,val){
                          if( !json[val]){
                              json[val] = 1;
                              nArr.push(val);
                          }
                      })
                      return nArr;
                  }
              })
      
              console.log($.removal(arr))
          </script>
      
      • 对象级别插件 是挂载在 JQuery.fn下 $.fn.extend({ 方法名:function(){})
          <script>
              // $.each(arr,function)  //类级别  工具级方法
              // $('div').each(fucntion())  //对象级别   对象的方法
              $.fn.extend({
                  'changeColor':function(oddColor,evenColor){
                      // console.log(this);// jq对象  tbody
                      this.children(':odd').css({background:oddColor});
                      this.children(':even').css({background:evenColor});
                      return this;
                  }
              })
      
              $(function(){
                  $('table tbody').changeColor('pink','green').css({fontSize:'18px'})
                  // $('table tbody').click(function(){
                  //     console.log(this);// ...  原生DOM  tbody
                  // })
                  $('ul').changeColor('#ccc','skyblue').children().css({border:'1px dotted #000'})
              })
          </script>
      
  • Zepto.js

    • 是专门用于移动端的一个js库 它的API基本上和jq是一样,只针对移动端,所以不兼容低版本浏览器。

      • 基本的通用库 Zepto.js(最基本的操作)
      • 可以使用一些扩展库 fx.js touch.js…
         <script src="./zepto.min.js"></script>
         <script src="./touch.js"></script>
         <script>
             $(function(){
                 $('div').on('tap',function(){
                     console.log(this);//原生DOM
                     console.log($(this));// Zepto对象
                 })
             })
         </script>
      
    • zepto获取元素宽高的区别

      • zepto 不能获取不显示的元素的宽高 jq可以
      • zepto中 width() 获取的是 content+padding+border zepto中没有 innerWidth和outerWidth
          <!-- <script src="../jquery.min.js"></script>
          <script>
              $(function(){
                  console.log($('#box').width());// 元素的内容宽
                  console.log($('#box').innerWidth());//元素的可视宽  content+padding
                  console.log($('#box').outerWidth());//元素的占位宽   content+padding+border
                  console.log($('#box').outerWidth(true));//元素的整个宽  content+padding+border+margin
              })
          </script> -->
          <script src="./zepto.min.js"></script>
          <script>
              $(function(){
                  console.log($('#box').width());//content+padding+border
              })
          </script>
      
    • zepto offset()的区别

      • position() 没有变化
      • offset() jq中返回对象{top,left} 到文档的top和left值,在zepto中对象多了两个属性 width和height
          <!-- <script src="../jquery.min.js"></script>
          <script>
              $(function(){
                  console.log($('#box div').position());// 到有定位属性的父级
                  console.log($('#box div').offset());//  到文档
                  
              })
          </script> -->
          <script src="./zepto.min.js"></script>
          <script>
              $(function(){
                  console.log($('#box div').position());// 到有定位属性的父级
                  console.log($('#box div').offset());//  到文档top left 及该元素的  占位宽高
              })
          </script>
      
    • zepto中的touch

          <script>
              $(function(){
                  // $('div').on('tap',function(){
                  //     console.log('tap');
                  // })
      
                  $('div').on('singleTap',function(){
                      console.log('单击');
                  })
      
                  $('div').on('doubleTap',function(){
                      console.log('双击');
                  })
      
                  $('div').on('longTap',function(){
                      console.log('长按');
                  })
      
                  $('div').on('swipe',function(){
                      console.log('滑动');
                  })
      
                  $('div').on('swipeLeft',function(){
                      console.log('左滑');
                  })
      
                  $('div').on('swipeRight',function(){
                      console.log('右滑');
                  })
      
                  $('div').on('swipeUp',function(){
                      console.log('上滑');
                  })
      
                  $('div').on('swipeDown',function(){
                      console.log('下滑');
                  })
              })
          </script>
      

你可能感兴趣的:(javascript)