DOM BOM

Web API

Web API是浏览器提供的一套操作浏览器功能和页面元素的API(BOM和DOM).

Web API主要是针对于浏览器提供的接口,主要针对于浏览器做交互效果。

Web API一般都有输入和输出(函数的传参和返回值), WebAPI很多都是方法(函数)

DOM(文档对象模型)

文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展标记语言( HTML或者XML)的标准编程接口

w3C已经定义了一系列的DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式。

我们获取过来的DOM元素是一个对象( object ),所以称为文档对象模型

1、DOM树

文档:一个页面就是一个文档,DOM中使用document表示

元素∶页面中的所有标签都是元素,DOM中使用element表示
节点∶网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用node表示

DOM把以上内容都看做是对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BoPPUt7H-1669643074814)(1667728180456.png)]

2、获取元素

DOM在我们实际开发中主要用来操作元素。我们如何来获取页面中的元素呢?

(1)根据ID获取

使用getElementByld()方法可以获取带有ID的元素对象。

<body>
<div id="time">2022-11-5</div>
<script>
  // 因为文档页面从上往下加载,所以先得有标签 所以script标签写到标签下面
  //get获得 element元素 by通过 驼峰命名法
  //参数:id是大小写敏感的字符串
  //返回的是一个元素对象
  var timer = document.getElementById('time');
  console.log(timer)
  console.log(typeof timer) //object
  //console.dir 打印返回的元素对象 更好地查看里面的属性和方法
  console.dir(timer)

</script>
</body>

(2)根据标签名获取

使用getElementsByTagName()方法可以返回带有指定标签名的对象的集合

<body>
<ul>
  <li>web前端学习之路漫长1</li>
  <li>web前端学习之路漫长2</li>
  <li>web前端学习之路漫长3</li>
  <li>web前端学习之路漫长4</li>
  <li>web前端学习之路漫长5</li>
</ul>
<ol id="ol">
  <li>生僻字1</li>
  <li>生僻字2</li>
  <li>生僻字3</li>
  <li>生僻字4</li>
  <li>生僻字5</li>
</ol>
<script>
  //返回的是 获取过来元素对象的集合,以伪数组的形式存储
  //  如果页面中只有一个li返回的还是伪数组的形式
  //  如果页面中没有这个元素返回的是空的伪数组的形式
  var lis = document.getElementsByTagName('li')
  console.log(lis)
  console.log(lis[0])
//  我们想要依次打印里面的元素对象我们可以采取遍历的方式
  for (var i = 0;i<lis.length;i++){
    console.log(lis[i])
  }
//  指定父元素element.getElementsByTagName('标签名')
//  1、父元素必须是单个对象(必须指明是哪一个元素对象).获取的时候不包括父元素自己。
  /*var ol = document.getElementsByTagName('ol')
  console.log(ol[0].getElementsByTagName('li'))*/
  //2、给ol一个id
  var ol = document.getElementById('ol')
  console.log(ol.getElementsByTagName('li'))
</script>
</body>

(3)H5新增获取元素方法

document.getElementsByClassName(‘类名’) 根据类名获取元素

<body>
<div class="box">盒子1</div>
<div class="box">盒子2</div>
<div id="nav">
  <ul>
    <li>首页</li>
    <li>产品</li>
  </ul>
</div>
<script>
  //1、document.getElementsByClassName('类名') 根据类名获取元素
  var boxs = document.getElementsByClassName('box')
  console.log(boxs)
//  2、querySelector('选择器')返回指定选择器的第一个元素对象 里面的选择器需要加符号 .box #nav
  var firstBox = document.querySelector('.box')
  console.log(firstBox)
  var nav = document.querySelector('#nav')
  console.log(nav)
  var li = document.querySelector('li')
  console.log(li)
//  3、querySelectorAll('选择器')返回指定选择器返回所有元素对象集合
  var allBox = document.querySelectorAll('.box')
  console.log(allBox)
  var lis = document.querySelectorAll('li')
  console.log(lis)
</script>
</body>

(4)获取特殊元素(body,html)

<body>
<script>
  // 1、获取body元素
  var bodyEle = document.body
  console.log(bodyEle)
  console.dir(bodyEle)
  //2、获取html元素
  // var htmlEle = document.html
  var htmlEle = document.documentElement
  console.log(htmlEle)
</script>
</body>

3、事件基础

JavaScript使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为。

简单理解∶触发—响应机制。
网页中的每个元素都可以产生某些可以触发JavaScript的事件,例如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作。

鼠标事件触发条件
onclick鼠标点击左键触发
onmouseover鼠标经过触发
onmouseout鼠标离开触发
onfocus获得鼠标焦点触发
onblur失去鼠标焦点触发
onmousemove鼠标移动触发
onmouseup鼠标弹起触发
onmousedown鼠标按下触发
ondblclick双击

(1)事件三要素

事件由三部分组成: 事件源、事件类型、事件处理程序

<body>
  <button id="btn">唐伯虎</button>
  <script>
    //点击一个按钮,弹出对话框
  //  1、事件由三部分组成: 事件源、事件类型、事件处理程序
  //  (1)事件源:事件被触发的对象 ? 按钮
    var btn = document.getElementById('btn');
  //  (2)事件类型 如何触发 什么事件  比如鼠标点击(onclick)、鼠标经过、键盘按下
    //  (3)事件处理程序 通过一个函数赋值的方式完成
    btn.onclick = function (){
      alert('点秋香')
    }
  </script>
</body>

(2)执行事件的步骤

1.获取事件源
⒉注册事件(绑定事件)
3.添加事件处理程序(采取函数赋值形式)

<body>
  <div>123</div>
  <script>
    //执行事件步骤
  //  点击div 控制台输出:我被选中了
  //  1、获取事件源
    var div = document.querySelector('div')
    // console.log(div)
  //  2、注册事件(绑定事件)
  //  div.onclick
    //  3、添加事件处理程序(采取函数赋值形式)
    div.onclick = function (){
      console.log('我被选中了')
      alert('123')
    }
  </script>
</body>

4、操作元素

JavaScript的DOM操作可以改变网页内容、结构和样式,我们可以利用DOM操作元素来改变元素里面的内容、属性等。注意以下都是属性

(1)改变元素内容

<body>
    <div></div>
    <p>
        我是文字
        <span>123</span>
    </p>
    <script>
        // innerText 和 innerHTML的区别 
        // 1. innerText 不识别html标签 非标准  去除空格和换行
        var div = document.querySelector('div');
        // div.innerText = '<strong>今天是:</strong> 2019';
        // 2. innerHTML 识别html标签 W3C标准 保留空格和换行的
        div.innerHTML = '<strong>今天是:</strong> 2019';
        // 这两个属性是可读写的  可以获取元素里面的内容
        var p = document.querySelector('p');
        console.log(p.innerText);
        console.log(p.innerHTML);
    </script>
</body>
    <style>
        div,
        p {
            width: 300px;
            height: 30px;
            line-height: 30px;
            color: #fff;
            background-color: greenyellow;
        }
    </style>
</head>

<body>
    <button>显示当前系统时间</button>
    <div>某个时间</div>
    <p>1123</p>
    <script>
        //当我们点击了按钮,div里的文字会发生变化
    //    1、获取元素
        var btn = document.querySelector('button')
        var div = document.querySelector('div')
    //    2、注册事件
        btn.onclick = function (){
            // div.innerText = '2022-11-5'
            div.innerText = getDate()
        }

        function getDate(){
            var date = new Date();
            //  写2022年11月3日
            var year = date.getFullYear();
            var month = date.getMonth()+1;
            var dates = date.getDate();
            var arr = ['星期日','星期一','星期二','星期三','星期四','星期五','星期六']
            var day = date.getDay();
            return '今天是:' + year + '年' + month + '月' + dates + '日\t' + arr[day]
        }
    //    我们元素可以不用添加事件
        var p = document.querySelector('p')
        p.innerText = getDate()
    </script>
</body>

(2)修改元素属性

  <style>
    img {
      width: 300px;
    }
  </style>
</head>

<body>
<button id="ldh">刘德华</button>
<button id="zxy">张学友</button> <br>
<img src="images/ldh.jpg" alt="" title="刘德华">

<script>
  //修改元素属性
//  1、获取元素
  var ldh = document.getElementById('ldh')
  var zxy = document.getElementById('zxy')
  var img = document.querySelector('img')
//  2、注册事件
  zxy.onclick = function (){
    img.src = 'images/zxy.jpg'
    img.title = '张学友'
  }
  ldh.onclick = function (){
    img.src = 'images/ldh.jpg'
    img.title = '刘德华'
  }
</script>
</body>

(3)表单元素的属性操作

<body>
    <button>按钮</button>
    <input type="text" value="输入内容">
    <script>
        // 1. 获取元素
        var btn = document.querySelector('button');
        var input = document.querySelector('input');
        // 2. 注册事件 处理程序
        btn.onclick = function() {
            // input.innerHTML = '点击了';  这个是 普通盒子 比如 div 标签里面的内容
            // 表单里面的值 文字内容是通过 value 来修改的
            input.value = '被点击了';
            // 如果想要某个表单被禁用 不能再点击 disabled  我们想要这个按钮 button禁用
            // btn.disabled = true;  //可以实现按钮禁用
            // this 指向的是事件函数的调用者 btn
            this.disabled = true;
        }
    </script>
</body>

(4)样式属性操作

我们可以通过S修改元素的大小、颜色、位置等样式。

Js修改style样式操作,产生的是行内样式,css权重比较高

1)使用element.style 获得修改样式
<style>
        div {
            width: 200px;
            height: 200px;
            background-color: pink;
        }
    </style>
