JS基础2.0

day1

js简介

  • js:javascript

  • js 是一种直译型的脚本语言 script 脚本

  • js 组成部分 ECMAScript + BOM(browser object model) + DOM(document object model)

  • js 历史 为了解决表单验证问题

  • js 前端页面效果 + 后端进行交互!!!!!

2+2+2

js创建

  1. 内部js

        <script>
            // 内部js
        </script>
    
  2. 外部引入js

     <script src="../js/test.js"></script>
    
  • 错误写法

    	<!-- 错误写法 -->
        <!-- <script src="../js/">
            // 此处不能写js代码
        </script> -->
    

js输出

弹窗
alert("hello");
文档输出
document.write("hello");

可解析标签

document.write("<h1>LIGHT UP THE SKY</h1>");
控制台

用于调试代码

console.log("hello")

变量

  • 变量:经常会改变的值
  • 常量:不会改变的值
声明变量

声明变量就需要var 关键字

        var x ;
        var y ;
        var a ;
        var hello ;
标识符

就是变量、函数、属性或函数参数的名称。

  1. 第一个字符必须是字母、下划线_或 美元符号
  2. 剩下其他字符可以是字母、下划线、美元符号或数字

驼峰命名

  1. 小驼峰命名法

      // studentname        studentName
    
  2. 大驼峰命名法

    // studentname        StudentName
    
变量的赋值
  • 赋值

    var beiZi ;
    beiZi = '水' ;
    
  • 声明变量并赋值

    var studentName = '李肖' , beiZi = '水' ;
    

变量的数据类型

  • 字符串
  • 数字
  • 布尔值 true false
  • undefined 未定义(变量声明了但是没有赋值)
  • null 空对象
typeof

typeof 判断数据类型

  1. 字符串 string
  2. 数字 number
  3. 布尔值 boolean
  4. null object
  5. undefind undefined
        var a = "black";
        console.log(typeof a); //string

        var b = 3;
        console.log(typeof b); //number

        var c = true;
        console.log(typeof c); //boolean

        var d = null;
        console.log(typeof d); //object

        var e;
        console.log(typeof e); //undefined

算数运算符

  • /
  • %
        var count = 3 ; 
        var price = 9 ;
        console.log(count * price) ;
        console.log(count + price) ;
        console.log(count - price) ;
        console.log(count / price) ;
        // 余数
        console.log(7 % 3) ; //1

比较运算符

  • == 判断值是否相等
  • === 判断值和数据类型都必须相等 并且 两个条件必须同时满足
  • >
  • <
  • >=
  • <=
        var a = 3 ; 
        var b = 3 ; 
        console.log(a >= b) ;  // 大于或者等于 true

        console.log(a <= b) ;  // 小于或者等于 true
   		var m = 5 ; 
        var n = '5' ;
        // ==判断只要值是一样就可以
        console.log(m == n) ; //true
        // ===值和数据类型必须都一样  严格判断
        console.log(m === n) ; //false

逻辑运算符

  • 与 && 条件必须同时满足
  • 或 || 条件只需要满足一个
  • 非 ! 取反
短路
  • 与运算

    只要见到条件为假就直接结束 见假即为假

  • 或运算

    只要见到条件为真就直接结束 见真即为真

        var a = 13;
        var b = 4;
        var c = 50;

        console.log(a > b && b > c); //false
        console.log(a < b || b < c); //true


        //短路与
        console.log(a < b && b < c);//false

        //短路或
        console.log(a > b || b > c);//false


        console.log(!(a > b)); //false

自增自减

  • a++ 先执行表达式,再自增

  • ++a 先自增,在执行表达式

  • a-- 先执行表达式,再自减

  • –a 先自减,在执行表达式

        var b = 1;
        console.log(b++); //1
        console.log(++b); //3

        var c = 1;
        console.log(++c); //2

        console.log(c++ + 1); //3

        console.log(c++ + ++c); //3+5 = 8

赋值运算符

  		var a = 17 ; 
        // a = (a + 2) ;
        a = a + 2 ;
        console.log(a) ;

        // 简写
        a += 2 ;
        console.log(a) ;

        a -=2 ; 
        console.log(a) ;

        a *= 2 ; 
        console.log(a) ;

        a %= 2 ;   // a = a % 2 ;
        console.log(a) ;
输入框求和案例

在这里插入图片描述

  • document.getElementById()
    <input type="text" id="inp1">
    <span>-</span>
    <input type="text" id="inp2">
    <button id="btn">=</button>
    <input type="text" id="result">


    <script>
        //1.找到按钮
        var oButton = document.getElementById("btn");
        //2.点击事件

        oButton.onclick = function () {
            //3.拿到第一个输入框
            var oInput1 = document.getElementById("inp1");
            console.log(oInput1);

            //4.拿到第一个输入框的值
            var num1 = oInput1.value;


            var oInput2 = document.getElementById("inp2");
            console.log(oInput2);

            var num2 = oInput2.value;

            //测试是否拿到了输入框的值
            console.log(num1, num2);


            //计算结果
            var res = num1 - num2;

            console.log(res);


            //把结果放到最后一个输入框
            var outPut3 = document.getElementById("result");
            outPut3.value = res;


        };

    </script>

作业

        // 02 var k=0; var sum = k++ + ++k +k +k++; console.log(sum)
        // 03 入职薪水10K,每年涨幅入职薪水的5%,50年后工资多少?  
        // 04 小明要到美国旅游,可是那里的温度是以华氏度为单位记录的,它需要一个程序将华氏温度(80度)转换为摄氏度,并以华氏度和摄氏度为单位分别显示该温度。(摄氏度与华氏度的转换公式为:摄氏度 = 5/9.0*(华氏度-32)保留3位小数)
        // 05 如何交换两个变量的值

        
        // 06 实现加减乘除
        // 07 给定一个四位数,分别把这个数字的千位、百位、十位、个位算出来并显示

day02

字符串拼接

+作用

  • 求和
  • 字符串拼接 多个字符串或者多个变量拼接时都需要使用+
    <script>
        var a = 'abc';
        var b = 'def';
        console.log(a + b);

        document.write(a + b);

    </script>

精度丢失

由于计算机是二进制的,所以有精度缺失问题

        var a = 0.1;
        var b = 0.2;

        console.log(a + b); // 0.30000000000000004
        console.log(0.1 + 0.2 == 0.3); //false

        console.log(9999999999999999 == 10000000000000001);//true


        console.log(0.1 + 0.7); //0.799999

解决办法

将数都扩大成整数

          //解决办法
        console.log((a * 10 + b * 10) / 10); //0.3


关于Number

数字除了普通数字还具有

  • Infinity 无穷大
  • NaN (Not a Number) 非法数字
        var a = 1 / 0;
        console.log(a); //Infinity


        var b = "bbb";
        console.log(b - 0); //NaN

数据类型转换

强制转换
String()

其他数据类型转换成字符串

        var a = 5;
        console.log(String(a)); //'5'

        var b = true;
        console.log(String(b)); //'true'  

        var c = false;
        console.log(String(c)); //'false'


        var d = null;
        console.log(String(null)); //'null'

        var e = undefined;
        console.log(String(undefined)); //undefined
        var a = Infinity;
        console.log(String(a)); //Infinity

        var b = 'a' - 0;
        console.log(String(b)); //NaN
Boolean()

其他数据类型转布尔值

  • 数字除了 0 和NaN ,其他都是true
  • 字符串除了空串,其他都是true
  • null false
  • undefined
  //number
        var a = 12;
        console.log(Boolean(a)); //true

        var b = 0;
        console.log(Boolean(b)); //false


        //string

        var c = "acd";
        console.log(Boolean(c)); //true

        var d = " "; //空格字符
        console.log(Boolean(d)); //true


        var e = ""; //空字符
        console.log(Boolean(e)); //false

        //null
        var f = null;
        console.log(Boolean(e)); //false

        //undefined
        var g = undefined;
        console.log(Boolean(g)); //false
        var k = Infinity;
        console.log(Boolean(Infinity)); //true
        var h = NaN;
        console.log(Boolean(h)); //false
Number()

其他数据类型转数字

  • 字符串
    • 纯数字字符串 直接变为数字
    • 非纯数字字符串, NaN
  • 布尔值
    • true 1
    • false 0
  • undefined NaN 0
  • null 0
 //string
        var a = "31";
        console.log(Number(a)); //31

        var b = "2b";
        console.log(Number(b)); //NaN

        var c = " ";//空格字符串
        console.log(Number(c)); //0


        var d = ""; //空字符
        console.log(Number(d)); //0


        //boolean
        var e = true;
        console.log(Number(e)); //1

        var f = false;
        console.log(Number(f)); //0


        //undefined
        console.log(Number(undefined)); //NaN


        //null
        console.log(Number(null)); //0

隐式转换
算数运算符

通过算数运算符,将类型进行隐式转换

  • -,*,/,% 自动转换为Number 数字
    • 碰到字符串就自动转字符串
    • 没有字符串就转成数字
        var a = '3';

        console.log(a * 1); //3
        console.log(a - 0); //3
        console.log(a / 1); //3

        //碰到字符串,字符串拼接
        console.log(a + 44); //'344'


比较运算符
  • 有数字时,就转数字进行比较

  • 字符串与字符串比较的是ACSII值

  • NaN与任何值不相等 不比较 ,NaN是一个集合

  • undefined==null

  • null ==0 -->false

  • 因为a 转为数字时NaN,不与任何值比较

        console.log('a' > 3); //FALSE
        console.log('a' < 3); //FALSE
        console.log('a' == 3); //FALSE
 console.log("33" > 4); //true
        console.log(true < 1); //false
        console.log(false < 1);  //true

 console.log(true < Infinity); //true
console.log(null < 4); //true
  • undefined转为数字为NaN
        console.log(undefined < 0);
        console.log(undefined == 0);
        console.log(undefined > 0);

字符串与字符串比较

 console.log("hello" > "hi"); //false
    console.log(null == undefined); //true
  • null与数字0比较不转换成字符串

     console.log(null == 0); //false
    
            console.log(null > 1); //false
            console.log(null < 1); //true
    

isNaN

isNaN()函数判断是否为NaN

可用来判断是否为合法数字

        var a = "33";
        var b = "2b";

        console.log(isNaN(Number(a))); //false
        console.log(isNaN(Number(b))); //true

取数字

parseInt
parseFlot
        var m = 2; //int 整数
        var n = 2.4; //float 浮点数


        var fontSize = '20.56.78px 78';

        console.log(parseInt(fontSize)); //20

        console.log(parseFloat(fontSize)); //20.56

数字的处理

  • Number()
  • isNaN()
  • toFiexed() —保留几位小数
  • parseInt()
  • parseFlot()
toFixed

保留几位小数

        var a = 3.14999;
        console.log(a.toFixed(3)); //3.150

Math对象

  • abs()绝对值
  • round()四舍五入取整
  • ceil()向上取整
  • floor() 向下取整
  • random 产生0-1之间随机数 (包含0 不包含1)

产生某一区间的数字

max

min

  • parseInt(Math.random()*(max-min+1))+min
  • Math.round(Math.random()*(max-min))+min
  • Math.ceil(Math.random()*(max-min)) + min
  • Math.floor( Math.random() * (max-min + 1) ) + min
        //100以内的随机整数 0-100
        var a = Math.random();
        a *= 100;

        a = Math.round(a);
        console.log(a);


        //产生一个三位数
        //100-999
        //100+(0-899)
        var a = Math.random() * 900;
        a = parseInt(a);
        a += 100;
        console.log(a);
        //bug取不到999


        //产生某一区间的随机数
        var max = 990;
        var min = 999;
        var res = min + Math.round(Math.random() * (max - min));
        var res = min + Math.ceil(Math.random() * (max - min));
        var res = min + Math.ceil(Math.random() * (max - min + 1));
        var res = parseInt(Math.random() * (max - min + 1)) + min;
        console.log(res);

if语句

三大流程控制语句

  • 顺序yuju

  • 选择语句

  • 循环语句

  • 选择结构

    • 单分支
    • 双分支
    • 多分支
判断奇偶
  // 产生一个100以内的随机整数,判断奇数偶数
        var a = parseInt(Math.random() * 100) ; 
        // if(a % 2 === 0) {
        //     alert(a + '是一个偶数')
        // } 
        // else {
        //     alert(a + '是一个奇数') 
        // }

        // if(条件)   条件 true / false   隐式转化

        if(a % 2) {
            alert(a + '是一个奇数') 
        } 
        else {
            alert(a + '是一个偶数') 
        }
判断能3和7整除
  <h3>判断数字是否能同时被3和7整除</h3>
    <input type="text" id="inp1">
    <button id="btn">判断</button>
    <input type="text" id="inp2">

    <script>
        // 1 点击事件
        // 2 拿到输入的值
        // 3 判断同时被3和7整除   求模
        // 4 把结果给输入框

        var oBtn = document.getElementById('btn') ;
        oBtn.onclick = function() {
            var num = document.getElementById('inp1').value ;

            var res ;

            if(num % 3 == 0 && num % 7 == 0) {
                // document.getElementById('inp2').value = '是'
                res = '是';
            }
            else {
                // document.getElementById('inp2').value = '否'
                res = '否'
            }


            document.getElementById('inp2').value = res ;

            
        }

判断数字为整数

  • number % 1 == 0
  • number == parseInt(number)

day3

switch

        var a = 4;
        多分支语句
        switch (a) {
            case 0: {

            }
            case 1: {

            }
            case 2: {

            }
            default: {

            }
        }
 var light = 'red';
        switch (light) {
            case 'red': alert('stop'); break;
            case 'green': {
                alert('go');

            }
                break;
            case 'yellow': {
                alert('wait')

            }
                break;
            default: {
                alert('灯坏了')
            }
        }
 // 简写:大括号里面如果只有一条语句,就可以简写(去掉大括号)

        if (light == 'red') { alert('stop'); console.log('stop'); }
        else alert('go')
判断分数
   var score = 56;
        // switch 实现分数的判断
        // 60-70 及格  
        // 70-80 还行
        // 80-90 良好
        // 90-100 优秀
        // 100  666
        // 0-60 优雅降级

        score = parseInt(score / 10);

        switch (score) {
            case 10: alert(666); break;
            case 9: alert('优秀'); break;
            case 8: alert('B'); break;
            case 7: alert('C'); break;
            case 6: alert('D'); break;
            case 5:
            case 4:
            case 3:
            case 2:
            case 1:
            case 0: alert('优雅降级'); break;

        }
switch特殊语法
  • swich语句一般适用于值是确定的,而不是范围值
  • switch默认穿透,需要结合break语句一起使用 break仅在switch中使用
  • case是做严格判断(值和数据类型必须严格一致)
  • switch(true) case 比较运算符 特殊语法
        var score = 65;
        switch (true) {
            case score < 60: alert('不及格'); break;
            case score >= 60 && score < 70: alert('及格'); break;
        }
计算天数
  年:<input type="text" id="inp1">
    月:<input type="text" id="inp2">
    日:<input type="text" id="inp3">
    <input type="button" value="计算是当年的第几天" id="btn">
    <input type="text" id="inp4">

    <script>
        var oInp1 = document.getElementById('inp1');
        var oInp2 = document.getElementById('inp2');
        var oInp3 = document.getElementById('inp3');
        var oBtn = document.getElementById('btn');
        var oInp4 = document.getElementById('inp4');

        oBtn.onclick = function () {
            var y = oInp1.value * 1;
            var m = oInp2.value * 1;
            var d = oInp3.value * 1;

            var total = 0;

            var erDay = 28;
            if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0) {
                erDay = 29;
            }

            switch (m) {
                // case 1: total = d; break;
                // case 2: total = 31 + d; break;
                // case 3: total = 31 + erDay + d; break;
                // case 4: total = 31 + erDay + 31 + d; break;
                // case 5: total = 31 + erDay + 31 + 30 + d; break;
                // case 6: total = 31 + erDay + 31 + 30 + 31 + d; break;
                // case 7: total = 31 + erDay + 31 + 30 + 31 + 30 + d; break;
                // case 8: total = 31 + erDay + 31 + 30 + 31 + 30 + 31 + d; break;
                // case 9: total = 31 + erDay + 31 + 30 + 31 + 30 + 31 + 31 + d; break;
                // case 10: total = 31 + erDay + 31 + 30 + 31 + 30 + 31 + 31 + 30 + d; break;
                // case 11: total = 31 + erDay + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + d; break;
                // case 11: total = 31 + erDay + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 + d; break;


                // 2000  12  12

                // total = 0
                // 0 + 30 + 31 + 31 + 31 + 30


                case 12: total += 30;
                case 11: total += 31;
                case 10: total += 30;
                case 9: total += 31;
                case 8: total += 31;
                case 7: total += 30;
                case 6: total += 31;
                case 5: total += 30;
                case 4: total += 31;       // 31 + erDay + 31 + 5
                case 3: total += erDay;    // erDay + 31 + 5
                case 2: total += 31;       // 31 + 5
                case 1: total += d;        // 5
            }

            oInp4.value = total;
        }
    </script>

while

        while (条件) {
            // 循环要做的事情
        }
案例

打印100以内所有的奇数

        var i = 1;
        while (i < 100) {
            if (i % 2) {
                console.log(i)
            }
            i++;
        }

打印能同时被3和7整除的数

        var i = 1;
        while (i < 100) {
            if (i % 3 == 0 && i % 7 == 0) {
                console.log(i);
            }
            i++;
        }

100以内求和

  var i = 1;
        var total = 0;
        while (i <= 100) {
            total += i;
            i++;
        }
        console.log(total)

do-while

        var i = 0;
        do {
            console.log(666);
            i++;
        } while (i < 10);

区别

  • while 是先判断后执行 有可能一次也不会执行
  • do while 先执行后判断 至少会执行一次

for

        for(初始值;条件;变量变化){
            循环体
        }
    for (var i = 0; i <= 100; i++) {
            if (i % 2 == 0) {
                console.log(i);
            }
        }
      for (var i = 0; i <= 100; i += 2) {
            console.log(i);
        }

day4

九九乘法表

 <style>
        .b {
            display: flex;
            margin: 0;
        }

        span {
            width: 90px;
            text-align: center;
            line-height: 30px;
            border: 1px solid #000;
            margin: 10px;
        }
    </style>
</head>

<body>

    <!-- <p>
        <span>1*1=1</span>
    </p>
    <p>
        <span>1*2=2</span>
        <span>2*2=4</span>
    </p> -->








    <script>

        // 内   行
        // i   j
        // 1 * 1 = 1 
        // 1 * 2 = 2  2 * 2 = 4 
        // 1 * 3 = 3  2 * 3 = 6  3 * 3 = 9  

        for (var j = 1; j <= 9; j++) {
            document.write('<p class="b">')
            for (var i = 1; i <= j; i++) {
                // document.write(i + '×' + j + '=' + i * j + ' ');
                document.write('<span>' + i + '×' + j + '=' + i * j + '</span>')
            }
            document.write('</p>')
        }

取数问题

parseInt(上一位的余数 / 本位的数)

  • 取个位/十位/百位…

     var num = 4532;
            var qian = parseInt(num / 1000);
            var bai = parseInt(num % 1000 / 100);
            var shi = parseInt(num % 100 / 10);
            var ge = num % 10;
    
            var qian = parseInt(num % 10000 / 1000);
            var bai = parseInt(num % 1000 / 100);
            var shi = parseInt(num % 100 / 10);
            var ge = parseInt(num % 10 / 1);
    
  • 取时分秒

            var miao = 3661000;
            var day = parseInt(miao / (3600 * 24));
            var hour = parseInt(miao % (3600 * 24) / 3600);
            var min = parseInt(miao % 3600 / 60);
            var sec = parseInt(miao % 60 / 1);
    
    

循环的选择

  • while 可以做更复杂的条件循环
  • for 更适合于循环次数比较确定的

产生0-10之间的随机数 ,需要多少次才能出现0?

        var flag = true;
        var count = 0;
        while (flag) {
            var num = parseInt(Math.random() * 10);
            count++;
            if (num == 0) {
                flag = false;
            }
        }
        console.log(count);

函数

函数:封装具有同一个功能的代码

  • 创造
  • 反复的使用
  • 需要被使用

函数语法

        function 函数名(参数) {
            // 实现的功能
        }
		function washer(clothes, xiyiye) {
            console.log('我是被' + xiyiye + '洗干净的' + clothes);
        }

        // 调用工具
        washer('帽子', '蓝月亮');

        washer('臭袜子', '李白洗衣粉');
	function star(n, m) {
            for (var j = 0; j < n; j++) {
                for (var i = 0; i < n; i++) {
                    document.write(m)
                }
                document.write('<br>')
            }
        }

        star(4, '6');

day5

变量作用域

全局变量
  • 函数外面声明的变量是全局变量,在外面或者是函数里面都可以访问
局部变量

在函数里面声明的变量,只能在函数里面使用,函数外面使用会报错

        //全局变量
        var a = 10;
        function test() {
            
            var b = 30;
            
            //全局变量在函数内外都可以使用
            console.log(a, b); //10,30

        }

        test();
        console.log(a); //10
        
        //局部变量:只能在函数内使用
        console.log(b); // b is not defined


形参和实参

  • 形参:形式参数 函数定义时,括号里面写的变量
  • 实参:实际参数 函数调用时,括号里面写的值
function sum(num) { //形参
            var sum = 0;
            for (var i = 0; i <= num; i++) {
                sum += i;
            }
            console.log(sum);

        }


        var num = parseInt(Math.random() * 10);

        //实参
        sum(num);

函数形参与实参可以不对等

        function sum(a, b) {

            return a + b;

        }

        sum(1, 2, 3, 4);

实参比形参少时,默认undefined

        function sum(a, b) {
            console.log(a, b); //1,undefined

        }

        sum(1);

函数作用域和参数问题

  • 全局变量:函数外声明的变量

  • 局部变量:函数内部声明的变量

  • 形参:函数定义时的参数

  • 实参:函数调用时的参数

  • 形参相当于局部变量

  • 函数外和函数内声明了同一个变量时(变量名相同),函数优先使用自己的

        var a = 10;
        function sum(a) { //形参

            //函数优先使用自己的变量
            console.log(a);
        }

        sum(5); //5

函数返回值return

想让函数外面访问函数里面的变量,需要把这个变量return

        function rand(min, max) {
            //num是函数里面声明的,函数外面无法访问
            var num = min + Math.round(Math.random() * (max - min));

            //返回值 ---函数执行的结果
            return num;
        }


        console.log(rand(10, 20));
        console.log(num); //num is not defined

函数如果只有return 提前结束函数

质数封装
        function isZhi(num) {

            if (!isNaN(num) && num % 1 == 0) {
                if (num == 2) {
                    return true;
                }

                for (var i = 2; i < num; i++) {
                    if (num % i == 0) {
                        return false;
                    }
                }

                return true;
            } else {
                return "参数错误";
            }
        }
计算器封装
        function calc(num1, num2, opt) {
            num2 *= 1;
            num2 *= 1;
            var res;
            switch (opt) {
                case '+': res = num1 + num2; break;
                case '-': res = num1 - num2; break;
                case '*': res = num1 * num2; break;
                case '/': res = num1 / num2; break;
                default: res = "符号错误,无法计算";
            }
            return res;
        }

        function calc(num1, num2, opt) {
            num1 *= 1;
            num2 *= 1;
            switch (opt) {
                case '+': return num1 + num2;
                case '-': return num1 - num2;
                case '*': return num1 * num2;
                case '/': return num1 / num2;
                default: return "符号错误,无法计算";
            }
        }

函数声明

具名函数
        function fn1() {
            console.log(666);

        }
        fn1();
赋值函数

匿名函数 ,赋值式声明

        var fn2 = function () {
            console.log("xxx");

        }
        fn2();
匿名函数自调用
        !function (num) {
            console.log(num); //3
        }(3);


        + function (a) {

            console.log(a);

        }("BLACK");

函数总结

  • 函数可以没有形参
  • 函数的形参与实参不对等
  • 函数可以没有返回值,返回undefind
  • 函数如果有return 提前结束

函数无返回值

返回undefined

        function test() {
            console.log("xx");
        }

        var a = test();
        console.log(a); //undefind
        function test() {
            console.log("xx");
            return;
            console.log("pink");

        }

        var a = test();
        console.log(a); //undefind

系统函数

  • isNaN

  • alert 没有返回值 undefined

  • confirm

  • prompt

  • eval

  • alert

    警告作用

            var a = alert("BLACKPINK");
    
            console.log(a); //undefined
    
  • confirm

    具有确认与取消按钮

    确认 返回true

    取消 返回false

            var a = confirm("确认删除");
    
            console.log(a);
    
  • prompt

    具有输入框,可输入数据

    点击取消,则返回–null

    确认,返回输入的数据

            var a = prompt("请输入成绩");
    
            console.log(a);
    
  • eval

            console.log(eval('1+2')); //3
    

计算器封装

          function calc(num1, num2, opt) {
  
              var res = eval(num1 + opt + num2);
              return res;
          }
  
          console.log(calc(3, 4, '+'));

预编译

js运行的两个阶段

  • 预编译阶段

  • 执行阶段

  • 变量的预编译–提升var

  • 函数的预编译–提升具名函数

  • js从上而下执行

变量的提升

        console.log(a); //undefined,变量的提升
        var a = 5;
        console.log(a); //5

函数的提升

        //具名函数的提升
        fn1(); //pink
        function fn1() {
            console.log("PINK");

        }

        // 你看到的代码

        console.log(a);

        var a = 5;

        console.log(a)


        fn();


        function fn() {
            console.log(1)
        }




        // 真正js执行的顺序


		//提升
        var a;

        function fn() {
            console.log(1)
        }
        
        
        

        console.log(a);

        a = 5;

        console.log(a)

        fn();

面试题
        console.log(v1); //undefined
        var v1 = 100;
        function foo() {
            console.log(v1); //undefined
            var v1 = 200;
            console.log(v1); //200
        }
        foo();
        console.log(v1); //100

实际执行顺序

  • 函数内部的变量也会有提升
var v1;


function foo(){
	var v1;
	console.log(v1);
	v1 = 200;
	console.log(v1);
}
 console.log(v1); 

v1 = 100;


foo();

console.log(v1);
		console.log(add(1, 2));

        function add(x, y) {
            return x + y;
        }

        console.log(add);

        var add = 10;

        console.log(add);

        console.log(add(1, 2))

实际执行顺序

		var add;
        function add(x, y) {
            return x + y;
        }
        
       console.log(add(1, 2)); //3
       
        console.log(add) //fn..
        
        add = 10
        
       console.log(10);
       
       console.log(add(1, 2)) //error

默认值

形参和实参不对等
      function foo() {
            // a++;
            return 666;
        }

        console.log(foo(3, 4, 5, 6));

短路赋值
  		// 短路赋值 见真伪真
        var a = 0 || 4;
        console.log(a);  // 4

        var a = 3 || 4;
        console.log(a)  // 3


        // 见假即为假 
        var b = 3 && 4 && 6 && 0 && 6;
        console.log(b);

        function add(a, b) {
            //当a/b为空字符串,boolean值为false,则返回0
            a = a || 0;
            b = b || 0;
            console.log(a + b);
        }
        var a = 3;

        function test(a) {
            return ++a;
        }

        console.log(test(a)); //4

        console.log(a); //3

三目运算符

  n % 2 ? console.log('奇数') : console.log('偶数');

质数判断

        var num = 7;
        for (var i = 2; i < num; i++) {
            if (num % i == 0) {
                break
            }
        }

        i == num ? console.log('质数') : console.log('合数');

        function isZhi(num) {
            for (var i = 2; i < num; i++) {
                if (num % i == 0) {
                    break;
                }
            }

            return i == num ? true : false;
        }
        function isZhi(num) {
            for (var i = 2; i < num; i++) {
                if (num % i == 0) {
                    return false;
                }
            }

            return true;
        }

总结

  • 作用域: 全局变量和局部变量
  • 形参和实参 不对等
  • 返回值 return
  • 函数的声明方式 具名函数 赋值式函数 匿名函数
  • 系统函数 isNaN alert confirm prompt eval
  • js预编译
  • 短路赋值
  • 三目运算符
  • 质数判断的方法

day6

封装

// min -max 之间的随机数 ,不包含max
function rand(min, max) {
    return parseInt(Math.random() * (max - min)) + min;
}

// 获取元素
function $(id) {
    return document.getElementById(id)
}

最大公约数

                // 最大公约数  4   6
                // 4 %2   6 %2     2
                // 4 %3   6 %3
                // 4 %4   6%4   
        
        
        function gcd(a, b) {
            //找到a和b之间更小的数
            var min = a < b ? a : b;

            //假设法
            var res = 1;

            for (var i = 2; i <= min; i++) {
                if (a % i == 0 && b % i == 0) {
                    res = i;
                }
            }

            return res;
        }

        function gcd(a, b) {
            //找到a和b之间更小的数
            var min = a < b ? a : b;

            //倒着取余数
            for (var i = min; i >= 1; i--) {
                if (a % i == 0 && b % i == 0) {
                    return i;
                }
            }
        }

递归

递归函数:函数不断地调用自己

  • 出口
  • 调用自己

求和

        function sum(n) {
            if (n == 1) {
                return 1;
            } else {
                return sum(n - 1) + n;
            }

        }

阶乘

        function jieCheng(n) {
            if (n == 1) {
                return 1;
            }
            return n * jieCheng(n - 1)
        }

斐波拉切数列

        // 斐波拉切数列

        // 1 1 2 3 5 8 13 21

        function fb(n) {
            if (n == 1 || n == 2) {
                return 1;
            }

            return fb(n - 1) + fb(n - 2);
        }

欧几里得算法

求最大公约数

        // 欧几里得算法
        // 6  24
        //  6 % 24   6
        // 24 % 6   0    6
        function gcd(a, b) {

            if (a % b == 0) {
                return b;
            }

            return gcd(b, a % b);

        }

数组

数组:存储多个数据

数组声明
字面量声明
        //字面量声明
        var arr = [1, 2, 3, 4, 5, 6, 7];
实例化对象
        // 实例化对象   存储10条数据
        var arr = new Array(10);
数组属性

角标:从0开始

