JavaScript WebAPI学习 demo5

JavaScript WebAPI学习

这篇文章讲解了修改元素属性,自定义属性,节点的增删添加删除等操作
这篇文章实在是太长了,里面主要有一些代码占据了很多的空间,我尝试能不能把他们折叠起来
这篇博客是初学者写下的笔记,如有错误,欢迎前来指正!
最后推荐大家看这部分知识点的总结,六分钟回顾一下这里的知识点

js案例

案例:排他思想

  • 案例:当点击一个按钮时选中它,并且其他的按钮都恢复未被选中的状态 (不能出现多个按钮同时被选中的状态)
  • 思考过程:在选中之前把其他的选中都去掉
    1. 先把其他元素的样式清除掉
    2. 在设置自己的样式
  • 代码示例:
<body>
  <button>按钮1button>
  <button>按钮2button>
  <button>按钮3button>
  <script>
   // 1. 获取所有按钮元素
   var btns = document.querrySelectorAll('button');
   // 返回含有三个button的伪数组
   for (var i = 0; i < btns.length; i++) {
   // 为背景颜色添加事件
   btns[i].onclick = function() {
    // 先把所有的背景颜色清空,防止出现多个被选中的状态
    for (var i = 0; i < btns.length; i++) {
    btns[i].style.backgroundColor = '';
    }
    // 改变按钮的背景颜色
    this.style.backgroundColor = 'blue';
    }
   }
  script>
body>

案例:百度换肤

  • 这里我们没有图片做背景,还是用颜色作为背景
  • 就是点击一个按钮,然后整个网页的颜色就会改变
  • 代码示例:
<head>
  <style>
  ul li {
    float: left;
    list-style: none;
  }

  .color ul li:first-child {
    height: 40px;
    width: 40px;
  }

  .color ul li:nth-child(2) {
    height: 40px;
    width: 40px;
  }

  .color ul li:nth-child(3) {
    height: 40px;
    width: 40px;
  }

  .color ul li:last-child {
    height: 40px;
    width: 40px;
  }
  style>
head>
<body>
  <div class="color">
    <ul>
      <li><img src="1.ipg" alt="">li>
      <li><img src="2.jpg" alt="">li>
      <li><img src="3.jpg" alt="">li>
      <li><img src="4.jpg" alt="">li>
    ul>
  div>
  <script>
    var items = document.querySelector('.color').  querySelectorAll('img');
    console.log(items);
    for (var i = 0; i < items.length; i++) {
      items[i].onclick = function () {
      console.log(this.style.backgroundColor);
      // 这里需要注意一下,这里需要两边加上url()
      document.body.style.backgroundColor = 'url('  +this.src+')';
      }
    }
  script>
body>

案例:当前行变色

  • 实现效果:鼠标放在一行上,该行变色,鼠标移开时该行变成原来的颜色
  • 做法:直接用 onmouseover 事件和 onmouseout 两个事件更改背景颜色
  • 代码示例:
<body>
  <div class="table">
  <div class="thead">表头div>
  <div class="tbody">
    <ul>
      <li>行1<li>
      <li>行2<li>
      <li>行3<li>
    ul>
  div>
  div>
  <script>
    // 多重选择
    var tbody = document.querySelector('.tbody'). querySelectorAll('li');
    for (var i = 0; i < tbody.length; i++) {
      // 鼠标经过事件
      tbody[i].onmouseover =  function() {
        this.style.backgroundColor = 'gray';
      }
      // 鼠标离开事件
      tbody[i].onmouseout = function() {
        this.style.backgroundColor = '';
      }
    }
  script>
body>

案例:表单全选取消

  • 要求:有一个全选按钮,当所有元素都被选中时他也被选中,反之只要有一个还是没有选中的状态他就没有选中,点击他可以实现全选与非全选之间的切换,同样,下面有一个按钮未选中时全选按钮就不选中,下面所有按钮选中时上面全选按钮选中

  • 操作思路:

    • 全选按钮影响下面的按钮:给全选按钮绑定点击事件,当全选按钮被点击时让下面所有复选框的状态和全选按钮的状态一样
    • 下面的按钮影响全选框:给所有的下面的按钮绑定点击事件,当被点击时遍历所有的子按钮,如果全都处于选中状态则全选按钮为 True 只要有一个按钮未选中则全选按钮为 False (这个里面坑特别多,代码下面细讲)
  • 代码示例:

<body>
  <div class="checkall"><input type="checkbox">全选div>
  <div>
    <dl>
      <dd><input type="checkbox">dd>
      <dd><input type="checkbox">dd>
      <dd><input type="checkbox">dd>
    dl>
  div>
  <script>
    var dtinput = document.querySelector('.checkall').querySelector('input');
    var ddinput = document.querySelector('dl').getElementsByTagName('input');
    // 全选按钮影响下面的按钮
    dtinput.onclick = function () {
      for (var i = 0; i < ddinput.length; i++) {
        // 这里十分巧妙,让下面的普通复选框保持和全选复选框一样的状态就可以了
        ddinput[i].checked = this.checked;
      }
    }
    // 下面按钮影响全选按钮
    for (var i = 0; i < ddinput.length; i++) {
      ddinput[i].onclick = function () {
        // 这个flag一定要放在function里面,否则会出现下面的按钮全选,而上面的全选按钮没有选上
        var flag = true;
        for (var i = 0; i < ddinput.length; i++) {
          if (!ddinput[i].checked) {
            flag = false;
            // 这里是为了提高运行效率
            break;
          }
        }
        dtinput.checked = flag;
      }
    }

  script>
body>
  • 这里讲一下我写这段代码时遇到的坑,首先,就是一定一定要把全选按钮和下面的按钮分开放,要不会出现一堆莫名奇妙的问题(我之前是使用dt存放全选标签,然后用dd存放下面的按钮,就导致他们两个是处于一个大标签下面的平级的两个小标签,很难把他们分离开)
  • 然后就是在下面定义 flag 时,需要把 flag 定义在 function 里面,之前我有一个 bug ,就是下面的按钮全选,而上面的全选按钮并没有选上,这个问题困扰了我好长时间,再加上我上面的获取元素也有一些问题,浪费了我一个小时之久(其实就是一个小问题,大家都可能不会犯这个错误),最后发现这里其实是作用域问题,我把 flag 定义在了 function 的外面,而 bool 类型的初值还是 false ,所以就出现我上面的那种情况

获取/修改/删除元素属性值

  • 获取属性:

  • 可以使用element.属性来获取元素属性值

  • 或者通过element.getAttribute('属性')获取属性

  • 代码示例:

<body>
  
div> <script> var div = document.querrySelector('div'); // element.属性 console.log(div.id); // element.getAttribute('属性') console.log(div.getAttribute('index')); script> body>
  • 两者区别:

    • element.属性:获取元素本身自带的属性 (无法获取自定义属性)
    • element.getAttribute('属性'):获取程序员自己定义的属性(自定义属性)
  • 修改属性:

  • element.属性同样可以改变元素的属性值

  • 还可以通过element.setAttribute('属性','值');来修改元素属性值 (同样针对自定义属性值,但是也能修改普通的属性)

小知识:用element.属性修改class属性时应该写element.className

  • 删除属性:
  • 移除属性:removeAttribute('属性')

操作元素属性值实例:tab栏切换

  • 点击不同的标签显示不同的内容
  • 这里面的难点,不知道点击哪个li
    • 解决方法,给 li 添加自定义属性例如index等于从 0 到 4 然后通过 this 来取出哪个要显示的标签
<head>
    <style>
        li {
            list-style: none;
        }


        .headbox {
            height: 50px;
        }

        .headbox ul li {
            float: left;
            height: 48px;
            width: 100px;
            background-color: #a7a3a3;
            text-align: center;
            line-height: 50px;
            margin-left: 10px;
        }

        .footbox {
            display: none;
            height: 200px;
            width: 100%;
            background-color: #a7a7a7;
            font-size: 24px;
            text-align: center;
            line-height: 200px;
            z-index: 0;
        }

        .tagbox .selected {
            background-color: red;
            color: white;
        }
    style>
head>