</head>
<body>
    <div></div>
    <script>
        // 1. 获取元素
        var div = document.querySelector('div');
        // 2. 注册事件 处理程序
        div.onclick = function() {
            // div.style里面的属性 采取驼峰命名法 
            //Js修改style样式操作,产生的是行内样式,css权重比较高
            this.style.backgroundColor = 'purple';
            this.style.width = '250px';
        }
    </script>
</body>
2)通过className修改元素样式
 <style>
    div{
      width: 200px;
      height: 200px;
      background-color: hotpink;
    }
    .change{
      background-color: green;
      font-size: 25px;
      color: #fff;
      margin-top: 100px;
    }
  </style>
</head>
<body>
  <div class="before">文本</div>
  <script>
    //1、使用element.style 获得修改样式  如果样式比较少或者功能简单的情况下使用
    var test = document.querySelector('div')
    test.onclick = function (){
      /*this.style.backgroundColor = 'green'
      this.innerHTML = '改变了'
      this.style.color = '#fff'
      this.style.fontSize = '25px'*/
      //2、通过className修改元素样式 让当前元素的类名改为了 change
      //class因为是个保留字,因此使用className来操作元素类名属性
      // className会直接更改元素的类名,会覆盖原先的类名。
      //可以通过修改元素的className修改元素样式  适合样式较多或功能复杂的情况
      //如果想要保留原先的类名,可以 多类名:
      this.className = 'first change'
      // this.className = 'change'
    }
  </script>
</body>

(5)排他思想

首先先排除其他人,然后才设置自己的样式 这种排除其他人的思想我们成为排他思想

<body>
    <button>按钮1</button>
    <button>按钮2</button>
    <button>按钮3</button>
    <button>按钮4</button>
    <button>按钮5</button>
    <script>
        // 1. 获取所有按钮元素
        var btns = document.getElementsByTagName('button');
        // btns得到的是伪数组  里面的每一个元素 btns[i]
        for (var i = 0; i < btns.length; i++) {
            btns[i].onclick = function() {
                // (1) 我们先把所有的按钮背景颜色去掉  干掉所有人
                for (var i = 0; i < btns.length; i++) {
                    btns[i].style.backgroundColor = '';
                }
                // (2) 然后才让当前的元素背景颜色为pink 留下我自己
                this.style.backgroundColor = 'pink';

            }
        }
        //2. 首先先排除其他人,然后才设置自己的样式 这种排除其他人的思想我们成为排他思想
    </script>
</body>

(6)自定义属性的操作

1)获取属性值
<body>
  <div id="demo" index="1"></div>
  <script>
    var div = document.querySelector('div')
    //1、获取元素的属性值
  // (1)element.属性值
  //  获取内置属性值(元素本身自带的属性)
    console.log(div.id) //demo
  //  (2)element.getAttribute('属性')
  //  主要获得自定义的属性(标准)我们程序员自定义的属性 例如index
    console.log(div.getAttribute('id')) //demo
    console.log(div.getAttribute('index')) //1
  </script>
</body>
2)设置属性值
<body>
  <div id="demo" index="1" class="nav"></div>
  <script>
    var div = document.querySelector('div')

  //  2、设置元素属性值
  //  (1)element.属性 = ‘值’
    div.id = 'test'
    console.log(div.id) //test
    div.className = 'navs'
    console.log(div.className) //navs
  //  (2) element.setAttribute('属性','值')
    div.setAttribute('index','2')
    console.log(div.getAttribute('index')) //2
    console.log(div.index) //undefined
    //class比较特殊,这里写的就是class,不是className
    div.setAttribute('class','footer')
  </script>
</body>
3)移除属性
<script>
//  3、移除属性element.removeAttribute('属性')
  div.removeAttribute('index')
  console.log(div.getAttribute('index')) //null
</script>

(7)H5自定义属性

自定义属性目的∶是为了保存并使用数据。有些数据可以保存到页面中而不用保存到数据库中。

H5规定自定义属性data开头作为属性名并且赋值

<div getTime="13" data-index="2" data-list-name="andy"></div>
<script>
    var div = document.querySelector('div');
    // console.log(div.getTime);
    console.log(div.getAttribute('getTime'));
    div.setAttribute('data-time', 20);
    console.log(div.getAttribute('data-index'));
    console.log(div.getAttribute('data-list-name'));
    // h5新增的获取自定义属性的方法 它只能获取data-开头的 有兼容性问题 IE 11以上
    // dataset 是一个集合里面存放了所有以data开头的自定义属性
    console.log(div.dataset);
    console.log(div.dataset.index);
    console.log(div.dataset['index']);
    // 如果自定义属性里面有多个-链接的单词,我们获取的时候采取 驼峰命名法
    console.log(div.dataset.listName);
    console.log(div.dataset['listName']);
</script>

5、节点操作

利用层级关系获取元素更加方便

网页中的所有内容都是节点(标签、属性、文本、注释等),在DOM中,节点使用node来表示。
HTML DOM树中的所有节点均可通过JavaScript进行访问,所有HTML元素(节点)均可被修改,也可以创建或删除。

一般地,节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。

元素节点nodeType 为1 (主要操作元素节点)

属性节点nodeType为2

文本节点nodeType 为3(文本节点包含文字、空格、换行等)

(1)节点层级

利用DOM树可以把节点划分为不同的层级关系,常见的是父子兄层级关系。

1)父节点 parentNode
<script>
    // 1. 父节点 parentNode
    var erweima = document.querySelector('.erweima');
    // var box = document.querySelector('.box');
    // 得到的是离元素最近的父级节点(亲爸爸) 如果找不到父节点就返回为 null
    console.log(erweima.parentNode);
</script>

2)子节点 childNodes
  <script>
        // DOM 提供的方法(API)获取
        var ul = document.querySelector('ul');
        var lis = ul.querySelectorAll('li');
        // 1. 子节点  childNodes 所有的子节点 包含 元素节点 文本节点等等
        console.log(ul.childNodes);
        //nodeType  元素1 属性2 文本3
        console.log(ul.childNodes[0].nodeType); //3 文本节点
        console.log(ul.childNodes[1].nodeType); //1 元素节点
        // 2. children 获取所有的子元素节点 也是我们实际开发常用的
        console.log(ul.children);
    </script>

子元素第一个节点和最后一个节点

<script>
    var ol = document.querySelector('ol');
    // 1. firstChild 第一个子节点 不管是文本节点还是元素节点
    console.log(ol.firstChild);
    console.log(ol.lastChild);
    // 2. firstElementChild 返回第一个子元素节点 ie9才支持
    console.log(ol.firstElementChild);
    console.log(ol.lastElementChild);
    // 3. 实际开发的写法  既没有兼容性问题又返回第一个子元素
    console.log(ol.children[0]);
    console.log(ol.children[ol.children.length - 1]);
</script>

3)兄弟、姐妹节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4vCjG9h7-1669643074818)(1667737182828.png)]

<p>我是p</p>
<div>我是div</div>
<span>我是span</span>
<script>
    var div = document.querySelector('div');
    // 1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等
    console.log(div.nextSibling);
    //   previousSibling 上一个兄弟节点
    console.log(div.previousSibling);
    // 2. nextElementSibling 得到下一个兄弟元素节点 有兼容性问题,ie9以上支持
    console.log(div.nextElementSibling);
    //   previousElementSibling 上一个兄弟元素节点
    console.log(div.previousElementSibling); //如果没有上一个兄弟,则返回null
</script>

(2)创建节点

document.createElement()方法创建由tagName指定的HTML元素。因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建元素节点。

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

高级的做法:element.insertAdjacentHTML(position,text);

<ul>
    <li>123</li>
</ul>
<script>
    // 1. 创建节点元素节点
    //document.createElement()方法创建由tagName指定的HTML元素。
    // 因为这些元素原先不存在,是根据我们的需求动态生成的,所以我们也称为动态创建元素节点。
    var li = document.createElement('li');

    // 2. 添加节点 node.appendChild(child)  node 父级  child 是子级 后面追加元素  类似于数组中的push
    //node. appendchild()方法将一个节点添加到指定父节点的子节点列表末尾。类似于css里面的after伪元素。
    var ul = document.querySelector('ul');
    ul.appendChild(li); //在原来li的后面
    // 3. 添加节点 node.insertBefore(child, 指定元素);
    //node.insertBefore()方法将一个节点添加到父节点的指定子节点前面。类似于css里面的before伪元素。
    var lili = document.createElement('li');
    ul.insertBefore(lili, ul.children[0]);
    // 4. 我们想要页面添加一个新的元素 : 1. 创建元素 2. 添加元素
</script>

(3)删除节点

<button>删除</button>
<ul>
    <li>熊大</li>
    <li>熊二</li>
    <li>光头强</li>
</ul>
<script>
    // 1.获取元素
    var ul = document.querySelector('ul');
    var btn = document.querySelector('button');
    // 2. 删除元素  node.removeChild(child)
    // ul.removeChild(ul.children[0]);
    // 3. 点击按钮依次删除里面的孩子
    btn.onclick = function() {
        /*if (ul.children.length === 0) {
            this.disabled = true;
        } else {
            ul.removeChild(ul.children[0]);
            ul.children.length === 0 ? this.disabled = true : this.disabled = false
        }*/
        ul.removeChild(ul.children[0]);
        ul.children.length === 0 ? this.disabled = true : this.disabled = false
    }
</script>

(4)复制节点(克隆节点)

<ul>
    <li>1111</li>
    <li>2</li>
    <li>3</li>
</ul>
<script>
    var ul = document.querySelector('ul');
    // 1. node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容
    // 2. node.cloneNode(true); 括号为true 深拷贝 复制标签复制里面的内容
    var lili = ul.children[0].cloneNode(true);
    ul.appendChild(lili);
</script>