长度:length

        //字面量声明
        var arr = [1, 2, 3, 4, 5, 6, 7];

        console.log(arr[3]); //4

        //数组长度
        console.log(arr.length); //7

        console.log(typeof arr); //object
isArray

判断否为数组

 var arr = [1, 2, 3, 4, 5, 6, 7];

 console.log(Array.isArray(arr)); //true
数组练习
        //随机产生0-100之间的数,放入数组中

        var arr = [];

        for (var i = 0; i < 10; i++) {
            arr[i] = parseInt(Math.random() * 100);
        }

        console.log(arr);

        arr[arr.length] = 'BLACK';

        console.log(arr);

        var arr2 = [, 5, 6, 7, 8, 9, , , , 10, 20];

        console.log(arr2);

        //追加10条数据
        for (var i = 0; i < 10; i++) {
            arr2[arr2.length] = parseInt(Math.random() * 100);
        }

        console.log(arr2);
数组遍历
  • 直接利用for循环
  • for in 关键字遍历
  • for of 关键字遍历
        var arr = [2, 4, 6, 8, 10, 12, 14, , , 0];


        // 数组中为空的元素为 undefined
        for (var i = 0; i < arr.length; i++) {

            console.log(arr[i]);

        }


        // 数组中元素为空的元素,不输出
        //for in    i可以自定义 代表的是角标
        for (var i in arr) {

            console.log(arr[i]);
        }

        //数组中为空的元素为 undefined
       // for  of   val可以自定义 代表的是数组的值
        for (var val of arr) {

            console.log(val);

        }
数组方法
  • pop 删除数组的最后一个元素并返回删除的元素。
  • push 向数组的末尾添加一个或更多元素,并返回新的长度。
  • shift 删除并返回数组的第一个元素。
  • unshift 向数组的开头添加一个或更多元素,并返回新的长度。

day7

数组的深拷贝和浅拷贝

  • 基本数据类型存储的是值—存储在栈内存
  • 引用数据类型存储的是地址—存储在堆内存中
基本数据类型
        var a = 3;
        var b = a;
        a = 5;

        console.log(a, b); //5,3

a的值改变,不影响b的值

基本数据类型存储的是值,存储在栈内存中

浅拷贝
        var arr1 = [1, 2, 3];

        // arr1的改变会影响arr2
        // var arr1 = [1, 2, 3];
        // // 把arr1的地址给了arr2,因此他们指向了同一个地址 --- 浅复制

        var arr2 = arr1;

        arr1.pop();

        console.log(arr1); //[1,2]
        console.log(arr2); //[1,2]

两个数组指向的是同一个地址,一个改变,会影响另一个

深拷贝

深复制 arr1和arr2没有关联

  • 重新声明一个数组
  • 将数组进行遍历,然后赋值
        var arr1 = [1, 2, 3];

        var arr2 = [];

        for (var val of arr1) {
            arr2.push(val);
        }

        arr1.pop();

        console.log(arr1); //[1,2]

        console.log(arr2); //[1,2,3]


       var arr1 = [1, 2];

        var arr2 = arr1;
        //arr1重新指向了一个地址
        arr1 = [8, 9];

        console.log(arr1); //[8,9]

        console.log(arr2); //[1,2]

函数的值传递和引用传递

  • 引用数据类型,实参是把地址传给了函数

            function pop(arr) {
                // 把数组的长度-1
                arr.length = arr.length - 1;
                return arr
            }
    
  • 普通数据类型,实参这是把值传递给函数使用

            // 普通数据类型,实参只是把值传递给函数使用
            function fn(n) {
                n++;
                return n;
            }
            var a = 5;
    
            console.log(fn(a)); //6
    
            console.log(a); //5
    

indexOf封装

        function indexOf(arr, val) {
            for (var i in arr) {
                if (arr[i] === val) {
                    return i;
                }
            }

            return -1;
        }

        var arr = [3, 4, 5, 6];
        console.log(indexOf(arr, 9));


数组常用方法

splice

splice() 方法用于添加或删除数组中的元素。

**注意:**这种方法会改变原始数组

返回值:

返回删除元素的数组

如果仅删除一个元素,则返回一个元素的数组。 如果未删除任何元素,则返回空数组。

可利用此方法实现删除、插入、替换

参数描述
index必需。规定从何处添加/删除元素。 该参数是开始插入和(或)删除的数组元素的下标,必须是数字。
howmany可选。规定应该删除多少元素。必须是数字,但可以是 “0”。 如果未规定此参数,则删除从 index 开始到原数组结尾的所有元素。
item1, …, itemX可选。要添加到数组的新元素
  • 利用splice删除元素

    splice(index,howmany) 删除

        var arr = ["a", "b", "c"];

        //参数:
        // 1:起始下标
        // 2:删除元素的个数
      

        // 元素的删除
        console.log(arr.splice(1, 2)); //["b","c"]

        //改变元素组,删除b,c两个元素
        console.log(arr); //[a]
  • 利用splice替换元素

    splice(index,howmany,val1,val2…) 替换

            var arr = ["a", "b", "c"];
    
            //参数:
            // 起始下标从1开始
            // 删除两个元素
            // 添加两个新的元素
            arr.splice(1, 2, "e", "f");
    
            console.log(arr); //[a,e,f]
    
  • 利用splice插入元素

    splice(index,0,val1,val2…) 插入

            var arr = ["a", "b", "c"];
    
            //参数含义:
            // 1.起始下标从1开始
            //2.删除0个元素
            //3-n:插入的元素
            arr.splice(1, 0, "k", "d", "s");
    
            console.log(arr); //["a", "k", "d", "s", "b", "c"]
    
    
slice

slice()方法可提取字符串的某个部分,并以新的字符串返回被提取的部分。

注意: slice() 方法不会改变原始数组。

参数

参数描述
start可选。规定从何处开始选取。如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取
end可选。规定从何处结束选取(结果不包含end)。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。
 var arr = ["a", "b", "c", "d", "e", "f"];



        //从下标1开始截取,不包含下标3
        console.log(arr.slice(1, 3)); //["b","c"]

        console.log(arr.slice(1)); //["b","c","d", "e", "f"]


        //从倒数第二个开始截取
        console.log(arr.splice(-2)); //["e","f"]

indexOf

查找数组中是否存在某个值,返回角标

不存在返回-1

        var arr = ["a", "b", "c", "d", "e", "f"];


        console.log(arr.indexOf("c")); //2

        console.log(arr.indexOf("k")); //-1
includes

includes 查找数组中是否存在某个值,返回布尔值

        var arr = ["a", "b", "c", "d", "e", "f"];


        console.log(arr.includes("d")); //true

        console.log(arr.includes("t")); //false
join

把数组变成字符串

参数:分隔符

无参数,分隔符默认为,

        var arr = ["a", "b", "c", "d", "e", "f"];

        // 无参数,默认分割符,
        console.log(arr.join()); //a,b,c,d,e,f

        console.log(arr.join("-")); //a-b-c-d-e-f
concat

把数组或者字符串拼接起来

concat() 方法用于连接两个或多个数组或普通类型元素。

参数

参数描述
array2, array3, …, arrayX必需。该参数可以是具体的值,也可以是数组对象。可以是任意多个。
        var arr = ["a", "b", "c"];

        var b = ["d", "e"];

        //连接数组
        console.log(arr.concat(b)); //["a", "b", "c","d","e"]

        //连接基本类型元素
        console.log(arr.concat("hello")); //["a", "b", "c","hello"]



        //不会改变元素组
reverse

数组反转

        var arr = ["a", "b", "c"];

        //会改变元素组
        arr.reverse();

        console.log(arr); //["c","b","a"]



总结
方法说明
splice实现数组 删除/替换/插入元素(改变原元素组)
slice截取数组
indexOf查找数组中是否存在某个值,返回角标
includes查找数组中是否存在某个值,返回布尔值
join把数组变成字符串
concat把数组或者字符串拼接起来
reverse改变原数组 反向 (改变原数组)

arguments

arguments 接收到的实参列表 ,是一个伪数组

有数组的状态,可以拿到长度和角标,但是没有数组的方法(无pop,push,shift等数组方法)

        function fn() {

            //传过来的实参,变成一个数组
            console.log(arguments); //[1,2,3]

            console.log(arguments.length); //3,实参个数

        }

        fn(1, 2, 3);

数组方法封装

push封装
        function push(arr) {
            //第一个参数是数组,不需要遍历,i从1开始

            //遍历arguments实参数组[arr,"a","b"],第一个实参是数组本身,不需要遍历,i从1开始
            for (var i = 1; i < arguments.length; i++) {
                arr.push(arguments[i]);
            }
            return arr;
        }

        var arr = [3, 4, 5];

        push(arr, "a", "b");

        console.log(arr); //[3, 4, 5,"a","b"]
join封装

join: 数组:arr[1,2,3] —>字符串 1&2&3

        function join(arr, fuhao) {

            //连接符号默认为,
            fuhao = fuhao || ",";

            //定义字符串进行拼接
            var res = '';

            //遍历数组
            for (var i in arr) {
                console.log(arr[i]);

                // 字符串拼接上遍历的数组元素
                res += arr[i];

                //如果数组元素不是最后一个,添加上分割符
                // 最后一个,后面没有分割符发
                i < arr.length - 1 ? res += fuhao : res;

            }

            return res;


        }

        var arr = [1, 2, 3];
        console.log(join(arr, "&")); // 1&2&3
concat封装
        function concat(arr1, arr2) {
        
            var newArr = [];

            //遍历实参列表
            for (var i = 0; i < arguments.length; i++) {

                var tempArr = arguments[i];

                //如果参数是数组,则遍历数组,将数组元素一个一个添加到newArr中

                if (Array.isArray(tempArr)) {

                    //遍历数组
                    for (var val of tempArr) {

                        //将值添加入新数组 newArr
                        newArr.push(val);
                    }
                } else {
                    //如果参数是普通元素,直接添加到newArr
                    newArr.push(tempArr);
                }

            }


            return newArr;

        }

        var arr1 = [1, 2, 3];
        var arr2 = [4, 5, 6];

        //连接数组
        console.log(concat(arr1, arr2)); //[1,2,3,4,5,6]

        //连接普通元素
        console.log(concat(arr1, "hi")); //[1,2,3,"hi"]

排序

冒泡排序

请添加图片描述

 var arr = [9, 8, 7, 6, 5];
        // 排序
        // 第一趟   拿到最大值9放在最后面
        // 9 8     8 9 7 6 5
        // 9 7     8 7 9 6 5
        // 9 6     8 7 6 9 5
        // 9 5     8 7 6 5 9

        // 第二趟  拿到倒数第二大的值
        // 8 7     7 8 6 5 9
        // 8 6     7 6 8 5 9
        // 8 5     7 6 5 8 9
        // 8 9

        // 第三趟
        // 7 6    6 7 5 8 9
        // 7 5    6 5 7 8 9
        // 7 8
        // 8 9

        // 第四趟
        // 6 5    5 6 7 8 9
        // 6 7
        // 7 8
        // 8 9
 // 冒泡排序:相邻的两个值进行比较,大的往后排

        // 比较的趟数
        for (var i = 0; i < arr.length - 1; i++) {
            // 相邻的比较
            for (var j = 0; j < arr.length - 1 - i; j++) {
            	//大于前面的值则与前面的值进行交互
                if (arr[j] > arr[j + 1]) {
                    var temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }
            }
        }

  
选择排序

请添加图片描述

  • 从第一个开始,与数组其他的值进行比较
  • 如果小于自身,进行替换
  • 从而保证当前位置总是相对于数组其他元素的最小值
 // 选择排序,拿第一个位置上的 数与后面所有的数进行比较,拿到最小值
        // 比较的趟数
        for (var j = 0; j < arr.length - 1; j++) {
            // 拿第j个位置上的数与后面所有的数进行比较
            for (var i = j + 1; i < arr.length; i++) {
            
            	//大于数组其他元素,进行替换
                if (arr[j] > arr[i]) {
                    var temp = arr[j];
                    arr[j] = arr[i];
                    arr[i] = temp;
                }
            }
        }
        console.log(arr)
选择排序改进

较少交换的次数

将min标记为当前最小的角标

        // 减少比较排序的交换次数

        // 比较的趟数
        for (var j = 0; j < arr.length - 1; j++) {
            // 假设第j个数是最小的
            var min = j;
            for (var i = j + 1; i < arr.length; i++) {
                if (arr[min] > arr[i]) {
                    // 找到最小数的角标
                    min = i;
                }
            }

            if (min != j) {
                var temp = arr[min];
                arr[min] = arr[j];
                arr[j] = temp;
            }
        }

数组去重

  • 方法一

    创建一个新的数组,把不重复的数丢进去

     function quChong(arr) {
     			//创建新数组
                var newArr = [];
                for (var i = 0; i < arr.length; i++) {
                	//如果新数组不包含当前遍历的元素,进行添加push
                    if (!newArr.includes(arr[i])) {
                        newArr.push(arr[i]);
                    }
                }
    
                return newArr;
            }
    
  • 方法二

    • 遍历数组
    • 拿每个元素与后面所有的元素比较,如果相等,则重复,利用splice删除
    • 不相等,继续遍历下一个
       var arr = [1, 4, 2, 4, 2, 1, 1, 1, 5, 3];
            for (var j = 0; j < arr.length; j++) {
                // 拿点前遍历的arr[j]与后面所有的数做比较
                //如果相等,则重复,利用splice删除
                for (var i = j + 1; i < arr.length; i++) {
                    if (arr[j] === arr[i]) {
                    	//利用splice方法删除当前元素
                        // 数组会塌陷 !!!!!!
                        arr.splice(i, 1);
                        i--;
                    }
                }
            }
            console.log(arr)
    

数据统计

方法一

  • 首先将数组去重
  • 遍历去重后的数组,将遍历的元素,在先前的数组中进行计数
  var arr = [3, 3, 3, 2, 2, 5, 6, 3, 0, 6];



        //数组去重
        function noRepeat(arr) {
            var newArr = [];

            for (var val of arr) {
                if (!newArr.includes(val)) {
                    newArr.push(val);
                }
            }

            return newArr;
        }

        function tongJi(arr) {
            //去重数组
            var newArr = noRepeat(arr);

            //遍历原数组
            for (var val of newArr) {
                var count = 0;
                for (var value of arr) {
                    if (value == val) {
                        count++;
                    }
                }


                document.write(val + "出现了" + count + "次" + "<br/>");
            }
        }

        tongJi(arr);

方法二

  • 首先遍历数组元素
  • 从当前元素的后一个开始,看是否有相同的,如果相同则重复,计数器+1,并将其删除(splice)
  • 每次遍历一个元素,计数器都从1开始
        var arr = [3, 3, 3, 2, 2, 5, 6, 3, 0, 6];

        //数组统计
        //找到相同的则删除一个 ,并计数
        for (var i = 0; i < arr.length; i++) {
            var count = 1;
            for (var j = i + 1; j < arr.length; j++) {
                if (arr[i] == arr[j]) {
                    count++;
                    //删除当前找到的,重复的
                    arr.splice(j, 1);
                    //防止数组塌陷!!
                    j--;
                }
            }

            document.write(arr[i] + "出现了" + count + "次" + "<br/>");
        }

方法三

  • 首先将数组排序

    [3, 3, 3, 2, 2, 5, 6, 3, 0, 6]

    排序后:

    [0, 2, 2, 3, 3, 3, 3, 5, 6, 6]

  • 然后遍历数组,如果后面的值与其相同,则计数器+1,否则,后面无相同的数据,数组下标从当前数组+count(计数器)开始,遍历下一个元素

 //数组统计
       svar arr = [3, 3, 3, 2, 2, 5, 6, 3, 0, 6];
       arr.sort();
        console.log(arr);

        for (var i = 0; i < arr.length;) {
            var count = 0;

            for (var j = i; j < arr.length; j++) {
                if (arr[i] === arr[j]) {
                    count++;

                } else {
                    break;
                }
            }

            document.write(arr[i] + "出现了" + count + "次" + "<br/>");
            i += count;
        }

day8

回顾

1.数据类型
基本数据类型 number string boolean null undefined
引用数据类型 array object
区别
基本数据类型存储在栈内存中,变量实际上存储的是值
引用数据类型存储在堆内存中,变量实际上存储的是地址
数组的深拷贝和浅拷贝
浅拷贝  拷贝的是地址  --- 共享一个地址
深拷贝  拷贝的是值  -- 不会共享地址

3 函数的值传递和引用传递
值传递指的是普通数据类型
 引用传递指的是引用数据类型  传递的实际上是地址(形参和实参共享一个地址)
 
4数组的基本方法
pop
push
shift unshift

5.数组常用方法
splice 删除  替换  插入
slice[startindex,endindex)  截取数组  
indexOf
includes
join    数组转字符串
concat
reverse

6.数组的方法的封装
arguments  接收实参的方式   伪数组
函数的引用传递
需要改变原数组,就操作原数组   如果不需要改变原数组,就声明一个新的数组

7.数组的排序
冒泡排序  相邻的做比较   j  j+1
选择排序
i  j(i+1)  作比较   一边比较一边交换
i  j(i+1)    作比较只记录角标  最后才做交换

8.数组的去重
方法一:
	把不重复的值放进新数组
		创建新数组
		遍历原数组,判断原数组中的值在新数组中是否存在,不存在就push
		 if (!newArr.includes(arr[i]))
		 
方法二:
	把重复的删掉
	拿原数组中的每一个值与后面的每一个值进行比较,如果重复就删除后面的值
		for(var i = 0 ; i < arr.length ; i++)
			 for(var j = i + 1 ; j < arr.length ; j++)
			 	数组塌陷  j--

作业

  • 找到数组的最大值和最小值

     function minAndMaxFromArr(arr) {
                // 需要返回两个值,因此返回一个数组
                var newArr = [];
                // 假设第一个值是最小的,然后拿后面的每一个值与第一个做比较,记录较小的这个值的角标
                var min = 0;
                var max = 0;
                //遍历数组
                for (var i in arr) {
                    // 找最小值的角标
                    if (arr[min] > arr[i]) {
                        min = i
                    }
                    // 找最大值的角标
                    if (arr[max] < arr[i]) {
                        max = i;
                    }
                }
                newArr.push(arr[min])
    
                // var max = 0;
                // for (var i in arr) {
                //     if (arr[max] < arr[i]) {
                //         max = i
                //     }
                // }
                newArr.push(arr[max]);
    
                return newArr
            }
    
            console.log(minAndMaxFromArr([4, 1, 2, 7, 5, 3]))
    

数组插入一个值

实现数组的插入值:找到插入的位置,找角标

  • 最前面 插入的值比第一个更小
  • 最后面 插入发值比最后一个还大
  • 中间某个位置 插入的值比前一个大,比后一个小
// 实现数组的插入值:找到插入的位置,找角标
        // 最前面   插入的值比第一个更小
        // 最后面   插入发值比最后一个还大
        // 中间某个位置  插入的值比前一个大,比后一个小
        function insert(arr, n) {
            var index;
            if (n < arr[0]) {
                index = 0;
            }
            if (n > arr[arr.length - 1]) {
                index = arr.length
            }
            for (var i = 0; i < arr.length; i++) {
                if (n >= arr[i] && n <= arr[i + 1]) {
                    index = i + 1;
                    break;
                }
            }

            arr.splice(index, 0, n)
        }

        var arr = [2, 4, 7, 8, 9, 9, 10];
        insert(arr, 9);
        console.log(arr)

统计

        //数组去重
        function noRepeat(arr) {
            var newArr = [];
            for (var i in arr) {
                if (!newArr.includes(arr[i])) {
                    newArr.push(arr[i])
                }
            }
            return newArr
        }

        // 先去重得到新数组
        // 拿新数组中的每一个值与原数组中的每一个值进行比较,如果相等就计数
        // function countArr(arr) {
        //     var newArr = noRepeat(arr);
        //     console.log(newArr);
        //     // 拿新数组中的每一个值与原数组中的每一个值进行比较,如果相等就计数
        //     for (var i in newArr) {
        //         var count = 0;
        //         for (var j in arr) {
        //             if (newArr[i] === arr[j]) {
        //                 count++;
        //             }
        //         }
        //         document.write(newArr[i] + '出现的次数是' + count + '次' + '<br>')
        //     }
        // }


        // // 3 2 5 6 0
        // var arr = [3, 3, 3, 2, 2, 5, 6, 3, 0, 6];
        // countArr(arr)

方法二

 // 第二种方法
        // 拿数组中的每一个值与后面的每一个值进行比较

        // function countArr(arr) {
        //     for (var i = 0; i < arr.length; i++) {
        //         var count = 1;
        //         for (var j = i + 1; j < arr.length; j++) {
        //             if (arr[i] === arr[j]) {
        //                 arr.splice(j, 1);
        //                 j--; //防止数组塌陷
        //                 count++;
        //             }
        //         }
        //         document.write(arr[i] + '出现的次数是' + count + '次' + '<br>')
        //     }
        // }
        // var arr = [3, 3, 3, 2, 2, 5, 6, 3, 0, 6];
        // countArr(arr)



      

方法三

  // 0,2,2,3,3,3,3,5,6,6

        // 先进行排序
        // 再排序后的数组中的不重复的值拿出来统计
        function countArr(arr) {
            arr.sort();
            console.log(arr);
            // [0, 2, 2, 3, 3, 3, 3, 5, 6, 6]
            for (var i = 0; i < arr.length;) {
                var count = 0;
                for (var j = i; j < arr.length; j++) {
                    if (arr[i] === arr[j]) {
                        count++
                    }
                    else {
                        break;
                    }
                }
                document.write(arr[i] + '出现的次数是' + count + '次' + '<br>');

                i += count;
            }


        }
        var arr = [3, 3, 3, 2, 2, 5, 6, 3, 0, 6];

数组扩展方法

