前端从零开始第五周

261 阅读18分钟

第二十天

1. 事件

1.1 注册事件

  • 传统注册方法:

    • 利用on开头的事件;例如 onclick

      <button onclick="fn"></button>
      ​
      btn.onclick = function() {}
      
    • 注册事件的唯一性:同一个事件只能设置一个处理函数,后面的会覆盖

  • 监听注册方式:

    • w3c推荐方式:addEventListener() 是一个方法

      eventTarget.addEventListener(type, listener[, useCapture])
      

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

      • type:事件类型字符串;例如 cilck,mouseover(不要带on
      • listener:事件处理函数
      • useCapture:可选参数
    • 同一个元素同一个事件可以注册多个监听器;按注册顺序执行

1.2 解绑事件

  • 传统解绑方式: eventTarget.onclick=null;

  • 监听解绑方式:

    • eventTarget.removeEventIistener(type,listener [,useCapture] );
    • eventTarget.detachEvent(eventNamewithon,callback) ;

1.3 事件流

  • 思考: 当点击div的时候,同时也点击了其父元素和整个页面,那么是先执行谁的点击事件呢?

  • 概念: 事件流描述的是页面中接收事件的顺序;事件发生是会在元素节点间按特定顺序传播,这个过程叫做DOM事件流。

  • 经历阶段:

    1. 捕获阶段:由DOM最顶层节点开始,再向下传播到最具体的元素接受的过程
    2. 当前目标阶段
    3. 冒泡阶段:由最具体的元素接收,逐级向上传播到最顶层节点的过程
  • 注意点:

    1. JS代码中只能执行捕获或冒泡中的一种阶段
    2. onclick 和 attachEvent 只能得到冒泡阶段
    3. addEventListener(type, listener[, useCapture])第三个参数如果是true,标识在事件捕获阶段调用事件处理函数,如果是false(默认false),表示在冒泡阶段调用事件处理。
    4. 有些事件是没有冒泡的:例如onblur、onfocus、onmouseenter、onmouseleave

事件冒泡

    <div class="father">
        <div class="son">son盒子</div>
    </div>
    <script>
        // onclick 和 attachEvent(ie) 在冒泡阶段触发
        // 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 
        // son -> father ->body -> html -> document
        var son = document.querySelector('.son');
		// 给son注册单击事件
        son.addEventListener('click', function() {
            alert('son');
        }, false);
		// 给father注册单击事件
        var father = document.querySelector('.father');
        father.addEventListener('click', function() {
            alert('father');
        }, false);
		// 给document注册单击事件,省略第3个参数
        document.addEventListener('click', function() {
            alert('document');
        })
    </script>

事件捕获

    <div class="father">
        <div class="son">son盒子</div>
    </div>
    <script>
        // 如果addEventListener() 第三个参数是 true 那么在捕获阶段触发
        // document -> html -> body -> father -> son
         var son = document.querySelector('.son');
		// 给son注册单击事件,第3个参数为true
         son.addEventListener('click', function() {
             alert('son');
         }, true);
         var father = document.querySelector('.father');
		// 给father注册单击事件,第3个参数为true
         father.addEventListener('click', function() {
             alert('father');
         }, true);
		// 给document注册单击事件,第3个参数为true
        document.addEventListener('click', function() {
            alert('document');
        }, true)
    </script>

1.4 事件对象

  • 概念: 事件发生后,跟事件相关的一系列信息数据的集合都放在这个对象里,这个对象就是事件对象。如鼠标事件,就会得到鼠标的相关信息。

  • 事件对象的使用:事件触发就会产生事件对象,并且系统会以实参的形式传给事件函数,所以需要形参接收。

    eventTarget.onclick = function(event) {
    	// 这个event就是事件对象,常用形参命名:event,e,evt
    }
    

    注意: 事件对象本身的获取存在兼容性问题

    1. 标准浏览器中是浏览器给方法传递参数,只需要定义形参就能获取

    2. 在IE6-8中,浏览器不会给方法传递参数,如果需要的话,需要到window.event中获取

          <div>123</div>
          <script>
              var div = document.querySelector('div');
              div.onclick = function(e) {
                      // 事件对象
                      e = e || window.event;
                  	// 短路与,当前面的存在,直接返回,并不会执行后面的
                      console.log(e);
              }
          </script>
      

    属性和方法

    属性方法说明
    e.target返回触发事件的对象
    e.srcElement返回触发事件的对象(非标准)
    e.type返回时间的类型,比如click,mouseover不带on
    e.cancelBubble该属性阻止冒泡(非标准)
    e.returnValue该属性阻止默认事件(默认行为)——非标准
    e.preventDefault()该方法阻止默认——标准
    e.stopPropagation()阻止冒泡——标准

    e.target 和 this 的区别

    • this 是事件绑定的元素(绑定这个事件处理函数的元素)
    • e.target是事件触发的元素
        <div>123</div>
        <script>
            var div = document.querySelector('div');
            div.addEventListener('click', function(e) {
                // e.target 和 this指向的都是div
                console.log(e.target);
                console.log(this);
    
            });
        </script>
    

    事件冒泡下的e.target和this

        <ul>
            <li>abc</li>
            <li>abc</li>
            <li>abc</li>
        </ul>
        <script>
            var ul = document.querySelector('ul');
            ul.addEventListener('click', function(e) {
                  // 我们给ul 绑定了事件  那么this 就指向ul  
                  console.log(this); // ul
    
                  // e.target 触发了事件的对象 我们点击的是li e.target 指向的就是li
                  console.log(e.target); // li
            });
        </script>
    

1.5 事件委托

  • 概念: 也称事件代理,不给子元素注册事件,给父元素注册事件,把处理代码放在父元素的事件中执行。

  • 事件委托的原理

    给父元素注册事件,利用事件冒泡,当子元素的事件触发,会冒泡到父元素,然后去控制相应的子元素。

  • 事件委托的作用

    • 我们只操作了一次 DOM ,提高了程序的性能。
    • 动态新创建的子元素,也拥有事件。
    <ul>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
        <li>知否知否,点我应有弹框在手!</li>
    </ul>
    <script>
        // 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
        var ul = document.querySelector('ul');
        ul.addEventListener('click', function(e) {
            // e.target 这个可以得到我们点击的对象
            e.target.style.backgroundColor = 'pink';
        })
    </script>

2. 常用事件

2.1 常用鼠标事件

鼠标事件触发条件
onclick鼠标点击左键触发
onmouseover鼠标经过触发
onmouseout鼠标离开触发
onfocus获得鼠标焦点触发
onblur失去鼠标焦点触发
onmousemove鼠标移动触发
onmouseup鼠标弹起触发
onmousedown鼠标按下触发
  • 鼠标事件对象属性
鼠标事件对象说明
e.clientX返回鼠标相对于浏览器窗口可视区的X坐标
e.clientY---浏览器窗口可视区的Y坐标
e.pageX---文档页面的X坐标
e.pageY---文档页面的Y坐标
e.screenX---电脑屏幕的x坐标
e.screenY---电脑屏幕的Y坐标

2.2 键盘事件

键盘事件触发条件
onkeyup某个键盘按键被松开时触发
onkeydown某个键盘按键按下时触发
onkeypress某个键盘按键按下时触发(不识别 ctrl、shift、左右箭头)

注意: 执行顺序 keydown —— keypress —— keyup

  • 键盘事件对象

    • keyCode:返回该键的ASCII值
  • onkeydown 和 onkeyup 不区分大小写, onkeypress区分大小写

  • 更多使用keydown和keyup

使用keyCode属性判断用户按下哪个键

    <script>
        // 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
        document.addEventListener('keyup', function(e) {
            console.log('up:' + e.keyCode);
            // 我们可以利用keycode返回的ASCII码值来判断用户按下了那个键
            if (e.keyCode === 65) {
                alert('您按下的a键');
            } else {
                alert('您没有按下a键')
            }
        })
        document.addEventListener('keypress', function(e) {
            // console.log(e);
            console.log('press:' + e.keyCode);
        })
    </script>

第二十一天/ 第二十二天

1. BOM对象

  • 概念: BOM(Browser Object Model)即浏览器对象模型,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心对象是 window。
  • 包含关系: BOM 》 window 》DOM

1.1 window对象

  1. window对象是访问浏览器的一个接口
  2. 它是一个全局的对象。定义在全局作用域中的变量、函数都会变成window对象的属性和方法
  3. 调用的时候可以省略window,如alert()
  • window对象常见事件

    • window.onload:窗口 (页面)加载事件,当文档内容完全加载完成会触发该事件(包括图像、脚本文件、CSS 文件等), 就调用的处理函数。

      window.onload = function() {}
      window.addEventListener("load", function() {})
      
    • DOMContentLoaded: 事件触发时,仅当DOM加载完成,不包括样式表,图片等(IE9以上

      • 注:如果页面资源很多的话,用户访问到onload触发事件较长,影响用户体验,此时使用DOMContentLoaded事件合适。
          <script>
              window.addEventListener('load', function() {
                  var btn = document.querySelector('button');
                  btn.addEventListener('click', function() {
                      alert('点击我');
                  })
              })
              window.addEventListener('load', function() {
                  alert(22);
              })
              document.addEventListener('DOMContentLoaded', function() {
                  alert(33);
              })
          </script>
    • window.onresize: 是调整窗口大小加载事件, 当触发时就调用的处理函数。

      1. 只要窗口大小发生像素变化,就会触发这个事件。
      2. 我们经常利用这个事件完成响应式布局。 window.innerWidth 当前屏幕的宽度
  • 定时器(两种)

    • setTimeout()延迟定时器

      window.setTimeout(调用函数, 延迟的毫秒数); // widow可以省略
      /*
          调用函数也成为回调函数 callback,延迟时间不写默认是0
      */
       <script>
              // 回调函数是一个匿名函数
               setTimeout(function() {
                   console.log('时间到了');
      ​
               }, 2000);
              function callback() {
                  console.log('爆炸了');
              }
          // 回调函数是一个有名函数
          // 因为定时器可能有很多,所以我们给定时器赋值一个标识
              var timer1 = setTimeout(callback, 3000);
              var timer2 = setTimeout(callback, 5000);
          </script>
      
    • setInterval() 循环定时器: 循环执行调用函数

          <script>
              // 1. setInterval 
              // window.setInterval(调用函数, 循环的毫秒数); // widow可以省略
              setInterval(function() {
                  console.log('继续输出');
              }, 1000);
          </script>
      
    • 停止定时器: 取消先前调用的定时器

      var btn = document.querySelector('button');
          // 开启定时器
              var timer = setTimeout(function() {
                  console.log('爆炸了');
              }, 5000);
              var timer1 = setInterval(function() {
                  console.log('继续输出');
              }, 1000);
          // 给按钮注册单击事件
              btn.addEventListener('click', function() {
                  // 停止定时器
                  clearTimeout(timer);
                  clearTimeout(timer1);
              })
      
  • this指向

    1. 全局作用域或普通函数中this指向全局对象window(定时器中的this也指向window)
    2. 方法调用中,谁调用就指向谁
    3. 构造函数中this指向构造函数的实例
    <button>点击</button>
    <script>
        // this 指向问题 一般情况下this的最终指向的是那个调用它的对象
        // 1. 全局作用域或者普通函数中this指向全局对象window( 注意定时器里面的this指向window)
        console.log(this);
        function fn() {
            console.log(this);
        }
        window.fn();
        window.setTimeout(function() {
            console.log(this);
        }, 1000);
        // 2. 方法调用中谁调用this指向谁
        var o = {
            sayHi: function() {
                console.log(this); // this指向的是 o 这个对象
            }
        }
        o.sayHi();
        var btn = document.querySelector('button');
        btn.addEventListener('click', function() {
                console.log(this); // 事件处理函数中的this指向的是btn这个按钮对象
            })
        // 3. 构造函数中this指向构造函数的实例
        function Fun() {
            console.log(this); // this 指向的是fun 实例对象
        }
        var fun = new Fun();
    </script>

1.2 locatian对象

  • 作用: location对象用于获取或设置窗体的URL,并且可以用于解析URL。

    • URL: 统一资源定位符是互联网上标准资源的地址。——路径

      // URL一般的语法格式
      // protocol://host[:post]/path/[?query]#fragment
      https://study.163.com/course/courseLearn.htm?courseId=11111#/learn/live?lessonId=11111&courseId=11111
      
      组成说明
      protocol通信协议;常用的http,ftp等
      host主机(域名)
      port端口号(可选),省略时使用默认端口
      path路径,由零或多个‘/'隔开的字符串,表示主机上的一个地址
      query参数,以键值对的形式,通过&隔开
      fragment片段,#后面内容创建于链接锚点
  • location对象的属性

    属性返回值
    href获取或者设置整个URL
    host返回主机域名
    port返回端口号,没有返回空字符串
    pathname返回路径
    search返回参数
    hash返回片段
  • 常见方法

    location对象方法返回值
    assign()跟href一样,可以跳转页面(也成为重定向页面)
    replace()替换当前页面(无记录)
    reload()重新加载页面(相当于按F5),参数为true时为强制刷新

1.3 navigator对象

navigator对象包含有关浏览器的信息,存在很多信息,常用的是 userAgent,该属性可以返回由客户机发送服务器的user-agent头部的值。

1.userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36" // PC

2.userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1" // mobile

示例: 判断用户那个终端打开页面,实现跳转

if((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
    window.location.href = "";     //手机
 } else {
    window.location.href = "";     //电脑
 }

1.4 history对象

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

history对象方法作用
back()可以后退
forward()前进
go(参数)前进后退;参数是正整数前进n个页面;否则相反

2. JS执行机制——单线程

JavaScript的一大的特点就是单线程,同一时间只能做一件事。

单线程意味着,所有的任务都是一个一个排着队执行的,如果前面的任务耗时很长,下一个任务得一直等着,容易产生堵塞的问题;因此产生了同步任务和异步任务来解决该问题。

  • 同步: 排队执行,和原来的任务是一致的

  • 异步: 不进入主线程、而进入”任务队列”的任务,当主线程中的任务运行完了,才会从”任务队列”取出异步任务放入主线程执行。

    常见异步任务

    • 普通事件,如click、resize等
    • 资源加载,如load,error等
    • 定时器,包括setInterval、setTimeout等

    异步任务相关的回调函数添加到任务队列中(消息队列)

执行机制——事件循环

  1. 先执行执行栈中的同步事件
  2. 异步任务放在任务队列中
  3. 当执行栈中的所有同步任务执行完毕后,系统会按顺序读取任务队列中的异步任务,被读取的任务将放在执行栈中运行。
 console.log(1);
 document.onclick = function() {
   console.log('click');
 }
​
 setTimeout(function() {
   console.log(3)
 }, 3000)
 console.log(2);
//输出顺序: 1,2,3 (click当点击才会触发)

3. 元素位置

3.1 offset 元素偏移

offset就是偏移量,使用offset系列相関属性可以动态得到该元素的位置(偏移)、大小等

  1. 获得元素距离带有定位父元素的位置(没有定位,则到HTML)
  2. 获得元素自身的大小(宽度高度)
  3. 返回的数值不带单位
  • 属性说明

    offset系列属性作用
    element.offsetParent返回该元素带有定位的父级元素,没有则返回body
    element.offsetTop返回元素相对定位父元素上方的偏移
    element.offsetLeft返回元素相对定位父级左边框的偏移
    element.offsetWidth返回自身宽度包括padding、border、width; 返回数值无单位
    element.offsetHeight返回自身高度包括padding、border、height; 返回数值无单位
  • offset 与 style 区别

    • style只能得到行内样式表的样式值,offset可以得到任意样式表中的样式值

    • style.width获取的带单位的字符串,offsetWidth获取的无单位

    • style.width不包含padding和border,offsetWidth包含padding,border和width

    • style.width属性可读可写,offsetWidth只读属性

    获取元素大小位置,用offset更合适;想要给元素更改值,则需要用style改变

3.2 元素可视区 client

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

  • 属性说明
client系列属性作用
element.clientTop返回元素上边框的大小
element.clientLeft返回元素左边框的大小
element.clientWidth返回自身包括padding、width,不含border,返回值不带单位
element.clientHeight返回自身包括padding、height,不含border,返回值不带单位

3.3 元素滚动 scroll系列

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

  • 属性说明
scroll系列属性值作用
element.scrollTop返回被卷去的上侧距离,返回数值不带单位
element.scrollLeft返回被卷去的左侧距离,返回数值不带单位
element.scrollWidth返回自身实际宽度,不含边框,返回数值不带单位
element.scrollHeight返回自身实际高度,不含边框,返回数值不带单位
  • 页面被卷去的头部兼容性解决方案

需要注意的是,页面被卷去的头部,有兼容性问题,因此被卷去的头部通常有如下几种写法:

1声明了 DTD,使用 document.documentElement.scrollTop

2未声明 DTD,使用 document.body.scrollTop

3新方法 window.pageYOffset和 window.pageXOffset,IE9 开始支持

function getScroll() {
    return {
      left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft||0,
      top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0
    };
 } 
//使用的时候  getScroll().left

3.4 总结

属性作用
element.offsetWidth返回自身宽度包括padding、border、width; 返回数值无单位
element.clientWidth返回自身包括padding、width,不含border,返回值不带单位
element.scrollWidth返回自身实际宽度,不含边框,返回数值不带单位

1.offset系列 经常用于获得元素位置 offsetLeft offsetTop

2.client经常用于获取元素大小 clientWidth clientHeight

3.scroll 经常用于获取滚动距离 scrollTop scrollLeft

4.注意页面滚动的距离通过 window.pageXOffset 获得

第二十三天

1. 防抖与节流

防抖和节流严格算起来应该属于性能优化的知识,但实际上遇到的频率相当高,处理不当或者放任不管就容易引起浏览器卡死。所以还是很有必要早点掌握的。

从滚动条监听的例子说起: 很多网站会提供这么一个按钮:用于返回顶部。这个按钮只会在滚动到距离顶部一定位置之后才出现,那么我们现在抽象出这个功能需求-- 监听浏览器滚动事件,返回当前滚条与顶部的距离

实现

function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll  = showTop

运行的时候会发现存在一个问题:这个函数的默认执行频率,太!高!了!。

1.1 防抖

基于上述场景,首先提出第一种思路:在第一次触发事件时,不立即执行函数,而是给出一个期限值比如200ms,然后:

  • 如果在200ms内没有再次触发滚动事件,那么就执行函数
  • 如果在200ms内再次触发滚动事件,那么当前的计时取消,重新开始计时

效果:如果短时间内大量触发同一事件,只会执行一次函数。

实现:既然前面都提到了计时,那实现的关键就在于setTimeout这个函数,由于还需要一个变量来保存计时,考虑维护全局纯净,可以借助闭包来实现:

function debounce(fn,delay){
    let timer = null //借助闭包
    return function() {
        if(timer){
            clearTimeout(timer) 
        }
        timer = setTimeout(fn,delay) // 简化写法
    }
}
// 然后是旧代码
function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll = debounce(showTop,1000) // 为了方便观察效果我们取个大点的间断值,实际使用根据需要来配置

防抖定义:

  • 对于短时间内连续触发的事件(上面的滚动事件),防抖的含义就是让某个时间期限(如上面的1000毫秒)内,事件处理函数只执行一次。
  • 白话: 事件在限定时间内多次触发只会触发最后一次

1.2 节流

当用户一直滑动滚动条,则将不会出现回到顶部的按钮,这样用户的不到反馈;需要加以限制。

其实很简单:我们可以设计一种类似控制阀门一样定期开放的函数,也就是让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活(类似于技能冷却时间)。

效果:如果短时间内大量触发同一事件,那么在函数执行一次之后,该函数在指定的时间期限内不再工作,直至过了这段时间才重新生效。

实现: 这里借助setTimeout来做一个简单的实现,加上一个状态位valid来表示当前函数是否处于工作状态:

function throttle(fn,delay){
    let valid = true
    return function() {
       if(!valid){
           //休息时间 暂不接客
           return false 
       }
       // 工作时间,执行函数并且在间隔期内把状态位设为无效
        valid = false
        setTimeout(() => {
            fn()
            valid = true;
        }, delay)
    }
}
/* 请注意,节流函数并不止上面这种实现方案,
   例如可以完全不借助setTimeout,可以把状态位换成时间戳,然后利用时间戳差值是否大于指定间隔时间来做判定。
   也可以直接将setTimeout的返回的标记当做判断条件-判断当前定时器是否存在,如果存在表示还在冷却,并且在执行fn之后消除定时器表示激活,原理都一样
    */// 以下照旧
function showTop  () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
  console.log('滚动条位置:' + scrollTop);
}
window.onscroll = throttle(showTop,1000)

运行以上代码的结果

  • 如果一直拖着滚动条进行滚动,那么会以1s的时间间隔,持续输出当前位置和顶部的距离

节流定义:

  • 对于短时间内连续触发的事件(上面的滚动事件),节流的含义就是让频繁触发事件处理函数在设定的时间间隔内只执行一次。
  • 白话: 在规定的某个时间内事件触发多次,但是只能生效一次

2. 移动端触摸事件

移动端并没有鼠标,触屏事件可响应用户手指(或触控笔)对屏幕或者触控板操作。

常见的触屏事件:

事件说明
touchstart手指触摸到一个DOM元素时触发
touchmove手指在一个DOM元素上滑动时触发
touchend手指从一个DOM元素上移开时触发

触摸事件对象(TouchEvent)

ouchEvent 是一类描述手指在触摸平面(触摸屏、触摸板等)的状态变化的事件。这类事件用于描述一个或多个触点,使开发者可以检测触点的移动,触点的增加和减少,等等

touchstart、touchmove、touchend 三个事件都会各自有事件对象。

触摸事件对象重点我们看三个常见对象列表:

触摸列表说明
touches正在触摸屏幕的所有手指列表
targetTouches正在触摸当前的DOM元素上的手指列表
changedTouches手指状态发生了改变的列表

示例实现拖动元素

拖动元素三步曲:

(1) 触摸元素 touchstart: 获取手指初始坐标,同时获得盒子原来的位置

(2) 移动手指 touchmove: 计算手指的滑动距离,并且移动盒子

(3) 离开手指 touchend:

<style type="text/css">
  body{
    width: 100vw;
    height: 100vh;
    margin: 0;
  }
  #d1{
    width: 200px;
    height: 200px;
    position: absolute;
    left: 0;
    top: 0;
    background-color: deepskyblue;
  }
</style>
<script>
    var body = document.body;
    var isDarg = false;
  var startX = 0;
  var startY = 0;
  var endX = 0;
  var endY = 0;
  var dragX = 0;
  var dragY = 0;
  body.addEventListener('touchstart',function(event){
    if(event.target.id == 'd1'){
      isDarg = true;
      console.log(event)
      var x = event.touches[0].pageX
      var y = event.touches[0].pageY
​
      startX = x;
      startY = y;
    }
​
  })
​
​
  body.addEventListener('touchmove',function(event){
    if(isDarg){
      console.log(event)
      var x = event.touches[0].pageX;
      var y = event.touches[0].pageY;
      dragX = x - startX + endX;
      dragY = y - startY + endY;
      d1.style.transform = "translate("+dragX+"px,"+dragY+"px)"
    }
​
  })
​
  body.addEventListener('touchend',function(){
    endX = dragX;
    endY = dragY;
    isDarg = false;
  })
</script>

第二十四天

1. 本地存储

在 HTML5 之前,应用程序数据只能存储在 cookie 中,包括每个服务器请求。本地存储则更安全,并且可在不影响网站性能的前提下将大量数据存储于本地。

HTML 本地存储提供了两个在客户端存储数据的对象:

  • window.localStorage - 存储没有截止日期的数据
  • window.sessionStorage - 针对一个 session 来存储数据(当关闭浏览器标签页时数据会丢失)

1.1 localStorage

localStorage 对象存储的是没有截止日期的数据。当浏览器被关闭时数据不会被删除,在下一天、周或年中,都是可用的。

语法示例:

// 存储: 三种写法
localStorage.setItem("lastname", "Gates");
localStorage.lastname = "Gates";
localStorage['lastname'] = "Gates";
// 取回
document.getElementById("result").innerHTML = localStorage.getItem("lastname");
// 删除
localStorage.removeItem("lastname");

1.2 sessionStorage 对象

sessionStorage 对象等同 localStorage 对象,不同之处在于只对一个 session 存储数据。如果用户关闭具体的浏览器标签页,数据也会被删除。

示例

if (sessionStorage.clickcount) {
    sessionStorage.clickcount = Number(sessionStorage.clickcount) + 1;
} else {
    sessionStorage.clickcount = 1;
}
document.getElementById("result").innerHTML = "在本 session 中,您已经点击这个按钮 " +
sessionStorage.clickcount + " 次。";

2. JSON数据

2.1 什么是 JSON?

  • JSON 指的是 JavaScript Object Notation
  • JSON 是轻量级的数据交换格式
  • JSON 独立于语言
  • JSON 是“自描述的”且易于理解

JSON 的语法是来自 JavaScript 对象符号的语法,但 JSON 格式是纯文本。读取和生成 JSON 数据的代码可以在任何编程语言编写的。

JSON 数据实例

{
  "employees":[
      {"firstName":"Bill", "lastName":"Gates"}, 
      {"firstName":"Steve", "lastName":"Jobs"},
      {"firstName":"Alan", "lastName":"Turing"}
  ]
}

2.2 JSON 语法规则

  • 数据是名称/值对
  • 数据由逗号分隔
  • 花括号保存对象
  • 方括号保存数组
名称和值

JSON 数据的书写方式是名称/值对,类似 JavaScript 对象属性。

名称/值对由(双引号中的)字段名构成,其后是冒号,再其后是值:

"firstName":"Bill"

JSON 名称需要双引号。JavaScript 名称不需要。

JSON 对象

JSON 对象是在花括号内书写的。

类似 JavaScript,对象能够包含多个名称/值对:

{"firstName":"Bill", "lastName":"Gates"}
JSON 数组

JSON 数组在方括号中书写。

类似 JavaScript,数组能够包含对象:

"employees":[
    {"firstName":"Bill", "lastName":"Gates"}, 
    {"firstName":"Steve", "lastName":"Jobs"}, 
    {"firstName":"Alan", "lastName":"Turing"}
]

在上面的例子中,对象 "employees" 是一个数组。它包含了三个对象。

2.3 JSON格式转换

JSON 的通常用法是从 web 服务器读取数据,然后在网页中显示数据。为了简单起见,可以使用字符串作为输入演示。

首先,创建包含 JSON 语法的 JavaScript 字符串:

var text = '{ "employees" : [' +
'{ "firstName":"Bill" , "lastName":"Gates" },' +
'{ "firstName":"Steve" , "lastName":"Jobs" },' +
'{ "firstName":"Alan" , "lastName":"Turing" } ]}';

然后,使用 JavaScript 的内建函数 JSON.parse() 来把这个字符串转换为 JavaScript 对象:

var obj = JSON.parse(text); // 字符串转JSON
text = JSON.stringify(obj); // JSON转字符串