<address id="ttjl9"></address>

      <noframes id="ttjl9"><address id="ttjl9"><nobr id="ttjl9"></nobr></address>
      <form id="ttjl9"></form>
        <em id="ttjl9"><span id="ttjl9"></span></em>
        <address id="ttjl9"></address>

          <noframes id="ttjl9"><form id="ttjl9"></form>

          首頁

          與原型相關的那些事兒

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          寫在前面: 
          1、什么是對象? 
          對象就是屬性的集合; 
          2、對象與函數的關系? 
          對象都可以看做是由構造函數Object實例化生成的; 
          函數都可以看做是由構造函數Function實例化生成的; 
          構造函數Object也是由構造函數Function生成的;

          1、原型prototype

          如果讓用簡單的幾句話說一下什么是原型,或者給原型下個定義,我覺得還是有點困難的,困難之處在于即使說了之后,對于聽的人來說,估計也是一頭霧水。不過,關于原型的一些基本的東西還是要說明的,這些基本的東西差不多就可以構成一個對原型的理解。首先,原型是函數才有的一個屬性;其次,原型就是一個對象,我們可以給它添加屬性或方法;最后,原型的作用是實現對象屬性的繼承。

          每個對象都有一個隱藏的__proto__屬性,__proto__屬性指向創建該對象的函數的原型prototype;

          這里寫圖片描述

          每個函數都有一個prototype屬性,其prototype屬性值是一個對象;

          這里寫圖片描述

          這里寫圖片描述

          對象是沒有prototype屬性的,函數是沒有__proto__屬性的;

          通過原型prototype,可以實現對象屬性的繼承,即創建在構造函數原型上的方法和屬性可以被所有由該構造函數生成的實例所共享;

          2、原型鏈

          什么是原型鏈? 
          原型鏈描述的是對象的繼承圖譜(類似于家譜圖),當訪問一個對象的屬性的時候,會在該對象中進行查詢,如果在該對象中沒有查詢到,則會沿著該對象的__proto__線進行查詢,直到查詢到該屬性或者到Object.prototype,這樣層層向上查詢的線路就是該對象的原型鏈。

          3、instanceof

          typeof在判斷引用數據類型時只能返回object和function,不能準確判斷引用數據類型時數組還是對象。而instanceof可以很好用于判斷引用數據類型。

          用法: A instanceof B

          instanceof是通過判斷對象A的原型鏈上是否存在B的原型來確定A的數據類型;

          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務

          canvas粒子效果

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          <html lang="en">
          <head>
            <meta charset="UTF-8">
            <title>Document</title>
            <style>
              html, body {
                margin: 0;
                padding: 0;
                height: 100%;
                overflow: hidden;
              }
              .container {
                width: 100%;
                height: 100%;
              }
            </style>
          </head>
          <body>
            <div class="container">
              <canvas id="cs"></canvas>
            </div>
          </body>
          <script>
            function MoveBalls(element, opts) {
              var canvas = document.querySelector(element);
              this.canvas = canvas;
              this.ctx = canvas.getContext("2d");
              var defaultOpts = {
                total: 100,
                color: "#00D0FF",
                size: 1,
                width: this.canvas.parentNode.clientWidth,
                height: this.canvas.parentNode.clientHeight
              };
              var opts = opts || defaultOpts;
              for (var key in opts) {
                  defaultOpts[key] = opts[key];
              };
              for (var key in defaultOpts) {
                  this[key] = defaultOpts[key];
              };
              opts = null;
              defaultOpts = null;
              // 鼠標坐標
              this.coordinate = {
                x: null,
                y: null,
                max: 100
              };
              // 粒子
              this.dots = [];
              // 含鼠標坐標的粒子數組
              this.newDots = [];
              // 總數
              this.count = 0;
              // requestAnimationFrame兼容處理
              window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function(callback) {
                    window.setTimeout(callback, 1000 / 60);
                  };
              this.colorReg = /[rgba()]/g;
              this.init();
            };
            MoveBalls.prototype = {
              constructor: MoveBalls,
              init: function () {
                var _this = this;
                this.freshResize();
                this.mouseEvent();
                this.getDots();
                var timer = setTimeout(function () {
                  clearTimeout(timer);
                  _this.draw(_this)
                }, 300);
              },
              colorCheck: function () {
                this.canvas.style.color = this.color;
                var colorData = this.canvas.style.color;
                return colorData = colorData.replace(this.colorReg, "").split(",");
              },
              resize: function (self) {
                var _this = self || this;
                _this.canvas.width = _this.width;
                _this.canvas.height = _this.height;
              },
              freshResize: function () {
                this.resize();
                var _this = this;
                window.addEventListener("resize", function () {
                  _this.resize(_this);
                });
              },
              mouseEvent: function () {
                var _this = this;
                _this.canvas.addEventListener("mousemove", function (e) {
                  var e = e || winodw.event;
                  _this.coordinate.x = e.offsetX ? e.offsetX : e.layerX;
                  _this.coordinate.y = e.offsetY ? e.offsetY : e.layerY;
                });
                _this.canvas.addEventListener("mouseout", function () {
                  _this.coordinate.x = null;
                  _this.coordinate.y = null;
                })
              },
              getDots: function () {
                while(this.count < this.total) {
                  var x = Math.random() * this.canvas.width;
                  var y = Math.random() * this.canvas.height;
                  var xMove = Math.random() * 2 - 1;
                  var yMove = Math.random() * 2 - 1;
                  this.dots.push({
                    x: x,
                    y: y,
                    xMove: xMove,
                    yMove: yMove,
                    max: 100
                  });
                  this.count ++;
                }
              },
              draw: function (self) {
                var _this = self || this;
                var ctx = _this.ctx;
                ctx.clearRect(0, 0, _this.canvas.width, _this.canvas.height);
                _this.newDots = [_this.coordinate].concat(_this.dots);
                _this.dots.forEach(function (dot) {
                  dot.xMove *= (dot.x > _this.canvas.width || dot.x < 0) ? -1 : 1;
                  dot.yMove *= (dot.y > _this.canvas.height || dot.y < 0) ? -1 : 1;
                  dot.x += dot.xMove;
                  dot.y += dot.yMove;
                  // 繪制點
                  ctx.save();
                  ctx.beginPath();
                  ctx.arc(dot.x, dot.y, _this.size, 0, Math.PI * 5);
                  ctx.fillStyle = _this.color;
                  ctx.fill();
                  ctx.restore();
                  // 循環比對粒子間的距離
                  for (var i = 0; i < _this.newDots.length; i ++) {
                    var newDot = _this.newDots[i];
                    // 如果是第一個點,則跳過
                    if(newDot === dot || newDot.x === null || newDot.y === null) continue;
                    var xDistance = dot.x - newDot.x;
                    var yDistance = dot.y - newDot.y;
                    var distance = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
                    // 顏色深度
                    var deep = 0;
                    // 小于最小距離,則連線
                    if (distance <= newDot.max) {
                      // 附近的小球向鼠標位置移動
                      if(newDot === _this.coordinate && distance > (newDot.max / 2)) {
                        dot.x -= xDistance * 0.05;
                        dot.y -= yDistance * 0.05;
                      }
                      // 距離越近---值越大---顏色越深
                      deep = (newDot.max - distance) / newDot.max;
                      // 畫線
                      ctx.save();
                      ctx.beginPath();
                      ctx.lineWidth = deep / 2;
                      var colorInfo = _this.colorCheck();
                      ctx.strokeStyle = "rgba(" + colorInfo[0] + ", " + colorInfo[1] + ", " + colorInfo[2] + "," + (deep + 0.4) + ")";
                      ctx.moveTo(dot.x, dot.y);
                      ctx.lineTo(newDot.x, newDot.y);
                      ctx.stroke();
                      ctx.restore();
                    }
                  }
                  // 將已經計算過的粒子刪除,減少遍歷的總數量
                  _this.newDots.splice(_this.newDots.indexOf(dot), 1);
                });
                window.requestAnimationFrame(function (obj) {
                  _this.draw(_this);
                });
              }
            }
            var moveBalls = new MoveBalls("#cs", {total: 66, color: "#00D0FF", size: 1});
          </script>
          </html>

          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務


          移動端web頁面開發

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

           字號

          工作了有一段時間,基本上都在搞移動端的前端開發,工作的過程中遇到過很多問題,bug的解決方案,記錄下來,以便后用!??!內容并不是很全,以后每遇到一個問題都會總結在這里,分享給大家!

          一、meta標簽相關知識

          1、移動端頁面設置視口寬度等于設備寬度,并禁止縮放。

          <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />

          2、移動端頁面設置視口寬度等于定寬(如640px),并禁止縮放,常用于微信瀏覽器頁面。

          <meta name="viewport" content="width=640,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />

          3、禁止將頁面中的數字識別為電話號碼

          <meta name="format-detection" content="telephone=no" />

          4、忽略Android平臺中對郵箱地址的識別

          <meta name="format-detection" content="email=no" />

          5、當網站添加到主屏幕快速啟動方式,可隱藏地址欄,僅針對ios的safari

          
              
          1. <meta name="apple-mobile-web-app-capable" content="yes" />
          2. <!-- ios7.0版本以后,safari上已看不到效果 -->

          6、將網站添加到主屏幕快速啟動方式,僅針對ios的safari頂端狀態條的樣式

          
              
          1. <meta name="apple-mobile-web-app-status-bar-style" content="black" />
          2. <!-- 可選default、black、black-translucent -->

          viewport模板

          
              
          1. <!DOCTYPE html>
          2. <html>
          3. <head>
          4. <meta charset="utf-8">
          5. <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport">
          6. <meta content="yes" name="apple-mobile-web-app-capable">
          7. <meta content="black" name="apple-mobile-web-app-status-bar-style">
          8. <meta content="telephone=no" name="format-detection">
          9. <meta content="email=no" name="format-detection">
          10. <title>title</title>
          11. <link rel="stylesheet" href="index.css">
          12. </head>
          13. <body>
          14. content...
          15. </body>
          16. </html>

          二、CSS樣式技巧

          1、禁止ios和android用戶選中文字

          .css{-webkit-user-select:none}

          2、禁止ios長按時觸發系統的菜單,禁止ios&android長按時下載圖片

          .css{-webkit-touch-callout: none}

          3、webkit去除表單元素的默認樣式

          .css{-webkit-appearance:none;}

          4、修改webkit表單輸入框placeholder的樣式

          
              
          1. input::-webkit-input-placeholder{color:#AAAAAA;}
          2. input:focus::-webkit-input-placeholder{color:#EEEEEE;}

          5、去除android a/button/input標簽被點擊時產生的邊框 & 去除ios a標簽被點擊時產生的半透明灰色背景

          a,button,input{-webkit-tap-highlight-color:rgba(255,0,0,0);}

          6、ios使用-webkit-text-size-adjust禁止調整字體大小

          body{-webkit-text-size-adjust: 100%!important;}

          7、android 上去掉語音輸入按鈕

          input::-webkit-input-speech-button {display: none}

          8、移動端定義字體,移動端沒有微軟雅黑字體

          
              
          1. /* 移動端定義字體的代碼 */
          2. body{font-family:Helvetica;}

          三、其他技巧

          1、手機拍照和上傳圖片

          
              
          1. <!-- 選擇照片 -->
          2. <input type=file accept="image/*">
          3. <!-- 選擇視頻 -->
          4. <input type=file accept="video/*">

          2、取消input在ios下,輸入的時候英文首字母的默認大寫

          <input autocapitalize="off" autocorrect="off" />

          3、打電話和發短信

          
              
          1. <a href="tel:0755-10086">打電話給:0755-10086</a>
          2. <a href="sms:10086">發短信給: 10086</a>

          四、CSS reset

          
              
          1. /* hcysun */
          2. @charset "utf-8";
          3. /* reset */
          4. html{
          5. -webkit-text-size-adjust:none;
          6. -webkit-user-select:none;
          7. -webkit-touch-callout: none
          8. font-family: Helvetica;
          9. }
          10. body{font-size:12px;}
          11. body,h1,h2,h3,h4,h5,h6,p,dl,dd,ul,ol,pre,form,input,textarea,th,td,select{margin:0; padding:0; font-weight: normal;text-indent: 0;}
          12. a,button,input,textarea,select{ background: none; -webkit-tap-highlight-color:rgba(255,0,0,0); outline:none; -webkit-appearance:none;}
          13. em{font-style:normal}
          14. li{list-style:none}
          15. a{text-decoration:none;}
          16. img{border:none; vertical-align:top;}
          17. table{border-collapse:collapse;}
          18. textarea{ resize:none; overflow:auto;}
          19. /* end reset */

          五、常用公用CSS style

          
              
          1. /* public */
          2. /* 清除浮動 */
          3. .clear { zoom:1; }
          4. .clear:after { content:''; display:block; clear:both; }
          5. /* 定義盒模型為怪異和模型(寬高不受邊框影響) */
          6. .boxSiz{
          7. -webkit-box-sizing: border-box;
          8. -moz-box-sizing: border-box;
          9. -ms-box-sizing: border-box;
          10. -o-box-sizing: border-box;
          11. box-sizing: border-box;
          12. }
          13. /* 強制換行 */
          14. .toWrap{
          15. word-break: break-all; /* 只對英文起作用,以字母作為換行依據。 */
          16. word-wrap: break-word; /* 只對英文起作用,以單詞作為換行依據。*/
          17. white-space: pre-wrap; /* 只對中文起作用,強制換行。*/
          18. }
          19. /* 禁止換行 */
          20. .noWrap{
          21. white-space:nowrap;
          22. }
          23. /* 禁止換行,超出省略號 */
          24. .noWrapEllipsis{
          25. white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
          26. }
          27. /* 文字兩端對齊 */
          28. .text-justify{
          29. text-align:justify;
          30. text-justify:inter-ideograph;
          31. }
          32. /* 定義盒模型為 flex布局兼容寫法并讓內容水平垂直居中 */
          33. .flex-center{
          34. display: -webkit-box;
          35. display: -moz-box;
          36. display: -ms-flexbox;
          37. display: -o-box;
          38. display: box;
          39. -webkit-box-pack: center;
          40. -moz-box-pack: center;
          41. -ms-flex-pack: center;
          42. -o-box-pack: center;
          43. box-pack: center;
          44. -webkit-box-align: center;
          45. -moz-box-align: center;
          46. -ms-flex-align: center;
          47. -o-box-align: center;
          48. box-align: center;
          49. }
          50. /* public end */

          六、flex布局

          1、定義彈性盒模型兼容寫法

          
              
          1. /*
          2. box
          3. inline-box
          4. */
          5. display: -webkit-box;
          6. display: -moz-box;
          7. display: -ms-flexbox;
          8. display: -o-box;
          9. display: box;

          2、box-orient 定義盒模型內伸縮項目的布局方向

          
              
          1. /**
          2. * vertical column 垂直
          3. * horizontal row 水平 默認值
          4. */
          5. -webkit-box-orient: horizontal;
          6. -moz-box-orient: horizontal;
          7. -ms-flex-direction: row;
          8. -o-box-orient: horizontal;
          9. box-orient: horizontal;

          3、box-direction 定義盒模型內伸縮項目的正序(normal默認值)、倒敘(reverse)

          
              
          1. /* Firefox */
          2. display:-moz-box;
          3. -moz-box-direction:reverse;
          4. /* Safari、Opera 以及 Chrome */
          5. display:-webkit-box;
          6. -webkit-box-direction:reverse;

          4、box-pack 對盒子水平富??臻g的管理

          
              
          1. /*
          2. start
          3. end
          4. center
          5. justify
          6. */
          7. -webkit-box-pack: center;
          8. -moz-box-pack: center;
          9. -ms-flex-pack: center;
          10. -o-box-pack: center;
          11. box-pack: center;

          5、box-pack 對盒子垂直方向富裕空間的管理

          
              
          1. /*
          2. start
          3. end
          4. center
          5. */
          6. /* box-align */
          7. -webkit-box-align: center;
          8. -moz-box-align: center;
          9. -ms-flex-align: center;
          10. -o-box-align: center;
          11. box-align: center;

          6、定義伸縮項目的具體位置

          
              
          1. /*-moz-box-ordinal-group:1;*/ /* Firefox */
          2. /*-webkit-box-ordinal-group:1;*/ /* Safari 和 Chrome */
          3. .box div:nth-of-type(1){-webkit-box-ordinal-group:1;}
          4. .box div:nth-of-type(2){-webkit-box-ordinal-group:2;}
          5. .box div:nth-of-type(3){-webkit-box-ordinal-group:3;}
          6. .box div:nth-of-type(4){-webkit-box-ordinal-group:4;}
          7. .box div:nth-of-type(5){-webkit-box-ordinal-group:5;}

          7、定義伸縮項目占空間的份數

          
              
          1. -moz-box-flex:2.0; /* Firefox */
          2. -webkit-box-flex:2.0; /* Safari 和 Chrome */
          3. .box div:nth-of-type(1){-webkit-box-flex:1;}
          4. .box div:nth-of-type(2){-webkit-box-flex:2;}
          5. .box div:nth-of-type(3){-webkit-box-flex:3;}
          6. .box div:nth-of-type(4){-webkit-box-flex:4;}
          7. .box div:nth-of-type(5){-webkit-box-flex:5;}

          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務

          原生JS實現ajax詳解

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          原生js寫ajax可以類比打電話

          打電話分下面4步:
          1.拿出手機
          2.撥號
          3.說話
          4.聽對方說話

          ajax也分下面4步:
          1.創建ajax對象
          2.連接到服務器
          3.發送請求(告訴服務器我要什么文件)
          4.接收返回值

          下面是原生js寫ajax的具體寫法 :

          
              
          1. <script>
          2. window.onload=function()
          3. {
          4. var oBtn = document.getElementById("btn1");
          5. oBtn.onclick = function()
          6. {
          7. //1.創建ajax對象
          8. //只兼容非ie6的瀏覽器,在ie6瀏覽器上運行會提示沒有被定義
          9. //var oAjax = new XMLHttpRequest();//這才是ajax實際的請求
          10. //alert(oAjax);
          11. //ie6瀏覽器下按照下面方法寫,但是在別的瀏覽器中不能用,會報錯。
          12. //var oAjax = new ActiveXObject("Microsoft.XMLHTTP");
          13. //alert(oAjax);
          14. //鑒于上面出現的問題,可以采取下面的方法解決,用if判斷是否為IE6瀏覽器
          15. if(window.XMLHttpRequest)//如果有XMLHttpRequest,那就是非IE6瀏覽器。()里面加window的原因下面會有描述。
          16. {
          17. var oAjax = new XMLHttpRequest();//創建ajax對象
          18. }
          19. else//如果沒有XMLHttpRequest,那就是IE6瀏覽器
          20. {
          21. var oAjax = new ActiveXObject("Microsoft.XMLHTTP");//IE6瀏覽器創建ajax對象
          22. }
          23. //2.連接服務器
          24. //open(方法、文件名、異步傳輸)
          25. //方法:
          26. //傳輸方式是get方式還是post方式。
          27. //文件名
          28. //告訴服務器要讀哪個文件
          29. //異步傳輸
          30. //異步:多件事一件一件的做
          31. //同步:多件事情一起進行
          32. //但是js里面的同步和異步和現實的同步異步相反。
          33. //同步:多件事一件一件的做
          34. //異步:多件事情一起進行
          35. //ajax天生是用來做異步的
          36. oAjax.open("GET","a.txt?t='+new Date().getTime()",true);//加上t='+new Date().getTime()"的目的是為了消除緩存,每次的t的值不一樣。
          37. //3.發送請求
          38. oAjax.send();
          39. //4.接收返回
          40. //客戶端和服務器端有交互的時候會調用onreadystatechange
          41. oAjax.onreadystatechange=function()
          42. {
          43. //oAjax.readyState //瀏覽器和服務器,進行到哪一步了。
          44. //0->(未初始化):還沒有調用 open() 方法。
          45. //1->(載入):已調用 send() 方法,正在發送請求。
          46. //2->載入完成):send() 方法完成,已收到全部響應內容。
          47. //3->(解析):正在解析響應內容。
          48. //4->(完成):響應內容解析完成,可以在客戶端調用。
          49. if(oAjax.readyState==4)
          50. {
          51. if(oAjax.status==200)//判斷是否成功,如果是200,就代表成功
          52. {
          53. alert("成功"+oAjax.responseText);//讀取a.txt文件成功就彈出成功。后面加上oAjax.responseText會輸出a.txt文本的內容
          54. }
          55. else
          56. {
          57. alert("失敗");
          58. }
          59. }
          60. };
          61. }
          62. };
          63. /*//上面if里面需要些window的原因
          64. //js里面的變量和屬性
          65. var a = 12;
          66. alert(a);//頁面上彈出12很正常,而實際上輸出的是下面的寫法,是屬于window的,只是window能省就省了。
          67. alert(window.a);//輸出結果是一樣的
          68. window.alert(window.a);
          69. //想a這種全局變量實際上是winow的一個屬性。
          70. //如果不定義一個變量a直接像下面那樣輸出a
          71. alert(a)//系統會報錯,而不是undefind,因為沒有定義變量a。
          72. alert(window.a);//如果是這樣寫,系統就不會報錯了,會顯示undefind。
          73. //出現上面的原因是因為直接寫a從根上就找不到a,而前面加上window只是找不到window的屬性a了。*/
          74. </script>

          但是,不能每次用ajax的時候都寫那么多代碼,要把這段ajax代碼封裝起來,方便使用。

          封裝ajax代碼如下:

          
              
          1. //最后把代碼封裝起來,封裝起來以后,要給這個函數加上一個參數url.參數是為了替換要讀取的文件名
          2. function ajax(url,fnSucc)
          3. {
          4. if(window.XMLHttpRequest)
          5. {
          6. var oAjax = new XMLHttpRequest();
          7. }
          8. else
          9. {
          10. var oAjax = new ActiveXObject("Microsoft.XMLHTTP");//IE6瀏覽器創建ajax對象
          11. }
          12. oAjax.open("GET",url,true);//把要讀取的參數的傳過來。
          13. oAjax.send();
          14. oAjax.onreadystatechange=function()
          15. {
          16. if(oAjax.readyState==4)
          17. {
          18. if(oAjax.status==200)
          19. {
          20. fnSucc(oAjax.responseText);//成功的時候調用這個方法
          21. }
          22. else
          23. {
          24. if(fnfiled)
          25. {
          26. fnField(oAjax.status);
          27. }
          28. }
          29. }
          30. };
          31. }

          將封裝的ajax調用:

          
              
          1. <script src="new_ajax.js"></script>//引用封裝的ajax文件
          2. <script>
          3. window.onload=function()
          4. {
          5. var oBtn = document.getElementById("btn1");
          6. oBtn.onclick = function()
          7. {
          8. ajax('a.txt',function(str){//讀取a.txt文件里面的內容
          9. alert(str);//將讀取的內容輸出
          10. })
          11. }
          12. };
          13. </script>
          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務

          遮罩層上滾動,使下方的列表隨之滾動

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          效果

          這里寫圖片描述

          遮罩層為一張邊框樣式圖(如下圖):

          這里寫圖片描述

          邊框樣式遮罩層顯示在最上方,然后是中間的列表,最下層是一個透明黑色遮罩層,滾動鼠標滾輪,能控制列表滾動

          實現原理

          注冊最上面遮罩層的滾動事件,拿到滾動滾動方向,然后控制列表滾動的方向和距離

          上代碼

          注冊事件 /**
           * 增加滾輪滾動事件(暫時只實現了chrome的滾動效果)
           * @param modalDomId 遮罩層domId
           * @param domId 需要滾動下層列表domId
           */ addMousewheelListener(modalDomId:string,domId:string){ //添加頁面監聽 let modalAwardPanel = document.getElementById(modalDomId);
            modalAwardPanel.addEventListener('mousewheel',function(e){
              let scrollContentDom = document.getElementById(domId); //向上滾 if (e.wheelDelta > 0){ if (scrollContentDom.scrollTop -20 >= 0){
                  scrollContentDom.scrollTop = scrollContentDom.scrollTop - 20;
                } else{
                  scrollContentDom.scrollTop = 0 ;
                }
              } //向下滾 else{ if(scrollContentDom.scrollTop + scrollContentDom.clientHeight < scrollContentDom.scrollHeight){
                  scrollContentDom.scrollTop = scrollContentDom.scrollTop + 20;
                }
              }
            });
          }
          
          組件調用: this.addMousewheelListener("你的最上方遮罩層id","你想要滾動的列表id");
          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務

          前端算法之彈幕設計

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          大家都說前端寫頁面較多,幾乎用不到算法。本文愿從彈幕設計這個場景來描述算法在前端中的應用,我們先來看下實現效果:

          圖1.1 彈幕效果

           

          開場之前我們先來描述彈幕開發的難度,再集中精力描述算法設計的思路。

          * 如何保證不同字號的彈幕不碰撞
          * 彈幕的位置計算
          * 彈幕的速度控制及動畫實現
          * 彈幕與視頻的同步

          ***如何保證不同字號的彈幕不碰撞***

          如果彈幕采用相同的字號,碰撞的問題處理起來比較簡單,只要考慮相鄰彈幕的播放速度和偏移的位置就可以計算出來。然而使用不同字號的彈幕處理起來就麻煩了許多,彈幕的起始位置不可以線性的增加,比如第一行放了字幕,接下來的字幕可以按順序從上至下依次放置即可。

          ***彈幕的位置計算***

          只有設計好彈幕的初始位置,才可以動態、的管理不同字號彈幕的碰撞問題。打個比方,我們通過接口獲取了2秒之內的彈幕數據1000條,每個字幕的長度、速度、字號都不同,怎么管理這些彈幕,示意圖如下:

          圖2.1 彈幕管理示意圖

           

          這是第一種情況,按照從上到啊的順序依次擺放以后會有幾個問題:
          1. 彈幕五、六、七該怎么計算位置,按top值循環取模+累加嗎?
          2. 當彈幕一或者彈幕三足夠長的時候,如何準時的跳過當前位置計算?
          3. 當前屏幕的彈幕播放結束,如何再計算的時候利用空出來的位置
          4. 空出的位置是否滿足當前彈幕的高度
          5. ……

          一系列問題就不統統列舉出來了,基于這個背景我們結合數學建模的思維方式,找到了彈幕場景相似度非常高的機場運營。我們可以把彈幕當做飛機,每個時間段播放多少彈幕和機場每個時間段放飛多少飛機一個道理。

          首都國際機場一共有3條跑道,兩條4E級跑道、一條4F級跑道,2016年的吞吐量為9000萬人次。它的運行機制就是所有飛機通過搭臺有順序的共用3條跑道來完成運輸任務的。

          同理,我們也設計了幾個個角色:一個是軌道(跑道)、一個是調度(塔臺)、一個是彈幕(飛機),我們為每個角色設計一個類分為為Track、Main、Bullet。

          * 軌道
                      
                 軌道這個角色很重要,它可以解決彈幕位置計算、速度控制、碰撞檢測問題。
                 首先,我們要來初始化軌道。通俗的說我們要修建幾個跑道呢,我們不是實物,可以動態調整軌道的                        數量,計算的原則:
                  軌道數量 = 播放器有效高度 / 設備基準字號
              * 播放器有效高度:播放器的實際高度減去控制條的高度,因為彈幕不可以遮擋控制條。
              * 設備基準字號:移動端是10px,pc端是12px;
                  為啥計算公式是這樣的?因為我們要支持不同字號的彈幕。試想不同的字號對物理空間的占用是不同的,然而如果要求軌道的尺寸是動態的,那就帶來很復雜的計算。本文提出“虛擬軌道”的概念,在交通管制中最常見的就是道路合并或者改向。我們也是采用將相鄰的物理軌道臨時合并為一條軌道。這樣就可以輕松的解決不同字號的軌道占用問題。原理圖如下:
                  

          圖2.2 軌道計算示意圖

          其次我們來回憶下機場的工作流程:
          1. 機長呼叫塔臺,CZ6132請求起飛
              * 目前跑道均被占用,請等待
                  * N時刻后再次執行步驟1
              * 目前跑道 A1 空閑,準許進入
                  * 執行步驟3
          2. 塔臺查看跑道使用情況
          3. 進入跑道,起飛完成
          4. 機長通知塔臺,本次起飛完成,釋放跑道的占用
          5. 其他飛機同樣執行上述步驟

          按照這個思路,我們的彈幕工作流程:
              
          1. 彈幕進入播放器
          2. 軌道根據彈幕的播放速度、尺寸計算是否有合適的軌道提供
              * 沒有
                  * 通知彈幕尚無合適軌道提供,請等待;同時,彈幕隊列中的其他彈幕依次執行步驟1
              * 有
                  * 執行步驟3
          3. 播放器加載彈幕DOM,開始播放,待播放完成
          4. 播放完成通知軌道更新軌道占用情況
          5. 其他彈幕同樣執行上述步驟

          圖2.3 軌道可用性計算示意圖

           

          關于軌道的基本原理我們整理清楚了,當然還有不少細節比如如何和調度通信、如何和彈幕通信以及虛擬軌道檢測算法等。有興趣的同學可以參考代碼吧。https://github.com/bytedance/xgplayer/blob/master/packages/xgplayer/src/control/makeBullet.js

          * 彈幕
                 彈幕基本是實現“飛機”的角色,我們要求它具有自身的屬性和方法。比如調度中心通過id能拿到它所有的基本信息,軌道控制也可以通過彈幕進行檢查和更新。當然彈幕也必須具備狀態自動更新、移動、播放結束通知、自動銷毀等功能。
          * 調度
                  調度就是搭臺的化身,承接著軌道、彈幕的控制,也保持著與播放器的步調一致。它的職責如下:
              1. 播放器交互控制
              2. 彈幕隊列控制
              3. 自身狀態更新
              4. 數據格式轉換
              5. 動畫執行
                  還是直接用流程圖來描述更直接些:
                  
                 

          圖2.4 彈幕運行機制流程圖

          在彈幕啟動之后,首先要檢查本地是否已有緩存數據,沒有的話直接請求數據并緩存,然后執行數據讀取,首次過濾數據進入彈幕隊列,同時啟動定時器。彈幕隊列的數據會定期請求軌道,檢測隊列里的彈幕是否可以進入,一旦確認后軌道做好登記,彈幕就可以進入播放器開啟動畫播放了。定時器每隔2秒就會再次更新數據進入到彈幕隊列(這塊不同的業務可以定制不同的規則)。彈幕播放結束后會通知調度和軌道,調度會在彈幕隊列中移除該彈幕實例,軌道也會移除該彈幕實例的軌道占用。

          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務


          快速開發一個自己的微信小程序

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          一.寫在前面

          小程序學習資料

          1.為什么要學小程序開發?

          對于前端開發而言,微信小程序因為其簡單快速、開發成本低、用戶流量巨大等特點,也就成了前端開發工程師必會的一個技能。

          2.開發準備:

          (1)有人開玩笑說,會vue小程序根本都不用學:

          微信小程序雖然是騰訊自己搞的,但是核心的思想跟vue等框架是一樣一樣的哦~

          (2)善于搜集精美的小組件: “我們不生產代碼,我們只是代碼的搬運工”,善于找到想要的組件并把他們巧妙優雅的組裝成一個大項目,也算是程序員一項基本技能了。

          具體怎么找到想要的小程序demo,篇末會給大家推薦小程序的資源,有很多大神的項目哦

          擼起袖子開干了

          一.注冊小程序賬號,下載IDE

          1.官網注冊https://mp.weixin.qq.com/,并下載IDE。

          2.官方文檔一向都是最好的學習資料。

          注意:

          (1)注冊賬號之后會有一個appid,新建項目的時候需要填上,不然很多功能是用不了的,比如不能預覽,不能上傳代碼等等。

          (2)如果你注冊過微信公眾號的話,一定要注意,微信公眾號和小程序是兩個賬號,二者的appid也是不同,小程序開發必須使用小程序的appid哦。

          二.小程序框架介紹和運行機制

          1.我們建立了“普通快速啟動模板”,然后整個項目目錄如下:

          2.app.js

          整個項目的啟動文件,如注釋寫的onlaunch方法有三大功能,瀏覽器緩存進行存和取數據;用登陸成功的回調;獲取用戶信息。

          globalData是定義整個項目的全局變量或者常量哦。

          3.app.json

          整個項目的配置文件,比如注冊頁面,配置tab頁,設置整個項目的樣式,頁面標題等等;

          !注意:小程序啟動默認的第一個頁面,就是app.json的pages中的第一個頁面哦。

          4.pages

          小程序的頁面組件,有幾個頁面就會有幾個子文件夾。比如快速啟動模板,就有兩個頁面,index和logs

          5.打開index目錄

          可以看到有三個文件,其實和我們web開發的文件是一一對應的。

          index.wxml對應index.html;

          index.wxss對應index.css;

          index.js就是js文件哦。

          一般我們還會給每個頁面組件添加一個.json文件,作為該頁面組件的配置文件,設置頁面標題等功能

          6.雙擊index.js文件

          (1)var app = getApp();

          引入整個項目的app.js文件,用來取期中的公共變量等信息。

          如果要使用util.js工具庫中的某個方法,在util.js中module.exports導出,然后在需要的頁面中require即可得到哦。

          (2)比如,我們要獲取豆瓣電影的時候,我們需要調用豆瓣的api;我們先在app.js中的gloabData中定義doubanBase

          然后在index.js中使用app.globaData.doubanBase即可取到這個值。

          當然這些常量你也可以在頁面需要的時候,再用寫死的值,但是為了整個項目的維護,還是建議把這種公用參數統一寫在配置文件中哦。

          (3)接下來在整個page({})中,第一個data,就是本頁面組件的內部數據,會渲染到該頁面的wxml文件中,類似于vue、react哦~

          通過setData修改data數據,驅動頁面渲染

          (4)一些生命周期函數

          比如onload(), onready(), onshow(), onhide()等等,監聽頁面加載、頁面初次渲染、頁面顯示、頁面隱藏等等

          更多的可以查官網API哦。其中用的最多的就是onload()方法,和onShareAppMessage()方法(設置頁面分享的信息)

          7 .wxml模板的使用。

          比如本項目電影頁面,就是以最小的星級評價組件wxml當做模板,star到movie到movie-list,一級一級的嵌套使用。

          star-template.wxml頁面寫好name屬性;然后import引入的時候通過name獲得即可

          8.常用的wxml標簽

          view,text,icon,swiper,block,scroll-view等等,這些標簽直接查官網文檔即可

          三.小程序框架、各個頁面以及發布上線的注意點

          1.整個框架中的一些注意點

          (1)整個wxml頁面,最底層的標簽是哦。

          (2) 每個頁面頂部導航欄的顏色,title在本頁面的json中配置,如果沒有配置的話,取app.json中的總配置哦。

          (3)json中不能寫注釋哦,不然會報錯的。

          (4)路由相關

          1)使用wx.SwitchTab跳轉tab頁的話,在app.json中除了注冊pages頁面,還需要在tabBar中注冊tab頁,才能生效哦。

          注意:tab最多5個,也就是我們說的頭部或者底部最多5個菜單。其他的頁面只能通過其他路由方法打開哦。

          2)navigateTo是跳到某個非tab頁,比如歡迎頁,電影詳情頁,城市選擇頁;在app.json中注冊后,不能在tabBar里注冊哦,不然同樣也是不能跳轉的哦。

          3)reLaunch跳轉,新開的頁面左上角是沒有退回按鈕的,本項目只用了一次,切換城市的時候哦。

          (5)頁面之間傳遞參數

          參數寫在跳轉的url之中,然后另一個頁面在onload方法中的傳參option接收到。如下傳遞和獲取id

          (6)data-開頭的自定義屬性的使用

          比如wxml中我們怎么寫

          點擊的事件對象可以這么取,var postId = event.currentTarget.dataset.postid;

          注意: 大寫會轉換成小寫,帶_符號會轉成駝峰形式

          (7)事件對象event,event.target和event.currentTarget的區別:

          target指的是當前點擊的組件 和currentTarget 指的是事件捕獲的組件。

          比如,輪播圖組件,點擊事件應該要綁定到swiper上,這樣才能監控任意一張圖片是否被點擊,

          這時target這里指的是image(因為點擊的是圖片),而currentTarget指的是swiper(因為綁定點擊事件在swiper上)

          (8)使用免費的網絡接口:

          本項目中用到了 和風天氣api,騰訊地圖api,百度地圖api,豆瓣電影api,聚合頭條新聞api等,具體用法可以看各自官網的接口文檔哦,很詳細的

          注意:免費接口是有訪問限制的,所以如果用別人的組件用了這種接口的話,最好還是自己注冊一個新的key替換上哦

          附上一個免費接口大全:

          https://github.com/jokermonn/-Api

          !!另外還要注意,要把這些接口的域名配置到小程序的合法域名中,不然也是訪問不了的

          (8)wxss有一個坑:無法讀取本地資源,比如背景圖片用本地就會報錯哦。

          把本地圖片弄成網絡圖片的幾種方式: 上傳到個人網站;QQ空間相冊等等也是可以的哦

          2.切換城市頁面:

          (1)首頁使用navigateTo跳轉到切換城市頁,由于首頁并沒有關閉,導致切換了城市返回來,天氣信息還是舊的。

          正確的處理邏輯如下:

          1)使用reLaunch跳轉到切換城市頁面,實質是關閉所有頁面打開新的頁面哦。

          2)切換城市頁面,更新公共變量中城市信息為手動切換的城區,再switchTab回到首頁,觸發首頁重新加載。

          3)首頁獲取城市信息的時候加一個判斷,全局沒有才取定位的,全局有(比如剛才設置了)就用全局的哦。

          (2)城市列表的滾動和回到頂部

          基于scroll-view組件的scroll-top屬性,初始就是0,滾動就會增加的;點擊回到頂部給它置為0即可回到頂部

          3.天氣頁

          (1)初始化頁面,天氣顯示的邏輯

          首先調用小程序的wx.getLocation方法獲得當前的經緯度,然后調用騰訊地圖獲得當前的城市名稱和區縣名稱,并存到公共變量中,

          再調用查詢天氣和空氣質量的方法哦。

          (2)容錯處理

          城市的名稱長短不一,有點名字特別長,比如巴彥淖爾市這種,需要動態的獲取完整的城市名稱;

          有些偏僻的城市暫時沒有天氣信息,我們需要對返回的結果進行判斷,沒有信息的需要給用戶一個良好的提示信息。

          4.周邊-地圖服務頁面

          (1)調用百度地圖的各種服務,查詢酒店,美食,生活服務三種信息,更多信息可以看百度地圖的文檔

          (2)點擊時給被點中的圖標加個邊框,數據驅動視圖,所以使用一個長度為3的數組保存三個圖標當前是否被點中的狀態

          然后wxml再根據數據來動態添加class,增加邊框樣式

          5.豆瓣電影頁

          (1)電影詳情頁的預覽圖片,用小程序本身的previewImage實現。

          (2)詳情頁使用onReachBottom()方法,監控用戶上拉觸底事件,然后發送請求繼續獲得數據,實現懶加載的效果

          (3)用戶體驗方面的優化,js中將整數評分比如7分統一改為7.0分,然后wxml模板再判斷分數是否為0顯示“暫無評分”

          (4)搜索之后清空搜索框

          因為小程序中不能使用getelementbyId這種方式獲得元素,只能用數據來控制了

          在data中加一個屬性searchText來保存搜索框的內容并和 input的value屬性綁定,搜索完成或者點擊X時,searchText變量清空即可實現清空輸入框的效果哦。

          6.新聞頁面

          (1)聚合頭條新聞的免費接口,只返回了新聞的基本信息,新聞的主體內容是沒有的哦。

          我找了好多新聞類的接口,好像都是沒有新聞主體內容的。如果誰知道更好的接口歡迎留言告訴我哈~

          (2)當然,也可以自己去爬新聞網站的數據哦

          7.更多頁面

          (1)小程序目前開放外鏈的功能只是給公司組織的小程序開放了,個人開發還是不能使用外鏈的哦。

          (2)彩蛋頁面,獲得用戶信息

          通過 wx.setStorageSync('userInfos', userInfos); 可以獲得登陸小程序的用戶的個人信息,可以發送給后臺存到數據庫中,方便對用戶進行分析

          我這里只是存儲到瀏覽器緩存中哦,最大應該是10M緩存;如果用戶把這個小程序從小程序列表中刪除掉,就會清空這個緩存。

          8.發布注意

          (1) 新版本小程序發布的限制為2M,一般都是圖片最占空間,所以盡量使用網絡圖片

          具體怎么把本地圖片變成網絡圖片,上面有講哦。

          (2)在開發者工具上預覽測試沒問題,點擊上傳;網頁版小程序個的人中心的左側“開發管理”菜單,第三塊--開發版本就有了內容。

          (3)點擊提交,填寫小程序相關信息,就可以提交審核了哦。

          注意:分類最好填寫準確,這樣才能更快的通過審核哦。我這個小程序一天半時間過審上線的

          至此,我就把兩天開發內碰到的坑和注意點都過了一遍,據說還有更多的坑,等之后更深入的開發再繼續研究咯。

          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 平面設計服務

          mongoose中save無法獲取回調函數值的解決方法

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          mongoose保存數據:

          const save = new Model(data).save()
              
          • 1

          如果成功,則可以獲取到保存在數據庫的值,但是如果保存數據失敗,則會拋出異常,好在save可以傳入一個回調函數,用法如下:

          const save = new Model(data).save((err, result)=>{ if(err){ // 保存失敗執行的操作
              }else { // 保存成功執行的操作
              }
          
          })
              
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8

          我們希望根據結果獲取到不同的值,但是此時save返回的是undefined,因為save中的回調函數是一個異步操作

          解決方法:

          使用try catch:

          try{
              const save = await new Model(data).save();
              // 保存成功執行的操作 return ... }catch(err){
              // 保存失敗執行的操作 return ... }
              
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8

          注意:在async函數中才可以這么使用,因為await只能用在async函數中

          示例:(注冊功能)

          user.model.js

          const mongoose  = require("mongoose"); const port      = process.env.PORT || "8899"; const UserSchema = mongoose.Schema({
              userName: {
                  type: String,
                  unique: true },
              passWord: String,
              createTime: {
                  type: Date, default: Date.now()
              },
              updateTime: {
                  type: Date, default: Date.now()
              }
          }, {
              timestamps: {
                  createAt: "createTime",
                  updateTime: "updateTime" }
          });
          
          module.exports = mongoose.model("USER", UserSchema);
              
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
          • 13
          • 14
          • 15
          • 16
          • 17
          • 18
          • 19
          • 20
          • 21
          • 22
          • 23
          • 24
          • 25

          service.js

          const User = require("./user.model);
          class User{
              async login(user){
                      try{
                          const result = await new User(user).save();
                          // 其他操作,如發送注冊郵件
                          return { success: true }
                      }catch(err){
                          return { success: false, message: "用戶名或密碼錯誤" }
                      }
             }
          }
          moduel.exports = new User();
              
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
          • 13

          controller.js

          const server = require("./server); async login(){ // 首先獲取請求中攜帶的用戶信息 const result = await server.login(user);
              if(result.success){ // 注冊成功執行的操作 }else { // 注冊失敗執行的操作 }
          }
          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務

          HTML-圖片標簽img

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          圖片標簽

          圖片標簽<img src=路徑屬性 alt:加載失敗后顯示的文本  width:指定圖片寬度  height:指定圖片高度>  單位: px

          路徑屬性

          絕對路徑
                  E:\ruanjian\軟件\環境\images
          相對路徑:相對于主文件位置的路徑
                  引用文件方式:

                  同級:直接寫文件名.后綴名
                  上級:../文件名.后綴名   ../返回上一級文件夾
                  下級:文件夾/文件名.后綴名

          
              
          1. <!DOCTYPE html>
          2. <html>
          3. <head>
          4. <meta charset="utf-8">
          5. <title></title>
          6. </head>
          7. <body>
          8. <h1>這是一個圖片</h1>
          9. <!-- 圖片標簽<img src=路徑屬性 alt:加載失敗后顯示的文本 width:指定圖片寬度 height:指定圖片高度 單位:px>
          10. 路徑屬性:
          11. 絕對路徑
          12. E:\ruanjian\軟件\環境\images
          13. 相對路徑:相對于主文件位置的路徑
          14. 同級:直接寫文件名.后綴名
          15. 上級:../文件名.后綴名 ../返回上一級文件夾
          16. 下級:文件夾/文件名.后綴名
          17. -->
          18. <img src="../img/ad.jpg" alt="加載中" width="1000px" height="500px">
          19. <img src="../img/1.jpg" alt="加載中"><br><br><br><br><br><br><br><br><br><br><br>
          20. <img src="../footer.jpg" ><br>
          21. </body>
          22. </html>

          <br>標簽:換行   <img>標簽為內聯標簽所以不換行,所以添加<br>標簽換行。

          頁面是這樣的:

          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務


          前端性能優化之Lazyload

          seo達人

          如果您想訂閱本博客內容,每天自動發到您的郵箱中, 請點這里

          前端性能優化之Lazyload

          @(Mob前端-冬晨)[JavaScript|技術分享|懶加載]


          Lazyload 簡介

          前端工作中,界面和效果正在變得越來越狂拽炫酷,與此同時性能也是不得不提的問題。有些項目,頁面長,圖片多,內容豐富。像商城頁面。如果同步加載時一次性加載完畢,那肯定是要等到花都謝了,loading轉的人都崩潰~。今天分享的是Lazyload技術 是一種延遲加載技術。讓頁面加載速度快到飛起、減輕服務器壓力、節約流量、提升用戶體驗。

          一、實現思路

          頁面較長,屏幕的可視區域有限。 
          不設置頁面中img標簽src屬性值或者將其指向同一個占位圖。 
          圖片的實際地址存在img標簽自定義的一個屬性中,如:“data-url”。 
          監聽scroll,滾動到某個位置時,動態的將url替換成實際的“data-url”。

          二、上代碼

          • html部分(簡單示意下結構)
          <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Lazyload</title> <style type="text/css"> .mob-wrap li{list-style: none;width: 100%;height: 345px;} </style> </head> <body> <ul class="mob-wrap"> <li"> <img class="tamp-img" alt="loading" data-src="http://mob.com/public/images/index/sharesdk-logo.jpg"><p>ShareSDK輕松實現社會化功能</p> </li> <li"> <img class="tamp-img" alt="loading" data-src="http://mob.com/public/images/index/sms-logo.jpg"><p>短信驗證碼SDK</p> </li> <li"> <img class="tamp-img" alt="loading" data-src="http://mob.com/public/images/index/rec-logo.jpg"><p>MobLink實現Web與App的無縫鏈接</p> </li> </ul> </body> </html>
              
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
          • 13
          • 14
          • 15
          • 16
          • 17
          • 18
          • 19
          • 20
          • 21
          • 22
          • 23

          簡要流程

          Start監聽滾動事件距頂部高度<scrollTop么?將url替換成data-urlEndyesno
          • js部分
          var aImg = [
            {"src":"http://mob.com/public/images/index/sharesdk-logo.jpg","txt":"ShareSDK輕松實現社會化功能"},
            {"src":"http://mob.com/public/images/index/sms-logo.jpg","txt":"短信驗證碼SDK"},
            {"src":"http://mob.com/public/images/index/rec-logo.jpg","txt":"MobLink實現Web與App的無縫鏈接"}
          ]; var sLi = '';
          document.getElementsByClassName("mob-wrap")[0].innerHTML=""; for(let i = 0;i<10;i++){
            sLi = document.createElement("li");
            sLi.innerHTML = `<img class="tamp-img" alt="loading" src="./zwt.gif" data-src="${aImg[i%3].src}"><p>${aImg[i%3].txt}</p>`;
            document.getElementsByClassName("mob-wrap")[0].appendChild(sLi);
          };
          
          window.onscroll = function () {
            var bodyScrollHeight =  document.documentElement.scrollTop;// body滾動高度
            var windowHeight = window.innerHeight;// 視窗高度
            var imgs = document.getElementsByClassName('tamp-img');
            for (var i =0; i < imgs.length; i++) { var imgHeight = imgs[i].offsetTop;// 圖片距離頂部高度 if (imgHeight < windowHeight + bodyScrollHeight - 340) { imgs[i].src = imgs[i].getAttribute('data-src'); imgs[i].className = imgs[i].className.replace('tamp-img','');
              }
            }
          };
              
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
          • 13
          • 14
          • 15
          • 16
          • 17
          • 18
          • 19
          • 20
          • 21
          • 22
          • 23
          • 24
          • 25




          謝謝觀看,搞定收工0.0~~~這樣草草了事總是不好的

          三、再優化

          不做任何處理直接監聽scroll必然導致在滾動鼠標滾輪的時候,過于頻繁的觸發處理函數。 
          如果剛巧在處理函數中有大量的操作dom等消耗性能的行為,引發大量操作,導致頁面變卡變慢, 
          甚至瀏覽器崩潰無響應。 
          處理這種問題的思路是節流和防抖。 
          節流函數的概念有一個很形象的比喻:在接咖啡的時候,按了一次按鈕會出咖啡, 
          緊跟著再按幾次按鈕接到的還是那一杯咖啡,相當于后面幾次按的沒有起作用。


          常規的節流在這里就不多說了,下面介紹的是一種每隔least時間內至少執行一次的節流函數。

          //節流函數 _throttle = (fn, delay, least) => { var timeout = null,
            startTime = new Date();
              fn(); return function() { var curTime = new Date();
              clearTimeout(timeout); if(curTime - startTime >= least) {
                  fn();
                  startTime = curTime;
              }else {
                  timeout = setTimeout(fn, delay);
              }
              }
          }
              
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
          • 13
          • 14
          • 15
          • 16

          使用節流函數

          function compare () { var bodyScrollHeight =  document.documentElement.scrollTop;// body滾動高度 console.log(bodyScrollHeight+"替換src方法") var windowHeight = window.innerHeight;// 視窗高度 var imgs = document.getElementsByClassName('tamp-img'); for (var i =0; i < imgs.length; i++) { var imgHeight = imgs[i].offsetTop;// 圖片距離頂部高度  if (imgHeight < windowHeight + bodyScrollHeight - 340) {
                 imgs[i].src = imgs[i].getAttribute('data-src');
                 imgs[i].className = imgs[i].className.replace('tamp-img','');
              }
            }
          }
          window.onscroll = _throttle(compare, 350,600);
              
          • 1
          • 2
          • 3
          • 4
          • 5
          • 6
          • 7
          • 8
          • 9
          • 10
          • 11
          • 12
          • 13
          • 14

          滾動時間least長于600,調用compare,否則延遲350ms執行。 
          這樣相對于直接onscroll性能得到更進一步提升,在功能上也沒有什么問題。 
          不同的業務場景調整一下delay和least就可以。


          結語:歷史潮流浩浩蕩蕩,前端技術的發展也是日新月異。 
          不斷通過一個個小的技術點深入探究,以加深自己對js這門語言的理解。 
          溫故知新,回顧舊的內容,學習新的內容和特性,更好的適應工作中的需求。

          藍藍設計www.syprn.cn )是一家專注而深入的界面設計公司,為期望卓越的國內外企業提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網站建設 、平面設計服務



          日歷

          鏈接

          個人資料

          藍藍設計的小編 http://www.syprn.cn

          存檔

          亚洲va欧美va天堂v国产综合