forEach:迭代方法

  • sort(function(a,b){return a-b}):排序
  • forEach(function(val,i,arr){}:遍历数组,没有返回值
  • map 同一种规律去改变数组中的每一个值 map(function(val,i,arr){return val…}) 一定要有返回值
  • some:判断数组中是否有一个值满足条件 返回的是布尔值 some(function(val,i,arr){return val > 18})
  • filter:过滤器 把数组中满足条件的值筛选出来 返回的是新的数组 filter(function(val,i,arr){return val > 18})
  • reduce:reduce 把数组当中的值变成一个值(比如求和) reduce(function(total,val,i,arr){return total += val})
        var arr = [3, 2, 12, 45, 65, 5, 51];
        // 按照ASCII升序排列
        // arr.sort();

        // console.log(arr);

        // // sort括号里面,是一个实参,是一个匿名函数
        // arr.sort(function (a, b) { return b - a });
        // console.log(arr)

        var sum = 0;
        arr.forEach(function (val, i, arr) {
            console.log(val)
            sum += val;
        })
        console.log(sum)


        var arr = [1, 2, 3, 4];
        var res = arr.map(function (val, i, arr) {
            return val += 2
        })
        console.log(res); //[2,4,5,6] 将数组中的值都+2


        var arr = [16, 26, 38, 8];
        var res = arr.every(function (val, i, arr) {
            return val > 18
        });//判断数组中每个值是否都大于18,
        console.log(res) //false

		
        var arr = [16, 26, 38, 8];
        var res = arr.some(function (val, i, arr) {
            return val > 20
        }) //判断数组中是否有值大于20,大于返回true,都小于返回false
        console.log(res) //true


        var arr = [16, 26, 38, 8];
        var res = arr.filter(function (val, i) {
            return val > 20
        }); //过滤数组中,都大于20的值,返回的依然是数组
        console.log(res) //[26,38] 



        var arr = [16, 26, 38, 8];
        var res = arr.reduce(function (sum, val, i, arr) {
            return sum += val;
        }) //求和,sum形参为初始值,0
        console.log(res)

回调函数

回调函数:函数作为参数

	//自行封装的forEach方法,
	//参数:1.要遍历的数组,第二个参数,一个函数,此函数可包含两个参数,分别是数组中的每个值,数组下标数组本身
	function forEach(arr, fn) {

            for (var i in arr) { //循环遍历数组
                // 函数实际调用的地方  实参
                fn(arr[i], i, arr)
            }
        }

        var newArr = [];
        forEach([1, 2, 3], function (a, i) { 
            console.log(a)
            newArr[i] = a;
        })

        function rand(min, max, fn) {
            var num = min + parseInt(Math.random() * (max - min));
            // console.log(n);
            // document.write(n)
            // 实际调用函数的地方
            fn()
        }
        
        
        // 这个匿名函数是声明的地方
        rand(10, 20, function () {
            console.log(6)
        })
every封装

数组中只要有一个不满足条件,返回ture,都满足条件才返回false

<script>
        function every(arr, fn) {
            for (var i in arr) {
                if (!fn(arr[i], i, arr)) { //传值给fn,如果fn一旦不满足条件,则是true
                    return false
                }
            }
            return true
        }


        var res = every([1, 2, 3], function (val, i, arr) {
            return val > 1
        })
        console.log(res)
    </script>

二维数组

   // var arr = [1, 2, 4, 5];
        var arr = [
            [1, 2, 3],
            [4, 5, 6],
            [7, 8, 9]
        ];
        
   // 取值
  // console.log(arr[0][0]);
  
  
  
  //遍历
  
   		// arr.forEach(function (val) {
        //     // console.log(val);
        //     val.forEach(function (item) {
        //         console.log(item)
        //     })
        // })

        for (var i = 0; i < arr.length; i++) {
            for (var j = 0; j < arr[i].length; j++) {
                console.log(arr[i][j])
            }
        }

字符串

字符串声明

  • 字面量声明
  • 对象声明
 		// 字符串的声明方式  字面量声明
        var str = 'hello';
        // var str = new String('hello');
        console.log(str);
        // 长度
        console.log(str.length);
        // 角标
        console.log(str[2]);
        // 字符串的长度和角标对应的值只能读不能改写
        // str[1] = 'w';  // 错误
字符串遍历
        var str = 'hesvdv';
        // for (var i = 0; i < str.length; i++) {
        //     console.log(str[i])
        // }


        // for (var i in str) {
        //     console.log(str[i])
        // }

        // for (var val of str) {
        //     console.log(val)
        // }
字符串方法
  • charAt 角标对应的字符

  • charCodeAt 角标对应的字符对应的ASCII

  • String.fromCharCode 把ASCII转成对应的字符

  • indexOf

  • includes

  • toUpperCase

  • toLowerCase

 <script>
        var str = 'hahahaW';
        console.log(str.charAt(2)) //h
        console.log(str[2]) //h


        console.log(str.charCodeAt(0)) //104

        console.log(String.fromCharCode(104)); //h

        console.log(str.toUpperCase()) //HAHAHAW

        console.log(str.toLowerCase()) //hahahaw

        console.log(str.indexOf('a')) //1

        console.log(str.indexOf('ah'));  // 1


        console.log(str.includes('ah')); //true
 </script>

验证码

准备工作

 <script>
        // var arr = [0,1,2,3,4,5,6,6]

        var numArr = [];
		//0-9d的数组
        for (var i = 0; i < 10; i++) {
            numArr.push(i)
        }
		
		//A-Z大写字母
        var bigArr = []
        for (var i = 65; i <= 90; i++) {
            var str = String.fromCharCode(i);
            bigArr.push(str)
        }
	
		//a-z小写字母
        var smallArr = []
        for (var i = 97; i <= 122; i++) {
            var str = String.fromCharCode(i);
            smallArr.push(str)
        }

        var arr = numArr.concat(bigArr, smallArr)



        console.log(arr)


        // 验证码必须包含小写,大写和数字
   </script>

作业

        // 1 数组的去重
        // 2 数组的统计
        // 3 数组的迭代方法  回调函数
        // 4 动态生成表格  forEach ********************
        // 5 验证码及验证(不区分不大小写,必须有数字和字母)
        // 6 自己封装 toUpperCase   toLowerCase

day9

回顾

// 数组
        // 引用数据类型   堆和栈
        // 深复制和浅复制
        // 函数的值传递和引用传递
        // 基本方法
        // pop  push unshift  shift
        // 常用方法
        // splice slice indexOf  includes  join  concat  reverse
        // 迭代方法
        // forEach  map  every  some  filter  reduce   sort
        // 排序  
        // 去重
        // 统计
        // 多维数组 动态表格的生成
        // 回调函数

  // 字符串的声明方式
        // 字面量声明,直接声明
        var str = '';
        var arr = [];

        // 实例化对象
        var str = new String('hello');
        var arr = new Array();

        // 角标和长度
            // 数组的角标和长度可读可写
            // 字符串的角标和长度可读不可写

        // 字符串遍历   for   for in   for of 

        // 字符串的基本方法
            // charAt(i)     [i]
            // charCodeAt(i)    ASCII 
            // String.fromCharCode(ASCII)  字符

        // 字符串的常用方法
            // indexOf  查找字符串
            // includes
            // toUpperCase
            // toLowerCase

大小写封装

        function upperCase(str) {
            // 字符串本身无法修改,搞一个新的字符串做拼接 +
            var res = '';
            for (var i = 0; i < str.length; i++) {
                // res += str.charAt(i)
                var code = str.charCodeAt(i);
                // 判断小写
                if (code >= 97 && code <= 122) {
                    code -= 32;
                    res += String.fromCharCode(code)
                } else {
                    res += str.charAt(i)
                }
            }
            return res
        }

验证码

在这里插入图片描述
    <span id="showCode"></span>
    <input type="text" id="inp">
    <input type="button" id="refresh" value="刷新">
    <br>
    <input type="button" value="验证" id="btn">

    <script>

 	$('showCode').innerHTML = code(4);

        $('refresh').onclick = function () {
            $('showCode').innerHTML = code(4);
        }

        $('btn').onclick = function () {
            var codes = $('showCode').innerHTML;
            var inpValue = $('inp').value;
            if (codes.toLowerCase() === inpValue.toLowerCase()) {
                // alert('验证成功')
                // 页面的跳转
                location.href = 'http://www.baidu.com'
            } else {
                $('showCode').innerHTML = code(4);
                alert('验证失败')
            }
        }



        var numArr = [];
        for (var i = 0; i < 10; i++) {
            numArr.push(i)
        }
        var bigArr = [];
        for (var i = 65; i <= 90; i++) {
            bigArr.push(String.fromCharCode(i))
        }
        var smallArr = [];
        for (var i = 97; i <= 122; i++) {
            smallArr.push(String.fromCharCode(i))
        }

        var allArr = numArr.concat(bigArr, smallArr);
        console.log(allArr);



        function $(id) {
            return document.getElementById(id);
        }

		//随机生成0-n的随机数
        function rand(n) {
            return parseInt(Math.random() * n)
        }
        
        
         // 数字,小写,大写各取一个,随机再取剩下的
        // 打乱顺序  -- 字符串不能改变  数组可以改变
        // 把生成的验证码放进数组
        function code(n) {
            n = n || 4;
            var arr = [];
            arr.push(numArr[rand(numArr.length)]);
            arr.push(bigArr[rand(bigArr.length)]);
            arr.push(smallArr[rand(smallArr.length)]);

            for (var i = 0; i < n - 3; i++) {
                arr.push(allArr[rand(allArr.length)]);
            }

            // 打乱数组
            for (var i = 0; i < arr.length; i++) {
            	//随机交换顺序
                var num = rand(arr.length);
                var temp = arr[i];
                arr[i] = arr[num];
                arr[num] = temp;
            }
            console.log(arr)

            return arr.join('');
        }
        
 </script>    

字符串方法

  • indexOf
  • includes
  • toUpperCase
  • toLowerCase
  • substring[startIndex,endIndex) 截取字符串
  • substr(index,howmany) 截取字符
  • replace 替换
  • trim 去掉首尾的空格
  • split 字符串转为数组
	 	var str = 'good good study , day day up';

        var res = str.substring(1, 3); 
        console.log(res) //oo

        var res = str.substr(2, 3);
        console.log(res) // od空格

        var str = '卧槽,字符串真简单';
        var res = str.replace('卧槽', '**');
        console.log(res); // **,字符串真简单

        var str = '   dvdv  csv   a       ';
        console.log(str.trim()); // dvdv  csv   a


        var str = 'hello';
        var str = 'good&good&study';
        console.log(str.split('&')) // ["good", "good", "study"]

随机5位数

   // 随机5位以内的数,输出每一位分别是多少?
        // 0 - 100000   0 - 99999     
        // var arr = ['个','十','百','千','万']

        var str = parseInt(Math.random() * 100000) + '';
        console.log(str);
        // var arr = ['万', '千', '百', '十', '个']
        var arr = ['个', '十', '百', '千', '万']
        for (var i = 0; i < str.length; i++) {
            console.log(arr[str.length - 1 - i] + ':' + str[i])
        }

切割字符串

        // 1 拿到问号后面的一串
        var str = 'http://127.0.0.1:5500/day09/1.php?user=www&pwd=123123&repwd=123123&code=asda';
        var str2 = str.split('?')[1];
        console.log(str2);
        var arr = str2.split('&');
        console.log(arr);
        // ["user=www", "pwd=123123", "repwd=123123", "code=asda"]

        for (var i in arr) {
            arr[i] = arr[i].split('=')
        }



        // arr = arr.map(function (val) {
        //     return val.split('=')
        // })
        // console.log(arr)


  

压缩统计

<script>
        // 压缩统计 'asdasdsfda'   =>  'a3s3d3f1'
        function countStr(str) {
            // 放最终统计的结果
            var res = '';
            // 字符串去重
            // 创建一个新的字符串,不重复的字符放进新的字符串
            var str2 = '';
            for (var i in str) {
                if (!str2.includes(str[i])) {
                    str2 += str[i]
                }
            }
            // 统计
            for (var i in str2) {
                var count = 0;
                for (var j in str) {
                    if (str2[i] === str[j]) {
                        count++;
                    }
                }
                res += str2[i] + count;
            }

            return res
        }

        console.log(countStr('asdasdsfda'))
    </script>

对象

引用数据类型:数组和对象

  • 数组是有序的,对象是无序的
  • 对象的键名不能重复,后面覆盖前面
字面量声明
// 字面量声明
        var obj = {
            // 键名 :键值
            name: '思文',
            age: '28',
            hobby: '思文',
            say: function () {
                console.log('我不高兴了')
            },
            name: '丁旭',
        };
        
        
         // 读数据
        console.log(obj.name);
        obj.say();
        console.log(obj['name']);
对象遍历
        for (var i in obj) {
            console.log(i);
            // i是一个变量  obj[i]
            console.log(obj[i])
        }
        
        
         // var arr = [1, 2, 3];
        // for (var i in arr) {
        //     console.log(i)   //字符串
        // }


        // var arr = {
        //     length: 10,
        //     push: function () { },
        //     pop: function () { }
        // }

        // arr.length
        // ar.pop()
实例化对象
        var obj = new Object();
        obj.name = 'jennie';
        obj.age = 28;
        obj.say = function () {
            console.log(this.name);

        }




        // 在对象里面,this指点对象本身
        obj.say();


        var arr = new Array();
        arr[0] = 1;
        arr[1] = 2;

数组+对象

        var data = [
            {
                name: '丁旭',
                age: '28'
            },
            {
                name: '丁旭2',
                age: '282'
            },
            {
                name: '丁旭3',
                age: '283'
            }
        ]


        data.forEach(function (val) {
            for (var key in val) {
                console.log(val[key])
            }
        })

动态生成商品列表

<body>

    <div class="search">
        <input type="text" id="inp">
        <input type="button" value="搜索" id="btn">
    </div>

    <ul class="list" id="list">

    </ul>



    <script>
        var data = [
            {
                goods: '手机',
                price: '20¥',
                title: '黑鲨4 磁动力升降肩键',
                img: '../images/1.png'
            },
            {
                goods: '手机',
                price: '10¥',
                title: '小米11 青春版 轻薄',
                img: '../images/1.jpg'
            },
            {
                goods: '电视',
                price: '200¥',
                title: '小米全面屏电视65英寸 E65X',
                img: '../images/1.png'
            },
            {
                goods: '电视',
                price: '100¥',
                title: '小米电视4A 70英寸',
                img: '../images/2.jpg'
            },
            {
                goods: '衣服',
                price: '20¥',
                title: '衣服真显瘦',
                img: '../images/3.jpg'
            },
            {
                goods: '帽子',
                price: '10¥',
                title: '帽子真百搭',
                img: '../images/1.png'
            },
            {
                goods: '衣服2',
                price: '200¥',
                title: '衣服真显瘦',
                img: '../images/1.png'
            },
            {
                goods: '帽子2',
                price: '100¥',
                title: '帽子真百搭',
                img: '../images/1.png'
            }
        ]

        renderUl(data);

        $('btn').onclick = function () {
            var wd = $('inp').value;
            // 筛选数据   把满足条件的数据筛选出来   filter
            var res = data.filter(function (val) {
                return val.goods.includes(wd)
            })
            console.log(res);
            renderUl(res)
        }


        function renderUl(data) {
            var res = '';
            data.forEach(function (val) {
                // res += '<li><img src="../images/1.jpg" alt=""><h3>电视</h3><p>电视真好汗啊</p><strong>9999¥</strong></li>'
                // ``模板字符串
                res += `
                <li>
                    <img src="${val.img}" alt="">
                    <h3>${val.goods}</h3>
                    <p>${val.title}</p>
                    <strong>${val.price}</strong>
                </li>
            `
            })
            $('list').innerHTML = res;
        }





        function $(id) {
            return document.getElementById(id)
        }

表单验证

    <p>用户要求:名字只能包含数字、字母,数字不可以开头,长度不低于6,不长于12 [0-9 a-z A-Z]</p>
    <p>
        <label for="user">用户名</label>
        <input id="user" name="user" type="text">
        <span id="user_span">错误提示</span>
    </p>
    <p>密码6-12位 不能包含特殊字符 (弱 z/1/A 中 包含两种 强 包含三种)</p>
    <p>
        <label for="pwd">密码</label>
        <input id="pwd" name="pwd" type="text">
        <span id="pwd_span"></span>
    </p>
    <p>确认密码 两次输入相同</p>
    <p>
        <label for="repwd">确认密码</label>
        <input id="repwd" name="repwd" type="text">
        <span id="repwd_span"></span>
    </p>
    <p>随机4位验证码(点击切换验证码)</p>
    <p>
        <label for="code">验证码</label>
        <input id="code" name="code" type="text">
        <span id="random_code"></span>
        <button id="refresh">刷新验证码</button>
        <span id="code_span"></span>
    </p>
    <button id="btn">注册</button>


    <script>

        var numArr = [];
        for (var i = 0; i < 10; i++) {
            numArr.push(i)
        }
        var bigArr = [];
        for (var i = 65; i <= 90; i++) {
            bigArr.push(String.fromCharCode(i))
        }
        var smallArr = [];
        for (var i = 97; i <= 122; i++) {
            smallArr.push(String.fromCharCode(i))
        }

        var allArr = numArr.concat(bigArr, smallArr);
        console.log(allArr);




        $('btn').onclick = function () {
            // 验证用户名
            var uname = $('user').value;
            //  是否输入
            if (!uname) {
                $('user_span').innerHTML = '输入不能为空';
                $('user_span').style.color = 'red'
                return
            }
            //  输入长度
            if (uname.length < 6 || uname.length > 12) {
                $('user_span').innerHTML = '长度必须在6-12之间';
                $('user_span').style.color = 'red'
                return
            }

            //  输入的第一个是不是数字
            if (!isNaN(uname[0])) {
                $('user_span').innerHTML = '第一位不能是数字';
                $('user_span').style.color = 'red'
                return
            }

            //  是否有非法字符   遍历整个用户名
            for (var i = 0; i < uname.length; i++) {
                if (allArr.indexOf(uname[i]) == -1) {
                    $('user_span').innerHTML = '只能由数字和字母组成';
                    $('user_span').style.color = 'red'
                    return
                }
            }

            $('user_span').innerHTML = '√';
            $('user_span').style.color = 'green'

            // 验证密码

            // 验证码
        }



        function $(id) {
            return document.getElementById(id)
        }

day11

延时器改为定时器

函数递归,自调用

延时器相对定时器,更加灵活,延时器可以指定,第一次为某个时间出发,之后,当这个延时器结束后,再隔多长时间触发

        //第一次调用
        setTimeout(fn, 4000);

        function fn() {

            //操作 
            console.log(666);


            //再次调用自己 
            setTimeout(fn, 2000); //每两秒调用自己
        }
        fn();

        function fn() {

            //操作 
            console.log(666);


            //再次调用自己 
            setTimeout(fn, 2000); //每两秒调用自己
        }
定时器bug
  • 异步 定时器与延时器异步程序
  • 定时器叠加问题
  • 全局变量和局部变量理解
定时器叠加问题

定时器会进行叠加,每次点击按钮,都会触发一个定时器,以至于–速度变快

        var btn = document.getElementById("btn");

        btn.onclick = function () {

            var timer = setInterval(function () {

                btn.innerHTML--;

            }, 1000);
        }

需要在点击时,关闭前一个定时器

        var btn = document.getElementById("btn");

        btn.onclick = function () {

            clearInterval(timer);

            var timer = setInterval(function () {

                btn.innerHTML--;

            }, 1000);
        }

此时关闭前一个定时器失败,因为timer为局部变量,相当于一下代码

 btn.onclick = function () {

            var timer;

            clearInterval(timer);

             timer = setInterval(function () {

                btn.innerHTML--;

            }, 1000);
        }

需将定时器变为全局变量

        var btn = document.getElementById("btn");

        var timer;

        btn.onclick = function () {



            clearInterval(timer);

            timer = setInterval(function () {

                btn.innerHTML--;

            }, 1000);
        }

BOM

js:ECMAscript(基础语法,所有的浏览器都支持基础语法) + BOM(浏览器) + DOM(标签)

BOM : browser object model

window对象

window对象 属于浏览器的内置对象 打开一个浏览器也就生成一个window对象

不同的浏览器窗口不共享window对象

  • 变量本质上是window对象的自定义属性
  • 函数本质上是window对象的自定义方法
    <script>
        //window的自定义属性
        var a = 'hello';
        console.log(a);
        console.log(window.a);

        //window的自定义方法
        function fn() {
            console.log(666);

        }


        fn();

        window.fn();
    </script>
BOM常见属性
navigator

浏览器名称等相关信息

userAgent属性

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36

可用其判断手机型号

    <script>
        console.log(navigator);

        console.log(navigator.userAgent); // Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36

        var type = navigator.userAgent;

        if (type.includes('Android')) {
            console.log('安卓');

        }

        if (type.includes('iPhone')) {
            console.log('爱疯');

        }

        if (type.includes('Windows')) {
            console.log('Windows电脑');

        }

    </script>
history

历史记录

DOM
  • document (整个文档)
  • document.documentElement (html)
  • document.doctype(文档类型)
  • document.head (头部)
  • document.body (body)
  • document.title (可读可写)
        console.log(document);

        console.log(document.documentElement);

        console.log(document.doctype);

        console.log(document.head);

        console.log(document.body);

        console.log(document.title);

day12

BOM的方法

window.open

打开页面(会在新窗口打开页面【与a标签的target=_blank一致】)

        setTimeout(function () {
        	//在新窗口中打开  自动拦截
            window.open("http://www.mi.com");
            
        }, 2000);
window.close()

关闭当前窗口

     setTimeout(function () {
            close();
        }, 2000);

Window对象的事件

window.onfocus

获取焦点事件

        window.onfocus = function () {
            console.log("获取");

        }
window.onblur

失去焦点

        window.onblur = function () {
            console.log("失去焦点");

        }

页面打开的时候,页面没有焦点(既没有失去,也没有获取)

window.onscroll

滚动条滚动事件

滚动事件是一个频繁触发的事件

        window.onscroll = function () {
            console.log(666);
        }
window.resize
        window.onresize = function () {
        
            console.log(666);

        }

高频率触发事件,性能差 解决方法:每300毫秒监听一次

        window.onscroll = function () {
            setTimeout(function () {
                console.log(666);

            }, 3000)
        }

onload

等页面资源加载完毕之后,再执行函数

    <script>
        //等页面所有资源加载完毕之后,再执行函数
        window.onload = function () {

            console.log(document.getElementById("test").innerHTML);
        }

    </script>
</head>

<body>

    <div id="test">BLACK</div>

    <script>
        //先加载
        console.log(document.getElementById("test").innerHTML + "**");
    </script>

DOM

DOM:document object model 有兼容问题

页面的几种宽高
  • 浏览器的宽高
  • 页面的实际宽高
  • 页面被卷取的宽高
clientWidth

浏览器可用宽度(可视宽高)

  • clientWidth
  • clientHeight
   <style>
        body {
            height: 3000px;
            width: 3000px;
        }
    </style>

    <script>


        //浏览器可视宽高(跟随窗口大小)
        console.log(document.documentElement.clientWidth);

        console.log(document.documentElement.clientHeight);


    </script>
scrollHeight

页面实际宽高

    <script>


        //浏览器可视宽高
        console.log(document.documentElement.clientWidth);

        console.log(document.documentElement.clientHeight);

        //页面实际宽高

        console.log(document.documentElement.scrollHeight + "*"); //3000
        console.log(document.documentElement.scrollWidth + "*"); //2000



        
        
    </script>
scrollTop

被卷取的高度/宽度

  • scrollTop
  • scrollLeft
        //被卷取的高度/宽度
        console.log(document.documentElement.scrollTop);
        console.log(document.documentElement.scrollLeft);
兼容问题

浏览器的不同,或文档类型未申明时,获取方式不同

有时需要用document.docuentElement,有时需要docuent.body.clientHeight…

文档申明

<!DOCTYPE html>

兼容写法

        //兼容写法

        var root = document.documentElement || document.body;

        console.log(root.scrollHeight);
        console.log(root.clientHeight);
        console.log(root.scrollTop);

返回顶部
    <script>

        //回到顶部
        window.onload = function () {
            var oA = document.getElementById("back");
            var root = document.documentElement || document.body;
            oA.onclick = function () {
                //定时器需要被关闭
                var t = setInterval(function () {
                    root.scrollTop -= 50;
                    //滚动条到达顶部时,清除定时器
                    if (root.scrollTop <= 0) {

                        clearInterval(t);
                        //滚动条的位置置零,否则可能 影响下一次点击事件
                        root.scrollTop = 0;
                    }
                }, 10);
            }
        }
    </script>
    
    
    <body>

    <!-- 阻止a标签的跳转 -->
    <a href="javascript:;" id="back">返回顶部</a>

	</body>
Dom元素获取
获取元素
getElementById

通过id获取元素

获取第一次出现的元素

    <div id="a">1</div>
    <div id="a">2</div>
    
    
    <script>
        console.log(document.getElementById("a")); // <div id="a">1</div>
    </script>
getElementsByClassName()

通过类名获取

获取的数组(伪数组)

即使只有一个元素,获取的也是伪数组

    <p class="p">c</p>
    <p class="p">d</p>
    
    
      <script>

        //得到的是一个数组 (伪数组,长度不可修改)
        //length = 2
        console.log(document.getElementsByClassName('p')); //HTMLCollection(2) [p.p, p.p]]

console.log(document.getElementsByClassName('p')[0].innerHTML); //c
    </script>
getElementsByTagName

通过标签获取元素

获取的也是伪数组

    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
        var oLis = document.getElementsByTagName('li');

        console.log(oLis); //HTMLCollection(5) [li, li, li, li, li
        
        
        
getElementsByName

获取到的也是伪数组

有兼容问题,并且并不是所有标签都有name属性

    <input type="text" name="username">
    <input type="text" name="pwd">

    <script>

        //同样得到的是数组
        console.log(document.getElementsByName('pwd'));
querySelector

ES6新增

拿到第一次出现的元素

 <div id="a">a</div>
 
        console.log(document.querySelector('#a'));
        console.log(document.querySelector('#a').innerHTML); //a

querySelector永远只能查到一个元素

    <div>1</div>
    <div>2</div>

    <script>


        console.log(document.querySelector('div')); //<div>1</div>

querySelectorAll

通过选择器,查询到所有符合条件的DOM

返回的是数组

    <div>1</div>
    <div>2</div>

    <script>


        console.log(document.querySelectorAll('div')); //NodeList(2) [div, div]
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
    </ul>
    
    
        //获取第三个li
        var oLi = document.querySelector('ul li:nth-child(3)');


        console.log(oLi);


        //拿到 2,3,4,5 li
        // var oLis = document.querySelectorAll('ul li +li'); //兄弟选择器
        var oLis = document.querySelectorAll('ul li:not(:first-child)'); //兄弟选择器

        console.log(oLis);
DOM内容操作
  • value
  • innerHTML 可解析标签
  • innerText (无法解析标签)
    <h1>xx</h1>

    <script>

        var oH1 = document.querySelector('h1');

        oH1.innerHTML = '<span>新增的</span>';

    </script>
    <h1>xx</h1>

    <script>

        var oH1 = document.querySelector('h1');

        oH1.innerText = '<span>新增</span>'

    </script>
DOM属性操作
atrributes

对象

拿到所有的属性

    <a href="#" target='_blank' title='鼠标悬停显示' kkk='哈哈哈'></a>


    <script>

        var ele = document.querySelector('a');

		//对象
        // NamedNodeMap {0: href, 1: target, 2: title, 3: kkk, href: href, target: target, title: title, kkk: kkk, length: 4}
        console.log(ele.attributes);
        
        
        console.log(ele.attributes.title); //title='鼠标悬停显示'

        console.log(ele.attributes.target); //target='_blank'

        console.log(ele.attributes.kkk); //kkk='哈哈哈'
直接写法

元素.属性

  • 自有属性可直接获取
  • 自定义属性拿不到,不可获取 undefined
  • 获取class属性,需要用 className(ele.className)
    <a href="#" target='_blank' title='鼠标悬停显示' kkk='哈哈哈'></a>


    <script>

        var ele = document.querySelector('a');



        //直接拿到值
        console.log(ele.title); //鼠标悬停显示

        //不可以获取自定义属性
        console.log(ele.kkk); //undefined
getAttribute

元素.getAtrribute(‘属性’)

  • 可获取自定义属性
    <a href="#" target='_blank' title='鼠标悬停显示' kkk='哈哈哈'></a>


    <script>

        var ele = document.querySelector('a');

        console.log(ele.getAttribute('title')); //鼠标悬停显示

        console.log(ele.getAttribute('kkk')); //哈哈哈
获取属性总结
  • attributes 拿带所有属性,对象
    • attributes.属性 可以拿到任意的属性 (属性 = 属性值)
  • getAttribute(‘属性’)
    • 可以拿到所有的属性值
  • ele.属性
    • 只能拿到自有属性 ele.className ,ele.id
    • 拿不到自定义属性
设置类属性
        #red {
            color: red;
        }
    </style>

</head>

<body>

    <a href="javascript:;" class='head' target='_blank' title='鼠标悬停显示' kkk='哈哈哈'>xx</a>


    <script>

        var a = document.querySelector('a');

        a.onclick = function () {
            a.id = 'red';
            //直接替换原来的class属性
            a.className = 'test';
        }
  .head {
            font-size: 40px;
        }

        .b {
            background-color: pink;
        }
    </style>

</head>

<body>

    <a href="javascript:;" class="head" title='鼠标悬停显示' kkk='哈哈哈'>xx</a>


    <script>

        var a = document.querySelector('a');



        a.onclick = function () {
            //(替换或新增)会直接替换原来的class属性值
            // a.className = 'b';

			//添加类名 += ' 类名'
            a.className += ' b'

        }

classList

问题引入

实现移除一个类名

    <p class="a b c">哈哈</p>

    <script>

        var oP = document.getElementsByTagName('p')[0];

        oP.className -= 'c'; //  <p class="NaN">哈哈</p>

ele.classList

  • 是一个数组
        var oP = document.getElementsByTagName('p')[0];
        
   		//字符串(可替换或拼接 )
        console.log(oP.className); //a b c


        //数组(可删除、新增、替换。。。)
        console.log(oP.classList); //DOMTokenList(3) ["a", "b", "c", value: "a b c"]

     
        

使用

  • add(类名) 新增类
  • remove() 移除类
  • replace(旧类名,新类名) 替换类
    <p class="a b c">哈哈</p>

    <script>

        var oP = document.getElementsByTagName('p')[0];

        //添加类名
        oP.classList.add('black');


        //删除类名
        oP.classList.remove('c');

        //替换(将black类替换成pink类)
        oP.classList.replace('black', 'pink');
ele.自定义属性
        var bn = document.getElementById('bn');


        //不会添加到dom元素上,但是有,是一个属性
        bn.index = 'black';


        console.log(bn.index); //black


        //因为没有添加到dom元素上,所以获取不到
        console.log(bn.getAttribute('index')); //null

        console.log(bn.getAttribute('test')); //pink


循环绑定事件

事件是异步的

    <ul>
        <li class="item active">所有</li>
        <li class="item">好评</li>
        <li class="item">有图</li>
        <li class="item">差评</li>
    </ul>

    <script>

        var oLis = document.querySelectorAll('li');


        for (var i = 0; i < oLis.length; i++) {


            //循环绑定点击事件,而for循环已经执行完,是同步事件,i = 4
			//事件的执行是异步的,  oLis[i].onclick 还是同步的
			
            oLis[i].onclick = function () {
            	//函数里面的代码是异步的
            	
                //在事件里面,this指代触发事件的对象
                // console.log(this);


                // 事件是异步的
                console.log(i); //都是4


            }
        }

        console.log(666);
        
        
  先打印666
  点击事件后执行

简单选项1

    <ul>
        <li class="item active">所有</li>
        <li class="item">好评</li>
        <li class="item">有图</li>
        <li class="item">差评</li>
    </ul>

    <script>


        var oLis = document.querySelectorAll('li');


        for (var i = 0; i < oLis.length; i++) {

            oLis[i].onclick = function () {

                //遍历循环,取消之前的active类

                for (var i = 0; i < oLis.length; i++) {
                    oLis[i].classList.remove('active');
                }

                //点谁给谁添加active类
                //使用this,动态添加active类
                this.classList.add('active');
            };


        }

选项卡

    <style>
        * {
            margin: 0;
            padding: 0;
        }

        li {
            list-style: none;
        }

        .tab_hd {
            display: flex;
            width: 300px;
            margin: 0 auto;
            margin-top: 50px;
        }

        .tab_hd li {
            width: 100px;
            text-align: center;
            line-height: 2;
            background-color: #ddd;
        }

        .tab_bd {
            width: 300px;

            margin: 0 auto;

            font-size: 30px;

        }

        .tab_bd li {
            width: 300px;
            height: 100px;
            background-color: pink;
        }

        .tab_bd li {
            /* 隐藏选项卡 */
            display: none;
        }

        .tab_hd .active {
            background-color: pink;
        }

        .tab_bd .show {

            display: block;
        }
    </style>

</head>

<body>

    <ul class="tab_hd">
        <li class="active">1</li>
        <li>2</li>
        <li>3</li>
    </ul>


    <ul class="tab_bd">
        <li class="show">1</li>
        <li>2</li>
        <li>3</li>
    </ul>


    <script>


        var oLis1 = document.querySelectorAll('.tab_hd li');


        var oLis2 = document.querySelectorAll('.tab_bd li')


        //循环绑定事件
        for (var i = 0; i < oLis1.length; i++) {

            //所有头部选项卡添加一个自定义属性,设置角标 

            oLis1[i].index = i;   //此方法不会添加到dom属性上,通过getAttribute获取不到

            oLis1[i].onclick = function () {
                //移除之前的类名

                for (var j = 0; j < oLis1.length; j++) {
                    oLis1[j].classList.remove('active');

                    //移除之前所有的 .show
                    oLis2[j].classList.remove('show');
                }


                this.classList.add('active');


                console.log(this.getAttribute('index'));


                //this对应的li要显示,找角标
                oLis2[this.index].classList.add('show');
            }
        }

    </script>
DOM自有属性
  • 元素设置自有属性,会在dom标签上显示
  • 设置自定义属性,不会在dom标签上显示,只能读取
    <p id='a' class="b">哈哈</p>


    <script>

        var oP = document.querySelector('p');

        //会自动添加到标签上面并且显示
        oP.title = '鼠标悬停显示';

        //自定义属性,也会添加属性,但是不会显示在标签上
        oP.haha = '哈哈哈哈';

        console.log(oP.haha); //哈哈哈哈


        var obj = new Object();
        obj.name = 'pink';
setAttribute

给dom设置自有属性,并且会在dom标签上显示

  <p id='a' class="b">哈哈</p>
var oP = document.querySelector('p');
  oP.setAttribute('hehe', "呵呵");
    <p id='a' class="b">哈哈</p>


    <script>

        var oP = document.querySelector('p');

        //在dom元素上显示
        oP.title = '鼠标悬停显示';

        //自定义属性,在dom上不显示,但是可以读到
        oP.haha = '哈哈哈哈';

        console.log(oP.haha); //哈哈哈哈

        //在标签上添加hehe属性
        oP.setAttribute('hehe', "呵呵");

        console.log(oP.hehe); //undefined


        console.log(oP.getAttribute('hehe')); //hehe


        console.log(oP.getAttribute('haha')); //null

removeAttribute

删除自定义属性

oP.removeAttribute('hehe');
dom属性小结
  • 获取所有的标签属性 attributes

  • 获取单个的属性值

    • getAttribute() 可以获取到自定义属性和自有属性
    • 获取自有属性:ele.属性 (ele.id,ele.title)
    • 获取自定义属性 getAttribute()
  • 添加属性

    • setAttribute()可以同时设置自定义属性和自有属性

    • 设置自有属性 ele.id = ‘a’

    • 设置自定义属性

      • ele.setAttribute() 会在标签上显示。 必须通过getAttribute得到
      • ele.自定义属性 = 属性值 。属性不会在标签上显示,可以读取
dom特殊属性
  • disabled 按钮禁用

    • true
    • false
  • checked 复选框选中

    true

    false

按钮倒计时
    <input type="button" value='按钮'>
    
    
            btn.onclick = function () {
            //按钮禁用
            btn.disabled = true;

            this.value = 10;

            var timer = setInterval(function () {

                btn.value--;

                if (btn.value == 0) {
                    clearInterval(timer);
                    this.disabled = false;
                    btn.value = '按钮';
                }
            }, 1000);
        }
复选框选中
        var checkBox = document.querySelector('input[type="checkbox"]')

        setTimeout(function () {
            checkBox.checked = true;
        }, 2000)

select

   <select id="sec">
        <option value="1">1</option>
        <option value="2" selected>2</option>
        <option value="3">3</option>
    </select>
全选
<body>


    全选<input type="checkbox" class="checkAll"> <br>

    JENNIE<input type="checkbox" class="checkOne">
    LISA<input type="checkbox" class="checkOne">
    JISOO<input type="checkbox" class="checkOne">
    ROSIE<input type="checkbox" class="checkOne">

    <script>
        var checkAll = document.querySelector('.checkAll');

        var checkOnes = document.querySelectorAll('.checkOne');


        checkAll.onclick = function () {
            for (var i = 0; i < checkOnes.length; i++) {
                checkOnes[i].checked = this.checked;
            }
        };

        //反选---当子选项有一个不选择,全选按钮取消,全选时,全选按钮勾选


        for (var i = 0; i < checkOnes.length; i++) {
            //给每个checkbox绑定事件
            checkOnes[i].onclick = function () {
                //判断是不是每个都选中
                for (var j = 0; j < checkOnes.length; j++) {
                    if (!checkOnes[j].checked) {
                        break;
                    }
                }

                //全部选中
                //数组全部遍历完,所有checkOne都为选中状态
                console.log(j == checkOnes.length);


                // if (j == checkOnes.length) {
                //     //全新框勾选
                //     checkAll.checked = true;
                // } else {
                //     checkAll.checked = false;
                // }

               // checkAll.checked = j == checkOnes.length ? true : false;
               
               
                checkAll.checked = j == checkOnes.length;
            }
        }

day13