(5)三种动态创建元素区别

document.write是直接将内容写入页面的内容流,但是文档流执行完毕,则它会导致页面全部重绘
innerHTML是将内容写入某个 DOM节点,不会导致页面全部重绘
innerHTMI创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂

createElement()创建多个元素效率稍低一点点,但是结构更清晰

<button>点击</button>
<p>abc</p>
<div class="inner"></div>
<div class="create"></div>
<script>
    // window.onload = function() {
    //         document.write('<div>123</div>');

    //     }
    // 三种创建元素方式区别 
    // 1. document.write() 创建元素  如果页面文档流加载完毕,再调用这句话会导致页面重绘
    // var btn = document.querySelector('button');
    // btn.onclick = function() {
    //     document.write('<div>123</div>');
    // }

    // 2. innerHTML 创建元素 将内容写入某个 DOM节点,不会导致页面全部重绘
    var inner = document.querySelector('.inner');
    // for (var i = 0; i <= 100; i++) {
    //字符串拼接 创建元素 将内容写入某个 DOM节点,不会导致页面全部重绘 效率最低
    //     inner.innerHTML += '<a href="#">百度</a>'
    // }
    //innerHTML数组形式创建元素 效率更高
    var arr = [];
    for (var i = 0; i <= 100; i++) {
        arr.push('<a href="#">百度</a>');
    }
    inner.innerHTML = arr.join('');
    // 3. document.createElement() 创建多个元素效率稍低一点点,但是结构更清晰
    var create = document.querySelector('.create');
    for (var i = 0; i <= 100; i++) {
        var a = document.createElement('a');
        create.appendChild(a);
    }
</script>

6、事件高级

(1)注册事件(绑定事件)

给元素添加事件,称为注册事件或者绑定事件。

注册事件有两种方式:传统方式和方法监听注册方式

1)传统注册方式

利用on开头的事件onclick
特点:注册事件的唯一性
同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖前面注册的处理函数

2)方法监听注册方式

w3c标准推荐方式
addEventListener()它是一个方法
IE9之前的IE不支持此方法,可使用attachEvent()代替

特点:同一个元素同一个事件可以注册多个监听器

按注册顺序依次执行

eventTarget .addEventListener(type,listener[, usecapture])
eventTarget .addEventListener()方法将指定的监听器注册到eventTarget(目标对象)上,当该对象触发指定的事件时,就会执行事件处理函数。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-keM7DoSd-1669643074819)(1667812181424.png)]

<body>
    <button>传统注册事件</button>
    <button>方法监听注册事件</button>
    <button>ie9 attachEvent</button>
    <script>
        var btns = document.querySelectorAll('button');
        // 1. 传统方式注册事件
        btns[0].onclick = function() {
            alert('hi');
        }
        btns[0].onclick = function() {
                alert('hao a u');
            }
            // 2. 事件侦听注册事件 addEventListener
            //eventTarget .addEventListener(type,listener[, usecapture])
        /*type:事件类型字符串,比如click、mouseover ,注意这里不要带on
        listener:事件处理函数,事件发生时,会调用该监听函数
        useCapture : 可选参数,是一个布尔值,默认是false。学完DOM事件流后,我们再进一步学习*/
            // (1) 里面的事件类型是字符串 必定加引号 而且不带on
            // (2) 同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
        btns[1].addEventListener('click', function() {
            alert(22);
        })
        btns[1].addEventListener('click', function() {
                alert(33);
            })
            // 3. attachEvent ie9以前的版本支持
        btns[2].attachEvent('onclick', function() {
            alert(11);
        })
    </script>
</body>

(2)删除事件(解绑事件)

<div>1</div>
<div>2</div>
<div>3</div>
<script>
    var divs = document.querySelectorAll('div');
    divs[0].onclick = function() {
            alert(11);
            // 1. 传统方式删除事件
            divs[0].onclick = null;
        }
        // 2. removeEventListener 删除事件
    divs[1].addEventListener('click', fn) // 里面的fn 不需要调用加小括号

    function fn() {
        alert(22);
        divs[1].removeEventListener('click', fn);
    }
    // 3. detachEvent ie9以前才能用
    divs[2].attachEvent('onclick', fn1);

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

(3)DOM事件流

事件流描述的是从页面中接收事件的顺序。
事件发生时会在元素节点之间按照特定的顺序传播,这个传播过程即DOM事件流。

DOM事件流分为3个阶段:

1、捕获阶段 2、当前目标阶段3、冒泡阶段

事件冒泡:IE最早提出,事件开始时由最具体的元素接收,然后逐级向上传播到到DOM最顶层节点的过程。

事件捕获︰网景最早提出,由DOM最顶层节点开始,然后逐级向下传播到到最具体的元素接收的过程。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tJsa0ej6-1669643074820)(1667813103860.png)]

注意:

  1. Js代码中只能执行捕获或者冒泡其中的一个阶段。
  2. onclick和attachEvent只能得到冒泡阶段。
  3. addEventListener(type,listener[,usecapture])第三个参数如果是true,表示在事件捕获阶段调用事件处理程序;如果是 false(不写默认就是false ),表示在事件冒泡阶段调用事件处理程序。

4.实际开发中我们很少使用事件捕获,我们更关注事件冒泡
5.有些事件是没有冒泡的,比如onblur、onfocus、onmouseenter、onmouseleave

<div class="father">
    <div class="son">son盒子</div>
</div>
<script>
    // dom 事件流 三个阶段
    // 1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。
    // 2. onclick 和 attachEvent(ie) 只能得到冒泡阶段。
    // 3. 捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段  document -> html -> body -> father -> son
    /*var son = document.querySelector('.son')
    son.addEventListener('click',function (){
        alert('son')
    },true)
    var father = document.querySelector('.father')
    father.addEventListener('click',function (){
        alert('father')
    },true)*/
    // 4. 冒泡阶段 如果addEventListener 第三个参数是 false或者省略  那么则处于冒泡阶段  son -> father -> body -> html -> document
    var son = document.querySelector('.son')
    son.addEventListener('click',function (){
        alert('son')
    },false)
    var father = document.querySelector('.father')
    father.addEventListener('click',function (){
        alert('father')
    },false)
    document.addEventListener('click',function (){
        alert('document')
    })
</script>

(4)事件对象

<div>123</div>
<script>
    // 事件对象
    var div = document.querySelector('div');
    // 1. event 就是一个事件对象 写到我们侦听函数的 小括号里面 当形参来看
    // 2. 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
    div.onclick = function(e) {
            // console.log(e);
            // console.log(window.event);
            // e = e || window.event;
     // 3. 事件对象 是 我们事件的一系列相关数据的集合 跟事件相关的 比如鼠标点击里面就包含了鼠标的相关信息,
     // 鼠标坐标啊,如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键
            console.log(e);


        }
        /*div.addEventListener('click', function(e) {
                console.log(e);

        })*/

    // 4. 这个事件对象我们可以自己命名 比如 event 、 evt、 e
    // 5. 事件对象也有兼容性问题 ie678 通过 window.event 兼容性的写法  e = e || window.event;
</script>

事件对象的常见属性和方法
事件对象属性方法说明
e.target返回触发事件的对象 标准
e.srcElement返回触发事件的对象 非标准 ie678使用
e.type返回事件的类型 比如 click mouseover 不带on
e.cancelBubble该属性阻止冒泡 非标准 ie678使用
e.returnValue该属性阻止默认事件(默认行为) 非标准 ie678使用 比如不让链接跳转
e.preventDefault()该属性阻止默认事件(默认行为) 标准 比如不让链接跳转
e.stopPropagation()阻止冒泡 标准
contextmenu主要控制应该何时显示上下文菜单,主要用于程序员取消默认的上下文菜单
selectstart
1)e.target
<div>123</div>
<ul>
    <li>abc</li>
    <li>abc</li>
    <li>abc</li>
</ul>
<script>
    // 常见事件对象的属性和方法
    // 1. e.target 返回的是触发事件的对象(元素)  this 返回的是绑定事件的对象(元素)
    // 区别 : e.target 点击了那个元素,就返回那个元素 this 那个元素绑定了这个点击事件,那么就返回谁
    var div = document.querySelector('div');
    div.addEventListener('click', function(e) {
        console.log(e.target);
        console.log(this);

    })
    var ul = document.querySelector('ul');
    ul.addEventListener('click', function(e) {
            // 我们给ul 绑定了事件  那么this 就指向ul  
            console.log(this);
        // 2. 了解 跟 this 有个非常相似的属性 currentTarget  ie678不认识
            console.log(e.currentTarget);

            // e.target 指向我们点击的那个对象 谁触发了这个事件 我们点击的是li e.target 指向的就是li
            console.log(e.target);

        })
        // 了解兼容性
        // div.onclick = function(e) {
        //     e = e || window.event;
        //     var target = e.target || e.srcElement;
        //     console.log(target);
    // }
</script>

2)阻止默认行为
<div>123</div>
<a href="http://www.baidu.com">百度</a>
<form action="http://www.baidu.com">
    <input type="submit" value="提交" name="sub">
</form>
<script>
    // 常见事件对象的属性和方法
    // 1. 返回事件类型
    var div = document.querySelector('div');
    div.addEventListener('click', fn);
    div.addEventListener('mouseover', fn);
    div.addEventListener('mouseout', fn);

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

    }
    // 2. 阻止默认行为(事件) 让链接不跳转 或者让提交按钮不提交
    var a = document.querySelector('a');
    a.addEventListener('click', function(e) {
            e.preventDefault(); //  dom 标准写法
        })
        // 3. 传统的注册方式
    a.onclick = function(e) {
        // 普通浏览器 e.preventDefault();  方法
        // e.preventDefault();
        // 低版本浏览器 ie678  returnValue  属性
        // e.returnValue;
        // 我们可以利用return false 也能阻止默认行为 没有兼容性问题 特点: return 后面的代码不执行了, 而且只限于传统的注册方式
        return false;
        alert(11);
    }