<body>
    <div class="tagbox">
        <div class="headbox">
            <ul>
                <li index="0">商品介绍li>
                <li index="1">规格与包装li>
                <li index="2">售后保障li>
                <li index="3">商品评价li>
            ul>
        div>
        <div class="footbox" style="display:block;">产品介绍div>
        <div class="footbox">规格与包装div>
        <div class="footbox">售后保障div>
        <div class="footbox">商品评价div>

    div>
    <script>
        var tab = document.querySelector('.headbox').querySelectorAll('li');
        var items = document.querySelectorAll('.footbox');
        // 点击一个按钮后按钮变色
        for (var i = 0; i < tab.length; i++) {
            tab[i].onclick = function () {

                // tag标签变色
                for (var i = 0; i < tab.length; i++) {
                    tab[i].className = '';
                }
                this.className = 'selected';
                // 显示内容变化
                var index = this.getAttribute('index');
                console.log(index);
                for (var i = 0; i < items.length; i++) {
                    items[i].style.display = 'none';
                }
                items[index].style.display = 'block';
            }
        }

    script>
body>
  • 刚开始我尝试自己做的时候,就陷入了一个误区,我当时认为可以通过外面给 li 注册事件的循环计数的 i 可以知到我点击的是哪个 li,但是注册事件是一次注册完成的,就是说你无论点击哪个 li,他能获取到的 i 的值都是 4 (刚开始我看到这个 4 还十分奇怪,后来仔细想想 for 循环是先++再判断,所以最后 i 值是 4),所以外层循环的 i 是没有价值的
  • 然后我又琢磨了好长时间,当时的我既不知到 this 来知到我们选择的是哪个元素又想不出穿透作用域的方法,后来接着看老师的视频,才发现如此简单
  • 这里简单总结一下,其实很简单,通过 this 指针来知到我们点击的是哪个 li 在和下面的div相对应,然后就可以实现点击不同标签出现不同内容的效果了

H5自定义属性

  • 自定义属性目的是保存数据

  • 自定义属性通过element.getAttribute('属性')获取

  • 为了区分自带的属性和我们自己定义的自定义属性,H5做出如下规范

    • H5规定自定义属性用data-属性作为自定义属性名
  • 新方法:可以通过element.dataset.属性名或者element.dataset['属性名'] (IE11兼容)

    • 注意:属性名前面不用加data-
    • element.dataset存放了所有以 data 开头的属性 (也就是自定义属性)
    • 自定义属性里面有多个-连接,dataset后面的用小驼峰命名法
  • 代码示例:

<body>
  <div data-list-name="andy">div>
  <script>
    var div = document.querySelector('div');
    // 这是个特例,需要注意下
    console.log(div.dataset.listName);
    console.log(div.dataset['listName']);
  script>
body>

节点操作

  • 通过节点层级关系获取元素

  • 节点包括:文档,元素,属性,文本

  • 一个节点至少包括nodeType(节点类型) nodeName(节点名称) nodeValue(节点值)

  • 其中nodeType分类:

    • 元素节点nodeType = 1
    • 属性节点nodeType = 2
    • 文本节点nodeType = 3 (包括文字,空格,换行)

节点层级

  • 分为父子兄三种关系

父节点

  • 父节点 parentNode
  • 同样是就近原则,返回的是最近的父节点
  • 没有返回null
  • 代码示例:
<body>
  <div class="box">
    <span class="ada">span>
  div>
  <script>
    var ada = documnet.querySelector('.ada');
    // 获取父节点
    console.log(ada.parentNode);
  script>
body>

子节点

  • 所有子节点 childNodes

  • 这种子节点方法会返回文本节点和元素节点,如果我们只想要元素节点的话,我们根据 nodeType 来区分

  • 只获取元素的子节点children

  • 代码示例:

<body>
  <ul>
    <li>li>
    <li>li>
    <li>li>
  ul>
  <script>
    var ul = document.querySelector('ul');
    console.log(ul.childNodes);
    // 这时返回 7 个节点,里面包括四个文本节点 (包括换行)
    console.log(ul.children);
    // 这时只输出三个 li
  script>
body>
  • 获取子节点 (同样会获取文本节点)

    • 第一个节点firstChild
    • 最后一个节点lastChild
  • 获取子元素节点 (有兼容性问题 IE9以上支持)

    • 第一个元素节点firstElementChild
    • 最后一个元素节点lastElementChild
  • 实际开发写法ul.children[0](这不挺正常)

    • 最后一个的写法ul.children[ul.children.length - 1]