回顾

    //BOM事件

    // focus
    // blur
    // scroll 高频率触发事件
    // onload 页面资源加载完毕
    // resiaze 高频率触发的事件
         //节流和防抖  每300ms监听一次
        //淘宝适配 flexible.js  
            //动态设置了meta
            //动态设置dpr
            //防止屏幕过大,导致的文字过大
            //onresize的延迟监听
        //移动端适配的实现
        //动态设置 根元素 html的字体大小 (100vw/7.5)rem
        //js实现:document.documentElement.font-size = clientWidth/7.5;


        // DOM节点 head body title documentElement doctype 

        //元素的获取 

        //ES6元素获取 querySelector querySelectorAll

        //DOM元素的内容 value innerText innerHTML

        //DOM元素的属性 

            // 自有属性 src href className classList

            //自定义属性 setAttribute(data,dataValue)

            //给对象添加自定义属性  ele.data = dataValue

         //DOM元素的特殊属性--表单
            //disabled
            //checked
            //selected   


         //全选和反选

         //选项卡   

到达底部判断
        var root = document.documentElement || document.body;

    window.onscroll = function () {
            console.log(88);

            if (root.scrollTop >= (root.scrollHeight - root.clientHeight)) {
                alert('到达底部');
            }
        }
选项卡foreach
 <ul class="tab_hd">
        <li class="active">1</li>
        <li>2</li>
        <li>3</li>
    </ul>


    <ul class="tab_bd">
        <li class="show">1</li>
        <li>2</li>
        <li>3</li>
    </ul>


    <script>


        var oLis1 = document.querySelectorAll('.tab_hd li');


        var oLis2 = document.querySelectorAll('.tab_bd li');



        //使用forEach遍历
        //此处没有异步,角标bug
        oLis1.forEach(function (val, j) {
            val.onclick = function () {

                //清除原有

                oLis1.forEach(function (item, i) {
                    item.classList.remove('active');
                    oLis2[i].classList.remove('show');
                });

                val.classList.add('active');

                oLis2[j].classList.add('show');

            }
        })
    </script>

角标不会因为异步而发生改变。这与foreach封装方法有关

       //i处在函数内部,属于局部变量
       function foreach(arr, callback) {
            for (var i = 0; i < arr.length; i++) {
                callback(arr[i],i,arr);
            }
        }

选项卡

    <style>
        * {
            padding: 0;
            margin: 0;
            list-style: none;
        }

        .tab_hd {
            display: flex;
            width: 300px;
            margin: 50px auto;
        }

        .tab_hd li {
            width: 100px;
            text-align: center;
            line-height: 2;
            background-color: #eee;
        }

        .tab_hd .active {
            background-color: pink;
        }

        .tab_bd {
            width: 300px;
            height: 300px;
            margin: 50px auto;
        }

        .tab_bd li {
            width: 300px;
            height: 300px;
            display: flex;
            justify-content: center;
            align-items: center;
            font-size: 30px;
            background-color: #f00;
        }

        .tab_bd li {
            display: none;
        }

        .tab_bd .show {
            display: flex;
        }
    </style>
</head>

<body>
    <ul class="tab_hd">
        <li class="active">11</li>
        <li>22</li>
        <li>33</li>
    </ul>

    <ul class="tab_bd">
        <li class="show">111111</li>
        <li>222222</li>
        <li>333333</li>
    </ul>


    <script>
        var oLis1 = document.querySelectorAll('.tab_hd li');

        var oLis2 = document.querySelectorAll('.tab_bd li');

        // 循环绑定点击事件
        oLis1.forEach(function (val, j) {
            val.onclick = function () {
                oLis1.forEach(function (item, i) {
                    item.classList.remove('active');
                    oLis2[i].classList.remove('show');
                })
                val.classList.add('active');
                oLis2[j].classList.add('show');
            }
        })

        // 全局变量  操作同一个i
        // for (var i = 0; i < oLis2.length; i++) {
        //     // i产生覆盖
        //     console.log(i)
        // }

        // var i = 0;
        // while (i < oLis2.length) {
        //     console.log(i);
        //     i++
        // }


        function forEach(arr, fn) {
            for (var i in arr) {
                fn(arr[i], i, arr)
            }
        }


        // i处在函数内部,属于局部变量
        forEach(oLis2, function (val, i) {
            // 内部声明了一个i
            console.log(i)
        })




    </script>

DOM样式修改

style.样式

ele.style.样式—修改行内样式,驼峰名法

        var oH = document.querySelector('#h');
        oH.style.background = 'red';
        // 驼峰命名法
        oH.style.fontSize = '30px';
cssText

也是添加行内样式,会覆盖之前的行内样式

   oH.style.cssText = 'background:red;font-size:30px';
添加类名
        .a {
            background: red;
            font-size: 30px;
        }

oH.classList.add('a')

获取样式

  • style获取

    只能获取行内样式,拿不到css中的样式

     console.log(oH.style.background);
     
    
  • getComputedStyle(ele.width)

     console.log(getComputedStyle(oH).width)
    console.log(getComputedStyle(oH)['backgroundColor'])
     console.log(getComputedStyle(oH)['background'])
    

    兼容IE8及以下获取样式的方法

    oH.currentStyle.width
    console.log(oH.currentStyle.width)
    
兼容写法
        // 封装获取样式的兼容简写
        function getStyle(ele, property) {
            if (getComputedStyle) {
                return getComputedStyle(ele)[property]
            }
            
            return ele.currentStyle[property]
        }

dom操作

查询
  • getElementById
  • getElementByClassName
  • getElementByTagName
  • querySelector
  • querySelectorAll
找父元素
  • parentNode
找子元素
  • childNodes 所有的子节点(包含换行、文本和注释)

  • children 所有的标签节点

  • firstChild 找到第一个结点

  • firstElementChild 找到第一个标签节点

  • lastChild 找到最后一个结点

  • lastElementChild 找到最后一个标签节点

找兄弟
  • 相邻兄弟节点
    • previousSibling
    • nextSibling
  • 相邻标签节点
    • previousElementSibling
    • nextElementSibling
节点
        // 节点类型 nodeType 返回数字
        // 标签 1
        // 文本 3
        // 注释 8
        //属性节点 2


        // 节点名字 nodeNae
        // 标签 SPAN 返回标签名称大写
        // 文本 #text
        // 注释 #comment

        // 节点的值 nodeValue
        // 标签 null
        // 文本 文本的内容
        // 注释 注释的内容
克隆节点
        // cloneNode 克隆节点
        // 默认是false ,也就是只克隆节点

        var res = h.cloneNode();
        console.log(res);  //<h1 id="h"></h1> 没有克隆里面的子元素
dom操作
新增
        // 创建标签
        // innerHTML 替换原来的所有内容
        // document.createElement 创建标签
        // document.createTextNode 创建文本结点


        // 新增
        // appendChild 最后新增子元素
        // insertBefore(new,old),把new结点插入到old前面
删除
        // dom删除
        // innertHTML = ''; 删除所有子元素
        // remove() 删除包括自己
        // removeChild(ele) 删除指定子元素,不能删除孙子  (只能删除子元素)
替换
        // DOM 修改
        // replaceChild(new,old) 替换 只能替换子节点 ,不能替换孙子

day14

留言板

<body>
    <div class="bacground">
        <div class="head">留言板</div>
        <input class="name" type="text" placeholder="请输入您的昵称">
        <textarea class="content" placeholder="请保持言论文明......"></textarea>
        <button class="btn">留言</button>
        <h3>大家在说</h3>
        <ul class="text">
            <!-- <li>
				<div class="message-head">
					<span class="photo">系统</span>
					<p class="time">2019-9-27 0:47:38</p>
				</div>
				<p class="liuyan">测试留言</p>
				<div class="reply">
					<p>测试回复</p>
				</div>
				<button class="delete">Delete</button>
				<button class="answer">Answer</button>
			</li> -->
        </ul>
    </div>
    <!-- 弹窗 -->
    <div class="popup">
        <div class="pop-content">
            <div class="pop-head">回复板</div>
            <textarea class="pop-reply" placeholder="请保持言论文明......"></textarea>
            <button class="pop-btn1">回复</button>
            <button class="pop-btn2">取消</button>
        </div>
    </div>


    <script>


        $('.btn').onclick = function () {
            //判断留言和昵称是否为空
            var nickName = $('.name').value;
            var content = $('.content').value;

            if (!nickName || !content) {
                alert('请输入内容');
                return;
            }

            $('.name').disabled = true;
            // 清空内容
            $('.content').value = '';
            //按钮倒计时
            toTime();

            //创建留言
            createContent(nickName, content);

        };

        // /删除留言
        function delContent() {
            //遍历所有 留言
            var dels = document.querySelectorAll('.delete');

            dels.forEach(function (val, i) {
                val.onclick = function () {
                    // 删除留言
                    this.parentNode.remove();
                }

            });
        }

        // 回复
        function replayContent() {
            //给每个回复按钮点击 事件
            var reps = document.querySelectorAll('.answer');

            // 遍历绑定事件
            reps.forEach(function (val, i) {
                // val代表 回复按钮
                val.onclick = function () {
                    //弹窗出现
                    $('.popup').style.display = 'flex';
                    //点击取消 
                    $('.pop-btn2').onclick = function () {
                        $('.popup').style.display = 'none';
                        //清空留言板内容
                        $('.pop-reply').value = '';
                        return;
                    }
                    // 点击了回复
                    $('.pop-btn1').onclick = function () {
                        //判断回复内容是否为空
                        var replay = $('.pop-reply').value;
                        if (!replay) {
                            alert('留言不能为空');
                            return;
                        }

                        //找到留言的地方
                        // 回复按钮的前一个的前一个兄弟
                        // console.log(this);
                        // val代表正在 遍历的回复按钮
                        var rep = val.previousElementSibling.previousElementSibling;
                        // console.log(rep);

                        var p = document.createElement('p');
                        p.innerText = replay;
                        // 将p加到对应的留言区中 
                        rep.insertBefore(p, rep.firstElementChild);

                        // 将回复关闭
                        $('.popup').style.display = 'none';
                        //清空留言板内容
                        $('.pop-reply').value = '';
                    }

                }
            })
        }


        // 创建留言
        function createContent(nickName, content) {
            var oLi = document.createElement('li');

            oLi.innerHTML = `
                <div class="message-head">
					<span class="photo">${nickName}</span>
					<p class="time">${dateFormat()}</p>
				</div>
				<p class="liuyan">${content}</p>
				<div class="reply">
					
				</div>
				<button class="delete">Delete</button>
				<button class="answer">Answer</button>
            `;
            $('.text').insertBefore(oLi, $('.text').firstElementChild);

            //删除留言

            delContent();

            //回复
            replayContent();
        }





        function dateFormat() {
            var date = new Date();
            var res = + date.getFullYear() + "-" + date.getMonth() + '-' + date.getDate() + ' ' + date.getHours() + ':' + date.getMinutes() + ":" + date.getSeconds();
            return res;

        }
        // 倒计时
        function toTime() {
            $('.btn').disabled = true;
            var count = 10;
            var timer = setInterval(function () {

                $('.btn').innerHTML = --count + '秒后留言';

                if (count == 0) {
                    clearInterval(timer);
                    $('.btn').innerHTML = '留言';
                    $('.btn').disabled = false;
                }


            }, 300);
        }
        function $(qs) {
            return document.querySelector(qs);
        }
    </script>

盒子宽高问题

  • getComputedStyle(oDiv)[‘width’] :200px 返回盒子CSS设置的宽度,带px
  • clientWidth :width+padding
  • offsetWidth(offsetHeight) :width+padding+border
  • offsetLeft (offsetTop):距离最近的具有定位的祖先元素的距离
.a {
            width: 200px;
            height: 200px;
            padding: 30px;
            border: 10px solid #000;
            margin: 100px;
        }

        .box {
            width: 400px;
            height: 400px;
            background-color: red;
            position: relative;
            left: 50px;

        }
    </style>
</head>

<body>

    <div class="box">
        <div class="a"></div>
    </div>

    <script>
        // 盒子的宽高问题
        var oDiv = document.querySelector('.a')
        //CSS设置的宽度
        console.log(getComputedStyle(oDiv)['width']); //200px

        //clientWidth:width+padding
        console.log(oDiv.clientWidth); //260

        //offsetWidth:width+padding+border
        console.log(oDiv.offsetWidth); //280


        //offsetLeft  相对于最近的具有定位的父元素的距离
        console.log(oDiv.offsetLeft); //100

事件

事件:事件发生并得到处理。

事件的三要素

  1. 事件源
  2. 事件类型
  3. 事件处理函数
绑定事件的方式
  • 行内js (0级事件)
  • οnclick=function(){} (0级事件)
  • 事件监听 (2级事件)

方式一

        var oP = document.querySelector('p');
        oP.onclick = function () {
            console.log(this.innerText);
        }
行内JS
 <p onclick="fn(this)">1</p>
 
         function fn(a) {
            console.log(999);
            console.log(a.innerText);
        }
<body>
    <p onclick="fn(this)">1</p>

    <script>

        function fn(a) {
            console.log(999);
            // console.log(a.innerText);
        }

        //同时出现时,fn只是指向,这个函数会覆盖fn,因为同是0级事件
        var oP = document.querySelector('p');
        oP.onclick = function () {
            console.log(666);

            // console.log(this.innerText);
        }

    </script>
事件监听

事件不会发生覆盖。dom2级事件

<p onclick="fn(this)">1</p>


var oP = document.querySelector('p');


        // 添加事件监听
        // 参数:1.事件类型,事件处理函数
        oP.addEventListener('click', function () {
            console.log(444);
            console.log(this.innerText);

        });



        oP.onclick = function () {
            console.log(666);
        }


先打印666,在打印444

 oP.addEventListener('click', function () {
            console.log(444);
            console.log(this.innerText);

        });

        oP.addEventListener('click', function () {
            console.log(1010);


        });



        oP.onclick = function () {
            console.log(666);
        }

IE

        oP.attachEvent('onclick', function () {
            console.log('IE');

        });
兼容
        // 兼容写法

        // 参数:dom,事件类型,监听函数
        function addEvent(ele, type, fn) {
            if (window.addEventListener) {
                ele.addEventListener(type, fn);
            } else {
                ele.attachEvent('on' + type, fn);
            }
        }

使用

        var oP = document.querySelector('p');

        addEvent(oP, 'click', function () {
            console.log('xxx');

        })
dom0级事件和2级事件

在dom0级事件处理中,后定义的事件处理会覆盖前面的。

在dom2级事件处理中,对一个按钮点击的事件处理就没有被覆盖掉。所以,dom0级和dom2级事件处理,在形式上和功能上都是有差异的。这就是dom0级和dom2级事件最简单也最常用的不同之处了

0级事件:行内js与ele.onclick = function(){}

2级事件:dom.addEventListener

事件的移除
  • DOM 0级事件的移除 onclick = null

  • DOM 2级事件的移除 在绑定事件监听时必须使用具名函数,移除时使用removeEventListener(移除事件类型,函数),需要一个一个的移除

    removeEventListener(‘click’,fn);

      <p id="p">11</p>

    <script>
        // 事件的移除
        p.onclick = function () {
            console.log(888);
        }

        p.addEventListener('click', fn1);

        p.addEventListener('click', fn2);


        function fn1() {
            console.log(222);

        }


        function fn2() {
            console.log(333);

        }


        // 五秒后事件移除

        setTimeout(function () {
            // 事件的移除,不能清除2级事件(addEventListener)
            p.onclick = null;

            // 移除监听事件:参数:移除的事件类型,函数
            p.removeEventListener('click', fn1);

            p.removeEventListener('click', fn2);
        }, 5000)

    </script>

兼容写法
        function removeEven(ele, type, fn) {
            if (window.removeEventListener) {
                ele.removeEventListener(type, fn);
            } else {
                // IE解除事件方式 
                ele.detachEvent('on' + type, fn);
            }
        }

使用

    removeEven(p, click, fn1);
事件对象

事件对象:浏览器用于记录事件发生的整个过程

获取事件对象的方式:事件处理函数的第一个参数

<h1 id="h">2333</h1>


        document.onclick = function (e) {
            console.log(e);
            console.log(e.target); //html
            console.log(222);


        }

        h.onclick = function (e) {
            console.log(e);
            console.log(e.target); //h1
            console.log(333);

        }

IE写法

IE不需要参数,直接使用event

        h.onclick = function () {

            console.log(event);


        }

关于targetIE写法

  • 普通浏览器
        h.onclick = function (e) {

            console.log(e.target); //h1
    

        }
  • IE
        h.onclick = function (e) {
            var ev = e || event;
            // console.log(ev.target);
   

            // IE中target使用srcElement
            console.log(ev.srcElement);

        }
兼容写法
        h.onclick = function (e) {
            var ev = e || event;
        }

target兼容写法

IE浏览器event没有target属性

     h.onclick = function (e) {
            var ev = e || event;

            var target = ev.target || ev.srcElement;

            console.log(target);


        }
target

事件对象的target能够准确记录哪个元素的事件被触发

    <p>111</p>

    <h1>blackpink</h1>

    <div>hahahah</div>
    
    
    document.onclick = function (e) {
            var ev = e || event;

            console.log(ev.target);

        }
tagName

元素的tagName为元素标签大写

 <h1 id="h1" class="black">blackpink </h1> 
 
 tagName-->H1
自定义属性

通过自定义属性判断触发元素

   <div pink='black'>hahahah</div>
   
   document.onclick = function (e) {
            var ev = e || event;
            var target = e.target;
            // 通过自定义属性判断元素
            if (target.getAttribute('pink') == 'black') {
                console.log(target.innerHTML);
            }
        }
事件机制和事件流

事件流:事件流描述的是从页面中接受事件的顺序

IE和网景提出两种相反事件流概念

  • IE的时间里是事件冒泡流(event bubble)

    即事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点

  • 网景是事件捕获流

    不具体的DOM节点应该更早接收到事件,而最具体的节点应该最后接收到事件

  • 事件冒泡:事件由内而外触发

  • 事件捕获:事件由外而内触发

事件流包含三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段

事件冒泡
    <div class="a">
        <div class="a1">

        </div>
    </div>

    <script>
        // 事件机制和事件流

        // 事件冒泡
        // 先具体元素,后不具体元素

        var oA = document.querySelector('.a');

        var oA1 = document.querySelector('.a1');

        oA.onclick = function () {
            alert('父元素');

        }

        oA1.onclick = function () {
            alert('子元素');
        }

        document.onclick = function () {
            alert('文档对象');
        }

    </script>
事件捕获

事件捕获:事件由外而内触发

事件监听的第三个参数为true(默认为false,事件冒泡)

        // 事件捕获:
        // 事件监听的第三个参数,设置为true

        a.addEventListener('click', function () {
            alert('父');
        }, true)

        a1.addEventListener('click', function () {
            alert('子');
        }, true)

        document.addEventListener('click', function () {
            alert('html');
        }, true)
阻止事件冒泡
        // 阻止事件冒泡:不希望a1的点击事件向外扩散
        var a = document.querySelector('.a');
        var a1 = document.querySelector('.a1');

        a.onclick = function () {
            console.log('a');

        }

        a1.onclick = function (e) {
            var ev = e || event;

            // 阻止事件冒泡
            ev.stopPropagation();

            console.log('a1');
            
           }

兼容写法

        // 阻止事件冒泡:不希望a1的点击事件向外扩散
        var a = document.querySelector('.a');
        var a1 = document.querySelector('.a1');

        a.onclick = function () {
            console.log('a');

        }

        a1.onclick = function (e) {
            var ev = e || event;

           
            console.log('a1');

 			// 阻止事件冒泡
            if (ev.stopPropagation) {
                ev.stopPropagation();

            } else {
                // 兼容IE
                ev.cancelBubble = true;
            }

        }
事件委托

现阶段弊端

  • 事件处理函数越多,执行效率越低
  • 如果一个标签在未来才会出现,不能绑定事件

委托

  1. 可以对未生成的DOM绑定事件
  2. 事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件

事件委托基于事件冒泡

原本,

    <div class="a">
        <p id="p">11</p>
    </div>

动态添加h1标签,并给其绑定事件

 setTimeout(function () {
            var a = document.querySelector('.a');

            var h1 = document.createElement('h1');

            h1.innerText = '2333';

            a.appendChild(h1);

            //给新添加的元素绑定事件
            var oH1 = document.querySelector('h1');
            oH1.onclick = function () {
                console.log(this.innerText);
            }

        }, 2000)

后动态生成元素无法绑定事件

	    <ul>
        <li>a</li>
        <li>b</li>
        <li>c</li>
        <li>d</li>
    </ul>


        var oLis = document.querySelectorAll('li');

        oLis.forEach(function (val, i) {
            val.onclick = function () {
                alert(this.innerText)
            }
        })

        setTimeout(function () {
            var ul = document.querySelector('ul');
            var li = document.createElement('li');
            li.innerHTML = '2s后出现的';

            ul.appendChild(li);
        }, 4000)

优点

  • 减少事件处理函数
  • 给未来的元素添加事件绑定
    <ul>
        <p>1o1</p>
        <li>a</li>
        <li>b</li>
        <li>c</li>
        <li>d</li>
    </ul>


    <script>
        var ul = document.querySelector('ul');

        // 4s后新增元素
        setTimeout(function () {
            var li = document.createElement('li');
            li.innerHTML = 'KKK';
            ul.appendChild(li);
        }, 4000)

		//给其父元素绑定事件
        ul.onclick = function (e) {
            var ev = e || event;

            var target = ev.target || ev.srcElement;

            if (target.tagName == 'LI') {
                console.log(target.innerHTML);
            }
            // 获取目标元素
            console.log(target);

        }

    </script>
模拟select
普通版
    <div class="select">
        <div class="text">1</div>
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
        </ul>
    </div>

    <script>

        $('.text').onclick = function (e) {
            var ev = e || event;

            // 阻止冒泡,否则会触发document.click,会一瞬间关闭
            e.stopPropagation();
            // 弹出Ul ,选项
            $('ul').style.display = 'block';


            var oLis = document.querySelectorAll('li');

            oLis.forEach(function (val, i) {
                //给每个Li绑定事件
                val.onclick = function () {
                    $('.text').innerHTML = this.innerHTML;
                    $('ul').style.display = 'none';
                }
            })


            //点击旁边空白处的关闭

            document.onclick = function () {
                $('ul').style.display = 'none';
            }


        }
事件委托版

事件委托 一般委托给触发事件的最外面的一层

  document.onclick = function (e) {
            var ev = e || event;

            var target = e.target || e.srcElement;
            //判断点击的元素,进行相应的操作
            
            if (target.className == 'text') {
                //  点击.text,select进行了选择
                $('ul').style.display = 'block';
                // 返回,不执行最后的      $('ul').style.display = 'none';
                return

            }
			
	
            if (target.tagName == 'LI') {
             //li点击
                $('.text').innerHTML = target.innerHTML;

            }
	
			// 点击空白处隐藏,(除了点击.text,其他元素点击都隐藏)
            $('ul').style.display = 'none';

        }


事件委托留言板
        document.onclick = function (e) {
            var ev = e || event;

            var target = ev.target || ev.srcElement;

            if (target.className == 'btn') {
                // 点击留言按钮
                var nickName = $('.name').value;
                var content = $('.content').value;

                if (!nickName || !content) {
                    alert('留言/用户名不能为空')
                    return;
                }

                // 用户名不可更改
                $('.name').disabled = true;

                // 清空留言板
                $('.content').value = '';


                // 倒计时10s
                timeOut(10);
                //创建留言
                creatContent(nickName, content);
            }

            // 点击删除留言
            if (target.className == 'delete') {

                // 删除留言
                target.parentNode.remove();

            }

            if (target.className == 'answer') {
                replayContent(target);
            }



        }


        // 回复留言
        //ele为当前点击的回复按钮
        function replayContent(ele) {
            $('.popup').style.display = 'flex';
            $('.pop-btn1').onclick = function () {

                var repContent = $('.pop-reply').value;

                // 清空留言板
                $('.pop-reply').value = '';

                if (!repContent) {
                    alert('留言不能为空');
                }
                // 创建回复
                // 找到留言的地方
                var reps = ele.previousElementSibling.previousElementSibling;
                var p = document.createElement('p');
                p.innerHTML = repContent;

                reps.insertBefore(p, reps.firstElementChild);


                $('.popup').style.display = 'none';

            }

            $('.pop-btn2').onclick = function () {
                $('.popup').style.display = 'none';
                // 清空留言板
                $('.pop-reply').value = '';
            }



        }



        // 创建留言

        function creatContent(nickName, content) {
            //创建

            var li = document.createElement('li');
            li.innerHTML = `
            <li>
                    <div class="message-head">
                        <span class="photo">${nickName}</span>
                        <p class="time">${getTime()}</p>
                    </div>
                    <p class="liuyan">${content}</p>
                    <div class="reply">
                       
                    </div>
                    <button class="delete">Delete</button>
                    <button class="answer">Answer</button>
                </li>
            `;

            $('.text').insertBefore(li, $('.text').firstElementChild);
        }



        // 时间格式化
        function getTime() {
            var date = new Date();

            return `
                ${date.getFullYear()}-${date.getMonth()}-${date.getDate()} ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}
            `;
        }

        // 倒计时
        function timeOut(time) {
            // 倒计时
            $('.btn').disabled = true;

            var count = time;
            var timer = setInterval(function () {

                $('.btn').innerHTML = count-- + '秒后留言';
                if (count < 0) {
                    clearInterval(timer);
                    $('.btn').innerHTML = '留言';
                    $('.btn').disabled = false;
                }
            }, 500);
        }


        function $(ele) {
            return document.querySelector(ele);
        }

    </script>

day15

表单事件

  • 表单事件
    • onsubmit 表单提交
    • onblur 失去焦点
    • onfoucs 获取焦点
    • onchange 失去焦点,并且发生改变才会触发
    • oninput 输入就会触发 (频繁触发事件)
  • 方法
    • focus()获取焦点
    • blur()失去焦点
    <form action="#">
        <input type="text" name='username'> <span id="tips">还可以输入<i>6</i>个字符</span><br>
        <input type="password" name="pwd">
        <button type="submit">提交</button>
    </form>

<script>

        $('form').onsubmit = function (e) {
            var e = e || event;

            // 阻止默认事件
            e.preventDefault();

            console.log(888);

        }

        // 失去焦点
        $('input[type="text"]').onblur = function () {

            if (this.value == '') {
                alert('报错');
            }

        }


        // 值改变
        $('input[type="password"]').onchange = function () {
            console.log(this.value);

        }


        // 只要输入就会触发 频繁触发
        $('input[type="text"]').oninput = function () {
            if (this.value.length > 6) {

                // 显示前6个字符
                // console.log($('input[type="text"]').value.substring(0, 7));

                $('input[type="text"]').value = $('input[type="text"]').value.substring(0, 6);

                // 光标移到下一行
                $('input[type="password"]').focus();
                // this.blur(); 失去焦点
                return;
            }


            $('#tips i').innerHTML = 6 - this.value.length;

        }

        function $(el) {
            return document.querySelector(el);
        }

preventDefault()

阻止默认事件

  $('form').onsubmit = function (e) {

            var e = e || event;

            // 阻止默认事件
            e.preventDefault();

            console.log(888);

        }

键盘事件

  • onkeydown 键盘按下触发 ,按着不动会持续触发
    • e.key 键盘上的值
    • e.keyCode 键值对应的ASCII值
    • e.altKey 如果按下的是ctrl则返回true,否则false
    • e.ctrlKey
    • e.shiftKey
  • onkeyup
  • onkeypress

大部分时候onkeydown和onkeypress是一样的效果

但是 onkeypress不支持部分功能键(上下左右键/ctrl/shift/alt)

keyCode兼容写法
var keyCode = e.keyCode|| e.which // 兼容IE8及以下 
document.onkeydown = function (event) {

            // 获取键值对应的ASCII码值 键值
            // IE8及以下 e.witch
            var keyCode = event.keyCode || event.which

            // console.log(event);

            // console.log(event.key);
            // console.log(event.keyCode);


            // 特殊的键
            // console.log(event.ctrlKey); //按ctrl则true,否则为false

            // console.log(event.shiftKey);

            // console.log(event.altKey);

            // console.log(event.keyCode);


            // ctrl+回车
            if (event.ctrlKey && event.keyCode == 13) {
                console.log('回车');

            }
        }

        document.onkeyup = function (e) {
            console.log(e.keyCode);

        }

        // 键盘抬起事件
        window.onkeypress = function (e) {
            console.log(e.keyCode);

        }

    </script>
键盘控制方块移动
    <style>
        .a {
            width: 200px;
            height: 200px;
            background-color: springgreen;
            position: absolute;

            border: 10px solid pink;
        }
    </style>
</head>

<body>
    <div class="a"></div>

    <script>


        var root = document.documentElement || document.body;

        // 最大宽度
        // var maxW = root.clientWidth - parseFloat(getComputedStyle($('.a')).width);

        // console.log(maxW);

        // 最大高度
        // var maxH = root.clientHeight - parseFloat(getComputedStyle($('.a')).height);


        var maxW = root.clientWidth - $('.a').offsetWidth;

        var maxH = root.clientHeight - $('.a').offsetHeight;


        document.onkeydown = function (e) {
            var e = e || event;
            var keyCode = e.keyCode || e.which;
            //右 37
            // 上38
            // 左 39
            //下40

            //上

            var top = $('.a').offsetTop;

            var left = $('.a').offsetLeft;


            // 限制
            if (top < 0) {
                top = 0;
            }

            // 上
            if (keyCode == 38) {
                // $('.a').style.top = (top - 10) + 'px';
                top -= 10;
            }

            // 下
            if (keyCode == 40) {
                top += 10;
                // $('.a').style.top = (top + 10) + 'px';
            }


            // 左
            if (keyCode == 37) {
                left -= 10;
                // $('.a').style.left = (left - 10) + 'px';
            }


            // 右
            if (keyCode == 39) {
                left += 10
                // $('.a').style.left = (left + 10) + 'px';
            }

            if (top < 0) top = 0;
            if (left < 0) left = 0


            if (top > maxH) top = maxH;

            if (left > maxW) left = maxW;

            $('.a').style.cssText = `left:${left}px;top:${top}px`;




        }

        function $(ele) {
            return document.querySelector(ele);
        }
    </script>
