web API—DOM基础

导读

什么是API?

API(Application Programming Interface 应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

简单理解为:API是提供给程序员的一种工具,以便可以轻松实现想要完成的功能

JS与web API的关联

JavaScript基础学习ECMAScript基础语法为后面做铺垫,web API是JavaScript的应用,大量使用JavaScript基础语法做出交互效果

JavaScript的组成

js组成.png

web API是什么

  • web API 是浏览器提供的一套操作浏览器功能和页面元素的API(BOM与DOM)
  • 针对于浏览器常用的API,可以做出交互效果
  • MDN详细的API查阅:https://developer.mozilla.org/zh-CN/docs/Web/API
  • 鉴于数量众多,现阶段称其为web APIs

DOM简介

什么是DOM

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

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

DOM树

dom树.png
  • 文档:一个页面就是一个文档,DOM中使用document表示
  • 元素:页面中的所有标签都是元素,DOM中用element表示
  • 节点:网页中所有的内容都是节点(标签、属性、文本、注释等),DOM中用node表示
    DOM把以上内容都看做是对象

获取元素

因为文档是从上往下加载,所以必须先有HTML标签,如果在HTML加载完毕之前执行JavaScript,可能会造成网页渲染错误

getElementById():根据ID获取元素

    var timer = document.getElementById('time');   // 返回一个dom的element对象
    console.log(timer);
    console.log(typeof timer);   // object
    console.dir(timer);    // 打印返回的元素对象,可查看里面的属性与方法

getElementsByTagName():根据标签名获取元素

    var lis = document.getElementsByTagName('li');   // 返回元素对象的集合,并以伪数组的形成存储
    console.log(lis);
    console.log(lis[0]);

遍历方式

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

获取父元素中的子元素

    var ol = document.getElementsByTagName('ol');
    console.log(ol[0].getElementsByTagName('li'));   // 因为获取的父元素返回的是伪数组形式,所以必须制定一个元素对象

或者使用ID来获取父元素

    var ol = document.getElementById('ol');
    console.log(ol.getElementsByTagName('li'))

HTML5 新增的获取元素方法

getElementByClassName():根据类名获取元素

    var boxs = document.getElementsByClassName('box');
    console.log(boxs);

querySelector():返回指定选择器的第一个元素对象

    var firstbox = document.querySelector('.box');
    console.log(firstbox);
    var nav = document.querySelector('#nav');
    console.log(nav);

querySelectorAll():返回指定选择器的所有元素对象(同样返回伪数组)

    var allBox = document.querySelectorAll('.box')
    console.log(allBox);

获取HTML和body

获取body

    var bodyEle = document.body;
    console.log(bodyEle);
    console.log(typeof bodyEle);   // object

获取HTML

    var htmlEle = document.documentElement;
    console.log(htmlEle);
    console.log(typeof htmlEle);   // object

事件基础

事件三要素:事件源、事件对象、事件处理程序

  1. 事件源:事件被触发的对象
    var btn = document.getElementById('btn');
  1. 事件类型:如何触发

  2. 事件处理程序:通过一个函数赋值的方式来完成

    btn.onclick = function () {
        alert('HelloWorld');
    }

操作元素

修改元素内容

    // 获取事件源:
    var btn1 = document.querySelector('#btn1');
    var div = document.querySelector('#show');
    // 注册事件:
    btn1.onclick = function () {
        div.innerText = getTime();
    }

    function getTime() {
        var day = new Date();
        var h = day.getHours();
        h = h < 10 ? '0' + h : h;
        var m = day.getMinutes();
        m = m < 10 ? '0' + m : m;
        var s = day.getSeconds();
        s = s < 10 ? '0' + s : s;
        var time = `${h}:${m}:${s}`
        return time;
    }

当然也可以不添加事件直接调用函数:

    var p = document.querySelector('p');
    p.innerText = getTime();    // 刷新浏览器将自动显示时间

innerText 和 innerHTML的区别

  • innerText 不识别HTML标签; innerText 会自动去除元素内的空格和换行
    var div = document.querySelector('div');
    div.innerText = '<strong> Hello! </strong> , how are you ?'
image.png
  • innerHTML 可以识别HTML标签; innerHTML 会保留元素内的空格和换行
    var div = document.querySelector('div');
    div.innerHTML = '<strong> Hello! </strong> , how are you ?'
image.png

对于同一段代码而言,两种方式有本质上的区别

这两种属性都是可以读写的:

    var p = document.querySelector('p');
    console.log(p.innerText);
    console.log(p.innerHTML);

不过相比之下,innerHTML是由W3C标准制定出来的,所以更推荐使用!

修改元素属性

    // 修改 src 属性:
    // 获取元素
    var btn1 = document.querySelector('.btn1');
    var btn2 = document.querySelector('.btn2');
    var img = document.querySelector('img');
    // 注册事件  处理程序
    btn1.onclick = function(){
        img.src = 'pic/Kana.jpg';   // 与修改元素内容不同,修改元素属性只需要用点表示法就行了
        img.title = 'Kana'; 
    }
    btn2.onclick = function(){
        img.src = 'pic/Megumin.jpg';
        img.title = 'Megumin';
    }


    // 此外,经常改变的元素属性还有 href 连接,可自行尝试

修改表单属性

    // 获取元素
    var btn = document.querySelector('button');
    var input = document.querySelector('input')
    // 注册事件 处理程序
    btn.onclick = function(){
        // input.innerHTML = 'I am clicked!'
        // 结果当然不能更改表单里的值,因为innerHTML仅仅适用于修改普通盒子里的内容,比如div
        input.value = 'I am clicked!';    // 修改表单内的值,需使用value属性

        // 按钮禁用
        // btn.disabled = true;
        this.disabled = true;
        // this 指向事件函数的调用者,即btn
    }

修改样式属性

    // 获取元素
    var div = document.querySelector('div');
    // 注册事件 处理程序
    div.onclick = function(){
        // div.style 里的样式属性 需要采用驼峰命名法
        this.style.backgroundColor = 'yellow';   
        this.style.width = '250px'
        // JS修改style样式,新产生的是行内样式,CSS权重比价高,所以能覆盖掉内联样式表中的样式
    }

    // 点击按钮隐藏图片
    var pic = document.querySelector('.box');
    var close = document.querySelector('i');

    close.onclick = function(){
        pic.style.display = 'none';
    }

使用className修改样式属性

html:

<body>
    <button>change style</button>
    <div class="box">
    </div>


</body>

CSS:

    <style>

        .box {
            width: 200px;
            height: 200px;
            margin: 60px auto;
            background-image: url(pic/Kana.jpg);
            background-size: contain;
            background-repeat: no-repeat;
        }

        .change {
            width: 200px;
            height: 200px;
            margin: 60px auto;
            background-image: url(pic/Megumin.jpg);
            background-size: contain;
            background-repeat: no-repeat;
        }

    </style>

js:

    // 类名样式操作
    // element.style 行内样式操作适用于简单并且样式数量较少修改
    // 对于样式修改较为复杂的元素,推荐使用 element.className (类名样式操作)进行修改
    var btn = document.querySelector('button');
    var box = document.querySelector('.box');

    btn.onclick = function(){
        // box.class = 'change';   这样写是错误的  
        box.className = 'change';
    }

    // class因为是保留字,因此规定使用className来操作类名属性
    // className 会直接更改元素的类名,并且覆盖掉原来的1类名
    // 如果需要添加多个类名样式,可以这样做:
    // element.className = 'class1 class2'

操作元素总结

操作元素总结.png

排他算法

html:

<body>
    <div class="box">
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
        <div class="item"></div>
    </div>

</body>

css:

    <style>
        .box {
            margin: 100px auto;
            width: 600px;
            height: 100px;
            display: flex;
            justify-content: space-around;
            
        }

        .item {
            width: 50px;
            height: 50px;
            background-color: turquoise;
        }

    </style>

js:

<script>
    // 排他算法
    var item = document.getElementsByClassName('item');
    for (var i = 0; i < item.length; i++){            //  利用循环,为每一个元素添加事件
        item[i].onclick = function(){                 //  侦测到点击事件,就把所有元素都设置为蓝色,再把被点击的那个元素设为红色
            for (var i = 0; i < item.length; i++){
                item[i].style.backgroundColor = 'turquoise';
            }
            this.style.backgroundColor = 'red';
        }
    }

</script>

自定义属性

html:

<body>
    <div id="demo" index='1' class="nav"></div>
</body>

获取元素属性值

element.属性
这种方法只能获取内置属性的值(元素本身自带属性,如id , class...)

    console.log(div.id);

element.getAttribute('属性')
这种方法除了可以获取内置属性值以外,还可以获取自定义的属性值,比如上面的index

    console.log(div.getAttribute('id'));
    console.log(div.getAttribute('index'));

设置属性值

element.'属性' = '值'

    div.id = 'test';
    div.className = 'navs';

element.setAttribute('属性','值')

    div.setAttribute('index',2);
    div.setAttribute('class','footer');   // 注意这里是class而不是className

移除属性

element.removeAttribute('属性值')

    div.removeAttribute('index');

自定义属性使用案例

再这个案例中,内容会随着tab栏的切换而更变
关键在于,每一个tab栏与内容是相对应的,利用自定义属性可以处理好这种一一对应的关系


image.png

以下是实现代码:
html:

<body>
    <div class="tab">
        <div class="tab_list">
            <ul>
                <li class="current">商品介绍</li>
                <li>规格与包装</li>
                <li>售后保障</li>
                <li>商品评价(50000)</li>
                <li>手机社区</li>
            </ul>
        </div>
        <div class="tab_con">
            <div class="item" style="display: block;">
                商品介绍模块内容
            </div>
            <div class="item">
                规格与包装模块内容
            </div>
            <div class="item">
                售后保障模块内容
            </div>
            <div class="item">
                商品评价(50000)模块内容
            </div>
            <div class="item">
                手机社区模块内容
            </div>

        </div>
    </div>
</body>

css:

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

        li {
            list-style-type: none;
        }

        .tab {
            width: 978px;
            margin: 100px auto;
        }

        .tab_list {
            height: 39px;
            border: 1px solid #ccc;
            background-color: #f1f1f1;
        }

        .tab_list li {
            float: left;
            height: 39px;
            line-height: 39px;
            padding: 0 20px;
            text-align: center;
            cursor: pointer;
        }

        .tab_list .current {
            background-color: #c81623;
            color: #fff;
        }

        .item_info {
            padding: 20px 0 0 20px;
        }

        .item {
            display: none;
        }
    </style>

js:

    <script>
        // 仿京东商品tab栏切换
        // 获取元素
        var lis = document.querySelector('.tab_list').querySelectorAll('li');
        var item = document.querySelector('.tab_con').querySelectorAll('.item');

        // 为每个标签添加事件
        for (var i = 0; i < lis.length; i++) {
            lis[i].setAttribute('index', i);   // 对标签栏设置自定义属性
            lis[i].onclick = function () {
                for (var i = 0; i < lis.length; i++) {  // 排他算法
                    lis[i].className = '';
                }
                this.className = 'current';

                // 更改对应模块内容
                // console.log(this.getAttribute('index'));
                for (var i = 0; i < item.length; i++) {     // 排他算法
                    item[i].style.display = 'none';
                }
                item[this.getAttribute('index')].style.display = 'block';
            }


        }

    </script>

H5当中的自定义属性

自定义属性设置规范.png

节点

为什么学习节点操作

为什么要学习节点操作.png

节点概述

节点概述.png

节点类型

节点类型.png

父节点与子节点

先看html:

<body>
    <div>我是div</div>
    <span>我是span</span>
    <ul>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
        <li>我是li</li>
    </ul>
    <div class="demo">
        <div class="box">
            <span class="erweima">×</span>
        </div>
    </div>
</body>
  • 父节点 parentNode
        var erweima = document.querySelector('.erweima');
        console.log(erweima.parentNode);
        // 得到的是离元素最近的父级节点,如果找不到父节点则返回null
  • 子节点 childNodes 包含所有的子节点(元素节点、文本节点...)
        var ul = document.querySelector('ul');
        console.log(ul.childNodes);   // NodeList(9) [text, li, text, li, text, li, text, li, text]
        console.log(ul.childNodes[0].nodeType);    // 3,表示此节点为文本节点(换行)
        console.log(ul.childNodes[1].nodeType);    // 1,表示此节点为元素节点
  • children 可以获取所有的子元素节点 也是实际开发中最常用的
        console.log(ul.children);   // HTMLCollection(4) [li, li, li, li]
  • firstChild 第一个子节点 ;lastChild 最后一个子节点
        console.log(ul.firstChild);   // #text
        console.log(ul.lastChild);    // #text
  • firstElementChild 第一个子元素节点 ; lastElementChild 最后一个子元素节点
        console.log(ul.firstElementChild);   // <li>...</li>
        console.log(ul.lastElementChild);    // <li>...</li>
  • 开发中最常用
        console.log(ul.children[0]);
        console.log(ul.children[ul.children.length - 1]);

实例,仿微博下拉案例

效果预览:


image.png

虽然类似于上一个例子,但完全没必要用自定义属性来做对应关系
节点的逻辑性很强,在这方面有很好的体现,通过对html编写,使其更满足效果展示的逻辑结构:

<body>
    <ul class="nav">
        <li>
            <a href="#">微博</a>
            <ul>
                <li>
                    <a href="">私信</a>
                </li>
                <li>
                    <a href="">评论</a>
                </li>
                <li>
                    <a href="">@我</a>
                </li>
            </ul>
        </li>
        <li>
            <a href="#">微博</a>
            <ul>
                <li>
                    <a href="">私信</a>
                </li>
                <li>
                    <a href="">评论</a>
                </li>
                <li>
                    <a href="">@我</a>
                </li>
            </ul>
        </li>
        <li>
            <a href="#">微博</a>
            <ul>
                <li>
                    <a href="">私信</a>
                </li>
                <li>
                    <a href="">评论</a>
                </li>
                <li>
                    <a href="">@我</a>
                </li>
            </ul>
        </li>
        <li>
            <a href="#">微博</a>
            <ul>
                <li>
                    <a href="">私信</a>
                </li>
                <li>
                    <a href="">评论</a>
                </li>
                <li>
                    <a href="">@我</a>
                </li>
            </ul>
        </li>
    </ul>
</body>

css:

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

        li {
            list-style-type: none;
        }

        a {
            text-decoration: none;
            font-size: 14px;
        }
        
        .nav {
            margin: 100px;
        }

        .nav>li {    /* 子代选择器 */
            position: relative;
            float: left;
            width: 80px;
            height: 41px;
            text-align: center;
        }

        .nav li a {
            display: block;
            width: 100%;
            height: 100%;
            line-height: 41px;
            color: #333;
        }

        .nav>li>a:hover {
            background-color: #eee;
        }

        .nav ul {
            display: none;
            position: absolute;
            top: 41px;
            left: 0;
            width: 100%;
            border-left: 1px solid #fecc5b;
            border-right: 1px solid #fecc5b;
        }

        .nav ul li {
            border-bottom: 1px solid #fecc5b;
        }

        .nav ul li a:hover {
            background-color: #fff5da;
        }



    </style>

js:

    <script>
        // 仿微博下拉菜单
        var nav = document.querySelector('.nav');
        var lis = nav.children;
        
        for(var i = 0; i < lis.length; i++){
            lis[i].onmouseover = function(){
                this.children[1].style.display = 'block'
            }

            lis[i].onmouseout = function(){
                this.children[1].style.display = 'none'
            }
        }

    </script>

节点的创建、添加与删除

html:

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

    <ul>
        <li>123</li>
    </ul>
    <button>删除</button>
</body>
  • 兄弟节点
    nextSibiling 返回下一个兄弟节点 ; previousSibiling 返回上一个兄弟节点
    会返回所有类型的节点(包括元素节点,文本节点)
        var div = document.querySelector('div')
        console.log(div.nextSibling);    // #text
        console.log(div.previousSibling);   // #text

nextElementSibling 返回下一个兄弟元素节点 ; previousElementSibling 返回上一个兄弟元素节点
如没有兄弟节点则返回null
IE 9.0 以上支持

        console.log(div.nextElementSibling);    // <span>...</span>
        console.log(div.previousElementSibling);    // null
  • 创建节点
        var li1 = document.createElement('li');
        var li2 = document.createElement('li');

  • 添加节点
    node.appendChild(child) 在node后追加元素,类似于数组中的push
        document.querySelector('ul').appendChild(li1);

node.insertBefore(child,指定元素) 在指定元素前添加节点

        var ul = document.querySelector('ul');
        ul.insertBefore(li2,ul.children[0]);

往页面里添加元素需要执行以上两个步骤:1.创建节点,2.添加节点

  • 删除节点 node.removeChild(child)
        var btn = document.querySelector('button');

        btn.onclick = function(){
            var li = ul.children[0];
            ul.removeChild(li);
        }

节点克隆

        var ul = document.querySelector('ul');
        // 克隆节点 node.cloneNode();

        // node.cloneNode() ;括号内参数可以填true或false(或者为空)
        // 如果参数为空(false),则表示为浅拷贝,只复制标签而不复制里面的内容
        // 如果参数为true,则表示深拷贝,复制标签的所有内容

        // var li1 = ul.children[0].cloneNode();
        var li1 =  ul.children[0].cloneNode(true);
        ul.appendChild(li1);

实例,动态表格生成

image.png

html:

<body>

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

        </tbody>
    </table>

</body>

css:

    <style>
        table {
            width: 500px;
            margin: 100px auto;
            border-collapse: collapse;
            text-align: center;
        }

        td,
        th {
            border: 1px solid #333;
        }

        thead tr {
            height: 40px;
            background-color: #ccc;
        }
    </style>

js:

    <script>
        // 动态生成表格
        // 数据存储
        var data = [{
            name: 'student1',
            subject: 'Computer Science',
            score: '98',
        }, {
            name: 'student2',
            subject: 'Computer Science',
            score: '88',
        }, {
            name: 'student3',
            subject: 'Computer Science',
            score: '90',
        }, {
            name: 'student4',
            subject: 'Computer Science',
            score: '78',
        }, {
            name: 'student5',
            subject: 'Computer Science',
            score: '69',
        }];

        // console.log(data);
        // 生成表格行
        var tbody = document.querySelector('tbody');
        for(var i = 0; i < data.length; i++){
            // 创建表格行节点
            var tr = document.createElement('tr');
            // 添加表格行节点
            tbody.appendChild(tr);

            // 对象属性遍历
            for(var k in data[i]){
                // 创建单元格节点
                var td = document.createElement('td');
                td.innerHTML = data[i][k];    // 单元格赋值
                // 添加单元格节点
                tr.appendChild(td);
            }

            // 添加删除按钮
            var del = document.createElement('td');
            del.innerHTML = "<a href='javascript:;'>delete</a>";
            tr.appendChild(del);
        }

        // 删除按钮添加事件
        var dels = document.querySelectorAll('a');
        for (var i = 0; i < dels.length; i++){
            dels[i].onclick = function(){
                tbody.removeChild(this.parentNode.parentNode);   // <a> --> td --> tr
            }
        }



    </script>

三种不同创建元素方式的区别

三种动态创建元素的区别.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,386评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,142评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,704评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,702评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,716评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,573评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,314评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,230评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,680评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,873评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,991评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,706评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,329评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,910评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,038评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,158评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,941评论 2 355

推荐阅读更多精彩内容