JS学习笔记

1.输入输出、数据类型

(1)输入框:var name = prompt('请输入你的名字:');
(2)判断是不是数字,是数字返回false,否则返回true:
var address = '或英寸';
console.log(isNaN(address)); //返回true
(3)NAN
//undefined
var varible = undefined;
console.log(varible + 1); //undefined和数字相加输出NaN=not a number
(4)typeof
//typeof可以检测数据是什么数据类型
console.log(typeof address); //string

2.数据类型转换

(1)转换成string类型的三种方法
  • toString
//方法一:toString()
var num1 = 1;
console.log(num1.toString());
  • String强制转换
var num2 = 2;
console.log(String(num2));
  • 与字符串进行加号的拼接
var num3 = 3;
console.log("我是字符串" + num3);
(2)转换成数字类型的四种方法
  • parseInt(string)
//方法一:parseInt(string),重点
//如果有px会直接去掉
console.log(parseInt('78px')); //输出:78
  • parseFloat(string)
//方法二:parseFloat(string),重点
console.log(parseFloat('78.25'));
  • Number()强制转换
//方法三:Number()强制转换
console.log(Number('12'));
  • 隐式转换,利用算术运算符转换
console.log('12' - 0);
//注意:console里面有默认数据转换类型 会把字符串型数据转换为数字型

3.==与===   逻辑判断

  • ==:用于判断,表示只要数值相等即可
  • 全等===:程序里面完全一致。表示需要数值一样 数据类型还要完全相同
console.log(18 == '18'); //返回true
console.log(18 === '18'); //返回false
  • 短路运算:当有多个表达式(值)时,左边的表达式值可以确定结果的时候,就不要再继续运算右边表达式的结果了
  • 逻辑与短路运算:表达式1 && 表达式2   如果表达式1为真则返回表达式2 如果表达式1为假,返回表达式1
console.log(456 && 123); //返回123
console.log(0 && 123); //返回0
  • 逻辑或短路运算:表达式1 || 表达式2   如果表达式1为真则返回表达式1 如果表达式1为假,返回表达式2
console.log(456 || 123); //返回456
console.log(0 || 123); //返回123

4.数组

(1)创建数组:
  • 利用new来创建新数组
var array1 = new Array();
  • 利用数组字面量来创建数组,可以放任意类型,是最常适用类型
var array2 = [1, 2, '老师', true];
(2)新增元素
array2[4] = 789;
array2[5] = 'Amy';

5.函数

function getSum(num1, num2) {
    var sum = 0;
    for (var i = num1; i <= num2; i++) {
        sum = sum + i;
    }
    console.log(sum);
}
  • getSum(1,2,3):如果实参个数多于形参个数 会取到形参个数,即取1,2
  • getSum(1,2):如果实参和形参个数一样 则正常输出结果
  • getSum(1):若小于,则num2为undefined
function fn() {
    console.log("数组长度是:" + arguments.length);
    for (var i = 0; i < arguments.length; i++)
        console.log(arguments[i]);
}
arguments:存储了所有传递过来的实参.每个函数才有,只有函数才有。是一个伪数组,并不是真正意义上的数组具有length属性按照索引的方式进行存储的。
fn(1,2,3,4)、fn(1,2,3,4,5):
声明函数:var 变量名 = function() {}
var fun = function(aru) {
    console.log("im here");
    console.log(aru);
}
fun();

6.预解析和对象

6.1预解析

js会把所有的变量var 还有function函数 提升到当前作用域的最前边,即变量预解析(变量提升)+函数预解析(函数提升 )

6.2创建对象的三种方式

  • 字面量{}创建,创建一个空对象:
var obj = {
    //采取键值对形式
    //多个属性和方法中间用逗号隔开
    //方法冒号后边跟的是一个匿名函数
    name: "张三丰",
    age: 135,
    sex: '男',
    sayhi: function() {
        console.log("hi~");
    }
};

//1.调用对象的属性 采取【对象名.属性名】
console.log(obj.age);
//2.调用属性第二种方法 【对象名['属性名']】
console.log(obj['age']);
//3.调用方法:对象名.方法名()
obj.sayhi();
  • 用new Object创建对象
var obj2 = new Object(); //创建了一个空对象
//利用等号赋值的方法 添加对象的属性和方法
obj2.name = '周芷若';
obj2.age = 18;
obj2.sex = '女';
obj2.saygun = function() {
    console.log("gun~");
}
//输出
console.log(obj2.name);
  • 以构造函数来创建对象:前边两种创建方式一次只能创建一个对象,里面很多属性和方***大量相同,我们只能复制。
    因此我们可以利用函数的方法,把重复代码提出来 就把这个函数称为构造函数,
    又因为这个函数不一样 里面封装的不是普通代码 而是对象
    构造函数 就是把我们对象里面的一些相同的属性和方法抽象出来封装到函数里面
 function Stars(name, age, sex) {
     //构造函数首字母要大写
     this.name = name;
     this.sex = sex;
     this.age = age;
     this.sing = function(song) {
         console.log("我有一首歌叫" + song);
     }
 }
//创建对象
var ldh = new Stars('刘德华', 54, '男');
var zxy = new Stars('张学友', 66, '男');
ldh.sing("冰雨"); //我有一首歌叫冰雨
console.log(ldh.age + ldh.name + ldh['sex']);
遍历对象:key得到的是属性名,
//for...in...增强for循环 遍历对象
for (var key in ldh) {
    console.log(key); //得到的是属性名
    console.log(ldh[key]); //得到的是属性值
}


7.内置对象Math和Date

7.1Math

//Math内置对象
console.log(Math.max(1, 99, 8, 652)); //取最大值
console.log(Math.PI);
console.log(Math.max(1, 99, 8, 652, 'pink'));//NaN
console.log(Math.floor(2.35)); //向下取整2
console.log(Math.ceil(2.35)); //向上取整3
console.log(Math.round(-3.5)); //四舍五入版本-3
console.log(Math.abs(-3.5)); //绝对值3.5
//random():返回一个随机小数,不跟参数,可以用于代码验证
console.log(Math.random());//[0,1)
ex.得到两个数之间的随机整数 并且包含这两个整数
function getRandom(min, max) {
    return Math.floor((Math.random() * (max - min + 1) + min)); //记住这个公式
}
//随机点名
var arr = ['Amy', 'Daki', 'Sam', 'Dom'];
console.log(arr[getRandom(0, arr.length - 1)]); //下标从0到3

7.2Date

  •  Date() 日期对象是一个构造函数 必须用new来创建我们的日期对象
var date = new Date(); //如果没有参数 返回系统当前时间
console.log(date); //Fri May 06 2022 12:32:50 GMT+0800 (中国标准时间)
  • 常用的参数型写法:
//数字型2019,10,1
//注意这里的月份是按照数组形式表示的,从0-11
var date1 = new Date(2019, 9, 1);
console.log(date1);
//字符串型
var date2 = new Date('2019-10-1 8:8:8');
console.log(date2);
  • 年月日