节点操作实例:下拉菜单

  • 鼠标一经过,显示下拉菜单,离开时隐藏下拉菜单
  • 这里使用定位来确定这两个下拉菜单,注册鼠标经过与鼠标离开两个事件
  • 代码如下:
<head>
    <style>
        ul,
        li {
            list-style: none;
            margin: 0;
            padding: 0;
        }

        .tag ul li {
            float: left;
            padding: 10px;
            position: relative;
        }

        .tag ul li a {
            height: 30px;
            width: 40px;
            background-color: yellow;
        }

        .tag ul li ul {
            position: absolute;
            display: none;
        }

        .tag ul li ul li {
            height: 40px;
            width: 50px;
            background-color: #dd72bd;
        }
    style>
head>

<body>
    <div class="tag">
        <ul>
            <li>
                <a href="#">下拉菜单1a>
                <ul>
                    <li>目录1li>
                    <li>目录2li>
                    <li>目录3li>
                ul>
            li>
            <li>
                <a href="#">下拉菜单2a>
                <ul>
                    <li>目录1li>
                    <li>目录2li>
                    <li>目录3li>
                ul>
            li>
        ul>
    div>
    <script>
        var tag = document.querySelector('.tag');
        // 找到两个li
        var lis = tag.querySelector('ul').children;
        console.log(lis);
        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>
body>

兄弟节点

  • 获取上一个兄弟节点的方式:node.previousSibling

  • 获取下一个兄弟节点的方式:node.nextSibling

    • 这两种种获取方式都包括文本节点
  • 获取下一个元素兄弟节点:node.nextElementSibling

  • 获取上一个元素兄弟节点:node.previousElementSibling

    • 这两种方法有兼容性问题,IE9以上支持
    • 解决兼容性方法:写一个兼容性的函数

创建和添加节点

  • 动态创建元素节点document.createElement('tagname')
  • 创建完节点之后还要把节点添加到某个地方
  • 添加 (插入) 节点:node.appendChild(child)
    • 给父节点 node 节点添加一个元素 child 在父元素的末尾 (类似于 after 伪元素)
  • 代码示例:
<body>
  <ul>ul>
  <script>
    var ul = document.querySeletor('ul');
    // 创建节点
    var li = document.createElement('li');
    // 添加节点
    ul.appendChild(li);
  script>
body>
  • 第二种添加 (插入) 方法:node.insertBefore(child,指定元素)
  • 在指定元素前面插入

创建/添加节点案例:留言板

  • 在一个文本框内输入后点击提交后会在下方出现一个 li 来展示输入的内容

  • 小知识:text.value获取文本框里的文字

    • 通过li.innerHTML把值给li
  • 代码示例:

<body>
    <div class="comments">
        <input type="text"><button>提交button>
        <ul>ul>
    div>
    <script>
        // 获取元素
        var btn = document.querySelector('button');
        var text = document.querySelector('input');
        var ul = document.querySelector('ul');
        // 注册按钮事件
        btn.onclick = function () {
            if (text.value == '') {
                alert('您还没有输入');
                return false;
            } else {
                // 创建元素
                var li = document.createElement('li');
                // 给li里面赋值
                li.innerHTML = text.value;
                // 添加元素
                ul.appendChild(li);
            }

        }
    script>
body>
  • 如果想让最新的评论显示在最上面的话把ul.appendChild(li)改成node.insertBefore(li,ul.children[0])就可以了

删除节点

  • 删除某个节点的方法:node.removeChlid(child)

    • 删除父节点中的一个子节点,返回删除的节点
  • 代码示例:

<body>
  <ul>
    <li>1li>
    <li>2li>
    <li>3li>
  ul>
  <script>
    // 获取父元素
    var ul = document.querrySelector('ul');
    // 开始删除
    ul.removeChild(ul.children[0]);
  script>
body>

删除节点案例:删除留言

  • 接着上一个示例做
  • li 后面有一个链接,当点击链接的时候,删除这个 li
  • 代码示例:
// 获取元素
var btn = document.querySelector('button');
var text = document.querySelector('input');
var ul = document.querySelector('ul');
// 注册按钮事件
btn.onclick = function () {
    if (text.value == '') {
        alert('您还没有输入');
        return false;
    } else {
        // 创建元素
        var li = document.createElement('li');
        // 给li里面赋值
        li.innerHTML = text.value + "删除";
        // 添加元素
        ul.appendChild(li);
    }
}
var as = document.querySelectorAll('a');
for(var i = 0;i<as.length;i++) {
    as[i].oncilck = function() {
        // 这里删除的是 ul 的子元素 li ,但是是这个事件 a 的父元素
        ul.removeChild(this.parentElement);
    }
}
  • 样式尽量通过css修改
  • 阻止链接跳转可以使用 javascript:void(0); 或者 javascript:;

复制节点

  • 复制节点的方法:node.cloneNode()
  • 返回这个节点的一个副本
  • 注意:参数为空或者为 flase 则为浅拷贝,只复制节点本身,不复制里面的子节点(包括内容)
  • 括号里为 true 时为深拷贝
<body>
  <ul>
    <li>1li>
    <li>2li>
    <li>3li>
  ul>
  <script>
    // 获取父元素
    var ul = document.querrySelector('ul');
    // 开始复制
    var li = ul.chlidren[0].cloneNode();
    // 把复制的节点放入ul里面
    ul.appendChild(li);
    // 浅拷贝只复制了节点
  script>
body>

动态表格示例

  • 使用动态数据 (在js里面使用数据)
  • 这个主要是通过这个示例来把 json 数据 和 js 联系起来,然后又复习了节点操作
  • 代码示例:
<head>
    <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>
head>
<body>
    <table cellspacing="0">
        <thead>
            <tr>
                <th>姓名th>
                <th>科目th>
                <th>成绩th>
                <th>操作th>
            tr>
        thead>
        <tbody>

        tbody>
    table>
    <script>
        // 感觉这个就是 json 文件里的东西
        var datas = [{
            name: '小铭',
            subject: 'JavaScript',
            score: 100
        }, {
            name: '子程序',
            subject: 'JavaScript',
            score: 90
        }, {
            name: '海洋哥',
            subject: 'JavaScript',
            score: 80
        }, {
            name: 'zzmc',
            subject: 'JavaScript',
            score: 70
        }];
        // 动态生成表格
        var tbody = document.querySelector('tbody');
        for (var i = 0; i < datas.length; i++) {
            // 创建四行 tr
            var tr = document.createElement('tr');
            tbody.appendChild(tr);
            // 创建单元格 td
            for (var k in datas[i]) {
                var td = document.createElement('td');
                // 把值赋给单元格
                td.innerHTML = datas[i][k];
                tr.appendChild(td);
            }
            // 创建删除单元格
            var td = document.createElement('td');
            td.innerHTML = "删除";
            tr.appendChild(td);
            td.onclick = function () {
                tbody.removeChild(this.parentElement);
            }
        }
    script>
body>

三种动态创建元素的区别

  • document.white()使用很少 (不推荐)

    • 代码示例:
    document.white('
    123
    '
    ); // 新建一个页面,里面只显示div一个元素
    • 这种方法如果文档流执行完毕 (页面显示完毕),这种写法会导致重绘页面
    • 重绘页面:新建一个网页,里面只显示white里的元素
  • innerHTML创建元素

    • 代码示例:
    // 前面有个 div 标签,类名叫 inner
    var inner = document.querySelector('.inner');
    inner.innerHTML = '123';
    
    • 字符串不可变性,所以在大量创建的时候耗时较长 (拼接字符串时间较长)
    • 改进方法:新建一个数组,把要添加的标签放在数组里,然后通过 join 来一起给添加 (效率极高,甚至比createElement还高)
    • 改进方法示例:
    for(var i = 0;i < 1000;i++) {
      array.push('123');
    }
    document.body.innerHTML = array.join('');
    // 运行效率极高,达到几毫秒级别
    
  • document.createElement('tagname')创建元素

    • 代码示例:
    // 前面依旧有一个 div 标签,类名叫 inner
    var inner = document.querySelector('.inner');
    var a = document.createElement('a');
    inner.appendChild(a);
    

你可能感兴趣的:(JavaScript学习)