控制方块一直移动
 <style>
        .a {
            width: 200px;
            height: 200px;
            background-color: springgreen;
            position: absolute;

            border: 10px solid pink;
        }
    </style>
</head>

<body>
    <div class="a"></div>

    <script>

        var timer;
        var root = document.documentElement || document.body;

        // 最大宽度
        // var maxW = root.clientWidth - parseFloat(getComputedStyle($('.a')).width);

        // console.log(maxW);

        // 最大高度
        // var maxH = root.clientHeight - parseFloat(getComputedStyle($('.a')).height);


        var maxW = root.clientWidth - $('.a').offsetWidth;

        var maxH = root.clientHeight - $('.a').offsetHeight;


        document.onkeydown = function (e) {
            var e = e || event;
            var keyCode = e.keyCode || e.which;
            //右 37
            // 上38
            // 左 39
            //下40

            //上

            var top = $('.a').offsetTop;

            var left = $('.a').offsetLeft;


            clearInterval(timer);
            timer = setInterval(function () {
                // 上
                if (keyCode == 38) {
                    // $('.a').style.top = (top - 10) + 'px';
                    top -= 10;
                }

                // 下
                if (keyCode == 40) {
                    top += 10;
                    // $('.a').style.top = (top + 10) + 'px';
                }


                // 左
                if (keyCode == 37) {
                    left -= 10;
                    // $('.a').style.left = (left - 10) + 'px';
                }


                // 右
                if (keyCode == 39) {
                    left += 10
                    // $('.a').style.left = (left + 10) + 'px';
                }

                // 限制

                if (top < 0) top = 0;
                if (left < 0) left = 0


                if (top > maxH) top = maxH;

                if (left > maxW) left = maxW;

                $('.a').style.cssText = `left:${left}px;top:${top}px`;

            }, 100)



        }

        function $(ele) {
            return document.querySelector(ele);
        }
    </script>

Day16

回顾

        // DOM的增删改
        // 节点和元素或者标签(对象)
        // 属性操作
            // 自有属性
            // 自定义属性
            // 特殊的属性
            // className(字符串 ) classList
            // checked disabled selected

        // 事件
            //事件的概念:三要素:事件源 事件类型 事件处理函数
            // 事件绑定的方式
            // 行内JS 事件监听   addEvenlistener DOM0级 2级事件(2级事件后执行)
            // 事件的移除 null removeEventListener(具名函数)
            // 事件对象
                // 事件对象的获取 事件处理函数的第一个参数 /event
                // target
                //preventDefault()阻止默认事件
                // keyCode/key
            // 事件机制和事件流(三个阶段)
                // 事件冒泡和事件捕获
                // 事件委托
                    // 概念:子元素和父元素触发同类型事件,此时直接给父元素绑定(子元素会冒泡给父元素)
                    // 优点:
                    // 原理:基于事件冒泡(子元素的事件也会触发父元素的事件)

                // 事件类型
                    // 键盘事件
                        // keyCode  ctrlKey shiftKey altKey
                        // onkeydown 
                        // onkeyup
                        // 案例:键盘控制移动方向

                    // 鼠标事件
                    // 其他事件

                    //留言板 

购物车


轮播图

鼠标事件

  • click 单击

  • dbclick 单击

  • mouseenter 鼠标移入 支持的是事件捕获

  • mouseleave 鼠标移开

  • mouseover 鼠标移入 支持事件冒泡

  • mouseout 鼠标移开

  • mousemove 鼠标移动

  • mousedown 鼠标按下

  • mouseup 鼠标抬起

鼠标移入随机颜色
    <script>
        document.onmouseover = function () {
            document.body.style.background = randColor();
        }


        function randColor() {
            var r = parseInt(Math.random() * 256);
            var g = parseInt(Math.random() * 256);
            var b = parseInt(Math.random() * 256);

            return `rgb(${r},${g},${b})`;
        }
    </script>

鼠标坐标

  • e.x和e.y ==e.clientX e.clientY 距离浏览器实际边缘的距离
  • e.pageX e.pageY 距离页面实际边缘的距离
  • e.offsetX e.offsetY 距离事件源边缘的距离
        // e.x和e.y  == e.clientX e.clientY  距离浏览器边缘的距离
        // e.pageX e.pageY   距离页面实际边缘的距离
        // e.offsetX  e.offsetY  距离事件源边缘的距离


        a.onclick = function (e) {
            console.log(e.x, e.y);
            console.log(e.clientX, e.clientY);

            console.log(e.pageX, e.pageY);

            console.log(e.offsetX, e.offsetY)
        }

鼠标跟随

day18

day19

运动

加速运动
        var speed = 5;
        var end = 1000;

        document.onclick = function () {

            var current = box.offsetLeft;

            var t = setInterval(function () {

                current += speed;

                // 变速运动 (速度逐渐变快)
                speed += 5;


                if (current >= end) {
                    box.style.left = end + 'px';
                    clearInterval(t);
                }

                box.style.left = current + 'px';


            }, 100);

        }
变加速运动
 var speed = 5;
        var end = 1000;

        document.onclick = function () {

            var current = box.offsetLeft;


            var t = setInterval(function () {

                current += speed;

                // 变速运动 (速度主键变快)
                speed += 5;


                if (current >= end) {
                    box.style.left = end + 'px';
                    clearInterval(t);
                }

                box.style.left = current + 'px';


            }, 100);

        }

缓冲运动

在这里插入图片描述

思路

  • 速度跟随元素的移动而不断的变化
  • 确认一个缓冲因子
  • 速度 = 元素剩下的距离 /缓冲因子
 <style>
        div {
            width: 100px;
            height: 100px;
            background-color: #f00;
            position: absolute;
        }
    </style>
</head>

<body>
    <div id="box"></div>

    <script>

        // 匀速
        // 加速 : 匀加速和变减速
        // 减速 :匀减速和变减速以及缓冲运动

        var end = 1100;
        var t = setInterval(function () {
        	//获取当前位置
            var current = box.offsetLeft;
            // 30 缓冲因子
            var speed = (end - current) / 30;
            //向上取整,以至于一致为0.几,移动变慢,到达不了目的地
            speed = Math.ceil(speed);
            console.log(speed);
            current += speed;
            box.style.left = current + 'px';
            if (current >= end) {
                clearInterval(t);
                box.style.left = end + 'px';
            }
        }, 10)
    </script>

es5严格模式

js的语法存在一些不严谨的地方

开启严格模式

  • 为脚本开启严格模式

    为整个脚本文件开启严格模式,需要在所有语句之前放一个特定语句 "use strict"; (或 'use strict';

  • 为函数开启严格模式

    要给某个函数开启严格模式,得把 "use strict"; (或 'use strict';)声明一字不漏地放在函数体所有语句之前。

严格模式下:

  • 函数/变量必须先声明后使用

  • 普通函数的this指向为undefined

  • 函数里面不允许出现同名参数的出现

  • 普通模式下变量如果没有var, 那么就是全局变量

        a = 5;
        console.log(a); //5

        function aa() {
            b = 4;
        }

        aa();
        console.log(b); //4

开启严格模式后,必须先声明后使用

        'use strict';

        a = 5;
        console.log(a); //a is not defined
  • 严格模式下this指向问题

    普通模式

            function aa() {
                console.log(this);
            }
    
            aa(); //Window对象
    

    严格模式

            'use strict';
            function aa() {
                console.log(this);
            }
    
            aa(); //undefined
    
  • 严格模式下,函数里面不允许同变量的出现

    普通模式,值进行覆盖,为最后一次

            function bb(a, a) {
                console.log(a);
            }
    
            bb(3, 4); //4
    

    严格模式下,

            'use strict';
            function bb(a, a) {
                console.log(a);
            }
    
            bb(3, 4); //Duplicate parameter name not allowed in this context
    

this指向

  • 一般情况下,this指向window对象
  • 普通函数,this指向window对象
  • 事件处理函数中,this指向的绑定事件的对象
  • 在对象里面,this指向对象本身

一般情况,this指向windown对象

 console.log(this); //window对象

普通函数里,this指向window对象(非严格模式)

        function add() {
            console.log(this);
        }

        add(); //window对象

事件处理函数中,this指向的是绑定事件的对象

        // this指向的是绑定此事件的dom元素
        btn.onclick = function () {
            console.log(this); //<button id='btn'>按钮</button>
        }

在对象里面,this指向对象本身

        var obj = {
            name: 'Jennie',
            age: 18,
            sayHi: function () {
                console.log(this);  //{name:'Jennie',age:19,sayHi:f}
                console.log(this.name); //jennie

            }
        }
        obj.sayHi();

ES6新增语法

变量的声明方式
  • var

  • let

    • 不会产生预编译,变量必须先声明,后使用

    • 变量名不允许重复

    • 块级作用域

  • const 常量

let

无预编译

        console.log(a); //undefined
        var a = 5;
       
        console.log(a); //Cannot access 'a' before initialization
        let a = 5;

变量名不允许重复

var

        var a = 5;
        var a = 6;

        console.log(a); //6

let

        let a = 3;
        let a = 4;

        console.log(a); // Identifier 'a' has already been declared

块级作用域

var

        {
            var a = 3;

        }

        console.log(a); //3

        {
            console.log(a); //3

        }

let

        let m = 10;

        {
            console.log(m); //10

            let n = 20;

        }


        console.log(n); //n is not defined


        {
            console.log(n); //n is not defined

        }

        {
            let b = 10;
        }

        {
            let b = 20;
            console.log(b); //20

        }
for应用let
        for (var i = 0; i < 3; i++) {

        }

        console.log(i); //3

let应用到for循环时,是有块级作用域的

    for (let i; i < ops.length; i++) {

    }

    console.log(i); //i is not defined
    <p>1</p>
    <p>2</p>
    <p>3</p>



    <script>
        var ops = document.querySelectorAll('p');

        var ops = document.querySelectorAll('p');
        // 每个i都是3,
        // 从始至终都声明了一个变量i
        for (var i = 0; i < ops.length; i++) {
            ops[i].onclick = function () {

                alert(i);
            }
        }

        console.log(i); //3
        
        
        //相当于
     <p>1</p>
    <p>2</p>
    <p>3</p>


        var i = 0;

        ops[i].onclick = function () { };
        i++;
        ops[i].onclick = function () { };
        i++;
        ops[i].onclick = function () { };

        // 事件的绑定函数异步的,此时i已经为3
    </script>

let

	<p>1</p>
    <p>2</p>
    <p>3</p>
       
       var ops = document.querySelectorAll('p');


        for (let i = 0; i < ops.length; i++) {
            ops[i].onclick = function () {
                alert(i);
            }
        }
        
        //因为let的作用域是块级的,因此有三个变量i,分别为i=0,i=1,i=2
        
        
        
        //相当于
       
        {
            let i = 0;
            ops[i].onclick = function(){
                alert(i); //0
            }

        }

        {
            let i=1;
            ops[i].onclick  = function(){
                alert(i); //1
            }
        }


        {
            let i=2;
            ops[i].onclick = function(){
                alert(i); //2
            }
        }


const

常量是块级范围的,非常类似用let 语句定义的变量。但常量的值是无法(通过重新赋值)改变的,也不能被重新声明。

  • const声明时,必须被赋值

  • const的值不可被改变(值为引用类型时,值可变【本质上存储的是地址】)

        // const是块级作用域
        {
            const a = 3;
        }

        console.log(a); //a is not defined

const值不可被改变

       const a = 3;
        a = 4; // Assignment to constant variable.

声明时必须赋值

const a; // Missing initializer in const declaration

const为引用类型时

        const a = [1, 2, 3]; //引用的是地址
        a.pop(3);
        console.log(a); //[1,2]
 
        const a = [1, 2, 3]; //引用的是地址

        // 改变了地址,报错
        a = [1, 2, 3]; //Assignment to constant variable.
函数参数默认值
        function test(a, b) {
            // 给默认值0
            a = a || 0;
            b = b || 0;
            console.log(a, b);

        }

        test();
		//给参数默认值
        function test(a = 0, b = 0) {
            console.log(a, b);

        }

        test();
箭头函数
  • 具名函数
  • 赋值式声明函数 不会产生预编译
  • 声明函数的时候,尽量使用赋值式声明方式

形式一:把function去掉 ,变为=> 只有赋值式声明函数可改成箭头函数

        var fn = () => {
            console.log(666);
        }

        fn(); 
//带有参数
      var fn = (a, b) => {
            console.log(a + b);
        }
        fn(3, 4); //7

形式二:当函数体只有一句代码,且有返回值时

        var add = (a = 0, b = 0) => a + b;


        console.log(add(5, 6)); //11

形式三:当函数有且仅有一个参数,可以省略括号

        var test = a => {
            console.log(a);
        }

        test(3); //3

形式四:多参数…arrr

使用箭头函数,无arguments

必须使用…arr接收不可定的多个参数

        var fn = (...arr) => {
            // console.log(arguments); //报错

            console.log(arr);
        }

        fn(1, 2, 3, 4); //[1,2,3,4]
展开运算符

用于数组和对象

数组

        var arr = [1, 2, 3];
        var arr2 = [0, ...arr, 4];
        arr.pop();
        console.log(arr2); //[0,1,2,3,4]
        const arr1 = [1, 2, 3];
        const arr2 = [4, 5, 6];

        const arr3 = [...arr1, ...arr2];

        console.log(arr3); //[1,2,3,4,5,6]

对象

        const obj1 = {
            name: 'cc',
            age: '18'
        }

        const obj2 = {
            hobby: '干饭',
            say: function () {
                console.log(666);
            }
        }


        obj1.name = 'Jennie';

        const obj3 = { ...obj1, ...obj2 };

        console.log(obj3);
解构
解构赋值

解构赋值:把数组或对象中的值存储在普通变量中

交换变量的值

        // 解构赋值
        let a = 3;
        let b = 4;
        [a, b] = [b, a];

        console.log(a, b); //4,3

数组的解构

深复制

        const arr = [1, 2, 3, 4];
        let [a, b, c, d] = arr;
        console.log(a, b, c, d); //1,2,3,4
        let [m, , n] = [2, 3, 4, 5, 6];
        console.log(m, n); //2 4
        let [a, b, c, d] = [1, 2, [3, 4], 5];
        console.log(c); //[3,4]
        let [a, b, [c, m], d] = [1, 2, [3, 4], 5];
        console.log(a, b, c, m, d); //1,2,3,4,5
对象的解构
        const obj = {
            name: 'jennie',
            age: 18,
            hobby: 'dance'
        }

        let { name: a, age: b, hobby: c } = obj;
        console.log(a, b, c); //jennie,18,dance
        const obj = {
            name: 'jennie',
            age: 18,
            hobby: 'dance'
        }

        let { name, age, hobby } = obj;
        console.log(name, age, hobby); //jennie,18,dance
        const obj = {
            name: 'jennie',
            age: 18,
            hobby: 'dance',
            obj2: {
                sex: '女',
                say: function () {
                    console.log(666);

                }
            }
        }


        let { name, age, hobby, obj2: { sex, say } } = obj;

        console.log(sex);
        say(); //6666

day21

回顾

1.数组有序
pop() push() shift() unshift() 改变原数组
indexOf() includes() join() concat() splice() slice()
forEach() map() filter() some() every() reduce() sort

2.对象 无序
键值对 键名:键值
属性
方法
对象可以自定义属性
DOM对象--标签

3.ES6
模板字符串
变量的声明 let const 
函数参数的默认值 fn(a=0,b=0)
箭头函数 ()=>{}  a=>{} (a,b)=>a+b 没有arguments (...arr)
解构 交换变量的值 解构赋值


cookie

cookie:会话跟踪技术 用于存储数据

cookie 有前提的可以跨页面访问

  • 基于http/https protocol;
  • 同源策略(安全):不同的网站之间不能访问cookie
  • cookie存在客户端
创建cookie

默认到期时间 :会话结束(浏览器关闭)

cookie的key是唯一的,后面会覆盖前面的

document.cookie = 'username=jennie';

路径 path

path=/ ——此站点下的所有路径都可访问

默认情况下,cookie 属于当前页面。

document.cookie = `username=dd;path=/`;

过期时间 expires

 var date = new Date();  // 东八区的时间,比标准时间快了8个小时
 document.cookie = `username=dd;path=/;expires=${date}`;
封装cookie
// 获取所有的cookies   
// 返回值是JOSN格式的数据   [{},{}]
function getCookies() {
    const cookies = document.cookie;
    let arr = cookies.split('; ');
    arr = arr.map(val => {
        const item = val.split('=');
        return {
            name: item[0],
            content: item[1]
        }
    });
    return arr
}




// 添加cookie ,默认时间7天
function setCookie(name, content, days = 7) {
    // 创建的时间实际上是东八区的时间,比标准时间快了8个小时
    const date = new Date();
    date.setHours(date.getHours() - 8);
    // 设置到期时间
    date.setDate(date.getDate() + days);
    document.cookie = `${name}=${content};path=/;expires=${date}`
}

function $(e) {
    return document.querySelector(e)
}

cookie注册登录案例
 <input type="text" id="username" autocomplete="off">
    <br><br>
    <input type="text" id="userpwd" autocomplete="off">
    <br><br>
    <button id="btn">登录</button>

    <script>
        $('#btn').onclick = function () {
            const uname = $('#username').value;
            const upwd = $('#userpwd').value;
            // 不为空
            if (uname && upwd) {
                // document.cookie = `${uname}=${upwd};path=/;expires=${new Date()}`

                // 实际上存储用户名的时候,不需要存密码
                document.cookie = `login_user=${uname};path=/;expires=${new Date()}`;
                location.href = '04other.html'
            }
        }


        function $(e) {
            return document.querySelector(e)
        }
    </script>
 <h1>你好,欢迎
        <!-- <span id="user">QQ</span> -->
        <span>
            <a href="">注册</a>
            <a href="">登录</a>
        </span>
    </h1>
    <script>
        const cookies = document.cookie;
        console.log(cookies)
        // 坑: 分号加空格
        let arr = cookies.split('; ');
        console.log(arr);
        // ["usernames=ee", "username=ee", "yy=666", "uu=222", "login_user=aa"];
        // arr = arr.map(val => {
        //     return {
        //         name: val.split('=')[0],
        //         content: val.split('=')[1]
        //     }
        // })

        arr = arr.map(val =>
        ({
            name: val.split('=')[0],
            content: val.split('=')[1]
        })
        )
        console.log(arr);
        //验证用户名,如果在cookie中找到 对象 name:login_user,返回具有一个值的数组(数组中的值为一个对象)
        const res = arr.filter(val => val.name === 'login_user')[0];
        console.log(res);
        if (res) {
            $('#user').innerHTML = res.content;
        } else {
            alert('请登录')
        }

        function $(e) {
            return document.querySelector(e)
        }

        // [
        //     {
        //         name: 'login_user',
        //         content: 'aa'
        //     },
        //     {
        //         name: 'username',
        //         content: 'ee'
        //     },
        //     {
        //         name: 'usernames',
        //         content: 'ee'
        //     },
        //     {
        //         name: 'uu',
        //         content: '222'
        //     },
        // ]
注册
    <script>

        // 1 点击事件
        //   获取输入发用户名和密码
        //   1,非空
        //   2,判断用户名是否重复
        //   3,把用户名和密码存入cookie


        // 获取所有的cookie  --- 字符串
        const cookies = document.cookie;
        console.log(cookies)  // usernames=ee; yy=666; uu=222; login_user=aa; username=ee
        // 把字符串变成数组
        let arr = cookies.split('; ');
        console.log(arr)
        // map  改变数组中的值  --- 每个值都加1
        arr = arr.map(val => {
            const item = val.split('=');
            return {
                name: item[0],
                content: item[1]
            }
        })
        console.log(arr)


        // JSON 
        // [
        //     {
        //         name: 'login_user',
        //         content: 'aa'
        //     },
        //     {
        //         name: 'username',
        //         content: 'ee'
        //     },
        //     {
        //         name: 'usernames',
        //         content: 'ee'
        //     },
        //     {
        //         name: 'uu',
        //         content: '222'
        //     },
        // ]





        $('#btn').onclick = function () {
            const uname = $('#username').value;
            const upwd = $('#userpwd').value;
            // 验证非空
            if (uname && upwd) {
                // 判断重复  -- 找到用户名
                const res = arr.some(val => val.name === 'user_' + uname);
                // const res = arr.filter(val => val.name === uname)[0];  // obj
                console.log(res);
                if (res) {
                    alert('用户名已被注册')
                } else {
                    alert('恭喜你注册成功');
                    // 把用户名和密码存入cookie
                    // document.cookie = `${uname}=${upwd};path=/;expires=${new Date()}`
                    setCookie('user_' + uname, upwd);
                    location.href = './06登录.html'
                }

                // const res = arr.filter(function (val) {
                //     return val.name == uname
                // })


            }
        }

        function $(e) {
            return document.querySelector(e)
        }

    </script>
登录
 <script>
        // 登录
        // 点击事件
        //   1 获取用户名和密码
        //   2 非空
        //   3 用户名是否存在
        //     3.1 不存在  alert()
        //     3.2 存在
        //       3.2.1 判断密码




        $('#btn').onclick = function () {
            const uname = $('#username').value;
            const upwd = $('#userpwd').value;
            if (uname && upwd) {
                // 判断用户名是否存在
                const arr = getCookies();
                const res = arr.filter(val => val.name === 'user_' + uname)[0];   // obj
                console.log(res)   //{name:"yy",content:"222"}
                if (res) {
                    // 判断密码
                    if (res.content === upwd) {
                        alert('登录成功');
                        // 表明当前登录的用户
                        setCookie('login_user', uname);
                        location.href = './07列表.html'
                    } else {
                        alert('用户名或者密码错误')
                    }
                } else {
                    alert('用户名不存在')
                }

            }
        }


    </script>
用户列表
 <h1>
        logo
        <span id="login_user">欢迎aa</span>
        <span id="noLogin">
            <a href="./06登录.html">登录</a>
            <a href="./05注册.html">注册</a>
        </span>
    </h1>
    <table>
        <thead>
            <tr>
                <th>用户名</th>
                <th>密码</th>
            </tr>
        </thead>
        <tbody></tbody>
    </table>


    <script src="../js/cookie.js"></script>
    <script>

        // 1 判断用户是否登录
        //   没有登录   显示注册
        //   已经登录   
        //        显示用户名
        //        显示用户列表

        const arr = getCookies();
        const res = arr.filter(val => val.name === 'login_user')[0];
        console.log(res)
        if (res) {
            $('#login_user').classList.add('show');
            $('#login_user').innerHTML = res.content;

            // 显示列表
            let fragment = document.createDocumentFragment();
            const arr1 = arr.filter(val => val.name.includes('user_'));
            console.log(arr1)
            arr1.forEach(val => {
                const oTr = document.createElement('tr');
                oTr.innerHTML = `
                    <td>${val.name.replace('user_', '')}</td>
                    <td>${val.content}</td>
                `
                fragment.appendChild(oTr);
            })
            $('tbody').appendChild(fragment)
        } else {
            $('#noLogin').classList.add('show')
        }

    </script>
删除cookie

删除cookie就是设置cookie的有效期

        // 删除cookie   有效期

        document.cookie = `bb=333;path=/;expires=${new Date(-1)}`;
        document.cookie = `login_user=;path=/;expires=${new Date('2020,1,1')}`
cookie小结

cookie 会话跟踪技术

cookie 存储在客户端 会被用户删除

cookie 实现不同页面的数据共享(处在同源策略的情况下)

cookie缺点

  • 容易被用户直接 删除或屏蔽
  • cookie一般只能存储50条左右 4kb
  • cookie在页面向服务器发送请求的时候,会一起被携带过去 影响页面的响应速度

cookie 一般用于存储一些不重要的信息

  • 注册的用户名和密码 重要信息
  • 登录的用户名和密码 不重用信息

localStorage

WebStorage h5提供的一种取代cookie的存储技术

  • sessionStorage 会话 浏览器关闭就删除

  • localStorage 本地 永久有效

  • setItem(key,value) 设置

  • getItem() 获取

  • removeItem() 删除

  • clear() 清空

window.localStorage
localStorage.setItem("key", "value");
var lastname = localStorage.getItem("key");
localStorage.removeItem("key");

day22

回顾

数组常用方法
	splice 删除,替换,新增
	join 数组变字符串
	forEach map filter some every
	
字符串
	split 切割成数组
	replace 替换
	includes
	
对象
	{name:'cc',age:18}
	//对象的遍历 for in
	//键名不会重复
	
JSON数据格式 
	[{},{}]
	
cookie 有前提的实现跨页面的数据共享
    前提:基于http,同源策略
    存储在客户端
    缺点:
        可以被用户删除
        容量小 <4kb
        cookie会随着服务器请求一起发送,影响页面的响应速度
        
        
WebStorage 
	两种API 对象
		localStorage 永久存储
		sessionStorage 页面关闭
		
	方法
		setItem(key,value)
		getItem(key)
		removeItem()
		clear()

localStorage案例

注册
    <input type="text" id="username">
    <br> <br>
    <input type="text" id="userpwd">
    <br><br>
    <input type="button" value="注册" id="btn">

    <script>

        // 收集常见的js报错及原因
        //   博客




        $('#btn').onclick = () => {
            const uname = $('#username').value;
            const upwd = $('#userpwd').value;
            if (uname && upwd) {
                // 判断用户名是否已经被注册
                if (localStorage.getItem('user_' + uname)) {
                    alert('用户名已被注册')
                } else {
                    localStorage.setItem('user_' + uname, upwd);
                    location.href = './02login.html'
                }
            }
        }

        function $(e) {
            return document.querySelector(e)
        }

    </script>
登录
  <input type="text" id="username">
    <br> <br>
    <input type="text" id="userpwd">
    <br><br>
    <input type="button" value="登录" id="btn">

    <script>

        $('#btn').onclick = () => {
            const uname = $('#username').value;
            const upwd = $('#userpwd').value;
            if (uname && upwd) {
                // 判断用户名是否已经被注册
                const res = localStorage.getItem('user_' + uname);
                if (res) {
                    if (res === upwd) {
                        alert('登录成功');
                        localStorage.setItem('login_user', uname);
                        location.href = './03list.html'
                    } else {
                        alert('错误')
                    }
                } else {
                    alert('用户名不存在')
                }
            }
        }

        function $(e) {
            return document.querySelector(e)
        }

    </script>
列表
 <h1>
        logo
        <span id="login_user">欢迎aa</span>
        <span id="noLogin">
            <a href="./02login.html">登录</a>
            <a href="./01reg.html">注册</a>
        </span>
    </h1>
    <table>
        <thead>
            <tr>
                <th>用户名</th>
                <th>密码</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody id="tbody">
            <!-- <tr>
                <td>qq</td>
                <td>11</td>
                <td>删除</td>
            </tr> -->
        </tbody>
    </table>

    <script>
        const res = localStorage.getItem('login_user');
        if (res) {
            login_user.classList.add('show');
            login_user.innerHTML = res;
        } else {
            noLogin.classList.add('show');
        }

        console.log(localStorage)
        const fragment = document.createDocumentFragment();
        //遍历localStorage对象
        for (let key in localStorage) {
            if (key.includes('user_')) {
                const oTr = document.createElement('tr');
                oTr.innerHTML = `
                    <td>${key.replace('user_', '')}</td>
                    <td>${localStorage[key]}</td>
                    <td class="del">删除</td>
                `
                fragment.appendChild(oTr)
            }
        }

        tbody.appendChild(fragment);
        tbody.onclick = e => {
            var e = e || event;
            const target = e.target || e.srcElement;
            if (target.className === 'del') {
                // 删除DOM节点
                target.parentNode.remove();
                const names = target.previousElementSibling.previousElementSibling.innerHTML;
                // 删除对应的数据
                localStorage.removeItem('user_' + names);
            }
        }

    </script>

sessionStorage

  • 依然可以实现不同页面的数据共享,但是不能切换窗口
  • 一般应用于敏感账号的一次性登录
    <!-- 页面跳转,但是属于同一页面 -->
    <a href="./01.test.html">共享数据</a>

    <!-- 不同页面,不可共享数据 -->
    <a href="./test.html" target="_blank">不可进行数据共享</a>

    <script>
        sessionStorage.setItem('uname', 'Jisoo Kim');

        // 三秒后跳转页面,但仍属于同一页面
        setTimeout(() => {
            location.href = './test.html';
        }, 3000)

    </script>

总结

  • cookie <4kb 可以设置路径和到期时间 ,用于存储不太重要的数据
  • sessionStorage <5MB 属于有效期为关闭页面
  • localStorage 长期存储,除非手动删除

JSON

  • JSON.stringify(obj) 将数组/对象转为JSON格式字符串
  • JSON.parse(string) 把数组或对象类型的字符串变为原来的数组或对象
<input type="text" id="username">
    <br><br>
    <input type="text" id="usertel">
    <br><br>
    <input type="text" id="useremail">
    <br><br>
    <input type="text" id="userpwd">
    <br><br>
    <button id="btn">注册</button>


    <script>
        btn.onclick = function () {
            // 手机号唯一
            const uname = username.value;
            const utel = usertel.value;
            const uemail = useremail.value;
            const upwd = userpwd.value;
            const obj = {
                uemail: uemail,
                uname: uname,
                upwd: upwd
            }


            // JSON.stringify()   把数组或者对象变成字符串
            // JSON.parse()       把数组或者对象类型的字符串变成原来的数组或者对象

			//key:user_电话号,value,为字符串类型的对象
            localStorage.setItem('user_' + utel, JSON.stringify(obj));
            console.log(localStorage.getItem('user_' + utel));
            
            //取
            let res = localStorage.getItem('user_' + utel);
            //将对象形式 的字符串,转为对象
            res = JSON.parse(res);
            console.log(res)
        }

    </script>

中文编码

  • encodeURIComponent 对中文进行编码 对部分符号也会编码

  • decodeURIComponent 解码成中文

  • cookie或localStorage 当中尽量不要存储中文,用中文就需进行编码

        //编码

        let encode = encodeURIComponent('张三');
        console.log(encode); //%E5%BC%A0%E4%B8%89

        //解码
        console.log(decodeURIComponent(encode)); //张三


        // 在cookie或者localStorage  当中尽量不要存储中文,实在需要用到中文,就进行编码

        // encodeURIComponent  对中文进行编码    对部分符号也会编码

        // decodeURIComponent  解码成中文

        const names = encodeURIComponent('hello,');


        localStorage.setItem(names, '222')

        console.log(decodeURIComponent(names))

Ajax

ajax : asynchonous javacript and xml / json 异步无刷新技术

xml/json 是一种数据格式

ajax 实现数据交互

前端 画页面 渲染数据 没有权限直接改数据

后端 处理数据 – 给前端

进程 谷歌浏览器

线程 打开不同的页面,不同的线程

  • 多线程
  • 单线程

谷歌内核 多线程

javascript 单线程 js的作用是操作DOM

任务队列

js的运行机制

所有的同步任务都在主线程上排列运行,遇到异步任务,会挂在任务队列中,等到所有的主线任务执行完毕之后,再去看任务队列,如果有任务到时间完成就到主线上去执行此任务

event loop 事件循环

异步程序:

  • 定时器和延时器
  • 事件处理函数
  • ajax
ajax创建

状态码 readyState

  • 0:(未初始化) 还没有调用open()方法
  • 1:(启动) 已经调用open()方法,但还没有调用send()方法。
  • 2:(发送) 已经调用send()方法,但还没有接收到响应。
  • 3:(接收) 已经接收到部分响应数据。
  • 4:(完成) 已经接收到全部的响应数据,且可以在客户端使用了。

响应值 status

  • 1xx
  • 2xx
  • 3xx
  • 4xx
  • 5xx
const xhr = new XMLHttpRequest();
xhr.open("get",'路径',true);
xhr.send();
xhr.onreadystatechange = function(){
	if(xhr.readyState==4&&xhr.status==200){
		//const res = xhr.responseText;
	}
}
        // 创建数据请求
        const xhr = new XMLHttpRequest();
        console.log(xhr.readyState)


        // get 数据请求的方式    
        // 请求数据的路径
        // 异步请求
        xhr.open('get', '../daeta/1.txt', true);

        console.log(xhr.readyState)
        // 发送请求
        xhr.send();
        console.log(xhr.readyState)
        // 监听状态的改变   state 状态
        xhr.onreadystatechange = function () {
            console.log(xhr.readyState)
            // readystate  状态的改变
            // status  后端返回的结果
            if (xhr.readyState == 4 && xhr.status == 200) {
                // 服务器返回的数据
                const res = xhr.responseText;
                console.log(res)
            }
        }

ajax模拟注册

数据

[
    {
        "uname": "jennie",
        "pwd": 111
    },
    {
        "uname": "jisoo",
        "pwd": 222
    },
    {
        "uname": "lisa",
        "pwd": 333
    },
    {
        "uname": "rosie",
        "pwd": 444
    }
]
    <h1>注册</h1>
    用户名: <input type="text" id='username'>
    <br><br>
    密码:<input type="text" id="userpwd">
    <br><br>
    <button id="btn">注册</button>

    <script src="./js/ajax.js"></script>
    <script>
        btn.onclick = () => {
            let uname = username.value.trim();
            let upwd = userpwd.value.trim();

            if (uname && upwd) {

                // ajax请求

                ajax({
                    url: './data/reg.json',
                    success: data => {
                        // 成功后要做的事
                        console.log(data);
						//筛选看是否有重名
                        const res = data.some(val => val.uname == uname);
                        console.log(res);

                        if (res) {
                            alert('用户名已存在');
                        } else {
                            // 跳转登录
                            location.href = './login.html';
                        }


                    }
                })


            } else {
                alert('请输入用户名或密码')
            }
        }
    </script>
登录
  <script>
        btn.onclick = () => {
            let uname = username.value;
            let upwd = userpwd.value;

            if (uname && upwd) {

                ajax({
                    url: './data/reg.json',
                    success: data => {

                        // 数据筛选,得到筛选的用户对象
                        data = data.filter(val => val.uname == uname)[0];
                        console.log(data);

                        if (data) {
                            if (data.pwd == upwd) {
                                // 登录成功
                                alert('登录成功');

                                // 存储当前登录的用户信息
                                localStorage.setItem('login_user', data.uname);

                                // 跳转商品列表
                                location.href = './list.html';


                            } else {
                                alert('用户名或密码错误');
                            }
                        } else {
                            alert('用户不存在')
                        }

                    }
                })


            } else {
                alert('请输入用户名或密码')
            }
        }
    </script>
商品列表渲染 ajax

数据

[
    {
        "goodsName": "娃哈哈AD钙奶",
        "img": "./img/1.jpg",
        "desc": "好喝哈哈哈哈",
        "price": 50
    },
    {
        "goodsName": "手机",
        "img": "./img/a.jpg",
        "desc": "全面屏设计,双扬声器,立体",
        "price": 999
    },
    {
        "goodsName": "小米电视",
        "img": "./img/b.jpg",
        "des": "超大屏,海量内容",
        "price": 10000
    }
]
    <script>
        // 查看用户是否登录

        if (localStorage.getItem('login_user')) {

            // 有用户登录

            $('#login').classList.add('show');
            $('#user').innerHTML = localStorage.getItem('login_user');


            // 商品列表展示
            ajax({
                url: './data/goods.json',
                success: data => {
                    console.log(data);

                    // 显示搜索框
                    $('.search').classList.add('searchshow');

                    // 得到数据,渲染商品列表
                    let fragment = new DocumentFragment();
                    // 遍历商品数据
                    data.forEach(val => {
                        let li = document.createElement('li');
                        li.innerHTML = `
                        <img src="${val.img}" alt="">
                        <h2>${val.goodsName}</h2>
                        <p>${val.desc}</p>
                        <span id='price'>¥${val.price}</span>
                        `;

                        fragment.appendChild(li);
                    });

                    $('ul').appendChild(fragment);

                    // 搜索框绑定点击事件
                    $('.search button').onclick = () => {
                        let content = $('.search input').value;

                        let searchContent = data.filter(val =>
                            val.goodsName.includes(content)

                        );

                        // 清空ul里的内容,重新渲染
                        $('ul').innerHTML = '';

                        console.log(searchContent);

                        let fragment = new DocumentFragment();
                        // 遍历商品数据
                        searchContent.forEach(val => {
                            let li = document.createElement('li');
                            li.innerHTML = `
                        <img src="${val.img}" alt="">
                        <h2>${val.goodsName}</h2>
                        <p>${val.desc}</p>
                        <span id='price'>¥${val.price}</span>
                         `;

                            fragment.appendChild(li);
                        });

                        $('ul').appendChild(fragment);





                    }



                }
            })

        } else {
            // 用户未登录,显示登录注册
            $('#noLogin').classList.add('show');
        }
    </script>

城市三级联动

数据

[
    {
        "province": "湖北省",
        "children": [
            {
                "city": "武汉市",
                "children": [
                    "江岸区",
                    "江汉区",
                    "硚口区",
                    "汉阳区",
                    "武昌区"
                ]
            },
            {
                "city": "孝感市",
                "children": [
                    "孝南区",
                    "应城市",
                    "安陆市",
                    "汉川市"
                ]
            }
        ]
    },
    {
        "province": "江苏省",
        "children": [
            {
                "city": "南京市",
                "children": [
                    "玄武区",
                    "白下区",
                    "鼓楼区"
                ]
            },
            {
                "city": "宿迁市",
                "children": [
                    "宿城区",
                    "宿豫区"
                ]
            }
        ]
    },
    {
        "province": "山西省",
        "children": [
            {
                "city": "太原市",
                "children": [
                    "小店区",
                    "迎泽区",
                    "杏花岭区"
                ]
            },
            {
                "city": "大同市",
                "children": [
                    "南郊区",
                    "光临县"
                ]
            }
        ]
    }
]
<body>
    <h1>全国城市三级联动</h1>

    <script src="./js/ajax.js"></script>
    <h2>

        <select id="province">
            <option>省份</option>
        </select>

        <select id="city">
            <option>地级市</option>
        </select>

        <select id="area">
            <option>市、县级市</option>
        </select>
    </h2>

    <script>

        // 首先加载省
        ajax({
            url: "./data/city.json",
            success: data => {
                console.log(data);


                data.forEach(val => {
                    let option = document.createElement("option");
                    option.innerHTML = val.province;
                    $('#province').appendChild(option);


                });
            }
        });

        // // 省绑定事件
        $("#province").onchange = function () {
            // console.log(this);
            console.log(this.value);
            let pro = this.value;

            ajax({
                url: "./data/city.json",
                success: data => {

                    // data.forEach(val => {
                    //     let option = document.createElement("option");
                    //     option.innerHTML = val.province;
                    //     $('#province').appendChild(option);
                    // });


                    // console.log(data);
					//得到选择的省的数组对象(即包含其孩子children)
                    let prov = data.filter(val => {
                        return val.province == pro;
                    })[0];


                    $("#city").innerHTML = '<option>地级市</option>';
                    $("#area").innerHTML = '<option>地区</option>';

                    // 如果有对应的市
                    if (prov) {
                        prov.children.forEach(val => {
                            let option = document.createElement("option");
                            option.innerHTML = val.city;
                            $('#city').appendChild(option);

                        });
                    }

                    $("#city").onchange = function () {
                        console.log(this);
                        let city = this.value;
                        let area = prov.children.filter(val => {
                            return val.city === city;
                        })[0];



                        $("#area").innerHTML = '<option>地区</option>';

                        if (area) {
                            area.children.forEach(val => {
                                console.log(val);

                                let option = document.createElement("option");
                                option.innerHTML = val;
                                $('#area').appendChild(option);
                            })
                        }
                    }
                }
            });

        }

        // 箭头函数,this为window
        // $('#province').onchange = () => {
        //     console.log(this);
        //     console.log(this.value);
        // }

aJax封装

// 参数:对象类型 
// path:请求路径
// method: get/post
// dataType:返回数据的类型 json(从后端的到josn格式的字符串,再转为具体数组/对象,返回给前端)/text
// success: 成功后的回调函数 data ,请求后得到的数据
function ajax(option) {

    const { path, method = "get", dataType = "json", success } = obj;

    const xhr = new XMLHttpRequest();
    xhr.open(method, path, true);
    xhr.send();

    xhr.onreadystatechange = () => {

        if (xhr.readyState == 4 && xhr.status == 200) {
            let res = xhr.responseText;
            if (dataType == 'json') {
                // 从请求初(后端)得到json格式字符串,再转为具体数组/对象,返回,给成功后的调用函数使用
                res = JSON.parse(xhr.responseText);
            }

            success && success(res);
        }
    }
}

day23

网站开发的流程
//需求
//原型图
//UI出设计图 同时后端设计数据库和接口
//前端页面
//前端把静态页面变成动态的页面 需要数据

//接口 --前端想要的数据
	//要求前端传过去的数据
	
	
//前后端联调 调接口

//测试

//上线 域名, 服务器 --网站对外发布

//狭义的服务器:超级计算机
// 广义的服务器:服务器上所需要的环境  -- 服务器和数据库

// phpstudy_pro  集成了这些环境  apache-服务器  mysql-数据库

php实现动态交互性网站的服务端脚本语言

php能做什么

  • 写html js php写代码
  • 可以读写数据库的内容
  • 读写cookie
  • 读写服务器上的文件

php运行在服务器上

vscode live server 是一个假的服务 不能进行逻辑处理

文件夹必须放在 小P WWW文件夹下

            // 访问PHP文件   

            // IP地址访问

            // 127.0.0.1/

            // localhost
登录的接口

路径 : 192.168.56.23/login.php
前端需要携带的数据
username : string
userpwd : string
后端返回的数据
{
status : true ,
msg : '登录成功'
}

php语法

输出

echo

<?php

    header('content-type:text/html;charset=utf-8');

    echo('hello world');
    
    echo '<br/>';

    echo 'BLACKPINK';

?>

var_dump

<?php

    header('content-type:text/html;charset=utf-8');

    var_dump('hello'); //string(5) "hello"

    var_dump(3); //int(3)

?>
变量和数据类型

变量的声明使用$

数据类型 int float string null object array

    $a = 10;
    $b = 3.4;
    $c = 'test';

    var_dump($a); //int(10) 
    var_dump($b); //float(3.4) 
    var_dump($c); //string(4) "test"
数组

php中的数组分为两种

  • 数值数组 ——js的数组
  • 关联数组——js的对象的形式
    $arr = [3,4,5,6];

    echo $arr; //Array


    // array(4) { [0]=> int(3) [1]=> int(4) [2]=> int(5) [3]=> int(6) }
    var_dump($arr); 

关联数组

    $objArr = ['name'=>'jennie',"age"=>18];

    // echo $objArr; //Arr


    //array(2) { ["name"]=> string(6) "jennie" ["age"]=> int(18) }
    var_dump($objArr)

运算符
  • 算数运算符
  • 比较运算符
  • 逻辑运算符
  • 自增自减
  • 并置运算符 . ,相当于js中的 +,拼接字符串
  • 双引号实现类似js的模板字符串 ``
    $a = 3+4;
    echo $a; //7
    
    
     $a = 3>4;
    // echo $a; //7
    var_dump($a);
并置运算符
    $a = 'I love ';
    $b = 'BLACKPINK';

    echo ($a.$b); //I love BLACKPINK
双引号
    $a = 3;
    $b = 4;
    $c = $a+$b;

    echo("$a+$b 的值是:$c"); //3+4 的值是:7
数组的遍历
数值数组
    $arr = [3,4,5,6];
    for($i=0;$i<count($arr);$i++){
        echo $i;
         echo $arr[$i];
         echo '<br/>';
    }
    
    
0 3
1 4
2 5
3 6
关联数组遍历
    $arr = ['name'=>'jennie','age'=>18,'pwd'=>'test123'];

    //jennie18test123
    foreach($arr as $val){
        echo $val;
    }
    $arr = ['name'=>'jennie','age'=>18,'pwd'=>'test123'];

    // namejennie
    // age18
    // pwdtest123

    foreach ($arr as $key=>$val){
        echo $key;
        echo $val;
        echo '<br/>';
    }

json转换

json_encode
    $obj = ['name'=>'jennie','age'=>18,'pwd'=>'test123'];

    // {
    //     "name": "jennie",
    //     "age": 18,
    //     "pwd": "test123"
    // }
    echo json_encode($obj);
json_decode

表单

在这里插入图片描述
action跳转

使用form表单的action会跳转到请求地址。

get请求的执行效率更高

post数据量更大

post请求更安全

get获取数据列表

post修改数据

get方式

form.html

注意name要与后端接口一致

    <form action="../php/first.php" method="get">
        用户名 <input type="text" name='username'>
        <br><br>
        密码:<input type="text" name='password'>
        <br><br>
        <button type="submit">注册</button>

    </form>

first.php

<?php

    header('content-type:text/html;charset=utf-8');

    // get方式接收前端数,name一致
    $uname = $_GET['username'];
    $password = $_GET['password'];

    //转为php关联数组(类似对象)
    $obj =['name'=>$uname,'pwd'=>$password];


    // 转为json格式字符串
    echo json_encode($obj); //{"name":"\u738b\u4e94","pwd":"123"} 中文字符编码原因

?>
post方式

html

    <form action="../php/first.php" method="post">
        用户名 <input type="text" name='username'>
        <br><br>
        密码:<input type="text" name='password'>
        <br><br>
        <button type="submit">注册</button>

    </form>

php

<?php

    header('content-type:text/html;charset=utf-8');

    // post方式接收前端数,name一致
    $uname = $_POST['username'];
    $password = $_POST['password'];

    //转为php关联数组(类似对象)
    $obj =['name'=>$uname,'pwd'=>$password];


    // 转为json格式字符串
    echo json_encode($obj);

?>
ajax方式
get方式
  • get方式需要在请求地址后拼接 ?参数名1=参数值1&参数名2=参数值2

html

    用户名 <input type="text" id='username'>
    <br><br>
    密码:<input type="text" id='password'>
    <br><br>
    <button id='btn'>注册</button>

    <script>

        btn.onclick = function () {
            let uname = username.value;
            let upwd = password.value;


            // 发送请求给后端
            const xhr = new XMLHttpRequest();

            // 参数
            let param = `username=${uname}&password=${upwd}`;

            // get方式拼接参数
            xhr.open('get', '../php/get.php?' + param);

            xhr.send();

            xhr.onreadystatechange = () => {

                if (xhr.readyState == 4 && xhr.status == 200) {
                    // 请求成功,得到数据

                    // 返回的是Json格式字符串(中文还未转码)
                    let res = xhr.responseText; //string {"name":"\u738b\u4e94","pwd":"123"}
                    console.log(res);

                    // 转为javascript中的对象

                    res = JSON.parse(res); //obj {name: "王五", pwd: "123"}

                    console.log(res);

                }
            }

        }

    </script>

php


post方式
  • post方式必须设置请求头 xhr.setRequestHeader(“Content-type”,“application/x-www-form-urlencoded; charset=utf-8”)
  • send时传参

html

    用户名 <input type="text" id='username'>
    <br><br>
    密码:<input type="text" id='password'>
    <br><br>
    <button id='btn'>注册</button>

    <script>

        btn.onclick = function () {
            let uname = username.value;
            let upwd = password.value;


            // 发送请求给后端
            const xhr = new XMLHttpRequest();

            // 参数
            let param = `username=${uname}&password=${upwd}`;

            // 请求头改为post
            xhr.open('post', '../php/post.php');

            // 设置请求头
            xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
            // send时发送参数


            xhr.send(param);

            xhr.onreadystatechange = () => {

                if (xhr.readyState == 4 && xhr.status == 200) {
                    // 请求成功,得到数据

                    // 返回的是Json格式字符串(中文还未转码)
                    let res = xhr.responseText;
                    console.log(res); //string {"uname":"\u91d1\u667a\u59ae","upwd":"111"}

                    // 转为javascript中的对象
                    res = JSON.parse(res);

                    console.log(res);//object{uname: "金智妮", upwd: "111"}

                }
            }

        }

    </script>

php

<?php

    header('content-type:text/html;charset=utf-8');

    $uname = $_POST['username'];
    $upwd = $_POST['password'];

    $obj = ['uname'=>$uname,'upwd'=>$upwd];

    // 返回josn格式字符串 对象
    echo(json_encode($obj));


?>

ajax封装

//ajax 向服务器请求数据
// 1.创建一个请求 new
// 2.打开连接 open
// 3.发送连接 send
// 3.1携带数据
// 3.2 方式 get/post 携带数据的区别
// 4.等待 onreadystatechange =function (){}


/**
 * 
 * @param {对象} options
 * type:请求方式 get/post
 * path:请求路径,url
 * dataType:后端返回数据格式
 * data:前端向后端传递的数据,对象格式
 *  success:成功后的回到函数 ,data形参:请求返回的数据
 */
function ajax(options) {
    const {
        type = 'get',
        path,
        dataType = 'json',
        data,
        success
    } = options;


    //解析传过来的参数(遍历对象)
    let params = '';
    for (let key in data) {
        params += `${key}=${data[key]}&`;
    }
    //将最后一个多余的&删除
    params = params.substring(0, params.length - 1);


    const xhr = new Request();

    // 判断数据请求方式
    //get方式
    if (type.toLowerCase() == 'get') {
        xhr.open('get', path + '?' + params);
        xhr.send();
    } else if (type.toLowerCase() == 'post') {
        //post方式
        xhr.open('post', path);
        // 设置请求头
        xhr.setRequestHeader('Content-type', 'application/x-www-form- urlencoded;charset=utf-8');
        xhr.send(params);
    }


    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
            // 请求成功

            let data = xhr.responseText;

            // dataType为josn时,将最后的结果数据转为json
            if (dataType.toLowerCase() == 'json') {
                data = JSON.parse(res);
            }

            // 执行成功后的回调函数
            sussess && success(data);

        }
    }


}