//格式化日期 年月日
var date3 = new Date();
console.log(date3.getFullYear());
console.log("月份" + date3.getMonth()+1); //获取当月,序号从0-11,记得加一
console.log(date3.getDate()); //获取当天日期
console.log(date3.getDay()); //获取星期几(周日0-周六6)周日返回的是0
var datt = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
console.log(date3.getFullYear() + "年" + (date3.getMonth() + 1) + "月" + date3.getDate() + "日" + datt[date3.getDay()]);
  • 时分秒
 //时分秒
console.log(date3.getHours()); //获取当前小时
console.log(date3.getMinutes()); //获取当前分钟
console.log(date3.getSeconds()); //获取当前秒钟

function getTime() {
    var time = new Date();
    var hour = time.getHours();
    hour = hour < 10 ? "0" + hour : hour;
    var minutes = time.getMinutes();
    minutes = minutes < 10 ? "0" + minutes : minutes;
    var second = time.getSeconds();
    second = second < 10 ? "0" + second : second;
    return hour + ":" + minutes + ":" + second;
}
console.log(getTime());

  • 获取日期的总的毫秒形式(时间戳)的四种方法
console.log(date3.valueOf());

console.log(date3.getTime());

//简单写法,且最常用
var date4 = +new Date();
console.log(date4);

//H5新增
console.log(Date.now());
  • 倒计时
function countDJS(time) {
    //time是用户输入时间
    var nowtime = Date.now();
    var inputtime = +new Date(time);
    //这个要背下来!!!
    var times = (inputtime - nowtime) / 1000; //等于剩余时间的总秒数

    var dayy = parseInt(times / 60 / 60 / 24); //天
    dayy = dayy < 10 ? "0" + dayy : dayy; //补0操作

    var hourr = parseInt(times / 60 / 60 % 24); //时
    hourr = hourr < 10 ? "0" + hourr : hourr; //补0操作

    var minutess = parseInt(times / 60 % 60); //分
    minutess = minutess < 10 ? "0" + minutess : minutess; //补0操作

    var secondss = parseInt(times % 60); //秒
    secondss = secondss < 10 ? "0" + secondss : secondss; //补0操作

    return dayy + "天" + hourr + "小时" + minutess + "分" + secondss + "秒";
}
console.log(countDJS('2023-5-1 8:8:8'));//359天18小时45分35秒

8.数组

  • 创建数组的两种方式
var arr = [1, 2, 3];
var arr1 = new Array(); //创建了一个空数组
var arr2 = new Array(2); //创建了一个长度为2的空数组
var arr3 = new Array(2, 3); //创建了一个数组 里面的元素是2 3
  • 检测是否为数组的两种方式
console.log(arr instanceof Array); //(1)如果是则返回true
console.log(Array.isArray(arr)); //(2)如果是则返回true
  • 添加元素
var arr = [1, 2, 3];

//方法一:push(在数组末尾增添一个或者多个数组元素)
arr.push(4, 'pink');
console.log(arr.push(5, 'pink')); //push完成之后返回的是新数组的长度
console.log(arr);

//方法二:unshift(在数组最前方增添一个或者多个数组元素)
arr.unshift(0);
console.log(arr);
//完成之后返回的是新数组的长度
  • 删除元素
//方法一:pop(删除数组末尾的最后一个元素)
arr.pop();
console.log(arr.pop()); //返回值是删除的元素

//方法二:shift(删除数组的第一个元素)
arr.shift();
console.log(arr.shift());
  • 数组反转
arr4 = [1, 5, 9, 2, 6, 8, 3, 9, 5, 44, 6, 2, 0];
console.log(arr4.reverse());
  • 数组排序
console.log(arr4.sort()); //这个是先看第一位排序,再看第2位进行排序。在10以内好用
//解决方法!!!背下来
arr4.sort(
    function(a, b) {
        // return a - b;//升序的方法排列
        return b - a; //降序的方法排列
    }
);
console.log(arr4);
  • 数组索引
//数组索引,存在返回索引号,不存在返回-1
//index:从第一个开始找
console.log(arr4.indexOf(44));
console.log(arr4.indexOf(9)); //有两个一样的,只返回第一个
console.log(arr4.indexOf(99)); //返回-1

//lastindexOf:从最后一个开始找
console.log(arr4.lastIndexOf(1)); //返回索引下标
  • 数组去重:
 //核心思想:拿着旧数组跟新数组比较,如果该元素在新数组里面就接着走,不在就加进去
function unique(arr) {
    var arrnew = [];
    for (var i = 0; i < arr.length; i++) {
        if (arrnew.indexOf(arr[i]) == -1) {
            arrnew.push(arr[i]);
        }

    }
    return arrnew;
}
  • 数组转换成字符串
//toString():把数组转换成字符串 逗号分隔每一项
var arr6 = ['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b'];
console.log(arr6.toString());
//join('分隔符'):方法用于把数组中的所有元素转换成一个字符串,默认用这个分隔符来分割
console.log(arr6.join('-'));
其他方法:
(1)concat():连接两个或者多个数组 不影响原数组
(2)slice(begin,end):数组截取,返回新截取的新数组
(3)splice(第几个开始,要删除的个数):返回被删除的新数组,会影响原数组

9.字符串

字符串的所有方法本身不会修改字符串本身(因为字符串是不可变的) 操作完成后会返回一个新的字符串
  • 根据字符返回位置
var str2 = '改革春风吹面对,春天';
console.log(str.indexOf('春')); //默认从索引位置0开始找下标
console.log(str.indexOf('春', 3)); //从索引位置3开始找下标
ex.查找一段字符串中o的下标索引
var str3 = "abcodsfgsdodsfsdofsfeooo";
var index = str3.indexOf('o');
while (index != -1) {
    console.log(index);
    index = str3.indexOf('o', index + 1);
}
  • 根据位置返回字符
var str4 = 'andyyy';
console.log(str4.charAt(3));
console.log(str4.charCodeAt(3)); //返回指定位置处字符的ASCII码,可以判断用户按下了哪个按键
console.log(str4[3]); //H5新增的
遍历所有元素
for (var i = 0; i < str4.length; i++) {
    console.log(str4.charAt(i));
}
  • ex:判断字符出现最多的字符并统计其次数
var str5 = "abcodsfgsdodsfsdofsfeooo";
var zifu = {}; //创建一个对象,用于存放key-value

for (var j = 0; j < str5.length; j++) {
    var chars = str5.charAt(j); //chars是字符串中的每一个字符
    //如果chars在zifu里面
    if (zifu[chars]) { //o[chars]是得到的属性值
        zifu[chars]++;
    } else {
        zifu[chars] = 1;
    }
}
//遍历对象
var max = 0;
var ch = '';
for (var key in zifu) { //key是属性名,zifu[key]是属性值
    if (zifu[key] > max) {
        max = zifu[key];
        ch = key;
    }
}
console.log("最大的数字是:" + ch + ",个数为:" + max);
  • 其他方法:
//(1)concat(str1,str2,....):连接两个或者多个字符串 不影响原数组
console.log(str4.concat("red"));
//(2)substr(start,length):从start开始截取长度为length的字符串,返回值是截取的字符
console.log(str4.substr(0, 4));
//(3)slice(begin,end):字符串截取,返回新截取的新字符串
//(4)substring(start,end):从start开始,截取到end位置,end取不到。和slice差不多,但是不接受负值
替换字符串:
//替换字符串,replace('被替换的字符','替换为的字符') 只会替换第一个字符
var str6 = 'andyandyaa';
console.log(str6.replace('a', 'b'));
//把str7里面的o全部替换为*
var str7 = "abcodsfgsdodsfsdofsfeooo";
while (str7.indexOf('o') != -1) {//只要str7里面还有o
    str7 = str7.replace('o', '*');
}
console.log(str7);
  • 字符串转换为数组:split('分隔符') 前边学过把数组转换成字符串利用join
var str8 = "ab,cod,sfg,sd,odsf,sd,fsfe,oo"; //这个字符串有特点是用逗号分割开的
console.log(str8.split(','));
注意:简单数据类型(变量等)传递数值,复杂数据类型(对象等)传递地址

10.DOM

DOm就是一个接口用于处理html
文档:一个页面就是一个文档,DOM中使用document表示
元素:页面中所有的标签都是元素,DOM使用element表示
节点:网页中的所有内容都是节点(标签、属性、文本、注释),dom使用node表示
dom把以上都看作对象
  • 获取页面元素
<div id="time">20220206 17:07</div>
<script>
    //(1)根据id获取
    //返回的是一个元素对象object
    var timer = document.getElementById("time");
</script>


<ol id="ol_target">
    <li>这个是ol的li1</li>
    <li>这个是ol的li2</li>
    <li>这个是ol的li3</li>
</ol>
<script>
    //(2)根据标签名获取:getElementsByTagName('标签名') 返回某个元素(父元素)内部所有指定”标签名“的子元素
    //返回的是 获取的元素对象集合 以伪数组形式存储的
    var lis = document.getElementsByTagName('li');
    console.log(lis[0]);
    
    var ols2 = document.getElementById('ol_target');
    console.log(ols2.getElementsByTagName('li')); //获取ol下所有标签名是li的子元素
</script>


<div class="box">盒子1</div>
<script>
    //(3)通过html5新增方法获取:getElementsByClassName('类名') 根据类名获得某些元素集合
    var boxes = document.getElementsByClassName('box');
</script>
<script>
   //querySelector:返回指定选择器的第一个元素对象
    //类对象获取,在前边加.
    var firstbox = document.querySelector('.box');
    //id对象获取,在前边加#
    var nav = document.querySelector('#nav');
    //元素对象获取,前边不用加
    var uls1 = document.querySelector('ul');
    //querySelectorAll():返回指定选择器所有元素对象
    var allbox = document.querySelectorAll('.box');
</script>


<script>
    //特殊元素(body\html)获取
    //获取body
    var bodyEle = document.body;
    //获取html
    var htmlEle = document.documentElement;
</script>

10.1事件操作

<button id="btn">唐伯虎</button>
<script>
    //事件源:事件被触发的对象 谁? 按钮btn
    var btn = document.getElementById('btn');
    //事件类型:如何触发?什么事件?比如鼠标点击(onclick) 还是鼠标经过 还是键盘按下
    //事件处理程序: 通过一个函数赋值的方式完成
    btn.onclick = function() { //鼠标左键触发
        alert("点秋香");
    }
    //执行事件的步骤:(1)获取事件源(2)注册事件(绑定事件)(3)添加事件处理程序(采用函数赋值的形式)
</script>
 常见鼠标事件:
btn.onmouseover 鼠标经过触发
btn.onmouseoout 鼠标离开触发
btn.onfocus 获得鼠标焦点触发
btn.onblur 失去鼠标焦点触发
btn.onmousemove 鼠标移动触发
btn.onmouseup 鼠标弹起触发
btn.onmousedown 鼠标按下触发

10.2操作元素

  • element.innerText():改变元素内容,但是不识别元素标签。在显示的时候会去除空格和换行。
btn.onclick = function() {
    div.innerText = getdate();
}
  • element.innerHTML():改变元素内容,可以识别html标签。在显示的时候保留空格和换行。
p[1].innerHTML = "<strong>今天的时间是:</strong>" + getdate();
  • 普通元素用element.innerHTML()修改,表单元素用value修改。表单元素有以下属性:type、value、checked、selected、disabled。
btn3.onclick = function() {
    input.value = "点击了button";
    //注意这里不能用input.innerHTML 这个只对于普通盒子 如div
    //表单盒子得用value改
    this.disabled = true; //点击一次就让整个按钮被禁用 不能再点击
    //btn3.disabled=true也可以
}
//点击按钮密码明文显示
btn4.onclick = function() {
    if (flag == 0) {
        input2.type = "text";
        flag = 1;
    } else {
        input2.type = "password";
        flag = 0;
    }
}
  • 循环精灵图
//精灵图每个小图片大小是24*24,y坐标是0,0、0,44、0,88。。。
//因此只要让循环里的i索引号*44即是每个图片的y坐标
//获取元素
var lis = document.querySelectorAll('li');
//注册事件
for (var i = 0; i < lis.length; i++) {
    var index = i * 44;
    lis[i].style.backgroundPosition = '0 -' + (index) + 'px';
}
  • 显示和隐藏文本框内容:文本框onfucus获得焦点,onblur失去焦点
var inputt = document.querySelector('input');
inputt.onfocus = function() {
    if (this.value == '手机') {
        this.value = '';
        this.style.color = '#333';
        // 当输入元素的时候颜色变黑
    }
}
inputt.onblur = function() {
    if (this.value == '') {
        this.value = '手机';
        this.style.color = '#999'
    }
}
  • 使用classname修改样式属性
<style>
    div {
        width: 200px;
        height: 200px;
        background-color: pink;
    }

    .first {
        font-family: 'Courier New', Courier, monospace;
    }

    .change {
        background-color: purple;
        color: #fff;
        font-size: 100px;
        margin-top: 100px;
    }
</style>

<body>
    <div class="first">文本</div>
    <script>
        var wenben = document.querySelector('div');
        wenben.onclick = function() {
            //如果样式比较少或者功能简单,通过this.style修改样式属性就比较好
            // this.style.backgroundColor = 'purple';
            // this.style.color = '#fff';
            // this.style.fontSize = '50px';
            // this.style.marginTop = '100px';

            //样式比较多的话 可以用classname来修改
            // this.className = ' change';
            //就是点击之后让<div>变成了<div class="change">
            // classname会直接更改元素的类名,会覆盖原先的类名

            //如果想要原先的类有用 想让他不被覆盖的话,要在前边加一个first类名
            this.className = 'first change';
        }
    </script>
</body>
  • 密码框验证
<div class="register">
    <input type="password">
    <p class="message">请输入6-16位的密码</p>
</div>

<script>
    var inputt = document.querySelector('input');
    var message = document.querySelector('p');
    inputt.onfocus = function() {
}
inputt.onblur = function() {
    //根据表单里面的长度length比较
    if (this.value.length < 6 || this.value.length > 16) {
        message.className = "message wrong";
        message.innerHTML = "您输入的密码不符合6-16位,请重新输入";
    }
    if (this.value.length >= 6 && this.value.length <= 16) {
        message.className = "message right";
        message.innerHTML = "输入正确";
    }
}
</script>