</script>

3)阻止冒泡
<div class="father">
    <div class="son">son儿子</div>
</div>
<script>
    // 常见事件对象的属性和方法
    // 阻止冒泡  dom 推荐的标准 stopPropagation() 
    var son = document.querySelector('.son');
    son.addEventListener('click', function(e) {
        alert('son');
        e.stopPropagation(); // stop 停止  Propagation 传播
        e.cancelBubble = true; // 非标准 cancel 取消 bubble 泡泡
    }, false);

    var father = document.querySelector('.father');
    father.addEventListener('click', function() {
        alert('father');
    }, false);
    document.addEventListener('click', function() {
        alert('document');
    })
</script>

4)事件委托(代理、委派)

**原理:**不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。

**作用:**只操作了一次DOM,提高了程序的性能。

<ul>
    <li>知否知否,点我应有弹框在手1!</li>
    <li>知否知否,点我应有弹框在手2!</li>
    <li>知否知否,点我应有弹框在手3!</li>
    <li>知否知否,点我应有弹框在手4!</li>
    <li>知否知否,点我应有弹框在手5!</li>
</ul>
<script>
    // 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
    var ul = document.querySelector('ul');
    ul.addEventListener('click', function(e) {
        // alert('知否知否,点我应有弹框在手!');
        // for (var i = 0;i<ul.children.length-1;i++){
        //     ul.backgroundColor = ''
        // }
        // e.target 这个可以得到我们点击的对象
        e.target.style.backgroundColor = 'pink';
        // console.log(e.target.innerText)
        // console.log(e.target)
        // console.log(ul.children.length)
    })
</script>

5)常见鼠标事件
我是一段不愿意分享的文字
<script>
    // 1. contextmenu 我们可以禁用右键菜单
    document.addEventListener('contextmenu', function(e) {
            e.preventDefault();
        })
        // 2. 禁止选中文字 selectstart
    document.addEventListener('selectstart', function(e) {
        e.preventDefault();

    })
</script>

6)鼠标事件对象

event对象代表事件的状态,跟事件相关的一系列信息的集合。现阶段我们主要是用鼠标事件对象MouseEvent和键盘事件对象KeyboardEvent.

<script>
    // 鼠标事件对象 MouseEvent
    document.addEventListener('click', function(e) {
        // 1. client 鼠标在可视区的x和y坐标
        console.log(e.clientX);
        console.log(e.clientY);
        console.log('---------------------');

        // 2. page 鼠标在页面文档的x和y坐标
        console.log(e.pageX);
        console.log(e.pageY);
        console.log('---------------------');

        // 3. screen 鼠标在电脑屏幕的x和y坐标
        console.log(e.screenX);
        console.log(e.screenY);

    })
</script>

7)常用的键盘事件
键盘事件触发条件
onkeyup某个键盘按键被松开时触发
onkeydown某个键盘按键被按下时触发
onkeypress某个键盘按键被按下时触发 但是它不识别功能键比如ctrl shift箭头等
<script>
    //常用键盘事件
//    1、keyup  某个键盘按键被松开时触发
    /*document.onkeyup = function (){
        console.log('我弹起了')
    }*/
    document.addEventListener('keyup',function (){
        console.log('我弹起了')
    })

//    3、keypress  某个键盘按键被按下时触发   但是它不识别功能键比如ctrl shift箭头等
    document.addEventListener('keypress',function (){
        console.log('我按下了press')
    })
    //    2、keydown  某个键盘按键被按下时触发
    document.addEventListener('keydown',function (){
        console.log('我按下了down')
    })
//    三个事件的执行顺序:keydown、keypress、keyup
</script>

8)键盘事件对象
<script>
    //键盘事件对象中的keycode属性可以得到相应键的ASCII码
    document.addEventListener('keyup',function (e){
        // console.log(e)
        console.log(e.keyCode)
    //    keyup 和 keydown 事件不区分大小写 a和A得到的都是65
    //    可以通过keycode的返回值判断用户按下了哪个键
        if (e.keyCode === 65){
            alert('你按下了a键')
        }else{
            alert('你没有按下a')
        }
    })
    //    keypress 事件区分大小写
    document.addEventListener('keypress',function (e){
        // console.log(e)
        console.log('press:' + e.keyCode)
    })
</script>

案例

<body>
<div class="search">
  <div class="con">123</div>
  <input type="text" placeholder="请输入您的快递单号" class="jd">
</div>
<script>
  //快递单号输入内容时,上面的大号字体盒子( con )显际(这里面的字号更大)
  // ②表单检测用户输入:给表单添加键盘事件
  // ③同时把快递单号里面的值( value )获取过来赋值给con盒子( innerText )做为内容
  // 如果快递单号里面内容为空,则隐藏大号字体盒子(con)盒子
  var con = document.querySelector('.con')
  var jd_input = document.querySelector('.jd')
  //注意:keydown和keypress在文本框里面的特点∶他们两个事件触发的时候,文字还没有落入文本框中。
  // keyup事件触发的时候,文字已经落入文本框里面了
  jd_input.addEventListener('keyup',function (){
    // console.log('输入了')
    if (this.value === ''){
      con.style.display = 'none'
    }else{
      con.innerText = this.value;
      con.style.display = 'block'
    }
  })
  //失去焦点时,隐藏盒子
  jd_input.addEventListener('blur',function (){
    con.style.display = 'none'
  })
  //获得焦点时,显现盒子
  jd_input.addEventListener('focus',function (){
    if (this.value !== ''){
      con.style.display = 'block'
    }
  })
</script>

BOM(浏览器对象模型)

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

BOM缺乏标准,JavaScript语法的标准化组织是ECMA,DOM的标准化组织是W3C,BOM最初是Netscape浏览器标准的一部分。

BOM比DOM更大,它包含DOM

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7U32BoeG-1669643074821)(1667963020442.png)]

window对象是浏览器的顶级对象,它具有双重角色。

1.它是S访问浏览器窗口的一个接口。
2.它是一个全局对象。定义在全局作用域中的变量、函数都会变成window对象的属性和方法。

在调用的时候可以省略window,前面学习的对话框都属于window对象方法,如alert()、prompt()等。

1、常见事件

(1)onload

  <script>
    //window.onload是窗口(页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS文件等),就调用的处理函数。
   /* window.onload = function (){
      var btn = document.querySelector('button')
      btn.addEventListener('click',function (){
        alert('点击我')
      })
    }
    //1.有了window.onload就可以把JS代码写到页面元素的上方,因为onload是等页面内容全部加载完毕,再去执行处理函数。
    // 2. window.onload传统注册事件方式只能写一次,如果有多个,会以最后一个window.onload为准。
    window.onload = function (){
      alert('第二个')
    }*/
    //3.如果使用addEventListener则没有限制
    window.addEventListener('load',function (){
      var btn = document.querySelector('button')
      btn.addEventListener('click',function (){
        alert('点击我')
      })
    })
    window.addEventListener('load',function (){
        alert('22')
    })

    document.addEventListener('DOMContentLoaded',function (){
      alert('33')
    })
    // load 等页面内容全部加载完毕,包含页面dom元素 图片 flash  css 等等
    // DOMContentLoaded 是DOM 加载完毕,不包含图片 falsh css 等就可以执行 加载速度比 load更快一些
  </script>
</head>
<body>
<button>点击</button>

</body>

(2)调整窗口事件resize

<script>
  window.addEventListener('load', function() {
    var div = document.querySelector('div');
    //window . onresize是调整窗口大小加载事件,当触发时就调用的处理函数。
    window.addEventListener('resize', function() {
      console.log(window.innerWidth);
      //1.只要窗口大小发生像素变化,就会触发这个事件。
    // ⒉我们经常利用这个事件完成响应式布局。window.innerWidth当前屏幕的宽度
      console.log('变化了');
      if (window.innerWidth <= 800) {
        div.style.display = 'none';
      } else {
        div.style.display = 'block';
      }

    })
  })
</script>
<div></div>
</body>

2、定时器

(1)定时器使用

<script>
    // 1. setTimeout 
    // 语法规范:  window.setTimeout(调用函数, 延时时间);  到了延时时间后就调用函数
    // 1. 这个window在调用的时候可以省略
    // 2. 这个延时时间单位是毫秒 但是可以省略,如果省略默认的是0
    // 3. 这个调用函数可以直接写函数 还可以写 函数名 还有一个写法 '函数名()'
    // 4. 页面中可能有很多的定时器,我们经常给定时器加标识符 (名字)
    // setTimeout(function() {
    //     console.log('时间到了');

    // }, 2000);
    function callback() {
        console.log('爆炸了');
    }
    var timer1 = setTimeout(callback, 3000);
    var timer2 = setTimeout(callback, 5000);
    // setTimeout('callback()', 3000); // 我们不倡这个写法
</script>

(2)回调函数