day24

php数据库连接

<?php
    header('content-type:text/html;charset=utf-8') ;

    // php连数据库

    $host = 'localhost:3306';
    $user = 'root';
    $pwd = 'root';
    // 注意:不是连接名,而是数据库的名字
    $dbname = 'test';

    // 创立数据库连接
    $conn = mysqli_connect($host , $user , $pwd , $dbname);

    // if($conn) {
    //     echo 'ok';
    // } else {
    //     echo 'err';
    // }

    if(!$conn) {
        // 结束整个php
        die('数据库连接失败');
    }

    echo 'ok';


?>

php的sql查询

 // 定义sql语句  username字段名
        $sql = "select * from user_info where username = '$uname'";
        // 执行sql语句   执行之后会得到一个结果集
        $res = mysqli_query($conn , $sql);
        // 需要把结果集变成数组
        $arr = mysqli_fetch_array($res) ; //得到的是一条数据
        // echo json_encode($arr);
    // 定义sql语句
    $sql = "select * from user_score";
    // 执行sql语句   执行之后会得到一个结果集
    $res = mysqli_query($conn , $sql);
    
    $list = [];
    while($data = mysqli_fetch_array($res)) {
        // 把需要的数据留下来
        $temp = [];
        $temp['uid'] = $data['uid'];
        $temp['username'] = $data['username'];
        $temp['html'] = $data['html'];
        $temp['css'] = $data['css'];
        $temp['js'] = $data['js'];
        $temp['php'] = $data['php'];
        array_push($list , $temp) ;
    }

删除/新增,返回影响行数

        // 定义sql语句
        $sql = "delete from user_score where uid = $id ";
        // 执行sql语句   执行之后会得到一个结果集
        mysqli_query($conn , $sql);

        $rows = mysqli_affected_rows($conn) ;

        if($rows > 0) {
            $obj['flag'] = true ;
            $obj['msg'] = '删除成功' ;
        } else {
            $obj['flag'] = false ;
            $obj['msg'] = '删除失败' ;
        }
登录
  • 前端传用户名/密码给后端
  • 后端
    • 根据用户名查询数据库
    • 无结果集,用户不存在,直接 返回status=false,msg=用户名不存在
    • 有结果集,说明用户存在,比对用户输入的密码与查询到的密码,比对正确,status=true。否则status=false,msg=用户名/密码输入错误。

php

<?php
    header('content-type:text/html;charset=utf-8') ;

    // php连数据库

    $host = 'localhost:3306';
    $user = 'root';
    $pwd = 'root';
    // 注意:不是连接名,而是数据库的名字
    $dbname = 'test';

    // 创立数据库连接
    $conn = mysqli_connect($host , $user , $pwd , $dbname);


    if(!$conn) {
        // 结束整个php
        die('数据库连接失败');
    }




    // 登录的接口
    // 1 连数据库
    // 2 接受前端传来的用户名和密码
    //   2.1 收到了
    //   2.2 收不到  返回结果
    // 3 去数据库查数据
    //   3.1 查询用户名
    //     3.1.1 不存在  返回结果
    //     3.1.2 存在 
    //        3.1.2.1 找密码   返回结果

    // 接受前端传来的数据
    $uname = $_POST['username'] ;
    $upwd = $_POST['userpwd'] ;

    // $uname = 'aa' ;
    // $upwd = '11' ;

    // 返回给前端的结果
    $obj = [];

    // 判断数据是否接受成功
    if($uname && $upwd) {
        // 查询用户名是否存在

        // 定义sql语句  username字段名
        $sql = "select * from user_info where username = '$uname'";
        // 执行sql语句   执行之后会得到一个结果集
        $res = mysqli_query($conn , $sql);
        // 需要把结果集变成数组
        $arr = mysqli_fetch_array($res) ;
        // echo json_encode($arr);
        // 判断是否有结果
        if($arr) {
            // 判断密码
            if($arr['userpwd'] == $upwd) {
                $obj['status'] = true ;
                $obj['msg'] = '登录成功' ;
            } else {
                $obj['status'] = false ;
                $obj['msg'] = '用户名或密码错误' ;
            }
        } else {
            $obj['status'] = false ;
            $obj['msg'] = '用户名不存在' ;
        }

    } else {
        $obj['status'] = false ;
        $obj['msg'] = '前端数据错误' ;
    }
	//转为josn字符串格式给前端
    echo json_encode($obj);
?>

html

  <input type="text" id="user">
    <input type="text" id="pwd">
    <button id="btn">登录</button>

    <script src="../js/tool.js"></script>
    <script>

        // 登录的接口
        // 路径   '../php/login.php'
        // 参数   
        //    请求方式  post
        //    参数名字   
        //        username  string
        //        userpwd   string
        // 后端返回的数据  json
        //   {status : true , msg : '登录成功'}
        //   {status : false , msg : '登录失败'}



        $('#btn').onclick = () => {
            const uname = $('#user').value;
            const upwd = $('#pwd').value;
            if (uname && upwd) {
                ajax({
                    path: '../php/login.php',
                    data: {
                        username: uname,
                        userpwd: upwd
                    },
                    type: 'post',
                    successCB: data => {
                        console.log(data);
                        // 解构
                        const { msg, status } = data;
                        if (status) {
                            console.log(msg);
                            localStorage.setItem('login_user', username);
                        } else {
                            alert(msg);
                        }
                    }
                })
            }
        }
    </script>
注册

php

<?php
    header('content-type:text/html;charset=utf-8') ;

    // php连数据库

    $host = 'localhost:3306';
    $user = 'root';
    $pwd = 'root';
    // 注意:不是连接名,而是数据库的名字
    $dbname = 'test';

    // 创立数据库连接
    $conn = mysqli_connect($host , $user , $pwd , $dbname);

    if(!$conn) {
        // 结束整个php
        die('数据库连接失败');
    }

    // 注册的接口
    // 1 连数据库
    // 2 接受前端传来的用户名和密码
    //   2.1 收到了
    //   2.2 收不到  返回结果
    // 3 去数据库查数据
    //   3.1 查询用户名
    //     3.1.1 已存在  返回结果
    //     3.1.2 不存在 
    //        3.1.2.1 继续去数据库添加数据  insert into

    // 接受前端传来的数据
    $uname = $_POST['username'] ;
    $upwd = $_POST['userpwd'] ;

    // $uname = 'yys钱' ;
    // $upwd = '11' ;

    // 返回给前端的结果
    $obj = [];

    // 判断数据是否接受成功
    if($uname && $upwd) {
        // 查询用户名是否存在

        // 定义sql语句
        $sql = "select * from user_info where username = '$uname'";
        // 执行sql语句   执行之后会得到一个结果集
        $res = mysqli_query($conn , $sql);
        // 需要把结果集变成数组
        $arr = mysqli_fetch_array($res) ;
        // echo json_encode($arr);
        // 判断是否有结果
        if(!$arr) {
            // 插入语句
            $sql =  "insert into user_info (username , userpwd) VALUES ('$uname' , '$upwd')" ;
            // 执行
            mysqli_query($conn , $sql) ;
            // 受影响的行数
            $rows = mysqli_affected_rows($conn) ;
            // echo $rows;
            // 受影响的行数大于0
            if($rows > 0) {
                $obj['status'] = true ;
                $obj['msg'] = '注册成功' ;
            } else {
                $obj['status'] = false ;
                // 数据没有插入成功
                $obj['msg'] = '数据库注册失败' ;
            }
        } else {
            $obj['status'] = false ;
            $obj['msg'] = '用户名已被注册' ;
        }

    } else {
        $obj['status'] = false ;
        $obj['msg'] = '前端数据错误' ;
    }

    // JSON_UNESCAPED_UNICODE 防止中文编码
    echo json_encode($obj , JSON_UNESCAPED_UNICODE);
?>

html

 <input type="text" id="user">
    <input type="text" id="pwd">
    <button id="btn">注册</button>

    <script src="../js/tool.js"></script>
    <script>

        // 注册的接口
        // 路径   '../php/reg.php'   404
        // 参数   
        //    请求方式  post
        //    参数名字   
        //        username  string
        //        userpwd   string
        // 后端返回的数据  json
        //   {status : true , msg : '注册成功'}
        //   {status : false , msg : '注册失败'}


        $('#btn').onclick = () => {
            const username = $('#user').value;
            const userpwd = $('#pwd').value;
            if (username && userpwd) {
                ajax({
                    path: '../php/reg.php',
                    data: {
                        username,
                        userpwd
                    },
                    type: 'post',
                    successCB: data => {
                        console.log(data);
                        // 解构
                        const { msg, status } = data;
                        if (status) {
                            alert(msg)
                            location.href = './login.html'
                        } else {
                            alert(msg);
                        }
                    }
                })
            }
        }
    </script>
列表渲染

php

<?php
    header('content-type:text/html;charset=utf-8') ;

    // php连数据库

    $host = 'localhost:3306';
    $user = 'root';
    $pwd = 'root';
    // 注意:不是连接名,而是数据库的名字
    $dbname = 'test';

    // 创立数据库连接
    $conn = mysqli_connect($host , $user , $pwd , $dbname);

    // if($conn) {
    //     echo 'ok';
    // } else {
    //     echo 'err';
    // }

    if(!$conn) {
        // 结束整个php
        die('数据库连接失败');
    }

    // 返回给前端的结果
    $obj = [];

    

    // 定义sql语句
    $sql = "select * from user_score";
    // 执行sql语句   执行之后会得到一个结果集
    $res = mysqli_query($conn , $sql);
    
    $list = [];
    while($data = mysqli_fetch_array($res)) {
        // 把需要的数据留下来
        $temp = [];
        $temp['uid'] = $data['uid'];
        $temp['username'] = $data['username'];
        $temp['html'] = $data['html'];
        $temp['css'] = $data['css'];
        $temp['js'] = $data['js'];
        $temp['php'] = $data['php'];
        array_push($list , $temp) ;
    }

    if($list) {
        $obj['status'] = true ;
        $obj['data'] = $list ;
    } else {
        $obj['status'] = false ;
        $obj['msg'] = '数据请求失败' ;
    }



    echo json_encode($obj);
?>