11.排他思想

<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<button>按钮5</button>
<script>
    var buttons = document.getElementsByTagName('button');
    for (var i = 0; i < buttons.length; i++) {
        buttons[i].onclick = function() {
            //当我们点击按钮的时候 先让所有的颜色变为一开始的颜色
            for (var j = 0; j < buttons.length; j++) {
                buttons[j].style.backgroundColor = '';
            }
            //点击以后 再变成粉色
            this.style.backgroundColor = 'pink';
            //这里不能用button[i]是因为外层for循环是在给每一个button声明对象,并没有执行相应的代码,只有被点击才会执行相应的代码
            //被调用的时候i已经=5,此时buttons[i]=5是不存在的
        }
    }
</script>
<ul class="box">
    <li class="img1"><img src="images/1.jpg" alt="" class="img11"></li>
    <li class="img2"><img src="images/2.jpg" alt="" class="img22"></li>
    <li class="img3"><img src="images/3.jpg" alt="" class="img33"></li>
    <li class="img4"><img src="images/4.jpg" alt="" class="img44"></li>
</ul>
<script>
    var imgs = document.querySelector(".box").querySelectorAll('img');
    for (var i = 0; i < imgs.length; i++) {
        imgs[i].onclick = function() {
            document.body.style.backgroundImage = 'url(' + this.src + ')';
        }
    }
</script>
  • ex:表格鼠标移动上去变色
<script>
    var hangs = document.querySelector('tbody').querySelectorAll('tr');
    for (var i = 0; i < hangs.length; i++) {
        // 用className修改样式属性
        hangs[i].onmouseover = function() {
            this.className = 'bg';
        }
        hangs[i].onmouseout = function() {
            this.className = '';
        }
    }
</script>

12.案例:全选、取消全选


(1)红色框影响黄色框,红色框对勾那黄色框也就对勾。
var all = document.getElementById('all');
var cboxs = document.querySelector('tbody').querySelectorAll('input');
all.onclick = function() {
    //步骤一:上边全选按钮影响下边小按钮
    // this.checked  是当前复选框的选定状态
    for (var i = 0; i < cboxs.length; i++) {
        cboxs[i].checked = this.checked;
    }
}
(2)黄色会影响红色,每次点击都要查看循环下边的其他按钮有没有被点击 如果有一个没有被点击 上边全选就不选中
for (var i = 0; i < cboxs.length; i++) {
    cboxs[i].onclick = function() {
        var flag = true; //控制变量是否全选中
        for (var i = 0; i < cboxs.length; i++) {
            if (!cboxs[i].checked) {
                //如果存在没有被选中的,就让全选按钮不按下
                flag = false;
                break; //四个按钮有一个被选中了就无需再看是否被选中了 直接break即可
            }
        }
        all.checked = flag;
    }
}

13.自定义属性

<div id="demo" why_index="1" class="nav"></div>
  • 获取自定义属性:element.getAttribute('属性')  get得到获取 attribute 属性的意思 我们程序员自己添加的属性我们称为自定义属性
var div = document.querySelector('div');
console.log(div.getAttribute('id'));
console.log(div.getAttribute('why_index'));
  • 设置元素属性值
div.setAttribute('why_index', 2);
div.setAttribute('class', 'footer');
  • 移除属性
div.removeAttribute('why_index');

13.1 Tab栏切换内容


思路:排他思想。(1)先让所有的tablist变成灰色,当点击this的时候再变色。(2)对于显示内容模块:让所有介绍模块先消失,再让内容显示出来
<div class="tab">
    <div class="tablist">
        <li class="changecolor">商品介绍</li>
        <li>评价</li>
    </div>

    <div class="tabcon">
        <div class="item" style="display: block;">
            商品介绍模块
        </div>
        <div class="item">
            商品评价模块
        </div>
    </div>
</div>
<script>
    var tablists = document.querySelector(".tablist").querySelectorAll('li');
    var tabcons = document.querySelector(".tabcon").querySelectorAll('.item');
    for (var i = 0; i < tablists.length; i++) {
        // 开始先给2个小li 设置索引号 
        tablists[i].setAttribute('index', i);
        tablists[i].onclick = function() {
            // 排他思想 先让所有的tablist变成灰色,当点击this的时候再变色
            for (var i = 0; i < tablists.length; i++)
                tablists[i].className = '';
            this.className = 'changecolor';
            //显示内容模块 点击的时候 对应的div显示 不点击的时候隐藏
            //所以可以设置索引号获取当前点击了哪个
            var index = this.getAttribute('index');
            //排他思想 让所有介绍模块先消失,再让内容显示出来
            for (var i = 0; i < tabcons.length; i++) {
                tabcons[i].style.display = 'none';
            }
            //让对应序号里面的div内容显示出来
            tabcons[index].style.display = 'block';
        }
    }
</script>

13.2自定义属性设置

(1)为了区分内置属性和自定义属性,H5规定自定义属性要以“data-”开头作为属性名 并且赋值
(2)用多个“-”链接的单词 获取的时候用驼峰命名法listName来获取
<body>
    <div data-getTime="20" data-index="1" data-list-name="anmdy"></div>
    <script>
        var div = document.querySelector('div');
        div.setAttribute('data-Time', 20);
        console.log(div);
        //H5新增获取自定义属性的方法 dataset就是一个集合:只能获取data-开头的
        //兼容性不太好
        console.log(div.dataset);
        console.log(div.dataset.index);
        console.log(div.dataset['index']);
        // 如果自定义属性里面有多个“-”链接的单词 我们获取的时候采用 驼峰命名法
        //如上面我们命名为data-list-name,而下边获取的时候用listName
        console.log(div.dataset['listName']);
    </script>
</body>

14.节点操作

<div>我是div</div>
<span>我是span</span>
<ul>
    <li>我是li111</li>
    <li>我是li222</li>
    <li>我是li333</li>
    <li>我是li444</li>
</ul>
<div class="box">
    <span class="erweima">×</span>
</div>

14.1 父节点

我们获取的是最近的父亲节点(亲爸爸),如果找不到父节点 就返回为空
var erweima = document.querySelector('.erweima');
console.log(erweima.parentNode);

14.2子节点

子节点childNode 里面包含了元素节点 文本节点等所有可能出现的节点
var ul = document.querySelector('ul');
console.log(ul.childNodes);
//输出了文本节点(里面存在着换行)和li子节点
//如果只想要元素节点 就可以使用nodeType
//如果只想要元素节点 就可以使用nodeType
//方法1
console.log(ul.childNodes[1].nodeType); //看一下li元素节点的nodeType是多少  =1
for (var i = 0; i < ul.childNodes.length; i++) {
    if (ul.childNodes[i].nodeType == 1) {
        //如果是li元素节点 则输出
        console.log(ul.childNodes[i]);
    }
}
//方法2:用children可以输出元素节点 是非标准方法 但是每个浏览器都支持 也是实际开发常用的 提倡!!!
console.log(ul.children);

