JavaScript从入门到精通

文章目录

JavaScript从入门到精通

初探 JavaScript 魅力

JavsScript 是什么

  • 网页特效原理
    • JavaScript 就是修改样式(文档)
  • 编写 JS 的流程
    • 布局:HTML + CSS
    • 属性:确定要修改的属性
    • 事件: 确定用户 做哪些操作(产品设计)
    • 编写 JS :在事件中,用 JS 来修改页面元素的样式

第一个 JS 特效:鼠标提示框

  • 分析效果实现原理

    • 样式:divdisplay / none
    • 事件:onmouseover / onmouseout
    • 动手编写效果
  • 特效基础

    • 事件驱动:onmouseover
    • 元素属性操作:obj.style.[...]
    • 特效实现原理概括:响应式用户操作,对页面元素样式修改
  • 兼容性问题

    // div2.style.display='block'; // 部分浏览器不兼容
    document.getElementById('div2').style.display='block'; // 所有浏览器兼容
    
  • 函数

    • 制作更复杂的效果
    • 直接在事件内写代码会很乱
      • 引入 function() 函数的基本形式
      • 把 JS 标签里放入到函数里,类似于 css 里的 class
      • 变量的使用:别名
    • 定义和调用
      • 函数定义:告诉系统有这个函数,不会执行
      • 函数调用:执行函数里面的代码
      • 关系和区别
  • 代码

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>第一个JS效果</title>
    
        <style>
          #div2 {
            display: none; 
            background: red; 
            width: 100px; 
            height: 50px; 
            font-size: 16px;
          }
          #div1 {
            display: block; 
            background: red; 
            width: 100px; 
            height: 100px; 
            font-size: 16px;
          }
        </style>
    
        <script>
    
        // 封装 getElementById 函数
        function get(id) {
          return document.getElementById(id);
        }
    
        // 显示 div2
        function show() {
          // div2.style.display='block'; // 部分浏览器不兼容
          get('div2').style.display='block';
        }
    
        // 隐藏 div2
        function hide() {
          // div2.style.display='none'; // 部分浏览器不兼容
          get('div2').style.display='none';
        }
    
        // div1 变绿
        function toGreen() {
         get('div1').style.background='green';
        }
    
        // div1 变蓝
        function toblue() {
          get('div1').style.background='blue';
        }
    
        // div1 变红
        function toRed() {
          get('div1').style.background='red';
        }
        
        // 点击循环变色
        var i = 0;
        function changeColor() {
          console.log('i=',i)
          if (i == 0) {
            toGreen();
            i++;
            console.log('i=',i)
            return;
          } 
          if (i == 1) {
            toblue();
            i++;
            console.log('i=',i)
            return;
          } 
          if (i == 2) {
            toRed();
            i = i - 2;
            console.log('i=',i)
            return;
          }
        }
        </script>
      </head>
    
      <body>
         <!-- 调用页内函数修改样式 -->
        <input type="button" onclick="changeColor()" value="按钮">
        <div id="div1">
        </div>
          <!-- 行内 JS 修改样式 -->
        <input type="checkbox" onmouseover="div2.style.display='block';" onmouseout="div2.style.display='none';" value="按钮">  
        <div id="div2">
          <p>文字<br>文字2</p>
        </div>
      </body>
    </html>
    

网页换肤和 if 判断

  • 网页换肤

    • 土豆网 “开灯” “关灯效果”
    • 任何标签都可以加 ID ,包括 link
    • 任何标签的属性,都可以修改
    • HTML 里面怎么写,JS 里面就怎么写
  • if 判断

    • 特效实现原理
    • if 基本形式
    • JS 里面 = 赋值, == 判断
    • 为 a 链接添加 JS
      • <a href="javascript:;"></a>
    • className 的使用
      • class 是关键字,所以用 className 代替
      • 其它 HTML 里面怎么写,JS 里面就怎么写
  • 代码

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <link id="link1" rel="stylesheet" type="text/css" href="css/grey.css">
    
        <script>
        function changeColor() {
          if (document.getElementById('b1').value == '关灯') {
            document.getElementById('link1').href = 'css/black.css';
            document.getElementById('b1').value = '开灯';
            console.log('black')
          } else {
            document.getElementById('link1').href = 'css/grey.css';
            document.getElementById('b1').value = '关灯';
            console.log('bl2:', document.getElementById('link1').href)
          }
        }
    
        function changeText() {
          document.getElementById('text1').value = '456';
          document.getElementById('text1').title = '文字1';
        }
    
        function showHide() {
          var div2 = document.getElementById('div2');
          if(div2.style.display == 'block') {
            div2.style.display ='none';
            console.log('1');
          } else {
            div2.style.display = 'block';
            div2.style.background = 'blue';
          }
          console.log('display:', div2.style.display);
        }
    
        function class1() {
          var div = document.getElementById('div4');
          div.className='div5';
          div.id='div5';
        }
        </script>
      </head>
      <body>
        <!-- 换肤 -->
        <input id="b1" type="button" onclick="changeColor()" value="关灯">
        <div id="div1">1</div>
        <div id="div2">2</div>
        <div id="div3">3</div>
        <input type="button" value="显示隐藏div2" onclick="showHide()">
        <br>
        <!-- HTMl 里面怎么写,JS 里面就怎么写 -->
        <input id="text1" type="text" value="123">
        <input type="button" value="改文字" onclick="changeText()">
        <br>
        <!-- a 链接的使用 -->
        <a href="javascript:;">javascript:;</a>
    
        <!-- className 的使用 -->
        <div id="div4">4</div>
        <input type="button" value="className" onclick="class1()">
      </body>
    </html>
    

函数传参

  • 改变背景颜色

    • 函数传参:参数就是占位符
      • 函数里面变量用传参
  • 改变 div 的任意样式

    • 操纵属性的第二种方式
      • 要修改的属性不确定时:元素.style[ 变量/字符串 ] = 变量/字符串
      • JS 中用 . 的地方都可以用 [] 代替;
      • 字符串变量区别和关系 :带引号是字符串,不带是变量
    • 将属性名作为参数传递
  • style 与 className

    • 元素.style.属性 = 变量/字符串
      
      • style 是修改行内样式
    • 行内样式优先级最高,之后再修改 className 不会有效果

    • 建议:只操作一种样式,要么只操作 style ,要么只操作 className

  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>函数传参</title>
    
        <style>
          div {
            display: block; 
            background: red; 
            width: 100px; 
            height: 100px; 
            font-size: 16px;
          }
    
          .div2 {
            display: block; 
            background: grey; 
            width: 100px; 
            height: 100px; 
          }
        </style>
    
        <script>
    
        // 封装 getElementById 函数
        function get(id) {
          return document.getElementById(id);
        }
    
        // div1 变绿
        function toGreen() {
         get('div1').style.background='green';
        }
    
        // div1 变蓝
        function toblue() {
          get('div1').style.background='blue';
        }
    
        // div1 变红
        function toRed() {
          get('div1').style.background='red';
        }
        
        // 点击循环变色
        var i = 0;
        function changeColor() {
          console.log('i=',i)
          if (i == 0) {
            toGreen();
            i++;
            console.log('i=',i)
            return;
          } 
          if (i == 1) {
            toblue();
            i++;
            console.log('i=',i)
            return;
          } 
          if (i == 2) {
            toRed();
            i = i - 2;
            console.log('i=',i)
            return;
          }
        }
    
        // 函数传参
        function toColor(color, width) {
          get('div1').style.background = color;
          get('div1').style.width = width;
        }
        // 将属性名作为参数传递
        function chgName(name, width) {
          // get('div1').style.name = width; // name 会被当作属性赋值
          get('div1')['style'][name] = width; // 数组 可以加字符串或者变量
        }
        // 样式优先级
        function chgClass(className) {
          get('div1').className =  className; 
        }
        </script>
      </head>
    
      <body>
        <!-- 调用页内函数修改样式 -->
        <input type="button" onclick="changeColor()" value="循环">
        <!-- 函数传参 -->
        <input type="button" onclick="toColor('green', '200px')" value="变绿">
        <input type="button" onclick="toColor('blue', '300px')" value="变蓝">
        <input type="button" onclick="toColor('red', '400px')" value="变红">
        <input type="button" onclick="chgName('height', '200px')" value="变高">
        <input type="button" onclick="chgClass('div2')" value="class变灰">
        <div id="div1"></div>
    
      </body>
    </html>
    

提取行间事件

  • 提取事件

    • 为元素添加事件

      • 事件和其它属性一样,可以用 JS 添加:

        元素.事件 = 函数名/函数;
        
        • 不能加括号,加括号直接执行函数
      • window.onload 的意义:等待页面加载完成再执行 JS

      • 行为( js )、样式( css )、结构( html ) 三者分离

  • 获取一组元素

    • 元素.getElementsByTagName('标签名')
      
      • 数组的使用
      • 数组的属性
    • 全选的实现

  • 代码: 同下

循环 while 和 for

  • 用 while 引入 循环的概念

    • while 循环语法
      • 自增的意义
      • 循环的构成:初始化、条件、语句、自增
  • for 循环

    • 用 for 代替 while 循环
      • 用 for 循环为一组元素甜腻骄傲事件
      • 什么时候用循环----一组元素
    • 例子
      • 全选---- checked 属性
      • 反选---- for 循环配合 if 判断
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="utf-8">
        <title>提取行间事件和循环</title>
    
        <style>
          div {
            display: block; 
            border: 1px solid black; 
            width: 100px; 
            height: 100px; 
            margin: 10px;
            float: left;
          }
        </style>
          
        <script>
          window.onload = function () {
            // 封装 getElementById 函数
            function get(id) {
              return document.getElementById(id);
            }
    
            // 封装 getElementsByTagName
            function gets(tagName) {
              return document.getElementsByTagName(tagName)
            }
    
            // 提取行间样式
            get('btn1').onclick = function () {
              get('btn1').value = '提取成功';
            }
    
            // 修改一组元素中的某一个元素
            get('btn2').onclick = function () {
              gets('div')[2].style.background = 'blue';
            } 
    
            // 修改一组元素- while 循环
            get('btn3').onclick = function () {
              var i = 0;
              while ( i < gets('div').length ) {
                gets('div')[i].style.background = 'yellow';
                i++;
              }
            } 
            // for
            get('btn4').onclick = function () {
              for (var i = 0; i < gets('div').length; i++ ){
                gets('div')[i].style.background = 'pink';
              }
            } 
    
            // 全选的实现 if 判断 无需div
            get('btn5').onclick = function () {
              for (var i = 0; i < gets('input').length; i++ ){
                if (gets('input')[i].type == 'checkbox'){
                  if (gets('input')[i].checked == false) {
                    gets('input')[i].checked = true;
                  } else {
                    gets('input')[i].checked = false;
                  }
                }
              }
            } 
            // 元素.getElementsByTagName 方法 单个div
            get('btn6').onclick = function () {
              var div2 = get('div2');
              var inp = div2.getElementsByTagName('input');
              for (var i = 0; i < inp.length; i++ ){
                // console.log(inp);
                if (inp[i].checked == false) {
                  inp[i].checked = true;
                } else {
                  inp[i].checked = false;
                }
              }
            }
            // 元素.getElementsByTagName 方法 多个div
            get('btn7').onclick = function () {
              var div2 = gets('div');
              for (var i = 0; i < div2.length; i++ ){
                var div = gets('div')[i];
                var inps = div.getElementsByTagName('input');
                for (var a = 0; a < inps.length; a++){
                  if (inps[a].checked == false) {
                    inps[a].checked = true;
                  } else {
                    inps[a].checked = false;
                  }
                }
              }
            }  
          };
        </script>
      </head>
    
      <body>
        <!-- 提取行间样式 -->
        <input id="btn1" type="button" value="按钮">
        <!-- 修改一组元素中的某一个元素 -->
        <input type="button" id="btn2" value="改第三个元素">
        <!-- 修改一组元素-循环 -->
        <input type="button" id="btn3" value="while循环改一组元素">
        <input type="button" id="btn4" value="for循环改一组元素">
        <input type="button" id="btn5" value="全选">
        <input type="button" id="btn6" value="全选2">
        <input type="button" id="btn7" value="全选3">
        <div><input type="checkbox" name="1" id="c1"></div>
        <div><input type="checkbox" name="1" id="c2"></div>
        <div><input type="checkbox" name="1" id="c3"></div>
        <div><input type="checkbox" name="1" id="c4"></div>
        <div><input type="checkbox" name="1" id="c5"></div>
    
        <div id="div2">
          <input type="checkbox" name="" id="">
          <input type="checkbox" name="" id="">
          <input type="checkbox" name="" id="">
          <input type="checkbox" name="" id="">
          <input type="checkbox" name="" id="">
          <input type="checkbox" name="" id="">
          <input type="checkbox" name="" id="">
        </div>
    
      </body>
    </html>
    

导航栏选项卡

  • 按钮的实现

    • 添加事件
      • this 的使用: 指当前发生事件的元素
    • 先清空所有按钮,再选中当前按钮
  • 内容的实现(ul)

    • 先隐藏所有 ul,再显示当前 ul
      • 索引值的使用:什么时候用索引值
      • HTML 添加 index 会被 FireFox 过滤
      • JS 添加 index
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>导航选项卡</title>
        <style>
          body {
            margin: 0;
            padding: 0;
          }
          #div2 {
            width: 200px;
            height: 200px;
            margin-top: 20px;
            position: relative;
          }
          #div1 {
            width: 200px;
            height: 20px;
            position: absolute;
            top: 0px;
          }
          ul {
            margin: 0;
            padding: 0;
            display: block;
            background: rgb(157, 234, 253);
            float: left;
            position: absolute;
            display: none;
            width: 200px;
            height: 200px;
          }
          .ul {
            display: block;
          }
          a {
            display: block;
            float: left;
            width: 49px;
            height: 20px;
            background: rgb(7, 184, 253);
            border-left: 1px solid rgb(255, 0, 234);
            text-decoration: none;
          }
          .a {
            background: rgb(32, 108, 221);
          }
        </style>
        <script>
          window.onload = function (){
            // 封装 getElementById 函数
            function get(id) {
              return document.getElementById(id);
            }
            // 封装 getElementsByTagName
            function gets(tagName) {
              return document.getElementsByTagName(tagName)
            }
            // 显示第一个元素
            gets('ul')[0].className = 'ul';
            // 当鼠标覆盖某个标签时 显示对应元素
            for (var i = 0; i < 4; i++) {
              gets('a')[i].index = i;
              gets('a')[i].onmouseover = function () {
                for (var a = 0; a < 4; a++) {
                  gets('ul')[a].className = '';
                  gets('a')[a].className = '';
                }
                // console.log(this);
                gets('ul')[this.index].className = 'ul';
                this.className = 'a';
              }
            }
          }
        </script>
      </head>
      <body>
        <div id="div1">
          <a href="javascript:;" id="a0">1</a>
          <a href="javascript:;" id="a1">2</a>
          <a href="javascript:;" id="a2">3</a>
          <a href="javascript:;" id="a3">4</a>
        </div>
        <div id="div2">
          <ul>
            <li>1</li>
            <li>1</li>
            <li>1</li>
          </ul>
          <ul>
            <li>2</li>
            <li>2</li>
            <li>2</li>
          </ul>
          <ul>
            <li>3</li>
            <li>3</li>
            <li>3</li>
          </ul>
          <ul>
            <li>4</li>
            <li>4</li>
            <li>4</li>
          </ul>
        </div>
      </body>
    </html>
    

JS 简易日历

  • 程序实现思路

    • 类似于选项卡,只是下面只有一个div
    • innerHTML 的使用
  • 数组的使用

    • 定义:arr = [1, 2, 3]
    • 使用:arr[0]
  • 字符串拼接

    • 作用:拼接两个字符串
    • 问题:拼接中的优先级
      • 就近相加, 字符串后面数字相加要加括号
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>简易日历</title>
        <style>
          body {
            margin: 0;
            padding: 0;
          }
          td {
            border: 5px solid rgb(218, 218, 218);
            width: 59px;
            height: 59px;
            text-align: center;
            background: rgb(83, 83, 83);
            color: white;
          }
          .td {
            background: rgb(255, 255, 255);
            color: rgb(0, 0, 0);
          }
    
          /* 日历数字区 */
          #t1 {
            border: 10px solid rgb(218, 218, 218);
            margin:0 auto;
            position: relative;
            width: 240px;
            height: 320px;
            background: rgb(218, 218, 218);
          }
    
          /* 下方文字 */
          #d2 {
            margin:0 auto;
            width: 240px;
            height: 100px;
            background: rgb(218, 218, 218);
          }
          #p1 {
            position: relative;
            margin: auto;
            width: 205px;
            height: 80px;
            background: rgb(255, 255, 255);
          }
        </style>
        <script>
          window.onload = function () {
            // 封装 getElementById 函数
            function get(id) {
              return document.getElementById(id);
            }
            // 封装 getElementsByTagName
            function gets(tagName) {
              return document.getElementsByTagName(tagName)
            }
            // 获取所有 td,注册 onmouseover 事件,添加索引
            // console.log(gets('td')) 
            var tds = gets('td');
            var i = 0;
            for (i = 0; i < tds.length; i++) {
              tds[i].index = i;
              tds[i].onmouseover = function () {
                // 先清空 td className
                for (a = 0; a < tds.length; a++) {
                  tds[a].className = '';
                }
                // 修改td className 并插入文字
                tds[this.index].className = 'td';
                // console.log(i);
                get('p1').innerHTML = (this.index + 1) + arr[this.index];
              }
            }
    
            arr = [
            '月活动:学编程、英语', '月活动:学编程、英语', '月活动:学编程、日语', 
            '月活动:学编程、画画', '月活动:学编程、旅游', '月活动:学编程', 
            '月活动:学编程', '月活动:学编程', '月活动:学编程', 
            '月活动:学编程', '月活动:学编程', '月活动:学编程'
            ]
          }
        </script>
      </head>
      <body>
        <div id="d1">
          <table id="t1">
            <tr>
              <td>1 <br>JAN</td>
              <td>2 <br>FER</td>
              <td>3 <br>MAR</td>
            </tr>
            <tr>
              <td>4 <br>APR</td>
              <td>5 <br>MAY</td>
              <td>6 <br>JUN</td>
            </tr>
            <tr>
              <td>7 <br>JUL</td>
              <td>8 <br>AUG</td>
              <td>9 <br>SEP</td>
            </tr>
            <tr>
              <td>10 <br>OCT</td>
              <td>11 <br>NOV</td>
              <td>12 <br>DEC</td>
            </tr>
          </table>
          <div id="d2">
            <p id="p1">
    
            </p>
          </div>
        </div>
      </body>
    </html>
    

JavaScript 基础

JavaScript 组成

  • ECMAScript:解释器、编译器(几乎所有兼容)

  • DOM:Document Object Model,HTML,document(大部分兼容)

  • BOM:Browser Object Model,浏览器,

    window
    

    (完全不兼容)

    • 各组成部分的兼容性、兼容性问题的由来

变量类型

  • 类型:

    typeof
    

    运算符

    • 用法:typeof 元素返回变量的类型
    • 常见类型:
      • numberstringbooleanundefined(未定义或定义未使用)、objectfunction
  • 一个变量应该只放一种类型的数据

变量类型转换

  • 数据类型转换

    • 例子:计算两个文本框的和

    • 显式类型转换(强制类型转换)

      • parseInt() 去除小数、parseFloat()保留小数:从左至右提取数字,遇到不是数字跳出

      • NaN的意义和检测:Not a Number

      • NaN: NaN 和任何值都不相等,包括它自己

        • 使用 isNaN() 检测是否是全是数字
      • Number() 转换数值,String() 转换字符串,Boolean() 转换布尔值
        
    • 隐式类型的转换

      • ==:先转换类型 再比较

        对比 ===:全等于,不转换类型直接比较

      • -:数字相减

        对比 +:字符串连接、数字相加

      • 5 + null    // 返回 5         因为 null 被转换为 0
        "5" + null  // 返回 "5null"   因为 null 被转换为  "null"
        "5" + 2     // 返回 52        因为 2 被转换为 "2"
        "5" - 2     // 返回 3         因为 "5" 被转换为 5
        "5" * "2"   // 返回 10        因为 "5" 和 "2" 被转换为 5 和 2
        
  • 更多可用于将数值转换为字符串的方法:

    方法描述
    toExponential()返回字符串,对数字进行舍入,并使用指数计数法来写。
    toFixed()返回字符串,对数字进行舍入,并使用指定位数的小数来写。
    toPrecision()返回字符串,把数字写为指定的长度。
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>变量类型转换</title>
        <style></style>
        <script>
          window.onload = function () {
            // 封装 getElementById 函数
            function get(id) {
              return document.getElementById(id);
            }
    
            let t1 = get('t1');
            let t2 = get('t2');
            let b1 = get('b1');
            let s1 = get('s1');
            let s2 = get('s2');
            b1.onclick = function (){
              if (isNaN(t1.value)) {
                s1.innerHTML = '<br>' + t1.value + '不是数字';
              } else if (isNaN(t2.value)) {
                s1.innerHTML = '<br>' + t2.value + '不是数字';
              } else {
                console.log('t1:',typeof t1.value, 't2',typeof t2.value);
                let val = parseInt(t1.value) + parseInt(t2.value);
                let val2 = parseFloat(t1.value) + parseFloat(t2.value);
                s1.innerHTML = '<br>int结果:' + val+ '<br>float结果:' + val2;
                console.log(typeof val);
    
                // == 和 - 隐式转换
                let a = t1.value ;
                let b = t2.value;
                if (a == b) {
                  s2.innerHTML = 'a == b' + '<br>a - b = ' + (a - b) + '<br>a + b = ' + (a + b);
                } else if (a === b) {
                  s2.innerHTML = 'a === b!';
                } else {
                  s2.innerHTML = 'a不等于b!' + '<br>a - b = ' + (a - b) + '<br>a + b = ' + (a + b);
                }
              }
            }
          }
        </script>
      </head>
      <body>
        <input type="text" name="" id="t1">
        <input type="text" name="" id="t2">
        <input type="button" name="" id="b1" value="计算">
        <div>
            <span id="s1"></span>
        </div>
        <div>
            <span id="s2"></span>
        </div>
      </body>
    </html>
    

变量的作用域和闭包

  • 变量作用域(作用范围)
    • 局部变量、全局变量
  • 什么是闭包?
    • 子函数可以使用父函数中的局部变量
    • 之前一直在使用闭包
    • 网上对于闭包的定义

命名规范

  • 命名规范及必要性
    • 可读性–能看懂
    • 规范性–符合规则
  • 匈牙利命名法
    • 类型前缀 + 首字母大写getElementByTagName
类型前缀类型(英文)实例
数组aArrayaItems
布尔值bBooleanbIsComplete
浮点数fFloatfPrice
函数fnFunctionfnHandler
整数iIntegeriItemCount
对象oObjectoDiv1
正则表达式reRegExpreEmailCheck
字符串sStringsUserName
变体变量vVariantvAnything

运算符

  • 算数:+加、-减、*乘、/ 除、%取模

    • 实例:隔行变色、秒转时间
  • 赋值:=、+=、-=、*=、/=、%=

    • +=i += 1 等于 i++
  • 关系:<、>、<=、>=、== 、===、!=、!==

    • !== :不同类型不比较,且无结果,同类型才比较,对应 ===
    • !=:若类型不同,会偿试转换类型,对应 ==
  • 逻辑:&&与、||或、!否

    • 实例:全选与反选
  • 运算符优先级:括号

  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>运算符</title>
        <style>
        .blue {
          width: auto;
          height: 20px;
          background: blue;
        }
        .yellow {
          width: auto;
          height: 20px;
          background: yellow;
        }
        </style>
        <script>
          window.onload = function () {
            // 封装 getElementById 函数
            function get(id) {
              return document.getElementById(id);
            }
            // 封装 getElementsByTagName
            function gets(tagName) {
              return document.getElementsByTagName(tagName)
            }
            // 隔行变色
            function liCol() {
              let i = 0;
              let oLi = gets('li') ;
              for (i = 0; i < oLi.length; i++) {
                if (i % 2 === 0) {
                  oLi[i].className = 'blue';
                } else {
                  oLi[i].className = 'yellow';
                }
              }
            }
            liCol();
    
            // 毫秒转日期
            const date = Date.now();
            // 60000ms / 1000ms /60s /60m /24h /365d
            const millisecond = date % 1000 + '毫秒';
            const second = parseInt(date/1000) % 60 + '秒';
            const minute = parseInt(date/1000/60) % 60 + '分';
            const hour = parseInt(date/1000/60/60) % 24 + 8 + '小时';
            const day = parseInt(date/1000/60/60/24/365) % 30 - 9 + '号';
            const month = parseInt(date/1000/60/60/24/30) % 12 + 4 + '月'; 
            const year = parseInt(date/1000/60/60/24/265) + 1951 +'年';
            const d1 = get('d1');
            d1.innerHTML = millisecond+ second+ minute+ hour+ day+ month+ year;
          }
    
          // 赋值 ` =、+=、-=、*=、/=、%= `
          let i = 11;
          i += 2;
          console.log(i);
          i -= 3;
          console.log(i);
          i *= 2;
          console.log(i);
          i /= 2;
          console.log(i);
          i %= 3;
          console.log(i);
    
          // 判断 <、>、<=、>=、== 、===、!=、!==
          if (i > 0) {
          console.log('i > 0');
          } 
          if (i <= i) {
            console.log('i <= i');
          }
          if (i == '1') {
            console.log('i == "1"')
          }
          if (i === 1) {
            console.log('i === 1')
          }
          if (i != '1') {
            console.log('i != 2')
          }
          if (i !== 1) {
            console.log('i !== 1')
          }
    
          // 逻辑 &&与、||或、!否
          if (i<2 && i>0) {
            console.log('i<2 && i>0')
          }
          if (i<2 || i<0) {
            console.log('i<2 || i<0')
          }
        </script>
      </head>
      <body>
        <div>
          <ul>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
            <li></li>
          </ul>
        </div>
        <div id="d1"></div>
      </body>
    </html>
    

程序流程控制

  • 判断:if、switch、?:
  • 循环:while、for
  • 跳出:break、continue
  • 什么是真、什么是假
    • JavaScript 中,truthy(真值)指的是在布尔值上下文中,转换后的值为真的值。所有值都是真值,除非它们被定义为 假值(即除 false0""nullundefinedNaN 以外皆为真值)。
  • 代码:同下

JSON

  • 什么是 JSON

  • JSON 和数组

  • JSONfor in

  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>程序流程控制</title>
        <script>
        window.onload = function () {
          // switch
          var i = 0;
          switch (i){
            case i*++i:
              console.log('i');
              break;
            case 1:
              console.log('1')
              break;
            default:
              console.log('default');
              break;
          }
    
          // ?:  条件?语句一:语句二
          var a = 1;
          a % 2 == 0 ? console.log('双数'):console.log('单数');
    
          // break continue
          for (i = 0; i < 5; i++){
            if (i === 2){
              // break; // 中断所有循环
              continue; // 中断本次循环
            }
            console.log(i);
          }
    
          // json 和 数组
          const json = {a: 2, b: 5, c:9};
          const arr = [23, 45, 5467];
          console.log('b:', json.b, 'c:', json['c'], '没有length', json.length);
          console.log(arr[2], arr.length);
    
          // JSON 和 for in
          for (var i in arr) {
            console.log('第' + i + '个:' + arr[i]);
          }
          for (var i in json) {
            console.log('第' + i + '个:' + json[i]);
          }
        }
        </script>
      </head>
      <body>
      </body>
    </html>
    

深入 JavaScript

函数返回值

  • 什么是函数返回值
    • 函数的执行结果
    • 可以没有 return
  • 一个函数应该只有一种返回值类型

函数传参与行间样式

  • 可变函数(不定参数):arguments

    • 是一个对应于传递给函数的参数的类数组对象。

    • arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。

    • JavaScript 中的函数与其他面向对象语言有几个不同的地方。

      1. 没有函数重载
      2. 有一个表示实参列表的类数组对象 arguments

      img

  • 例子:求和

    • 求所有参数的和
  • 例子2:CSS 函数

    • 判断 arguments.length
    • 给参数取名,增强可读性
  • 取非行间样式(不能用来设置):

    • obj.currentStyle[attr] 只兼容 IE ,返回小数

    • getComputedStyle(obj, false)[attr],返回小数

    • // 解决兼容问题
      // 封装获取计算后元素样式函数
      function getStyle(obj, name) {
          if (obj.currentStyle) {
              return obj.currentStyle[name];
          } else {
              return getComputedStyle(obj, '') [name];
          }
      }
      
    • 复合样式:background / border要用具体样式名 backgroundColor

    • 单一样式:width / height / position