php

 <h1>
        <span class="login"></span>
        <span class="nologin">
            <a href="">登录</a>
            <a href="">注册</a>
        </span>
    </h1>

    <ul>
        <li>
            <span>姓名</span>
            <span>html</span>
            <span>css</span>
            <span>js</span>
            <span>php</span>
            <span>
                操作
            </span>
        </li>
    </ul>

    <ul class="list">
        <li>
            <span>yy</span>
            <span>100</span>
            <span>100</span>
            <span>100</span>
            <span>100</span>
            <span>
                <button class="edit">编辑</button>
                <button class="del">删除</button>
            </span>
        </li>
    </ul>

    <script src="../js/tool.js"></script>

    <script>
        // 根据localStorage
        const uname = localStorage.getItem('login_user');
        if (uname) {
            $('.login').innerHTML = uname;
            ajax({
                path: '../php/list.php',
                type: 'get',
                successCB: data => {
                    console.log(data);
                    var { status, msg, data } = data;
                    if (status) {
                        console.log(data);
                        let res = '';
                        // val 实际上是一个对象 val = {uid , }
                        // val 进行解构
                        data.forEach(({ uid, username, html, css, js, php }) => {
                            res += `
                            <li>
                                <span>${username}</span>
                                <span>${html}</span>
                                <span>${css}</span>
                                <span>${js}</span>
                                <span>${php}</span>
                                <span data-id="${uid}">
                                    <button class="edit">编辑</button>
                                    <button class="del">删除</button>
                                </span>
                            </li>
                            `
                        })
                        console.log(res)
                        $('.list').innerHTML = res;
                    } else {
                        console.log(msg)
                    }
                }
            })
        } else {
            $('.nologin').style.display = 'inline-block';
        }
删除

php

<?php
    header('content-type:text/html;charset=utf-8') ;

    // php连数据库

    $host = 'localhost:3306';
    $user = 'root';
    $pwd = 'root';
    // 注意:不是连接名,而是数据库的名字
    $dbname = 'test';

    // 创立数据库连接
    $conn = mysqli_connect($host , $user , $pwd , $dbname);

    // if($conn) {
    //     echo 'ok';
    // } else {
    //     echo 'err';
    // }

    if(!$conn) {
        // 结束整个php
        die('数据库连接失败');
    }

    // echo 'ok';


    // 删除的接口
    // 1 连数据库
    // 2 接受前端传来的id
    //   2.1 收到了
    //   2.2 收不到  返回结果
    // 3 去数据库删数据
    //   3.1 受影响的行数
    

    // 接受前端传来的数据
    $id = $_POST['userid'] ;


    // 返回给前端的结果
    $obj = [];

 

        // 定义sql语句
        $sql = "delete from user_score where uid = $id ";
        // 执行sql语句   执行之后会得到一个结果集
        mysqli_query($conn , $sql);

        $rows = mysqli_affected_rows($conn) ;

        if($rows > 0) {
            $obj['flag'] = true ;
            $obj['msg'] = '删除成功' ;
        } else {
            $obj['flag'] = false ;
            $obj['msg'] = '删除失败' ;
        }

      


    // JSON_UNESCAPED_UNICODE 防止中文编码
    echo json_encode($obj , JSON_UNESCAPED_UNICODE);
?>

html

     // 绑定事件 
        $('.list').onclick = e => {
            var e = e || event;
            var target = e.target;
            const userid = target.parentNode.getAttribute('data-id');
            // 删除
            // 删除的接口
            // 路径   '../php/del.php'
            // 参数   
            //    请求方式  post
            //    参数名字   
            //        userid
            // 后端返回的数据  json
            //   {flag : true , msg : '删除成功'}
            //   {flag : false , msg : '删除失败'}

            ajax({
                type: 'post',
                path: '../php/del.php',
                data: {
                    userid,
                },
                successCB: data => {
                    console.log(data);
                    const { flag, msg } = data;
                    if (flag) {
                        alert(msg);
                        target.parentNode.parentNode.remove()
                    } else {
                        alert(msg)
                    }
                }
            })
        }

day26

同源策略

是一种约定,是浏览器最基本也是最核心的安全功能,少了它,浏览器的正常功能会受到影响,可以说web是构建在同源策略的基础之上的,浏览器只是针对同源策略的一种实现。

同源

同源: 域名,端口,协议 必须相同

  • 协议:http / https
  • 端口 :80/5500
  • 域名 :jd.com / taobao.com

有的时候,一个大型网站有很多小的网站共同构建 需要实现数据共享

例如百度

  • https://www.baidu.com/
  • https://www.news.baidu.com/
  • https://www.mp3.baidu.com/

跨域

出于浏览器的同源策略限制。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。

使用vscode的LiveServer起一个服务,此时 ,端口会变,访问不同源的网站

http://127.0.0.1:5500/html/test.html

1.php

<?
   echo '888';
?>

html

因为同源策略受限,不同源的网站之间不能数据共享

    <script src="../js/ajax.js"></script>

    <script>
        ajax({
            path: 'http://192.168.56.110/day26/php/kuayu.php',
            type: 'get',
            success: function (data) {
                console.log(data);

            }

        })
    </script>

此时会报错

Access to XMLHttpRequest at 'http://192.168.56.110/day26/php/kuayu.php?' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

解决跨域

CROS

CORS 是跨域资源分享(Cross-Origin Resource Sharing)的缩写。它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法。

后端说明一下谁跨域访问我的接口

header('Access-Control-Allow-Origin: http://127.0.0.1:5500');  // 只允许指定的用户访问
 header('Access-Control-Allow-Origin: *');  // 允许所有的人访问

修改Php

<?

// 允许 http://127.0.0.1:5500的可以访问
header('Access-Control-Allow-Origin: http://127.0.0.1:5500');
   echo '888';
?>

html

    <script>
        ajax({
            path: 'http://192.168.56.110/day26/php/kuayu.php',
            type: 'get',
            success: function (data) {
                console.log(data);

            }

        })
    </script>
jsonp
  • href与src不受同源策略的影响(img,script标签,link标签【使用href】)

  • 跨域 :只能以get方式访问接口,一般用于查询。(因为一般删除,修改,之类的接口,后端会使用Post方式,此时使用get方式,后端后接受不到参数)

  • 动态创建script标签

  • 给标签设置路径:需要访问的接口

  • 如果要携带参数,那么就在接口后面拼接问号

  • 后端返回的是一个函数调用

  • 前端定义一个同名函数来接受后端的数据

<?

//    $user = $_GET('user');
   $user = 'blink';
   echo "fn($user)";
?>

直接访问php结果

fn(blink) //此时blink代表一个变量,错误

正确写法

<?

//    $user = $_GET('user');
   $user = 'blink';
   echo "fn('$user')";
?>


//fn('blink')

前端

    <script>

        // src不受同源策略的影响
        var oScript = document.createElement('script');
        oScript.src = 'http://192.168.137.1/day26/php/kuayu.php?user=jennie';
        document.body.appendChild(oScript);

        // 回调函数
        function fn(data) {
            console.log(data);
        }

    </script>

php

<?
   $user = $_GET['user'];
   echo "fn('$user')";
?>

结果

打印 jennie

对象php

<?
   $user = $_GET['user'];

   $obj = [];
   $obj['status'] = true;
   $obj['data'] = $user;

   $obj = json_encode($obj);
   echo "fn(${obj})";
?>
百度搜索api接口
https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=key

day27

回顾

 1.
 商品列表跳转到详情页   根据商品的id进行数据的更改
 queryString
 network
 get   前端携带了参数  queryString parameters   不能说明后端确实收到
 post  前端携带了参数 FormData    不能说明后端确实收到
 
 前端数据错误-- - 参数没有收到  (1 请求方式不对,2参数确实没有携带)
 同源策略  域名,端口号,协议
 3 跨域
 跨域的解决方案
 	 1 CORS   后端说明一下谁跨域访问我的接口
 	 	header('Access-Control-Allow-Origin: http://127.0.0.1:5500');  // 只允许指定的用户访问
 	 	 header('Access-Control-Allow-Origin: *');  // 允许所有的人访问
 	
 	 2 jsonp  利用了src和href 不受同源策略的影响   get
 	 	创建script标签,把接口放在src属性,参数就直接拼接在后面 
 	 	后端会返回给你一个函数的执行(携带了参数) 
 	 	前端定义这个同名函数用于接收后端传来的参数
 	 	
 	 
百度接口利用

接口

https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=key
<body>
    <input type="text" id="inp">
    <div class="list">
        <p>
            <a href=""></a>
        </p>
    </div>

    <script>
        // https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=关键字

        inp.oninput = function () {
            const wd = this.value;
            if (!wd) {
                return
            }
            const oScript = document.createElement('script');
            oScript.src = `https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=${wd}`;
            oScript.id = 'jsonp';
            // 先判断这个标签是否存在
            const os = document.querySelector('#jsonp');
            if (os) {
                os.remove()
            }
            document.body.appendChild(oScript);
        }

        // window.baidu.sug({q:"1",p:false,s:["1升等于多少毫升","1kg等于多少斤","1美元等于多少人民币","163 邮箱","192.1681.1","1吨等于多少千克","192.168.0.1 登陆页面","163","163邮箱登录","12306官网"]});


        var baidu = {
            sug: data => {
                console.log(data);
                const { s } = data;
                let html = '';
                s.forEach(val => {
                    html += `
                    <p>
                        <a href="https://www.baidu.com/s?wd=${val}">${val}</a>
                    </p>
                    `
                })
                document.querySelector('.list').innerHTML = html;
            }
        }

    </script>

try

    <script>
        try {
            JSON.parse('hello');
        } catch (error) {
            console.log(error);

        }

        console.log(ff);

    </script>

地狱回调

异步

  • 事件处理函数
  • 定时器和延时器
  • ajax
        // document.onclick = function () { }

        // setTimeout(function () { }, 1000) 

        // xhr.onreadystatechange = function(){}

1.php

<?
    echo '湖北';
?>

2.php

<?
    echo '武汉';
?>

3.php

<?
    echo '新洲';
?>

思考:发现ajax是 异步的,执行顺序靠请求的时间,不固定

       // var str = '';
        // 请求接口1  str += data
        // 请求接口2  str += data
        // 请求接口3  str += data
        
         // 执行完所有的主线任务,遇到异步任务就挂在任务队列里面
          // 任务队列看谁先请求到数据  就在主线任务上执行
          
          
          // 实际上想实现异步中的同步
           // 先拿到1,确保拿到1之后再拿2,2拿到之后才能拿3
           
        // let str = '';
        // ajax({
        //     type: 'get',
        //     dataType: '',
        //     path: '../php/1.php',
        //     successCB: data => {
        //         str += data
        //     }
        // })

        // ajax({
        //     type: 'get',
        //     dataType: '',
        //     path: '../php/2.php',
        //     successCB: data => {
        //         str += data
        //     }
        // })

        // ajax({
        //     type: 'get',
        //     dataType: '',
        //     path: '../php/3.php',
        //     successCB: data => {
        //         str += data
        //         console.log(str)
        //     }
        // })

地狱回调

 // 恐怖回调   地狱回调

        let str = '';
        ajax({
            type: 'get',
            dataType: '',
            path: '../php/1.php',
            successCB: data => {
                // 才能确认拿到数据1
                str += data;
                ajax({
                    type: 'get',
                    dataType: '',
                    path: '../php/2.php',
                    successCB: data => {
                        // 才能确认拿到数据2
                        str += data
                        ajax({
                            type: 'get',
                            dataType: '',
                            path: '../php/3.php',
                            successCB: data => {
                                str += data
                                console.log(str)
                            }
                        })
                    }
                })
            }
        })

promise

Promise是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了用法,原生提供了Promise对象。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。
Promise提供统一的API,各种异步操作都可以用同样的方法进行处理。

promise对象特点

  1. 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为成功fulfilled和从pending变为失败的rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。

promise 构造函数—对象

  • resolve 承诺兑现 成功的
  • reject 承诺没有兑现 失败的
const p = new Promise((resolve, reject) => {
            console.log(1)
            // 异步处理程序
            setTimeout(() => {
                // 产生一个奇数
                var num = 37;
                if (num % 2) {
                    resolve(num)
                } else {
                    reject(num)
                }
            }, 1000)
            console.log(2)
        })
        console.log(p)


        // 许下承诺  pending-- - 一段时间去考验承诺是否兑现

        // 1s之后  resolve / reject

        p.then(function (num) {
            console.log('成功的生成了奇数:' + num)
        }, function (err) {
            console.log('失败的生成了其他数:' + err)
        })

    </script>
promise实现Ajax
<script>
        const p = new Promise((resolve, reject) => {
            ajax({
                type: 'get',
                dataType: '',
                path: '../php/1.php',
                successCB: data => {
                    resolve(data)
                },
                failCB: err => {
                    reject(err)
                }
            })
        });


        p
            .then(
                data => {
                    console.log(data)
                },
                err => {
                    console.log(err)
                }
            )
    </script>
promise异步图片加载
    <script>
        const img = `https://img.zcool.cn/community/01c2365ca2cfd7a80121416828984e.jpg@1280w_1l_2o_100sh.jpg`;

        const p = new Promise((resolve, reject) => {
            let oImg = document.createElement('img');
            oImg.src = img;

            // 图片的成功加载事件
            oImg.onload = function () {
                resolve(oImg);
            }

            // 图片加载失败事件
            oImg.onerror = function () {
                reject(oImg);
            }
        });


        p.then(img => {
            // resolve
            document.body.append(img);
        },
            error => {
                // 图片加载失败,使用指定图片
                error.src = '../img/fail.jpg';
                document.body.append(error);
            }
        )
封装
 function loadImg(url) {
            const p = new Promise((resolve, reject) => {
                const oImg = document.createElement('img');
                oImg.src = url;

                oImg.onload = () => {
                    resolve(oImg)
                }

                oImg.onerror = () => {
                    reject(oImg)
                }
            })
            return p
        }


        loadImg('https://img12.360buyimg.com/babel/s1180x940_jfs/t1/120286/5/18951/151642/60af7d79E1f7a0a06/5aeb32ea87bb8a63.jpg.webp')
            .then(
                img => {
                    document.body.appendChild(img)
                },
                errImg => {
                    errImg.src = '../images/1.png'
                    document.body.appendChild(errImg)
                }
            )


        loadImg('https://img12.360buyimg.com/babel/s1180x940_jfs/t1/120286/5/18951/151642/6af7d79E1f7a0a06/5aeb32ea87bb8a63.jpg.webp')
            .then(
                img => {
                    document.body.appendChild(img)
                },
                errImg => {
                    errImg.src = '../images/1.png'
                    document.body.appendChild(errImg)
                }
            )


    </script>
        let imgArr = [`https://img.zcool.cn/community/01c2365ca2cfd7a80121416828984e.jpg@1280w_1l_2o_100sh.jpg`,
            `https://img.zcool.cn/community/01b2db5c9a2849a801214168aa621b.jpg@1280w_1l_0o_100sh.jpg`,
            `https://img.zcool.cn/communiy/0116355c9a284fa801214168be79ce.jpg@1280w_1l_2o_100sh.jpg`

        ];

        imgArr.forEach(val => {
            let img = document.createElement('img');
            img.width = '200';
            img.height = '400';
            loadImg(val, '../img/fail.jpg', img);
            document.body.appendChild(img);


        })






        //封装图片异步加载
        function loadImg(url, failImgUrl, oImg,) {
            const p = new Promise((resolve, reject) => {

                oImg.src = url;

                oImg.onload = function () {
                    resolve(oImg);
                };

                oImg.onerror = function () {
                    reject(oImg);
                }


            });

            p
                .then(img => {
                    console.log('加载成功');

                },
                    error => {
                        oImg.src = failImgUrl;
                        // oImg.src = '../img/fail.jpg';
                    });

        }

promise方法封装登录

ajax
// option 对象
function ajax(options) {
    const {
        type,
        path,
        data = {},
        dataType = 'json',
        successCB,
        failCB
    } = options;

    let params = '';
    for (let key in data) {
        params += `${key}=${data[key]}&`;
    }
    // 去掉最后面的一个多余的&
    params = params.substring(0, params.length - 1);

    const xhr = new XMLHttpRequest();
    // 判断数据请求的方式
    if (type == 'get') {
        xhr.open(type, path + '?' + params, true);
        xhr.send()
    } else {
        xhr.open(type, path, true);
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded; charset=utf-8");
        xhr.send(params);
    }
    xhr.onreadystatechange = () => {
        try {
            if (xhr.readyState == 4 && xhr.status == 200) {
                let data = xhr.responseText;
                if (dataType == 'json') {
                    data = JSON.parse(data);
                }
                successCB && successCB(data);
            }
        }
        // 如果ajax报错 ,这个时候程序依然会向下执行,但是这个错误可以被捕捉到
        catch (err) {
            failCB && failCB(err)
        }
    }
}



// 查询地址栏的数据参数
function queryString(name) {
    var href = location.search.replace('?', '');
    var arr = href.split('&');
    arr = arr.map(val => {
        return {
            name: val.split('=')[0],
            value: val.split('=')[1]
        }
    })
    var res = arr.filter(val => val.name === name)[0];
    if (res) {
        return res.value
    } else {
        return ''
    }
}


function $(e) {
    return document.querySelector(e)
}


api1

api1.js

function login(data) {
    return new Promise((resolve, reject) => {
        ajax({
            type: 'post',
            path: '../php/login.php',
            data,
            success: val => {
                resolve(val);
            }
        })
    });
}

function reg(data) {
    return new Promise((resolve, reject) => {
        ajax({
            type: 'post',
            path: '../php/reg.php',
            data,
            success: val => {
                resolve(val);
            }
        })
    })
}

调用

    <script src="../js/a1.js"></script>
    <script>
        let data = {
            username: 'jennie',
            password: 12
        }

        login(data)
            .then(val => {

                console.log(val);

            });

        reg(data)
            .then(val => {
                console.log(val);

            });


    </script>
api2
function request(data, type, path) {
    return new Promise((resolve, reject) => {
        ajax({
            path,
            data,
            type,
            success: val => {
                resolve(val);
            }
        })
    })
}


function login(data) {
    return request(data, 'post', '../php/login.php');
}

function reg(data) {
    return request(data, 'post', '../php/reg.php');
}

function list(data) {
    return request(data, 'get', '../php/list.php');
}

使用

        let data = {
            keyword: '',
            orderType: 'html',
            orderSort: 'desc'
        }

        list(data)
            .then(
                val => {
                    console.log(val);

                }
            );
api3
function request(path, data, type) {
    return new Promise((resolve, reject) => {
        ajax({
            path,
            data,
            type,
            success: val => {
                resolve(val);
            }
        })
    });
}


// 变为表达式函数
// 因为箭头函数,只能是表达式形式

const login = data => request('../php/login.php', data, 'post');

const reg = data => request('../php/reg.php', data, 'post');

const list = data => request('../php/list.php', data, 'get');

day28

回顾

跨域
	后端  cors
	jsonp  
		后端返回的是一个带有参数的函数的执行
 		 前端接受这个函数  写参数,接受后端传来的数据
图片服务器
异步  -- 任务队列   --- 是按时间排列

恐怖回调  想让异步任务想同步一样执行  
	函数嵌套比较深
	耗时比较长  t1+t2+t3
	
promise  承诺 
	为了解决异步的一些问题
	对象,构造函数--创建对象的工具
	容器,存放的是一个结果(未来才会揭晓)
	三种状态
		创建的时候   pending
		揭晓结果之后   fulfilled(成功)  /  rejected(失败)
	new Promise(resolve , reject)  回调函数
	.then(function(){} , function(){})
	
	图片   onload   onerror
	 接口的api

链式操作

链式操作能实现的根本原因 就是方法会不断的返回同样类型的数据

var str = 'hello';
var res = str.replace('l', '*').replace('l', '*');


 var arr = [1, 2, 3];
  var res = arr.concat(4).concat(5, 6);
  

promise的链式操作

        // promise的链式操作

        // 以下代码执行报错
        // var p = new Promise();

        // p
        // .then()  return Promise
        // .then()
        // .then()

promise补充

promise链式操作

promise

  • then 同时接受成功和失败两个回调
  • catch 只能接受失败的回调
  • finally 不管成功还是失败都执行,不接受参数
  var p = new Promise((resolve, reject) => {
            setTimeout(() => {
                var num = parseInt(Math.random() * 100);
                if (num > 20) {
                    resolve(num)
                } else {
                    reject(num)
                }
            }, 400)
        })
        
     // p
        //     .then(
        //         num => {
        //             console.log('成功的生成了大于20的数:' + num)
        //         },
        //         num => {
        //             console.log('失败的生成了不大于20的数:' + num)
        //         },

        //     )


 		p
            .then(num => console.log('成功的生成了大于20的数:' + num))
            .catch(num => console.log('失败的生成了不大于20的数:' + num))
            .finally(() => console.log('不管你成功还是失败,我都要执行'))

promise地狱回调
        function aa() {
            return new Promise((resolve, reject) => {
                ajax({
                    type: 'get',
                    dataType: '',
                    path: '../php/1.php',
                    successCB: data => {
                        resolve(data)
                    }
                })
            })
        }

        function bb() {
            return new Promise((resolve, reject) => {
                ajax({
                    type: 'get',
                    dataType: '',
                    path: '../php/2.php',
                    successCB: data => {
                        resolve(data)
                    }
                })
            })
        }

        function cc() {
            return new Promise((resolve, reject) => {
                ajax({
                    type: 'get',
                    dataType: '',
                    path: '../php/3.php',
                    successCB: data => {
                        resolve(data)
                    }
                })
            })
        }
        
        
        var str = '';
        
        //  链式操作   不断的返回同类型的数据
        //  依然是等aa执行完毕,再执行的bb   t1+t2+t3
        aa()
            .then(data => {
                str += data;
                // bb(); return p 
                return bb()
            })
            .then(data => {
                str += data;
                return cc()
            })
            .then(data => {
                str += data;
                console.log(str)
            })
        
promise.All

Promise.all方法用于将多个Promise实例,包装成一个新的Promise实例。新Promise的状态由多个Promise实例的状态决定,所有的实例全为fulfilled时新Promise的状态才为fulfilled,只要其中有一个状态为rejected,新Promise的状态也会变成rejected。
当新Promise的状态为fulfilled时,可以拿到所有实例的成功结果集合,状态为rejected时拿到的是第一个状态为rejected实列失败的结果

  • promise的结果由多个实例的结果来决定

    • 成功 必须每个实例都是成功的
    • 失败 第一个失败的实例的结果
    • 请求时同时执行的

t1:100ms t2:200ms t3:300ms

链式实现p.then.then.then t1+t2+t3 600ms

p.all 最长300ms ,最短100ms(第一个就失败了)

var p1 = new Promise((resolve, reject) => {
            ajax({
                type: 'get',
                dataType: '',
                path: '../php/1.php',
                successCB: data => {
                    resolve(data)
                }
            })
        })


        function bb() {
            return new Promise((resolve, reject) => {
                ajax({
                    type: 'get',
                    dataType: '',
                    path: '../php/2.php',
                    successCB: data => {
                        resolve(data)
                    }
                })
            })
        }

        function cc() {
            return new Promise((resolve, reject) => {
                ajax({
                    type: 'get',
                    dataType: '',
                    path: '../php/3.php',
                    successCB: data => {
                        resolve(data)
                    }
                })
            })
        }
        
        
        
              var str = '';
        // 多个实例是同时请求的    1s   500ms   600ms
        // 结果集的顺序的是由数组的顺序决定
        var p = Promise.all([p1, bb(), cc()]);
        	p
            .then(data => console.log(data))
promise.all失败
  • 成功的结果建立在多个实例的结果都是成功的
  • 失败的结果 谁先失败就catch谁作为失败的结果
        // 产生一个大于20的数
        function aa() {
            var p = new Promise((resolve, reject) => {
                setTimeout(() => {
                    var num = parseInt(Math.random() * 100);
                    if (num > 20) {
                        resolve('1:' + num)
                    } else {
                        reject('1:' + num)
                    }
                }, 400)
            })
            return p
        }

        // 产生一个小于20的数
        function bb() {
            var p = new Promise((resolve, reject) => {
                setTimeout(() => {
                    var num = parseInt(Math.random() * 100);
                    if (num < 20) {
                        resolve('2:' + num)
                    } else {
                        reject('2:' + num)
                    }
                }, 300)
            })
            return p
        }
        
        
        Promise.all([aa(), bb()])
            .then(data => console.log(data))
            .catch(data => console.log(data))
promise.race

谁先拿到数据,结果就显示谁的,不管成功或者失败

        Promise.race([aa(), bb()])
            .then(data => console.log(data))
            .catch(data => console.log(data))

面向对象

面向对象基本特点

  • 对象是单个实物的抽象
  • 对象是一个容器,封装了’属性’和’方法’

函数的基本特点

  • 可传参
  • 可有返回值
  • 可调用

所谓构造函数,就是提供一个生成对象的模板,并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构。