//获取第一个节点firstChild 和 获取最后一个节点lastChild 但是可能是文本节点
//所以有了新方法 获取第一个元素节点 firstElementChild 但是这两个有兼容性问题 必须是IE9以上才支持
console.log(ul.firstElementChild);
console.log(ul.lastElementChild);
//实际开发中写法 既没有兼容性 又可以返回第一个子元素 和最后一个元素
console.log(ul.children[0]);
console.log(ul.children[ul.children.length - 1]);

14.3兄弟节点

<div>我是div</div>
<span>我是span</span>

<script>
    var div = document.querySelector('div');
    // 1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等
    console.log(div.nextSibling); //发现得到的下一个是文本节点#text
    console.log(div.previousSibling); //如果找不到 返回的是null

    // 2. nextElementSibling 得到下一个“兄弟元素节点”
    //有兼容性问题 必须是ie9以上才可以使用
    console.log(div.nextElementSibling);
    console.log(div.previousElementSibling);
</script>
  • 创建createElement和插入appendChild、insertBefore节点
<ul>
    <li>123</li>
</ul>
<script>
    var ul = document.querySelector('ul');
    //创建节点
    var li = document.createElement('li');
    //添加节点 node.appendChild(child)  node是父级 child是子级
    //追加元素(添加在后边,相当于push)      
    ul.appendChild(li);

    //追加元素(添加在前边) ul.insertBefore(child,指定元素);
    var lili = document.createElement('li');
    ul.insertBefore(lili, ul.children[0]);
</script>
  • 删除节点removeChild
<button>删除</button>
<ul>
    <li>熊大</li>
    <li>熊二</li>
    <li>光头强</li>
</ul>
<script>
    var btn = document.querySelector('button');
    var ul = document.querySelector('ul');
    btn.onclick = function() {
        if (ul.children.length == 0) {
            //如果已经删完了 就让这个按钮禁用
            this.disabled = true;
        } else {
            //删除元素
            ul.removeChild(ul.children[0]);
        }
    }
</script>

14.4案例:发布、删除留言案例

思路:(1)设置一个空的ul,点击按钮之后就动态创建一个li 添加到ul里面.(2)将textarea里面的值通过li.innerHTML赋值给li
<div class="liuyan">
    <textarea name="liuyanban" id="" cols="30" rows="10"></textarea>
    <button id="fb">发布</button>
</div>
<ul>

</ul>
<script>
    //核心就是 点击按钮之后就动态创建一个li 添加到ul里面
    //将textarea里面的值通过li.innerHTML赋值给li
    var button = document.getElementById('fb');
    var text = document.querySelector('textarea');
    var ul = document.querySelector('ul');

    button.onclick = function() {
        if (text.value == '') {
            alert("您没输入内容");
            return false;
        } else {
            //创建元素
            var li = document.createElement('li');   
            //a href='javascript:;'表示点击a的时候不会跳转            
            li.innerHTML = text.value + "<a href='javascript:;'>删除</a>"; //添加内容

            //在最前边添加元素
            ul.insertBefore(li, ul.children[0]);
            //在后边添加元素
            // ul.appendChild(li);

            //删除操作:要把它放在button的里面 因为要先创建了a元素才可以删除 所以一定要在button里面
            //每生成一个a就给当前元素添加一个事件
            var a = document.querySelector('a');
            a.onclick = function() {
                // node.removeChild(child); 删除的是 li 当前a所在的li  this.parentNode;
                ul.removeChild(this.parentNode);
            }
        }
    }
</script>

14.5复制节点

复制节点:node.cloneNode()
<ul>
    <li>1111</li>
    <li>2</li>
    <li>3</li>
</ul>
<script>
    var ul = document.querySelector('ul');
    //如果cloneNode() 括号里面的参数为空或者为false 则是浅拷贝 即只克隆复制节点本身 并不复制里面的子节点
    // 1. node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容
    // 2. node.cloneNode(true); 括号为true 深拷贝 复制标签复制里面的内容
    var lili = ul.children[1].cloneNode(true);
    ul.appendChild(lili);
</script>

14.6案例:动态生成学生成绩表和删除

<body>
    <table cellspacing="0">
        <thead>
            <tr>
                <th>姓名</th>
                <th>科目</th>
                <th>成绩</th>
                <th>操作</th>
            </tr>
        </thead>
        <tbody>

        </tbody>
    </table>
    <script>
        //先准备好学生数据
        var dates = [{
            name: "WHY",
            subject: "JS",
            grades: 100
        }, {
            name: "HL",
            subject: "JS",
            grades: 90
        }, {
            name: "FH",
            subject: "JS",
            grades: 80
        }, {
            name: "MY",
            subject: "JS",
            grades: 99
        }];
        //所有数据放到tbody里面,一个人对应一行
        var tb = document.querySelector('tbody');
        for (var i = 0; i < dates.length; i++) {
            //创建tr行
            var tr = document.createElement('tr');
            tb.appendChild(tr);
            // 一个i代表一个对象
            //有多少列跟对象属性有几个有关系
            for (var k in dates[i]) {
                //k得到的是属性名 obj[k]得到的是属性值
                //创建单元格
                var td = document.createElement('td');
                td.innerHTML = dates[i][k];
                tr.appendChild(td);
            }
            //创建删除单元格
            var td = document.createElement('td');
            td.innerHTML = "<a href='javascript:;'>删除</a>";
            tr.appendChild(td);
        }
        //删除操作:放在创建下边
        var as = document.querySelectorAll('a');
        for (var i = 0; i < as.length; i++) {
            as[i].onclick = function() {
                tb.removeChild(this.parentNode.parentNode);
                //在tbody里面删除【删除链接的爸爸的爸爸=单元行】
            }
        }
    </script>
</body>

14.7三种动态创建元素的区别

  • document.write():创建元素  如果页面文档流加载完毕,再调用这句话会导致页面重绘
var btn = document.querySelector('button');
btn.onclick = function() {
    document.write('<div>123</div>');
}
  • inner()创建
如果创建多个 采用的是字符串拼接的话  效率特别慢 3000+毫秒
var inner = document.querySelector('.inner');
for (var i = 0; i <= 100; i++) {
    inner.innerHTML += '<a href="#">百度</a>'
}
如果创建多个 采用的是数组形式拼接的话  效率特别快 6毫秒
	
	
	
	
var inner = document.querySelector('.inner');
var arr = []; for (var i = 0; i <= 100; i++) {     arr.push('<a href="#">百度</a>'); } inner.innerHTML = arr.join('');
  • createElement创建 如果创建多个 效率快 20毫秒 但是结构会更加清晰【推荐】
var create = document.querySelector('.create');
for (var i = 0; i <= 100; i++) {
    var a = document.createElement('a');
    create.appendChild(a);
}

15.注册/绑定事件  删除/解绑事件

15.1 注册/绑定事件