数组基础操作

  • 数组的使用

    • 定义
      • var arr = [23, 234, 23, 45];
      • var arr = new Array(12, 5, 7, 34);
      • 没有任何差别,[] 的性能略高,因为代码短
  • 数组的属性

    • length
      
      • 既可以获取,又可以设置
      • 例子:快速清空数组 length = 0
  • 数组的使用原则:数组中应该只存一种类型的变量

  • 数组的方法

    • 添加
      • push(元素),从尾部添加
      • unshift(元素),从头部添加
    • 删除
      • pop(),从尾部删除
      • shift(),从头部删除
  • 排序

    • 数组.sort([比较函数]),排序一个数组,只有数组能使用

      • 排序一个字符串数组,不加比较函数,默认按照 ASCII 码排序

      • 排序一个数字数组,加数字比较大小函数

      • // 正序比较函数 数字比大小 字符比ASCII值大小
        function positiveSort(n1, n2) {
            if (isNaN) {
                if (n1 > n2) {
                    return 1;
                }
                if (n1 < n2) {
                    return -1;
                }
                if (n1 === n2) {
                    return 0;
                }
            } else {
                return n1 - n2;
            }
        }
        
  • 转换类

    • 数组.concat(数组2)
      
      • 连接两个数组,可用于深度复制
    • 数组.join(分隔符)
      
      • 用指定分隔符替代数组的 ,,重新组合数组元素,生成字符串
      • 字符串 split
    • 数组.reverse()
      
      • 颠倒数组中元素的顺序
  • 数组.slice(start,end)

    • 从已有数组中返回选定元素,可用于深度复制
    • start 为负数时,和数组长度相加再查找
  • splice:先删除,后插入

  • 数组.splice(起点,长度,元素)

  • 删除

    • 数组.splice(起点,长度)
  • 插入

    • 数组.splice(起点,0,元素...)
  • 替换

    • 数组.splice(起点,长度,元素)
  • ECMAScript 两个关于位置的方法

    • arrayObject.indexOf(searchvalue,startIndex)
      
      • 从startIndex 开始向后查找,默认值为 0
      • 返回 number 查找项在数组中的位置,没找到返回-1
    • ``arrayObject.lastIndexOf(searchvalue,startIndex)`

      • 从startIndex 开始向前查找,默认值为 0
      • 返回 number 查找项在数组中的位置,没找到返回-1
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>数组操作</title>
        <style>
        div {
          margin-top: 10px;
        }
        </style>
        <script>
        var arr = [23, 435, 567, 321, 9, 4];
        var arr2 = new Array('m', 'r', 'a', 'z', 'c', 'p', 'e', '破就', '不发');
    
        // 封装getById
        function get(id) {
          return document.getElementById(id);
        }
    
        window.onload = function () {
          // 显示数组
          function showArr() {
            get('d1').innerHTML = arr + ' + ' + arr2;
          }
          showArr();
    
          // 添加元素 从尾部添加
          get('btn2').onclick = function () {
            arr.push(222);
            showArr();
          }
    
          // 添加元素 从头部添加
          get('btn22').onclick = function () {
            arr.unshift(234);
            showArr();
          }
    
          // 删除元素 从尾部删除
          get('btn3').onclick = function () {
            arr.pop();
            showArr();
          }
    
          // 删除元素 从头部删除
          get('btn33').onclick = function () {
            arr.shift();
            showArr();
          }
    
          // 排序元素
          get('btn4').onclick = function () {
            arr.sort(positiveSort);
            arr2.sort(positiveSort);
            showArr();
          }
          // 比较函数 数字比大小 字符比ASCII值大小
          function positiveSort(n1, n2) {
            if (isNaN) {
              if (n1 > n2) {
                return 1;
              }
              if (n1 < n2) {
                return -1;
              }
              if (n1 === n2) {
                return 0;
              }
            } else {
              return n1 - n2;
            }
          }
    
          // 拼接数组
          get('btn5').onclick = function () {
            arr = arr.concat(arr2);
            showArr();
          }
          
          // 分隔符
          get('btn6').onclick = function () {
            arr = arr.join('_');
            showArr();
          }
          
          // splice 插入 splice(起点,长度,元素)
          get('btn7').onclick = function () {
            arr.splice(2, 0, 5, 1);
            showArr();
          }
          // splice 删除
          get('btn8').onclick = function () {
            arr.splice(0, arr.length);
            showArr();
          }
          // splice 替换 = 删除 + 插入
          get('btn9').onclick = function () {
            arr.splice(2, 1, 999, 888);
            showArr();
          }
    
        }
        </script>
      </head>
      <body>
        <div>
          <input type="button" name="" id="btn2" value="尾部添加元素">
          <input type="button" name="" id="btn22" value="头部添加元素">
          <input type="button" name="" id="btn3" value="尾部删除元素">
          <input type="button" name="" id="btn33" value="头部删除元素">
          <input type="button" name="" id="btn4" value="正序排序元素">
        </div>
        <div>
          <input type="button" name="" id="btn5" value="拼接数组">
          <input type="button" name="" id="btn6" value="分割数组">
        </div>
        <div>
          <input type="button" name="" id="btn7" value="插入元素">
          <input type="button" name="" id="btn8" value="删除元素">
          <input type="button" name="" id="btn9" value="替换元素">
        </div>
        <div id="d1"></div>
      </body>
    </html>
    
  • 数组名作为变量(遍历数组中的数组):

    var arr1=new Array(); 
    var arr2=new  Array(); 
    var arrlist= new Array(); //存放以上数组
    arrlist.push(arr1);
    arrlist.push(arr2);
    //循环遍历arrlist,就可以达到你要的效果
    

定时器的使用

定时器的作用

  • 开启定时器

    • setInterval(函数, 间隔时间) 间隔型,函数后面不能带括号和传参

    • setTimeout(函数, 延时时间) 延时型

      1. 如果当前任务执行时间过久,会影延迟到期定时器任务的执行
      2. 使用 setTimeout 设置的回调函数中的 this 环境不是指向回调函数
      3. 未激活的页面,setTimeout 执行最小间隔是 1000 毫秒
      4. setTimeout 存在嵌套调用问题,调用超过5次后,系统会设置最短执行时间间隔为 4 毫秒
      5. 延时执行时间有最大值
    • Web Workers 是 HTML5 提供的一个javascript多线程解决方案,可以将一些大计算量的代码交由web Worker运行而不冻结用户界面。

      注意:Web Workers需要IE10及其以上的浏览器支持。

    • 两种定时器的区别,定时器要 window.onload 完一秒后才执行

  • 停止定时器

    • clearInterval(定时器名字)
    • clearTimeout(定时器名字)
  • 代码:

    window.onload = function () {
    	var oBtn1 = document.getElementById('btn1');
    	var oBtn2 = document.getElementById('btn2');
        var timer = null;
        
        oBtn1.onclick = function () {
    		timer = setInterval(function () {
                alert('a');
            }, 2000);
        };
        
        oBtn2.onclick = function () {
            clearInterval(timer);
        };
    };
    

数码时钟

  • 效果思路

  • 获取系统时间

    • new Date 对象
    • getHours / getMinutes / getSeconds
  • 显示系统时间

    • 字符串连接
    • 空位补零
  • 设置图片路径

    • str[i]:取出字符串中的第 i 个值,不兼容 ie7
  • charAt(i) 方法 :取出字符串中的第 i 个值,兼容各种浏览器

  • 设置路径:"url('img/0.png')"

  • JavaScript 中的 String 字符串操作方法

    • obj.charAt(index)
      
      • 返回index位置的字符
    • obj.charCodeAt()
      
      • 返回index位置的字符编码
    • obj.indexOf("str")
      
      • 顺序搜索str,返回其位置,未找到返回-1
    • obj.lastIndexOf("str")
      
      • 倒序搜索str,返回其位置,未找到返回-1
    • slice(start,end):同数组

    • substring(start,end):同上,区别在于参数为负数时自动转换为0,并且较小的数为起始位

    • substr(start,len):同上,len 表示截取的长度

  • 代码:

    <!DOCTYPE html>
    <html>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
      <title>数码时钟</title>
      <style>
      body{
        margin: 0;
        padding: 0;
        background-color: rgb(49, 49, 49);
      }
      li {
        list-style: none;
        float: left;
        width: 100px;
        height: 149px;
      }
      span {
        float: left;
        font-size: 100px;
        color: rgb(255, 255, 255);
      }
      </style>
      <script>
      window.onload = function () {
        // 封装 getElementsByTagName
        function gets(tagName) {
          return document.getElementsByTagName(tagName)
        }
    
        // 数码时钟
        // 数字时钟图片设置函数
        const oLi = gets('li');
        function clock() {
          const date = new Date();
          const str = addZero(date.getHours()) + addZero(date.getMinutes()) + addZero(date.getSeconds());
        
          let i = 0;
          for (i = 0; i < oLi.length; i++) {
            oLi[i].style.backgroundImage = "url('img/"+ str.charAt(i) +".png')";
          }
        }
        // 补零
        function addZero(num) {
          if (num < 10) {
            num = '0' + num;
          } else {
            num = '' + num;
          }
          return num;
        }
        // 先执行一遍,就不会出现一秒的空白,定时器要 window.onload 完一秒后才执行
        clock();
        // 定时器 每秒刷新一次
        setInterval(clock, 1000);
      }
      </script>
      <body>
        <ul>
          <li></li>
          <li></li>
          <span>:</span>
          <li></li>
          <li></li>
          <span>:</span>
          <li></li>
          <li></li>
        </ul>
      </body>
    </html>
    

Date 对象其它方法

方法描述
getDate()获得以数值计(1-31)的日
getDay()或者以数值计(0-6)的周
getFullYear()获得四位的年(yyyy)
getHours()获得时(0-23)
getMilliseconds()获得毫秒(0-999)
getMinutes()获得分钟(0-59)
getMonth()获得月(0-11)
getSeconds()获得秒(0-59)
getTime()获得时间(1970 年 1 月 1 日以来的毫秒)

延时提示框

  • 效果演示
  • 原来的方法
    • 移入显示,移出隐藏
  • 移出延时隐藏
    • 移入下面 div 后,还是隐藏
  • 简化代码
    • 合并两个相同的 mouseovermouseout
    • 连续 a=b=c=function() 两个事件共使用一个函数
  • 代码:同下

无缝滚动

  • 效果演示

  • 物体运动基础

    • div 移动起来
    • offsetLeft/offsetTop 的作用:获取当前对象的左边距/上边距
    • offsetWidth/offsetHeight
    • 用定时器让物体连续移动:
      • innerHTML 拼接两节图片, 宽度后面加 px 才会生效
      • overflow:hidden; 隐藏元素外的内容
  • 改变滚动的方向

    • 修改 speed
    • 修改判定条件
    • 多次点击越来越快:if (!timer)clearInterval(timer); 避免重复调用
  • 鼠标移入暂停

    • 移入关闭定时器
    • 移出重新开启定时器
  • 代码:

    <!DOCTYPE html>
    <html>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
      <link rel="stylesheet" href="../reset.css">
      <title>移出延时隐藏</title>
      <style>
        body {
          width: 560px;
          margin: 0 auto;
        }
        #d2 {
          margin: 10px;
          width: 200px;
          height: 200px;
          background-color: rgb(0, 204, 255);
          display: none;
          float: left;
        }
        #d1 {
          margin: 10px;
          width: 100px;
          height: 100px;
          background-color: rgb(0, 255, 149);
          float: left;
        }
        #d3 {
          margin: 220px auto;
          width: 560px;
          height: 140px;
          position: absolute;
          background-color: rgb(135, 182, 182);
          overflow: hidden;
        }
        #u1 {
          position: relative;
        }
        #u1 li {
          float: left;
        }
      </style>
      <script>
      window.onload = function () {
        // 封装 getElementById 函数
        function get(id) {
          return document.getElementById(id);
        }
        // 封装 getElementsByTagName
        function gets(tagName) {
          return document.getElementsByTagName(tagName)
        }
    
        // 鼠标移动到 d1 上,d2 显示,移出隐藏;
        // 鼠标移到 d2 上,清除定时器,移出 d2 开启定时器
        let timer = '';
        get('d1').onmouseover= get('d2').onmouseover = function () {
          clearTimeout(timer);
          get('d2').style.display = 'block';
        }
        get('d1').onmouseout= get('d2').onmouseout = function () {
          timer = setTimeout(hide,1000);
        }
        function hide() {
          get('d2').style.display = 'none';
        }
    
        // 无缝滚动
        get('u1').innerHTML += get('u1').innerHTML;
        get('u1').style.width = gets('li').length * gets('li')[0].offsetWidth + 'px';
        let timer2 = '';
        let speed = 2;
        // 左移
        get('btn1').onclick = function () {
          speed = -2;
          if (!timer2) {
            timer2 = setInterval(move, 30);
          }
        }
        // 右移
        get('btn2').onclick = function () {
          speed = 2;
          if (!timer2) {
            timer2 = setInterval(move, 30);
          }
        }
        // 移动
        function move() {
          get('u1').style.left = get('u1').offsetLeft + speed + 'px';
          if (get('u1').offsetLeft < -get('u1').offsetWidth/2) {
            get('u1').style.left = 0;
          } else if (get('u1').offsetLeft > 0){
            get('u1').style.left = -get('u1').offsetWidth/2 + 'px';
          }
            console.log(get('u1').offsetLeft);
        }
        // 鼠标悬停
        get('d3').onmouseover = function () {
          clearInterval(timer2);
        }
        get('d3').onmouseout = function () {
          timer2 = setInterval(move, 30);
        }
      }
      </script>
      <body>
        <div id="d1"></div>
        <div id="d2"></div>
        <div id="d3">
          <ul id="u1">
            <li><img src="images/1.png" alt=""></li>
            <li><img src="images/2.png" alt=""></li>
            <li><img src="images/3.png" alt=""></li>
            <li><img src="images/4.png" alt=""></li>
          </ul>
        </div>
        <input type="button" name="" id="btn1" value="左移">
        <input type="button" name="" id="btn2" value="右移">
      </body>
    </html>
    

DOM 基础

DOM 基础

  • 什么是 DOM
  • 浏览器支持情况

DOM 节点

  • DOM 节点

    • 获取子节点

      • childNodes
        

        :不兼容高版本,用

        nodeType
        

        兼容

        • 获取文本节点( nodeType == 3) 和元素节点( nodeType == 1)
      • children只获取元素节点,兼容

    • parentNode
      

      :查找父节点

      • 例子:点击链接,隐藏整个 li
    • offsetParent
      

      :查找定位父级

      • 例子:获取元素在页面上的实际位置
    • 首尾子节点

      • firstChild 有兼容性问题,IE6-8用
      • firstElementChild 高版本使用
      • lastChild/ lastElementChild
    • 兄弟节点

      • 有兼容性问题,IE6-8用前面的
      • nextSbling / nextElementSibling
      • previousSibling/ previousElementSibling

操作元素属性

  • 操作元素属性
    • 元素属性操作
      • 第一种:oDiv.style.display = 'block';
      • 第二种:oDiv.style['display'] = 'block';
      • 第三种:Dom 方式
    • Dom 方式操作元素属性
      • 获取:getAttribute(名称)
      • 设置:setAttribute(名称, 值)
      • 删除:removeAttribute(名称)

DOM 元素灵活查找

  • 用 className 选择元素

    • 如何用 className 选择元素

      • 选出所有元素
      • 通过 className 条件筛选
    • 封装成函数:

      // 通过 className 查找元素
      function getByClass(oParent, sClass) {
      	var aResult = [];
      	var aEle = oParent.getElementsByTagName('*');
      	
      	for(var i = 0; i < aEle.length; i++) {
              if (aEle[i].className == sClass) {
                  aResult.push(aEle[i]);
              }
          }
          return aResult;
      }
      

DOM 操作应用

创建、插入和删除元素

  • 创建 DOM 元素

    • document.createElement(标签名) 创建一个节点,不渲染

    • 父级.appendChild(节点)
      

      删除原有子节点

      ,再添加子节点,并渲染

      • 例子:为 ul 插入 li
  • 插入元素

    • 父级.insertBefore(节点, 原有节点)
      

      在已有元素前插入

      • 例子:倒叙插入 li
  • 删除 DOM 元素

    • 父级.removeChild(节点)
      

      删除一个节点

      • 例子:删除 li
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>DOM创建插入删除元素</title>
        <script>
          window.onload = function () {
            // 封装getElementById
            function get(id) {
              return document.getElementById(id);
            };
    
            // 在 ul 下增加 li
            let oUl = get('u1');
            get('btn1').onclick = function () {
              let oLi = document.createElement('li');
              let sL = get('txt1').value + "<a href='javascript:;'>删除</a>";
              oLi.innerHTML = sL;
              oUl.appendChild(oLi);
              aRemove();
            };
            // 从 ul 下插入 li
            get('btn2').onclick = function () {
              let oLi = document.createElement('li');
              let aLi = document.getElementsByTagName('li');
              let sL = get('txt1').value + "<a href='javascript:;'>删除</a>";
              let i = get('txt2').value - 1;
              oLi.innerHTML = sL;
              if (aLi.length > i && aLi.length > 0) {
                oUl.insertBefore(oLi, aLi[i]);
              } else {
                oUl.appendChild(oLi);
              }
              aRemove();
            };
            // 从 ul 下删除 li
            get('btn3').onclick = function () {
              let aLi = document.getElementsByTagName('li');
              let i = get('txt2').value - 1;
              if (i < aLi.length && i >= 0) {
               oUl.removeChild(aLi[i]);
              } else {
                alert('找不到第'+ (parseInt(i) + 1) +'个li');
              }
            };
    
            // this 从 ul 删除 li
            function aRemove() {
              let aA = document.getElementsByTagName('a');
              let i =0
              for (i = 0; i < aA.length; i++) {
                aA[i].onclick = function () {
                  oUl.removeChild(this.parentNode);
                }
              }
            }
          }
        </script>
      </head>
      <body>
        <input type="text" name="" id="txt1" value="123">
        <input type="button" name="" id="btn1" value="增加">
        <input type="text" name="" id="txt2" value="1">
        <input type="button" name="" id="btn2" value="插入">
        <input type="button" name="" id="btn3" value="删除">
        <div is="d1">
          <ul id="u1">
          </ul>
        </div>
      </body>
    </html>
    

文档碎片

  • 文档碎片理论上可以提高 DOM 操作性能

  • 文档碎片原理

  • document.createDocumentFragment():Vue 、MVVM 还有用到

  • 代码:

    var element  = document.getElementById('ul'); // assuming ul exists
    var fragment = document.createDocumentFragment();
    var browsers = ['Firefox', 'Chrome', 'Opera', 
        'Safari', 'Internet Explorer'];
    
    browsers.forEach(function(browser) {
        var li = document.createElement('li');
        li.textContent = browser;
        fragment.appendChild(li);
    });
    
    element.appendChild(fragment);
    

DOM操作应用高级

表格标签

表格描述
<table>定义表格
<caption>定义表格标题。
<th>定义表格的表头。
<tr>定义表格的行。
<td>定义表格单元。
<thead>定义表格的页眉。
<tbody>定义表格的主体。
<tfoot>定义表格的页脚。
<col>定义用于表格列的属性。
<colgroup>定义表格列的组。

表格应用

  • 获取

    • tBodies / tHead / tFoot / rows / cells

      var oTab = document.getElementById('tab1');
      alert(oTab.tBodies[0].rows[1].cells[1].innerHTML);
      
  • 隔行变色

    • 鼠标移入高亮
  • 添加/删除一行

    • DOM 方法的使用
  • 搜索

    • 版本1:基础版本 – 字符串比较
    • 版本2:忽略大小写 – 大小写转换 toLowerCase()/toUpperCase(),返回字符串
    • 版本3:模糊搜索 – search() 的使用,没找到返回 -1,找到则返回位置
    • 版本4:多关键词 – split() 分割字符串,返回数组
    • 高亮显示、筛选
  • 排序

    • 移动 li ,使用appendChild(): 删除原有 li,尾部新增 li
    • 元素排序:元素集合转换成数组 – sort() 排序 – appendChild()插入
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>表格操作</title>
        <style>
          body {
            margin: 0 auto;
            width: 400px;
          }
          table {
            border: rgb(97, 97, 97) 1px solid;
            width: 400px;
          }
          td {
            border: rgb(255, 106, 136) 1px solid;
          }
        </style>
        <script>
          window.onload = function () { 
            // 封装getElementById
            function get(id) {
              return document.getElementById(id);
            };
    
            // 表格数据
            // tHead 作为最后一个数组传入
            var data = new Array(
              [1, '张三', 12, "<a href='javascript:;'>删除</a>"],
              [2, '李四', 13, "<a href='javascript:;'>删除</a>"],
              [3, '王五', 14, "<a href='javascript:;'>删除</a>"],
              [4, '王七', 19, "<a href='javascript:;'>删除</a>"],
              [5, '王九', 24, "<a href='javascript:;'>删除</a>"],
              [6, '李六', 42, "<a href='javascript:;'>删除</a>"],
              [7, '李三', 23, "<a href='javascript:;'>删除</a>"],
              [8, '李六', 76, "<a href='javascript:;'>删除</a>"],
              [9, 'CAT', 8, "<a href='javascript:;'>删除</a>"],
              [10, 'cat', 2, "<a href='javascript:;'>删除</a>"],
              [11, 'dog', 1, "<a href='javascript:;'>删除</a>"],
              [12, '3', 5, "<a href='javascript:;'>删除</a>"],
              [13, '31', 2, "<a href='javascript:;'>删除</a>"],
              [14, '4', 7, "<a href='javascript:;'>删除</a>"],
              [15, '42', 9, "<a href='javascript:;'>删除</a>"],
              [16, '啊Q', 9, "<a href='javascript:;'>删除</a>"],
              ['ID', '姓名', '年龄', "操作"]
            );
    
            // 传入格式化数组文件 data ,自动生成表格
            function createTable(data) {
              // 使用文档碎片 生成表格
              // var frag = document.createDocumentFragment();
              var table = document.createElement('table');
              var caption = document.createElement('caption');
              var thead = document.createElement('thead');
              var tbody = document.createElement('tbody');
              var tr = document.createElement('tr');
              // 渲染表格
              get('b1').appendChild(table);
              table.appendChild(caption);
              table.appendChild(thead);
              table.appendChild(tbody);
              thead.appendChild(tr);
              var oTr = document.getElementsByTagName('tr');
              // 渲染单元格
              caption.innerHTML = "<strong style='font-size: 20px'>人员表</strong>";
              var i = 0;
              var j = 0;
              var rNmb = data.length - 1; // 行
              var rLth = data[0].length;  //列
              // 生成表头
              for (i = 0; i < rLth; i++){
                var th = document.createElement('th');
                oTr[0].appendChild(th);
                // 写入th数据
                var aArr = data[rNmb];
                table.tHead.rows[0].cells[i].innerHTML = aArr[i];
              }
              // 生成 tbody 及插入内容
              for (i = 0; i < rNmb; i++) {
                var tr = document.createElement('tr');
                tbody.appendChild(tr);
                for (j = 0; j < rLth; j++) {
                  var td = document.createElement('td');
                  tr.appendChild(td);
                  // 写入td数据
                  aArr = data[i];
                  table.tBodies[0].rows[i].cells[j].innerHTML = aArr[j];
                }
              }
              // 不加 tBodies[0] 会把 tHead 当作一行
              // console.log(table.rows.length); 
              chgColor();
              aClick();
            }
            createTable(data);
    
            function chgColor() {
              // 隔行变色
              var oTr = document.getElementsByTagName('tr');
              var oldColor = '';
              for (i = 1; i < oTr.length; i++) {
                if (i % 2 === 0) {
                  oTr[i].style.background = '#eee';
                } else {
                  oTr[i].style.background = '#bbb';
                }
                // 鼠标移入高亮
                oTr[i].onmouseover = function () {
                  oldColor = this.style.background;
                  this.style.background = 'yellow';
                }
                oTr[i].onmouseout = function () {
                  this.style.background = oldColor;
                }
              }
            }
    
            // 增加/删除一行 
            var btn1 = get('btn1');
            var btn2 = get('btn2');
            var btn3 = get('btn3');
            var btn4 = get('btn4');
            var btn5 = get('btn5');
            var btn6 = get('btn6');
            var txt1 = get('txt1');
            var txt2 = get('txt2');
            var txt3 = get('txt3');
            var txt4 = get('txt4');
            var id = data.length;
            var oTab = document.getElementsByTagName('table');
            // txt1 txt2 增加一行
            btn1.onclick = function () {
              if (txt1.value != '' && txt2.value != '') {
                var newPerson = new Array(id, txt1.value, txt2.value, "<a href='javascript:;'>删除</a>")
                data.splice(data.length - 1, 0, newPerson);
                get('b1').removeChild(oTab[0]);
                createTable(data);
                id++;
              } else {
                alert('请输入姓名和年龄!');
              }
            }
            // 根据 txt4 删除一行
            btn3.onclick = del;
            function del() {
              for (var i in data) {
                var aData = data[i];
                // console.log(aData[0])
                // 校验输入ID 是否和 data.ID 匹配
                if (aData[0] === parseInt(txt4.value) || aData[0] === parseInt(txtTd)) {
                  data.splice(i, 1);
                  break;
                }
              }
              get('b1').removeChild(oTab[0]);
              createTable(data);
            }
    
            // 注册 a 标签删除操作事件
            var txtTd = '';
            function aClick() {
              var oA = document.getElementsByTagName('a');
              for (var i in oA) {
                oA[i].onclick = function () {
                  // oTab[0].tBodies[0].removeChild(this.parentNode.parentNode);
                  txtTd = this.parentNode.parentNode.cells[0].innerHTML;
                  del();
                }
              }
            }
    
            // data 筛选查询
            btn2.onclick = searchTr;
            function searchTr() {
              var oTr = document.getElementsByTagName('tr');
              var bData = new Array();
              // 储存表头
              var thData = data[data.length-1];
              if (txt3.value != '') {
                for (var i in data) {
                  var aData = data[i];
                  // console.log(aData[0])
                  // 校验输入name 是否和 data.name 匹配
                  if (aData[1].toLowerCase() === txt3.value.toLowerCase()) {
                    // 忽略大小写
                    bData.push(data[i]);
                  } else if (aData[1].toLowerCase().search(txt3.value.toLowerCase()) != -1) {
                    // 模糊搜索 search()
                    bData.push(data[i]);
                  } else {
                    // 多关键词搜索 split() 分割关键词
                    var aTxt = txt3.value.split(' ');
                    for(var j in aTxt) {
                      if (aData[1].toLowerCase().search(aTxt[j].toLowerCase()) != -1) {
                        bData.push(data[i]);
                        continue;
                      }
                    }
                  }
                }
              // 传入表头 thData
              bData.push(thData);
              get('b1').removeChild(oTab[0]);
              createTable(bData);
              } else {
                back();
              }
            }
    
            // 恢复 data
            btn4.onclick = back;
            function back() {
              get('b1').removeChild(oTab[0]);
              createTable(data);
            }
    
            // tr 高亮查询
            btn5.onclick = function () {
              chgColor();
              var name = '';
              for (i = 0; i < oTab[0].tBodies[0].rows.length; i++) {
                name = oTab[0].tBodies[0].rows[i].cells[1].innerHTML; 
                if (txt3.value != '') {
                  if (name.toLowerCase() === txt3.value.toLowerCase()) {
                    // 忽略大小写
                    oTab[0].tBodies[0].rows[i].style.background = 'yellow';
                  } else if (name.toLowerCase().search(txt3.value.toLowerCase()) != -1) {
                    // 模糊搜索 search()
                    oTab[0].tBodies[0].rows[i].style.background = 'yellow';
                  } else {
                    // 多关键词搜索 split() 分割关键词
                    var aTxt = txt3.value.split(' ');
                    for(var j in aTxt) {
                      if (name.toLowerCase().search(aTxt[j].toLowerCase()) != -1) {
                        oTab[0].tBodies[0].rows[i].style.background = 'yellow';
                        continue;
                      }
                    }
                  }
                } else {
                  back();
                }
              }
            }
    
            // data 根据元素排序 sort() 方法
            btn6.onclick = sortName;
            var item = 0; // 排序的元素
            var txt5 = get('txt5');
            var thData = data[data.length-1]; // 保存 th
            function sortName() {
              item = parseInt(txt5.value);
              data.pop(); // 去掉最后的 th
              data.sort(compare); // 正向排序
              data.push(thData); // th 加回去
              back(); //生成表格
            }
            // 比较函数 此函数 数字类型和字符串类型不能混排
            function compare(arr1, arr2) {
              var val1 = arr1[item];
              var val2 = arr2[item];
              if (!isNaN(val1) && !isNaN(val2)) {
                return val1 - val2;
              } else {
                if (val1 > val2) {
                  return 1;
                } else if (val1 < val2) {
                  return -1;
                } else if (val1 === val2) {
                  return 0;
                }
              }
            }
          }
        </script>
      </head>
      <body id="b1">
        <div>
          <input type="text" name="name" id="txt1" placeholder="姓名">
          <input type="text" name="age" id="txt2" placeholder="年龄">
          <input type="button" name="" id="btn1" value="增加">
        </div>
        <div>
          <input type="text" name="" id="txt3" value="张三 六 五">
          <input type="button" name="" id="btn2" value="筛选查询">
          <input type="button" name="" id="btn4" value="返回">
          <input type="button" name="" id="btn5" value="高亮查询">
        </div>
        <div>
          <input type="text" name="" id="txt4" placeholder="id">
          <input type="button" name="" id="btn3" value="删除">
        </div>
        <div>
          <input type="text" name="" id="txt5" value='1'>
          <input type="button" name="" id="btn6" value="排序">
        </div>
      </body>
    </html>
    

表单应用

  • 表单基础知识(本章学习事件的时候再详细说明)
    • 什么是表单
      • 向服务器提交数据,比如:用户注册
    • action: 提交到哪里
  • 表单事件
    • onsubmit:提交时发生
    • onreset:重置时发生
  • 表单内容验证
    • 阻止用户输入非法字符:阻止事件
    • 输入时、失去焦点时验证:onkeyuponblur
    • 提交时检查:onsubmit
    • 后台数据检查

JS 运动基础

运动基础

  • div 动起来
  • 速度:物体运动快慢
  • 运动中的 Bug
    • 不会停止
    • 速度取某些值会无法停止
    • 到达位置后点击还会运动
    • 重复点击速度加快
  • 匀速运动
    • 速度不变

运动框架及应用

  • 运动框架

    • 在开始运动时,关闭已有定时器
    • 把运动和停止隔开:if / else
  • 运动框架实例

    • 例子1:“分享到” 侧边栏
      • 通过目标点,计算速度值
    • 例子2:淡入淡出图片
      • 用变量储存透明度
      • filter:alpha(opacity=30); opacity: 0.3; IE 用前者
  • <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>运动框架及应用</title>
        <style>
          #div1 {
            width: 150px;
            height: 400px;
            background-color:cyan;
            position: absolute;
            left: -150px;
          }
          #div1 span {
            width: 20px;
            height: 60px;
            left: 150px;
            background-color:rgb(106, 176, 255);
            position: absolute;
            margin-top: 170px;
          }
          #div2 {
            left: 200px;
            position: absolute;
            filter:alpha(opacity=30);
            opacity: 0.3;
          }
        </style>
        <script>
          window.onload = function () {
            // 封装getElementById
            function get(id) {
              return document.getElementById(id);
            };
    
            var oDiv = get('div1');
            var timer = '';
            var speed = 0;
            var target = 0;
            // 运动框架
            function startMove(target) {
              clearInterval(timer);
              timer = setInterval(move, 30);
              function move() {
                if (oDiv.offsetLeft < target) {
                  speed = 10;
                  oDiv.style.left = oDiv.offsetLeft + speed + 'px';
                } else if (oDiv.offsetLeft > target) {
                  speed = -10;
                  oDiv.style.left = oDiv.offsetLeft + speed + 'px';
                } else if (oDiv.offsetLeft === target){
                  clearInterval(timer);
                }
              }
            }
            // 注册鼠标移入事件
            oDiv.onmouseover = function () {
              startMove(0);
            };
            oDiv.onmouseout = function () {
              startMove(-150);
            };
    
            // 图片淡入淡出
            var oDiv2 = get('div2');
            var alpha = 30;
            oDiv2.onmouseover = function () {
              shallow(100);
            }
            oDiv2.onmouseout = function () {
              shallow(30);
            }
            function shallow(target) {
              clearInterval(timer);
              timer = setInterval(shallowMove, 30);
              function shallowMove() {
                if (alpha === target) {
                  clearInterval(timer);
                } else if (alpha < target) {
                  speed = 10;
                  alpha += speed;
                  oDiv2.style.filter = 'alpha(opacity='+ alpha +')';
                  oDiv2.style.opacity = alpha/100;
                } else if (alpha > target) {
                  speed = -10;
                  alpha += speed;
                  oDiv2.style.filter = 'alpha(opacity='+ alpha +')';
                  oDiv2.style.opacity = alpha/100;
                }
              }
            }
          }
        </script>
      </head>
      <body>
        <div id="div1">
          <span>分享到</span>
        </div>
        <div id="div2"><img src="images/0.png" alt=""></div>
      </body>
    </html>
    

缓冲运动

  • 逐渐变慢,最后停止

  • 距离越大速度越大,速度取整

    • 速度由距离决定
    • 速度 = (目标值-当前值)/缩放系数
    • Math.ceil:向上取整
    • Math.floor:向下取整
  • 例子:缓冲菜单

    • Bug:速度取整 Math.ceilMath.floor

    • 跟随页面滚动的缓冲侧边栏

      • 潜在问题:目标不是整数时
      • 目标取整:parseInt()
    • scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
      
      • document.documentElement.scrollTop:IE、Firefox
      • document.body.scrollTop:chrome
  • Math.random()

    • 返回一个等于0小于1的一个随机浮点数

    • 说明:求 n到 m之间的

      随机整数的公式

      • random = Math.floor(Math.random()*(m-n+1)+n)
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <link rel="stylesheet" href="../reset.css">
        <title>缓冲运动及停止条件</title>
        <style>
          body {
            width: 800px;
            height: 2000px;
          }
          #div1 {
            width: 150px;
            height: 400px;
            background-color:cyan;
            position: absolute;
            left: -150px;
          }
          #div1 span {
            width: 20px;
            height: 60px;
            left: 150px;
            background-color:rgb(106, 176, 255);
            position: absolute;
            margin-top: 170px;
          }
          #div2 {
            top: 50px;
            left: 150px;
            position: absolute;
            filter:alpha(opacity=30);
            opacity: 0.3;
            width: 140px;
            height: 140px;
            background-color: red;
          }
          #div3 {
            width: 100px;
            height: 200px;
            background: rgb(99, 128, 255);
            position: absolute;
            right: 0px;
            bottom: 0px;
          }
          #div4 {
            width: 298px;
            height: 198px;
            border: rgb(0, 0, 0) solid 1px;
            position: absolute;
            left: 100px;
          }
        </style>
        <script>
          window.onload = function () {
            // 封装getElementById
            function get(id) {
              return document.getElementById(id);
            };
    
            var oDiv = get('div1');
            var timer = '';
    
            // 注册鼠标移入事件
            oDiv.onmouseover = function () {
              startMove(0, oDiv);
            };
            oDiv.onmouseout = function () {
              startMove(-150, oDiv);
            };
    
            // 图片淡入淡出
            var oDiv2 = get('div2');
            var alpha = 30;
            oDiv2.onmouseover = function () {
              shallow(100);
            }
            oDiv2.onmouseout = function () {
              shallow(30);
            }
            // 变浅函数
            function shallow(target) {
              clearInterval(timer);
              timer = setInterval(shallowMove, 30);
              function shallowMove() {
                speed = (target - alpha)/7;
                if (alpha === target) {
                  clearInterval(timer);
                } else if (alpha < target) {
                  alpha += speed;
                  oDiv2.style.filter = 'alpha(opacity='+ Math.ceil(alpha) +')';
                  oDiv2.style.opacity = Math.ceil(alpha)/100;
                } else if (alpha > target) {
                  alpha += speed;
                  oDiv2.style.filter = 'alpha(opacity='+ Math.floor(alpha) +')';
                  oDiv2.style.opacity = Math.floor(alpha)/100;
                }
              }
            }
    
            // 跟随页面滚动的缓冲侧边栏
    
            var oDiv3 = get('div3'); 
            window.onscroll = function () {
              var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
              var target = parseInt((document.documentElement.clientHeight - oDiv3.offsetHeight)/2 + scrollTop);
              scrollMove(target);
              console.log(
                '可视区:', document.documentElement.clientHeight,
                '滚动距离:', scrollTop, 
                'div3的高度:', oDiv3.offsetHeight, 
                '目标值:', target) 
            }
            // 纵向运动函数
            function scrollMove(target) {
              clearInterval(timer);
              timer = setInterval(scrollMoving, 30);
    
              function scrollMoving() {
                var speed = (target - oDiv3.offsetTop)/7;
                if (oDiv3.offsetTop === target) {
                  clearInterval(timer);
                } else if (oDiv3.offsetTop > target) {
                  oDiv3.style.top = oDiv3.offsetTop + Math.floor(speed) + 'px';
                } else if (oDiv3.offsetTop < target) {
                  oDiv3.style.top = oDiv3.offsetTop + Math.ceil(speed) + 'px';
                }
              }
            }
    
            // 运动停止的条件
            var btn1 = get('btn1');
            var btn2 = get('btn2');
            var btn3 = get('btn3');
            var btn4 = get('btn4');
            btn1.onclick = function () {
              startMove(100, oDiv2);
            }
            btn2.onclick = function () {
              startMove(400, oDiv2);
            }
            btn3.onclick = function () {
              startMove2(100, oDiv2);
            }
            btn4.onclick = function () {
              startMove2(400, oDiv2);
            }
            // 横向缓冲运动框架
            function startMove(target, div) {
              clearInterval(timer);
              timer = setInterval(move, 30);
              function move() {
                speed = (target - div.offsetLeft)/9;
                if (div.offsetLeft < target) {
                  div.style.left = div.offsetLeft + Math.ceil(speed) + 'px';
                } else if (div.offsetLeft > target) {
                  div.style.left = div.offsetLeft + Math.floor(speed) + 'px';
                } else if (div.offsetLeft === target){
                  clearInterval(timer);
                }
              }
            }
            // 横向匀速运动框架
            function startMove2(target, div) {
              clearInterval(timer);
              timer = setInterval(move2, 30);
              function move2() {
                // speed正向
                if (div.offsetLeft <= target) {
                  speed = 9;
                  moving();
                }
                // speed反向
                else if (div.offsetLeft >= target) {
                  speed = -9;
                  moving();
                } 
                function moving() {
                  if (Math.abs(target - div.offsetLeft) <= Math.abs(speed)) {
                    div.style.left = target + 'px'; // 直接到达
                    clearInterval(timer); // 停止
                  } else {
                    div.style.left = div.offsetLeft + speed + 'px';
                  }
                }
              }
            }
          }
        </script>
      </head>
      <body>
        <div id="div1">
          <span>分享到</span>
        </div>
        <div id="div2"><img src="images/0.png" alt=""></div>
        <div id="div3"></div>
        <div id="div4">
          <input type="button" name="" id="btn1" value="减速到100px">
          <input type="button" name="" id="btn2" value="减速到400px">
          <input type="button" name="" id="btn3" value="匀速到100px">
          <input type="button" name="" id="btn4" value="匀速到400px">
        </div>
        </div>
      </body>
    </html>
    

运动的停止条件

  • 运动终止条件
    • 匀速运动:两点足够近(直接改位置),Math.abs() 取绝对值
    • 缓冲运动:两点重合(取整后)
  • 代码:同上

JS 运动应用

多物体运动框架

  • 多个物体同时运动

    • 例子:多个

      div
      

      ,鼠标移入变宽

      • 单定时器,存在问题
      • 每个 div 一个定时器
  • 多物体运动框架

    • 定时器作为物体的属性

    • 参数的传递:物体、目标值

    • 例子:多个

      div
      

      淡入淡出

      • 所有东西都不能公用
      • 属性与运动对象绑定:速度、其它属性值(如透明度等)
  • 代码:同下

任意值运动框架

  • offset 属性的 Bug

    • 获取的是整个盒子模型的大小,有边框的 div 变宽
      • obj.currentStyle('name')getComputedStyle(obj,'').name代替 offset
  • 原有运动框架的问题

    • 只能让某个值运动起来
    • 如果想让其他值运动起来,要修改程序
  • 扩展的运动框架

    • 运动属性作为参数

    • 封装

      opacity
      
      • 小数精度问题:Math.round() 四舍五入取整
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <link rel="stylesheet" href="../reset.css">
        <title>缓冲运动及停止条件</title>
        <style>
          body {
            width: 800px;
            height: 2000px;
          }
          div {
            width: 100px;
            height: 100px;
            background-color: darkblue;
          }
          #div1 {
            position: absolute;
          }
          #div2 {       
            position: absolute;
            top: 110px;
          }
          #div3 {
            position: absolute;
            top: 220px;
          }
          #div4 {
            position: absolute;
            top: 330px;
            opacity: 0.3;
            filter: alpha(opacity=30);
          }
          #div5 {
            position: absolute;
            top: 440px;
            opacity: 0.3;
            filter: alpha(opacity=30);
          }
          #div6 {
            position: absolute;
            top: 550px;
            opacity: 0.3;
            filter: alpha(opacity=30);
          }
          #div7 {
            left: 400px;
            position: absolute;
          }
          #div8 {
            left: 510px;
            position: absolute;
            border: red solid 10px;
          }
          #div9 {
            left: 110px;
            top: 330px;
            position: absolute;
            color: seashell;
          }
          #div10 {
            left: 110px;
            top: 440px;
            position: absolute;
            border: rgb(255, 106, 0) solid 1px;
          }
          #div11 {
            left: 110px;
            top: 550px;
            position: absolute;
            opacity: 0.2;
            filter: alpha(opacity=20);
          }
        </style>
        <script>
          window.onload = function () {
            // 封装getElementById
            function get(id) {
              return document.getElementById(id);
            };
            // 封装获取计算后元素样式函数,返回小数
            function getStyle(obj, name) {
              if (obj.currentStyle) {
                return obj.currentStyle[name];
              } else {
                return getComputedStyle(obj, '') [name];
              }
            }
    
            //  多物体运动框架 offset 获取的是整个盒子的大小,无法通用
            // function startMove(obj, iTarget, name) {
            //   clearInterval(obj.timer);
            //   obj.timer = setInterval(move, 30);
            //   function move() {
            //     iTarget = parseInt(iTarget);
            //     var speed = (iTarget - obj['offset'+name])/7;  
            //     if (speed < 0) {
            //       speed = Math.floor(speed);
            //     } else {
            //       speed = Math.ceil(speed);
            //     }
            //     if (iTarget === obj['offset'+name]) {
            //       clearInterval(obj.timer);
            //     } else {
            //       obj.style[name.toLowerCase()] = obj['offset'+name] + speed + 'px'; 
            //     }
                
            //     console.log(iTarget,obj['offset'+name],speed)
            //   }
            // }
    
            // 任意值运动框架
            function startMove(obj, iTarget, name) {
              clearInterval(obj.timer);
              obj.timer = setInterval(move, 30);
              function move() {
                var objName = 0;
                if (name === 'opacity') {
                  // 用 parseFloat 保留小数并去掉后面 px ,从左至右提取数字,遇到不是数字跳出
                  // Math.round() 四舍五入取整 
                  objName = Math.round(parseFloat(getStyle(obj, name))*100);
                } else {
                  // 用 parseInt 去掉后面 px ,从左至右提取数字,遇到不是数字跳出
                  objName = parseInt(getStyle(obj, name));
                }
                var speed = (iTarget - objName)/7;  
                if (speed < 0) {
                  speed = Math.floor(speed);
                } else {
                  speed = Math.ceil(speed);
                }
                if (iTarget === objName) {
                  clearInterval(obj.timer);
                } else {
                  if (name === 'opacity') {
                    obj.style[name] = (objName + speed)/100;
                    obj.style.filter = "alpha("+[name]+ "=" + (objName + speed) + ")"; 
                  } else {
                    obj.style[name] = objName + speed + 'px'; 
                  }
                }
                console.log('iTarget',iTarget,'objName',objName,'getStyle',getStyle(obj, name),speed)
              }
            }
    
            var oDiv1 = get('div1');
            var oDiv2 = get('div2');
            var oDiv3 = get('div3');
            var oDiv7 = get('div7');
            var oDiv8 = get('div8');
            var oDiv9 = get('div9');
            var oDiv10 = get('div10');
            var oDiv11 = get('div11');
            // 变宽
            oDiv1.onmouseover = function () {
              startMove(oDiv1, 400, 'width')
            }
            oDiv1.onmouseout = function () {
              startMove(oDiv1, 100, 'width')
            }
            oDiv2.onmouseover = function () {
              startMove(oDiv2, 400, 'width')
            }
            oDiv2.onmouseout = function () {
              startMove(oDiv2, 100, 'width')
            }
            oDiv3.onmouseover = function () {
              startMove(oDiv3, 400, 'width')
            }
            oDiv3.onmouseout = function () {
              startMove(oDiv3, 100, 'width')
            }
            // 变高
            oDiv7.onmouseover = function () {
              startMove(oDiv7, 400, 'height')
            }
            oDiv7.onmouseout = function () {
              startMove(oDiv7, 100, 'height')
            }
            oDiv8.onmouseover = function () {
              startMove(oDiv8, 400, 'height')
            }
            oDiv8.onmouseout = function () {
              startMove(oDiv8, 100, 'height')
            }
            oDiv9.onmouseover = function () {
              startMove(oDiv9, 40, 'fontSize')
            }
            oDiv9.onmouseout = function () {
              startMove(oDiv9, 12, 'fontSize')
            }
            oDiv10.onmouseover = function () {
              startMove(oDiv10, 100, 'borderWidth')
            }
            oDiv10.onmouseout = function () {
              startMove(oDiv10, 1, 'borderWidth')
            }
            oDiv11.onmouseover = function () {
              startMove(oDiv11, 100, 'opacity')
            }
            oDiv11.onmouseout = function () {
              startMove(oDiv11, 20, 'opacity')
            }
    
            // 淡入淡出
            function shallowMove(obj, iTarget) {
              clearInterval(obj.timer);
              obj.timer = setInterval(move, 30);
              function move() {
                iTarget = parseInt(iTarget);
                var speed = (iTarget - obj.alpha)/7;  
                if (speed < 0) {
                  speed = Math.floor(speed);
                } else {
                  speed = Math.ceil(speed);
                }
                if (iTarget === obj.alpha) {
                  clearInterval(obj.timer);
                } else {
                  obj.alpha += speed;
                  obj.style.opacity = obj.alpha/100 ; 
                  obj.style.filter = "alpha(opacity="+ obj.alpha + ")";
                }
              }
            }
            var oDiv4 = get('div4');
            var oDiv5 = get('div5');
            var oDiv6 = get('div6');
            var aDiv = document.getElementsByTagName('div');
            for (var i in aDiv) {
              aDiv[i].alpha = 30;
            }
    
            oDiv4.onmouseover = function () {
              shallowMove(oDiv4, 100)
            }
            oDiv4.onmouseout = function () {
              shallowMove(oDiv4, 30)
            }
            oDiv5.onmouseover = function () {
              shallowMove(oDiv5, 100)
            }
            oDiv5.onmouseout = function () {
              shallowMove(oDiv5, 30)
            }
            oDiv6.onmouseover = function () {
              shallowMove(oDiv6, 100)
            }
            oDiv6.onmouseout = function () {
              shallowMove(oDiv6, 30)
            }
          }
        </script>
      </head>
      <body>
        <div id="div1"></div>
        <div id="div2"></div>
        <div id="div3"></div>
        <div id="div4"></div>
        <div id="div5"></div>
        <div id="div6"></div>
        <div id="div7"></div>
        <div id="div8"></div>
        <div id="div9">123adsfzv</div>
        <div id="div10"></div>
        <div id="div11"></div>
      </body>
    </html>
    

仿 Flash 图片展示

  • 效果思路

    • 两边的按钮:淡入淡出
    • 大图下拉:层级、高度变化
    • 下方的 li :多物体淡入淡出
    • 下方的 ul :位置计算
  • 左右按钮

    • 淡入淡出
      • 鼠标移动到按钮上,按钮会消失
        • 层级问题
        • 按钮和遮罩上都得加上事件
  • 下方 li 效果

    • 点击切换大图:选项卡
    • li 淡入淡出:移入移出
    • ul 移动:位置计算
  • 大图片切换

    • 图片层级:z-Index 一直 +1
    • 图片下拉效果(运动框架)
      • 可以改为淡入淡出
  • 加入自动播放

    • 和选项卡一样
  • 代码:

    <!DOCTYPE html>
    <html>
      <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
      <title>仿Flash图片展示</title>
      <link rel="stylesheet" href="../reset.css">
      <script src="./lib/move.js"></script>
      <style>
        body {
          width: 100%;
          height: 100%;
          background-color: cornsilk;
        }
        li {
          float: left;
        }
        /* 居中 div */
        #div_center {
          margin: 20px auto;
          width: 640px;
          height: 450px;
        }
        /* 定位 div */
        #div_position {
          width: 640px;
          height: 450px;
          overflow: hidden;
          background-color: rgb(70, 70, 70);
          position: absolute;
        }
    
        /* 大图样式 */
        #div_pic {
          width: 640px;
          height: 360px;
          overflow: hidden;
          position: relative;
        }
        .ul_pic {
          position: absolute;
        }
        .li_pic {
          position: absolute;
        }
        .li_pic img{
          width: 640px;
          height: 360px;
        }
    
        /* 左右键样式 */
        .ul_btn {
          top: 0px;
          width: 640px;
          height: 360px;
          position: absolute;
          float: left;
        }
        .slider_btn_left, .slider_btn_right {
          width: 150px;
          height: 360px;
        }
        .slider_btn_right {
          float: right;
        }
        .slider_btn_left img{
          padding: 150px 105px 150px 10px ;
          position: relative;
          width: 35px;
          height: 60px;
          opacity: 0;
          filter: alpha(opacity=0);
          float: left;
        }
        .slider_btn_right img{
          padding: 150px 10px 150px 105px ;
          position: relative;
          width: 35px;
          height: 60px;
          opacity: 0;
          filter: alpha(opacity=0);
          float: right;
        }
    
        /* 小图样式 */
        #div_thumbnail {
          width: 620px;
          background-color: rgb(70, 70, 70);
          margin: 0 10px 0 5px;
          overflow: hidden;
          position: relative;
        }
        .ul_thumbnail {
          width: 640px;
          height: 90px;
        }
        .li_thumnali {
          opacity: 0.5;
          filter: alpha(opacity=50);
        }
        .li_thumnali img{
          padding: 10px 0px 10px 10px;
          width: 125px;
          height: 70px;
        }
    
        /* 图片文字栏 */
        .ul_txt {
          width: 640px;
          height: 20px;
          position: absolute;
          top: 340px;
        }
        .li4_background {
          width: 640px;
          height: 20px;
          top: 0px;
          background-color: rgb(0, 0, 0);
          opacity: 0.5;
          filter: alpha(opacity=50);
        }
        .li4_introduction {
          top: -17px;
          margin-left: 10px;
          width: 500px;
          position: relative;
          color: rgb(255, 255, 255);
          filter: alpha(opacity=80);
          opacity: 0.8;
        }
        .li4_sum_num {
          width: 120px;
          top: -17px;
          left: 10px;
          position: relative;
          color: rgb(255, 255, 255);
          filter: alpha(opacity=80);
          opacity: 0.8;
        }
      </style>
      <script>
      window.onload = function () {
        // 封装 getElementById
        function get(id) {
          return document.getElementById(id);
        }
        // 封装 getElementsByTagName
        function gets(tagName) {
          return document.getElementsByTagName(tagName)
        }
        // 封装 getByClassName 方法
        function getByClassName(oParent, sClass) {
          var aResult = new Array();
          var aEle = document.getElementsByTagName('*');
          for (var i in aEle) {
            if (aEle[i].className === sClass) {
              aResult.push(aEle[i]);
            }
          }
          return aResult;
        }
    
        // 左右箭头切换图片
        // 获取箭头所在 ul
        var oDiv_position = get('div_position');
        var ul_btn = getByClassName(oDiv_position[1], 'ul_btn')[0];
        // 获取 li
        var li_btn_left = getByClassName(ul_btn, 'slider_btn_left')[0];
        var li_btn_right = getByClassName(ul_btn, 'slider_btn_right')[0];
        // 获取 img
        var left_icon = getByClassName(li_btn_left, 'left_icon')[0];
        var right_icon = getByClassName(li_btn_right, 'right_icon')[0];
        // 鼠标移入/移出 显示/隐藏
        li_btn_left.onmouseover = left_icon.onmouseover = function () {
          startMove(left_icon, 'opacity', 30);
        }
        li_btn_left.onmouseout = left_icon.onmouseout = function () {
          startMove(left_icon, 'opacity', 0);
        }
        li_btn_right.onmouseover = right_icon.onmouseover = function () {
          startMove(right_icon, 'opacity', 30);
        }
        li_btn_right.onmouseout = right_icon.onmouseout = function () {
          startMove(right_icon, 'opacity', 0);
        }
    
        // 获取大图 class li
        var ul_pic = getByClassName(oDiv_position[1], 'ul_pic')[0];
        var oli_pic = getByClassName(ul_pic, 'li_pic');
        var oImg = gets('img');
    
        // 获取缩略图 class li
        var div_thumbnail = get('div_thumbnail');
        var ul_thumbnail = getByClassName(div_thumbnail, 'ul_thumbnail')[0];
        var oli_thumnali = getByClassName(ul_thumbnail, 'li_thumnali');
        var pic_index = 0;
        var index = 0;
        var z = 1;
        // 缩略图鼠标移入高亮,移出恢复,并注册index 绑定大图
        for (var i in oli_thumnali) {
          oli_thumnali[i].index = i;
          oli_pic[i].index = i;
          // 鼠标移入
          oli_thumnali[i].onmouseover = function () {
            startMove(this, 'opacity', 100);
          }
          // 鼠标移出 如果是当前显示则不执行
          oli_thumnali[i].onmouseout= function () {
            if (oli_pic[this.index].style.zIndex != z) {
              startMove(this, 'opacity', 50);
            }
          }
          // 点击小图片显示大图
          oli_thumnali[i].onclick = function () {
            console.log(pic_index,parseInt(this.index))
            // 如果点击 this.index > 2 && this.index - pic_index > 0 则向右移
            if (parseInt(this.index) > 2 && this.index - pic_index >0) {
              pic_index = parseInt(this.index);
              // 下一张会 ++ 先--
              pic_index--;
              right_icon.onclick();
            } // 如果  this.index > 2 && this.index - pic_index < 0 则向左移
            else if (this.index > 0 && this.index - pic_index < 0) {
              pic_index = parseInt(this.index);
              // 下一张会 -- 先++
              pic_index++;
              left_icon.onclick();
            } else {
              pic_index = parseInt(this.index);
              tab();
            }
          }
          // 让第一个图片显示
          if (oli_pic[i].style.zIndex == z) {
            startMove(oli_thumnali[i], 'opacity', 100);
          }
        }
        // 鼠标点击按钮 上一张/下一张
        left_icon.onclick = function () {
          // 是否 <0
          if (0 <= pic_index - 1) {
            // console.log('1~length-1:',pic_index)
            pic_index--;
            if (0 < pic_index && pic_index <= oli_thumnali.length - 1) {
              // 1~length-1
              startMove(ul_thumbnail, 'marginLeft', -(pic_index-1)*li_thumbnali_width);
              tab(); 
            } else {
              // 0 
              tab();
            }
          } else {
            // <0 重置pic_index循环播放
            // console.log('0:',pic_index)
            pic_index = oli_thumnali.length - 1;
            startMove(ul_thumbnail, 'marginLeft', -(pic_index-2)*li_thumbnali_width);
            tab();
          }
        }
        right_icon.onclick = function () {
          // 判断下一张是否大于总数
          if (pic_index + 1 < oli_thumnali.length) {
            pic_index++;
            // console.log('1~oli_thumnali.length-1:',pic_index);
            if (2 < pic_index && pic_index <= oli_thumnali.length - 1) {
              startMove(ul_thumbnail, 'marginLeft', -(pic_index-2)*li_thumbnali_width);
              tab(); 
            } else {
              tab();
            }
          } else {
            // 大于 oli_thumnali.length-1 跳到第一张
            pic_index = 0;
            startMove(ul_thumbnail, 'marginLeft', pic_index*li_thumbnali_width);
            tab();
          }
        }
        
        function tab() {
          // 判断是否是当前显示图片
          if (oli_pic[pic_index].style.zIndex != z) {
            // 全部图片半透明
            for (var j in oli_thumnali) {
              startMove(oli_thumnali[j], 'opacity', 50);
            }
            // 显示当前点击图片
            startMove(oli_thumnali[pic_index], 'opacity', 100);
            // 显示当前index对应大图
            oli_pic[pic_index].style.zIndex = ++z;
            // 显示文字的按钮
            ul_btn.style.zIndex = ul_txt.style.zIndex = z;
            // 隐藏大图 再用动画显示
            oImg[pic_index].style.height = 0;
            startMove(oImg[pic_index],'height', 360);
            // 显示当前图片介绍
            introduction.innerHTML = arr[pic_index];
            sum_num.innerHTML = parseInt(pic_index) + 1 + '/' + oli_thumnali.length;
          }
        }
    
        // 自动播放
        oDiv_position.timer = setInterval(right_icon.onclick, 2000);
        oDiv_position.onmouseover = function () {
          clearInterval(oDiv_position.timer);
        }
        oDiv_position.onmouseout = function () {
          clearInterval(oDiv_position.timer);
          oDiv_position.timer = setInterval(right_icon.onclick, 2000);
        }
        // 设置 ul_thumbnail 的宽度
        var li_thumbnali_width = oli_thumnali[0].offsetWidth;
        ul_thumbnail.style.width = oli_thumnali.length * oli_thumnali[0].offsetWidth + 'px';
    
        // 设置文字说明
        var arr = new Array('雪山','峡谷','悬崖','岩壁','海岸','雪覆盖的悬崖','雪山','峡谷','悬崖','岩壁','海岸','雪覆盖的悬崖');
        // 获取文字说明 li
        var ul_txt = getByClassName(oDiv_position[1], 'ul_txt')[0];
        var introduction = getByClassName(ul_txt, 'introduction')[0];
        var sum_num = getByClassName(ul_txt, 'sum_num')[0];
        sum_num.innerHTML = pic_index + 1 + '/' + oli_thumnali.length;
        introduction.innerHTML = arr[pic_index];
      }
      </script>
      <body>
        <div id="div_center">
          <div id="div_position">
            <div id="div_pic">
              <ul class="ul_pic">
                <li class="li_pic" style="z-index:1"><img src="./images/album/1.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/2.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/3.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/4.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/5.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/6.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/2.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/5.jpeg" alt=""></li>
              </ul>
            </div>
            <ul class="ul_btn" style="z-index:1">
              <li class="slider_btn_left"><img class="left_icon" src="./images/images/slider_btn_icon_left.png" alt=""></li>
              <li class="slider_btn_right"><img class="right_icon" src="./images/images/slider_btn_icon_right.png" alt=""></li>
            </ul>
            <ul class="ul_txt" style="z-index:1">
              <li class="li4_background"></li>
              <li class="li4_introduction">图片说明:<span class="introduction">introduction</span></li>
              <li class="li4_sum_num">图片位置:<span class="sum_num"></span></li>
            </ul>
            <div id="div_thumbnail">
              <ul class="ul_thumbnail">
                <li class="li_thumnali"><img src="./images/album/1.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/2.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/3.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/4.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/5.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/6.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/2.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/5.jpeg" alt=""></li>
              </ul>
            </div>
          </div>
        </div>
      </body>
    </html>
    
  • // ./lib/move.js
    // 封装获取计算后元素样式函数,返回小数
    function getStyle(obj, name) {
      if (obj.currentStyle) {
        return obj.currentStyle[name];
      } else {
        return getComputedStyle(obj, '') [name];
      }
    }
            // 任意值运动框架
    function startMove(obj, name, iTarget ) {
      clearInterval(obj.timer);
      obj.timer = setInterval(move, 30);
      function move() {
        var current = 0;
        if (name === 'opacity') {
          // 用 parseFloat 保留小数并去掉后面 px ,从左至右提取数字,遇到不是数字跳出
          // Math.round() 四舍五入取整 
          current = Math.round(parseFloat(getStyle(obj, name))*100);
        } else {
          // 用 parseInt 去掉后面 px ,从左至右提取数字,遇到不是数字跳出
          current = parseInt(getStyle(obj, name));
        }
        var speed = (iTarget - current)/3;  
        if (speed < 0) {
          speed = Math.floor(speed);
        } else {
          speed = Math.ceil(speed);
        }
        if (iTarget === current) {
          clearInterval(obj.timer);
        } else {
          if (name === 'opacity') {
            obj.style[name] = (current + speed)/100;
            obj.style.filter = "alpha("+[name]+ "=" + (current + speed) + ")"; 
          } else {
            obj.style[name] = current + speed + 'px'; 
          }
        }
        // console.log('iTarget',iTarget,'current',current,'getStyle',getStyle(obj, name),speed)
      }
    }
    
  • 笔记:不让子元素继承父元素的 opacity属性

    • 使用 rgba(R,G,B,opacity) 间接的设定 opacity 的值,这个属性不会向下继承
    • 或者把 opacity 属性放到同级元素实现
  • 笔记:父级使用相对定位,子级才能在范围内绝对定位

JS 运动中级

链式运动框架

  • 回调函数:

    startMove(obj, attr, iTarget, fn)
    
    • 运动停止时,执行函数
    • 运动停止时,开始下一次运动
    • 例子:土豆网右下角菜单

完美运动框架

  • 多个值同时变化:startMove(obj, json)

    • setStyle
      

      同时设置多个属性

      • 参数传递:
        • JSON 的使用
        • for in 遍历属性
  • 运用到运动框架

  • 检测运动停止

    • 标志变量
  • 例子:伸缩同时淡入淡出的菜单

  • 代码:

    // ./lib/move2.js
    // 封装获取计算后元素样式函数,返回小数
    function getStyle(obj, name) {
      if (obj.currentStyle) {
        return obj.currentStyle[name];
      } else {
        return getComputedStyle(obj, '') [name];
      }
    }
            // 任意值运动框架
    function startMove(obj, json, fnEnd ) {
      clearInterval(obj.timer);
      obj.timer = setInterval(move, 30);
      function move() {
        var current = 0;
        var stop = true;
        for (const attr in json) {
          if (attr === 'opacity') {
            // 用 parseFloat 保留小数并去掉后面 px ,从左至右提取数字,遇到不是数字跳出
            // Math.round() 四舍五入取整 
            current = Math.round(parseFloat(getStyle(obj, attr))*100);
          } else {
            // 用 parseInt 去掉后面 px ,从左至右提取数字,遇到不是数字跳出
            current = parseInt(getStyle(obj, attr));
          }
          var speed = (json[attr] - current)/4;  
          if (speed < 0) {
            speed = Math.floor(speed);
          } else {
            speed = Math.ceil(speed);
          }
          if (json[attr] === current) {
            stop = true;
          } else {
            stop = false;
            if (attr === 'opacity') {
              obj.style[attr] = (current + speed)/100;
              obj.style.filter = "alpha("+[attr]+ "=" + (current + speed) + ")"; 
            } else {
              obj.style[attr] = current + speed + 'px'; 
            }
          }
          console.log('json[attr]:',json[attr],'attr:', attr,'current:',current,'getStyle:',getStyle(obj, attr),'speed:',speed);
        }
        if (stop === true) {
          clearInterval(obj.timer);
          if (fnEnd) {
            fnEnd()
          }
        }
      }
    }
    
  • <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>链式运动框架</title>
        <style>
          body {
            width: auto;
            height: 2000px;
          }
          #div1 {
            width: 50px;
            height: 50px;
            background: rgb(99, 128, 255);
            position: absolute;
          }
          #div_p {
            width: 50px;
            height: 50px;
            background-color: cornsilk;
            position: absolute;
            right: 0;
            top: 50%;
          }
          #div2 {
            width: 50px;
            height: 50px;
            background: rgb(99, 128, 255);
            position: absolute;
          }
          #div3 {
            position: absolute;
            height: 50px;
            width: 0px;
            right: 50px;
            background-color: rgb(119, 95, 255);
            overflow: hidden;
          }
          #div4 {
            position: absolute;
            width: 100px;
            height: 0px;
            right: 50px;
            top: 0px;
            overflow: hidden;
            background-color: rgb(98, 163, 248);
          }
          #close {
            position: absolute;
            float: right;
            right: 5px;
            color: white;
          }
        </style>
        <script src="./lib/move2.js"></script>
        <script>
        window.onload = function () {
          // 封装 getElementById
          function get(id) {
            return document.getElementById(id);
          }
    
          var btn1 = get('btn1');
          var div1 = get('div1');
          btn1.onclick = function () {
            startMove(div1,{'height': 400, "width": 101, "opacity": 30, "left": 100, "top": 200}, msg);
          }
          function msg() {
            console.log('链式函数执行完成!')
          }
    
          // 跟随页面滚动的缓冲侧边栏
          var div_p = get('div_p');
          window.onscroll = function () {
            var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
            var odiv_pHeight = parseInt(getStyle(div_p, 'height'));
            var target = parseInt((document.documentElement.clientHeight - odiv_pHeight)/2 + scrollTop);
            startMove(div_p, {"top":target});
            console.log(
              '可视区:', document.documentElement.clientHeight,
              '滚动距离:', scrollTop, 
              'div3的高度:', getStyle(div_p, 'height'), 
              '目标值:', target) 
          }
    
          // 土豆伸缩菜单栏
          var div2 = get('div2'); 
          var div3 = get('div3');
          var div4 = get('div4');
          var close = get('close');
          div2.onclick = function () {
            // div3.style.display = 'block';
            // div4.style.display = 'block';
            startMove(div3, {"width":100},fnEnd)
            function fnEnd() {
              startMove(div4,{"height":100, "top":-100})
            }
          }
          close.onclick = function () {
            startMove(div4, {"top": 0, "height": 0}, fnEnd);
            function fnEnd() {
            startMove(div3, {"width":0})
            }
          }
        }
        </script>
      </head>
      <body>
        <input type="button" id="btn1" value="链式运动">
        <div id="div1"></div>
        <div id="div_p">
          <div id="div2">土豆</div>
          <div id="div3">播放器</div>
          <div id="div4"><a id="close" href="javascript:;">关闭</a></div>
        </div>
      </body>
    </html>
    

运动框架总结

  • 运动框架演变过程
    • startMove(iTarget) :运动框架
    • startMove(obj, iTarget) :多物体
    • startMove(obj, attr, iTarget) :任意值
    • startMove(obj, attr, iTarget, fn) :链式运动
    • startMove(obj, json) :多值运动
    • startMove(obj, json, fn) :完美运动框架

运动框架应用

  • 运动框架应用

    • 例子:幻灯片
  • 例子:新浪微博

    • 链式运动

    • 笔记:CSS white-space 属性 保留换行

      值			描述
      normal		默认。空白会被浏览器忽略。
      pre			空白会被浏览器保留。其行为方式类似 HTML 中的 <pre> 标签。
      nowrap		文本不会换行,文本会在在同一行上继续,直到遇到 <br> 标签为止。
      pre-wrap	保留空白符序列,但是正常地进行换行。
      pre-line	合并空白符序列,但是保留换行符。
      inherit		规定应该从父元素继承 white-space 属性的值。
      
  • 代码:

    <!DOCTYPE html>
    <html>
      <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
      <title>幻灯片上下滑动和新浪微博效果</title>
      <link rel="stylesheet" href="../reset.css">
      <link rel="stylesheet" href="./css/18.1.css">
      <script src="./lib/move2.js"></script>
      <script>
      window.onload = function () {
        // 封装 getElementById
        function get(id) {
          return document.getElementById(id);
        }
        // 封装 getElementsByTagName
        function gets(tagName) {
          return document.getElementsByTagName(tagName)
        }
        // 封装 getByClassName 方法
        function getByClassName(oParent, sClass) {
          var aResult = new Array();
          var aEle = document.getElementsByTagName('*');
          for (var i in aEle) {
            if (aEle[i].className === sClass) {
              aResult.push(aEle[i]);
            }
          }
          return aResult;
        }
    
        // 左右箭头切换图片
        // 获取箭头所在 ul
        var oDiv_position = get('div_position');
        var ul_btn = getByClassName(oDiv_position[1], 'ul_btn')[0];
        // 获取 li
        var li_btn_left = getByClassName(ul_btn, 'slider_btn_left')[0];
        var li_btn_right = getByClassName(ul_btn, 'slider_btn_right')[0];
        // 获取 img
        var left_icon = getByClassName(li_btn_left, 'left_icon')[0];
        var right_icon = getByClassName(li_btn_right, 'right_icon')[0];
        // 鼠标移入/移出 显示/隐藏
        li_btn_left.onmouseover = left_icon.onmouseover = function () {
          startMove(left_icon, {'opacity': 30});
        }
        li_btn_left.onmouseout = left_icon.onmouseout = function () {
          startMove(left_icon, {'opacity': 0});
        }
        li_btn_right.onmouseover = right_icon.onmouseover = function () {
          startMove(right_icon, {'opacity': 30});
        }
        li_btn_right.onmouseout = right_icon.onmouseout = function () {
          startMove(right_icon, {'opacity': 0});
        }
    
        // 获取大图 class li
        var ul_pic = getByClassName(oDiv_position[1], 'ul_pic')[0];
        var oli_pic = getByClassName(ul_pic, 'li_pic');
        var oImg = gets('img');
    
        // 获取缩略图 class li
        var div_thumbnail = get('div_thumbnail');
        var ul_thumbnail = getByClassName(div_thumbnail, 'ul_thumbnail')[0];
        var oli_thumnali = getByClassName(ul_thumbnail, 'li_thumnali');
        var pic_index = 0;
        var index = 0;
        var z = 1;
        // 缩略图鼠标移入高亮,移出恢复,并注册index 绑定大图
        for (var i in oli_thumnali) {
          oli_thumnali[i].index = i;
          oli_pic[i].index = i;
          // 鼠标移入
          oli_thumnali[i].onmouseover = function () {
            startMove(this, {'opacity': 100});
          }
          // 鼠标移出 如果是当前显示则不执行
          oli_thumnali[i].onmouseout= function () {
            if (oli_pic[this.index].style.zIndex != z) {
              startMove(this, {'opacity': 50});
            }
          }
          // 点击小图片显示大图
          oli_thumnali[i].onclick = function () {
            console.log(pic_index,parseInt(this.index))
            // 如果点击 this.index > 2 && this.index - pic_index > 0 则向右移
            if (parseInt(this.index) > 2 && this.index - pic_index >0) {
              pic_index = parseInt(this.index);
              // 下一张会 ++ 先--
              pic_index--;
              right_icon.onclick();
            } // 如果  this.index > 0 && this.index - pic_index < 0 则向左移
            else if (this.index > 0 && this.index - pic_index < 0) {
              pic_index = parseInt(this.index);
              // 下一张会 -- 先++
              pic_index++;
              left_icon.onclick();
            } else {
              pic_index = parseInt(this.index);
              tab();
            }
          }
          // 让第一个图片显示
          if (oli_pic[i].style.zIndex == z) {
            startMove(oli_thumnali[i], {'opacity': 100});
          }
        }
        // 鼠标点击按钮 上一张/下一张
        var slide = ''; // 滑动方向
        left_icon.onclick = function () {
          // 是否 <0
          if (0 <= pic_index - 1) {
            // console.log('1~length-1:',pic_index)
            pic_index--;
            if (0 < pic_index && pic_index <= oli_thumnali.length - 1) {
              // 1~length-1
              startMove(ul_thumbnail, {'marginLeft': -(pic_index-1)*li_thumbnali_width});
              // 向右滑动特效
              slide = 'right';
              tab(); 
            } else {
              // 0 
              slide = 'right';
              tab();
            }
          } else {
            // <0 重置pic_index循环播放
            // console.log('0:',pic_index)
            pic_index = oli_thumnali.length - 1;
            startMove(ul_thumbnail, {'marginLeft': -(pic_index-2)*li_thumbnali_width});
            tab();
          }
        }
        right_icon.onclick = function () {
          // 判断下一张是否大于总数
          if (pic_index + 1 < oli_thumnali.length) {
            pic_index++;
            // console.log('1~oli_thumnali.length-1:',pic_index);
            if (2 < pic_index && pic_index <= oli_thumnali.length - 1) {
              startMove(ul_thumbnail, {'marginLeft': -(pic_index-2)*li_thumbnali_width});
              // 向左滑动特效
              slide = 'left';
              tab(); 
            } else {
              slide = 'left';
              tab();
            }
          } else {
            // 大于 oli_thumnali.length-1 跳到第一张
            pic_index = 0;
            startMove(ul_thumbnail, {'marginLeft': pic_index*li_thumbnali_width});
            tab();
          }
        }
        
        function tab() {
          // 判断是否是当前显示图片
          if (oli_pic[pic_index].style.zIndex != z) {
            // 全部图片半透明
            for (var j in oli_thumnali) {
              startMove(oli_thumnali[j], {'opacity': 50});
            }
            // 显示当前点击图片
            startMove(oli_thumnali[pic_index], {'opacity': 100});
            // 显示当前index对应大图
            oli_pic[pic_index].style.zIndex = ++z;
            // 显示文字的按钮
            ul_btn.style.zIndex = ul_txt.style.zIndex = z;
            // 隐藏大图 再用动画显示
            // oImg[pic_index].style.height = 0;
            // oli_pic[pic_index].style.top = '-360px';
            // oImg[pic_index].style.width = '0px';
            // startMove(oImg[pic_index],{"width": 640, "height": 360});
            if (slide === 'left') {
              oli_pic[pic_index].style.left = '640px';
              startMove(oli_pic[pic_index],{"left": 0});
              // 判断还有没有下一张 两张拼接
              if (pic_index-1 > 0 && pic_index+1 < oli_pic.length)
              startMove(oli_pic[pic_index-1],{"left": -640});
            } else if (slide === 'right') {
              oli_pic[pic_index].style.left = '-640px';
              startMove(oli_pic[pic_index],{"left": 0});
              // 判断还有没有下一张 两张拼接
              if (pic_index+1 < oli_pic.length) {
                startMove(oli_pic[pic_index+1],{"left": 640});
              }
            } else {
              oImg[pic_index].style.height = '0px';
              startMove(oImg[pic_index],{"height": 360});
            }
    
            // 显示当前图片介绍
            introduction.innerHTML = arr[pic_index];
            sum_num.innerHTML = parseInt(pic_index) + 1 + '/' + oli_thumnali.length;
          }
        }
    
        // 自动播放
        oDiv_position.timer = setInterval(right_icon.onclick, 2000);
        oDiv_position.onmouseover = function () {
          clearInterval(oDiv_position.timer);
        }
        oDiv_position.onmouseout = function () {
          clearInterval(oDiv_position.timer);
          oDiv_position.timer = setInterval(right_icon.onclick, 2000);
        }
        // 设置 ul_thumbnail 的宽度
        var li_thumbnali_width = oli_thumnali[0].offsetWidth;
        ul_thumbnail.style.width = oli_thumnali.length * oli_thumnali[0].offsetWidth + 'px';
    
        // 设置文字说明
        var arr = new Array('雪山','峡谷','悬崖','岩壁','海岸','雪覆盖的悬崖','雪山','峡谷','悬崖','岩壁','海岸','雪覆盖的悬崖');
        // 获取文字说明 li
        var ul_txt = getByClassName(oDiv_position[1], 'ul_txt')[0];
        var introduction = getByClassName(ul_txt, 'introduction')[0];
        var sum_num = getByClassName(ul_txt, 'sum_num')[0];
        sum_num.innerHTML = pic_index + 1 + '/' + oli_thumnali.length;
        introduction.innerHTML = arr[pic_index];
    
        // 新浪微博新微博效果 评论区
        var div_com_show = get('div_com_show');
        var text_comment = get('text_comment');
        var btn_comment = get('btn_comment');
        btn_comment.onclick = function () {
          // 1.创建子节点 2.文字添加到子节点 3.设置样式 
          // 4.渲染子节点 5.设置透明度并获取高度 6.链式动画
          var oLi = document.createElement('li');
          oLi.innerHTML = text_comment.value;
          oLi.className = 'li_comment'; 
          text_comment.value = '';
          if (div_com_show.children.length > 0) {
            div_com_show.insertBefore(oLi, div_com_show.children[0]);
          } else {
            div_com_show.appendChild(oLi);
          }
          // var iHeight = parseInt(oLi.offsetHeight) - 20; // 多算了padding
          var iHeight = parseInt(getStyle(oLi, 'height'));
          div_com_show.children[0].style.height = '0';
          startMove(oLi,{"height": iHeight}, function fn() {
            startMove(oLi,{"opacity":100});
          })
          
        }
      }
      </script>
      <body>
        <div id="div_center">
          <div id="div_position">
            <div id="div_pic">
              <ul class="ul_pic">
                <li class="li_pic" style="z-index:1"><img src="./images/album/1.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/2.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/3.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/4.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/5.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/6.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/2.jpeg" alt=""></li>
                <li class="li_pic"><img src="./images/album/5.jpeg" alt=""></li>
              </ul>
            </div>
            <ul class="ul_btn" style="z-index:1">
              <li class="slider_btn_left"><img class="left_icon" src="./images/images/slider_btn_icon_left.png" alt=""></li>
              <li class="slider_btn_right"><img class="right_icon" src="./images/images/slider_btn_icon_right.png" alt=""></li>
            </ul>
            <ul class="ul_txt" style="z-index:1">
              <li class="li4_background"></li>
              <li class="li4_introduction">图片说明:<span class="introduction">introduction</span></li>
              <li class="li4_sum_num">图片位置:<span class="sum_num"></span></li>
            </ul>
            <div id="div_thumbnail">
              <ul class="ul_thumbnail">
                <li class="li_thumnali"><img src="./images/album/1.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/2.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/3.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/4.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/5.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/6.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/2.jpeg" alt=""></li>
                <li class="li_thumnali"><img src="./images/album/5.jpeg" alt=""></li>
              </ul>
            </div>
            <div id="div_comments">
              <div id="div_com_inp">
                <textarea class="text" name="" id="text_comment" cols="60" rows="5"></textarea>
                <input class="btn" type="button" name="" id="btn_comment" value="发表评论">
              </div>
              <div id="div_com_show">
              </div>
            </div>
          </div>
        </div>
      </body>
    </html>
    
  • /* 18.1.css */
      body {
          width: 100%;
          height: 100%;
          background-color: cornsilk;
      }
      li {
          float: left;
      }
      /* 居中 div */
      #div_center {
          margin: 20px auto;
          width: 640px;
          height: 450px;
      }
      /* 定位 div */
      #div_position {
          width: 640px;
          height: 1100px;
          overflow: hidden;
          background-color: rgb(70, 70, 70);
          position: absolute;
      }
      
      /* 大图样式 */
      #div_pic {
          width: 640px;
          height: 360px;
          overflow: hidden;
          position: absolute;
      }
      .ul_pic {
          position: absolute;
      }
      .li_pic {
          position: absolute;
      }
      .li_pic img{
          width: 640px;
          height: 360px;
      }
      
      /* 左右键样式 */
      .ul_btn {
          top: 0px;
          width: 640px;
          height: 360px;
          position: absolute;
          float: left;
      }
      .slider_btn_left, .slider_btn_right {
          width: 150px;
          height: 360px;
      }
      .slider_btn_right {
          float: right;
      }
      .slider_btn_left img{
          padding: 150px 105px 150px 10px ;
          position: relative;
          width: 35px;
          height: 60px;
          opacity: 0;
          filter: alpha(opacity=0);
          float: left;
      }
      .slider_btn_right img{
          padding: 150px 10px 150px 105px ;
          position: relative;
          width: 35px;
          height: 60px;
          opacity: 0;
          filter: alpha(opacity=0);
          float: right;
      }
      
      /* 小图样式 */
      #div_thumbnail {
          top: 360px;
          width: 620px;
          background-color: rgb(70, 70, 70);
          margin: 0 10px 0 5px;
          overflow: hidden;
          position: absolute;
      }
      .ul_thumbnail {
          width: 640px;
          height: 90px;
      }
      .li_thumnali {
          opacity: 0.5;
          filter: alpha(opacity=50);
      }
      .li_thumnali img{
          padding: 10px 0px 10px 10px;
          width: 125px;
          height: 70px;
      }
      
      /* 图片文字栏 */
      .ul_txt {
          width: 640px;
          height: 20px;
          position: absolute;
          top: 340px;
      }
      .li4_background {
          width: 640px;
          height: 20px;
          top: 0px;
          background-color: rgb(0, 0, 0);
          opacity: 0.5;
          filter: alpha(opacity=50);
      }
      .li4_introduction {
          top: -17px;
          margin-left: 10px;
          width: 500px;
          position: relative;
          color: rgb(255, 255, 255);
          filter: alpha(opacity=80);
          opacity: 0.8;
      }
      .li4_sum_num {
          width: 120px;
          top: -17px;
          left: 10px;
          position: relative;
          color: rgb(255, 255, 255);
          filter: alpha(opacity=80);
          opacity: 0.8;
      }
      
      /* 评论区 */
      #div_comments {
          position: absolute;
          display: block;
          top: 450px;
          padding-top: 20px;
          width: 640px;
          background-color: rgb(252, 229, 200);
      }
      #div_com_inp  {
          margin-top: 5px;
          border-top: burlywood dashed 1px;
          border-bottom: burlywood dashed 1px;
      }
      .text {
          margin: 20px 0 20px 53px;
      }
      .btn {
          margin: 20px 0 20px 20px;
          width: 70px;
          height: 70px;
      }
      #div_com_show {
          height: 475px;
          margin: 20px 50px;
          padding: 0px 20px;
          background-color: rgb(255, 255, 255);
          overflow: hidden;
      }
      .li_comment {
          white-space: pre-wrap;
          padding: 10px 5px;
          float: none;
          border-bottom: cadetblue dashed 1px;
          opacity: 0;
          filter: alpha(opacity=0);
          overflow: hidden;
      }
    

JS事件基础

Event 对象和事件冒泡

  • 什么是 Event 对象

    • 用来获取鼠标/键盘事件的信息:鼠标位置、键盘按键

    • 例子:获取鼠标位置:clientX

    • document
      

      的本质是整个网页:

      document.childNodes[0].tagName = '<!DOCTYPE>'
      
      • body 不加事件,因为没有内容就没高度
  • 获取 Event 对象**(兼容性写法)**

    • var oEvent = ev||event; 火狐用 ev / IE 用 event
    • 事件函数把事件对象最为参数传入:btn.onclick = function(ev) { var oEvent = ev||event;}
  • 事件流

    • 事件流冒泡:事件往父级传递
      • 取消冒泡:oEvent.cancelBubble = true
      • 例子:仿 select 控件
      • DOM 事件流
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>键盘事件和仿select下拉框</title>
        <link rel="stylesheet" href="../reset.css">
        <style>
          #div1 {
            width: 200px;
            height: 200px;
            position: absolute;
            background-color: rgb(255, 0, 0);
            display: none;
          }
        </style>
        <script>
        // 封装 getElementById 函数
        function get(id) {
            return document.getElementById(id);
          }
        
        window.onload = function () {
          var oDiv = get('div1');
          var btn = get('btn');
          btn.onclick = function (ev) {
            var oEvent = ev||event;
            oDiv.style.display = 'block';
            console.log(this);
            oEvent.cancelBubble = true;
          }
          document.onclick = function () {
            oDiv.style.display = 'none';
            console.log(this);
          }
        }
        </script>
      </head>
      <body>
        <input type="button" value="显示" id="btn">
        <div id="div1"></di'v>
      </body>
    </html>
    

鼠标事件

  • 鼠标位置

    • 可视区位置:clientXclientY

    • 例子:跟随鼠标的 Div

      • 消除滚动条的影响:可视区页面顶部的距离
    • 代码:

      // 封装鼠标当前坐标函数
      function getPos(ev) {
          var scrollTop = document.documentElement.scrollTop||document.body.scrollTop;
          var scrollLeft = document.documentElement.scollLeft||document.body.scrollLeft;
      
          return {x: ev.clientX+scrollLeft, y: ev.clientY+scrollTop};
      }
      
    • 滚轮事件:onmousewheel 滚轮数据:event.wheelDelta

      • 代码:鼠标滚轮控制 div 移动

        <!DOCTYPE html>
        <html>
          <head>
            <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
            <title>事件绑定与鼠标滚轮</title>
            <link rel="stylesheet" href="../reset.css">
            <style>
              #div1 {
                width: 200px;
                height: 200px;
                position: absolute;
                background-color: rgb(255, 0, 0);
              }
            </style>
            <script type="text/javascript">  
              var iDis = 0;
              var scrollFunc = function (e) {  
                var oDiv1 = document.getElementById('div1');
                e = e || window.event;  
                if (e.wheelDelta) {  //判断浏览器IE,谷歌滑轮事件               
                  if (e.wheelDelta > 0) { //当滑轮向上滚动时  
                    iDis += -e.wheelDelta;
                    oDiv1.style.top = iDis/12 + 'px';
                    console.log("滑轮向上滚动",e.wheelDelta, iDis, oDiv1.offsetTop);
                  }  
                  if (e.wheelDelta < 0) { //当滑轮向下滚动时   
                    iDis += -e.wheelDelta; 
                    oDiv1.style.top = iDis/12 + 'px';
                    console.log("滑轮向上滚动",e.wheelDelta, iDis, oDiv1.offsetTop);
                  }  
                } else if (e.detail) {  //Firefox滑轮事件  
                  if (e.detail> 0) { //当滑轮向上滚动时  
                      console.log("滑轮向上滚动",e.wheelDelta);  
                  }  
                  if (e.detail< 0) { //当滑轮向下滚动时  
                      console.log("滑轮向下滚动",e.wheelDelta);  
                  }  
                }  
              }  
              //给页面绑定滑轮滚动事件  
              if (document.addEventListener) {//firefox  
                  document.addEventListener('DOMMouseScroll', scrollFunc, false);  
              }  
              //滚动滑轮触发scrollFunc方法  //ie 谷歌  
              window.onmousewheel = document.onmousewheel = scrollFunc;   
            </script>
          </head>
          <body>
            <div id="div1"></div>
          </body>
        </html>
        
  • 获取鼠标在页面的绝对位置

    • 封装函数

    • 例子:一串跟随鼠标的 Div

    • 代码:

      <!DOCTYPE html>
      <html>
        <head>
          <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
          <title>跟随鼠标的一串div</title>
          <link rel="stylesheet" href="../reset.css">
          <style>
            div {
              width: 10px;
              height: 10px;
              position: absolute;
              background-color: rgb(255, 0, 0);
            }
          </style>
          <script>
          window.onload = function () {
            // 封装鼠标当前坐标函数
            function getPos(ev) {
              var scrollTop = document.documentElement.scrollTop||document.body.scrollTop;
              var scrollLeft = document.documentElement.scollLeft||document.body.scrollLeft;
      
              return {x: ev.clientX+scrollLeft, y: ev.clientY+scrollTop};
            }
            var oDiv = document.getElementsByTagName('div');
            document.onmousemove = function () {
              var ev = ev || event;
              // 后一个元素跟随前一个元素
              for ( var i = oDiv.length-1; i > 0; i--) {
                console.log(oDiv[i].style.left,oDiv[i-1].offsetLeft)
                oDiv[i].style.left = oDiv[i-1].offsetLeft + 'px';
                oDiv[i].style.top = oDiv[i-1].offsetTop + 'px';
              }
              // 当前多变赋值给第一个元素,
              var pos = getPos(ev);
              oDiv[0].style.left = pos.x + 'px';
              oDiv[0].style.top = pos.y + 'px';
            }
          }
          </script>
        </head>
        <body>
          <div></div><div></div><div></div><div></div><div></div>
          <div></div><div></div><div></div><div></div><div></div>
          <div></div><div></div><div></div><div></div><div></div>
          <div></div><div></div><div></div><div></div><div></div>
          <div></div><div></div><div></div><div></div><div></div>
          <div></div><div></div><div></div><div></div><div></div>
          <div></div><div></div><div></div><div></div><div></div>
          <div></div><div></div><div></div><div></div><div></div>
          <div></div><div></div><div></div><div></div><div></div>
          <div></div><div></div><div></div><div></div><div></div>
          <div></div><div></div><div></div><div></div><div></div>
          <div></div><div></div><div></div><div></div><div></div>
        </body>
      </html>
      

键盘事件

  • keyCode

    • 获取用户按下键盘的哪个键:onkeydown / onkeyup
    • 例子:键盘控制 Div 移动
  • 其它属性

    • ctrlKeyshiftKeyaltKey
    • 例子:提交留言
      • 回车提交
      • CTRL + 回车 提交
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>键盘控制元素移动和回车提交</title>
        <link rel="stylesheet" href="../reset.css">
        <style>
         /* 评论区 */
         #div_comments {
           position: absolute;
           display: block;
           padding-top: 20px;
           width: 640px;
           background-color: rgb(252, 229, 200);
         }
         #div_com_inp  {
           margin-top: 5px;
           border-top: burlywood dashed 1px;
           border-bottom: burlywood dashed 1px;
         }
         .text {
           margin: 20px 0 20px 53px;
         }
         .btn {
           margin: 20px 0 20px 20px;
           width: 70px;
           height: 70px;
         }
         #div_com_show {
          height: 200px;
          margin: 20px 50px;
          padding: 0px 20px;
          background-color: rgb(255, 255, 255);
          overflow: hidden;
         }
         .li_comment {
           white-space: pre-wrap;
           padding: 10px 5px;
           float: none;
           border-bottom: cadetblue dashed 1px;
           opacity: 0;
           filter: alpha(opacity=0);
           overflow: hidden;
         }
        </style>
        <script>
        // 封装 getElementById 函数
        function get(id) {
            return document.getElementById(id);
          }
        
        window.onload = function () {
          // var oDiv = get('div1');
          // document.onkeydown = function () {
          //   var ev = event||ev;
          //   if (ev.keyCode === 37) {
          //     oDiv.style.left = oDiv.offsetLeft - 10 + 'px'
          //   } else if (ev.keyCode === 39) {
          //     oDiv.style.left = oDiv.offsetLeft + 10 + 'px'
          //   } else if (ev.keyCode === 38) {
          //     oDiv.style.top = oDiv.offsetTop - 10 + 'px'
          //   } else if (ev.keyCode === 40) {
          //     oDiv.style.top = oDiv.offsetTop + 10 + 'px'
          //   }
          // }
    
          //获取Div元素
          var oDiv = document.getElementById("div_comments");
     
          //创建各个方向条件判断初始变量
          var left = false;
          var right = false;
          var top = false;
          var bottom = false;
     
          //当按下对应方向键时,对应变量为true
          document.onkeydown = function(ev){
            var oEvent = ev || event;
            var keyCode = oEvent.keyCode;
            switch(keyCode){
              case 37:
                left=true;
                break;
              case 38:
                top=true;
                break;
              case 39:
                right=true;
                break;
              case 40:
                bottom=true;
                break;
            }
          };
     
          //设置一个定时,时间为50左右,不要太高也不要太低
          setInterval(function(){
     
            //当其中一个条件为true时,则执行当前函数(移动对应方向)
            if(left){
              oDiv.style.left = oDiv.offsetLeft-10+"px";
            }else if(top){
              oDiv.style.top = oDiv.offsetTop-10+"px";
            }else if(right){
              oDiv.style.left = oDiv.offsetLeft+10+"px";
            }else if(bottom){
              oDiv.style.top = oDiv.offsetTop+10+"px";
            }
          },30);
     
          //执行完后,所有对应变量恢复为false,保持静止不动
          document.onkeyup = function(ev){
            var oEvent = ev || event;
            var keyCode = oEvent.keyCode;
     
            switch(keyCode){
              case 37:
                left=false;
                break;
              case 38:
                top=false;
                break;
              case 39:
                right=false;
                break;
              case 40:
                bottom=false;
                break;
            }
          }
    
          // btn 提交
          var btn = get('btn_comment');
          var txt = get('text_comment');
          var board = get('div_com_show');
          btn.onclick = function () {
            if (true) {
              var oP = document.createElement('p');
              oP.innerHTML = txt.value;
              txt.value = '';
              if (board.children.length > 0) {
                board.insertBefore(oP,board.children[0])
              } else {
                board.appendChild(oP);
              }
            }
          }
          // ctrl + enter 提交
          txt.onkeydown = function (ev) {
            var ev = ev||event;
            if (ev.keyCode === 13 && ev.ctrlKey) {
              var oP = document.createElement('p');
              oP.innerHTML = txt.value;
              txt.value = '';
              if (board.children.length > 0) {
                board.insertBefore(oP,board.children[0])
              } else {
                board.appendChild(oP);
              }
            }
          }
        }
        </script>
      </head>
      <body>
        <div id="div_comments">
          <div id="div_com_inp">
            <textarea class="text" name="" id="text_comment" cols="60" rows="5"></textarea>
            <input class="btn" type="button" name="" id="btn_comment" value="发表评论">
          </div>
          <div id="div_com_show">
            <p>CTRL + 回车 提交</p>
            <p>键盘控制留言框位置</p>
          </div>
        </div>
      </body>
    </html>
    

JS 事件中级

默认事件

  • 默认事件

    • 什么是默认事件
  • 阻止默认事件

    • 普通写法:return false;
    • 例子1:屏蔽右键菜单
      • document.oncontextmenu = function (ev) { return false; }
      • 弹出自定义右键菜单
    • 例子2:只能输入数字的输入框
      • oTxt.onkeydown = function (ev) { return false; }
      • keydownkeyup 事件区别
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>默认事件</title>
        <link rel="stylesheet" href="../reset.css">
        <style>
          #div1 {
            width: 100px;
            height: 150px;
            position: absolute;
            background-color: rgb(207, 207, 207);
            display: none;
          }
        </style>
        <script>
    
        // 阻止默认事件 阻止右键菜单
        document.oncontextmenu = function (ev) {
          var ev = ev||event;
          var oDiv = get('div1');
          oDiv.style.display = 'block';
          oDiv.style.top = ev.clientY + 'px';
          oDiv.style.left = ev.clientX + 'px';
          return false;
        }
        // 点击其它位置div消失
        document.onclick = function (ev) {
          var oDiv = get('div1');
          oDiv.style.display = 'none';
        }
        
        // 封装 getElementById 函数
        function get(id) {
          return document.getElementById(id);
        }
    
        window.onload = function () {
          // 只能输入数字的文本框
          // ASCII 0:48 ~ 9:58 
          var txt = get('txt');
          txt.onkeydown = function (ev) {
            var ev = ev||event;
            if (ev.keyCode <= 58 && ev.keyCode >=48 || ev.keyCode === 8) {
    
            } else {
              return false;
            }
          }
        }
        
        </script>
      </head>
      <body>
        <input type="text" name="" id="txt">
        <div id="div1">
          <li>123</li>  
          <li>456</li>  
          <li>789</li>  
          <li>123</li>  
          <li>456</li>  
          <li>789</li>  
          <li>123</li>  
          <li>456</li>  
          <li>789</li>  
        </div>
      </body>
    </html>
    

拖拽

  • 简单拖拽

    • 拖拽原理
      • 鼠标按下位置到 div 距离不变
      • 三个事件:onmousedown onmousemove onmouseup
  • 靠谱拖拽

    • 原有拖拽的问题:移动太快鼠标会移出 div
      • 直接给 document 加事件
    • FireFox 下,空 Div 拖拽 Bug
      • 阻止默认事件:onmousedown {return false}
    • 防止拖出页面
      • 修正位置:在可视区内
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>拖拽</title>
        <link rel="stylesheet" href="../reset.css">
        <style>
          #div1 {
            width: 200px;
            height: 200px;
            position: absolute;
            background-color: rgb(255, 0, 0);
          }
        </style>
        <script>
        // 封装 getElementById 函数
        function get(id) {
          return document.getElementById(id);
        }
        window.onload = function () {
          var oDiv = get('div1');
          // oDiv.onmousedown 很容易移出范围
          document.onmousedown = function Drag() {
            var ev = event||ev;
            var _this = this;
            // 鼠标可视区位置 - div左边距 = 鼠标在div内的位置
            var disX = ev.clientX - oDiv.offsetLeft;
            var disY = ev.clientY - oDiv.offsetTop;
            console.log(disX,'可视区鼠标X:', ev.clientX, '鼠标Y:',ev.clientY);
            this.onmousemove = function mouseMove() {
              // 不断获取Event 对象,坐标才会不断更新
              var ev = event||ev;
              // console.log('可视区鼠标X:', ev.clientX, '鼠标Y:',ev.clientY);
              // div位置 = 鼠标可视区新的位置 - 鼠标与div的距离
              var left = ev.clientX -disX;
              var top = ev.clientY - disY;
              if (left < 0) {
                left = 0;
              }
              if (top < 0) {
                top = 0
              }
              if (left > document.documentElement.clientWidth - oDiv.offsetWidth) {
                left = document.documentElement.clientWidth - oDiv.offsetWidth + 'px';
              }
              if (top > document.documentElement.clientHeight - oDiv.offsetHeight) {
                top = document.documentElement.clientHeight - oDiv.offsetHeight + 'px';
              }
              oDiv.style.left = left + 'px';
              oDiv.style.top = top + 'px';
            }
            this.onmouseup = function mouseUp() {
              _this.onmousemove = '';
              this.onmouseup = '';
            }
            // 阻止火狐重影bug
            return false;
          }
        }
        
        </script>
      </head>
      <body>
        <div id="div1"></div>
      </body>
    </html>
    

JS 事件高级应用

事件绑定

  • IE 方式:

    • attachEvent(事件名称, 函数),绑定事件处理函数
    • detachEvent(事件名称, 函数),接触绑定
  • DOM 方式:不兼容 IE7

    • addEventListener(事件名称, 函数, 捕获)
    • removeEventListener(事件名称, 函数, 捕获)
  • 何时使用绑定

  • 绑定事件和 this

  • 绑定匿名函数,会无法删除

  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>事件绑定</title>
        <link rel="stylesheet" href="../reset.css">
        <style>
          #div1 {
            width: 200px;
            height: 200px;
            position: absolute;
            background-color: rgb(255, 0, 0);
          }
        </style>
        <script>
        // 封装 getElementById 函数
        function get(id) {
          return document.getElementById(id);
        }
    
        // 封装 attachEvent 兼容性函数
        function myAddEvent(obj, ev, fn) {
          if (obj.attachEvent) {
            obj.attachEvent('on'+ ev, fn);
          } else {
            obj.addEventListener(ev, fn , false);
          }
        }
    
        window.onload = function () {
          var oDiv = get('div1');
          var btn = get('btn');
          myAddEvent(btn, 'click', function () {
            console.log('event');
            oDiv.style.display = 'none';
          })
          myAddEvent(btn, 'click', function () {
            console.log('event2');
            setTimeout(function () {
              oDiv.style.display = 'block';
            }, 1000);
          })
        }
        </script>
      </head>
      <body>
        <input type="button"  id="btn" value="按钮">
        <div id="div1"></div>
      </body>
    </html>
    

高级拖拽

  • 复习拖拽原理

    • 距离不变
    • 三个事件
  • 限制范围

    • 对位置进行判断
      • 例子1:不能拖出窗口的 Div
      • 例子2:不能拖出指定窗口的 Div
    • 磁性吸附
  • 图片拖拽

    • 阻止默认事件
  • 文字选中

    • 阻止默认事件 return false 可以解决 chromeFireFoxIE9的文字选中问题
    • IE 下拖动有问题:
      • 事件捕获:.setCapture() 只兼容IE
      • 取消捕获:.releaseCapture()
  • 与 DOM 配合

    • 带框的拖拽
    • 保留原有位置的拖拽
  • 代码:

    <!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>高级拖拽</title>
        <link rel="stylesheet" href="../reset.css">
        <style>
          #div1 {
            width: 100px;
            height: 100px;
            position: absolute;
            background-color: rgb(82, 177, 255);
          }
          .box {
            border: black dashed 1px;
            position: absolute;
          }
        </style>
        <script>
        // 封装 getElementById 函数
        function get(id) {
          return document.getElementById(id);
        }
        window.onload = function () {
          var oDiv = get('div1');
          var oDiv0 = get('div0');
    
          // oDiv.onmousedown 很容易移出范围
          oDiv.onmousedown = function Drag() {
            var ev = event||ev;
            var _this = this;
    
            // 鼠标可视区位置 - div左边距 = 鼠标在div内的位置
            var disX = ev.clientX - oDiv.offsetLeft;
            var disY = ev.clientY - oDiv.offsetTop;
            console.log(disX,'可视区鼠标X:', ev.clientX, '鼠标Y:',ev.clientY);
            
            // 增加边框
            var oBox = document.createElement('div');
            oBox.className = 'box';
            // 边框的大小 - 线宽 = oDiv 的大小
            oBox.style.width = this.offsetWidth - 2 + 'px';
            oBox.style.height = this.offsetHeight - 2 + 'px';
            oDiv0.appendChild(oBox);
            // 边框的位置 = oDiv 的位置
            oBox.style.left = oDiv.offsetLeft + 'px';
            oBox.style.top = oDiv.offsetTop + 'px';
            // IE7 兼容
            if (this.setCapture) {
              this.onmousemove = mouseMove;
              this.onmouseup = mouseUp;
              oDiv.setCapture();
            } else {
              document.onmousemove = mouseMove;
              document.onmouseup = mouseUp;
            }
    
            function mouseUp() {
              this.onmousemove = '';
              this.onmouseup = '';
              // 鼠标松开,oDiv 到 oBox 的位置
              oDiv.style.left = oBox.offsetLeft + 'px';
              oDiv.style.top = oBox.offsetTop + 'px';
              // 删除生成的box
              oDiv0.removeChild(oBox);
              // IE7 兼容
              if (this.releaseCapture) {
                this.releaseCapture();
              }
            }
    
            function mouseMove(ev) {
              // 不断获取Event 对象,坐标才会不断更新
              var ev = event||ev;
              // console.log('可视区鼠标X:', ev.clientX, '鼠标Y:',ev.clientY);
              // div位置 = 鼠标可视区新的位置 - 鼠标与div的距离
              var left = ev.clientX -disX;
              var top = ev.clientY - disY;
              // 鼠标移动时 移动虚线框
              oBox.style.left = left + 'px';
              oBox.style.top = top + 'px';
            }
            
            // 阻止火狐重影bug, 解决 chrome FireFox IE9的文字选中问题
            return false;
          }
        }
        
        </script>
      </head>
      <body>
        <div id="div0">
          asdfasdfas/sad'234
          <div id="div1">asdfasdfas/sad</div>
          asdfasdfas/sad'234
        </div>
      </body>
    </html>
    

自定义滚动条

  • 拖拽

    • 只有横向拖拽
    • 限制范围:范围的大小
    • 计算比例:当前值/最大值
  • 控制其他对象

    • 例子1:控制物体的大小
    • 例子2:控制物体的透明度
    • 例子3:控制文字滚动
  • 代码:

    <!DOCTYPE html>
    <html>
    <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>自定义滚动条</title>
        <link rel="stylesheet" href="../reset.css">
        <style>
          #div0 {
            margin: 10px auto;
            width: 600px;
            height: 400px;
            position: relative;
            background-color: blanchedalmond;
          }
          /* 上下滚动条 */
          #div1 {
            top: 50px;
            right: 50px;
            width: 20px;
            height: 300px;
            position: absolute;
            border: rgb(139, 139, 139) solid 1px;
          }
          #div1_0 {
            width: 20px;
            height: 40px;
            position: absolute;
            background-color: rgb(140, 171, 255);
          }
          /* 文字区 */
          #div3 {
            left: 60px;
            top: 50px;
            width: 400px;
            height: 300px;
            position: absolute;
            background-color: rgb(255, 255, 255);
            overflow: hidden;
    
          }
          #div3_0 {
            width: 900px;
            position: absolute;
            white-space: pre-wrap;
            background-color: cornsilk;
          }
          /* 左右滚动条 */
          #div2 {
            top: 5px;
            right: 140px;
            width: 400px;
            height: 20px;
            position: absolute;
            border: rgb(139, 139, 139) solid 1px;
          }
          #div2_0 {
            width: 40px;
            height: 20px;
            position: absolute;
            background-color: rgb(140, 171, 255);
          }
        </style>
        <script>
        // 封装 getElementById 函数
        function get(id) {
          return document.getElementById(id);
        }
        // 封装获取计算后元素样式函数,返回小数
        function getStyle(obj, name) {
          if (obj.currentStyle) {
            return obj.currentStyle[name];
          } else {
            return getComputedStyle(obj, '') [name];
          }
        }
    
        window.onload = function () {
    
          var oDiv1 = get('div1'); // 上下滚动框
          var oDiv1_0 = get('div1_0'); // 上下滚动条
          var oDiv3 = get('div3'); // 文字框
          // var oDiv3_0 = get('div3_0'); // 文字可视区
          var oDiv2 = get('div2'); // 左右滚动框
          var oDiv2_0 = get('div2_0'); // 左右滚动条
    
          // 文字TOP = (文字框高-可视区高) * (滚动条TOP/(滚动框高-滚动条高))
          // 鼠标按下滚动条时触发事件
          // 鼠标Y移动时,滚动条top 移动
          // 鼠标松开时,事件结束
    
          // 合并函数:ev.clientY offsetTop offsetHeight oDiv1 oDiv1_0 oDiv3 oDiv3_0
          // 去掉 offset 改用 getStyle 
          // console.log(oDiv1.children[0], oDiv1_0) 
          // 直接传一个对象取子节点或父节点
          // 面对对象:srcoll 作为 oDiv1_0 和 oDiv2_0 的方法时,可以用 this 代替 oDiv1_0,只要传入 ev, 'clientY', oDiv3
          oDiv1_0.onmousedown = function (ev) {
            scroll(ev, 'clientY', oDiv1, oDiv3);
            return false; // 可以解决 chrome FireFox IE9的文字选中问题
          } 
          oDiv2_0.onmousedown = function (ev) {
            scroll(ev, 'clientX', oDiv2, oDiv3);
            return false; // 可以解决 chrome FireFox IE9的文字选中问题
          }
    
          function scroll(ev, dir, obj1 , obj2) {
            var attr = '';
            var attr2 = '';
            if (dir === 'clientY') {
              attr = 'height';
              attr2 = 'top';
            } else if (dir === 'clientX') {
              attr = 'width';
              attr2 = 'left';
            } else {
              return console.log('参数错误');
            }
    
            var oDiv1_0 = obj1.children[0];
            var oDiv3_0 = obj2.children[0];
            var ev = ev||event;
            var disMouse = ev[dir];
            // 滚动条旧的位置
            var oldPos = parseInt(getStyle(oDiv1_0, attr2));
            // 滚动范围 = 滚动条高 + 滚动框高
            var disScroll = parseInt(getStyle(obj1, attr)) - parseInt(getStyle(oDiv1_0, attr)); 
    
            document.onmousemove = function (ev) {
              ev = ev||event;
              // 移动距离
              var disMove = ev[dir] - disMouse;
              // 滚动条TOP = 滚动条TOP + 移动距离
              var divScroll = oldPos + disMove;
              // 文字TOP = (文字框高-可视区高) * (滚动条TOP/(滚动框高-滚动条高))
              var disTxt = parseInt(getStyle(obj2, attr)) - parseInt(getStyle(oDiv3_0, attr));
              var divTxt = (disTxt)*(divScroll/disScroll);
    
              // 向下移 disMove > 0; 向上移 disMove < 0 
              if (disMove > 0 && divScroll <= disScroll) {
                oDiv1_0.style[attr2] = divScroll + 'px';
                oDiv3_0.style[attr2] = divTxt + 'px';
                // 文字区
              } else if (disMove <= 0 && divScroll >= 0) {
                // 都 = 0;divScroll 才能取到 0px
                oDiv1_0.style[attr2] = divScroll + 'px';
                oDiv3_0.style[attr2] = divTxt + 'px';
              } else {
                // 防止移动过快超出判断范围, 滚动条距离小于 0 直接到达
                if (disMove < 0) {
                  oDiv1_0.style[attr2] = 0;
                  oDiv3_0.style[attr2] = 0;
                } else if (disMove > 0) {
                  oDiv1_0.style[attr2] = disScroll + 'px';
                  oDiv3_0.style[attr2] = disTxt + 'px';              
                }
              }
              document.onmouseup = function () {
                this.onmousemove = '';
                this.onmouseup = '';
              }
              console.log(disMove,divScroll,disScroll,oldPos,divTxt)
            }
          }
    
          // oDiv2_0.onmousedown = function (ev) {
          //   var ev = ev||event;
          //   var disMouse = ev.clientX;
          //   var oldPos = this.offsetLeft;
          //   // 滚动范围 = 滚动条高 + 滚动框高
          //   var disScroll = oDiv2.offsetWidth - oDiv2_0.offsetWidth -2; 
          // 
          //   document.onmousemove = function (ev) {
          //     ev = ev||event;
          //     // 移动距离
          //     var disMove = ev.clientX - disMouse;
          //     // 滚动条TOP = 滚动条TOP + 移动距离
          //     var divScroll = oldPos + disMove;
    
          //     // 文字TOP = (文字框高-可视区高) * (滚动条TOP/(滚动框高-滚动条高))
          //     var divTxt= (oDiv3.offsetWidth - oDiv3_0.offsetWidth)*(divScroll / disScroll);
    
          //     // 向下移 disMove > 0; 向上移 disMove < 0 
          //     if (disMove > 0 && divScroll <= disScroll) {
          //       oDiv2_0.style.left = divScroll + 'px';
          //       oDiv3_0.style.left = divTxt + 'px';
          //       // 文字区
          //     } else if (disMove <= 0 && divScroll >= 0) {
          //       // 都 = 0;divScroll 才能取到 0px
          //       oDiv2_0.style.left = divScroll + 'px';
          //       oDiv3_0.style.left = divTxt + 'px';
          //     } else {
          //       // 防止移动过快超出判断范围, 滚动条距离小于 30 直接到达
          //       if (disMove < 0 && divScroll < 30) {
          //         oDiv2_0.style.left = 0;
          //         oDiv3_0.style.left = 0;
          //       } else if (disMove > 0 && disScroll - divScroll < 30) {
          //         oDiv2_0.style.left = disScroll + 'px';
          //         oDiv3_0.style.left = oDiv3.offsetWidth - oDiv3_0.offsetWidth + 'px';              
          //       }
          //     }
          //     document.onmouseup = function () {
          //       this.onmousemove = '';
          //       this.onmouseup = '';
          //     }
          //     console.log(disMove,divScroll,disScroll,oldPos,divTxt)
          //   }
          //   return false; // 可以解决 chrome FireFox IE9的文字选中问题
          // }
        }
        </script>
      </head>
      <body>
        <div id="div0">
          <div id="div1">
            <div id="div1_0"></div>
          </div>
          <div id="div2">
            <div id="div2_0"></div>
          </div>
          <div id="div3">
            <div id="div3_0">
              值			描述
    normal		默认。空白会被浏览器忽略。
    pre			空白会被浏览器保留。其行为方式类似 HTML 中的  标签。inherit		规定应该从父元素继承 white-space 属性的值。
    nowrap		文本不会换行,文本会在在同一行上继续,直到遇到  标签为止。
    pre-wrap	保留空白符序列,但是正常地进行换行。
    pre-line	合并空白符序列,但是保留换行符。
    inherit		规定应该从父元素继承 white-space 属性的值。
    - 拖拽
      - 只有横向拖拽
      - 限制范围:范围的大小
      - 计算比例:当前值/最大值
    - 控制其他对象
      - 例子1:控制物体的大小
      - 例子2:控制物体的透明度
      - 例子3:控制文字滚动
    - 代码:- 拖拽
    - 只有横向拖拽
    - 限制范围:范围的大小
    - 计算比例:当前值/最大值
    - 控制其他对象
    - 例子1:控制物体的大小
    - 例子2:控制物体的透明度
    - 例子3:控制文字滚动
    - 代码:- 代码:- 拖拽
    - 只有横向拖拽
    - 限制范围:范围的大小
    - 计算比例:当前值/最大值
    - 控制其他对象
            </div>
          </div>
        </div>
      </body>
    </html>
    

Ajax 基础

Ajax 是什么

  • 什么是服务器

    • 网页浏览过程分析
    • 如何配置自己的服务器程序
  • 什么是

    Ajax = Asynchronous JavaScript and XML

    (异步的 JavaScript 和 XML)

    • 无刷新数据读取
    • 用户注册、在线聊天室
      • 异步、同步

使用 Ajax

  • 基础:请求并显示静态

    txt 
    

    文件

    • 字符集编码:必须统一编码
    • 缓存、阻止缓存:
      • 根据 URL 缓存:让 URL 一直在变化,在 URL 后加时间戳
  • 动态数据:请求 JS(或 json )文件,获取过来是字符串,需要解析

    • eval 的使用:解析成 JS 元素
    • DOM 创建元素
  • 局部刷新:请求并显示部分网页文件

Ajax 原理

  • HTTP 请求方法
    • GET ---- 用于获取数据(如:浏览帖子)
    • POST---- 用于上传数据(如:用户注册)
    • GET/POST 的区别
      • GET 是在 url 里传数据:安全性差、容量小、有缓存
      • POST 不通过 url :安全性较高,容量大(2G)、无缓存

Ajax 中级

编写 Ajax

  • 创建 Ajax 对象

    • ActiveXObject("Microsoft.XMLHTTP)
  • XMLHttpRequest()

    • 笔记:变量是 Window 的属性
      • 使用未定义的变量 —— 报错
    • 使用未定义的属性 —— undefined
    • window.XMLHttpRequest 返回真则是 chrome FF IE7,
      • window.ActiveXObject("Microsoft.XMLHTTP") 返回真则是 IE6
  • 连接服务器

    • open(方法,文件名,异步传输)
      
      • method:请求的类型;GETPOST必须大写
      • url:文件在服务器上的位置,GET 请求要避免缓存,请向 URL 添加一个唯一的 ID
      • async:true(异步)或 false(同步)
  • 发送请求

    • send()
      
      • string:仅用于 POST 请求
  • 接收返回值

  • 请求状态监控

    • onreadystatechange
      

      事件

      • readyState 属性:请求状态

        • 0: 未初始化还没有调用 open() 方法
        • 1: 开始载入已调用 send() 方法,正在发送请求
        • 2: 载入完成 ``send() 发送完成,已收到全部响应内容
        • 3: 解析正在解析响应内容
        • 4: 完成 响应内容解析完成,可以在客户端调用了
      • status 属性( http 状态码):请求结果,200: 成功

      • responseText 获得字符串形式的响应数据

        document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
        

POST 请求

一个简单 POST 请求:

实例

xmlhttp.open("POST","/try/ajax/demo_post.php",true); xmlhttp.send();

如果需要像 HTML 表单那样 POST 数据,请使用 setRequestHeader() 来添加 HTTP 头。然后在 send() 方法中规定您希望发送的数据:

实例

xmlhttp.open("POST","/try/ajax/demo_post2.php",true); xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); xmlhttp.send("fname=Henry&lname=Ford");
方法描述
setRequestHeader(header,value)向请求添加 HTTP 头。 header: 规定头的名称 value: 规定头的值
  • 代码:

    <html>
    <head>
    <script type="text/javascript">
    function Ajax(url, suc, err) {
        var oAjax = '';
        if (window.XMLHttpRequest) {
          // chrome FF IE9
          oAjax = new XMLHttpRequest;
        } else if (window.ActiveXObject) {
          oAjax = new ActiveXObject("Microsoft.XMLHTTP");
        }
        if (oAjax != '') {
          oAjax.onreadystatechange = state_change;
          oAjax.open('get', url, true);
          oAjax.send();
        } else {
          err();
        }
    
        function state_change() {
          if (oAjax.readyState === 4) {
            // 完成
            if (oAjax.status === 200) {
              // 成功
              if (suc) {
                suc(oAjax.responseText);
              } else {
                return oAjax.responseText;
              }          
            } else if (oAjax.status === 404){
              console.log('url错误或不存在');
            } else if (err){
              err();
            }
          } else if (oAjax.readyState === 0){
            console.log('未初始化');
          } else if (oAjax.readyState === 1){
            console.log('正在发送请求');
          } else if (oAjax.readyState === 2){
            console.log('处理请求中');
          } else if (oAjax.readyState === 3){
            console.log('正在解析');
          }
        }
      }
    window.onload = function () {
      var btn = document.getElementById('btn');
      btn.onclick = function () {
        Ajax('/api/blog/list', function (str) {
            // 使用返回数据
            console.log('成功')
            document.getElementById('T1').innerHTML = str;
        })
      }
    }
    
    </script>
    </head>
    
    <body>
    <div id="T1" style="border:1px solid black;height:40;width:300;padding:5"></div><br />
    <button id="btn">Click</button>
    </body>
    </html>
    

Ajax 数据

  • 数据类型
    • 什么叫数据类型——英语/中文
    • XML / JSON
  • 字符集( 文件编码 )
    • 所有文件字符集相同

XMLHttpRequest

XMLHttpRequest 是一个内建的浏览器对象,它允许使用 JavaScript 发送 HTTP 请求。

虽然它的名字里面有 “XML” 一词,但它可以操作任何数据,而不仅仅是 XML 格式。我们可以用它来上传/下载文件,跟踪进度等。

现如今,我们有一个更为现代的方法叫做 fetch,它的出现使得 XMLHttpRequest 在某种程度上被弃用。

在现代 Web 开发中,出于以下三种原因,我们还在使用 XMLHttpRequest

  1. 历史原因:我们需要支持现有的使用了 XMLHttpRequest 的脚本。
  2. 我们需要兼容旧浏览器,并且不想用 polyfill(例如为了使脚本更小)。
  3. 我们需要做一些 fetch 目前无法做到的事情,例如跟踪上传进度。

这些话听起来熟悉吗?如果是,那么请继续阅读下面的 XMLHttpRequest 相关内容吧。如果还不是很熟悉的话,那么请先阅读 Fetch 一章的内容。

XMLHttpRequest 基础

XMLHttpRequest 有两种执行模式:同步(synchronous)和异步(asynchronous)。

我们首先来看看最常用的异步模式:

要发送请求,需要 3 个步骤:

  1. 创建 XMLHttpRequest

    let xhr = new XMLHttpRequest();
    

    此构造器没有参数。

  2. 初始化它,通常就在 new XMLHttpRequest 之后:

    xhr.open(method, URL, [async, user, password])
    

    此方法指定请求的主要参数:

    • method —— HTTP 方法。通常是 "GET""POST"
    • URL —— 要请求的 URL,通常是一个字符串,也可以是 URL 对象。
    • async —— 如果显式地设置为 false,那么请求将会以同步的方式处理,我们稍后会讲到它。
    • userpassword —— HTTP 基本身份验证(如果需要的话)的登录名和密码。

    请注意,open 调用与其名称相反,不会建立连接。它仅配置请求,而网络活动仅以 send 调用开启。

  3. 发送请求。

    xhr.send([body])
    

    这个方法会建立连接,并将请求发送到服务器。可选参数 body 包含了 request body。

    一些请求方法,像 GET 没有 request body。还有一些请求方法,像 POST 使用 body 将数据发送到服务器。我们稍后会看到相应示例。

  4. 监听 xhr 事件以获取响应。

    这三个事件是最常用的:

    • load —— 当请求完成(即使 HTTP 状态为 400 或 500 等),并且响应已完全下载。
    • error —— 当无法发出请求,例如网络中断或者无效的 URL。
    • progress —— 在下载响应期间定期触发,报告已经下载了多少。
    xhr.onload = function() {
      alert(`Loaded: ${xhr.status} ${xhr.response}`);
    };
    
    xhr.onerror = function() { // 仅在根本无法发出请求时触发
      alert(`Network Error`);
    };
    
    xhr.onprogress = function(event) { // 定期触发
      // event.loaded —— 已经下载了多少字节
      // event.lengthComputable = true,当服务器发送了 Content-Length header 时
      // event.total —— 总字节数(如果 lengthComputable 为 true)
      alert(`Received ${event.loaded} of ${event.total}`);
    };
    

下面是一个完整的示例。它从服务器加载 /article/xmlhttprequest/example/load,并打印加载进度:

// 1. 创建一个 new XMLHttpRequest 对象
let xhr = new XMLHttpRequest();

// 2. 配置它:从 URL /article/.../load GET-request
xhr.open('GET', '/article/xmlhttprequest/example/load');

// 3. 通过网络发送请求
xhr.send();

// 4. 当接收到响应后,将调用此函数
xhr.onload = function() {
  if (xhr.status != 200) { // 分析响应的 HTTP 状态
    alert(`Error ${xhr.status}: ${xhr.statusText}`); // 例如 404: Not Found
  } else { // 显示结果
    alert(`Done, got ${xhr.response.length} bytes`); // response 是服务器响应
  }
};

xhr.onprogress = function(event) {
  if (event.lengthComputable) {
    alert(`Received ${event.loaded} of ${event.total} bytes`);
  } else {
    alert(`Received ${event.loaded} bytes`); // 没有 Content-Length
  }

};

xhr.onerror = function() {
  alert("Request failed");
};

一旦服务器有了响应,我们可以在以下 xhr 属性中接收结果:

  • status

    HTTP 状态码(一个数字):200404403 等,如果出现非 HTTP 错误,则为 0

  • statusText

    HTTP 状态消息(一个字符串):状态码为 200 对应于 OK404 对应于 Not Found403 对应于 Forbidden

  • response(旧脚本可能用的是 responseText

    服务器 response body。

我们还可以使用相应的属性指定超时(timeout):

xhr.timeout = 10000; // timeout 单位是 ms,此处即 10 秒

如果在给定时间内请求没有成功执行,请求就会被取消,并且触发 timeout 事件。

URL 搜索参数(URL search parameters)

为了向 URL 添加像 ?name=value 这样的参数,并确保正确的编码,我们可以使用 URL 对象:

let url = new URL('https://google.com/search');
url.searchParams.set('q', 'test me!');

// 参数 'q' 被编码
xhr.open('GET', url); // https://google.com/search?q=test+me%21

响应类型

我们可以使用 xhr.responseType 属性来设置响应格式:

  • ""(默认)—— 响应格式为字符串,
  • "text" —— 响应格式为字符串,
  • "arraybuffer" —— 响应格式为 ArrayBuffer(对于二进制数据,请参见 ArrayBuffer,二进制数组),
  • "blob" —— 响应格式为 Blob(对于二进制数据,请参见 Blob),
  • "document" —— 响应格式为 XML document(可以使用 XPath 和其他 XML 方法),
  • "json" —— 响应格式为 JSON(自动解析)。

例如,我们以 JSON 格式获取响应:

let xhr = new XMLHttpRequest();

xhr.open('GET', '/article/xmlhttprequest/example/json');

xhr.responseType = 'json';

xhr.send();

// 响应为 {"message": "Hello, world!"}
xhr.onload = function() {
  let responseObj = xhr.response;
  alert(responseObj.message); // Hello, world!
};

请注意:

在旧的脚本中,你可能会看到 xhr.responseText,甚至会看到 xhr.responseXML 属性。

它们是由于历史原因而存在的,以获取字符串或 XML 文档。如今,我们应该在 xhr.responseType 中设置格式,然后就能获取如上所示的 xhr.response 了。

readyState

XMLHttpRequest 的状态(state)会随着它的处理进度变化而变化。可以通过 xhr.readyState 来了解当前状态。

规范 中提到的所有状态如下:

UNSENT = 0; // 初始状态
OPENED = 1; // open 被调用
HEADERS_RECEIVED = 2; // 接收到 response header
LOADING = 3; // 响应正在被加载(接收到一个数据包)
DONE = 4; // 请求完成

XMLHttpRequest 对象以 0123 → … → 34 的顺序在它们之间转变。每当通过网络接收到一个数据包,就会重复一次状态 3

我们可以使用 readystatechange 事件来跟踪它们:

xhr.onreadystatechange = function() {
  if (xhr.readyState == 3) {
    // 加载中
  }
  if (xhr.readyState == 4) {
    // 请求完成
  }
};

你可能在非常老的代码中找到 readystatechange 这样的事件监听器,它的存在是有历史原因的,因为曾经有很长一段时间都没有 load 以及其他事件。如今,它已被 load/error/progress 事件处理程序所替代。

中止请求(Aborting)

我们可以随时终止请求。调用 xhr.abort() 即可:

xhr.abort(); // 终止请求

它会触发 abort 事件,且 xhr.status 变为 0

同步请求

如果在 open 方法中将第三个参数 async 设置为 false,那么请求就会以同步的方式进行。

换句话说,JavaScript 执行在 send() 处暂停,并在收到响应后恢复执行。这有点儿像 alertprompt 命令。

下面是重写的示例,open 的第三个参数为 false

let xhr = new XMLHttpRequest();

xhr.open('GET', '/article/xmlhttprequest/hello.txt', false);

try {
  xhr.send();
  if (xhr.status != 200) {
    alert(`Error ${xhr.status}: ${xhr.statusText}`);
  } else {
    alert(xhr.response);
  }
} catch(err) { // 代替 onerror
  alert("Request failed");
}

这看起来好像不错,但是很少使用同步调用,因为它们会阻塞页面内的 JavaScript,直到加载完成。在某些浏览器中,滚动可能无法正常进行。如果一个同步调用执行时间过长,浏览器可能会建议关闭“挂起(hanging)”的网页。

XMLHttpRequest 的很多高级功能在同步请求中都不可用,例如向其他域发起请求或者设置超时。并且,正如你所看到的,没有进度指示。

基于这些原因,同步请求使用的非常少,几乎从不使用。在这我们就不再讨论它了。

HTTP-header

XMLHttpRequest 允许发送自定义 header,并且可以从响应中读取 header。

HTTP-header 有三种方法:

  • setRequestHeader(name, value)

    使用给定的 namevalue 设置 request header。例如:xhr.setRequestHeader('Content-Type', 'application/json');Header 的限制一些 header 是由浏览器专门管理的,例如 RefererHost。 完整列表请见 规范。为了用户安全和请求的正确性,XMLHttpRequest 不允许更改它们。不能移除 headerXMLHttpRequest 的另一个特点是不能撤销 setRequestHeader。一旦设置了 header,就无法撤销了。其他调用会向 header 中添加信息,但不会覆盖它。例如:xhr.setRequestHeader('X-Auth', '123'); xhr.setRequestHeader('X-Auth', '456'); // header 将是: // X-Auth: 123, 456

  • getResponseHeader(name)

    获取具有给定 name 的 header(Set-CookieSet-Cookie2 除外)。例如:xhr.getResponseHeader('Content-Type')

  • getAllResponseHeaders()

    返回除 Set-CookieSet-Cookie2 外的所有 response header。header 以单行形式返回,例如:Cache-Control: max-age=31536000 Content-Length: 4260 Content-Type: image/png Date: Sat, 08 Sep 2012 16:53:16 GMTheader 之间的换行符始终为 "\r\n"(不依赖于操作系统),所以我们可以很容易地将其拆分为单独的 header。name 和 value 之间总是以冒号后跟一个空格 ": " 分隔。这是标准格式。因此,如果我们想要获取具有 name/value 对的对象,则需要用一点 JavaScript 代码来处理它们。像这样(假设如果两个 header 具有相同的名称,那么后者就会覆盖前者):let headers = xhr .getAllResponseHeaders() .split('\r\n') .reduce((result, current) => { let [name, value] = current.split(': '); result[name] = value; return result; }, {}); // headers['Content-Type'] = 'image/png'

POST,FormData

要建立一个 POST 请求,我们可以使用内建的 FormData 对象。

语法为:

let formData = new FormData([form]); // 创建一个对象,可以选择从 <form> 中获取数据
formData.append(name, value); // 附加一个字段

我们创建它,可以选择从一个表单中获取数据,如果需要,还可以 append 更多字段,然后:

  1. xhr.open('POST', ...) —— 使用 POST 方法。
  2. xhr.send(formData) 将表单发送到服务器。

例如:

<form name="person">
  <input name="name" value="John">
  <input name="surname" value="Smith">
</form>

<script>
  // 从表单预填充 FormData
  let formData = new FormData(document.forms.person);

  // 附加一个字段
  formData.append("middle", "Lee");

  // 将其发送出去
  let xhr = new XMLHttpRequest();
  xhr.open("POST", "/article/xmlhttprequest/post/user");
  xhr.send(formData);

  xhr.onload = () => alert(xhr.response);
</script>

multipart/form-data 编码发送表单。

或者,如果我们更喜欢 JSON,那么可以使用 JSON.stringify 并以字符串形式发送。

只是,不要忘记设置 header Content-Type: application/json,只要有了它,很多服务端框架都能自动解码 JSON:

let xhr = new XMLHttpRequest();

let json = JSON.stringify({
  name: "John",
  surname: "Smith"
});

xhr.open("POST", '/submit')
xhr.setRequestHeader('Content-type', 'application/json; charset=utf-8');

xhr.send(json);

.send(body) 方法就像一个非常杂食性的动物。它几乎可以发送任何 body,包括 BlobBufferSource 对象。

上传进度

progress 事件仅在下载阶段触发。

也就是说:如果我们 POST 一些内容,XMLHttpRequest 首先上传我们的数据(request body),然后下载响应。

如果我们要上传的东西很大,那么我们肯定会对跟踪上传进度感兴趣。但是 xhr.onprogress 在这里并不起作用。

这里有另一个对象,它没有方法,它专门用于跟踪上传事件:xhr.upload

它会生成事件,类似于 xhr,但是 xhr.upload 仅在上传时触发它们:

  • loadstart —— 上传开始。
  • progress —— 上传期间定期触发。
  • abort —— 上传中止。
  • error —— 非 HTTP 错误。
  • load —— 上传成功完成。
  • timeout —— 上传超时(如果设置了 timeout 属性)。
  • loadend —— 上传完成,无论成功还是 error。

handler 示例:

xhr.upload.onprogress = function(event) {
  alert(`Uploaded ${event.loaded} of ${event.total} bytes`);
};

xhr.upload.onload = function() {
  alert(`Upload finished successfully.`);
};

xhr.upload.onerror = function() {
  alert(`Error during the upload: ${xhr.status}`);
};

这是一个真实示例:带有进度指示的文件上传:

<input type="file" onchange="upload(this.files[0])">

<script>
function upload(file) {
  let xhr = new XMLHttpRequest();

  // 跟踪上传进度
  xhr.upload.onprogress = function(event) {
    console.log(`Uploaded ${event.loaded} of ${event.total}`);
  };

  // 跟踪完成:无论成功与否
  xhr.onloadend = function() {
    if (xhr.status == 200) {
      console.log("success");
    } else {
      console.log("error " + this.status);
    }
  };

  xhr.open("POST", "/article/xmlhttprequest/post/upload");
  xhr.send(file);
}
</script>

跨源请求

XMLHttpRequest 可以使用和 fetch 相同的 CORS 策略进行跨源请求。

就像 fetch 一样,默认情况下不会将 cookie 和 HTTP 授权发送到其他域。要启用它们,可以将 xhr.withCredentials 设置为 true

let xhr = new XMLHttpRequest();
xhr.withCredentials = true;

xhr.open('POST', 'http://anywhere.com/request');
...

有关跨源 header 的详细信息,请见 Fetch:跨源请求 一章。

总结

使用 XMLHttpRequest 的 GET 请求的典型代码:

let xhr = new XMLHttpRequest();

xhr.open('GET', '/my/url');

xhr.send();

xhr.onload = function() {
  if (xhr.status != 200) { // HTTP error?
    // 处理 error
    alert( 'Error: ' + xhr.status);
    return;
  }

  // 获取来自 xhr.response 的响应
};

xhr.onprogress = function(event) {
  // 报告进度
  alert(`Loaded ${event.loaded} of ${event.total}`);
};

xhr.onerror = function() {
  // 处理非 HTTP error(例如网络中断)
};

实际上还有很多事件,在 现代规范 中有详细列表(按生命周期排序):

  • loadstart —— 请求开始。
  • progress —— 一个响应数据包到达,此时整个 response body 都在 response 中。
  • abort —— 调用 xhr.abort() 取消了请求。
  • error —— 发生连接错误,例如,域错误。不会发生诸如 404 这类的 HTTP 错误。
  • load —— 请求成功完成。
  • timeout —— 由于请求超时而取消了该请求(仅发生在设置了 timeout 的情况下)。
  • loadend —— 在 loaderrortimeoutabort 之后触发。

erroraborttimeoutload 事件是互斥的。其中只有一种可能发生。

最常用的事件是加载完成(load),加载失败(error),或者我们可以使用单个 loadend 处理程序并检查请求对象 xhr 的属性,以查看发生了什么。

我们还了解了另一个事件:readystatechange。由于历史原因,它早在规范制定之前就出现了。如今我们已经无需使用它了,我们可以用新的事件代替它,但通常可以在旧的代码中找到它。

如果我们需要专门跟踪上传,那么我们应该在 xhr.upload 对象上监听相同的事件。

JS 面对对象基础

面对对象是什么

  • 什么是对象
    • 什么是收音机,许多成分构成的整体,提供一些功能
    • 对象是一个整体,对外界提供一些操作
  • 什么是面对对象
    • 使用对象时,只关注对象提供的功能,不关注其内部细节
    • 比如 JQuery
  • 面向对象是一种通用思想,并非只有编程中能用,任何事情都可以面对对象

JS 中的面对对象

  • 面对对象编程(OOP)的特点
    • 抽象:抓住核心问题,把主要特征、相关特征抽出来
    • 封装:不考虑内部实现,只考虑功能使用
    • 继承:基于已有对象,继承出新的对象
      • 多态继承:同时具有几个父对象的特性
      • 多态:JAVA 等强类型语言常用,JS 不常用
  • 对象的组成
    • 方法——函数:过程、动态的
      • 函数:不属于对象
      • 方法:属于对象的函数
    • 属性——变量:状态、静态的
      • 变量:不属于对象
      • 属性:属于对象的变量

第一个面对对象的程序

  • 为对象添加方法和属性

    • this
      

      详解,事件处理中

      this
      

      的本质

      • window
      • this —— 函数属于谁
    • 不能在系统对象中随意附加方法、属性,否则会覆盖已有方法、属性

    • Object 对象:系统空白对象

工厂方式

  • 工厂方式

    • 用构造函数创建一个类
    • 什么是类、对象(实例):模具和零件
    • 笔记:构造函数/工厂函数
      • 构建对象的函数
      • constructor 属性 返回所有 JavaScript 变量的构造器函数。
  • 工厂方式的问题

    • 没有 new
    • 函数重复定义:函数内容一样却不相等,浪费大量系统资源
  • 问题解决:

    构造函数加上

    new
    

    ,

    然后用原型

    Prototype
    

    为对象添加

    方法

    • new
      

      做了两件事

      • 替你创建了一个空白对象var this = new Object()
      • 替你返回了这个空白对象return this
    • newthis

原型:Prototype

  • 原型是什么

    • 原型是 class,修改它可以影响一类元素
    • 在已有对象中加入自己的属性、方法
  • 为所有 Array 添加 Sum 方法:Array.prototype.sum = function () {}

    • 给对象添加方法,类似于行间样式
    • 给原型添加方法,类似于 class
  • 原型的小缺陷

    • 无法限制覆盖
  • 类和对象的区别

    • 类:生产对象的模板

      Array
      
      • var arr = new Array()
    • 对象:产品 arr

  • 总结:用构造函数加属性,用原型加方法,叫做混合方式构造对象

  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>面对对象基础</title>
        <style>
        </style>
        <script>
          // 工厂方式
          function CreatePerson(name, qq) {
            var obj = new Object();
    
            obj.name = name;
            obj.qq = qq;
            
            obj.showName = function () {
              console.log('名字:', this.name);
            }
            obj.showQQ = function () {
              console.log('QQ:', this.qq)
            }
    
            return obj;
          }
          var person = CreatePerson('zhangsan','212345678');
          person.showName();
          person.showQQ();
    
          // 使用原型
          function CreatePerson2(name, qq) {
            this.name = name;
            this.qq = qq;
          }
                  
          CreatePerson2.prototype.showName2 = function () {
            console.log('名字:', this.name);
          }
          CreatePerson2.prototype.showQQ2 = function () {
            console.log('QQ:', this.qq)
          }
          var people = new CreatePerson2('asdf','535');
          people.showName2();
          people.showQQ2();
        </script>
      </head>
      <body>
      </body>
    </html>
    

面对对象编程方式

  • 用混合方式构造对象
    • 混合的构造函数 / 原型方式
    • Mixed Constructor Function / Prototype Method
  • 原则
    • 构造函数:加属性
    • 原型:加方法
  • 对象命名规范
    • 类名首字母大写

JS 面对对象实例

面对对象的选项卡

  • 把面向过程的程序,改写成面向对象的形式

    • 原则:不能有函数套函数,但可以有全局变量
    • 过程:
      • onload:构造函数
      • 全局变量:属性
      • 函数:方法
    • 改错:
      • this、事件、闭包、传参
  • 对象与闭包

    • 通过闭包传递 this
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>面对对象的选项卡</title>
        <style>
          .div2 {
            width: 200px;
            height: 200px;
            margin-top: 20px;
            position: relative;
          }
          .div1 {
            width: 200px;
            height: 20px;
            position: absolute;
            top: 0px;
          }
          ul {
            margin: 0;
            padding: 0;
            display: block;
            background: rgb(157, 234, 253);
            float: left;
            position: absolute;
            display: none;
            width: 200px;
            height: 200px;
          }
          .ul {
            display: block;
          }
          a {
            display: block;
            float: left;
            width: 49px;
            height: 20px;
            background: rgb(7, 184, 253);
            border-right: 1px solid rgb(255, 0, 234);
            text-decoration: none;
          }
          .a {
            background: rgb(32, 108, 221);
          }
        </style>
        <script>
        // 封装 getElementById 函数
        function get(id) {
            return document.getElementById(id);
          }
        // 封装 getElementsByTagName
        function gets(obj,tagName) {
          return obj.getElementsByTagName(tagName)
        }
        // onload 作为构造函数
        window.onload = function () {
          new TabSwitch('tabS')
        }
        // 构造一个对象
        function TabSwitch(id){
            var oDiv = get(id);
            var _this = this; // 避免找不到 this
            // 全局变量作为属性
            this.aA = gets(oDiv,'a');
            this.aUl = gets(oDiv,'ul');
            // 显示第一个元素
            this.aUl[0].className = 'ul';
            // 当鼠标覆盖某个标签时 显示对应元素
            for (var i = 0; i < this.aUl.length; i++) {
              this.aA[i].index = i;
              this.aA[i].onmouseover = function () {
                // 把当前this作为参数传入,_this作为当前this调用直接传入
                _this.showTab(this); 
              }
            }
          }
          // 函数作为方法 事件this作为参数传入
          TabSwitch.prototype.showTab = function (aA) {
            // console.log(this); // 当前this是调用方法的_this
            for (var i = 0; i < this.aA.length; i++) {
              this.aUl[i].className = '';
              this.aA[i].className = '';
            }
            this.aUl[aA.index].className = 'ul';
            this.aA.className = 'a';
          }
        </script>
      </head>
      <body>
        <div id="tabS">
          <div class="div1">
            <a href="javascript:;" id="a0">11</a>
            <a href="javascript:;" id="a1">22</a>
            <a href="javascript:;" id="a2">33</a>
            <a href="javascript:;" id="a3">44</a>
          </div>
          <div class="div2">
            <ul>
              <li>1</li>
            </ul>
            <ul>
              <li>2</li>
            </ul>
            <ul>
              <li>3</li>
            </ul>
            <ul>
              <li>4</li>
            </ul>
        </div>
        </div>
      </body>
    </html>
    

JS 面对对象高级

Json 方式的面向对象

  • 把方法包在一个 Json 里:简单 单体 不适合多个对象

    • 有人管它叫:命名空间
    • 把同一类方法,放在一起
  • 代码:

    var json = {
          name: 'zhangsan',
          QQ: 34543643,
          age: 23,
          showName: function () {
            console.log(this.name);
          },
          showQQ: function () {
            console.log(this.QQ);
          }
        }
        json.showName();
        json.showQQ();
    

拖拽和继承

  • 面向对象的拖拽

    • 改写原有拖拽,代码同下
  • 对象的继承

    • 什么是继承

      • 在原有类的基础上略作修改,得到一个新类
      • 不影响原有类的功能
    • instanceof
      

      运算符:返回

      true
      

      ,如果对象是对象类型的实例。

      • 查看对象是否是某个类的实例

使用继承

  • 限制范围的拖拽类

    • 构造函数的伪装

      • 属性的继承

        • 原理
      • call 的使用

        function A() {
        	this.abc = 12;
        }
        A.rototype.show = {
        	alert(this.abc);
        }
        function B() {
        	A.call(this); // 用 call 继承属性,把B传入A函数内
        }
        // B.prototype = A.prototype; // 浅复制方法是引用,指向同一个内存空间
        for (var i in A.prototype) {
            B.prototype[i] = A.ptoyotype[i]; // 深度复制就不会引用,直接复制内容
        }
        var obj = new B();
        alert(obj.abc);
        obj.show.call(); // call 一般省略
        
  • 原型链

    • 方法的继承
      • 原理:复制方法是引用,指向同一个内存空间
    • 覆盖原型的方法复制
      • for in 深度复制就不会引用,直接复制内容
  • 代码:拖拽改写为面对对象并继承一个新的对象

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>面对对象的拖拽</title>
        <link rel="stylesheet" href="../reset.css">
        <style>
          #div1 {
            top: 100px;
            left: 100px;
            width: 200px;
            height: 200px;
            position: absolute;
            background-color: rgb(255, 0, 0);
          }
          #div2 {
            width: 200px;
            height: 200px;
            position: absolute;
            background-color: rgb(0, 255, 170)
          }
        </style>
        <script src="./lib/Drag.js"></script>
        <script src="./lib/LimitDrag.js"></script>
        <script>
    
        window.onload = function () {
          new Drag('div1');
          new LimitDrag('div2');
        }
        
        </script>
      </head>
      <body>
        <div id="div1">普通拖拽</div>
        <div id="div2">限制范围的拖拽</div>
      </body>
    </html>
    
    function Drag(id) {
      this.disX = '';
      this.disY = '';
      this.oDiv = document.getElementById(id);
      var _this = this;
      this.oDiv.onmousedown = function (ev) {
        _this.fnDown(ev);
        return false;
      };
    }
    Drag.prototype.fnDown = function (ev) {
      var ev = event||ev;
      var _this = this;
      // 鼠标可视区位置 - div左边距 = 鼠标在div内的位置
      this.disX = ev.clientX - this.oDiv.offsetLeft;
      this.disY = ev.clientY - this.oDiv.offsetTop;
      console.log(this.disX,'可视区鼠标X:', ev.clientX, '鼠标Y:',ev.clientY);
      document.onmousemove = function (ev) {
        _this.mouseMove(ev);
      }
      document.onmouseup = function (ev) {
        _this.mouseUp(ev);
      }
    }
    Drag.prototype.mouseMove = function(ev) {
        // 不断获取Event 对象,坐标才会不断更新
        var ev = event||ev;
        // console.log('可视区鼠标X:', ev.clientX, '鼠标Y:',ev.clientY);
        // div位置 = 鼠标可视区新的位置 - 鼠标与div的距离
        this.oDiv.style.left = ev.clientX - this.disX + 'px';
        this.oDiv.style.top = ev.clientY - this.disY + 'px';
      }
    Drag.prototype.mouseUp = function () {
      document.onmousemove = '';
      document.onmouseup = ''; 
    }
    
    // 继承属性
    function LimitDrag(id) {
      Drag.call(this, id);
    }
    // 继承原型
    for (var i in Drag.prototype) {
      LimitDrag.prototype[i] = Drag.prototype[i];
    }
    
    LimitDrag.prototype.mouseMove = function(ev) {
      // 不断获取Event 对象,坐标才会不断更新
      var ev = event||ev;
      // console.log('可视区鼠标X:', ev.clientX, '鼠标Y:',ev.clientY);
      // div位置 = 鼠标可视区新的位置 - 鼠标与div的距离
      var l = ev.clientX - this.disX;
      var t = ev.clientY - this.disY; 
      if (l < 0) {
        l = 0;
      } else if (l > document.documentElement.clientWidth - this.oDiv.offsetWidth) {
        l = document.documentElement.clientWidth - this.oDiv.offsetWidth;
      }
      if ( t < 0) {
        t = 0;
      } else if (t > document.documentElement.clientHeight - this.oDiv.offsetHeight) {
        t = document.documentElement.clientHeight - this.oDiv.offsetHeight;
      }
      this.oDiv.style.top = t + 'px';
      this.oDiv.style.left = l + 'px';
    }
    

系统对象

  • 本地对象

    • 什么是本地对象

    • 常用对象:可以实例化(

      new
      

      )

      • Object / Function / Array / String / Boolean / Number / Date / RegExp / Error
  • 内置对象(静态对象):不能实例化

    • 什么是本地对象
      • Global(无法使用) / Math
  • 宿主对象(由浏览器提供的对象)

    • DOM / BOM

JavaScript 对象定义

在 JavaScript 中,几乎“所有事物”都是对象。

  • 布尔是对象(如果用 new 关键词定义)
  • 数字是对象(如果用 new 关键词定义)
  • 字符串是对象(如果用 new 关键词定义)
  • 日期永远都是对象
  • 算术永远都是对象
  • 正则表达式永远都是对象
  • 数组永远都是对象
  • 函数永远都是对象
  • 对象永远都是对象

所有 JavaScript 值,除了原始值,都是对象。

JavaScript 原始值

原始值指的是没有属性或方法的值。

原始数据类型指的是拥有原始值的数据。

JavaScript 定义了 5 种原始数据类型:

  • string
  • number
  • boolean
  • null
  • undefined

原始值是一成不变的(它们是硬编码的,因此不能改变)。

假设 x = 3.14,您能够改变 x 的值。但是您无法改变 3.14 的值。

类型注释
“Hello”string“Hello” 始终是 “Hello”
3.14number3.14 始终是 3.14
truebooleantrue 始终是 true
falsebooleanfalse 始终是 false
nullnull(object) null 始终是 null
undefinedundefinedundefined 始终是 undefined

对象是包含变量的变量

JavaScript 变量能够包含单个的值:

var person = "Bill Gates";

对象也是变量。但是对象能够包含很多值。

值按照名称 : 值对的形式编写(名称和值以冒号分隔)。

var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"};

JavaScript 对象是命名值的集合。

对象属性

JavaScript 对象中的命名值,被称为属性

属性
firstNameBill
lastNameGates
age62
eyeColorblue

以名称值对书写的对象类似于:

  • PHP 中的关联数组
  • Python 中的字典
  • C 中的哈希表
  • Java 中的哈希映射
  • Ruby 和 Perl 中的散列

对象方法

方法是可以在对象上执行的动作

对象属性可以是原始值、其他对象以及函数。

对象方法是包含函数定义的对象属性。

属性
firstNameBill
lastNameGates
age62
eyeColorblue
fullNamefunction() {return this.firstName + " " + this.lastName;}

JavaScript 对象是被称为属性和方法的命名值的容器。

您将在下一章中学到更多有关方法的知识。

创建 JavaScript 对象

通过 JavaScript,您能够定义和创建自己的对象。

有不同的方法来创建对象:

  • 定义和创建单个对象,使用对象文字。
  • 定义和创建单个对象,通过关键词 new。
  • 定义对象构造器,然后创建构造类型的对象。

在 ECMAScript 5 中,也可以通过函数 Object.create() 来创建对象。

使用对象字面量

这是创建对象最简答的方法。

使用对象文字,您可以在一条语句中定义和创建对象。

对象文字指的是花括号 {} 中的 名称:值对(比如 age:62)。

下面的例子创建带有四个属性的新的 JavaScript 对象:

var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"};

空格和折行不重要。对象定义可横跨多行:

var person = {
    firstName:"Bill",
    lastName:"Gates",
    age:62,
    eyeColor:"blue"
};

使用 JavaScript 关键词 new

下面的例子也创建了带有四个属性的新的 JavaScript 对象:

var person = new Object();
person.firstName = "Bill";
person.lastName = "Gates";
person.age = 50;
person.eyeColor = "blue"; 

上面的两个例子结果是一样的。无需使用 new Object()

出于简易性、可读性和执行速度的考虑,请使用第一种创建方法(对象文字方法)。

JavaScript 对象是易变的

对象是易变的:它们通过引用来寻址,而非值。

如果 person 是一个对象,下面的语句不会创建 person 的副本:

var x = person;  // 这不会创建 person 的副本。

对象 x 并非 person 的副本。它就是 person。x 和 person 是同一个对象。

对 x 的任何改变都将改变 person,因为 x 和 person 是相同的对象。

var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"}
 
var x = person;
x.age = 10;           // 这将同时改变 both x.age 和 person.age

**注释:**JavaScript 变量不是易变的。只有 JavaScript 对象如此。

JavaScript 对象方法

JavaScript 方法

JavaScript 方法是能够在对象上执行的动作。

JavaScript 方法是包含函数定义的属性。

属性
firstNameBill
lastNameGates
age62
eyeColorblue
fullNamefunction() {return this.firstName + " " + this.lastName;}

方法是存储为对象属性的函数。

this 关键词

在 JavaScript 中,被称为 this 的事物,指的是拥有该 JavaScript 代码的对象。

this 的值,在函数中使用时,是“拥有”该函数的对象。

请注意 this 并非变量。它是关键词。您无法改变 this 的值。

访问对象方法

请使用如下语法创建对象方法:

methodName : function() { 代码行 }

请通过如下语法来访问对象方法:

objectName.methodName()

您通常会把 fullName() 描述为 person 对象的方法,把 fullName 描述为属性。

fullName 属性在被通过 () 调用后会以函数形式执行。

此例访问 person 对象的 fullName() 方法

name = person.fullName();

如果您访问 fullName 属性时没有使用 (),则将返回函数定义

name = person.fullName;

使用内建方法

此例使用 String 对象的 toUpperCase() 方法,把文本转换为大写:

var message = "Hello world!";
var x = message.toUpperCase();

x 的值,在以上代码执行后将是:

HELLO WORLD!

添加新的方法

向对象添加方法是在构造器函数内部完成的:

function person(firstName, lastName, age, eyeColor) {
    this.firstName = firstName;  
    this.lastName = lastName;
    this.age = age;
    this.eyeColor = eyeColor;
    this.changeName = function (name) {
        this.lastName = name;
    };
}

changeName() 函数 name 的值赋给了 person 的 lastName 属性。

现在您可以尝试:

myMother.changeName("Jobs");

JavaScript 对象属性

属性指的是与 JavaScript 对象相关的值。

JavaScript 对象是无序属性的集合。

属性通常可以被修改、添加和删除,但是某些属性是只读的。

访问 JavaScript 属性

访问对象属性的语法是:

objectName.property           // person.age

或者:

objectName["property"]       // person["age"]

或者:

objectName[expression]       // x = "age"; person[x]

表达式必须计算为属性名。

person.firstname + " is " + person.age + " years old.";

person["firstname"] + " is " + person["age"] + " years old.";

JavaScript for…in 循环

JavaScript for…in 语句遍历对象的属性。

for (variable in object) {
    要执行的代码
}

for…in 循环中的代码块会为每个属性执行一次。

循环对象的属性:

var person = {fname:"Bill", lname:"Gates", age:62}; 

for (x in person) {
    txt += person[x];
}

添加新属性

您可以通过简单的赋值,向已存在的对象添加新属性。

假设 person 对象已存在 - 那么您可以为其添加新属性:

person.nationality = "English";

您不能使用预留词作为属性名(或方法名)。请使用 JavaScript 命名规则。

删除属性

delete 关键词从对象中删除属性:

var person = {firstName:"Bill", lastName:"Gates", age:62, eyeColor:"blue"};
delete person.age;   // 或 delete person["age"];

delete 关键词会同时删除属性的值和属性本身。

删除完成后,属性在被添加回来之前是无法使用的。

delete 操作符被设计用于对象属性。它对变量或函数没有影响。

delete 操作符不应被用于预定义的 JavaScript 对象属性。这样做会使应用程序崩溃。

属性值

所有属性都有名称。此外它们还有值。

值是属性的特性之一。

其他特性包括:可列举、可配置、可写。

这些特性定义了属性被访问的方式(是可读的还是可写的?)

在 JavaScript 中,所有属性都是可读的,但是只有值是可修改的(只有当属性为可写时)。

(ECMAScript 5 拥有获取和设置所有属性特性的方法)

原型属性

JavaScript 对象继承了它们的原型的属性。

delete 关键词不会删除被继承的属性,但是如果您删除了某个原型属性,则将影响到所有从原型继承的对象。

JavaScript 对象访问器

ECMAScript 5 (2009) 引入了 Getter 和 Setter。

Getter 和 Setter 允许您定义对象访问器(被计算的属性)。

JavaScript Getter

本例使用 lang 属性来获取 language 属性的值。

实例

// 创建对象:
var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "en",
  get lang() {
    return this.language;
  }
};

// 使用 getter 来显示来自对象的数据:
document.getElementById("demo").innerHTML = person.lang;

JavaScript Setter

本例使用 lang 属性来设置 language 属性的值。

实例

var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "",
  set lang(lang) {
    this.language = lang;
  }
};

// 使用 setter 来设置对象属性:
person.lang = "en";

// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.language;

例子 1

var person = {
  firstName: "Bill",
  lastName : "Gates",
  fullName : function() {
    return this.firstName + " " + this.lastName;
  }
};

// 使用方法来显示来自对象的数据:
document.getElementById("demo").innerHTML = person.fullName();

例子2

var person = {
  firstName: "Bill",
  lastName : "Gates",
  get fullName() {
    return this.firstName + " " + this.lastName;
  }
};

// 使用 getter 来显示来自对象的数据:
document.getElementById("demo").innerHTML = person.fullName;

例子 1 以函数形式访问 fullName:person.fullName()。

例子 2 以属性形式访问 fullName:person.fullName。

第二个例子提供了更简洁的语法。

省略写法:

// 创建对象:
var person = {
  firstName: "Bill",
  lastName: "Gates",
  id: 12345,
  fullName() { // 省略 fullName:fullName(){}
    return this.firstName + " " + this.lastName;
  }
}

// 显示对象中的数据:
console.log(person.fullName());

数据质量

使用 getter 和 setter 时,JavaScript 可以确保更好的数据质量。

在本例中,使用 lang 属性以大写形式返回 language 属性的值:

// Create an object:
var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "en",
  get lang() {
    return this.language.toUpperCase();
  }
};

// 使用 getter 来显示来自对象的数据:
document.getElementById("demo").innerHTML = person.lang;
var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "",
  set lang(lang) {
    this.language = lang.toUpperCase();
  }
};

// 使用 getter 来设置对象属性:
person.lang = "en";

// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.language;

为什么使用 Getter 和 Setter?

  • 它提供了更简洁的语法
  • 它允许属性和方法的语法相同
  • 它可以确保更好的数据质量
  • 有利于后台工作

一个计数器实例

实例

var obj = {
  counter : 0,
  get reset() {
    this.counter = 0;
  },
  get increment() {
    this.counter++;
  },
  get decrement() {
    this.counter--;
  },
  set add(value) {
    this.counter += value;
  },
  set subtract(value) {
    this.counter -= value;
  }
};

// 操作计数器:
obj.reset;
obj.add = 5;
obj.subtract = 1;
obj.increment;
obj.decrement;
Object.defineProperty()

Object.defineProperty() 方法也可用于添加 Getter 和 Setter:

// 定义对象
var obj = {counter : 0};

// 定义 setters
Object.defineProperty(obj, "reset", {
  get : function () {this.counter = 0;}
});
Object.defineProperty(obj, "increment", {
  get : function () {this.counter++;}
});
Object.defineProperty(obj, "decrement", {
  get : function () {this.counter--;}
});
Object.defineProperty(obj, "add", {
  set : function (value) {this.counter += value;}
});
Object.defineProperty(obj, "subtract", {
  set : function (value) {this.counter -= value;}
});

// 操作计数器:
obj.reset;
obj.add = 5;
obj.subtract = 1;
obj.increment;
obj.decrement;

JavaScript 对象构造器

对象类型(蓝图)(类)

前一章的实例是有限制的。它们只创建单一对象。

有时我们需要创建相同“类型”的许多对象的“蓝图”。

创建一种“对象类型”的方法,是使用对象构造器函数

在上面的例子中,函数 Person() 就是对象构造器函数。

通过 new 关键词调用构造器函数可以创建相同类型的对象:

function Person(first, last, age, eye) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eye;
}

var myFather = new Person("Bill", "Gates", 62, "blue");
var myMother = new Person("Steve", "Jobs", 56, "green");

this 关键词

在 JavaScript 中,被称为 this 的事物是代码的“拥有者”。

this 的值,在对象中使用时,就是对象本身。

在构造器函数中,this 是没有值的。它是新对象的替代物。 当一个新对象被创建时,this 的值会成为这个新对象。

请注意 this 并不是变量。它是关键词。您无法改变 this 的值。

为构造器添加属性

与向已有对象添加新属性不同,您无法为对象构造器添加新属性:

如需向构造器添加一个新属性,您必须添加到构造器函数:

Person.nationality = "English"; //The nationality of my friend is undefined

function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
    this.nationality = "English";
}

为构造器添加方法

您的构造器函数也可以定义方法:

function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
    this.name = function() {return this.firstName + " " + this.lastName;};
}

与向已有对象添加新方法不同,您无法为对象构造器添加新方法。

必须在构造器函数内部向一个对象添加方法。

内建 JavaScript 构造器

JavaScript 提供用于原始对象的构造器:

var x1 = new Object();    // 一个新的 Object 对象
var x2 = new String();    // 一个新的 String 对象
var x3 = new Number();    // 一个新的 Number 对象
var x4 = new Boolean();   // 一个新的 Boolean 对象
var x5 = new Array();     // 一个新的 Array 对象
var x6 = new RegExp();    // 一个新的 RegExp 对象
var x7 = new Function();  // 一个新的 Function 对象
var x8 = new Date();      // 一个新的 Date 对象

Math() 对象不再此列。Math 是全局对象。new 关键词不可用于 Math。

更快创建对象的方式

正如以上所见,JavaScript 提供原始数据类型字符串、数字和布尔的对象版本。但是并无理由创建复杂的对象。原始值快得多!

请使用对象字面量 {} 代替 new Object()

请使用字符串字面量 "" 代替 new String()

请使用数值字面量代替 Number()

请使用布尔字面量代替 new Boolean()。

请使用数组字面量 [] 代替 new Array()

请使用模式字面量代替 new RexExp()

请使用函数表达式 () {} 代替 new Function()

var x1 = {};            // 新对象
var x2 = "";            // 新的原始字符串
var x3 = 0;             // 新的原始数值
var x4 = false;         // 新的原始逻辑值
var x5 = [];            // 新的数组对象
var x6 = /()/           // 新的正则表达式对象
var x7 = function(){};  // 新的函数对象

JavaScript 对象原型

我们已经认识到,您无法为已有的对象构造器添加新属性,如需向构造器添加一个新属性,则必须把它添加到构造器函数

原型继承

所有 JavaScript 对象都从原型继承属性和方法。

日期对象继承自 Date.prototype。数组对象继承自 Array.prototype。Person 对象继承自 Person.prototype。

Object.prototype 位于原型继承链的顶端:

日期对象、数组对象和 Person 对象都继承自 Object.prototype。

使用 prototype 属性

JavaScript prototype 属性允许您为对象构造器添加新属性:

function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
}
Person.prototype.nationality = "English";

JavaScript prototype 属性也允许您为对象构造器添加新方法:

function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
}
Person.prototype.name = function() {
    return this.firstName + " " + this.lastName;
};

ECMAScript 5 特性

这些是 2009 年发布的新特性:

  • “use strict” 指令
  • String.trim()
  • Array.isArray()
  • Array.forEach()
  • Array.map()
  • Array.filter()
  • Array.reduce()
  • Array.reduceRight()
  • Array.every()
  • Array.some()
  • Array.indexOf()
  • Array.lastIndexOf()
  • JSON.parse()
  • JSON.stringify()
  • Date.now()
  • 属性 Getter 和 Setter
  • 新的对象属性和方法

ECMAScript 5 语法更改

  • 对字符串的属性访问 [ ]
  • 数组和对象字面量中的尾随逗号
  • 多行字符串字面量
  • 作为属性名称的保留字

“use strict” 指令

“use strict” 定义 JavaScript 代码应该以“严格模式”执行。

例如,使用严格模式,不能使用未声明的变量。

您可以在所有程序中使用严格模式。它可以帮助您编写更清晰的代码,例如阻止您使用未声明的变量。

“use strict” 只是一个字符串表达式。旧浏览器如果不理解它们就不会抛出错误。

String.trim()

String.trim() 删除字符串两端的空白字符。

let str = "   \n\n    Hello World!  \n \x11 \r ?  \t\  ";
console.log(str.trim());

Array.isArray()

isArray() 方法检查对象是否为数组。

let a = [],
  b = {};
console.log(Array.isArray(a), Array.isArray(b));

Array.forEach()

forEach() 方法为每个数组元素调用一次函数。不支持 break、continue 等。

arr.forEach(function(elem, index, array) {
    if (arr[i] == 2) {
        continue
    }
    console.log(elem, index)
})

[1, 2, 3, 4, 5].forEach(function(i) {
    if (i === 2) {
        return;
    } else {
        console.log(i)
    }
})
  • 这段代码的"本意"是从第一个元素开始遍历,遇到数组项 2 之后就结束遍历,不然打印出所遍历过的数值项。可是,事实让你大跌眼镜,因为它的输出是 1, 3, 4, 5。

Array.map()

这个例子给每个数组值乘以 2:

var numbers1 = [45, 4, 9, 16, 25];
var numbers2 = numbers1.map(myFunction);

function myFunction(value) {
  return value * 2;
}

Array.filter()

此例用值大于 18 的元素创建一个新数组:

var numbers = [45, 4, 9, 16, 25];
var over18 = numbers.filter(myFunction);

function myFunction(value) {
  return value > 18;
}

Array.reduce()

这个例子确定数组中所有数的总和:

var numbers1 = [45, 4, 9, 16, 25];
var sum = numbers1.reduce(myFunction);

function myFunction(total, value) {
  return total + value;
}

Array.reduceRight()

这个例子同样是确定数组中所有数的总和:

var numbers1 = [45, 4, 9, 16, 25];
var sum = numbers1.reduceRight(myFunction);

function myFunction(total, value) {
  return total + value;
}

Array.every()

这个例子检查是否所有值都超过 18:

var numbers = [45, 4, 9, 16, 25];
var allOver18 = numbers.every(myFunction);

function myFunction(value) {
  return value > 18;
}

Array.some()

这个例子检查某些值是否超过 18:

var numbers = [45, 4, 9, 16, 25];
var allOver18 = numbers.some(myFunction);

function myFunction(value) {
  return value > 18;
}

Array.indexOf()

检索数组中的某个元素值并返回其位置:

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var a = fruits.indexOf("Apple");

Array.lastIndexOf()

Array.lastIndexOf() 与 Array.indexOf() 类似,但是从数组结尾处开始检索。

var fruits = ["Banana", "Orange", "Apple", "Mango"];
var a = fruits.lastIndexOf("Apple");

JSON.parse()

JSON 的一个常见用途是从 Web 服务器接收数据。

想象一下,您从Web服务器收到这条文本字符串:

'{"name":"Bill", "age":62, "city":"Seatle"}'

JavaScript 函数 JSON.parse() 用于将文本转换为 JavaScript 对象:

var obj = JSON.parse('{"name":"Bill", "age":62, "city":"Seatle"}');

JSON.stringify()

JSON 的一个常见用途是将数据发送到Web服务器。

将数据发送到 Web 服务器时,数据必须是字符串。

想象一下,我们在 JavaScript 中有这个对象:

var obj = {"name":"Bill", "age":62, "city":"Seatle"};

请使用 JavaScript 函数 JSON.stringify() 将其转换为字符串。

var myJSON = JSON.stringify(obj);

结果将是遵循 JSON 表示法的字符串。

myJSON 现在是一个字符串,准备好发送到服务器:

var obj = {"name":"Bill", "age":62, "city":"Seatle"};
var myJSON = JSON.stringify(obj);
document.getElementById("demo").innerHTML = myJSON;

Date.now()

Date.now() 返回自零日期(1970 年 1 月 1 日 00:00:00:00)以来的毫秒数。

var timInMSs = Date.now();

Date.now() 的返回与在 Date 对象上执行 getTime() 的结果相同。

属性 Getter 和 Setter

ES5 允许您使用类似于获取或设置属性的语法来定义对象方法。

这个例子为名为 fullName 的属性创建一个 getter

// 创建对象:
var person = {
  firstName: "Bill",
  lastName : "Gates",
  get fullName() {
    return this.firstName + " " + this.lastName;
  }
};

// 使用 getter 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.fullName;

这个例子为语言属性创建一个 setter 和一个 getter

var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "NO",
  get lang() {
    return this.language;
  },
  set lang(value) {
    this.language = value;
  }
};

// 使用 setter 设置对象属性:
person.lang = "en";

// 使用 getter 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.lang;

这个例子使用 setter 来确保语言的大写更新:

var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "NO",
  set lang(value) {
    this.language = value.toUpperCase();
  }
};

// 使用 setter 设置对象属性:
person.lang = "en";

// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.language;

新的对象属性和方法

Object.defineProperty() 是 ES5 中的新对象方法。

它允许您定义对象属性和/或更改属性的值和/或元数据。

// 创建对象:
var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "NO", 
};

// 更改属性:
Object.defineProperty(person, "language", {
  value: "EN",
  writable : true,
  enumerable : true,
  configurable : true
});

// 枚举属性
var txt = "";
for (var x in person) {
  txt += person[x] + "<br>";
}
document.getElementById("demo").innerHTML = txt;

下一个例子是相同的代码,但它隐藏了枚举中的语言属性:

// 创建对象:
var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "NO", 
};

// 更改属性:
Object.defineProperty(person, "language", {
  value: "EN",
  writable : true,
  enumerable : false,
  configurable : true
});

// 枚举属性
var txt = "";
for (var x in person) {
  txt += person[x] + "<br>";
}
document.getElementById("demo").innerHTML = txt;

此例创建一个 setter 和 getter 来确保语言的大写更新:

// 创建对象:
var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "NO"
};

// 更改属性:
Object.defineProperty(person, "language", {
  get : function() { return language },
  set : function(value) { language = value.toUpperCase()}
});

// 更改语言
person.language = "en";

// 显示语言
document.getElementById("demo").innerHTML = person.language;

ECMAScript 5 对象方法:

ES5 新的对象方法

// 添加或更改对象属性
Object.defineProperty(object, property, descriptor)

// 添加或更改多个对象属性
Object.defineProperties(object, descriptors)

// 访问属性
Object.getOwnPropertyDescriptor(object, property)

// 将所有属性作为数组返回
Object.getOwnPropertyNames(object)

// 将可枚举属性作为数组返回
Object.keys(object)

// 访问原型
Object.getPrototypeOf(object)

// 防止向对象添加属性
Object.preventExtensions(object)

// 如果可以将属性添加到对象,则返回 true
Object.isExtensible(object)

// 防止更改对象属性(而不是值)
Object.seal(object)

// 如果对象被密封,则返回 true
Object.isSealed(object)

// 防止对对象进行任何更改
Object.freeze(object)

// 如果对象被冻结,则返回 true
Object.isFrozen(object)

对字符串的属性访问

charAt() 方法返回字符串中指定索引(位置)的字符:

var str = "HELLO WORLD";
str.charAt(0);            // 返回 H

ECMAScript 5 允许对字符串进行属性访问:

var str = "HELLO WORLD";
str[0];                   // 返回 H

对字符串的属性访问可能有点不可预测。

尾随逗号(Trailing Commas)

ECMAScript 5 允许在对象和数组定义中使用尾随逗号:

Object 实例
person = {
  firstName: "Bill",
  lastName: " Gates",
  age: 62,
}
Array 实例
points = [
  1,
  5,
  10,
  25,
  40,
  100,
];

警告!!!

Internet Explorer 8 将崩溃。

JSON 不允许使用尾随逗号。

JSON 对象:
// 允许:
var person = '{"firstName":"Bill", "lastName":"Gates", "age":62}'
JSON.parse(person)

// 不允许:
var person = '{"firstName":"Bill", "lastName":"Gates", "age":62,}'
JSON.parse(person)
JSON 数组:
// 允许:
points = [40, 100, 1, 5, 25, 10]

// 不允许:
points = [40, 100, 1, 5, 25, 10,]

多行字符串

如果使用反斜杠转义,ECMAScript 5 允许多行的字符串文字(字面量):

"Hello \
Kitty!";

\ 方法可能没有得到普遍的支持。

较旧的浏览器可能会以不同的方式处理反斜杠周围的空格。

一些旧的浏览器不允许 \ 字符后面的空格。

分解字符串文字的一种更安全的方法是使用字符串添加:

"Hello " + 
"Kitty!";

保留字作为属性名称

ECMAScript 5允许保留字作为属性名称:

var obj = {name: "Bill", new: "yes"}

ES5 新的对象方法

// 添加或更改对象属性
Object.defineProperty(object, property, descriptor)

// 添加或更改多个对象属性
Object.defineProperties(object, descriptors)

// 访问属性
Object.getOwnPropertyDescriptor(object, property)

// 以数组返回所有属性
Object.getOwnPropertyNames(object)

// 以数组返回所有可枚举的属性
Object.keys(object)

// 访问原型
Object.getPrototypeOf(object)

// 阻止向对象添加属性
Object.preventExtensions(object)

// 如果可将属性添加到对象,则返回 true
Object.isExtensible(object)

// 防止更改对象属性(而不是值)
Object.seal(object)

// 如果对象被密封,则返回 true
Object.isSealed(object)

// 防止对对象进行任何更改
Object.freeze(object)

// 如果对象被冻结,则返回 true
Object.isFrozen(object)

更改属性值

Object.defineProperty(object, property, {value : value})

本例更改了属性值:

var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "EN" 
};

// 更改属性
Object.defineProperty(person, "language", {value : "ZH"});

更改元数据

ES5 允许更改以下属性元数据:

writable : true      // 属性值可修改
enumerable : true    // 属性可枚举
configurable : true  // 属性可重新配置
writable : false     // 属性值不可修改
enumerable : false   // 属性不可枚举
configurable : false // 属性不可重新配置

ES5 允许更改 getter 和 setter:

// 定义 getter
get: function() { return language }
// 定义 setter
set: function(value) { language = value }

此例使语言为只读:

Object.defineProperty(person, "language", {writable:false});

此例使语言不可枚举:

Object.defineProperty(person, "language", {enumerable:false});

列出所有属性

此例列出对象的所有属性:

var person = {
  firstName: "Bill",
  lastName : "Gates"
  language : "EN" 
};

Object.defineProperty(person, "language", {enumerable:false});
Object.getOwnPropertyNames(person);  // 返回属性数组

列出可枚举的属性

此例只列出对象的所有可枚举属性:

var person = {
  firstName: "Bill",
  lastName : "Gates"
  language : "EN" 
};

Object.defineProperty(person, "language", {enumerable:false});
Object.keys(person);  // 返回可枚举属性的数组

添加属性

此例向对象添加新属性:

// 创建对象
var person = {
  firstName: "Bill",
  lastName : "Gates",
  language : "EN"
};

// 添加属性
Object.defineProperty(person, "year", {value:"2008"});

添加 Getter 和 Setter

Object.defineProperty() 方法也可以用于添加 Getter 和 Setter:

// 创建对象
var person = {firstName:"Bill", lastName:"Gates"};

// 定义 getter
Object.defineProperty(person, "fullName", {
  get : function () {return this.firstName + " " + this.lastName;}
});

BOM 应用

BOM 基础

  • 打开、关闭窗口

    • open(url, 打开方式)
      

      open('ablout.blank', '_blank')
      
      • 例子:页面内运行代码功能
    • close(url, 打开方式)
      

      window.close()
      

      关闭当前窗口

      • 例子:关闭时提示问题
        • 只能关闭自己 open 的窗口
  • 常用属性

    • window.navigator.userAgent
      
      • navigator:包含大量信息
      • userAgent:浏览器信息
    • window.location
      
      • href:当前网页地址
      • hostname:主机域名
      • pathname:页面路径和文件名
      • port:端口
      • protocol:http协议
      • assign:加载新文档,url
    • window.history
      
      • back():后退
      • forward():前进
      • go():历史中某个页面,-1 用于登陆后回跳

尺寸及坐标

  • 窗口尺寸、工作区尺寸
    • 可视区尺寸
      • document.documentElement.clientWidth
      • document.documentElement.clientHeight
    • 滚动距离
      • document.body.scrollTop:旧版本 chrome 和没有 DOCTYPE 声明的 IE
      • document.documentElement.scrollTop:IE FF
      • 完美的获取 scrollTop 赋值短语 : var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;

常用方法和事件

  • 系统对话框

    • 警告框:alert("内容"),没有返回值
    • 选择框:confirm("提问的内容"),返回 boolean
    • 输入框:prompt(),返回字符串或 null
  • window 对象常用事件

    • onload:页面加载完发生
    • onscroll:页面滚动时发生
    • onresize:事件会在窗口或框架被调整大小时发生
    • 例子:回到顶部按钮、侧边栏广告
      • 闪烁问题
        • userAgent > IE6position:fixed;
        • userAgent < IE6 用运动;
  • 代码:

    <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>Bom应用</title>
        <style>
          body {
            height: 2000px;
          }
        </style>
        <script>
        // 封装 getElementById 函数
        function get(id) {
          return document.getElementById(id);
        }
    
        window.onload = function () {
          // var text =  document.write('新网页');
          var btn = get('btn');
          var btn2 = get('btn2');
          btn.onclick = function () {
            window.open('27.BOM应用.html','_blank');
          }
          btn2.onclick = function () {
            window.close();
          }
    
    
          window.onscroll = function () {
            var scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
            console.log('scrollTop:',scrollTop);
          }
          
          console.log(window.navigator.userAgent);
          console.log(window.location.href);
          // alert('0');
          // confirm('yes?');
          // prompt('');
    
          window.onresize = function () {
            var cliHei = document.documentElement.clientHeight;
            var cliWid = document.documentElement.clientWidth;
            console.log('可视区高宽:',cliHei, cliWid)
          }
        }
        </script>
    </head>
      <body>
        <input type="button"  id="btn" value="打开网页">
        <input type="button"  id="btn2" value="关闭网页">
      </body>
    </html>
    

COOKIE 基础与应用

什么是 cookie

  • 页面用来保存信息

    • 比如:自动登录、记住用户名
  • cookie
    

    的特征

    • 同一网站中所有页面共享一套 cookie
    • 数量、大小有限
    • 过期时间
  • JS 中使用

    cookie
    
    • document.cookie

使用 cookie

  • 设置 cookie

    • 格式:名字 = 值

    • 赋值时不会覆盖

    • 过期时间:expires = 时间

      • 设置前一个 cookie 数据的过期时间,expires 放在数据后面:
        • document.cookie = 'password=123;expires='+ oDate;
      • 日期对象的使用
    • 封装函数

      // 封装 setCookie 函数
            function setCookie(name, value, iTime) {
              var oDate = new Date();
              oDate.setTime(oDate.getTime() + iTime); // 毫秒
              document.cookie = name + '=' + value + ';expires=' + oDate;
            }
            setCookie('username', '张三', 1000*60*60);
      
  • 读取 cookie

    • 字符串分割

      // 封装 getCookie 函数
       getCookie(name) {
              var arr = document.cookie.split('; ');
              for (var i in arr) {
                var arr2 = arr[i].split('=');
                if (arr2[0] === name){
                  return arr2[1];
                }
              }
              return '';
            }
            console.log(getCookie('username'));
      
  • 删除 cookie

    • 已经过期

      // 封装 removeCookie 函数
      function removeCookie(name) {
              setCookie(name, '', -1)
            }
            removeCookie('username');
      
  • 例子:使用 cookie 记录上次登陆的用户名

    • 提交时:记录用户名

    • window.onload:读取用户名

    • 代码:

      <!DOCTYPE html>
      <html>
        <head>
          <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
          <title>28.1.登陆后cookie读取用户名</title>
          <style>
          </style>
          <script>
            // 封装 setCookie 函数
            function setCookie(name, value, iTime) {
              var oDate = new Date();
              oDate.setTime(oDate.getTime() + iTime*1000*60*60);
              document.cookie = name + '=' + value + ';expires=' + oDate;
            }
            // 封装 getCookie 函数
            function getCookie(name) {
              var arr = document.cookie.split('; ');
              for (var i in arr) {
                var arr2 = arr[i].split('=');
                if (arr2[0] === name){
                  return arr2[1];
                }
              }
              return '';
            }
            // 封装 removeCookie 函数
            function removeCookie(name) {
              setCookie(name, '', -1)
            }
      
            window.onload = function () {
              var oUser = document.getElementById('username');
              var oPasswd = document.getElementById('passwd');
              var oBtn_sub = document.getElementById('btn_sub');
              if (getCookie('username')) {
                oUser.value = getCookie('username');
              }
              oBtn_sub.onclick = function () {
                setCookie("username", oUser.value, 1);
                setCookie("passwd", oPasswd.value, 1);
              }
            }
          </script>
        </head>
        <body>
          <form action="28.1.登陆后cookie读取用户名.html" method="GET">
          <input type="text" name="username" id="username">
          <input type="text" name="passwd" id="passwd">
          <input type="submit" name="" id="btn_sub" value="登录">
          </form>
        </body>
      </html>
      

JS 中的正则表达式

正则表达式基础

  • 复习字符串操作:

    var str = 'asdf1234';
    
    • search查找位置 str.search('3')

    • substring
      

      :获取子字符串,

      • 截取某段字符串, 不包含结束位str.substring(2,5)
      • 获取起点以后的字符串:str.substring(2)
    • charAt获取某个字符串 str.charAt(2)

    • split分割某个字符串 str.split('-')

  • 找出字符串中所有的数字

    • 用传统字符串操作完成
    • 用正则表达式完成
  • 什么是正则表达式

    • 什么叫正则?

      • 规则、模式
    • 强大的字符串匹配工具

    • 是一种人类很难读懂的文字

    • RegExp
      

      对象

      • JS 风格:new RegExp( "a" , "i" )
      • perl 风格:/a/i

字符串与正则配合

  • search:字符串搜索,返回位置或 -1

    • 返回出现的位置
    • 忽略大小写:i:ignore
    • 判断浏览器类型
  • match:获取匹配的项目,返回元素或

    • 量词:+ (若干个)
    • 量词变化:\d(单个数字一组) \d\d(两个数字一组) 和 \d+(若干连续数字)
    • 全局匹配:g:global
    • 例子:找出所有数字
  • replace(reg/str,replacement):替换所有匹配

    • 返回替换后的字符串
    • 例子:敏感词过滤
  • reg.test() 的问题

    • 一次是true, 一次是false. 原因在于正则表达式中的g, 使得搜索过程后, 如果匹配成功, 则记录上一次的位置, 如果匹配不成功, 则会归零.
    // 人工将位置归零, 防止这个 "错误" 的发生:
    var re = /^\w$/g;
    re.test('a'); //返回true
    re.lastIndex = 0; //归零搜索的位置
    re.test('b'); //返回true
    
    // 或者我们可以更简单地直接将g去掉:
    var re = /^\w$/;
    re.test('a'); //返回true
    re.test('b'); //返回true
    
  • exec() 方法用于检索字符串中的正则表达式的匹配。

    RegExpObject.exec(string)
    
    参数描述
    string必需。要检索的字符串

    如果 exec() 找到了匹配的文本,则返回一个结果数组。否则,返回 null。此数组的第 0 个元素是与正则表达式相匹配的文本,第 1 个元素是与 RegExpObject 的第 1 个子表达式相匹配的文本(如果有的话),第 2 个元素是与 RegExpObject 的第 2 个子表达式相匹配的文本(如果有的话),以此类推。除了数组元素和 length 属性之外,exec() 方法还返回两个属性。index 属性声明的是匹配文本的第一个字符的位置。input 属性则存放的是被检索的字符串 string。我们可以看得出,在调用非全局的 RegExp 对象的 exec() 方法时,返回的数组与调用方法 String.match() 返回的数组是相同的。

    但是,当 RegExpObject 是一个全局正则表达式时,exec() 的行为就稍微复杂一些。它会在 RegExpObject 的 lastIndex 属性指定的字符处开始检索字符串 string。当 exec() 找到了与表达式相匹配的文本时,在匹配后,它将把 RegExpObject 的 lastIndex 属性设置为匹配文本的最后一个字符的下一个位置。这就是说,您可以通过反复调用 exec() 方法来遍历字符串中的所有匹配文本。当 exec() 再也找不到匹配的文本时,它将返回 null,并把 lastIndex 属性重置为 0。

    **重要事项:**如果在一个字符串中完成了一次模式匹配之后要开始检索新的字符串,就必须手动地把 lastIndex 属性重置为 0。

    **提示:**请注意,无论 RegExpObject 是否是全局模式,exec() 都会把完整的细节添加到它返回的数组中。这就是 exec() 与 String.match() 的不同之处,后者在全局模式下返回的信息要少得多。因此我们可以这么说,在循环中反复地调用 exec() 方法是唯一一种获得全局模式的完整模式匹配信息的方法。

    var str = "Visit W3School"; 
    var patt = new RegExp("W3School","g");
    var result;
    
    while ((result = patt.exec(str)) != null)  {
      document.write(result);
      document.write("<br />");
      document.write(patt.lastIndex);
     }
    

字符串

  • 任意字符:

    []
    

    方括号(元字符)

    • [abc]
      
      • 例子:a[usb]tobt ost out
  • 范围

    • [a-z]
      
      [0-9]
      
      • 例子:id[0-9]id0 id5
  • 排除

    • [^a]
      
      • 例子:o[^0-9]oat ``o?t ot
  • 组合

    • [a-z0-9A-Z]
  • 实例:偷小说

    • 过滤 HTML 标签,
      • 正则贪婪特性,从最长的内容开始过滤
      • 自定义 innerText 方法
    • 代码:同下
  • 转义字符

    • .(点) :除换行任意字符
    • .+[\s\S].+:任意字符
    • \d (数字):[0-9]
    • \w (数字、英文、下划线) :[a-z0-9_]
    • \s (空白字符):[ ]
    • \D (除了数字):[^0-9]
    • \W (除了数字英文下划线) :[^a-z0-9_]
    • \S (除了空白字符):[^ ]
  • 行首、行尾

    • ^ :行首
    • $:行尾
  • 逻辑

    • | : 将两个匹配条件进行逻辑“或”(or)运算

量词

  • 什么是量词

    • {n}:刚好出现 n 次
    • {n,m} 至少出现 n 次,最多 m 次
    • 例子:查找 QQ 号
  • 常用量词

    • {n,} 至少 n 次,无上限

    • * 任意次 {0,} 可以为0次,不建议使用

    • 零次或一次 {0,1}

      固定电话:010-23456789-1234 或 23456789
      (0\d{2,3}-)?[1-9]\d{7}(-\d{1,5})?
      
    • + 一次或任意次{1,}

    • {n} 正好 n 次

常用正则例子

  • 表单校验实例

    • 检验邮箱
      • 行首行尾
  • <!DOCTYPE html>
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
        <title>正则表达式应用</title>
        <style>
        </style>
        <script>
        // 封装 getElementById 函数
        function get(id) {
          return document.getElementById(id);
        }
        
        var arr = [];
        var temp = '';
        var str = 'asdf-1234-as24-q2e4';
        // console.log(str.search('3'));
        // console.log(str.substring(2,5));
        // console.log(str.substring(2));
        // console.log(str.charAt(2));
        // console.log(str.split('-'));
        for (var i in str) {
          if(str.charAt(i) >= 0 && str.charAt(i) <= 9) {
            // arr.push(str.charAt(i));
            temp += str.charAt(i);
          } else if (temp) {
            arr.push(temp);
            temp = '';
          }
        }
        arr.push(temp);
        temp = '';
        console.log('字符串方法:',arr);
        console.log('match方法:',str.match(/\d+/g));
    
        
        window.onload = function () {
          var btn = get('btn');
          var btn2 = get('btn2');
          var btn3 = get('btn3');
          var btn4 = get('btn4');
          var text = get('text');
          var text2 = get('text2');
    
          // 检验邮箱
          // 获取内容,把不符合规则的找出来
          // abc_123@abc123.abc
          btn.onclick = function () {
            var reg = /^\w+@{1,}[0-9a-z]+\.{1,}[a-z]+$/i;
            var txt = text.value;
            text2.value = '';
            txt.search(reg);
            console.log(txt.match(reg),reg.test(txt));
            if (reg.test(txt)){
              text2.value = txt.match(reg);
            }
          }
          // 过滤HTML标签
          btn2.onclick = function () {
            var reg = /<[^<>]+>/g;
            txt = text.value.replace(reg,'')
            text2.value = txt;
          }
          // 检测固定电话
          btn3.onclick = function () {
            var reg = /^(0\d{2,3}-)?[1-9]\d{7}(-\d{1,5})?$/;
            var txt = text.value;
            text2.value = '';
            txt.search(reg);
            console.log(txt.match(reg),reg.test(txt));
            if (reg.test(txt)){
              text2.value = txt.match(reg);
            }
          }
          // 检测密码强度
          // 数字 低
          // 数字 英文或符号 中
          // 数字 英文 符号 高
          btn4.onclick = function () {
            var regLow = /\d+/;
            var regMid = /\d+[a-z]+/i;
            var regHei = /\d+[a-z_]+\S+/i;
            var txt = text.value;
            if (regHei.test(txt)) {
              text2.value = '高';
            } else if (regMid.test(txt)) {
              text2.value = '中';
            } else if (regLow.test(txt)) {
              text2.value = '低';
            }
          }
        }
        </script>
      </head>
      <body>
        <textarea name="" id="text" cols="30" rows="10"></textarea>
        <div>
          <input type="button" value="检测邮箱" id="btn">
          <input type="button" value="过滤HTML标签" id="btn2">
          <input type="button" value="检测电话" id="btn3">
          <input type="button" value="检测密码" id="btn4">
        </div>
        <textarea name="" id="text2" cols="30" rows="10"></textarea>
      </body>
    </html>
    

RegExp 对象

RegExp 对象表示正则表达式,它是对字符串执行模式匹配的强大工具。

直接量语法

/pattern/attributes

创建 RegExp 对象的语法:

new RegExp(pattern, attributes);

参数

参数 pattern 是一个字符串,指定了正则表达式的模式或其他正则表达式

参数 attributes 是一个可选的字符串,包含属性 “g”、“i” 和 “m”,分别用于指定全局匹配、区分大小写的匹配和多行匹配。ECMAScript 标准化之前,不支持 m 属性。如果 pattern 是正则表达式,而不是字符串,则必须省略该参数。

返回值

一个新的 RegExp 对象,具有指定的模式和标志。如果参数 pattern 是正则表达式而不是字符串,那么 RegExp() 构造函数将用与指定的 RegExp 相同的模式和标志创建一个新的 RegExp 对象。

如果不用 new 运算符,而将 RegExp() 作为函数调用,那么它的行为与用 new 运算符调用时一样,只是当 pattern 是正则表达式时,它只返回 pattern,而不再创建一个新的 RegExp 对象。

抛出

SyntaxError - 如果 pattern 不是合法的正则表达式,或 attributes 含有 “g”、“i” 和 “m” 之外的字符,抛出该异常。

TypeError - 如果 pattern 是 RegExp 对象,但没有省略 attributes 参数,抛出该异常。

修饰符

修饰符描述
i执行对大小写不敏感的匹配。
g执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
m执行多行匹配。

方括号

方括号用于查找某个范围内的字符:

表达式描述
[abc]查找方括号之间的任何字符。
[^abc]查找任何不在方括号之间的字符。
[0-9]查找任何从 0 至 9 的数字。
[a-z]查找任何从小写 a 到小写 z 的字符。
[A-Z]查找任何从大写 A 到大写 Z 的字符。
[A-z]查找任何从大写 A 到小写 z 的字符。
[adgk]查找给定集合内的任何字符。
[^adgk]查找给定集合外的任何字符。
(red|blue|green)查找任何指定的选项。

元字符

元字符(Metacharacter)是拥有特殊含义的字符:

元字符描述
.查找单个字符,除了换行和行结束符。
\w查找单词字符。
\W查找非单词字符。
\d查找数字。
\D查找非数字字符。
\s查找空白字符。
\S查找非空白字符。
\b匹配单词边界。
\B匹配非单词边界。
\0查找 NUL 字符。
\n查找换行符。
\f查找换页符。
\r查找回车符。
\t查找制表符。
\v查找垂直制表符。
\xxx查找以八进制数 xxx 规定的字符。
\xdd查找以十六进制数 dd 规定的字符。
\uxxxx查找以十六进制数 xxxx 规定的 Unicode 字符。

量词

量词描述
n+匹配任何包含至少一个 n 的字符串。
n*匹配任何包含零个或多个 n 的字符串。
n?匹配任何包含零个或一个 n 的字符串。
n{X}匹配包含 X 个 n 的序列的字符串。
n{X,Y}匹配包含 X 至 Y 个 n 的序列的字符串。
n{X,}匹配包含至少 X 个 n 的序列的字符串。
n$匹配任何结尾为 n 的字符串。
^n匹配任何开头为 n 的字符串。
?=n匹配任何其后紧接指定字符串 n 的字符串。
?!n匹配任何其后没有紧接指定字符串 n 的字符串。

RegExp 对象属性

属性描述FFIE
globalRegExp 对象是否具有标志 g。14
ignoreCaseRegExp 对象是否具有标志 i。14
lastIndex一个整数,标示开始下一次匹配的字符位置。14
multilineRegExp 对象是否具有标志 m。14
source正则表达式的源文本。14

RegExp 对象方法

方法描述FFIE
compile编译正则表达式。14
exec检索字符串中指定的值。返回找到的值,并确定其位置。14
test检索字符串中指定的值。返回 true 或 false。14

支持正则表达式的 String 对象的方法

方法描述FFIE
search检索与正则表达式相匹配的值。14
match找到一个或多个正则表达式的匹配。14
replace替换与正则表达式匹配的子串。14
split把字符串分割为字符串数组。14

JS Template 模板引擎

https://www.jb51.net/article/100095.htm

1、特性

(1)、性能卓越,执行速度通常是 Mustache 与 tmpl 的 20 多倍(性能测试)

(2)、支持运行时调试,可精确定位异常模板所在语句(演示)

(3)、对 NodeJS Express 友好支持

(4)、安全,默认对输出进行转义、在沙箱中运行编译后的代码(Node版本可以安全执行用户上传的模板)

(5)、支持include语句

(6)、可在浏览器端实现按路径加载模板(详情)

(7)、支持预编译,可将模板转换成为非常精简的 js 文件

(8)、模板语句简洁,无需前缀引用数据,有简洁版本与原生语法版本可选

(9)、支持所有流行的浏览器

2、语法

(1)、使用

引用简洁语法的引擎版本,例如:<script src="./lib/template-web.js"></script>

(2)、表达式

{{ 与 }} 符号包裹起来的语句则为模板的逻辑表达式。

template('test', data) : 渲染

(3)、输出表达式

对内容编码(转义)输出:{{content}} 不编码(转义)输出:{{#content}} 编码可以防止数据中含有 HTML 字符串,避免引起 XSS 攻击。

(4)、条件表达式

{{if admin}} 
 <p>admin</p> 
{{else if code > 0}} 
 <p>master</p> 
{{else}} 
 <p>error!</p> 
{{/if}} 

(5)、遍历表达式

无论数组或者对象都可以用 each 进行遍历。

{{each list as value index}} 
 <li>{{index}} - {{value.user}}</li> 
{{/each}} 
// 亦可以被简写:$ 特指当前函数中的变量
{{each list}} 
 <li>{{$index}} - {{$value.user}}</li> 
{{/each}} 

(6)、模板包含表达式

用于嵌入子模板。

{{include 'template_name'}}

子模板默认共享当前数据,亦可以指定数据:{{include 'template_name' news_list}}

(7)、辅助方法

使用 template.defaults.imports.dateFormat = function(arg1,arg2){}注册公用辅助方法:

template.defaults.imports.dateFormat = function(arg1,arg2) { 
 // .. 
 return value; 
}); 

模板中使用的方式:{{time | dateFormat:'yyyy-MM-dd hh:mm:ss'}} 支持传入参数与嵌套使用: {{time | say:'cd' | ubb | link}}

3、实例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Document</title>
  <script src="./lib/template-web.js"></script>
</head>

<body>
  <div id="content"></div>
  <script id="test" type="text/html">
    <div>
      <!-- 输出表达式 -->
      <p>{{name}}</p>
      <!-- 不转义输出 -->
      <p>{{#value}}</p>

      <!-- 条件表达式 -->
      {{if bool}}
      <p>{{bool}}</p>
      {{/if}}
      {{if num < 1 }}
      <p>'num < 1'</p> {{else}} <p>error!</p>
      {{/if}}

      <!-- 遍历表达式 数组 -->
      <p>遍历表达式 数组</p>
      {{each list as value index}}
      <li>{{index}}: {{value}}</li>
      {{/each}}
      <!-- $简写 $ 特指当前函数中的变量 -->
      <p>$简写</p>
      {{each list}}
      <li>{{$index}}: {{$value}}</li>
      {{/each}}
      <!-- 遍历表达式 对象 -->
      <p>遍历表达式 对象</p>
      {{each objList as value index}}
      <li>{{index}}: {{value}}</li>
      {{/each}}
      <!-- $简写 -->
      <p>$简写</p>
      {{each objList}}
      <li>{{$index}}: {{$value}}</li>
      {{/each}}

      <!-- 模板包含子模板,表达式 -->
      {{include 'news_list'}}

      <!-- 辅助方法 -->
    </div>
  </script>

  <script id="news_list" type="text/html">
    <p>模板包含子模板,表达式</p>
    <ul>
      {{each list as value i}}
      <li>索引 {{i + 1}}{{value + 1}}</li>
      {{/each}}
    </ul>
  </script>

  <script>
    const data = {
      name: 'zhangsan',
      value: '<h1>lisi</h1>',
      num: 0,
      bool: true,
      list: [1, 2, 3, 4, 5],
      objList: {
        name: 'zhangsan',
        age: '18',
        addr: '广东'
      }
    }
    let temp = template('test', data)
    document.getElementById('content').innerHTML = temp
  </script>
</body>

</html>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nKzQRjai-1626757481472)(/Eished/JavaScript_notes/raw/master/readme.assets/image-20200126152808449.png)]

<!DOCTYPE HTML> 
<html> 
<head> 
<meta charset="UTF-8"> 
<title>no escape-demo</title> 
<script src="../dist/template.js"></script> 
</head> 
  
<body> 
 <h1>不转义HTML</h1> 
 <div id="content"></div> 
 <script id="test" type="text/html"> 
 <p>不转义:{{#value}}</p> 
 <p>默认转义: {{value}}</p> 
 </script> 
  
 <script> 
 var data = { 
  value: '<span style="color:#F00">hello world!</span>' 
 }; 
 var html = template('test', data); 
 document.getElementById('content').innerHTML = html; 
 </script> 
</body> 
</html> 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LN8VEyOM-1626757481474)(/Eished/JavaScript_notes/raw/master/readme.assets/image-20200126152827260.png)]

<!DOCTYPE HTML> 
<html> 
<head> 
<meta charset="UTF-8"> 
<title>include-demo</title> 
<script src="../dist/template.js"></script> 
</head> 
  
<body> 
<div id="content"></div> 
<script id="test" type="text/html"> 
<h1>{{title}}</h1> 
{{include 'list'}} 
</script> 
<script id="list" type="text/html"> 
<ul> 
 {{each list as value i}} 
  <li>索引 {{i + 1}}{{value}}</li> 
 {{/each}} 
</ul> 
</script> 
  
<script> 
var data = { 
 title: '嵌入子模板', 
 list: ['文艺', '博客', '摄影', '电影', '民谣', '旅行', '吉他'] 
}; 
var html = template('test', data); 
document.getElementById('content').innerHTML = html; 
</script> 
</body> 
</html> 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-abZ6HnaM-1626757481475)(/Eished/JavaScript_notes/raw/master/readme.assets/image-20200126152842459.png)]


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7kusCLF2-1626757481476)(/Eished/JavaScript_notes/raw/master/readme.assets/image-20200126152920878.png)]

表达式和运算符分类

左侧工具栏是按字母表排序的列表。

主要表达式

JavaScript中基本关键字和常用表达式。

  • this

    this 关键字指向函数的执行上下文。

  • function

    function 关键字定义了函数表达式。

  • class

    class 关键字定义了类表达式。

  • function*

    function* 关键字定义了一个 generator 函数表达式。

  • yield

    暂停和恢复 generator 函数。

  • yield*

    委派给另外一个generator函数或可迭代的对象。

  • async function

    async function 定义一个异步函数表达式。

  • await

    暂停或恢复执行异步函数,并等待promise的resolve/reject回调。

  • [\]

    数组初始化/字面量语法。

  • {}

    对象初始化/字面量语法。

  • /ab+c/i

    正则表达式字面量语法。

  • ( )

    分组操作符。

左表达式

左边的值是赋值的目标。

  • 属性访问符

    成员运算符提供了对对象的属性或方法的访问 (object.propertyobject["property"]).

  • new

    new 运算符创建了构造函数实例。

  • new.target

    在构造器中,new.target 指向new调用的构造器。

  • super

    super 关键字调用父类的构造器.

  • ...obj

    展开运算符可以将一个可迭代的对象在函数调用的位置展开成为多个参数,或者在数组字面量中展开成多个数组元素。

自增和自减

前置/后置自增运算符和前置/后置自减运算符.

  • A++

    后置自增运算符.

  • A--

    后置自减运算符.

  • ++A

    前置自增运算符.

  • --A

    前置自减运算符.

一元运算符

一元运算符只有一个操作数.

  • delete

    delete 运算符用来删除对象的属性.

  • void

    void 运算符表示表达式放弃返回值.

  • typeof

    typeof 运算符用来判断给定对象的类型.

  • +

    一元加运算符将操作转换为Number类型.

  • -

    一元减运算符将操作转换为Number类型并取反.

  • ~

    按位非运算符.

  • !

    逻辑非运算符.

算术运算符

算术运算符以二个数值(字面量或变量)作为操作数,并返回单个数值。

  • +

    加法运算符.

  • -

    减法运算符.

  • /

    除法运算符.

  • *

    乘法运算符.

  • %

    取模运算符.

关系运算符

比较运算符比较二个操作数并返回基于比较结果的Boolean值。

  • in

    in运算符用来判断对象是否拥有给定属性.

  • instanceof

    instanceof 运算符判断一个对象是否是另一个对象的实例.

  • <

    小于运算符

  • >

    大于运算符.

  • <=

    小于等于运算符.

  • >=

    大于等于运算符。

注意: => 不是运算符,而是箭头函数的表示符。

相等运算符

如果相等,操作符返回的是Boolean(布尔)类型的true,否则是false。

  • ==

    相等 运算符.

  • !=

    不等 运算符.

  • ===

    全等 运算符.

  • !==

    非全等 运算符.

位移运算符

在二进制的基础上对数字进行移动操作

  • <<

    按位左移运算符。

  • >>

    按位右移运算符。

  • >>>

    按位无符号右移运算符。

二进制位运算符

二进制运算符将它们的操作数作为32个二进制位(0或1)的集合,并返回标准的JavaScript数值。

  • &

    二进制位与(AND)。

  • |

    二进制位或(OR)。

  • ^

    二进制位异或(XOR)。

二元逻辑运算符

逻辑运算符典型的用法是用于boolean(逻辑)值运算, 它们返回boolean值。

  • &&

    逻辑与.

  • ||

    逻辑或.

条件(三元)运算符

赋值运算符

赋值元素符会将右边的操作数的值分配给左边的操作数,并将其值修改为右边操作数相等的值。

  • =

    赋值运算符。

  • *=

    赋值乘积。

  • /=

    赋值商。

  • %=

    赋值求余。

  • +=

    赋值求和。

  • -=

    赋值求差。

  • <<=

    左位移。

  • >>=

    右位移。

  • >>>=

    无符号右位移。

  • &=

    赋值与。

  • ^=

    赋值按位异或。

  • |=

    赋值或。

  • [a, b\] = [1, 2\] {a, b} = {a:1, b:2}

    解构赋值允许你分配数组或者对象变量的属性通过使用规定的语法,其看起来和数组和对象字面量很相似。

  • 逗号操作符

  • ,

    逗号操作符允许在一个判断状态中有多个表达式去进行运算并且最后返回最后一个表达式的值。

JavaScript 运算符优先级值

运算符描述实例
20( )表达式分组(3 + 4)
19.成员person.name
19[]成员person[“name”]
19()函数调用myFunction()
19new创建new Date()
17++后缀递增i++
17后缀递减i–
16++前缀递增++i
16前缀递减–i
16!逻辑否!(x==y)
16typeof类型typeof x
15**求幂 (ES7)10 ** 2
14*10 * 5
14/10 / 5
14%模数除法10 % 5
13+10 + 5
13-10 - 5
12<<左位移x << 2
12>>右位移x >> 2
12>>>右位移(无符号)x >>> 2
11<小于x < y
11<=小于或等于x <= y
11>大于x > y
11>=大于或等于x >= y
11in对象中的属性“PI” in Math
11instanceof对象的实例instanceof Array
10==相等x == y
10===严格相等x === y
10!=不相等x != y
10!==严格不相等x !== y
9&按位与x & y
8^按位 XORx ^ y
7|按位或x | y
6&&逻辑与x && y
5||逻辑否x || y
4? :条件? “Yes” : “No”
3=赋值x = y
3+=赋值x += y
3-=赋值x -= y
3*=赋值x *= y
3%=赋值x %= y
3<<=赋值x <<= y
3>>=赋值x >>= y
3>>>=赋值x >>>= y
3&=赋值x &= y
3^=赋值x ^= y
3|=赋值x |= y
2yield暂停函数yield x
1,逗号7 , 8

**注意:**淡红色指示实验性或建议性的技术(ECMASScript 2016 或 ES7)

g/zh-CN/docs/Web/JavaScript/Reference/Operators/Logical_Operators#Logical_NOT)

逻辑非运算符.

算术运算符

算术运算符以二个数值(字面量或变量)作为操作数,并返回单个数值。

  • +

    加法运算符.

  • -

    减法运算符.

  • /

    除法运算符.

  • *

    乘法运算符.

  • %

    取模运算符.

关系运算符

比较运算符比较二个操作数并返回基于比较结果的Boolean值。

  • in

    in运算符用来判断对象是否拥有给定属性.

  • instanceof

    instanceof 运算符判断一个对象是否是另一个对象的实例.

  • <

    小于运算符

  • >

    大于运算符.

  • <=

    小于等于运算符.

  • >=

    大于等于运算符。

注意: => 不是运算符,而是箭头函数的表示符。

相等运算符

如果相等,操作符返回的是Boolean(布尔)类型的true,否则是false。

  • ==

    相等 运算符.

  • !=

    不等 运算符.

  • ===

    全等 运算符.

  • !==

    非全等 运算符.

位移运算符

在二进制的基础上对数字进行移动操作

  • <<

    按位左移运算符。

  • >>

    按位右移运算符。

  • >>>

    按位无符号右移运算符。

二进制位运算符

二进制运算符将它们的操作数作为32个二进制位(0或1)的集合,并返回标准的JavaScript数值。

  • &

    二进制位与(AND)。

  • |

    二进制位或(OR)。

  • ^

    二进制位异或(XOR)。

二元逻辑运算符

逻辑运算符典型的用法是用于boolean(逻辑)值运算, 它们返回boolean值。

  • &&

    逻辑与.

  • ||

    逻辑或.

条件(三元)运算符

赋值运算符

赋值元素符会将右边的操作数的值分配给左边的操作数,并将其值修改为右边操作数相等的值。

  • =

    赋值运算符。

  • *=

    赋值乘积。

  • /=

    赋值商。

  • %=

    赋值求余。

  • +=

    赋值求和。

  • -=

    赋值求差。

  • <<=

    左位移。

  • >>=

    右位移。

  • >>>=

    无符号右位移。

  • &=

    赋值与。

  • ^=

    赋值按位异或。

  • |=

    赋值或。

  • [a, b\] = [1, 2\] {a, b} = {a:1, b:2}

    解构赋值允许你分配数组或者对象变量的属性通过使用规定的语法,其看起来和数组和对象字面量很相似。

  • 逗号操作符

  • ,

    逗号操作符允许在一个判断状态中有多个表达式去进行运算并且最后返回最后一个表达式的值。

JavaScript 运算符优先级值

运算符描述实例
20( )表达式分组(3 + 4)
19.成员person.name
19[]成员person[“name”]
19()函数调用myFunction()
19new创建new Date()
17++后缀递增i++
17后缀递减i–
16++前缀递增++i
16前缀递减–i
16!逻辑否!(x==y)
16typeof类型typeof x
15**求幂 (ES7)10 ** 2
14*10 * 5
14/10 / 5
14%模数除法10 % 5
13+10 + 5
13-10 - 5
12<<左位移x << 2
12>>右位移x >> 2
12>>>右位移(无符号)x >>> 2
11<小于x < y
11<=小于或等于x <= y
11>大于x > y
11>=大于或等于x >= y
11in对象中的属性“PI” in Math
11instanceof对象的实例instanceof Array
10==相等x == y
10===严格相等x === y
10!=不相等x != y
10!==严格不相等x !== y
9&按位与x & y
8^按位 XORx ^ y
7|按位或x | y
6&&逻辑与x && y
5||逻辑否x || y
4? :条件? “Yes” : “No”
3=赋值x = y
3+=赋值x += y
3-=赋值x -= y
3*=赋值x *= y
3%=赋值x %= y
3<<=赋值x <<= y
3>>=赋值x >>= y
3>>>=赋值x >>>= y
3&=赋值x &= y
3^=赋值x ^= y
3|=赋值x |= y
2yield暂停函数yield x
1,逗号7 , 8

**注意:**淡红色指示实验性或建议性的技术(ECMASScript 2016 或 ES7)

**提示:**括号中的表达式会在值在表达式的其余部分中被使用之前进行完全计算。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet.Applet 简单实现!~ 网页表格组件 GWT Advanced Table GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以直接在你的网页里面显示搜查的结果。 github-java-api github-java-api 是 Github 网站 API 的 Java 语言版本。 java缓存工具 SimpleCache SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. 支持混合使用redis缓存和memcached缓存。可以将列表数据缓存到redis中,其他kv结构数据继续缓存到memcached 6. 支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类需求可以通过快速配置来开发。AutoTips基于搜索引擎Apache Lucene实现。AutoTips提供统一UI。 WAP浏览器 j2wap j2wap 是一个基于Java的WAP浏览器,目前处于BETA测试阶段。它支持WAP 1.2规范,除了WTLS 和WBMP。 Java注册表操作类 jared jared是一个用来操作Windows注册表的 Java 类库,你可以用来对注册表信息进行读写。 GIF动画制作工具 GiftedMotion GiftedMotion是一个很小的,免费而且易于使用图像互换格式动画是能够设计一个有趣的动画了一系列的数字图像。使用简便和直截了当,用户只需要加载的图片和调整帧您想要的,如位置,时间显示和处理方法前帧。 Java的PList类库 Blister Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端 JOpenID JOpenID是一个轻量级的OpenID 2.0 Java客户端,仅50KB+(含源代码),允许任何Web网站通过OpenID支持用户直接登录而无需注册,例如Google Account或Yahoo Account。 JActor的文件持久化组件 JFile JFile 是 JActor 的文件持久化组件,以及一个高吞吐量的可靠事务日志组件。 Google地图JSP标签库 利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JSEditor JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K
JavaScript从入门到精通PDF》是一本介绍JavaScript编程语言的书籍。它从基础概念开始,逐步深入介绍了JavaScript的各种特性和用法,帮助读者从入门到精通。 这本书首先会介绍JavaScript的发展历史和它在互联网中的作用。然后,它会讲解JavaScript的语法和基本概念,包括变量、数据类型、条件语句、循环语句等。读者通过这些基础知识,可以开始编写简单的JavaScript程序。 接下来,书籍会逐步介绍JavaScript的高级特性,如函数、对象、数组、闭包等。这些内容对于编写复杂的JavaScript程序非常重要。通过学习这些知识,读者可以更加灵活地运用JavaScript,编写出更加强大和高效的程序。 此外,书中还会介绍JavaScript的面向对象编程、异步编程、事件处理等高级主题。这些主题对于开发大型的Web应用非常关键。读者通过学习这些内容,可以了解如何在实际项目中使用JavaScript,并且提高程序的质量和性能。 《JavaScript从入门到精通PDF》不仅仅是一本教程,它还提供了大量的实例和练习题,帮助读者巩固所学知识。通过实际动手编写代码,读者可以更好地理解和运用JavaScript。 总的来说,《JavaScript从入门到精通PDF》是一本系统而全面的学习JavaScript的书籍。无论是初学者还是有一定编程基础的读者,都可以通过阅读这本书,逐步掌握JavaScript的核心概念和技巧,成为一名熟练的JavaScript开发者。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值