• Chapter12 更酷的JavaScript技术

    普通类
    • 支持
    • 批判
    • 提问
    • 解释
    • 补充
    • 删除
    • 地理定位

     

    查找访客的坐标

     

    地理定位说到底主要就是navigator.geolocation对象的三个方法:getCurrentPosition()、watchPosition()和clearWatch()

    取得访客位置可以调用getCurrentPosition(),需要提供一个完成函数;

    navigator.geolocation.getCurrentPosition(geolocationSuccess);

    //position对象包含两个属性:timestamp和coords。前者是确定地理位置的时间,后者是地理坐标,coords除了经纬度信息外还包含altitude、heading<移动方向>、speed(不过这三个目前还没有被支持)

     

    function geolocationSuccess(position){

            alert("你当前的位置在("+position.coords.latitude+","+ position.coords.longitude+")");

     }

     

    处理错误

    可以在调用getCurrentPosition()时传入两个函数,第一个是正确时调用,第二个是遇到错误终止时调用

    navigator.geolocation.getCurrentPosition(geolocationSuccess,geolocationFailure);

     

    function  geolocationFailure (positionError){

            alert("获取地理信息失败!");

            //positionError包含code和message两个属性,code表示问题类型,message包含对问题的见攒描述

     

    switch (positionError.code) {

        case 1:

          results.innerHTML = "You decided not to share, but that's OK. We won't ask again.";    //用户拒绝获取地理信息

          break;

        case 2:

          results.innerHTML = "The network is down or the positioning service can't be reached.";      //连接不上服务器

          break;

        case 3:

          results.innerHTML = "The attempt timed out before it could get the location data.";        //超时了

          break;

        case 0:

          results.innerHTML = "This the mystery error. Something else happened, but we don't know what.";        //未知的错误

          break;

      }

     }

     

    设置地理定位选项

     

    其实还可以再传入一个对象参数用于设置某些地理定位选项

     

     

    navigator.geolocation.getCurrentPosition(geolocationSuccess,geolocationFailure,

    {enableHighAccuracy:true,

    timeout:10000,

    maximumAge:60000}

    );

     

     

    maximumAge属性用于缓存位置数据,这样可以减少重复调用地理定位的次数,但在移动的时候时间越长定位越不准确

     

    显示地图

     

    结合Google Map显示当前位置:

     

     

    <!--要先引入脚本-->

     

    <script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>

     

     

    window.onload = function() {

      results = document.getElementById("results");

        //设置地图选项,此处设置了缩放级别和地图类型,更多选项参见https://developers.google.com/maps/documentation/staticmaps/?hl=zh-CN

      var myOptions = {

        zoom: 13,

        mapTypeId: google.maps.MapTypeId.ROADMAP

      };

      map = new google.maps.Map(document.getElementById("mapSurface"), myOptions);       //创建地图

      if (navigator.geolocation) {

        navigator.geolocation.getCurrentPosition(

          geolocationSuccess, geolocationFailure

        );

        results.innerHTML = "The search has begun.";

      } else {

        results.innerHTML = "This browser doesn't support geolocation.";

      }

    }

    function geolocationSuccess(position) {

          var location = new google.maps.LatLng(position.coords.latitude,position.coords.longitude);      //将坐标转换为LatLng对象的坐标点

          map.setCenter(location);    //在地图上显示点

          var infowindow = new google.maps.InfoWindow();  //创建信息气泡,设置文本内容和地图坐标

          infowindow.setContent("You are here, or somewhere thereabouts.");

          infowindow.setPosition(location);

          infowindow.open(map);

     results.innerHTML = "Now you're on the map.";

    }

    function geolocationFailure(positionError) {

      if (positionError.code == 1) {

        results.innerHTML = 

         "You decided not to share, but that's OK. We won't ask again.";

      }

      else if (positionError.code == 2) {

        results.innerHTML =

         "The network is down or the positioning service can't be reached.";

      }

      else if (positionError.code == 3) {

        results.innerHTML =

         "The attempt timed out before it could get the location data.";

      }

      else {

        results.innerHTML =

         "This the mystery error. Something else happened, but we don't know what.";

      }

    }

    跟踪访客移动

    类似的有:navigator.geolocation.watchPosition(geolocationSuccess,geolocationFailure);

     

    每一次位置更新的时候就会触发成功函数

    如果不想再关注可以将返回值传给clearWatch()方法

    var watch = navigator.geolocation.watchPosition(geolocationSuccess,geolocationFailure);

    ……

    navigator.geolocation.clearWatch(watch);

     

     

    • Web Workers

    Web Worker对象在后台完成费时的工作,前台应用不会受到干扰。它应该被用来执行那些真正费时的任务,否则优势不容易体现出来。比如执行1—5000000的素数计算,如果用JavaScript完成,页面几分钟都不会响应

    例子

    <script>

    var statusDisplay;

    var worker;

    var searchButton;

    window.onload = function() {

      statusDisplay = document.getElementById("status");

      searchButton = document.getElementById("searchButton");

    };

    function doSearch() {

      searchButton.disabled = true;       //禁止再次点击搜索按钮

      worker = new Worker("PrimeWorker.js");           //创建新的worker

      worker.onmessage = receivedWorkerMessage;         //指定onMessage时间以便从Worker哪儿接受消息

      worker.onerror = workerError;      

    //取得数值范围,发送给Web Worker

      var fromNumber = document.getElementById("from").value;

      var toNumber = document.getElementById("to").value;

      worker.postMessage(

       { from: fromNumber,
         to: toNumber
       }

      );

    //告诉用户正在搜索

      statusDisplay.innerHTML = "A web worker is on the job ("+

           fromNumber + " to " + toNumber + ") ...";  

    }

    function receivedWorkerMessage(event) {

      var message = event.data;

      if (message.messageType == "PrimeList") {

        var primes = message.data;

        var primeList = "";

        for (var i=0; i<primes.length; i++) {

          primeList += primes[i];

          if (i != primes.length-1) primeList += ", ";

        }

        var displayList = document.getElementById("primeContainer");

        displayList.innerHTML = primeList;

        if (primeList.length == 0) {

          statusDisplay.innerHTML = "Search failed to find any results.";

        }

        else {

          statusDisplay.innerHTML = "The results are here!";

        }

        searchButton.disabled = false;

      }

      else if (message.messageType == "Progress") {

        statusDisplay.innerHTML = message.data + "% done ...";

      }

    }

    function workerError(error) {

          statusDisplay.innerHTML = error.message;

    }

    function cancelSearch() {

      worker.terminate();

      worker = null;

      statusDisplay.innerHTML = "";

      searchButton.disabled = false;

    }

    </script>

    PrimeWorker.js中,接受onMessage事件,执行搜索然后返回信息

    onmessage=function(event){

        var fromNumber = event.data.from;

        var toNumber = event.data.to;

        //搜索素数

        var primes = findPrimes(fromNumber,toNumber);

        //发回结果

        postMessage({messageType:"PrimeList",data: primes});

    }

    function findPrimes(fromNumber,toNumber){

        //费时的查找素数的过程

        ……

        //计算进度百分比

        var progress = Math.round(i/list.length*100);

        //只有进度变化超过1%时才发送进度百分比信息

        if(progress!=priviousProgress){

            postMessage({messageType:"Progress",data:progress});

            preciviousProgress = progress;

        }

    }

    总结

    简而言之就是提供了一种把任务交给其他js处理的方式,避免了因执行一个需要较长时间的任务导致页面无法响应用户的其他操作。我感觉可以理解为js的多线程吧。上面的那个例子就是这样,让PrimeWorker去执行查找素数的操作,而在源html页面只需要获取信息,用户的其他操作如取消查找不会受到任何影响

     

    • 历史管理

    以前用得最多的就是history.back().

    HTML5提供了新功能,核心是pushState()方法,能够改变浏览器地址栏中的URL而同时不会刷新页面,特别适合于动态加载新内容并且无阻碍地更新页面的应用

    URL的问题

    动态页面会存在的问题是即使页面加载了新页面,但是浏览器中URL却保持不变,当这个链接被兴奋地分享出去却文不对题的时候,。麻烦了。“你不是发错链接了吧!”

    解决这个问题可以使用hashbang技术(URL末尾添加#!然后再加上选择的信息),不过比较麻烦啊。这里不再说了。可以使用PathJS库更简单地实现hashbang技术

    HTML5的方案:会话历史

    会话历史功能为上面的URL问题提供了不同的方案,它允许把URL改成任何的形式,因此第五张幻灯片可以成为

    http://www.prosetech.com/html5/Chapter%2012/Slides_WithHistory/ChinaSites5.html。这样,浏览不会去真正访问这个地址,而是停留在这个页面。但是问题是用户可能直接访问这些页面呀,而不是从第一张幻灯片一张张地点击下去,(understand?就是只改了地址也没有用啊,那岂不是要创建ChinaSites1.html—ChinaSites5.html这些页面?确实是需要创建的,因为URL标识必须是与内容一一对应的。两种方法:一种可以在服务器端用include方法把公共的部分包含到每一个页面,另一种就是使用dreamweaver这样的工具真正地去生成几个页面了呀。)

    而HTML5提供的历史会话就只是在用户浏览幻灯的时候能够相应的改变浏览器地址栏的地址,这样其他用户打开中间的某个链接的时候就可以直接定位到对应的页面。

    最重要的方法是pushState()

    var slideNumber;

    var req = new XMLHttpRequest();

    window.onload = function() {

      slideNumber = 0;

    }

    //在这个例子中,使用的是幻灯片的编号表示当前页面的状态(pushState的第一个参数).用户点击下一页pushState会向历史记录中存入一个新的状态,而onPopState事件意味着用户返回了某个状态,这为处理状态变化提供了机会。

    window.onpopstate = function(e) {

      if (e.state != null) {

        slideNumber = e.state;    //onPopState的事件对象里面存放了原来通过pushState存放进去的状态信息,因此次数可以直接使用,这一点的设计是比较精巧的

        goToNewSlide();

      }

    }

    function nextSlide() {

      if (slideNumber == 5) {

        slideNumber = 1;

      } else {

        slideNumber += 1;

      }

      history.pushState(slideNumber, null, "ChinaSites" + slideNumber + ".html");      //第一个参数可以是任何数据,表示页面的当前状态;第二个是页面标题;第三个最重要,是出现在浏览器地址栏中的内容

      goToNewSlide();

      return false;

    }

    function goToNewSlide() {

      if (req != null) {

        req.open("GET", "ChinaSites" + slideNumber + "_slide" + ".html", true);

        req.onreadystatechange = newSlideReceived;

        req.send();

      }

      else {

        // There was a problem. Ignore it.

      }

    }

    function previousSlide() {

      if (slideNumber == 1) {

        slideNumber = 5;

      } else {

        slideNumber -= 1;

      }

      history.pushState(slideNumber, null, "ChinaSites" + slideNumber + ".html");

      goToNewSlide();

      return false;

    }

    function newSlideReceived() {

      if ((req.readyState == 4) && (req.status == 200))

     {

        document.getElementById("slide").innerHTML = req.responseText;

      }

    }

    会话历史的支持情况

     IEFirefoxChromeSafariOperaSafari iOSAndroid
    最低版本——48511.54.2——

    上面那个例子,小破IE就在最后末端加了一个#,然后啥反应都没有了。。

    浏览器不支持会话历史时触发页面刷新来加载新内容也是可以理解的

    最复杂的就是尽可能使用会话历史,同时使用hashbang语法作为后备

    • 标签:
    • 设置
    • geolocationsuccess
    • geolocationfailure
    • 地图
    • 调用
    • function
    • 定位
    • 位置
    • results.innerhtml
    • 地理
    • javascript
  • 加入的知识群:
    学习元评论 (0条)

    评论为空
    聪明如你,不妨在这 发表你的看法与心得 ~



    登录之后可以发表学习元评论
      
暂无内容~~
顶部