绑定事件:给元素添加事件称之为注册事件有两种方式:传统方式+方法监听方式
//1.传统注册 特点是注册事件具有唯一性
//同一个元素同一个注册事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数
var btns = document.querySelectorAll('button');
btns[0].onclick = function() {
    alert('hi');
}
btns[0].onclick = function() {
    //只会显示hao a u
    alert('hao a u');
}
// 2. 事件侦听注册事件 addEventListener w3c标准
// (1) 里面的事件类型是字符串 必定加引号 而且不带on 只写click即可 不用谢onclick
// (2) 同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
btns[1].addEventListener('click', function() {
    alert(22);

})
// 3. attachEvent ie9以前的版本支持 是非标准的 尽量不要使用【了解】
btns[2].attachEvent('onclick', function() {
    alert(11);
})

15.2 删除/解绑

var divs = document.querySelectorAll('div');

//1.传统方式解绑事件
//每点一次div就会alert一次
divs[0].onclick = function() {
    alert(11);
    //我们希望可以点击一次下一次不会弹出来,用下边的语句解绑
    divs[0].onclick = null;
}

//2.方法监听注册方式解绑事件,removeEventListener
//在回调函数fn里面写上功能函数解绑
divs[1].addEventListener('click', fn);

function fn() {
    alert(22);
    divs[1].removeEventListener('click', fn);
}

// 3. detachEvent 【了解即可】
divs[2].attachEvent('onclick', fn1);

function fn1() {
    alert(33);
    divs[2].detachEvent('onclick', fn1);
}

16.DOM事件流

  1. DOM事件流:事件发生的时候会在元素节点之间按照特定的顺序传播 这个传播的过程就是 DOM事件流。
  2. DOM事件流分为三个阶段:捕获阶段(从上往下走)、当前目标阶段、冒泡阶段(从下往上走)
  3. JS代码中只能执行捕获或者冒泡其中一个阶段。onclick 和 attachEvent 只能得到冒泡阶段。
  4. addEvenListener(type,listener[,useCapture])第三个参数如果是true表示在事件捕获阶段调用事件处理程序。如果是false(不写默认是false),表示事件在冒泡阶段调用事件处理程序。
  5. 我们在实际开发中更关心的是事件冒泡 很少使用事件捕获。
  6. 有些事件没有冒泡 如onblur onfoucs onmouseover onmouseleave等
<div class="father">
    <div class="son">son盒子</div>
</div>
件捕获:document-html-body-father-son,输出father 在输出son
var son = document.querySelector('.son');
son.addEventListener('click', function() {
    alert('son');
}, true);
var fa = document.querySelector('.father');
fa.addEventListener('click', function() {
    alert('father');
}, true);
事件冒泡:son-father-body-html-document
//点击son向上冒泡。输出son-father
son.addEventListener('click', function() {
    alert('son');
}, false);
//点击father向上冒泡,输出father
var fa = document.querySelector('.father');
fa.addEventListener('click', function() {
    alert('father');
}, false);

17.事件对象

var div = document.querySelector('div');
div.onclick = function(event) {
    // console.log(event);
    // console.log(window.event);
    //兼容性写法如下,利用了||公式,如果第一个event=event能识别出来 则不用在进行window.event,如果识别不出来 则要进行
    event = event || window.event;
    console.log(event);
}
  • event 就是一个事件对象 写到我们侦听函数的 小括号里面 当形参来看。
  • 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数。
  • 事件对象 是 我们事件的一系列相关数据的集合 跟事件相关的 比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标啊,如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键。
  • 这个事件对象我们可以自己命名 比如 event 、 evt、 e等。
  • 事件对象也有兼容性问题 ie678 通过 window.event 兼容性的写法  e = e || window.event;

17.1 事件对象阻止默认行为

  • 返回事件类型 e.type
var div = document.querySelector('div');
div.addEventListener('click', fn);
div.addEventListener('mouseover', fn);
div.addEventListener('mouseout', fn);

function fn(e) {
    console.log(e.type);
}

  • 阻止默认行为 让链接不跳转 让提交按钮不提交
var a = document.querySelector('a');
a.addEventListener('click', function(e) {
    e.preventDefault(); //DOM推荐的标准写法
});

17.2 阻止事件冒泡

  • 点击son只出来son
var son = document.querySelector('.son');
son.addEventListener('click', function(e) {
    alert('son');
    e.stopPropagation(); // stop 停止  Propagation 传播
    // e.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡
}, false);
  • 点击father出来father和document,因为没有阻止事件冒泡
var father = document.querySelector('.father');
father.addEventListener('click', function() {
    alert('father');
}, false);
document.addEventListener('click', function() {
    alert('document');
})

18 事件委托

  • 事件委托=事件代理 在jQuery里面称为事件委派
  • 原理:不是每个子结点单独设置事件监听器 而是事件监听器设置在父节点上 然后利用冒泡原理影响设置每个子节点
  • 事件委托的作用:我们只操作了一次DOM 提高了程序的性能
  • e.target可以获取我们点击的对象
<ul>
    <li>点我应有弹框在手!</li>
    <li>点我应有弹框在手!</li>
    <li>点我应有弹框在手!</li>
    <li>点我应有弹框在手!</li>
    <li>点我应有弹框在手!</li>
</ul>
<script>
    //事件委托的核心原理:给父节点添加一个侦听器 也就是事件处理程序 利用子节点的操作 冒泡向上传到父节点进行输出
    //这样做的好处就是不用设置循环【点一次循环一次】,提升了效率
    var ul = document.querySelector('ul');
    ul.addEventListener('click', function(e) {
        alert('点我应有弹框在手!');
        //e.target可以获取我们点击的对象 所以可以让我们点那个哪个的背景颜色变红
        e.target.style.backgroundColor = 'pink';
    })
</script>

19 鼠标键盘事件

19.1 鼠标事件

  • 禁止鼠标右键菜单 contextmenu
  • 禁止鼠标选中 selectstart
我是一段不愿意分享的文字
<script>
    //禁止右键菜单
    document.addEventListener('contextmenu', function(e) {
        e.preventDefault(); //阻止默认行为
    })
    //禁止选中文字
    document.addEventListener('selectstart', function(e) {
        e.preventDefault(); //阻止默认行为
    })
</script>

19.2 鼠标事件对象

需要掌握的鼠标事件对象
  • e.clientX 返回鼠标相对于浏览器窗口可视区的X坐标
  • e.clientY 返回鼠标相对于浏览器窗口可视区的Y坐标
  • e.pageX 返回鼠标相对于文档页面的X坐标 IE9+支持
  • e.pageY 返回鼠标相对于文档页面的Y坐标 IE9+支持
  • e.screenX 返回鼠标相对于电脑屏幕的X坐标
  • e.screenY 返回鼠标相对于电脑屏幕的Y坐标
document.addEventListener('click', function(e) {
    //返回鼠标相对于浏览器窗口可视区的X坐标
    console.log(e.clientX);
    //返回鼠标相对于浏览器窗口可视区的Y坐标
    console.log(e.clientY);
    // 返回鼠标相对于文档页面的X坐标 常用
    console.log(e.pageX);
    //返回鼠标相对于文档页面的Y坐标 IE9+支持
    console.log(e.pageY);
    //返回鼠标相对于电脑屏幕的X坐标
    console.log(e.screenX);
    //返回鼠标相对于电脑屏幕的Y坐标
    console.log(e.screenY);
})
ex.图片跟随鼠标移动
var img = document.querySelector('img');
document.addEventListener('mousemove', function(e) {
    //得到最新的鼠标下标
    var x = e.pageX;
    var y = e.pageY;
    //千万不要忘记给left top添加px
    //如果想要居中 则再向左+向上一半图片像素即可
    img.style.left = x + "px";
    img.style.top = y + "px";
})