构造函数基本特点

  1. 构造函数的函数名的第一个字母通常大写
  2. .函数体内使用this关键字,代表所要生成的对象实例
  3. 生成对象的时候,必须使用new命令来调用构造函数
        // 对象   拥有属性和方法
        var obj = {
            name: 'cc',
            age: 18,
            say: function () {
                console.log('hello world')
            
面向对象解决问题
        // 面向对象
        function Dog(type, age, color) {
            var obj = {
                type,
                color,
                age,
                say: function () {
                    console.log(`有一只${obj.age}岁的${obj.color}的${obj.type}`)
                }
            }
            // 函数返回了一个对象
            return obj
        }
        
        
         var dog1 = Dog('狗子', 3, '黑色');
        dog1.say();

        var dog2 = Dog('狗子', 2, '白色');
        dog2.say();
        
         console.log(dog1 instanceof Dog);   // false
         console.log(dog1.say == dog2.say)  // false
         
     // 出现了问题
        //   dog1和Dog之间没有血缘关系
        //   dog1和dog2 在内存当中各自存储自己的属性和方法  
对象
        var str = 'hello';
        console.log(str); //hello


        var str2 = new String('hello');
        console.log(str2); //String {"hello"}
this指向问题
  • 普通 window
  • 普通函数 window
  • 事件处理函数 绑定事件的对象
  • 在对象里面 对象本身
        console.log(this);


        function fun() {
            console.log(this);

        }

        fun();


        btn.onclick = function () {
            console.log(this); //<button id="btn">按钮</button>
        }


        var obj = {
            name: 'jennie',
            age: 18,
            say: function () {
                console.log(this); //{name: "jennie", age: 18, say: ƒ}

                console.log(this.name); //jennie

            }
        }

        obj.say();
new与this

new做了三件事

  1. 创建一个对象
  2. 把this指向改变成这个对象
  3. 返回了这个对象
  function Person(name) {

            this.name = name;
            console.log(this);


        }

        var p1 = new Person('jennie'); 
        console.log(p1); //Person {name: "jennie"}
        console.log(p1.name); //jennie

        var p2 = new Person('lisa');
        console.log(p2); //Person {name: "lisa"}
        console.log(p2.name); //lisa

构造函数

当一个普通的函数和new一起使用的时候, 这个函数就叫构造函数

  • 为了与普通函数做区分 ,一般构造函数首字母大写
  • 使用this
  function Dog(type, age, color) {
            // var obj = {}
            // this => obj 

            // obj.type = type 
            this.type = type;
            this.age = age;
            this.color = color;
            this.say = function () {
                console.log(`有一只${this.age}岁的${this.color}的${this.type}`)
            }
            console.log(this)
            // return this/obj 
        }
        
        
        var dog1 = new Dog('狗子', 2, '黑色');
        dog1.say()

        console.log(dog1 instanceof Dog)   // true   血缘关系

        var dog2 = new Dog('狗子', 2, '黑色');


        console.log(dog1.say == dog2.say)   // false   依然各自占内存
原型对象prototype

js提供了一个属性 prototype ,实现实例化对象之间的数据共享

未使用 prototype

        // function Dog(type, age, color) {
        //     this.type = type;
        //     this.age = age;
        //     this.color = color;
        //     this.say = function () {
        //         console.log(`有一只${this.age}岁的${this.color}的${this.type}`)
        //     }
        // }

使用Prototype

        function Dog(age, color) {
            this.age = age;
            this.color = color;
        }
        // 通过原型对象prototype来存储共有的属性和方法
        Dog.prototype.type = '狗子';
        Dog.prototype.say = function () {
            console.log(`有一只${this.age}岁的${this.color}的${this.type}`)
        }
        // 类型和say方法是公用的
        var dog1 = new Dog(2, '白色')
        var dog2 = new Dog(3, '黑色')

        console.log(dog1.say == dog2.say)

        console.log(dog1)
扩展数组方法
 // 数组求和的方法
        Array.prototype.sum = function () {
            var sum = 0;
            //this代表使用这个prototype方法的实例对象
            this.forEach(val => {
                sum += val
            })
            return sum
        }


        var arr = [1, 2, 3];
        console.log(arr.sum())
扩展date

this指代使用此方法的 实例对象

        Date.prototype.format = function () {
            var year = this.getFullYear();
            var month = this.getMonth() + 1;
            var day = this.getDate();
            var hour = this.getHours();
            var min = this.getMinutes();
            var sec = this.getSeconds();
            return `${year}-${month}-${day} ${hour}:${min}:${sec}`
        }

        var date = new Date();
        console.log(date.format());

面向对象方式 封装选项卡

day29

NodeList循环

  <p class="aa">1</p>
    <p class="aa">2</p>

    <script>
		//通过这种方式得到的数组不能循环
        var aa1 = document.getElementsByClassName('aa');

        console.log(aa1); //HTMLCollection(2) [p.aa, p.aa]

        // 是一个伪数组,不能forEach
        // aa1.forEach(val => {
        //     console.log(val);
        // });

        for (var i = 0; i < aa1.length; i++) {
            console.log(aa1[i]);
        }



        var aa2 = document.querySelectorAll('.aa');
        console.log(aa2); //NodeList(2) [p.aa, p.aa]

        aa2.forEach(val => {
            console.log(val);
        });

jquery封装

获取元素封装
    <p>1</p>
    <p>2</p>
    <script>
        function GetEle(ele) {
            this.eles = document.querySelectorAll(ele);
        }

		// 为了省略new这个过程
        function $(ele) {
            // 返回的是一个对象
            // 这个对象的eles属性利用querySelectorAll保存着查询的元素数组
            return new GetEle(ele);
        }

        // 使用
        console.log($('p')); //GetEle 是一个对象
        console.log($('p').eles); //NodeList(2) [p, p]

    </script>
显示与隐藏
    <p>1</p>
    <p>2</p>
    <script>
        function GetEle(ele) {
            this.eles = document.querySelectorAll(ele);
        }

        function $(ele) {
            return new GetEle(ele);
        }


        // 添加hidden方法
        GetEle.prototype.hide = function () {
            // 循环遍历所有选择的元素(可能是一个,可能是多个)
            this.eles.forEach(val => {
                val.style.display = 'none';
            })
        }


        $('p').hide();


        //添加show方法

        GetEle.prototype.show = function () {
            this.eles.forEach(val => {
                val.style.display = 'block';
            })
        }

        $('p').show();
获取/设置元素内容
  • text()设置或返回所选元素的文本内容
  • html()设置或返回所选元素的 内容(包含HTML标记)
  • val() 设置或返回表单字段的值

html()

    <p><b>black</b></p>
    <p><b>pink</b></p>
    <script>

        function GetEle(ele) {
            this.eles = document.querySelectorAll(ele);
        }


        function $(ele) {
            return new GetEle(ele);
        }


        // 获取或设置html内容
        // 当 获取时,选中多个元素时,获取第一个元素的内容
        // 设置元素内容时,设置所有元素内容

        GetEle.prototype.html = function () {
         	// 有参数,表示给元素设置html内容
            if (arguments.length >= 1) {
                // 遍历所有的元素,全部赋值
                this.eles.forEach(val => {
                    val.innerHTML = arguments[0];
                })


            } else {
                // 如果没有参数就返回第一个元素的innerHTML
                return this.eles[0].innerHTML;
            }
        }


        // 获取Html内容
        console.log($('p').html()); //<b>black</b>

        // 设置html内容
        $('p').html('<i>jennie</i>');

text()

        GetEle.prototype.text = function () {
            if (arguments.length >= 1) {
                // 设置text
                this.eles.forEach(val => {
                    val.innerText = arguments[0];
                })
            } else {
                return this.eles[0].innerText;
            }
        }
	
		//使用
        console.log($('p').text()); //black
        $('p').text('lisa');

val()

        GetEle.prototype.val = function () {
            // 有参数,设置value
            if (arguments.length >= 1) {
                this.eles.forEach(val => {
                    val.value = arguments[0];
                })
            } else {
                // 返回值
                return this.eles[0].value;
            }

        }


        console.log($('input').val()); //jennie
        //设置
        $('input').val('jisoo')
元素属性
attr

​ // attr 自定义属性和自有属性 无法获取或者设置表单的自有属性

​ // attr(“src”); 获取元素属性

​ // attr(“src”,“test.jpg”); //设置一个元素属性

​ // attr({ src: “test.jpg”, alt: “Test Image” }); //同时设置多个属性

   // attr  自定义属性和自有属性    无法获取或者设置表单的自有属性

        // attr("src"); 获取元素属性
        // attr("src","test.jpg"); //设置一个元素属性
        // attr({ src: "test.jpg", alt: "Test Image" }); //同时设置多个属性

        GetEle.prototype.attr = function () {
            if (arguments.length >= 2) {
                // 参数有两个,设置一个属性
                this.eles.forEach(val => {
                    val.setAttribute(arguments[0], arguments[1]);
                })
            } else if (arguments.length >= 1) {
                if (typeof arguments[0] == 'object') {
                    // 设置多个属性

                    // 参数为对象形式

                    // 遍历对象
                    for (let key in arguments[0]) {
                        // 给每个元素设置属性
                        this.eles.forEach(val => {
                            val.setAttribute(key, arguments[0][key]);
                        })
                    }
                } else {
                    // 返回属性值

                    return this.eles[0].getAttribute(arguments[0]);
                }
            }
        }
    <!-- datas 自定义属性 -->
    <h1 class="test" datas='haha'>BLACK</h1>
    <h1>PINK</h1>
    <input type="radio" name="yg" checked>
    <input type="radio" name="yg">
    
    
    
    
    
       console.log($('h1').attr()); //undefined

        // console.log($('h1').attr(''));

        console.log($('h1').attr('datas')); //haha

        $('h1').attr('myattr', 'rosie'); //设置属性

        console.log($('input').attr('checked')); //空
prop

一般用于自有属性的获取,如checked,selected或class等

自有属性的获取

    <input type="radio" id="one">
    <input type="radio" checked id="two">


    <h1>black</h1>

    <h2 class="a b">pink</h2>



        
        // 获取特殊自有属性时

        var radio = document.querySelector('#one');

        // 初始未设置checked
        console.log(radio.getAttribute('checked')); //null

        // 获取checked属性的方法 
        console.log(radio.checked); //false



        var two = document.querySelector('#two');
        console.log(two.getAttribute('checked')); //空
        console.log(two.checked); //true



        var h1 = document.querySelector('h1');
        console.log(h1.className); //空


        var h2 = document.querySelector('h2');
        console.log(h2.className); //a b
        // prop 针对自有 属性而言的
        GetEle.prototype.prop = function () {
            if (arguments.length >= 2) {
                // 设置属性
                this.eles.forEach(val => {
                    if (arguments[0] == 'class') {
                        // 设置class
                        val.classList.add(arguments[1]);
                    } else {
                        // val.id = 'a'
                        // val.checked = true
                        val[arguments[0]] = arguments[1];
                    }
                })
            } else {
                // 返回自有 属性值
                if (arguments[0] == 'class') {
                    return this.eles[0].className;
                }
                return this.eles[0][arguments[0]];
            }
        }
        console.log($('input').prop('checked')); //false
        $('input').prop('checked', true);

        console.log($('h1').prop('class'));

        $('h1').prop('class', 'orange')
css
  • ​ 返回第一个元素的指定样式 .css(‘color’)
  • 设置单个样式 .css(‘color’ , ‘red’)
  • 设置多个样式 .css({‘color’:‘red’ , ‘fontSize’:‘20px’})
GetEle.prototype.css = function () {
            if (arguments.length >= 2) {
                // 设置单个样式
                this.eles.forEach(val => {
                    val.style[arguments[0]] = arguments[1];
                })
            } else if (arguments.length >= 1) {
                //只有一个参数,判断 返回样式还是设置多个样式 


                if (typeof arguments[0] == 'string') {
                    // 返回样式
                    if (window.getComputedStyle) {
                        return getComputedStyle(this.eles[0])[arguments[0]];
                    }
                    return this.eles[0].currentStyle[arguments[0]];
                } else {
                    // 是一个对象,设置多个样式

                    this.eles.forEach(val => {
                        // 遍历这个对象
                        for (let key in arguments[0]) {
                            val.style[key] = arguments[0][key];
                        }
                    })
                }
            }
        }

 		console.log($('h1').css('fontSize')); //32px

        $('h1').css('textDecoration', 'underline'); //设置单个样式

        $('h1').css({ color: 'pink', background: 'orange' }) //设置多个样式

类名操作
addClass
  • addClass() - 向被选元素添加一个或多个类
  //添加一个类
  $("div").addClass("important");

 //添加多个类
  $("#div1").addClass("important blue");

        // addClass('inport')
        //addClass(import blue)
        GetEle.prototype.addClass = function () {
            // 对参数以进行切割,返回一个类名数组
            if (arguments.length >= 1) {
                let parms = arguments[0].split(' ');

                // 添加类名
                this.eles.forEach(val => {
                    parms.forEach(value => {
                        val.classList.add(value);
                    })

                })
            }
        }
        
        //测试
      	$('h1').addClass('import blue');
        $('h1').addClass('blue');
removeClass
        // removeClass('import') -移除单个样式
        // removeClass('import blue') -移除多个样式
        GetEle.prototype.removeClass = function () {
            if (arguments.length >= 1) {
                // 参数进行切割
                let params = arguments[0].split(' ');


                this.eles.forEach(val => {
                    params.forEach(value => {
                        val.classList.remove(value);
                    })
                })

            }
        }
        // $('h1').removeClass('test');
        // $('h1').removeClass('test pink');
toggleClass

该方法对被选元素进行添加/删除类的切换操作:

  • 有指定的类,则移除
  • 没有指定的类,则添加
 // toggleClass 切换  如果原来有on就删除on   如果没有on就添加on
        GetEle.prototype.toggleClass = function (a) {
            this.eles.forEach(val => {
                // 把classList这个伪数组变成数组
                var list = [];
                val.classList.forEach(v => {
                    list.push(v)
                })
                if (list.includes(a)) {
                    val.classList.remove(a)
                } else {
                    val.classList.add(a)
                }

            })
        }
eq
        // eq 找到指定角标的元素
        // $("p").eq(1)
        // $("p").eq(-2)
        GetEle.prototype.eq = function () {
            if (arguments.length >= 1) {

                // this.eles.forEach((val, i) => {
                //     if (arguments[0] == i - 1) {

                //         // forEach没有返回值
                //         return val;
                //     }
                // })

                if (arguments[0] > 0) {

                    return this.eles[arguments[0] - 1];
                } else {
                    // 传过来负数
                    let index = Math.abs(arguments[0]);

                    let arr = [];
                    this.eles.forEach(val => {
                        arr.push(val);
                    })
                    // 数组反转
                    arr = arr.reverse();

                    return arr[index - 1];
                }
            }
        }
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
    </ul>
    
    
    
        console.log($('ul li').eq(3));

        console.log($('ul li').eq(-1));

链式操作

不断的返回同类型的数据

 GetEle.prototype.eq = function () {
            if (arguments.length >= 1) {

                if (arguments[0] > 0) {

                    this.eles = [this.eles[arguments[0] - 1]];
                 
                } else {
           
                    let index = Math.abs(arguments[0]);

                    let arr = [];
                    this.eles.forEach(val => {
                        arr.push(val);
                    })
                    // 数组反转
                    arr = arr.reverse();

                    this.eles = [arr[index - 1]];
                  
                }
                
                  // 链式操作
                    return this;
            }
        }
  GetEle.prototype.css = function () {

            if (arguments.length >= 2) {
                // 单个样式值
                this.eles.forEach(val => {
                    val.style[arguments[0]] = arguments[1];
                });

            } else if (arguments.length >= 1) {
                if (typeof arguments[0] == 'string') {
                    // 获取样式
                    if (getComputedStyle) {
                        return getComputedStyle(this.eles[0])[arguments[0]];
                    }
                    return this.eles[0].currentStyle[arguments[0]];
                } else {
                    // 设置多个样式
                    this.eles.forEach(val => {
                        for (var key in arguments[0]) {
                            val.style[key] = arguments[0][key];
                        }
                    });

           
                }
            }
            
             // 链式操作
             return this;

        }

使用

 $('ul li').eq(3).css('color', 'pink').css('background', 'springgreen');
        // addClass('pink')
        // addClass('blue pink')
        GetEle.prototype.addClass = function () {

            // 切割参数
            if (arguments.length >= 1) {

                let parmas = arguments[0].split(' ');

                this.eles.forEach(val => {
                    parmas.forEach(value => {
                        val.classList.add(value);
                    })
                });

                // 链式操作
                return this;
            }

        }
  $('li').addClass('blue').addClass('black pink ');

jquery.js

总体封装

// 构造函数
function GetEle(ele) {
    this.eles = document.querySelectorAll(ele);
}

// 为了省略new这个过程
function $(eles) {
    var p = new GetEle(eles)
    return p
}

GetEle.prototype.hide = function () {
    this.eles.forEach(val => {
        val.style.display = 'none'
    })
}

GetEle.prototype.html = function () {
    // 参数的长度大于等于1时,表示有参数
    if (arguments.length >= 1) {
        this.eles.forEach(val => {
            val.innerHTML = arguments[0]
        })
    }
    // 如果没有参数就返回第一个元素的值
    else {
        return this.eles[0].innerHTML
    }
}


GetEle.prototype.text = function () {
    // 参数的长度大于等于1时,表示有参数
    if (arguments.length >= 1) {
        this.eles.forEach(val => {
            val.innerText = arguments[0]
        })
    }
    // 如果没有参数就返回第一个元素的值
    else {
        return this.eles[0].innerText
    }
}


// eq  找到指定角标的元素   equal
// .eq(2)
GetEle.prototype.eq = function (index) {
    for (var i = 0; i < this.eles.length; i++) {
        if (i == index) {
            // return this.eles[i - 1]
            // this.eles = this.eles[i - 1]   // 数据类型就会改变
            this.eles = [this.eles[i - 1]]
        }
    }
    return this
}


// 返回第一个元素的指定样式   .css('color') 
// 设置单个样式  .css('color' , 'red')
// 设置多个样式  .css({'color':'red' , 'fontSize':'20px'})
GetEle.prototype.css = function (a, b) {
    // 设置单个样式 
    if (arguments.length >= 2) {
        this.eles.forEach(val => {
            // val.style.width = '200px'
            val.style[a] = b;
        })
    } else {
        if (typeof a == 'string') {
            // 只能返回行内样式
            // return this.eles[0].style[a]
            if (window.getComputedStyle) {
                return getComputedStyle(this.eles[0])[a]
            }
            return this.eles[0].currentStyle[a]
        } else {
            // 对象
            this.eles.forEach(val => {
                // 设置多个样式  .css({'color':'red' , 'fontSize':'20px'})
                for (let key in a) {
                    val.style[key] = a[key]
                }
            })
        }
    }
    return this
}


// toggleClass 切换  如果原来有on就删除on   如果没有on就添加on
GetEle.prototype.toggleClass = function (a) {
    this.eles.forEach(val => {
        // 把classList这个伪数组变成数组
        var list = [];
        val.classList.forEach(v => {
            list.push(v)
        })
        if (list.includes(a)) {
            val.classList.remove(a)
        } else {
            val.classList.add(a)
        }

    })
    return this
}

day30

封装链式操作

        function GetEle(ele) {
            this.eles = document.querySelectorAll(ele);
        }


        function $(ele) {
            return new GetEle(ele);
        }
        
        
          GetEle.prototype.toggleClass = function () {
            this.eles.forEach(val => {
                // 变为真的数组
                let list = [];
                val.classList.forEach(value => {
                    list.push(value);
                });


                if (list.includes(arguments[0])) {
                    // 存在移除
                    val.classList.remove(arguments[0]);
                } else {
                    // 添加
                    val.classList.add(arguments[0]);
                }

            })

            return this;
        }


        GetEle.prototype.eq = function () {
            // this.eles = [this.eles[arguments[0]]];

            this.eles.forEach((val, i) => {
                if (arguments[0] == i) {
                    this.eles = [this.eles[arguments[0]]];
                }
            })

            return this;
        }

sibling封装

 // 找到所有的兄弟元素
        GetEle.prototype.siblings = function () {
            var parent = this.eles[0].parentNode;
            var children = parent.children;

            var list = [];
            // 是一个htmlCollection  不能使用forEach
            for (var i = 0; i < children.length; i++) {
                if (children[i] != this.eles[0]) {
                    list.push(children[i]);
                }
            }

            this.eles = list;
            return this;
        }
$('#two').siblings().css('color', 'pink');

事件绑定

        GetEle.prototype.on = function () {
            // 一般事件绑定
            // $('p').on('click',function(){})
            if (arguments.length == 2) {
                this.eles.forEach(val => {
                    val.addEventListener(arguments[0], arguments[1]);
                })
            }


            // $('body').on('click','#black',function(){})
            // id为p的事件委托
            if (arguments.length > 2) {
                // 事件委托
                // 第二个参数,选择器 #black
                let select = arguments[1];
                // 回调函数
                let callback = arguments[2];


                this.eles.forEach(val => {
                    val.addEventListener(arguments[0], function (e) {
                        e = e || event;
                        var target = e.target || e.srcElement;


                        if (target.id == select.replace('#', '')) {
                            callback();
                        }

                    })
                })

            }

        }
      
      //一般事件绑定
      $('p').on('click', function () {
            console.log(888);

        })
        
        //事件委托

        $('body').on('click', "#black", function () {
            console.log('事件委托');

        })


this指向

  1. 一般情况下,this—>window
  2. 普通函数 this—>window
  3. 对象里面 this-> 对象本身
  4. 在事件处理函数中 this-> 绑定事件的元素
  5. 箭头函数 没有自己的指向 爹指向谁,我就指向谁
 console.log(this); //window
        function fn() {
            console.log(this); //window
        }

        fn();
        var obj = {
            name: 'IU',
            age: 23,
            say: function () {
                console.log(this);  //{name: "IU", age: 23, say: ƒ},指向对象本身
            }
        }

        obj.say();
        document.onclick = function () {
            console.log(this); //#document

        }

箭头函数

        var fn = () => {
            console.log(this); //window
        }

        fn();
        var obj = {
            name: 'JENNIE',
            fn: () => {
                console.log(this); //window

            }
        }

        obj.fn();

箭头函数this

箭头函数自己没有指向,指向父元素的指向。父元素的this

        var fn = () => {
            console.log(this); //window
        }

        fn();  // window.fn     fn的this实际指向window   因此 箭头函数  window
        var obj = {
            name: 'jennie',
            fn1: function () {
                console.log(this); //  this -> obj 

            },
            fn2: () => {
                console.log(this); //  window.obj   this -> window 
            }
        }

        obj.fn1(); //obj
        obj.fn2(); //window
        var obj = {
            name: 'IU',
            fn: function () {
                console.log(this); //obj

                return () => {
                    console.log(this);  // fn()obj

                    return () => {
                        console.log(this);  //fn()()obj

                    }
                }

            }
        }

        obj.fn();
        obj.fn()();
        obj.fn()()();

事件绑定的箭头函数

        document.onclick = function () {
            console.log(this); //#document

        }
     document.onclick = () => {
            console.log(this); //window

        }

        var obj = {
            name: 'cc',
            init: function () {
                console.log(this); //obj
                
                document.onclick = () => {
                    console.log(this); //obj

                }
            }
        }

        obj.init();

箭头函数使用实例

可以利用箭头函数,保留this,(因为箭头函数自己指向,依赖于父元素的指向)

        Banner.prototype.autoPlay = function () {
            clearInterval(this.timer);
            let that = this;
            //定时器的this指向会变,利用箭头函数,保留this指向
            //因为箭头函数自己没有指向 
            this.timer = setInterval(function () {
            	console.log(this); //window
                that.index++;
                if (that.index >= that.lis.length) {
                    that.index = 0;
                }

                that.activeOne();

            }, 2000);
        }
        
        
        
        //改变后
        
        Banner.prototype.autoPlay = function () {
            clearInterval(this.timer);

            //定时器的this指向会变,利用箭头函数,保留this指向
            this.timer = setInterval(() => {
                this.index++;
                if (this.index >= this.lis.length) {
                    this.index = 0;
                }

                this.activeOne();

            }, 2000);
        }

        
        
this指向小结
  1. 普通函数 this – window

  2. 事件处理函数 this – 绑定事件的标签

  3. 对象里面 this – 对象本身

  4. 箭头函数 自身没有this指向 父元素指向谁,箭头函数就指向谁

总结:注意箭头函数的使用场景

普通函数和箭头函数的区别

写法不一样

this指向也不一样

使用场景: 如果this有了一个固定的指向之后,不想让这个指向发生改变,就在这个函数内部统一使用箭头函数

this如果发生改变

  • 通过变量保存住这个this
  • 通过箭头函数,保留住this指向

原型链

  • 所有的对象都拥有 proto 属性 原型

  • prototype 属性对象 只有函数拥有

  • 原型 proto

  • 函数 prototype 和__proto_ _ _

原型链的应用
        var arr = [1, 2, 3];
        var arr2 = [3, 4, 5];

        // 相当于Array.prototype
        arr.__proto__.sum = function () {
            var res = 0;
            this.forEach(val => {
                res += val;
            })

            return res;
        }
        // Array.prototype.sum = function () {
        //     var res = 0;
        //     this.forEach(val => {
        //         res += val
        //     })
        //     return res
        // }

        console.log(arr.sum());
        console.log(arr2.sum());

伪数组

HTMLCollection和NodeList的prototype不同

  • NodeList可以forEach而HTMLCollection不能,是因为NodeList的Prototype有forEach方法
    <p>1</p>
    <p>2</p>
    <p>3</p>

    <script>
        var aa = document.getElementsByTagName('p');
        console.log(aa)
        // aa.__proto__  HTMLCollection  没有forEach , 但是有length

        var bb = document.querySelectorAll('p');
        console.log(bb)
        // bb.__proto__  原型上拥有forEach   NodeList.prototype.forEach=function()
 
<body>
    <p>1</p>
    <p>2</p>
    <p>3</p>
    <script>
        var aa = document.getElementsByTagName('p');
        console.log(aa); //HTMLCollection

        var bb = document.querySelectorAll('p');
        console.log(bb); //NodeList

        // bb.forEach(val => {
        //     console.log(val);
        // })

        // 在变为真正的数组之前保留length,因为其原型变为Array后没有了length数学
        var len = aa.length;



        // 将伪数组变为真正的数组(改变其指向)
        aa.__proto__ = Array.prototype;
        console.log(aa);

        aa.length = len;

        aa.forEach(val => {
            console.log(val);

        })

        // aa.pop(); //报错  Index property deleter is not supported.不支持


call和apply和bind

  • call,apply,bind 在函数的执行过程中改变this指向

  • call(newObj,arguments,arguments)

  • apply(newObj,[arguments,arguments])

  • bind(newObj,arguments,arguments)() 返回的是一个函数,必须执行一下

箭头函数本身没有指向—它的指向是不会被手动改变的

        // 在函数执行过程中改变this指向
        // call
        // apply
        // bind


        var name = 'window';
        var obj = {
            name: 'dog',
            age: 18,
            say: function (num1, num2) {
                console.log(this.name);
                console.log(num1);
            },
            speak: () => {
                console.log(this);
            }
        }

        obj.say(5); //dog 5

        obj.say.call(window, 6, 6); //window 6


        var obj2 = {
            name: 'obj2'
        }

        // call(newObj,argument,argument)
        obj.say.call(obj2, 7, 8); //obj2 7


        // apply
        obj.say.apply(obj2, [4, 5]); //obj2,4


        // bind 返回的是一个函数,需要再次执行
        console.log(obj.say.bind(obj2, 3, 4));
        // ƒ (num1, num2) {
        //         console.log(this.name);
        //         console.log(num1);
        //     }



        obj.say.bind(obj2, 3, 4)(); //obj2 3

day31

知识点回顾

1 cookie   设置cookie   获取cookie  删除cookie
2 webStorage
3 区分  cookie / localstorage / sessionStorage
4 同源策略
5 跨域  域名 / 端口号 / 协议
	CORS
	jsonp
	
6 获取地址栏的参数    列表跳转到详情页    querySelector
7  promise
	为了解决异步 问题
	本质上是一个构造函数   函数本身也是一个对象
	方法
	 实例化对象的方法   .then()   .catch()   .finally()
	 Promise.all([p1,p2,p3])   Promise.race([p1,p2])   
	 
8 面向对象  封装 , 继承,多态
	面向过程   面向对象 -- 原型链  追根溯源
	构造函数的封装
		首字母大写
		this
		prototype 原型对象  
		选项卡   轮播图   数组求和   日期对象    jq 
		 this指向 4种指向(普通函数/事件处理函数/对象/箭头函数)  call / apply / bind
		 原型链   __proto__  原型     prototype 原型对象
		 每一个对象都有 __proto__  原型 
		 每一个构造函数都有prototype属性对象
		 实例化对象原型链
		 	dog1.__proto__  === Dog.prototype
		 	 Dog.prototype.__proto__ === Object.prototype
		 	 Object.prototype.__proto__  === null
		 构造函数原型链
		 	 Dog.__proto__  === Function.prototype
		 	 Function.prototype.__proto === Object.prototype
		 	 Object.prototype.__proto__  === null

继承

继承:子类当中拥有父类的属性的方法

        // 父类
        function Dog() {
            this.type = '狗子';
            this.say = '汪';
        }


        // 子类
        function KeJi(name, color) {
            this.type = '狗子';
            this.say = '汪';
            // this.name = name;
            // this.color = color;
        }
构造函数继承

构造函数继承: 主要的实现方法就是改变父类的this指向

缺点:无法继承父类的原型对象(prototype)上的 属性和方法

    <script>
        function Dog() {
            this.type = '狗子';
            this.say = '汪';
        }


        Dog.prototype.speak = function () {
            console.log(this.say);

        }

        // 子类
        function Keji(name, color) {

            // 执行Dog这个函数,并改变this指向

            /* this.type = '狗子';
               this.say = '汪'; */

            Dog.call(this);
            this.name = name;
            this.color = color;

        }

        var kj = new Keji('kuma', '黑色');
        console.log(kj);
    </script>

在这里插入图片描述

原型链继承

原型链式继承: 让子类的prototype指向父类的实例化对象 (子类的原型对的constructor -> 子类)

// 缺点:子类无法向父类传参

    <script>
        function Dog(age) {
            this.type = '狗子';
            this.say = '汪';
            this.age = age;
        }


        Dog.prototype.speak = function () {
            console.log(this.say);

        }

        // 子类
        function Keji(name, color) {

            this.name = name;
            this.color = color;
            // 实例化对象会优先找自己的构造函数的属性或方法,如果自己没有,就找prototype上的属性和方法
            this.say = 'wang';

        }

        // 无法传参,参数固定了
        Keji.prototype = new Dog(5);

        // 改变构造器, 加和不加这一句,不影响继承, 只不过原型链会出现错乱
        Keji.prototype.constructor = Keji;


        var kj = new Keji('kuma', '黑色');
        console.log(kj);
    </script>

在这里插入图片描述

jquery-选项卡

    <div class="tab">
        <ul>
            <li class="on">1</li>
            <li>2</li>
            <li>3</li>
        </ul>

        <ol>
            <li>111</li>
            <li>222</li>
            <li>333</li>
        </ol>
    </div>

    <script src="../js/jquery.js"></script>
    <script>


        $('ol li').eq($('.on').index()).show();

        $('ul li').each(function (index, ele) {
            console.log(index, ele);

            $('ul li').eq(index).on('click', function () {

                $(this).addClass('on').siblings().removeClass('on')
                    .parent().parent().children('ol').children('li').eq($(this).index()).show().siblings().hide();

            })

        })

    </script>
组合继承

组合继承:构造函数继承+原型式继承 — 解决了传参的问题

缺点:原型链上出现了多余的属性和方法

    <script>
        function Dog(age) {
            this.type = '狗子';
            this.say = '汪';
            this.age = age;
        }


        Dog.prototype.speak = function () {
            console.log(this.say);

        }

        // 子类
        function Keji(age, name, color) {
            Dog.call(this, age)
            this.name = name;
            this.color = color;
            this.say = 'wang';

        }

        Keji.prototype = new Dog();
        // 改变构造器
        Keji.prototype.constructor = Keji;


        var kj = new Keji(3, 'kuma', '黑色');
        console.log(kj);
    </script>

在这里插入图片描述

组合继承优化

组合继承:构造函数继承+原型对象的继承 不推荐使用

缺点:子类的原型对象的改变会影响父类 – 共享了地址prototype

    <script>
        function Dog(age) {
            this.type = '狗子';
            this.age = age;
        }
        Dog.prototype.speak = function () {
            console.log(66)
        }


        function KeJi(name, color, age) {
            // 继承构造函数的属性和方法
            Dog.call(this, age);
            this.name = name;
            this.color = color;
        }
        // 继承原型对象的属性和方法   
        // 子类和父类指向了同一个原型对象,也就是共享了同一个地址  -- 浅拷贝
        KeJi.prototype = Dog.prototype;
        KeJi.prototype.constructor = KeJi;

        // 子类的原型对象的改变会影响父类
        KeJi.prototype.ss = 8;

        var kj = new KeJi('柯基', '白色', 2);
        console.log(kj)

        console.dir(Dog);



        console.log(Dog.prototype)
    </script>

在这里插入图片描述

拷贝继承

// 拷贝继承:构造函数 + 原型对象的深拷贝

<script>
        function Dog(age) {
            this.type = '狗子';
            this.say = '汪';
            this.age = age;
        }


        Dog.prototype.speak = function () {
            console.log(this.say);

        }

        // 子类
        function Keji(age, name, color) {
            Dog.call(this, age)
            this.name = name;
            this.color = color;
            this.say = 'wang';

        }
		
		//拷贝prototype方法
        for (var key in Dog.prototype) {
            Keji.prototype[key] = Dog.prototype[key];
        }


        var kj = new Keji(3, 'kuma', '黑色');
        console.log(kj);
    </script>

在这里插入图片描述

day32

回顾

js 继承
1 单一:构造函数的继承 -- 没有继承父类的prototype  call / apply / bind 
2 单一:原型链式继承 -- 无法向父类传参   Child.prototype = new Parent()

3 组合继承
	3.1 构造函数 + 原型链式   原型链上多出Parent的构造函数里面的属性和方法
	3.2 构造函数 + prototype
		 3.2.1   Child.prototype = Parent.prototype   地址相同  
		 3.2.2   拷贝继承 Child.prototype = {...Parent.prototype}  深拷贝
		 3.2.3   寄生式继承  F(){}   F.prototype = Parent.prototype   Child.prototype = new F()
		 	注意点:当child的prototype的指向改变了,就一定要加  Child.prototype.constructor = Child
		 
	4 Es6继承 -- 语法糖  extends   super


juery
	  parents()   parent()
	  find()      children()
	  siblings()  next()   prev()   nextAll()  prevAll()    
	  index()  在同级元素中所排的角标
	  filter  first  last  not eq()  
	  html  /   val   /   text
	  each  遍历  
	  on

attr-选项卡

  • attr 自定义属性 常见的自由属性
  • prop 特殊的自有属性 checked

html

    <div class="box" id="box1">
        <input type="checkbox" class="checkAll"><br>
        <input type="checkbox" class="checkOne">
        <input type="checkbox" class="checkOne">
        <input type="checkbox" class="checkOne">
        <input type="checkbox" class="checkOne">

    </div>

js

 <script src="../js/jquery.js"></script>
    <script>

        class Check {
            constructor(e) {
                this.ele = $(e);
                this.checkAll = this.ele.children('.checkAll');
                this.checkOnes = this.ele.find('.checkOne');

                this.init();
            }

            init() {
                var that = this;

                this.checkAll.click(function () {
                    // 全选
                    that.checkOnes.prop('
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值