setTimeout(这个调用函数我们也称为回调函数callback

普通函数是按照代码顺序直接调用。
而这个函数,需要等待时间,时间到了才去调用这个函数,因此称为回调函数。

(3)停止定时器

<button>点击停止定时器</button>
<script>
  var btn = document.querySelector('button')
  var timer = setTimeout(function (){
    console.log('爆炸了')
  },5000)
  btn.addEventListener('click',function (){
    //clearTimeout()方法取消了先前通过调用setTimeout ()建立的定时器。
    //里面的参数是定时器的标识符
    clearTimeout(timer)
  })
</script>

(4)定时器setInterval()

setInterval()方法重复调用一个函数,每隔这个时间,就去调用一次回调函数。

<script>
    // 1. setInterval
    //setInterval()方法重复调用一个函数,每隔这个时间,就去调用一次回调函数。
    // 语法规范:  window.setInterval(调用函数, 间隔的时间);
    setInterval(function() {
        console.log('继续输出');
    }, 1000);
    // 2. setTimeout  延时时间到了,就去调用这个回调函数,只调用一次 就结束了这个定时器
    // 3. setInterval  每隔这个间隔时间,就去调用这个回调函数,会调用很多次,重复调用这个函数
</script>

倒计时案例

<div>
  <span class="hour">1</span>
  <span class="minute">2</span>
  <span class="second">3</span>
</div>
<script>
  //这个倒计时是不断变化的,因此需要定时器来自动变化( setInterval )
  // 三个黑色盒子里面分别存放时分秒
  // 三个黑色盒子利用innerHTML放入计算的小时分钟秒数
  // 第一次执行也是间隔毫秒数,因此刚刷新页面会有空白
  // 最好采取封装函数的方式,这样可以先调用一次这个函数,防止刚开始刷新页面有空白问题
  var hour = document.querySelector('.hour')
  var minute = document.querySelector('.minute')
  var second = document.querySelector('.second')
  //括号里是需要计算倒计时的未来时间
  var inputTime = +new Date('2022-11-9 20:00:00')// 返回的是用户输入时间总的毫秒数
  countDown(); // 我们先调用一次这个函数,防止第一次刷新页面有空白

  // 2. 开启定时器
  setInterval(countDown, 1000);

  function countDown() {
    var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
    var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒数
    var h = parseInt(times / 60 / 60 % 24); //时
    h = h < 10 ? '0' + h : h;
    hour.innerHTML = h; // 把剩余的小时给 小时黑色盒子
    var m = parseInt(times / 60 % 60); // 分
    m = m < 10 ? '0' + m : m;
    minute.innerHTML = m;
    var s = parseInt(times % 60); // 当前的秒
    s = s < 10 ? '0' + s : s;
    second.innerHTML = s;
  }
</script>

(5)停止定时器setInterval()

<button class="begin">开启定时器</button>
<button class="stop">停止定时器</button>
<script>
    var begin = document.querySelector('.begin');
    var stop = document.querySelector('.stop');
    var timer = null; // 全局变量  null是一个空对象
    begin.addEventListener('click', function() {
        timer = setInterval(function() {
            console.log('ni hao ma');
        }, 1000);
    })
    stop.addEventListener('click', function() {
        clearInterval(timer);
    })
</script>

3、this指向问题

this 指向问题 一般情况下this的最终指向的是那个调用它的对象

<button>点击</button>
<script>
    // this 指向问题 一般情况下this的最终指向的是那个调用它的对象

    // 1. 全局作用域或者普通函数中this指向全局对象window( 注意定时器里面的this指向window)
    console.log(this);

    function fn() {
        console.log(this);

    }
    window.fn();
    window.setTimeout(function() {
        console.log(this);

    }, 1000);
    // 2. 方法调用中谁调用this指向谁
    var o = {
        sayHi: function() {
            console.log(this); // this指向的是 o 这个对象

        }
    }
    o.sayHi();
    var btn = document.querySelector('button');
    // btn.onclick = function() {
    //     console.log(this); // this指向的是btn这个按钮对象

    // }
    btn.addEventListener('click', function() {
            console.log(this); // this指向的是btn这个按钮对象

        })
        // 3. 构造函数中this指向构造函数的实例
    function Fun() {
        console.log(this); // this 指向的是fun 实例对象

    }
    var fun = new Fun();
</script>

4、JS执行队列

Js是单线程

JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。这是因为Javascript这门脚本语言诞生的使命所致——JavaScript是为处理页面中用户的交互,以及操作DOM而诞生的。比如我们对某个DOM元素进行添加和删除操作,不能同时进行。应该先进行添加,之后再删除。

单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。这样所导致的问题是∶如果JS执行的时间过长,这样就会造成页面的渲染不连贯,导致页面渲染加载阻塞的感觉。

为了解决这个问题,利用多核CPU的计算能力,HTMLS提出 Web Worker标准,允许JavaScript脚本创建多个线程。于是,JS中出现了同步异步

执行机制

1、先执行执行栈中的同步任务。
2、异步任务(回调函数)放入任务队列中。
3、一旦执行栈中的所有同步任多务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进入执行栈,开始执行。

由于主线程不断的重复获得任务、执行任务、再获取任务、再执行,所以这种机制被称为事件循环( eventloop ) 。

<script>
    //同步--异步(按顺序)
    // 第一个问题
    //异步,同时进行多个任务  执行顺序:1、2、3
    /*console.log(1);
    setTimeout(function() {
        console.log(3);
    }, 1000);
    console.log(2);*/

    // 2. 第二个问题
    // 同步任务:都在主线程上执行,形成一个执行栈。
    // 异步任务:JS的异步是通过回调函数实现的。
    /*一般而言,异步任务有以下三种类型
    1、普通事件,如click、resize等
    2、资源加载,如load、error等
    3、定时器,包括setInterval、setTimeout等
    异步任务相关回调函数添加到任务队列中(任务队列也称为消息队列)。*/
    /*console.log(1);
    setTimeout(function() {
        console.log(3);
    }, 0);
    console.log(2);*/

    // 3. 第三个问题

    console.log(1);
    document.onclick = function() {
        console.log('click');
    }
    console.log(2);
    setTimeout(function() {
        console.log(3)
    }, 3000)
</script>

5、BOM对象

(1)location对象

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

URL

统一资源定位符(Uniform Resource Locator,URL)是互联网上标准资源的地址。互联网上的每个文件都有一个唯一的URL,它包含的信息指出文件的位置以及浏览器应该怎么处理它。

组成说明
protocal通信协议常用的http,ftp,maito等
host主机(域名)www.itheima.com
port端口号可选,省略时使用方案的默认端口如http的默认端口为80
path路径由零或多个/符号隔开的字符串,一般用来表示主机上的一个目录或文件地址
query参数以键值对的形式,通过&符号分隔开来
fragment片段#后面内容常见于链接锚点
location对象属性
location对象属性返回值
location.href获取或者设置整个URL
location.host返回主机(域名)
location.port返回端口号 如果未写 返回 空字符串
location.pathname返回路径
location.search返回参数
location.hash返回片段 #后面内容 常见于链接 锚点
<button>点击</button>
<div></div>
<script>
    var btn = document.querySelector('button');
    var div = document.querySelector('div');
    btn.addEventListener('click', function() {
        // console.log(location.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);
</script>

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

(2)navigator对象

navigator对象包含有关浏览器的信息,它有很多属性,我们最常用的是userAgent,该属性可以返回由客户机发送服务器的user-agent头部的值。
下面前端代码可以判断用户那个终端打开页面,实现跳转

<script>
    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 = "../H5/index.html"; //手机
    }
</script>

(3)history对象

window对象给我们提供了一个 history对象,与浏览器历史记录进行交互。该对象包含用户(在浏览器窗口中)访问过的URL。

history对象方法作用
back()可以后退
forward()前进功能
go(参数)前进后退功能参数如果是1前进1个页面 如果是-1后退1个页面
<a href="list.html">点击我去往列表页</a>
<button>前进</button>
<script>
    var btn = document.querySelector('button');
    btn.addEventListener('click', function() {
        // history.forward();
        history.go(1);
    })
</script>

PC端网页特效

1、元素偏移量offset

offset翻译过来就是偏移量,我们使用offset系列相关属性可以动态的得到该元素的位置(偏移)、大小等。
获得元素距离带有定位父元素的位置
获得元素自身的大小(宽度高度)
注意:返回的数值都不带单位

offset系列属性作用
element.offsetParent返回作为该元素带有定位的父级元素如果父级都没有定位则返回body
element.offsetTop返回元素相对带有定位父元素上方的偏移
element.offsetLeft返回元素相对带有定位父元素左边框的偏移
element.offsetWidth返回自身包括padding、边框、内容区的宽度,返回数值不带单位
element.offsetHeight返回自身包括padding、边框、内容区的高度,返回数值不带单位
<div class="father">
    <div class="son"></div>
</div>
<div class="w"></div>
<script>
    // offset 系列
    var father = document.querySelector('.father');
    var son = document.querySelector('.son');
    // 1.可以得到元素的偏移 位置 返回的不带单位的数值  
    console.log(father.offsetTop);
    console.log(father.offsetLeft);
    // 它以带有定位的父亲为准  如果没有父亲或者父亲没有定位 则以 body 为准
    console.log(son.offsetLeft);
    var w = document.querySelector('.w');
    // 2.可以得到元素的大小 宽度和高度 是包含padding + border + width 
    console.log(w.offsetWidth);
    console.log(w.offsetHeight);
    // 3. 返回带有定位的父亲 否则返回的是body
    console.log(son.offsetParent); // 返回带有定位的父亲 否则返回的是body
    console.log(son.parentNode); // 返回父亲 是最近一级的父亲 亲爸爸 不管父亲有没有定位
</script>

offset与style的区别

<div class="box" style="width: 200px;"></div>
<script>
    // offset与style的区别
    /*offset:
    * offset可以得到任意样式表中的样式值;offset系列获得的数值是没有单位的
    offsetWidth包含padding+border+width;offsetWidth等属性是只读属性,只能获取不能赋值所以。
    * 我们想要获取元素大小位置,用offset更合适*/
    /*style:
    * style只能得到行内样式表中的样式值;style.width获得的是带有单位的字符串;
    * style.width获得不包含padding和border的值;style.width是可读写属性,可以获取也可以赋值。
    * 所以,我们想要给元素更改值,则需要用style改变*/
    var box = document.querySelector('.box');
    console.log(box.offsetWidth);
    console.log(box.style.width);
    // box.offsetWidth = '300px';
    box.style.width = '300px';
</script>

拖动的模态框案例

 <div class="login-header"><a id="link" href="javascript:;">点击,弹出登录框</a></div>
    <div id="login" class="login">
        <div id="title" class="login-title">登录会员
            <span><a id="closeBtn" href="javascript:void(0);" class="close-login">关闭</a></span>
        </div>
        <div class="login-input-content">
            <div class="login-input">
                <label>用户名:</label>
                <input type="text" placeholder="请输入用户名" name="info[username]" id="username" class="list-input">
            </div>
            <div class="login-input">
                <label>登录密码:</label>
                <input type="password" placeholder="请输入登录密码" name="info[password]" id="password" class="list-input">
            </div>
        </div>
        <div id="loginBtn" class="login-button"><a href="javascript:void(0);" id="login-button-submit">登录会员</a></div>
    </div>
    <!-- 遮盖层 -->
    <div id="bg" class="login-bg"></div>
    <script>
        // 1. 获取元素
        var login = document.querySelector('.login');
        var mask = document.querySelector('.login-bg');
        var link = document.querySelector('#link');
        var closeBtn = document.querySelector('#closeBtn');
        var title = document.querySelector('#title');
        // 2. 点击弹出层这个链接 link  让mask 和login 显示出来
        link.addEventListener('click', function() {
                mask.style.display = 'block';
                login.style.display = 'block';
            })
            // 3. 点击 closeBtn 就隐藏 mask 和 login 
        closeBtn.addEventListener('click', function() {
                mask.style.display = 'none';
                login.style.display = 'none';
            })

            // 4. 开始拖拽
            //移动事件和弹起事件都在鼠标按下事件内部写
            // (1) 当我们鼠标按下, 就获得鼠标在盒子内的坐标
        title.addEventListener('mousedown', function(e) {
            // 鼠标按下,我们要得到鼠标在盒子的坐标。
//            鼠标在盒子内的坐标是固定的
// 鼠标移动,就让模态框的坐标设置为︰鼠标坐标减去盒子坐标即可,注意移动事件写到按下事件里面。
            var x = e.pageX - login.offsetLeft;
            var y = e.pageY - login.offsetTop;
            // (2) 鼠标移动的时候,把鼠标在页面中的坐标,减去 鼠标在盒子内的坐标就是模态框的left和top值
            document.addEventListener('mousemove', move)

            function move(e) {
                login.style.left = e.pageX - x + 'px';
                login.style.top = e.pageY - y + 'px';
            }
            // (3) 鼠标弹起,就让鼠标移动事件移除
            document.addEventListener('mouseup', function() {
                document.removeEventListener('mousemove', move);
            })
        })
    </script>

2、元素可视区client系列

client翻译过来就是客户端,我们使用client系列的相关属性来获取元素可视区的相关信息。通过client系列的相关属性可以动态的得到该元素的边框大小、元素大小等。

client系列属性作用
element.clientTop返回元素上边框的大小
element.clientLeft返回元素左边框的大小
element.clientWidth返回自身包括padding 、内容区的宽度,不含边框,返回数值不带单位
element.clientHeight返回自身包括padding、内容区的高度,不含边框,返回数值不带单位
<div></div>
<script>
    // client 宽度 和我们offsetWidth 最大的区别就是 不包含边框
    var div = document.querySelector('div');
    console.log(div.clientWidth);
</script>

立即执行函数

立即执行函数:不需要调用,立马就能自己执行的函数

1.(function() {})() 或者 2. (function(){}());

主要作用:创建一个独立的作用域,避免了命名冲突

<script>
    // 1.立即执行函数: 不需要调用,立马能够自己执行的函数
    function fn() {
        console.log(1);
    }
    fn();
    // 2. 写法 也可以传递参数进来
    // 1.(function() {})()    或者  2. (function(){}());
    (function(a, b) {
        console.log(a + b);
        var num = 10;
    })(1, 2); // 第二个小括号可以看做是调用函数
    (function sum(a, b) {
        console.log(a + b);
        var num = 10; // 局部变量
    }(2, 3));
    // 3. 立即执行函数最大的作用就是 独立创建了一个作用域, 里面所有的变量都是局部变量 不会有命名冲突的情况
</script>

3、元素滚动scroll系列

scroll翻译过来就是滚动的,我们使用scroll系列的相关属性可以动态的得到该元素的大小、滚动距离等。

获取页面被卷去的头部:window.pageYOffset

scroll系列属性作用
element.scrollTop返回被卷去的上侧距离,返回数值不带单位
element.scrollLeft返回被卷去的左侧距离,返回数值不带单位
element.scrollWidth返回自身实际的宽度,不含边框,返回数值不带单位
element.scrollHeight返回自身实际的高度, 不含边框,返回数值不带单位
<div>
    我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容 我是内容
</div>
<script>
    // scroll 系列
    var div = document.querySelector('div');
    console.log(div.scrollHeight);
    console.log(div.clientHeight);
    // scroll滚动事件当我们滚动条发生变化会触发的事件
    div.addEventListener('scroll', function() {
        //拖动滚动条时 内容溢出盒子的高度
        console.log(div.scrollTop);

    })
</script>

仿淘宝固定侧边栏案例

<div class="slider-bar">
    <span class="goBack">返回顶部</span>
</div>
<div class="header w">头部区域</div>
<div class="banner w">banner区域</div>
<div class="main w">主体部分</div>
<script>
    //1. 获取元素
    var sliderbar = document.querySelector('.slider-bar');
    var banner = document.querySelector('.banner');
    // banner.offestTop 就是被卷去头部的大小 一定要写到滚动的外面
    var bannerTop = banner.offsetTop
    // 当我们侧边栏固定定位之后应该变化的数值
    var sliderbarTop = sliderbar.offsetTop - bannerTop;
    // 获取main 主体元素
    var main = document.querySelector('.main');
    var goBack = document.querySelector('.goBack');
    var mainTop = main.offsetTop;
    // 2. 页面滚动事件 scroll
    document.addEventListener('scroll', function() {
        // console.log(11);
        // window.pageYOffset 页面被卷去的头部
        // console.log(window.pageYOffset);
        // 3 .当我们页面被卷去的头部大于等于了 172 此时 侧边栏就要改为固定定位
        if (window.pageYOffset >= bannerTop) {
            sliderbar.style.position = 'fixed';
            sliderbar.style.top = sliderbarTop + 'px';
        } else {
            sliderbar.style.position = 'absolute';
            sliderbar.style.top = '300px';
        }
        // 4. 当我们页面滚动到main盒子,就显示 goback模块
        if (window.pageYOffset >= mainTop) {
            goBack.style.display = 'block';
        } else {
            goBack.style.display = 'none';
        }
    })
</script>

4、mouseover和mouseenter

当鼠标移动到元素上时就会触发mouseenter事件类似 mouseover,

它们两者之间的差别是
mouseover鼠标经过自身盒子会触发,经过子盒子还会触发。mouseenter 只会经过自身盒子触发

之所以这样,是因为mouseenter不会冒泡

跟mouseenter搭配鼠标离开mouseleave同样不会冒泡

动画

1、动画实现原理

核心原理∶通过定时器setInterval()不断移动盒子位置。
实现步骤∶
1、获得盒子当前位置
2、让盒子在当前位置加上1个移动距离

3、利用定时器不断重复这个操作

4、加一个结束定时器的条件
5、注意此元素需要添加定位,才能使用element.style.left

<style>
        div {
        /*5. 注意此元素需要添加定位, 才能使用element.style.left*/
            position: absolute;
            left: 0;
            width: 100px;
            height: 100px;
            background-color: pink;
        }
    </style>
</head>

<body>
    <div></div>
    <script>
        // 动画原理
        // 1. 获得盒子当前位置  offsetLeft只能获取 不能赋值
        // 3. 利用定时器不断重复这个操作
        // 4. 加一个结束定时器的条件
        var div = document.querySelector('div')
        var timer = setInterval(function (){
            if (div.offsetLeft >= 400){
                // 停止动画 本质是停止定时器
                clearInterval(timer)
            }
            // 2. 让盒子在当前位置加上1个移动距离
            div.style.left = div.offsetLeft + 1 + 'px'
        },30)
    </script>

2、动画函数封装

函数需要传递两个参数,动画对象移动到的距离

<style>
        div {
            position: absolute;
            left: 0;
            width: 100px;
            height: 100px;
            background-color: pink;
        }
        
        span {
            /*动画里面必须加定位*/
            position: absolute;
            left: 0;
            top: 200px;
            display: block;
            width: 150px;
            height: 150px;
            background-color: purple;
        }
    </style>
</head>

<body>
    <div></div>
    <span>夏雨荷</span>
    <script>
        // 简单动画函数封装obj目标对象(给谁做对象)  target 目标位置(什么时候停止动画)
        function animate(obj, target) {
            var timer = setInterval(function() {
                if (obj.offsetLeft >= target) {
                    // 停止动画 本质是停止定时器
                    clearInterval(timer);
                }
                obj.style.left = obj.offsetLeft + 1 + 'px';

            }, 10);
        }
        var div = document.querySelector('div');
        var span = document.querySelector('span');
        // 调用函数
        animate(div, 300);
        animate(span, 200);
    </script>

3、给不同对象添加不同定时器(obj.timer)

如果多个元素都使用这个动画函数,每次都要var声明定时器。我们可以给不同的元素使用不同的定时器(自己专门用自己的定时器)。
核心原理:利用JS是一门动态语言,可以很方便的给当前对象添加属性。

<button>点击夏雨荷才走</button>
<div></div>
<span>夏雨荷</span>
<script>
    // var obj = {};
    // obj.name = 'andy';
    // 简单动画函数封装obj目标对象 target 目标位置
    function animate(obj, target) {
        // 当我们不断的点击按钮,这个元素的速度会越来越快,因为开启了太多的定时器
        // 解决方案就是 让我们元素只有一个定时器执行
        // 先清除以前的定时器,只保留当前的一个定时器执行
        clearInterval(obj.timer);
        // 给不同的元素指定了不同的定时器  obj.timer
        obj.timer = setInterval(function() {
            if (obj.offsetLeft >= target) {
                // 停止动画 本质是停止定时器
                clearInterval(obj.timer);
            }
            obj.style.left = obj.offsetLeft + 1 + 'px';
        }, 10);
    }

    var div = document.querySelector('div');
    var span = document.querySelector('span');
    var btn = document.querySelector('button');
    // 调用函数
    animate(div, 300);
    btn.addEventListener('click', function() {
        animate(span, 200);
    })
</script>

4、缓动动画

缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来

思路:
1、让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。
2、核心算法:

( 目标值-现在的位置 ) / 10 做为每次移动的距离 步长

3、停止的条件是:当前盒子位置等于目标位置就停止定时器

<button class="btn500">点击夏雨荷才走到500</button>
<button class="btn800">点击夏雨荷才走到800</button>
<div></div>
<span>夏雨荷</span>
<script>
    // 简单动画函数封装obj目标对象 target 目标位置
    //  思路:
    // 1、让盒子每次移动的距离慢慢变小,速度就会慢慢落下来。
    // 2、核心算法:( 目标值-现在的位置 ) / 10  做为每次移动的距离  步长
    function animate(obj, target) {
        // 先清除以前的定时器,只保留当前的一个定时器执行
        clearInterval(obj.timer);
        // 给不同的元素指定了不同的定时器  obj.timer
        obj.timer = setInterval(function() {
            //步长值写在定时器里面
            //4、把步长值改为整数,不要出现小数的问题  往大取整
            // var step = Math.ceil((target - obj.offsetLeft) / 10)
            var step = (target - obj.offsetLeft) / 10
            //当我们点击按钮时候,判断步长是正值还是负值
            // 1.如果是正值,则步长往大了取整
            // 2.如果是负值,则步长向小了取整
            step = step > 0 ? Math.ceil(step) : Math.floor(step)
            // 3、停止的条件是:当前盒子位置等于目标位置就停止定时器
            if (obj.offsetLeft === target) {
                // 停止动画 本质是停止定时器
                clearInterval(obj.timer);
            }
            //把每次加1的步长值 改为一个慢慢变小的值(步长公式( 目标值-现在的位置 ) / 10 )
            obj.style.left = obj.offsetLeft + step + 'px';
        }, 30);
    }

    var div = document.querySelector('div');
    var span = document.querySelector('span');
    var btn500 = document.querySelector('.btn500');
    var btn800 = document.querySelector('.btn800');
    // 调用函数
    animate(div, 300);
    btn500.addEventListener('click', function() {
        animate(span, 500);
    })
    btn800.addEventListener('click', function() {
        animate(span, 800);
    })

    // 匀速动画 就是 盒子是当前的位置 +  固定的值 10
    // 缓动动画就是  盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)
</script>

5、动画函数添加回调函数

回调函数原理:函数可以作为一个参数。将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调

回调函数写在定时器结束的位置

<button class="btn500">点击夏雨荷到500</button>
<button class="btn800">点击夏雨荷到800</button>
<span>夏雨荷</span>
<script>
    // 缓动动画函数封装obj目标对象 target 目标位置
    // 思路:
    // 1. 让盒子每次移动的距离慢慢变小, 速度就会慢慢落下来。
    // 2. 核心算法:(目标值 - 现在的位置) / 10 做为每次移动的距离 步长
    // 3. 停止的条件是: 让当前盒子位置等于目标位置就停止定时器
    function animate(obj, target, callback) {
        // console.log(callback);  callback = function() {}  调用的时候 callback()

        // 先清除以前的定时器,只保留当前的一个定时器执行
        clearInterval(obj.timer);
        obj.timer = setInterval(function() {
            // 步长值写到定时器的里面
            // 把我们步长值改为整数 不要出现小数的问题
            // var step = Math.ceil((target - obj.offsetLeft) / 10);
            var step = (target - obj.offsetLeft) / 10;
            step = step > 0 ? Math.ceil(step) : Math.floor(step);
            if (obj.offsetLeft === target) {
                // 停止动画 本质是停止定时器
                clearInterval(obj.timer);
                // 回调函数写到定时器结束里面
                if (callback) {
                    // 调用函数
                    callback();
                }
            }
            // 把每次加1 这个步长值改为一个慢慢变小的值  步长公式:(目标值 - 现在的位置) / 10
            obj.style.left = obj.offsetLeft + step + 'px';

        }, 15);
    }
    var span = document.querySelector('span');
    var btn500 = document.querySelector('.btn500');
    var btn800 = document.querySelector('.btn800');

    btn500.addEventListener('click', function() {
        // 调用函数
        animate(span, 500);
    })
    btn800.addEventListener('click', function() {
            // 调用函数
            animate(span, 800, function() {
                // alert('你好吗');
                span.style.backgroundColor = 'red';
            });
        })
        // 匀速动画 就是 盒子是当前的位置 +  固定的值 10 
        // 缓动动画就是  盒子当前的位置 + 变化的值(目标值 - 现在的位置) / 10)
</script>

6、轮播图 制作过程

大盒子 包含 左右两个箭头 ul li a 放图片

给li设置浮动,让图片浮动起来,此时图片还是竖排列,需要把大盒子 ul的宽度设置大点,可以让图片在一行显示

轮播图也称为焦点图,是网页中比较常见的网页特效。功能需求︰
1、鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。
2、点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理。

3、图片播放的同时,下面小圆圈模块跟随一起变化。
4、点击小圆圈,可以播放相应图片。
5、鼠标不经过轮播图,轮播图也会自动播放图片。

6、鼠标经过,轮播图模块,自动停止播放

7、节流阀

防止轮播图按钮连续点击造成播放过快。
节流阀目的:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。

核心实现思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。

开始设置一个变量var flag = true;

lf(flag) {flag = false; do something}
关闭水龙头

利用回调函数动画执行完毕,flag = true打开水龙头

移动端特效

1、触屏事件

移动端浏览器兼容性较好,我们不需要考虑以前S的兼容性问题,可以放心的使用原生JS书写效果,但是移动端也有自己独特的地方。比如触屏事件touch (也称触摸事件),Android和IOS都有。

touch对象代表一个触摸点。触摸点可能是一根手指,也可能是一根触摸笔。触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。

触屏touch事件说明
touchstart手指触摸到一个DOM元素时触发
touchmove手指在一个DOM元素上滑动时触发
touchend手指从一个DOM元素上移开时触发
<div></div>
<script>
    // 1. 获取元素
    // 2. 手指触摸DOM元素事件
    var div = document.querySelector('div');
    div.addEventListener('touchstart', function() {
        console.log('我摸了你');

    });
    // 3. 手指在DOM元素身上移动事件
    div.addEventListener('touchmove', function() {
        console.log('我继续摸');

    });
    // 4. 手指离开DOM元素事件
    div.addEventListener('touchend', function() {
        console.log('轻轻的我走了');

    });
</script>

2、触摸事件对象

TouchEvent是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等
touchstart、touchmove、touchend三个事件都会各自有事件对象。

触摸列表说明
touches正在触摸屏幕的所有手指的一个列表
targetTouches正在触摸当前DOM元素上的手指的一个列表
changedTouches手指状态发生了改变的列表,从无到有,从有到无变化
<div></div>
<script>
    // 触摸事件对象
    // 1. 获取元素
    // 2. 手指触摸DOM元素事件
    var div = document.querySelector('div');
    div.addEventListener('touchstart', function(e) {
        // console.log(e);
        // touches 正在触摸屏幕的所有手指的列表 
        // targetTouches 正在触摸当前DOM元素的手指列表
        // 如果侦听的是一个DOM元素,他们两个是一样的
        // changedTouches 手指状态发生了改变的列表 从无到有 或者 从有到无
        // 因为我们一般都是触摸元素 所以最经常使用的是 targetTouches
        console.log(e.targetTouches[0]);
        // targetTouches[0] 就可以得到正在触摸dom元素的第一个手指的相关信息比如 手指的坐标等等
    });
    // 3. 手指在DOM元素身上移动事件
    div.addEventListener('touchmove', function() {
    });
    // 4. 手指离开DOM元素事件
    div.addEventListener('touchend', function(e) {
        // console.log(e);
        // 当我们手指离开屏幕的时候,就没有了 touches 和 targetTouches 列表
        // 但是会有 changedTouches
    });
</script>

3、classList属性

<div class="one two"></div>
<button> 开关灯</button>
<script>
    // classList 返回元素的类名
    var div = document.querySelector('div');
    // console.log(div.classList[1]);
    // 1. 添加类名  是在后面追加类名不会覆盖以前的类名 注意前面不需要加.
    div.classList.add('three');
    // 2. 删除类名
    div.classList.remove('one');
    // 3. 切换类
    var btn = document.querySelector('button');
    btn.addEventListener('click', function() {
        //点一下加上这个类,再点一下去掉这个类
        // 也就是判断类名,如果有bg类名那就删除,没有就添加
        document.body.classList.toggle('bg');
    })
</script>

4、框架

框架,顾名思义就是一套架构,它会基于自身的特点向用户提供一套较为完整的解决方案。框架的控制权在框架本身,使用者要按照框架所规定的某种规范进行开发。
插件一般是为了解决某个问题而专门存在,其功能单一,并且比较小
前端常用的框架有Bootstrap、Vue、Angular、React等。既能开发PC端,也能开发移动端前端常用的移动端插件有swiper、superslide、iscroll等。

框架:大而全,一整套解决方案
插件:小而专一,个功能的解决方案

本地存储

随着互联网的快速发展,基于网页的应用越来越普遍,同时也变的越来越复杂,为了满足各种各样的需求,会经常性在本地存储大量的数据,HTML5规范提出了相关解决方案。

1、本地存储特性

1、数据存储在用户浏览器中
2、设置、读取方便、甚至页面刷新不丢失数据
3、容量较大,sessionStorage约5M、localStorage约20M

4、只能存储字符串,可以将对象JSON.stringify()编码后存储

2、window.sessionStorage

1、生命周期为关闭浏览器窗口

2、在同一个窗口(页面)下数据可以共享

3.以键值对的形式存储使用

<input type="text">
<button class="set">存储数据</button>
<button class="get">获取数据</button>
<button class="remove">删除数据</button>
<button class="del">清空所有数据</button>
<script>
    console.log(localStorage.getItem('username'));

    var ipt = document.querySelector('input');
    var set = document.querySelector('.set');
    var get = document.querySelector('.get');
    var remove = document.querySelector('.remove');
    var del = document.querySelector('.del');
    set.addEventListener('click', function() {
        // 当我们点击了之后,就可以把表单里面的值存储起来
        var val = ipt.value;
        sessionStorage.setItem('uname', val);
        sessionStorage.setItem('pwd', val);
    });
    get.addEventListener('click', function() {
        // 当我们点击了之后,就可以把表单里面的值获取过来
        console.log(sessionStorage.getItem('uname'));

    });
    remove.addEventListener('click', function() {
        // 
        sessionStorage.removeItem('uname');

    });
    del.addEventListener('click', function() {
        // 当我们点击了之后,清除所有的
        sessionStorage.clear();

    });
</script>

3、window.localStorage

1、生命周期永久生效,除非手动删除否则关闭页面也会存在

2、可以多窗口(页面)共享(同一浏览器可以共享)
3.以键值对的形式存储使用

h<script>
    var ipt = document.querySelector('input');
    var set = document.querySelector('.set');
    var get = document.querySelector('.get');
    var remove = document.querySelector('.remove');
    var del = document.querySelector('.del');
    set.addEventListener('click', function() {
        var val = ipt.value;
        localStorage.setItem('username', val);
    })
    get.addEventListener('click', function() {
        console.log(localStorage.getItem('username'));
    })
    remove.addEventListener('click', function() {
        localStorage.removeItem('username');
    })
    del.addEventListener('click', function() {
        localStorage.clear();
    })
</script>

正则表达式

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

通常用来查找、替换那些符合正则表达式的文本,许多语言都支持正则表达式。

表单验证(匹配)、过滤敏感词(替换)、字符串中提取需要的部分(提取)

1、定义规则—》 2、查找

语法

1、定义正则表达式语法

let 变量名 = /表达式/

其中//是正则表达式字面量

2、判断是否有符合规则的字符串

test()方法,用来查看正则表达式与指定的字符串是否匹配

匹配成功,返回true 否则返回false

regObj.test(被检测的字符串)

<script>
  //定义正则表达式   reg里面存的是对象
  let reg = /前端/
  let reg1 = /java/
  let str = '我们大家都在学习前端,喜欢前端,工作前端'
  //检测是否匹配
  console.log(reg.test(str))
  console.log(reg1.test(str))
</script>

3、检索(查找)符合规则的字符串

exec()方法 在一个指定字符中执行一个搜索匹配

匹配成功返回一个数组,否则返回null

regObj.exec(被检测的字符串)

元字符

普通字符:
大多数的字符仅能够描述它们本身,这些字符称作普通字符,例如所有的字母和数字。

也就是说普通字符只能够匹配字符串中与它们相同的字符。

元字符(特殊字符)
是一些具有特殊含义的字符,可以极大提高了灵活性和强大的匹配功能。
比如,规定用户只能输入英文26个英文字母,普通字符的话abcdefghijklm…

但是换成元字符写法:[a-z]

1.边界符(表示位置,开头和结尾,必须用什么开头,用什么结尾)

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

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

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

<script>
  console.log(/哈哈/.test('哈哈哈'))
  console.log(/哈哈/.test('二哈哈'))
  //^开头
  console.log(/^哈/.test('二哈哈'))  //false
  console.log(/^哈/.test('开心哈哈大笑'))  //false
  //以哈开头,以哈结束
  console.log(/^哈$/.test('开心哈哈大笑'))  //false
  console.log(/^哈$/.test('哈'))  //true
  console.log(/^哈$/.test('哈哈哈'))  //false
</script>

2.量词(表示重复次数)

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

量词说明
*重复零次或更多次
+重复一次或更多次
?重复零次或一次
{n}重复n次
{n,}重复n次或更多次
{n,m}重复n到m次
<script>
/*    console.log(/a/.test('a'))
//    *  n>= 0
    console.log(/a*!/.test(''))  //true
    console.log(/a*!/.test('a'))  //true
    console.log(/a*!/.test('b'))  //true
    console.log('--------------')
    //    +  n>= 1
    console.log(/a+/.test(''))  //false
    console.log(/a+/.test('a'))  //true
    console.log(/a+/.test('b'))  //false
    console.log('--------------')
    //    ?  0||1
    console.log(/^a?$/.test(''))  //true
    console.log(/^a?$/.test('a'))  //true
    console.log(/^a?$/.test('aa'))  //false
    console.log(/^a?$/.test('b'))  //false
    console.log('--------------')*/

    // {n} 只能出现n次
    console.log(/^a{2}$/.test(''))  //false
    console.log(/^a{2}$/.test('a'))  //false
    console.log(/^a{2}$/.test('aa'))  //true
    console.log(/^a{2}$/.test('b'))  //false
    console.log('--------------')

    // {n,}   >=n
    console.log(/^a{2,}$/.test(''))  //false
    console.log(/^a{2,}$/.test('a'))  //false
    console.log(/^a{2,}$/.test('aa'))  //true
    console.log(/^a{2,}$/.test('aaa'))  //true
    console.log(/^a{2,}$/.test('b'))  //false
    console.log('--------------')

    // {n,m}   >=n  <=m
    console.log(/^a{2,5}$/.test(''))  //false
    console.log(/^a{2,5}$/.test('a'))  //false
    console.log(/^a{2,5}$/.test('aa'))  //true
    console.log(/^a{2,5}$/.test('aaa'))  //true
    console.log(/^a{2,5}$/.test('aaaaaaaaa'))  //false
    console.log('--------------')

</script>

3.字符类(比如\d表示0~9)

(1)[]匹配字符集合

后面的字符串只要包含abc中任意一个字符,都返回true

(2)[]里面加上-连字符

使用连字符,表示一个范围

比如:
[a-z]表示 a到z 26个英文字母都可以

[a-zA-Z]表示大小写都可以
[0-9]表示0~9的数字都可以

(3)[]里面加上^取反符号(了解)

[^a-z] 除了a-z

(4).匹配换行符之外的任何单个字符(了解)
<script>
  //(1)[]匹配字符集合   后面的字符串只要包含abc中任意单个字符,都返回true
  console.log(/[abc]/.test('andy'))  //true
  console.log(/[abc]/.test('ab'))  //true
  console.log(/[abc]/.test('abc'))  //true
  console.log(/[abc]/.test('def'))  //false
//  (2) []里面加上 - 连字符
  console.log(/^[abc]$/.test('abc'))  //false
  console.log(/^[abc]$/.test('a'))  //true
  console.log(/^[abc]$/.test('b'))  //true
  console.log(/^[abc]$/.test('c'))  //true
//  26个英文字母 选其中一个
  console.log(/^[a-zA-Z]$/.test('d'))  //true
  console.log(/^[a-zA-Z]$/.test('D'))  //true
  console.log(/^[a-zA-Z]$/.test('DD'))  //false
  console.log(/^[a-zA-Z]$/.test('Dd'))  //false
  console.log(/^[a-zA-Z0-9]$/.test('4'))  //true
  console.log(/^[a-zA-Z0-9-_]$/.test('4'))  //true
</script>

(5)预定义

指的是某些常见的简写方式

预定类说明
\d匹配0-9之间的任一数字,相当于[0-9]
\D匹配所有0-9以外的字符,相当于[^0-9]
\w匹配任意的字母、数字和下划线,相当于[A-Za-20-9]
\W除所有字母、数字和下划线以外的字符,相当于[^A-Za-z0-9_]
\s匹配空格(包括换行符、制表符、空格符等),相等于[ \t\r\n\v\f]
\S匹配非空格的字符,相当于[^\t\r\n\v\f]

日期格式:^ \d{4}-\d{1,2}-\d{1,2} 年月日

修饰符

修饰符约束正则执行的某些细节行为,如是否区分大小写、是否支持多行匹配等

i是单词ignore 的缩写,正则匹配时字母不区分大小写

g是单词global的缩写,匹配所有满足正则表达式的结果

替换replace

字符串.replace(/正则表达式/,‘替换的文本’)

<textarea name="" id="" cols="30" rows="10"></textarea>
<button>发布</button>
<div></div>
<script>
  let btn = document.querySelector('button')
  let textarea = document.querySelector('textarea')
  let div = document.querySelector('div')
  btn.addEventListener('click',function (){
    //过滤用户输入的内容
      //字符串.replace(/正则表达式/,'替换的文本')
    // g是单词global的缩写,匹配所有满足正则表达式的结果
    div.innerHTML = textarea.value.replace(/傻逼|二货/g,'**')
  })
</script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值