19.3 键盘事件

  • onkeyup 键盘按键松开时触发
  • onkeydown 键盘按键按下时触发
  • onkeypress 键盘按键按下时触发 但是不识别功能键 ctrl shift
document.addEventListener('keyup', function() {
    console.log("我弹起了");
});

document.addEventListener('keydown', function() {
    console.log("我按下了");
});

document.addEventListener('keypress', function() {
    console.log("我按下了 不识别功能键");
});
ex.判断按下了哪个按键
  • 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
  • 我们的keyup 和keydown事件不区分字母大小写  a A 得到的都是65
  • 我们的keypress 事件 区分字母大小写  a  97 A 得到的是65
document.addEventListener('keydown', function(e) {
    // 我们可以利用keycode返回的ASCII码值来判断用户按下了那个键
    if (e.keyCode === 65) {
        alert('您按下的a键');
    } else {
        alert('您没有按下a键')
    }
});
document.addEventListener('keypress', function(e) {
    console.log('press:' + e.keyCode);
});

ex. 按下s按键 定位到搜索框

  • 要用keyup 这样按下文字文字不会输入进去
  • 如果用keydown 按下会一直输入
<div class="box">
    <input type="text">
    <button>搜索</button>
</div>
<script>
    var search = document.querySelector('input');
    document.addEventListener('keyup', function(e) {
        //松开时才定位光标 这样文字不会输入进去
        //如果用keydown 按下会一直输入
        if (e.keyCode == 83) {
            search.focus();
        }
    })
