<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>

          首頁

          js reduce()

          seo達人

          是什么

          ES5提供的數組的方法。

          reduce() 方法接收一個函數作為回調函數(accumulator),數組中的每個值(從左到右)開始縮減(其實就是從左往右開始對每個數執行回調函數),最終為一個值。



          PS: 回調函數的返回結果類型和傳入的初始值相同



          語法以及參數

          arr.reduce(  callback(accumulator, currentValue,index ,array ) ,initialValue )

          1

          initialValue 可選

          如果有的話則作為,第一次調用 callback函數時的第一個參數的值。

          如果沒有提供初始值,callback則使用數組的第一個元素,作為第一次調用的初始值。

          在沒有初始值的空數組上調用 reduce 將報錯。



          accumulator

          默認傳入上一次調用回調函數的的返回值。

          初始值: initialValue存在的話,則是initialValue 若沒有則是數組的第一個元素



          currentValue

          數組中正在處理的元素。



          index 可選

          數組中正在處理的當前元素的索引。 如果提供了initialValue,則起始索引號為0,否則從索引1起始。



          array可選

          調用reduce()的數組



          一個小小的例子

          例1 無initialValue

          var  arr = [1, 2, 3, 4, 5];

          sum = arr.reduce(function(result, cur, index, arr) {

              console.log(result, cur, index,arr);

              return result+ cur;

          })

          console.log(sum) // 最后的結果是15



          result cur index arr

          第1次 1 2 1 [1, 2, 3, 4, 5]

          第2次 3 3 2 [1, 2, 3, 4, 5]

          第3次 6 4 3 [1, 2, 3, 4, 5]

          第4次 10 5 4 [1, 2, 3, 4, 5]

          例2 有initialValue 傳入10

          var  arr = [1, 2, 3, 4, 5];

          sum = arr.reduce(function(result, cur, index, arr) {

              console.log(result, cur, index,arr);

              return result+ cur;

          },10)

          console.log(sum) // 最后的結果是25



          result cur index arr

          第1次 10 1 0 [1, 2, 3, 4, 5]

          第2次 11 2 1 [1, 2, 3, 4, 5]

          第3次 13 3 2 [1, 2, 3, 4, 5]

          第4次 16 4 3 [1, 2, 3, 4, 5]

          第5次 20 5 4 [1, 2, 3, 4, 5]

          回調函數的返回值

          上面的例子返回的都是一個整型數字,如果希望返回其他類型的數據呢?



          這個就跟accumulator的初始值有關系了。

          下面的例子我們傳入的是一個object {sum: 0}



          var items = [0,1,2,3,4];

          var reducer = function add(sumT, item) {

            console.log(sumT)

            sumT.sum = sumT.sum + item;

            return sumT;

          };

          var total = items.reduce(reducer, {sum: 0});

          console.log(total); // {sum:1130}



          運行結果



           {sum: 0}

           {sum: 1}

           {sum: 3}

           {sum: 6}

           {sum: 10}



          reduce()的應用

          1. 數組扁平化

            遞歸+reduce



            let arr = [1, 2, '3js', [4, 5, [6], [7, 8, [9, 10, 11], null, 'abc'], {age: 12}, [13, 14]], '[]'];



            function flatten(arr) {

              if(Array.isArray(arr)) {

                return arr.reduce((prev, cur) => {

                   // 如果遍歷的當前項是數組,遞歸調用flatten

                  return Array.isArray(cur) ? prev.concat(flatten(cur)) : prev.concat(cur)

                }, [])

              } else {

                throw new Error(' 當前參數不是數組')

              }

            }

            console.log(flatten(arr));



            PS:這里的throw new Error只是用來判斷一開始的arr,這是因為在遞歸只傳入數組。


          node系列之數據接口注冊接口的實現(token驗證登陸)

          seo達人

          node系列之數據接口注冊登陸接口的實現

          1、使用express腳手架創建項目

          2、了解項目的目錄結構

          3、準備數據庫相關文件

          4、編寫注冊接口

          5、編寫登陸接口

          6、驗證登陸實現

          7、預告

          1、使用express腳手架創建項目

          // 安裝腳手架,只需安裝一次

          npm i express-generator -g

          // 創建express項目

          express myapp --view=ejs

          cd myapp

          // 安裝依賴

          npm i 

          // 安裝需要使用的模塊

          // 數據庫模塊 用戶唯一id模塊 密碼加密模塊 token模塊

          npm i mongoose node-uuid bcryptjs jsonwebtoken -S



          2、了解項目的目錄結構

          bin

          www ------- 服務器啟動

          node_modules ------- 項目的依賴文件

          public ------- 靜態資源文件夾

          images ------- 靜態圖片

          javascripts ------- 靜態的js文件

          stylesheets ------- 靜態的樣式表文件

          routes ------- 路由文件

          index.js ------- 默認的路由

          users.js ------- 用戶相關的路由

          views ------- 路由對應的頁面

          index.ejs ------- 默認的首頁

          error.ejs ------- 錯誤頁面

          app.js ------- 使用中間件,注冊路由

          package.json ------- 描述文件

          3、準備數據庫相關文件

          大勛在node系列之數據庫mongoose的封裝中給大家介紹了如何封裝mongoose,可以先行查看如何封裝,封裝的文件夾為sql,如果不想看的,可以直接通過網盤下載該文件夾



          將該sql文件放置項目的跟目錄下


          • myapp

            - sql

            - collection

            users.js

            db.js

            index.js



            4、編寫注冊接口

            目標文件: myapp/routes/users.js



            實現思路:使用post提交數據的方式,先以手機號查詢有沒有該用戶,如果有該用戶,提示用戶該賬號已經注冊過了;如果沒有該用戶,則可以完成注冊,首先得將密碼加密,加密完成后插入數據庫



            代碼實現:



            // 找到用戶集合

            var User = require('./../sql/collection/users');

            // 找到數據庫封裝文件

            var sql = require('./../sql');

            // 狀態碼的封裝

            var utils = require('./../utils')

            // 用戶唯一標識的id

            var uuid = require('node-uuid');

            // 密碼加密模塊

            var bcrypt = require('bcryptjs');

            var salt = bcrypt.genSaltSync(10); // 加密級別



            // 實現注冊接口 -- post提交方式

            router.post('/register', (req, res, next) => {

              // 1、先獲取表單信息

              let { username, password, tel } = req.body;

              // 2、根據手機號查詢 用戶集合中是否有該用戶,如果有,返回有該賬戶,如果沒有注冊繼續

              sql.find(User, { tel }, { id: 0 }).then(data => {

                // 2.1 判斷有沒有該用戶

                if (data.length === 0) {

                  // 2.2 沒有該用戶----繼續完成注冊操作

                  // 2.2.1 生成用戶的id

                  let userid = 'users
            ' + uuid.v1();

                  // 2.2.2 對密碼加密

                  password = bcrypt.hashSync(password, salt)

                  // 2.2.3 插入數據庫

                  sql.insert(User, { userid, username, password, tel}).then(() => {

                    res.send(utils.registersuccess)

                  })

                } else {

                  // 2.3 已有該用戶

                  res.send(utils.registered)

                }

              })

            })



            附 狀態碼封裝模塊 myapp/utils/index.js

            module.exports = {

              registered: {

                code: '10000',

                message: '該用戶已注冊,請直接登錄' 

              },

              registersuccess: {

                code: '10101',

                message: '注冊成功' 

              }

            }



            5、編寫登陸接口

            目標文件 myapp/routes/users.js

            實現思路:根據手機號查詢有沒有該用戶,如果沒有,提示用戶未注冊,如果有該用戶,使用bcryptjs模塊驗證密碼的有效性,如果有效,生成token,返回給前端相應的token值。

            var jwt = require('jsonwebtoken');

            // 實現登陸功能

            router.post('/login', (req, res, next) => {

              // 1、獲取表單信息

              let { tel, password } = req.body;

              // 2、依據手機號查詢有沒有該用戶

              sql.find(User, { tel }, { _id: 0 }).then(data => {

                // 2.1 判斷有么有該用戶

                if (data.length === 0) {

                  // 2.2 沒有該用戶

                  res.send(utils.unregister)

                } else {

                  // 2.3 有該用戶,驗證密碼

                  // 2.3.1 獲取數據庫中的密碼

                  let pwd = data[0].password;

                  // 2.3.2 比較 輸入的 密碼和數據庫中的密碼

                  var flag = bcrypt.compareSync(password, pwd) // 前為輸入,后為數據庫

                  if (flag) {

                    // 2.3.3 密碼正確,生成token

                    let userid = data[0].userid

                    let username = data[0].username

                    let token = jwt.sign({ userid, username }, 'daxunxun', {

                      expiresIn: 606024// 授權時效24小時

                    })

                    res.send({

                      code: '10010',

                      message: '登陸成功',

                      token: token

                    })

                  } else {

                    // 2.3.4 密碼錯誤

                    res.send({

                      code: '10100',

                      message: '密碼錯誤'

                    })

                  }

                }

              })

            })



            6、驗證登陸實現

            目標文件: myapp/app.js

            實現思路:很多的數據請求都需要登陸之后才能獲取到,在此統一封裝驗證登陸

            // 引入token模塊

            var jwt = require('jsonwebtoken');

            // 全局的路由匹配

            app.use((req, res, next) => {

             // 排除登陸注冊頁面

              if (req.url !== '/users/login' && req.url !== '/users/register') {

              // 不同形式獲取token值

                let token = req.headers.token || req.query.token || req.body.token;

                // 如果存在token ---- 驗證

                if (token) {

                  jwt.verify(token, 'daxunxun', function(err, decoded) {

                    if (err) {

                      res.send({ 

                        code: '10119', 

                        message: '沒有找到token.' 

                      });

                    } else {

                      req.decoded = decoded;  

                      console.log('驗證成功', decoded);

                      next()

                    }

                  }) 

                } else { // 不存在 - 告訴用戶---意味著未登錄

                  res.send({ 

                    code: '10119', 

                    message: '沒有找到token.' 

                  });

                }

              } else {

                next()

              }

            })




          Vue源碼剖析(三)patch和Diff算法

          seo達人

          Patch和Diff算法

          網上看了好多的博客和源碼教程,感覺很多仔細的地方沒有說清,而且在一些復雜的部分加了好多的描述,所以就想自己也寫下心得, 方便自己, 方便他人,有興趣的同學可以關注我的github里面有我之前一些博文 github/193Eric



          我們知道的,在數據更改后,會觸發getter,然后通過dep.notify()來通知watcher觸發update進而更新視圖,最終是通過Diff算法來對比新老Vnode的差異,并把差異更新到Dom視圖上



          Diff

          我們知道的,Virtual DOM是一顆樹,而diff算法主要把兩顆樹進行對比,找出之間的差異,來渲染頁面



          diff 算法是通過同層的樹節點進行比較而非對樹進行逐層搜索遍歷的方式,所以時間復雜度只有 O(n),是一種相當的算法



          1.調用patch函數比較Vnode和OldVnode,如果不一樣直接return Vnode即將Vnode真實化后替換掉DOM中的節點



          2.如果OldVnode和Vnode值得進一步比較則調用patchVnode方法進行進一步比較,分為以下幾種情況:



          Vnode有子節點,但是OldVnode沒有,則將Vnode的子節點真實化后添加到真實DOM上



          Vnode沒有子節點,但是OldVnode上有,則將真實DOM上相應位置的節點刪除掉



          Vnode和OldVnode都有文本節點但是內容不一樣,則將真實DOM上的文本節點替換為Vnode上的文本節點



          Vnode和OldVnode上都有子節點,需要調用updateChildren函數進一步比較



          updateChildren比較規則



          提取出Vnode和OldVnode中的子節點分別為vCh和OldCh,并且提出各自的起始和結尾變量標記為 oldS oldE newS newE



          如果是oldS和newE匹配上了,那么真實dom中的第一個節點會移到最后



          如果是oldE和newS匹配上了,那么真實dom中的最后一個節點會移到最前,匹配上的兩個指針向中間移動



          如果都沒有,在沒有key的情況下直接在DOM的oldS位置的前面添加newS,同時newS+1。在有key的情況下會將newS和Oldch上的所有節點對比,如果有相同的則移動DOM并且將舊節點中這個位置置為null且newS+1。如果還沒有則直接在DOM的oldS位置的前面添加newS且newS+1

          直到出現任意一方的start>end,則有一方遍歷結束,整個比較也結束



          updateChildren例子:



          假設:



          真實dom為 A、B、C

          oldDom為 A1、B1、C1

          newDom為 A2、D2、C2、B2



          先確定oldS = A1 ; oldE = C1; newS = A2; newE = B2



          先對比oldS和newS,oldE和newE,發現oldS = newS 所以真實dom的A固定不動。排序為 A、B、C

          然后oldS = B1 ; oldE = C1; newS = D2; newE = B2



          對比發現 oldS = newE , 所以真實dom,B要插入到后面去



          真實dom排序為:A、C、B



          然后oldS = C1; oldE = C1; newS = D2; newE = B2



          對比發現兩兩都不對等,所以走第三步。

          假設有key存在,所以newS直接和oldDom里面的所有節點對比,發現沒有存在,然后插入到oldS前面,且newS+1

          真實dom排序為:A、D、C、B

          然后重新開始,oldS++ > oldE-- ,結束了。



          這就是updateChildren,之后就是一直遍歷,運行updateChildren直到沒有


          一文秒懂 ajax, fetch, axios

          seo達人

          1, JavaScript的Ajax

          Ajax的全稱是Asynchronous JavaScript and XML,意思就是用JavaScript執行異步網絡請求,而不需要重載(刷新)整個頁面。

          Ajax使用XMLHttpRequest對象取得新數據,然后再通過 DOM 將新數據插入到頁面中。另外,雖然名字中包含 XML 的成分,但 Ajax 通信與數據格式無關; 這種技術就是無須刷新頁面即可從服務器取得數據,但不一定是 XML 數據。

          對于IE7+和其他瀏覽器,可以直接使用XMLHttpRequest對象,對于IE6及以前的瀏覽器,使用ActiveXObject對象。



          使用方法如下:



          var xhr;

          if (window.XMLHttpRequest) {

              xhr = new XMLHttpRequest();

          } else {

              xhr = new ActiveXObject('Microsoft.XMLHTTP');

          }

          1

          2

          3

          4

          5

          6

          啟動請求:



          xhr.open(method, url, boolean);     

          xhr.send();

          1

          2

          注:

          1,xhr.open參數含義:

          method:請求方式,post、get等

          url: 請求鏈接,只能向同源的url發送請求

          boolean:是否異步請求,true:異步, false: 同步,默認為true

          2,調用 open()方法并不會真正發送請求, 而只是啟動一個請求以備發送。

          3,send()方法接收一個參數,即要作為請求主體發送的數據(post方法會使用,get方法直接傳null)。如果不需要通過請求主體發送數據,則必須傳入 null,因為這個參數對有些瀏覽器來說是必需的。調用send()之后,請求就會被分派到服務器。



          XMLHttpRequest對象的異步請求示例如下:



          function success(text) {

              console.log(text);

          }



          function fail(code) {

             console.log(code);

          }



          var xhr = new XMLHttpRequest();     // 新建XMLHttpRequest對象

          xhr.onreadystatechange = function () { 

              // 狀態發生變化時,函數被回調

              if (xhr.readyState === 4) { // 成功完成

                  // 判斷響應結果:

                  if (xhr.status === 200) {

                      // 成功,通過responseText拿到響應的文本:

                      return success(xhr.responseText);

                  } else {

                      // 失敗,根據響應碼判斷失敗原因:

                      return fail(xhr.status);

                  }

              } else {

                  // HTTP請求還在繼續...

              }

          }



          // 發送請求:

          xhr.open('get', '/api/categories');

          xhr.send(null);

          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

          26

          27

          28

          xhr的屬性含義如下:

          responseText: 作為響應主體被返回的文本。

          responseXML: 如果響應的內容類型是"text/xml"或"application/xml",這個屬性中將保存響應數據的 XML DOM 文檔。

          status: 響應的 HTTP 狀態。

          statusText: HTTP 狀態的說明。

          readyState :表示請求/響應過程的當前活動階段??扇≈等缦?。

          0: 未初始化。尚未調用 open()方法。

          1: 啟動。已經調用 open()方法,但尚未調用 send()方法。

          2: 發送。已經調用 send()方法,但尚未接收到響應。

          3: 接收。已經接收到部分響應數據。

          4: 完成。已經接收到全部響應數據,而且已經可以在客戶端使用了。

          只要 readyState 屬性的值由一個值變成另一個值,都會觸發一次 readystatechange 事件??梢岳眠@個事件來檢測每次狀態變化后readyState 的值。通常,我們只對 readyState 值為 4 的階段感興趣,因為這時所有數據都已經就緒。不過,必須在調用 open()之前指定 onreadystatechange事件處理程序才能確??鐬g覽器兼容性。



          另外,在接收到響應之前還可以調用 abort()方法來取消異步請求:



          xhr.abort();

          1

          調用這個方法后,XHR 對象會停止觸發事件,而且也不再允許訪問任何與響應有關的對象屬性。在終止請求之后,還應該對 XHR 對象進行解引用操作。由于內存原因,不建議重用 XHR 對象。



          2, jQuery的Ajax

          $.ajax({

                  url:"",

                  type:"GET",

                  contentType: '',

                  async:true,

                  data:{},

                  dataType:"",

                  success: function(){

                  }

          });

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          url 必填項,規定把請求發送到哪個 URL。

          type 以什么樣的方式獲取數據,是get或post

          contentType:發送POST請求的格式,默認值為’application/x-www-form-urlencoded;

          charset=UTF-8’,也可以指定為text/plain、application/json

          async 是否異步執行AJAX請求,默認為true,千萬不要指定為false

          data 發送的數據,可以是字符串、數組或object。如果是GET請求,data將被轉換成query附加到URL上,如果是POST請求,根據contentType把data序列化成合適的格式;

          dataType

          接收的數據格式,可以指定為’html’、‘xml’、‘json’、'text’等,缺省情況下根據響應的Content-Type猜測。

          success 可選。執行成功時返回的數據。

          缺點:

          是基于XHR原生開發的,目前已有的fetch可替代。本身是針對mvc的編程模式,不太適合目前mvvm的編程模式。jQuery本身比較大,如果單純的使用ajax可以自己封裝一個,不然會影響性能體驗。



          3,Axios

          Vue2.0之后,axios開始受到更多的歡迎。其實axios也是對原生XHR的一種封裝,不過是Promise實現版本。它是一個用于瀏覽器和 nodejs 的 HTTP 客戶端,符合的ES規范。



          axios具有以下特征:



          從瀏覽器中創建 XMLHttpRequest

          支持 Promise API

          客戶端支持防止CSRF

          提供了一些并發請求的接口

          從 node.js 創建 http 請求

          攔截請求和響應

          轉換請求和響應數據

          取消請求

          自動轉換JSON數據

          PS:防止CSRF:就是讓你的每個請求都帶一個從cookie中拿到的key, 根據瀏覽器同源策略,假冒的網站是拿不到你cookie中得key的,這樣,后臺就可以輕松辨別出這個請求是否是用戶在假冒網站上的誤導輸入,從而采取正確的策略。



          設置全局的 axios 默認值



          axios.defaults.baseURL = '
          axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;

          axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'

          1

          2

          3

          注:axios 的 headers的 content-type 默認是 “application/json ”



          默認情況下,axios將JavaScript對象序列化為JSON,如果是get請求,對請求參數不用做任何處理,但是如果是post請求,并且Content-Type 為application/x-www-form-urlencoded,需要使用URLSearchParams API格式化請求參數, 否則Content-Type依然是application/json



          var params = new URLSearchParams();

          params.append('param1', 'value1');

          params.append('param2', 'value2');

          1

          2

          3

          get請求,以下3中寫法完全等價



          axios.get('/user?id=12345&name=xiaoming')

          .then(function (response) {

              console.log(response);

          })

          .catch(function (error) {

              console.log(error);

          });

          1

          2

          3

          4

          5

          6

          7

          axios.get('/user', {

              params: {

                id: '12345',

                name: 'xiaoming'

              }

          })

          .then(function (response) {

              console.log(response);

          })

          .catch(function (error) {

              console.log(error);

          });

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          axios({

              url: '/user',

              method: 'get',

              params: {

                id: '12345',

                name: 'xiaoming'

              }

          })

          .then(function (response) {

              console.log(response);

          })

          .catch(function (error) {

              console.log(error);

          });

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          post請求,以下2種寫法完全等價



          axios({

              url: '/user',

              method: 'post',

              headers: {

                  'Content-Type': 'application/json'

              },

              data: {

                id: '12345',

                name: 'xiaoming'

              }

          })

          .then(function (response) {

              console.log(response);

          })

          .catch(function (error) {

              console.log(error);

          });

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          15

          16

          17

          var url = '/user';

          var data = {

                id: '12345',

                name: 'xiaoming'

              };

          axios.post(url, data, {

                 headers: {

                  'Content-Type': 'application/json'

              }

          })

          .then(function (response) {

              console.log(response);

          })

          .catch(function (error) {

              console.log(error);

          });

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          15

          16

          執行多個并發請求



          function getUserAccount() {

            return axios.get('/user/12345');

          }

           

          function getUserPermissions() {

            return axios.get('/user/12345/permissions');

          }

           

          axios.all([getUserAccount(), getUserPermissions()])

            .then(axios.spread(function (acct, perms) {

              // 兩個請求現在都執行完成

          }));

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          創建實例



          可以使用自定義配置新建一個 axios 實例



          axios.create([config])

          var instance = axios.create({

            baseURL: '

            timeout: 1000,

            headers: {'X-Custom-Header': 'foobar'}

          });

          1

          2

          3

          4

          5

          6

          配置會以一個優先順序進行合并,順序由低到高為

          1,在 node_modules/axios/lib/defaults.js 找到的庫的默認值

          2,實例的 defaults 屬性

          3,請求的 config 參數



          // 使用由庫提供的配置的默認值來創建實例

          // 此時超時配置的默認值是 0

          var instance = axios.create();

           

          // 覆寫庫的超時默認值

          // 現在,所有請求都會等待 2.5 秒

          instance.defaults.timeout = 2500;

           

          // 為已知需要花費很長時間的請求覆寫超時設置

          instance.get('/longRequest', {

            timeout: 5000

          });

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          攔截器



          在請求發出之前或響應被 then 或 catch 處理前攔截它們做預處理。



          // 添加請求攔截器

          axios.interceptors.request.use(function (config) {

              // 在發送請求之前做些什么

            }, function (error) {

              // 對請求錯誤做些什么

            });

           

          // 添加響應攔截器

          axios.interceptors.response.use(function (response) {

              // 對響應數據做點什么

            }, function (error) {

              // 對響應錯誤做點什么

            });

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          可以在稍后移除攔截器:



          var myInterceptor = axios.interceptors.request.use(function () {/.../});

          axios.interceptors.request.eject(myInterceptor);

          1

          2

          可以為自定義 axios 實例添加攔截器



          var instance = axios.create();

          instance.interceptors.request.use(function () {/.../});

          1

          2

          4, fetch

          window 自帶了 window.fetch 方法, 在版的 Firefox 和 Chrome 中已經提供支持,其他瀏覽器還有兼容性問題,要做兼容性處理。fetch 是一個 基于promise設計的low-level API,不是ajax的進一步封裝,而是原生js,它注定不會像你習慣的 $.ajax 或是 axios 等庫幫你封裝各種各樣的功能或實現.



          interface GlobalFetch {

              fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;

          }

          1

          2

          3

          fetch()是一個全局的函數,返回一個promise對象。它有兩個參數,第一個參數是請求的地址,第二個參數是可選,RequestInit是個對象格式如下:



          interface RequestInit {

              body?: any;

              cache?: RequestCache;

              credentials?: RequestCredentials;

              headers?: HeadersInit;

              integrity?: string;

              keepalive?: boolean;

              method?: string;

              mode?: RequestMode;

              redirect?: RequestRedirect;

              referrer?: string;

              referrerPolicy?: ReferrerPolicy;

              window?: any;

          }

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          13

          14

          優點:

          符合關注分離,沒有將輸入、輸出和用事件來跟蹤的狀態混雜在一個對象里

          更好更方便的寫法

          更加底層,提供的API豐富

          脫離了XHR,是ES規范里新的實現方式

          fetch中可以設置mode為"no-cors"(不跨域)



          缺點:

          fetch不支持同步請求

          fetch只對網絡請求報錯,對400,500都當做成功的請求,需要封裝去處理

          fetch默認不會帶cookie,需要添加配置項

          fetch不支持abort,不支持超時控制,使用setTimeout及Promise.reject的實現的超時控制并不能阻止請求過程繼續在后臺運行,造成了流量的浪費

          fetch沒有辦法原生監測請求的進度,而XHR可以



          fetch的使用示例:



          window.fetch(url)

              .then(response => {

                  if (response.ok) {

                      //通過 response 原型上的 json 方法將 response.body 轉換為 JS 對象,再返回出去

                      return response.json();

                  }

              }

          ).then(result => {

              console.log(result);

          }).catch(error => {

              console.log(error);

          })

          1

          2

          3

          4

          5

          6

          7

          8

          9

          10

          11

          12

          需要注意以下幾點:

          1,用 response.ok判斷fetch請求是否成功

          2,服務端只返回了response對象,而真正的請求結果,即 response.body,則是一個 ReadableStream。fetch 將 response.body 設計成 ReadableStream 在請求大體積文件時變得非常有用。然而,在我們的日常使用中,還是短小的 JSON 片段更加常見。而為了兼容不常見的設計,我們不得不多一次 response.json() 的調用。不僅是調用變得麻煩,如果你的服務端采用了嚴格的 REST 風格,對于某些特殊情況并沒有返回 JSON 字符串,而是用了 HTTP 狀態碼(如:204 No Content),那么在調用 response.json() 時則會拋出異常。

          3,Response 限制了響應內容的重復讀取和轉換,response .json / response.text 方法只能使用一個并且只能使用一次,同時使用兩個,或使用兩次都會報如下錯誤:



          Uncaught (in promise) TypeError: Failed to execute 'json' on 'Response': body stream is locked

          1

          為什么不能使用兩次?

          因為數據流只能讀取一次,一旦讀取,數據流變空,再次讀取會報錯。

          ————————————————

          版權聲明:本文為CSDN博主「Sherry慈」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。

          原文鏈接:
          https://blog.csdn.net/weixin_41480546/article/details/102805864

          JS實現動態星空背景

          seo達人



          這里我截取的是一個圖片,實際上是會動的。廢話不多說,上代碼。

          HTML:



          <canvas id="canvas"></canvas>

          1

          CSS:



          /css reset /

          body,p,div,ol,ul,li,dl,dt,dd,h1,h2,h3,h4,h5,h6,form,input,iframe,nav {

              margin: 0;

              padding: 0;

          }

          html,body {

              width: 100%;

              height: 100%;

          }

          body {

              font: 14px Microsoft YaHei;

              -webkit-text-size-adjust:100%;

              -moz-user-select: none;

              -webkit-user-select: none;

              user-select: none;

              position: relative;

              background: #000;

          }


          canvas {

              width: 100%;

              height: 100%;

              display: block;

              opacity: .8;

          }





          // 音量大小,0.01-1





          //宇宙

          var canvas = document.getElementById('canvas'),

          ctx = canvas.getContext('2d'),

          w = canvas.width = window.innerWidth,

          h = canvas.height = window.innerHeight,



          hue = 217,

          stars = [],

          count = 0,

          maxStars = 1100;                //星星數量,默認1300

          var canvas2 = document.createElement('canvas'),

          ctx2 = canvas2.getContext('2d');

          canvas2.width = 100;

          canvas2.height = 100;

          var half = canvas2.width / 2,

          gradient2 = ctx2.createRadialGradient(half, half, 0, half, half, half);

          gradient2.addColorStop(0.025, '#CCC');

          gradient2.addColorStop(0.1, 'hsl(' + hue + ', 61%, 33%)');

          gradient2.addColorStop(0.25, 'hsl(' + hue + ', 64%, 6%)');

          gradient2.addColorStop(1, 'transparent');



          ctx2.fillStyle = gradient2;

          ctx2.beginPath();

          ctx2.arc(half, half, half, 0, Math.PI 2);

          ctx2.fill();



          // End cache

          function random(min, max) {

              if (arguments.length < 2) {

                  max = min;

                  min = 0;

              }



              if (min > max) {

                  var hold = max;

                  max = min;

                  min = hold;

              }



              return Math.floor(Math.random()
          (max - min + 1)) + min;

          }



          function maxOrbit(x, y) {

              var max = Math.max(x, y),

              diameter = Math.round(Math.sqrt(max max + max max));

              return diameter / 2;

              //星星移動范圍,值越大范圍越小,

          }



          var Star = function() {



              this.orbitRadius = random(maxOrbit(w, h));

              this.radius = random(60, this.orbitRadius) / 10;       //星星大小,值越大星星越小,默認8

              

              this.orbitX = w / 2;

              this.orbitY = h / 2;

              this.timePassed = random(0, maxStars);

              this.speed = random(this.orbitRadius) / 80000;        //星星移動速度,值越大越慢,默認5W

              

              this.alpha = random(2, 10) / 10;



              count++;

              stars[count] = this;

          }



          Star.prototype.draw = function() {

              var x = Math.sin(this.timePassed) this.orbitRadius + this.orbitX,

              y = Math.cos(this.timePassed)
          this.orbitRadius + this.orbitY,

              twinkle = random(10);



              if (twinkle === 1 && this.alpha > 0) {

                  this.alpha -= 0.05;

              } else if (twinkle === 2 && this.alpha < 1) {

                  this.alpha += 0.05;

              }



              ctx.globalAlpha = this.alpha;

              ctx.drawImage(canvas2, x - this.radius / 2, y - this.radius / 2, this.radius, this.radius);

              this.timePassed += this.speed;

          }



          for (var i = 0; i < maxStars; i++) {

              new Star();

          }



          function animation() {

              ctx.globalCompositeOperation = 'source-over';

              ctx.globalAlpha = 0.5;                                 //尾巴

              ctx.fillStyle = 'hsla(' + hue + ', 64%, 6%, 2)';

              ctx.fillRect(0, 0, w, h)



              ctx.globalCompositeOperation = 'lighter';

              for (var i = 1,

              l = stars.length; i < l; i++) {

                  stars[i].draw();

              };



              window.requestAnimationFrame(animation);

          }



          animation();

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

          點擊遮罩層的背景關閉遮罩層

          seo達人

          開發工具與關鍵技術:Adobe Dreamweaver CC

          作者:黃燦

          撰寫時間:2019.1.16



          在模仿華為官方網頁的練習當中我發現華為官網中有一個遮罩層是隨便點擊遮罩層的背景也能關閉掉遮罩層,但唯獨點擊內容區域不會關閉掉遮罩層。于是我開始模仿這個寫案例,連內容也一模一樣(因為這個練習就是要寫出和華為關一樣的效果或則比它更好的效果),一開始我是這樣子寫的(圖1)



          圖1



          class=Select_Region_bj 我給了一個灰色半透明的背景樣式,后來在Javascript中寫onclick事件無論這么寫,點擊內容區也是會關閉掉遮罩層。我百思不得其解到底怎么樣寫才能點擊內容區不會關閉遮罩層,后來下課期間我看見我同學他寫的帶能點擊內容區不會關閉遮罩層。我問他你是這么寫的,他告訴我:“把他們分離就可以的了?!蔽宜伎剂艘粫?,腦補:分離?怎么分離?補著補著補著就補出了背景和內容區分離。分離寫(圖2)

          圖2



          把背景層和內容區分開來寫,不要在背景層中包裹內容,這樣子點擊內容區就不會關閉掉遮罩層了!

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

          深入理解vue中的slot與slot-scope

          seo達人

          寫在前面

          vue中關于插槽的文檔說明很短,語言又寫的很凝練,再加上其和methods,data,computed等常用選項使用頻率、使用先后上的差別,這就有可能造成初次接觸插槽的開發者容易產生“算了吧,回頭再學,反正已經可以寫基礎組件了”,于是就關閉了vue說明文檔。

          實際上,插槽的概念很簡單,下面通過分三部分來講。這個部分也是按照vue說明文檔的順序來寫的。

          進入三部分之前,先讓還沒接觸過插槽的同學對什么是插槽有一個簡單的概念:插槽,也就是slot,是組件的一塊HTML模板,這塊模板顯示不顯示、以及怎樣顯示由父組件來決定。 實際上,一個slot最核心的兩個問題這里就點出來了,是顯示不顯示怎樣顯示

          由于插槽是一塊模板,所以,對于任何一個組件,從模板種類的角度來分,其實都可以分為非插槽模板插槽模板兩大類。
          非插槽模板指的是html模板,指的是‘div、span、ul、table’這些,非插槽模板的顯示與隱藏以及怎樣顯示由插件自身控制;插槽模板是slot,它是一個空殼子,因為它顯示與隱藏以及最后用什么樣的html模板顯示由父組件控制。但是插槽顯示的位置確由子組件自身決定,slot寫在組件template的哪塊,父組件傳過來的模板將來就顯示在哪塊。

          單個插槽 | 默認插槽 | 匿名插槽

          首先是單個插槽,單個插槽是vue的官方叫法,但是其實也可以叫它默認插槽,或者與具名插槽相對,我們可以叫它匿名插槽。因為它不用設置name屬性。

          單個插槽可以放置在組件的任意位置,但是就像它的名字一樣,一個組件中只能有一個該類插槽。相對應的,具名插槽就可以有很多個,只要名字(name屬性)不同就可以了。

          下面通過一個例子來展示。

          父組件:

          
          
          1. <template>
          2. <div class="father">
          3. <h3>這里是父組件</h3>
          4. <child>
          5. <div class="tmpl">
          6. <span>菜單1</span>
          7. <span>菜單2</span>
          8. <span>菜單3</span>
          9. <span>菜單4</span>
          10. <span>菜單5</span>
          11. <span>菜單6</span>
          12. </div>
          13. </child>
          14. </div>
          15. </template>

          子組件:

          
          
          1. <template>
          2. <div class="child">
          3. <h3>這里是子組件</h3>
          4. <slot></slot>
          5. </div>
          6. </template>

          在這個例子里,因為父組件在<child></child>里面寫了html模板,那么子組件的匿名插槽這塊模板就是下面這樣。也就是說,子組件的匿名插槽被使用了,是被下面這塊模板使用了。

          
          
          1. <div class="tmpl">
          2. <span>菜單1</span>
          3. <span>菜單2</span>
          4. <span>菜單3</span>
          5. <span>菜單4</span>
          6. <span>菜單5</span>
          7. <span>菜單6</span>
          8. </div>

          最終的渲染結果如圖所示:


          
          
          1. 注:所有demo都加了樣式,以方便觀察。其中,父組件以灰色背景填充,子組件都以淺藍色填充。

          具名插槽

          匿名插槽沒有name屬性,所以是匿名插槽,那么,插槽加了name屬性,就變成了具名插槽。具名插槽可以在一個組件中出現N次。出現在不同的位置。下面的例子,就是一個有兩個具名插槽單個插槽的組件,這三個插槽被父組件用同一套css樣式顯示了出來,不同的是內容上略有區別。

          父組件:

          
          
          1. <template>
          2. <div class="father">
          3. <h3>這里是父組件</h3>
          4. <child>
          5. <div class="tmpl" slot="up">
          6. <span>菜單1</span>
          7. <span>菜單2</span>
          8. <span>菜單3</span>
          9. <span>菜單4</span>
          10. <span>菜單5</span>
          11. <span>菜單6</span>
          12. </div>
          13. <div class="tmpl" slot="down">
          14. <span>菜單-1</span>
          15. <span>菜單-2</span>
          16. <span>菜單-3</span>
          17. <span>菜單-4</span>
          18. <span>菜單-5</span>
          19. <span>菜單-6</span>
          20. </div>
          21. <div class="tmpl">
          22. <span>菜單->1</span>
          23. <span>菜單->2</span>
          24. <span>菜單->3</span>
          25. <span>菜單->4</span>
          26. <span>菜單->5</span>
          27. <span>菜單->6</span>
          28. </div>
          29. </child>
          30. </div>
          31. </template>

          子組件:

          
          
          1. <template>
          2. <div class="child">
          3. // 具名插槽
          4. <slot name="up"></slot>
          5. <h3>這里是子組件</h3>
          6. // 具名插槽
          7. <slot name="down"></slot>
          8. // 匿名插槽
          9. <slot></slot>
          10. </div>
          11. </template>

          顯示結果如圖:


          可以看到,父組件通過html模板上的slot屬性關聯具名插槽。沒有slot屬性的html模板默認關聯匿名插槽。

          作用域插槽 | 帶數據的插槽

          最后,就是我們的作用域插槽。這個稍微難理解一點。官方叫它作用域插槽,實際上,對比前面兩種插槽,我們可以叫它帶數據的插槽。什么意思呢,就是前面兩種,都是在組件的template里面寫

          
          
          1. 匿名插槽
          2. <slot></slot>
          3. 具名插槽
          4. <slot name="up"></slot>

          但是作用域插槽要求,在slot上面綁定數據。也就是你得寫成大概下面這個樣子。

          
          
          1. <slot name="up" :data="data"></slot>
          2. export default {
          3. data: function(){
          4. return {
          5. data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
          6. }
          7. },
          8. }

          我們前面說了,插槽最后顯示不顯示是看父組件有沒有在child下面寫模板,像下面那樣。

          
          
          1. <child>
          2. html模板
          3. </child>

          寫了,插槽就總得在瀏覽器上顯示點東西,東西就是html該有的模樣,沒寫,插槽就是空殼子,啥都沒有。
          OK,我們說有html模板的情況,就是父組件會往子組件插模板的情況,那到底插一套什么樣的樣式呢,這由父組件的html+css共同決定,但是這套樣式里面的內容呢?

          正因為作用域插槽綁定了一套數據,父組件可以拿來用。于是,情況就變成了這樣:樣式父組件說了算,但內容可以顯示子組件插槽綁定的。

          我們再來對比,作用域插槽和單個插槽和具名插槽的區別,因為單個插槽和具名插槽不綁定數據,所以父組件是提供的模板要既包括樣式由包括內容的,上面的例子中,你看到的文字,“菜單1”,“菜單2”都是父組件自己提供的內容;而作用域插槽,父組件只需要提供一套樣式(在確實用作用域插槽綁定的數據的前提下)。

          下面的例子,你就能看到,父組件提供了三種樣式(分別是flex、ul、直接顯示),都沒有提供數據,數據使用的都是子組件插槽自己綁定的那個人名數組。

          父組件:

          
          
          1. <template>
          2. <div class="father">
          3. <h3>這里是父組件</h3>
          4. <!--第一次使用:用flex展示數據-->
          5. <child>
          6. <template slot-scope="user">
          7. <div class="tmpl">
          8. <span v-for="item in user.data">{{item}}</span>
          9. </div>
          10. </template>
          11. </child>
          12. <!--第二次使用:用列表展示數據-->
          13. <child>
          14. <template slot-scope="user">
          15. <ul>
          16. <li v-for="item in user.data">{{item}}</li>
          17. </ul>
          18. </template>
          19. </child>
          20. <!--第三次使用:直接顯示數據-->
          21. <child>
          22. <template slot-scope="user">
          23. {{user.data}}
          24. </template>
          25. </child>
          26. <!--第四次使用:不使用其提供的數據, 作用域插槽退變成匿名插槽-->
          27. <child>
          28. 我就是模板
          29. </child>
          30. </div>
          31. </template>

          子組件:

          
          
          1. <template>
          2. <div class="child">
          3. <h3>這里是子組件</h3>
          4. // 作用域插槽
          5. <slot :data="data"></slot>
          6. </div>
          7. </template>
          8. export default {
          9. data: function(){
          10. return {
          11. data: ['zhangsan','lisi','wanwu','zhaoliu','tianqi','xiaoba']
          12. }
          13. }
          14. }

          結果如圖所示:

          github

          以上三個demo就放在GitHub了,有需要的可以去取。使用非常方便,是基于vue-cli搭建工程。

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

          開發過程中積累的CSS樣式(持續更新)

          seo達人

          前言:平時寫頁面的時候有些樣式使用完發現沒過多久就忘記了,這篇文章主要是用來記錄開發過程中容易忘記的CSS樣式,與其總是去網上查,還不如一個一個記錄下來,雖然說之前的都沒有記錄,但是知識的累積不論什么時候開始做都不會晚的。



          首先 記錄幾個好用的插件網站:



          layDate日期與時間組件: https://www.layui.com/laydate/

          Vant移動端插件庫: https://youzan.github.io/vant/#/zh-CN/intro

          Element組件庫: https://element.eleme.cn/#/zh-CN/component/installation

          Vue.js框架: https://cn.vuejs.org/v2/guide/

          Bootstrap框架: https://v2.bootcss.com/index.html

          菜鳥教程官網: https://www.runoob.com/

          w3school官網: https://www.w3school.com.cn/

          下面是遇到的一些想累積的css樣式:(內容會隨時間累積的越來越多)



          1、一個 div 中的內容實現上下滑動效果(而不是超出body的高以后上下滑動):overflow:auto;

          簡單的描述:body 中的一個 div 內,如果設置了固定的 height,而內容的總 height 超出了 div 的高,則超出的部分就會被覆蓋,而想實現超出的部分變成滑動的效果而不被覆蓋,則用 overflow:auto; 實現。



          2、修改 前端框架封裝好的css樣式: border-radius: 20px!important;(注意使用英文的 ! 嘆號)

          簡單的描述:在開發過程中經常使用一些前端框架(bootstrap,vue.js,laydate,Vant等等),在使用link導入css文件以后,發現有些css是在標簽內使用內嵌的方式實現的,優先級最高,那么我們怎么修改呢?

          比如:css文件中的邊框弧度樣式為10px:border-radius: 10px;

          我們想改成20px,則在后面加上 !important 即可:border-radius: 20px!important;



          這篇文章主要是以后回頭復習或者忘記了的時候給我自己看的,但是如果恰好也幫助到了你,那是更加的有意義,在以后的開發過程中,該文章的內容一定會累積的越來越多

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

          JS--普通數字格式與會計金額格式之間的轉換

          seo達人

          普通數字轉會計金額格式(保留兩位小數)

          我們可以用數字的toLocaleString()方法將普通數字轉為會計金額格式,但是這種方式無法保留兩位小數(四舍五入),如果是整數或者小數長度只有一位的時候無法自動補0



          例如:





          思路:

          利用toLocaleString()以及toFixed()先對數字進行一個轉換得到最多保留了2位小數的金額,然后判斷數字是為整數還是帶有小數,如果帶有小數則進行切割,判斷小數長度為1時自動補0



          // 普通數字轉會計金額格式 第一種

              function toThousandsFormates(num) {

                  // 判斷傳進來的數字是否為非空數字

                 if (!isNaN(parseFloat(num))) {

                      var reg = /./g

                      var newNum = Number(Number(num).toFixed(2)).toLocaleString()

                      // 判斷轉換后的數字是否帶有小數

                      if (reg.test(newNum)) {

                          var numArr = newNum.split('.')

                          // 判斷小數點后數字長度為1,則自動補0

                          numArr[1] = numArr[1].length === 1 ? numArr[1] + '0' : numArr[1]

                          return numArr.join('.')

                      } else {

                          // 整數直接在后面補上0.00

                          return newNum + '.00'

                      }



                  } else {

                      return ''

                  }

              }

              console.log(toThousandsFormates('0')); // 0.00

              console.log(toThousandsFormates('')); // ''

              console.log(toThousandsFormates(966)); // 966.00

              console.log(toThousandsFormates(966.3)); // 966.30

              console.log(toThousandsFormates(9669228.55)); // 9,669,228.55

              console.log(toThousandsFormates(96566.56954)); // 96,566.57



          經過查閱資料后,發現toLocaleString()它里面自帶屬性可以檢查到最少保留了幾位小數,不夠自動補0,這樣我們上面的代碼其實可以更加簡單,如下:

          // 普通數字轉會計金額格式 第二種

          function toThousandsFormates2(num) {

              // 判斷傳進來的數字是否為非空數字

              if (!isNaN(parseFloat(num))) {

                  var newNum = Number(Number(num).toFixed(2)).toLocaleString('zh', { minimumFractionDigits: 2 })

                  return newNum



              } else {

                  return ''

              }

          }



          console.log(toThousandsFormates2('0')); // 0.00

          console.log(toThousandsFormates2('')); // ''

          console.log(toThousandsFormates2(966)); // 966.00

          console.log(toThousandsFormates2(966.3)); // 966.30

          console.log(toThousandsFormates2(9669228.55)); // 9,669,228.55

          console.log(toThousandsFormates2(96566.56954)); // 96,566.57



          // 結果一模一樣



          會計金額格式轉普通數字(利用正則)

          // 會計金額格式轉為普通數字

              function rMoney(num) {

                  return parseFloat(num.replace(/[^\d\.-]/g, ''))

              }

              console.log(rMoney('96,566.57')); // 96566.57

              console.log(rMoney('966.30')); // 966.3

              console.log(rMoney('9,669,228.55')); // 9669228.55

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

          日歷

          鏈接

          個人資料

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

          存檔

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