</script>
ex.快递单号查询

  • 快递单号输入内容时上面的大号字体盒子con显示(这里面的字号更大
  • 表单检测用户输入给表单添加键盘事件
  • 同时把快递单号里面的值value获取过来赋值给 con盒子innerText做为内容
  • 如果快递单号里面内容为空则隐藏大号字体盒子(con)盒子
<div class="search">
    <div class="con">123</div>
    <input type="text" placeholder="请输入您的快递单号" class="jd">
</div>
<script>
    var con = document.querySelector('.con');
    var jd_input = document.querySelector('.jd');
    jd_input.addEventListener('keyup', function(e) {
        if (this.value == '') {
            con.style.display = 'none';
        } else {
            con.style.display = 'block';
            con.innerText = this.value;
        }
    });
    // 当我们失去焦点,就隐藏这个con盒子
    jd_input.addEventListener('blur', function() {
        con.style.display = 'none';
    });
    // 当我们获得焦点,就显示这个con盒子
    jd_input.addEventListener('focus', function() {
        if (this.value != '')
            con.style.display = 'block';
    });
</script>

20 BOM

  • Bom是浏览器对象模型 它提供了独立于内容而与浏览器窗口进行交互的对象 其核心对象是window,BOM由一系列相关对象构成 并且每个对象都提供了很多方法和属性

Dom和Bom的区别
  • Dom是把文档当作一个对象 顶级对象是document 主要是用来学习如何操作页面元素
  • bom是把窗口当作一个对象 顶级对象是window 主要是用来学习浏览器窗口交互的一些对象 兼容性较差

window对象是浏览器的顶级对象 具有双重角色
  • 是访问浏览器窗口的一个接口
  • 是一个全局变量 定义在全局作用域中的变量和函数都会变成window对象的属性和方法在调用的时候都可以省略 见代码

20.1 页面加载事件 load

页面加载事件可以使得 js代码放在页面中的任何一个位置都不会受限
  • 方法一:传统注册方法
window.onload 窗口页面加载事件 当文档内容完全加载完成会触发该事件包括图像脚本文件CSS
window.onload传统注册方式只能写一次 如果有多个 会以最后一个window.onload为准
window.onload = function() {
    var btn = document.querySelector('button');
    btn.addEventListener('click', function() {
        alert('click on me!');
    })
}
  • 方法二:提倡的写法:使用addEventListener则没有“只能写一次 如果有多个 会以最后一个为准”的限制
window.addEventListener('load', function() {
    var btn = document.querySelector('button');
    btn.addEventListener('click', function() {
        alert('click on me!');
    })
})
  • DOMContentLoaded是等DOM加载完成以后 不包含图片 flash css就可以执行 加载速度会更快一点
document.addEventListener('DOMContentLoaded', function() {
    alert(33);
})

20.2 调整窗口大小 resize

  • 只要窗口的像素大小发生变化 就会触发这个事件
  • window.innerWidth可以获取当前屏幕的宽度 完成响应式布局
// 设置窗口小于800px就隐藏 大于800像素就显示
window.addEventListener('load', function() {
    var div = document.querySelector('div');
    window.addEventListener('resize', function() {
        if (window.innerWidth <= 800) {
            div.style.display = 'none';
        } else
            div.style.display = 'block';
        console.log('窗口变化了');
    })
})

21 两种定时器

21.1 settimeout

  • 延迟时间是毫秒 但是可以省略 默认为0  2000ms=2s
  • 这个调用函数可以直接写函数 也可以写函数名
  • 页面中可能会有很多的定时器 所以我们经常给定时器加标识符 即命名
//案例有一个广告 5s之后隐藏
var div = document.querySelector('div');
setTimeout(callback, 5000);

function callback() {
    div.style.display = 'none';
}
  • 清除定时器
<button>清除定时器</button>
<script>
    var btn = document.querySelector('button');
    var time3 = setTimeout(function() {
        console.log('时间到了');
    }, 4000);
    btn.addEventListener('click', function() {
        clearTimeout(time3);
    })
</script>

21.2 setInterval  方法重复调用一个函数 每隔这个时间 就去调用一次这个函数

每隔3s持续输出
setInterval(function() {
    console.log('持续输出');
}, 3000);
ex.倒计时
<div>
    <span class="hour">1</span>
<span class="minute">2</span>
<span class="second">3</span>
</div>
<script>
    // 获取元素
    var hour = document.querySelector('.hour');
var minute = document.querySelector('.minute');
var second = document.querySelector('.second');
var inputtime = +new Date('2022-5-13 8:8:8');
// 先调用一次这个函数 防止第一次刷新页面有空白
countDJS();
// 开启定时器
var time = setInterval(countDJS, 1000);

function countDJS() {
    //time是用户输入时间
    var nowtime = Date.now();

    var times = (inputtime - nowtime) / 1000; //等于剩余时间的总秒数

    var hourr = parseInt(times / 60 / 60 % 24); //时
    hourr = hourr < 10 ? "0" + hourr : hourr; //补0操作
    hour.innerHTML = hourr;

    var minutess = parseInt(times / 60 % 60); //分
    minutess = minutess < 10 ? "0" + minutess : minutess; //补0操作
    minute.innerHTML = minutess;

    var secondss = parseInt(times % 60); //秒
    secondss = secondss < 10 ? "0" + secondss : secondss; //补0操作
    second.innerHTML = secondss;
}
</script>
  • 清除定时器
<button class="end">清除定时器clearInterval</button>
<button class="start">开启定时器</button>
<script>
    var btn1 = document.querySelector('.end');
    var btn2 = document.querySelector('.start');
    btn1.addEventListener('click', function() {
        clearInterval(time);
    })
    btn2.addEventListener('click', function() {
        time = setInterval(countDJS, 1000);
    })
</script>
ex.5s内验证码不能点击
<!-- 案例:发送验证码 60s内不能点击 显示还剩XXs才能继续点击 -->
<!-- 如果变成0则让button解禁 -->
手机号码:<input type="number">
<button class="yzm">发送</button>
<script>
    var btn3 = document.querySelector('.yzm');
    var inputtime1 = 5;
    btn3.addEventListener('click', function() {
        // 先调用一次 不然会出现一秒的延时
        yzm();
        btn3.disabled = true;
        // 这里也可以用 this.disabled = true;
        var time4 = setInterval(yzm, 1000);

        function yzm() {
            if (inputtime1 > 0) {
                btn3.innerHTML = "还剩" + inputtime1 + "秒才可以继续点击";
                inputtime1--;
            } else {
                clearInterval(time4);
                // 更新inputtime1 当再次按下的时候就可以重新计时
                inputtime1 = 5;
                btn3.innerHTML = "发送";
                btn3.disabled = false;
            }
        }
    })
</script>

22 同步和异步

1.js原先是是单线程语言 也就是说同一个时间只能做同一件事 意味着所有的任务都需要排队 所以可能会造成页面渲染不连贯,所以元素的删除和添加不能同时进行 只能先添加之后才能删除
2.为了解决这个问题 js现在 允许创建多个线程 于是js出现了同步和异步
3.同步钱一个任务完成后在执行后一个任务 程序的执行顺序和任务的排列顺序是一致的
4.异步因为做一件事的时候 这件事会花费很长时间 所以在做这件事的时候 你还可以去处理其他事情 比如做饭的异步做法在烧水的10min里炒菜和切菜

同步任务都在主线程上执行 形成一个执行栈
异步任务JS的异步是通过回调函数来实现的一般来说异步任务有以下三种类型
1普通事件clickresize
2资源加载loaderror
3定时器setIntervasetTimeout
异步任务相关回调函数添加到任务队列消息队列

所以执行任务的顺序
1先执行执行栈中的同步任务
2如果遇到异步任务将其放入任务队列中
3执行栈中的任务完成 系统按次序执行任务队列中的异步任务 异步任务结束等待的状态 进入执行栈 开始执行
// (1)先执行“执行栈的1”
console.log(1);
// (2)放入任务队列中等待
// (4)1和2执行完成 去执行3
setTimeout(function() {

    console.log(3);

}, 0);
// (3)在执行2
console.log(2);

23 location

window 对象给我们提供了一个 location属性
location属性用于获取或者设置窗体的url,并且可以解析url因为这个属性返回的是一个对象所以我们将这个属性也称为 location 对象

url
  • 统一资源定位符uniform resouce locator==是互联网上标准资源的地址互联网上的每个文件都有一个唯一的 URL
  • 它包含的信息指出文件的位置以及浏览器应该怎么处理它

location对象属性       返回值
location.href      获取或者设置整个URL
location.host      返回主机域名www.baidu.com
location.port      返回端口号如果未写返回空字符串
location.pathname   返回路径
location.search    返回参数
location.hash       返回片段 #后面内容常见于链接 锚点
var btn = document.querySelector('button');
var div = document.querySelector('div');
btn.addEventListener('click', function() {
    // 给了一个新的href就会跳转到新的页面中
    location.href = 'http://www.itcast.cn';
})
var timer = 5;
setInterval(function() {
    if (timer == 0) {
        location.href = 'http://www.itcast.cn';
    } else {
        div.innerHTML = '您将在' + timer + '秒钟之后跳转到首页';
        timer--;
    }
}, 1000);

23.1 location.search参数

  • index页面有一个登录表单 可以提交到index2中
  • 第二个页面可以获取第一个页面的参数 可以实现数据不同页面的传递
  • 第二个页面之所以可以获取第一个页面的数据 是利用了url中的location.search参数
index1:
<form action="59index2.html">
    <!-- action表示跳转到第二个页面 -->
    <div>登陆页面:</div>
    用户名:<input type="text" name="uname">
    <input type="submit" value="登录">
</form>


index2:
console.log(location.search);
// 先去掉问号 substr('起始的位置',截取的字符)
var pa = location.search.substr(1); //生成uname=123
console.log(pa);
// 利用=把字符串分割为数组 split('=');
var arr = pa.split('=');
console.log(arr);
var div = document.querySelector('div');
div.innerHTML = "欢迎你," + arr[1];

23.2 location常用方法

  • location.assign 跟href一样 可以跳转页面也称为重定向页面
  • location.replace()  替换当前页面因为不记录历史所以不能后退页面
  • location.reload()   重新加载页面相当于刷新按钮或者 f5如果参数为true 强制刷新 ctrl+f5
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
    // 可以记录浏览历史 所以可以实现后退功能
    location.assign('http://www.baidu.com');
    // 不记录历史 无法实现后退功能
    location.replace('http://www.baidu.com');
    // 重新加载页面
    location.reload(true);
})

23.3 navigator

  • navigator 对象包含有关浏览器的信息它有很多属性
  • 我们常用的是userAgent,该属性可以返回由客户机发送服务器的user-agent头部的值
  • 下面前端代码可以判断用户是用哪个终端打开页面的如果是用 PC 打开的我们就跳转到 PC 端的页面如果是用手机打开的就跳转到手机端页面
//到时候复制这个代码即可
if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
    window.location.href = "移动端的网址"; //手机
} else {
    window.location.href = "pc端的网址"; //电脑
}

23.4 history

<a href="61index.html">点击我前往61index</a>
<button>前进</button>
<script>
    // window 对象给我们提供了一个 history 对象,与浏览器历史记录进行交互
    // 该对象包含用户(在浏览器窗口中)访问过的 URL。
    // back()	可以后退功能
    // forward()	前进功能
    // go(参数)	前进后退功能,参数如果是 1 前进1个页面 如果是 -1 后退1个页面
    var btn = document.querySelector('button');
    btn.addEventListener('click', function() {
        // history.forward();
        history.go(1);
    })
</script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
    // history.back();
    history.go(-1);
})

24 offset

// offset系列
var father = document.querySelector('.father');
var son = document.querySelector('.son');
// 可以得到元素的偏移 位置 返回不带单位的数值
console.log(father.offsetTop);
console.log(father.offsetLeft);
// son盒子以“带有定位”的父亲为准 如果没有父亲或者父亲没有定位 则以body为准
console.log(son.offsetLeft);
// 返回带有定位的父亲 否则返回的就是body
console.log(son.offsetParent);
// 可以得到元素的大小 宽度和高度
var w = document.querySelector('.w');
console.log(w.offsetWidth);
console.log(w.offsetHeight);

















全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务