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

          首頁

          前端實現生成帶有樣式的excel表格 Node和瀏覽器讀寫Excel文件探究實踐

          seo達人

          最近碰到個需要自動生成表格的任務,作為前端的我,就想在 node 和瀏覽器中生成強大的表格,所以特此研究了很多關于表格的 npm 庫

          支持讀寫 Excel 的 node.js 模塊

          node-xlsx: 基于 Node.js 解析 excel 文件數據及生成 excel 文件,僅支持 xlsx 格式文件

          js-xlsx: 目前 Github 上 star 數量最多的處理 Excel 的庫,支持解析多種格式表格 XLSX / XLSM / XLSB / XLS / CSV,解析采用純 js 實現,寫入需要依賴 nodejs 或者 FileSaver.js 實現生成寫入 Excel,可以生成子表 Excel,功能強大,但上手難度稍大。不提供基礎設置 Excel 表格 api 例單元格寬度,文檔有些亂,不適合快速上手;普通版本不支持定義字體、顏色、背景色等,有這個功能需要的可以使用 pro 版,是要聯系客服收費的,害我照著 API 設置調試了好多次都失敗。好在樣式設置問題有一些教程,通過研究本人已解決,可設置寬度顏色等等,見根目錄本人修改的 xlsx.js

          xlsx-style 基于 xlsx 封裝的樣式庫,可以在 xlsx 的基礎上設置樣式。樣式不全,寬度都設置不了,好多年前作者就不維護了.寬度設置問題本人已解決了,見修改的 xlsx-style.js 文件

          exceljs 在使用此庫之前,本人已花費了很大的精力,用以上庫做好了表格,但是發現不能設置頁眉頁腳,添加圖片,打印選項設置等等,直到發現了這個庫,文檔齊全,功能強大,并且還免費.但是star較少,差一點就錯過了。本教程主要針對這個庫

          代碼庫地址

          https://github.com/lingxiaoyi/excel

          安裝

          npm install


          npm install -g nodemon


          調試使用,替代 node 命令,實現保存文件,node 自動重新啟動執行,必須全局安裝才能運行


          使用

          nodemon app.js


          js-xlsx 具體 api 使用方法請參考 main.js demo 使用,app.js 中修改為 require('./src/main.js');

          exceljs 具體 api 使用方法請參考 main-exceljs.js demo 使用,app.js 中修改為 require('./src/main-exceljs.js');

          因為每次生成完表格,每次都需要打開表格查看樣式,在 windows 電腦中,打開表格之后就鎖定不能生成新文件了,本來想著能導出一個 html 文件對應表格的樣式


          node 調試

          vscode 中打開調試右側設置編輯,將下方代碼復制進去,點 nodemon 啟動就可以進行 debug 調試了


          {

               "type": "node",

               "request": "launch",

               "name": "nodemon",

               "runtimeExecutable": "nodemon",

               "program": "${workspaceFolder}/app.js",

               "restart": true,

               "console": "integratedTerminal",

               "internalConsoleOptions": "neverOpen",

               "skipFiles": ["<node_internals>/**"]

             },

          webpack 目錄的作用

          每次生成完新表格,都需要重新打開表格查看樣式,在 windows 電腦中,打開表格之后就鎖定了,再次生成新表格就會報錯,文件已鎖定,不能寫入,對于想偷懶的我,能不能實現像 webpack 熱更新功能那種,修改樣式 js 頁面自動更新呢?


          wps 自帶另存 html 文件功能,但是沒有提供生成的 api ,網上也搜索不到對應的轉換功能,

          本來以為自己要實現一套表格轉 html 的功能。通過不斷嘗試,偶然間發現手機瀏覽器可以直接打開預覽 xlsx 文件,內心狂喜啊


          使用方法

          進入 webpack 目錄安裝依賴包,安裝好之后執行


          npm run dev


          啟動成功之后,會自動打開帶有 ip 地址的預覽地址,此時在電腦瀏覽器會自動下載 xlsx 文件,忽略不管,用手機直接打開此地址,就能看到 xlsx 表格的內容了,并且每次新修改內容和樣式,都會自動刷新頁面顯示新表格.


          小技巧

          谷歌瀏覽器插件:


          生成二維碼的插件生成二維碼方便手機掃描

          劃詞翻譯 用來翻譯一些看不懂的英文文檔

          browser 目錄

          瀏覽器中實現生成 xlsx 表格方法


          進入 browser 目錄安裝依賴包,安裝好之后執行


          npm run dev


          啟動成功之后,拖動根目錄 src 下的李四表格到頁面上的輸入框里,成功生成表格之后會生成一個下載鏈接地址,右鍵在新標簽頁打開鏈接,即會生成一個新的表格文件出來,完整 api 使用和 demo 文件請參考 index.js


          vue 和 react 用法可以參考此例子,如果有必要也可以此版本庫的例子


          一些概念

          在使用這個庫之前,先介紹庫中的一些概念。


          workbook 對象,指的是整份 Excel 文檔。我們在使用 js-xlsx 讀取 Excel 文檔之后就會獲得 workbook 對象。

          worksheet 對象,指的是 Excel 文檔中的表。我們知道一份 Excel 文檔中可以包含很多張表,而每張表對應的就是 worksheet 對象。

          cell 對象,指的就是 worksheet 中的單元格,一個單元格就是一個 cell 對象。

          xlsx 使用注意事項

          constXLSX = require('xlsx');

          let html = XLSX.utils.sheet_to_html(workbook.Sheets.Sheet1)

          生成 html 的用法,并且不會有任何樣式


          exceljs 使用注意

          讀取文件問題

          因為 exceljs 讀取文件不支持 sync 同步讀取,給的實例也是 await 例子.導致我讀取完遇到一個問題,就是老是生成不成功,最后發現必須要把所有邏輯全部放入函數中,像下方這樣


          (async function (params) {

           let res = await workbook.xlsx.readFile(`${__dirname}/趙六.xlsx`);

           //執行所有數據處理邏輯

           //執行寫的邏輯

           workbook.xlsx.writeFile(path.resolve(__dirname, '../webpack/test222.xlsx'));

          });

          所有邏輯全部要寫入這個函數中,這樣本來是可以的,但是出錯調試幾率較大,并且讀取到的數據龐大還需要額外處理,所以我讀取數據邏輯就用的 node-xlsx,十分簡單方便,如果你用的 exceljs 讀取文件數據出現問題,大概率是異步同步邏輯搞錯了,多加注意即可

          寬度設置

          列寬不知道是以什么為單位,反正不是像素(已測量),例子中是以厘米為單位再乘以 4.7 的結果設置的,4.7 是不斷測試的結果.

          快捷查看列寬的方法,打開 wps 表格,長按列與列字母間的豎線,就能看到列寬,取厘米的單位即可.見下圖




          前景色

          前景色設置必須右鍵單元格選擇設置單元格格式,然后選擇圖案樣式選擇顏色,就可以前景色填充

          worksheet.getCell('A2').fill = { type: 'pattern', pattern:'darkTrellis', fgColor:{argb:'FFFFFF00'}, bgColor:{argb:'FF0000FF'} };


          背景色

          worksheet.getCell('A2').fill = { type: "pattern", pattern: "solid", fgColor: { argb: next.bgColor }, }


          排版不一致的問題

          解決 Mac 下編輯 Microsoft Office Word 文檔與 Windows 排版不一致的問題,,不同的系統用 wps 打開相同的表格,打印預覽的時候,表格寬度顯示不一樣

          問題詳細說明地址


          我的解決辦法就是 mac 下顯示正常,按 mac 下的寬度來設置就可以了


          參考資料

          exceljs

          node-xlsx

          js-xlsx

          函數節流與函數防抖的區別

          seo達人

          函數節流與函數防抖是我們解決頻繁觸發DOM事件的兩種常用解決方案,但是經常傻傻分不清楚。。。這不,在項目中又用遇到了,在此處記錄一下



          函數防抖 debounce

          原理:將若干函數調用合成為一次,并在給定時間過去之后,或者連續事件完全觸發完成之后,調用一次(僅僅只會調用一次?。。。。。。。。?!)。



          舉個栗子:滾動scroll事件,不停滑動滾輪會連續觸發多次滾動事件,從而調用綁定的回調函數,我們希望當我們停止滾動的時,才觸發一次回調,這時可以使用函數防抖。



          原理性代碼及測試:



          // 給盒子較大的height,容易看到效果

          <style>

              * {

                  padding: 0;

                  margin: 0;

              }



              .box {

                  width: 800px;

                  height: 1200px;

              }

          </style>

          <body>

              <div class="container">

                  <div class="box" style="background: tomato"></div>

                  <div class="box" style="background: skyblue"></div>

                  <div class="box" style="background: red"></div>

                  <div class="box" style="background: yellow"></div>

              </div>

              <script>

                  window.onload = function() {

                      const decounce = function(fn, delay) {

                          let timer = null



                          return function() {

                              const context = this

                              let args = arguments

                              clearTimeout(timer) // 每次調用debounce函數都會將前一次的timer清空,確保只執行一次

                              timer = setTimeout(() => {

                                  fn.apply(context, args)

                              }, delay)

                          }

                      }



                      let num = 0



                      function scrollTap() {

                          num++

                          console.log(看看num吧 ${num})

                      }

                      // 此處的觸發時間間隔設置的很小

                      document.addEventListener('scroll', decounce(scrollTap, 500))

                      // document.addEventListener('scroll', scrollTap)

                  }

              </script>

          </body>



          此處的觸發時間間隔設置的很小,如果勻速不間斷的滾動,不斷觸發scroll事件,如果不用debounce處理,可以發現num改變了很多次,用了debounce函數防抖,num在一次上時間的滾動中只改變了一次。



          調用debouce使scrollTap防抖之后的結果:



          直接調用scrollTap的結果:





          補充:瀏覽器在處理setTimeout和setInterval時,有最小時間間隔。

          setTimeout的最短時間間隔是4毫秒;

          setInterval的最短間隔時間是10毫秒,也就是說,小于10毫秒的時間間隔會被調整到10毫秒。

          事實上,未優化時,scroll事件頻繁觸發的時間間隔也是這個最小時間間隔。

          也就是說,當我們在debounce函數中的間隔事件設置不恰當(小于這個最小時間間隔),會使debounce無效。



          函數節流 throttle

          原理:當達到了一定的時間間隔就會執行一次;可以理解為是縮減執行頻率



          舉個栗子:還是以scroll滾動事件來說吧,滾動事件是及其消耗瀏覽器性能的,不停觸發。以我在項目中碰到的問題,移動端通過scroll實現分頁,不斷滾動,我們不希望不斷發送請求,只有當達到某個條件,比如,距離手機窗口底部150px才發送一個請求,接下來就是展示新頁面的請求,不停滾動,如此反復;這個時候就得用到函數節流。



          原理性代碼及實現



          // 函數節流 throttle

          // 方法一:定時器實現

          const throttle = function(fn,delay) {

            let timer = null



            return function() {

              const context = this

              let args = arguments

              if(!timer) {

                timer = setTimeout(() => {

                  fn.apply(context,args) 

                  clearTimeout(timer) 

                },delay)

              }

            }

          }



          // 方法二:時間戳

          const throttle2 = function(fn, delay) {

            let preTime = Date.now()



            return function() {

                const context = this

                let args = arguments

                let doTime = Date.now()

                if (doTime - preTime >= delay) {

                    fn.apply(context, args)

                    preTime = Date.now()

                }

            }

          }



          需要注意的是定時器方法實現throttle方法和debounce方法的不同:



          在debounce中:在執行setTimeout函數之前總會將timer用setTimeout清除,取消延遲代碼塊,確保只執行一次

          在throttle中:只要timer存在就會執行setTimeout,在setTimeout內部每次清空這個timer,但是延遲代碼塊已經執行啦,確保一定頻率執行一次




          我們依舊可以在html頁面中進行測試scroll事件,html和css代碼同debounce,此處不贅述,運行結果是(可以說是一場漫長的滾輪滾動了):





          最后再來瞅瞅項目中封裝好的debounce和throttle函數,可以說是很優秀了,考慮的特別全面,希望自己以后封裝的函數也能考慮的這么全面吧,加油!



          /*

           
          空閑控制 返回函數連續調用時,空閑時間必須大于或等于 wait,func 才會執行

           

           
          @param  {function} func        傳入函數,最后一個參數是額外增加的this對象,.apply(this, args) 這種方式,this無法傳遞進函數

            @param  {number}   wait        表示時間窗口的間隔

           
          @param  {boolean}  immediate   設置為ture時,調用觸發于開始邊界而不是結束邊界

            @return {function}             返回客戶調用函數

           
          /

          const debounce = function(func, wait, immediate) {

              let timeout, args, context, timestamp, result;



              const later = function() {

                  // 據上一次觸發時間間隔

                  let last = Number(new Date()) - timestamp;



                  // 上次被包裝函數被調用時間間隔last小于設定時間間隔wait

                  if (last < wait && last > 0) {

                      timeout = setTimeout(later, wait - last);

                  } else {

                      timeout = null;

                      // 如果設定為immediate===true,因為開始邊界已經調用過了此處無需調用

                      if (!immediate) {

                          result = func.call(context, ...args, context);

                          if (!timeout) {

                              context = args = null;

                          }

                      }

                  }

              };



              return function(..._args) {

                  context = this;

                  args = _args;

                  timestamp = Number(new Date());

                  const callNow = immediate && !timeout;

                  // 如果延時不存在,重新設定延時

                  if (!timeout) {

                      timeout = setTimeout(later, wait);

                  }

                  if (callNow) {

                      result = func.call(context, ...args, context);

                      context = args = null;

                  }



                  return result;

              };

          };



          /*

           
          頻率控制 返回函數連續調用時,func 執行頻率限定為 次 / wait

           

           
          @param  {function}   func      傳入函數

            @param  {number}     wait      表示時間窗口的間隔

           
          @param  {object}     options   如果想忽略開始邊界上的調用,傳入{leading: false}。

                                           如果想忽略結尾邊界上的調用,傳入{trailing: false}

           
          @return {function}             返回客戶調用函數

           */

          const throttle = function(func, wait, options) {

              let context, args, result;

              let timeout = null;

              // 上次執行時間點

              let previous = 0;

              if (!options) options = {};

              // 延遲執行函數

              let later = function() {

                  // 若設定了開始邊界不執行選項,上次執行時間始終為0

                  previous = options.leading === false ? 0 : Number(new Date());

                  timeout = null;

                  result = func.apply(context, args);

                  if (!timeout) context = args = null;

              };

              return function(..._args) {

                  let now = Number(new Date());

                  // 首次執行時,如果設定了開始邊界不執行選項,將上次執行時間設定為當前時間。

                  if (!previous && options.leading === false) previous = now;

                  // 延遲執行時間間隔

                  let remaining = wait - (now - previous);

                  context = this;

                  args = _args;

                  // 延遲時間間隔remaining小于等于0,表示上次執行至此所間隔時間已經超過一個時間窗口

                  // remaining大于時間窗口wait,表示客戶端系統時間被調整過

                  if (remaining <= 0 || remaining > wait) {

                      clearTimeout(timeout);

                      timeout = null;

                      previous = now;

                      result = func.apply(context, args);

                      if (!timeout) context = args = null;

                      //如果延遲執行不存在,且沒有設定結尾邊界不執行選項

                  } else if (!timeout && options.trailing !== false) {

                      timeout = setTimeout(later, remaining);

                  }

                  return result;

              };

          };


          超簡單入門Vuex小示例

          seo達人

          寫在前面

          本文旨在通過一個簡單的例子,練習vuex的幾個常用方法,使初學者以最快的速度跑起來一個vue + vuex的示例。

          學習vuex需要你知道vue的一些基礎知識和用法。相信點開本文的同學都具備這個基礎。

          另外對vuex已經比較熟悉的大佬可以忽略本文。

          生成基于vue的項目

          基于vue-cli腳手架生成一個vue項目
          常用npm命令:

          npm i vue-vli -g vue --version vue init webpack 項目名 

          進入項目目錄,使用npm run dev先試著跑一下。

          一般不會出現問題,試跑成功后,就可以寫我們的vuex程序了。

          使用vue完成的示例

          使用vuex首先得安裝vuex,命令:

          npm i vuex --save

          介紹一下我們的超簡單Demo,一個父組件,一個子組件,父組件有一個數據,子組件有一個數據,想要將這兩個數據都放置到vuex的state中,然后父組件可以修改自己的和子組件的數據。子組件可以修改父組件和自己的數據。

          先放效果圖,初始化效果如下:

          如果想通過父組件觸發子組件的數據,就點“改變子組件文本”按鈕,點擊后效果如下:

          如果想通過子組件修改父組件的數據,就在子組件點擊“修改父組件文本”按鈕,點擊后效果如下:

          代碼文件介紹

          首先是Parent.vue組件

          <template> <div class="parent"> <h3>這里是父組件</h3> <button type="button" @click="clickHandler">修改自己文本</button> <button type="button" @click="clickHandler2">修改子組件文本</button> <div>Test: {{msg}}</div> <child></child> </div> </template> <script> import store from '../vuex' import Child from './Child.vue' export default { computed: {
                      msg(){ return store.state.testMsg;
                      }
                  }, methods:{
                      clickHandler(){
                          store.commit('changeTestMsg', '父組件修改自己后的文本')
                      },
                      clickHandler2(){
                          store.commit('changeChildText', '父組件修改子組件后的文本')
                      }
                  }, components:{ 'child': Child
                  },
                  store,
              } </script> <style scoped> .parent{ background-color: #00BBFF; height: 400px;
              } </style> 

          下面是Child.vue子組件

          <template> <div class="child"> <h3>這里是子組件</h3> <div>childText: {{msg}}</div> <button type="button" @click="clickHandler">修改父組件文本</button> <button type="button" @click="clickHandler2">修改自己文本</button> </div> </template> <script> import store from '../vuex' export default { name: "Child", computed:{
                      msg(){ return store.state.childText;
                      }
                  }, methods: {
                      clickHandler(){
                          store.commit("changeTestMsg", "子組件修改父組件后的文本");
                      },
                      clickHandler2(){
                          store.commit("changeChildText", "子組件修改自己后的文本");
                      }
                  },
                  store
              } </script> <style scoped> .child{ background-color: palegreen; border:1px solid black; height:200px; margin:10px;
              } </style> 

          最后是vuex的配置文件

           import Vue from 'vue' import Vuex from 'vuex';
          
          Vue.use(Vuex) const state = { testMsg: '原始文本', childText:"子組件原始文本" } const mutations = {
              changeTestMsg(state, str){
                  state.testMsg = str;
              },
              changeChildText(state, str){
                  state.childText = str;
              }
          
          } const store = new Vuex.Store({ state: state, mutations: mutations
          }) export default store;

          后記

          通過該vuex示例,了解vuex的常用配置及方法調用。希望對不怎么熟悉vuex的同學快速上手vuex項目有點幫助。

          因為沒太多東西,我自己也是剛接觸,本例就不往GitHub扔了,如果嘗試了本例,但是沒有跑起來的同學,可以一起交流下。

          移動端列表查詢最佳實踐

          seo達人

          無論是 pc 端還是移動端,無可避免都會涉及到列表查詢有關的操作,但對于這兩種不同的設備,其列表查詢的最佳處理方式也是完全不同。

          對于 pc 端列表查詢來說,前端通常是給與服務端當前需要獲取的數據量(如 pageCount,limit 等參數)以及所需要獲取數據的位置(如 pageSize,offset 等參數)作為查詢條件。然后服務端然后返回數據總數,以及當前數據,前端再結合這些數據顯示頁面總數等信息。這里我稱為相對位置取數。

          對于移動端而言,沒有pc 端那么大的空間展示以及操作,所以基本上都會采用下拉取數這種方案。

          那么我們在處理移動端列表查詢時候使用這種相對位置取數會有什么問題呢?

          相對位置取數存在的問題

          性能劣勢

          通過相對位置取數會具有性能問題,因為一旦使用 offset 信息來獲取數據,隨著頁數的增加,響應速度也會變的越來越慢。因為在數據庫層面,我們每次所獲取的數據都是“從頭開始第幾條”,每次我們都需要從第一條開始計算,計算后舍棄前面的數據,只取最后多條數據返回前端。

          當然了,對于相對位置取數來說,數據庫優化是必然的,這里我就不多做贅述了。對于前端開發來說,優秀的的查詢條件設計可以在一定方面解決此問題。

          數據顯示重復

          事實上,對于一個實際運行的項目而言,數據更新才是常態,如果數據更新的頻率很高或者你在當前頁停留的時間過久的話,會導致當前獲取的數據出現一定的偏差。

          例如:當你在獲取最開始的 20 條數據后,正準備獲取緊接著的后 20 條數據時,在這段時間內 ,發生了數據增加,此時移動端列表就可能會出現重復數據。雖然這個問題在 pc 端也存在,但是 pc 端只會展示當前頁的信息,這樣就避免了該問題所帶來的負面影響。

          結合列表 key 維持渲染正確

          我們在上面的問題中說明了,移動端下拉加載中使用相對位置查詢取數是有問題的。

          那么,如果當前不能迅速結合前后端進行修改 api 的情況下,當服務端傳遞過來的數據與用戶想要得的數據不一致,我們必須在前端進行處理,至少處理數據重復問題所帶來的負面影響。

          因為當前分頁請求時無狀態的。在分頁取到數據之后前端可以對取得的數據進行過濾,過濾掉當前頁面已經存在的 key(例如 id 等能夠確定的唯一鍵)。

          通過這種處理方式,我們至少可以保證當前用戶看到的數據不會出現重復。同時當列表數據可以編輯修改的時候,也不會出現因為 key 值相同而導致數據錯亂。

          通過絕對位置獲取數據

          如果不使用相對位置獲取數據,前端可以利用當前列表中的最后一條數據作為請求源參數。前端事先記錄最后一條數據的信息。例如當前的排序條件為創建時間,那么記錄最后一條數據的創建時間為主查詢條件(如果列表對應的數據不屬于個人,可能創建時間不能唯一決定當前數據位置,同時還需要添加 ID 等信息作為次要查詢條件)。

          當我們使用絕對位置獲取數據時候,雖然我們無法提供類似于從第 1 頁直接跳轉 100 頁的查詢請求,但對于下拉加載這種類型的請求,我們不必擔心性能以及數據重復顯示的問題。

          對于相對位置取數來說,前端可以根據返回數據的總數來判斷。但當使用絕對位置取數時,即使獲取數據總數,也無法判斷當前查詢是否存在后續數據。

          從服務器端實現的角度來說,當用戶想要得到 20 條數據時候,服務端如果僅僅只向數據庫請求 20 條數據,是無法得知是否有后續數據的。服務端可以嘗試獲取當前請求的數據條數 + 1, 如向數據庫請求 21 條數據,如果成功獲得 21 條數據,則說明至少存在著 1 條后續數據,這時候,我們就可以返回 20 條數據以及具有后續數據的信息。但如果我們請求 21 條數據卻僅僅只能獲取 20 條數據(及以下),則說明沒有后續數據。

          如可以通過 “hasMore” 字段來表示是否能夠繼續下拉加載的信息。

          { data: [], hasMore: true }

          結合 HATEOAS 設計優化

          事實上,前面我們已經解決了移動端處理列表查詢的問題。但是我們做的還不夠好,前端還需要結合排序條件來處理并提供請求參數,這個操作對于前端來說也是一種負擔。那么我們就聊一下 HATEOAS 。

          HATEOAS (Hypermedia As The Engine Of Application State, 超媒體即應用狀態引起) 這個概念最早出現在 Roy Fielding 的論文中。REST 設計級別如下所示:

          • REST LEVEL 0: 使用 HTTP 作為傳輸方式
          • REST LEVEL 1: 引入資源的概念(每一個資源都有對應的標識符和表達)
          • REST LEVEL 2: 引入 HTTP 動詞(GET 獲取資源/POST 創建資源/PUT 更新或者創建字樣/DELETE 刪除資源 等)
          • REST LEVEL 3: 引入 HATEOAS (在資源的表達中包含了鏈接信息。客戶端可以根據鏈接來發現可以執行的動作)

          HATEOAS 會在 API 返回的數據中添加下一步要執行的行為,要獲取的數據等 URI 的鏈接信息??蛻舳酥灰@取這些信息以及行為鏈接,就可以根據這些信息進行接下來的操作。

          對于當前的請求來說,服務端可以直接返回下一頁的信息,如

          { data: [], hasMore: true, nextPageParams: {}    
          }

          服務端如此傳遞數據,前端就不需要對其進行多余的請求處理,如果當前沒有修改之前的查詢以及排序條件,則只需要直接返回 “nextPageParams” 作為下一頁的查詢條件即可。

          這樣做的好處不但符合 REST LEVEL 3,同時也減輕了前端的心智模型。前端無需配置下一頁請求參數。只需要在最開始查詢的時候提供查詢條件即可。

          當然,如果前端已經實現了所有排序添加以及查詢條件由服務端提供,前端僅僅提供組件,那么該方案更能體現優勢。 前端是不需要知道當前業務究竟需要什么查詢條件,自然也不需要根據查詢條件來組織下一頁的條件。同時,該方案的輸入和輸出都由后端提供,當涉及到業務替換( 查詢條件,排序條件修改)時候,前端無需任何修改便可以直接替換和使用。

          其他注意事項

          一旦涉及到移動端請求,不可避免的會有網絡問題,當用戶在火車或者偏遠地區時候,一旦下拉就會涉及取數,但是當前數據沒有返回之前,用戶多次下拉可能會有多次取數請求,雖然前端可以結合 key 使得渲染不出錯,但是還是會在緩慢的網絡下請求多次,無疑雪上加霜。這時候我們需要增加條件變量 loading。

          偽代碼如下所示:

          // 查詢 function search(cond) {
            loading = true api.then(res => {
                loading = false }).catch(err => {
                loading = false })
          } // 獲取下一頁數據 function queryNextPage() { if (!nextPageParams) return if (!loading) return search(nextPageParams)
          }

          前端架構演進及主流UI

          前端達人

          文章目錄



            前端三要素

            HTML(結構):超文本標記語言(Hyper Text Markup Language),決定網頁的結構和內容
            CSS(表現):層疊樣式表(Cascading Style Sheets),設定網頁的表現樣式
            JavaScript(行為):是一種弱類型腳本語言,其源代碼不需經過編譯,而是由瀏覽器解釋運行, 用于控制網頁的行為
            HTML 稱為超文本標記語言,是一種標識性的語言。它通過一系列標簽組合,組成一個個不同結構的頁面!關于html標簽的學習可以去菜鳥教程學習,此處不再贅述!

            CSS層疊樣式表 也是一門標記語言,并不是編程語言,因此不可以自定義變量,不可以引用等,換句話說
            就是不具備任何語法支持,它主要缺陷如下:

            語法不夠強大,比如無法嵌套書寫,導致模塊化開發中需要書寫很多重復的選擇器;
            沒有變量和合理的樣式復用機制,使得邏輯上相關的屬性值必須以字面量的形式重復輸出,導致難 以維護;
            這就導致了我們在工作中無端增加了許多工作量。為了解決這個問題,前端開發人員會使用一種稱之為 【CSS 預處理器】 的工具,提供 CSS 缺失的樣式層復用機制、減少冗余代碼,提高樣式代碼的可維護 性。大大提高了前端在樣式上的開發效率。

            什么是CSS 預處理器呢?

            CSS 預處理器定義了一種新的語言,其基本思想是,用一種專門的編程語言,為 CSS 增加了一些編程的 特性,將 CSS 作為目標生成文件,然后開發者就只要使用這種語言進行 CSS 的編碼工作。轉化成通俗易 懂的話來說就是“用一種專門的編程語言,進行 Web 頁面樣式設計,再通過編譯器轉化為正常的 CSS 文 件,以供項目使用”。

            常用的 CSS 預處理器有哪些?

            SASS:基于 Ruby,通過服務端處理,功能強大。解析效率高。需要學習 Ruby 語言,上手難度高于 LESS。
            LESS:基于 NodeJS,通過客戶端處理,使用簡單。功能比 SASS 簡單,解析效率也低于 SASS,但在實際開發中足夠了,所以我們后臺人員如果需要的話,建議使用 LESS。
            JavaScript 一門弱類型腳本語言,其源代碼在發往客戶端運行之前不需經過編譯,而是將文本格式的字 符代碼發送給瀏覽器由瀏覽器解釋運行。

            Native 原生 JS 開發
            原生 JS 開發,也就是讓我們按照 【ECMAScript】 標準的開發方式,簡稱是 ES,特點是所有瀏覽器都支持。

            ES 標準已發布如下版本:

            ES3
            ES4(內部,未正式發布)
            ES5(全瀏覽器支持)
            ES6(常用,當前主流版本:webpack打包成為ES5支持!)
            ES7
            ES8
            ES9(草案階段)
            從 ES6 開始每年發布一個版本,以年份作為名稱,區別就是逐步增加新特性。

            TypeScript 微軟的標準
            TypeScript 是一種由微軟開發的自由和開源的編程語言。它是 JavaScript 的一個超集,而且本質上向這 個語言添加了可選的靜態類型和基于類的面向對象編程。由安德斯·海爾斯伯格(C#、Delphi、 TypeScript 之父;.NET 創立者)主導。

            JavaScript 框架

            1.jQuery庫

            大家最熟知的 JavaScript庫,優點是簡化了 DOM 操作,缺點是 DOM 操作太頻繁,影響前端性能;在 前端眼里使用它僅僅是為了兼容 IE6、7、8;

            2.Angular庫

            Google 收購的前端框架,由一群 Java 程序員開發,其特點是將后臺的 MVC 模式搬到了前端并增加了模 塊化開發的理念,與微軟合作,采用 TypeScript 語法開發;對后臺程序員友好,對前端程序員不太友 好;最大的缺點是版本迭代不合理(如:1代 -> 2代,除了名字,基本就是兩個東西;已推出了 Angular6)

            3.React

            Facebook 出品,一款高性能的 JS 前端框架;特點是提出了新概念 【虛擬 DOM】 用于減少真實 DOM 操作,在內存中模擬 DOM 操作,有效的提升了前端渲染效率;缺點是使用復雜,因為需要額外學習一 門 【JSX】 語言;

            4.Vue

            一款漸進式 JavaScript 框架,所謂漸進式就是逐步實現新特性的意思,如實現模塊化開發、路由、狀態 管理等新特性。

            其特點是綜合了 Angular(模塊化) 和 React(虛擬 DOM) 的優點;

            5.Axios

            前端通信框架;因為 Vue 的邊界很明確,就是為了處理 DOM,所以并不具備通信能力,此時就需要額 外使用一個通信框架與服務器交互;當然也可以直接選擇使用 jQuery 提供的 A JAX 通信功能;

            JavaScript 構建工具

            Babel:JS 編譯工具,主要用于瀏覽器不支持的 ES 新特性,比如用于編譯 TypeScript
            WebPack:模塊打包器,主要作用是打包、壓縮、合并及按序加載

            NodeJs


            Node.js 是一個基于 Chrome V8 引擎的 JavaScript 運行環境,說白了就是運行在服務端的JavaScript;

            前端人員為了方便開發也需要掌握一定的后端技術,但我們 Java 后臺人員知道后臺知識體系極其龐大復 雜,所以為了方便前端人員開發后臺應用,就出現了 NodeJS 這樣的技術。NodeJS 的作者已經聲稱放棄 NodeJS(說是架構做的不好再加上笨重的node_modules,可能讓作者不爽了吧),開始開發全新架構的 什么是Deno?跟Node.js有何區別?

            既然是后臺技術,那肯定也需要框架和項目管理工具,NodeJS 框架及項目管理工具如下:

            Express: NodeJS 框架
            Koa: Express 簡化版
            NPM: 項目綜合管理工具,類似于 Maven
            YARN: NPM 的替代方案,類似于 Maven 和 Gradle 的關系

            常用UI框架


            Ant-Design:阿里巴巴出品,基于 React 的 UI 框架
            ElementUI、MintUi、iview、ic、:餓了么出品,基于 Vue 的 UI 框架
            Bootstrap:Twitter 推出的一個用于前端開發的開源工具包
            AmazeUI:又叫“妹子 UI”,一款 HTML5 跨屏前端框架
            Layui:輕量級框架(Layer)
            Ant-Design

            ant.design是基于react開發的一個解放ui和前端的工具,它提供了一致的設計方便我們快速開發和減少不必要的設計與代碼,很多實用react框架的開發者都已經在使用ant.design了,且其在github上的star數也早已上萬,足見其火熱程度。

            ant.design的目的也在于提高用戶、開發者等多方的體驗與幸福感。

            ant.design設計很精妙,vue的iview就是模仿ant.design來實現的

            官網地址:https://ant.design/index-cn
            github地址:https://github.com/ant-design/ant-design/
            ElementUi

            ElementUi是餓了么前端開源維護的VueUI組件庫,組件齊全基本涵蓋后臺所需的所有組件,文檔講解詳細,例子也很豐富。主要用于開發PC端的頁面,是一個質量比較高的VueUI組件庫!

            官網地址:http://element-cn.eleme.io/#/zh-CN
            github地址:https://github.com/ElementUI/element-starter
            vue-element-admin:https://github.com/PanJiaChen/vue-element-admin
            MintUi

            MintUi是由餓了么前端團隊推出的一個基于 Vue.js的移動端組件庫,組件比較單一,功能簡單易上手!

            官網地址:https://mint-ui.github.io/#!/zh-cn
            github地址:https://github.com/ElemeFE/mint-ui
            iview

            iview 是一個強大的基于 Vue 的 UI 庫,有很多實用的基礎組件比 elementui 的組件更豐富,主要服務于 PC 界面的中后臺產品。使用單文件的 Vue 組件化開發模式 基于 npm + webpack + babel 開發,支持 ES2015 高質量、功能豐富 友好的 API ,自由靈活地使用空間。

            官網地址:https://www.iviewui.com/
            github地址:https://github.com/TalkingData/iview-weapp
            iview-admin: https://github.com/iview/iview-admin
            備注:屬于前端主流框架,選型時可考慮使用,主要特點是移動端支持較多

            ICE

            飛冰是阿里巴巴團隊基于 React/Angular/Vue 的中后臺應用解決方案,在阿里巴巴內部,已經有 270 多 個來自幾乎所有 BU 的項目在使用。飛冰包含了一條從設計端到開發端的完整鏈路,幫助用戶快速搭建 屬于自己的中后臺應用。

            官網地址:https://alibaba.github.io/ice
            github地址 :https://github.com/alibaba/ice
            備注:主要組件還是以 React 為主,對 Vue 的支持還不太完善, 目前尚處于觀望階段

            VantUI

            Vant UI 是有贊前端團隊基于有贊統一的規范實現的 Vue 組件庫,提供了一整套 UI 基礎組件和業務組 件。通過 Vant,可以快速搭建出風格統一的頁面,提升開發效率。

            官網地址: https://youzan.github.io/vant/#/zh-CN/intro
            github地址: https://github.com/youzan/vant
            AtUi

            at-ui是一款基于Vue 2.x的前端UI組件庫,主要用于快速開發PC網站產品。 它提供了一套npm + webpack + babel 前端開發工作流程,CSS樣式獨立,即使采用不同的框架實現都能保持統一的 UI風格。

            官網地址:https://at-ui.github.io/at-ui/#/zh
            github地址: https://github.com/at-ui/at-ui
            CubeUI
            cube-ui 是滴滴團隊開發的基于 Vue.js 實現的精致移動端組件庫。支持按需引入和后編譯,輕量靈活; 擴展性強,可以方便地基于現有組件實現二次開發.

            官網地址:https://didi.github.io/cube-ui/#/zh-CN
            github地址:https://github.com/didi/cube-ui/
            Flutter

            Flutter 是谷歌的移動端 UI 框架,可在極短的時間內構建 Android 和 iOS 上高質量的原生級應用。 Flutter 可與現有代碼一起工作, 它被世界各地的開發者和組織使用, 并且 Flutter 是免費和開源的。

            官網地址:https://flutter.dev/docs
            github地址:https://github.com/flutter/flutter
            備注:Google 出品,主要特點是快速構建原生 APP 應用程序,如做混合應用該框架為必選框架

            Ionic

            Ionic 既是一個 CSS 框架也是一個 Javascript UI 庫,Ionic 是目前最有潛力的一款 HTML5 手機應用開發 框架。通過 SASS 構建應用程序,它提供了很多 UI 組件來幫助開發者開發強大的應用。它使用 JavaScript MVVM 框架和 AngularJS/Vue 來增強應用。提供數據的雙向綁定,使用它成為 Web 和移動 開發者的共同選擇。

            官網地址:https://ionicframework.com/
            github地址:https://github.com/ionic-team/ionic
            mpvue

            mpvue 是美團開發的一個使用 Vue.js 開發小程序的前端框架,目前支持 微信小程序、百度智能小程 序,頭條小程序 和 支付寶小程序。 框架基于 Vue.js,修改了的運行時框架 runtime 和代碼編譯器 compiler 實現,使其可運行在小程序環境中,從而為小程序開發引入了 Vue.js 開發體驗。

            官網地址:http://mpvue.com/
            github地址:https://github.com/Meituan-Dianping/mpvue
            備注:完備的 Vue 開發體驗,并且支持多平臺的小程序開發,推薦使用

            WeUi

            WeUI 是一套同微信原生視覺體驗一致的基礎樣式庫,由微信官方設計團隊為微信內網頁和微信小程序 量身設計,令用戶的使用感知更加統一。包含 button、cell、dialog、toast、article、icon 等各式元 素。

            官網地址:https://weui.io/
            github地址:https://github.com/weui/weui.git

            前后端分離的演進

            為了降低開發的復雜度,以后端為出發點,比如:Struts、SpringMVC 等框架的使用,就是后端的 MVC 時代;

            以 SpringMVC 流程為例:


            1.發起請求到前端控制器(DispatcherServlet)
            2.前端控制器請求HandlerMapping查找 Handler (可以根據xml配置、注解進行查找)
            3.處理器映射器HandlerMapping向前端控制器返回Handler,HandlerMapping會把請求映射為HandlerExecutionChain對象(包含一個Handler處理器(頁面控制器)對象,多個HandlerInterceptor攔截器對象),通過這種策略模式,很容易添加新的映射策略
            4.前端控制器調用處理器適配器去執行Handler
            5.處理器適配器HandlerAdapter將會根據適配的結果去執行Handler
            6.Handler執行完成給適配器返回ModelAndView
            7.處理器適配器向前端控制器返回ModelAndView (ModelAndView是springmvc框架的一個底層對象,包括 Model和view)
            8.前端控制器請求視圖解析器去進行視圖解析 (根據邏輯視圖名解析成真正的視圖(jsp)),通過這種策略很容易更換其他視圖技術,只需要更改視圖解析器即可
            9.視圖解析器向前端控制器返回View
            10.前端控制器進行視圖渲染 (視圖渲染將模型數據(在ModelAndView對象中)填充到request域)
            11.前端控制器向用戶響應結果
            優點:

            MVC 是一個非常好的協作模式,能夠有效降低代碼的耦合度,從架構上能夠讓開發者明白代碼應該寫在 哪里。為了讓 View 更純粹,還可以使用 Thymeleaf、Freemarker 等模板引擎,使模板里無法寫入 Java 代碼,讓前后端分工更加清晰。單體應用!

            缺點:

            前端開發重度依賴開發環境,開發效率低,這種架構下,前后端協作有兩種模式:

            1、第一種是前端寫 DEMO,寫好后,讓后端去套模板。好處是 DEMO 可以本地開發,很。不足是 還需要后端套模板,有可能套錯,套完后還需要前端確定,來回溝通調整的成本比較大;

            2、另一種協作模式是前端負責瀏覽器端的所有開發和服務器端的 View 層模板開發。好處是 UI 相關的 代碼都是前端去寫就好,后端不用太關注,不足就是前端開發重度綁定后端環境,環境成為影響前端開 發效率的重要因素。

            前后端職責糾纏不清:模板引擎功能強大,依舊可以通過拿到的上下文變量來實現各種業務邏輯。但這樣只要前端弱勢一點,往往就會被后端要求在模板層寫出不少業務代碼。還有一個很大的灰色地帶是,頁面路由等功能本應該是前端最關注的,但卻是由后端來實現。

            ajax 的時代

            時間回到 2005 年 AJAX (Asynchronous JavaScript And XML,異步 JavaScript 和 XML,老技術新 用法) 被正式提出并開始使用 CDN 作為靜態資源存儲,于是出現了 JavaScript 王者歸來(在這之前 JS 都是用來在網頁上貼狗皮膏藥廣告的)的 SPA(Single Page Application)單頁面應用時代。
            優點:
            這種模式下,前后端的分工非常清晰,前后端的關鍵協作點是 A JAX 接口。看起來是如此美妙,但回過 頭來看看的話,這與 JSP 時代區別不大。復雜度從服務端的 JSP 里移到了瀏覽器的 JavaScript,瀏覽器 端變得很復雜。類似 Spring MVC,這個時代開始出現瀏覽器端的分層架構:

            [外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fP8yZYUq-1587440620216)()]
            缺點:

            前后端接口的約定: 如果后端的接口一塌糊涂,如果后端的業務模型不夠穩定,那么前端開發會很 痛苦;不少團隊也有類似嘗試,通過接口規則、接口平臺等方式來做。有了和后端一起沉淀的 接口 規則,還可以用來模擬數據,使得前后端可以在約定接口后實現并行開發。
            前端開發的復雜度控制: SPA 應用大多以功能交互型為主,JavaScript 代碼過十萬行很正常。大量 JS 代碼的組織,與 View 層的綁定等,都不是容易的事情
            前端為主的 MV* 時代

            此處的 MV* 模式如下:

            MVC(同步通信為主):Model、View、Controller
            MVP(異步通信為主):Model、View、Presenter
            MVVM(異步通信為主):Model、View、ViewModel
            為了降低前端開發復雜度,涌現了大量的前端框架,比如: AngularJS 、 React 、Vue.js 、 EmberJS 等,這些框架總的原則是先按類型分層,比如 Templates、Controllers、Models,然后再在層內做切分,




            優點:

            前后端職責很清晰: 前端工作在瀏覽器端,后端工作在服務端。清晰的分工,可以讓開發并行,測 試數據的模擬不難,前端可以本地開發。后端則可以專注于業務邏輯的處理,輸出 RESTful等接 口。
            前端開發的復雜度可控: 前端代碼很重,但合理的分層,讓前端代碼能各司其職。這一塊蠻有意思 的,簡單如模板特性的選擇,就有很多很多講究。并非越強大越好,限制什么,留下哪些自由,代 碼應該如何組織,所有這一切設計,得花一本書的厚度去說明。
            -部署相對獨立: 可以快速改進產品體驗
            缺點:

            代碼不能復用。比如后端依舊需要對數據做各種校驗,校驗邏輯無法復用瀏覽器端的代碼。如果可 以復用,那么后端的數據校驗可以相對簡單化。
            全異步,對 SEO 不利。往往還需要服務端做同步渲染的降級方案。 性能并非最佳,特別是移動互聯網環境下。
            SPA 不能滿足所有需求,依舊存在大量多頁面應用。URL Design 需要后端配合,前端無法完全掌控。
            NodeJS 帶來的全棧時代

            前端為主的 MV* 模式解決了很多很多問題,但如上所述,依舊存在不少不足之處。隨著 NodeJS 的興 起,JavaScript 開始有能力運行在服務端。這意味著可以有一種新的研發模式:
            ————————————————
            版權聲明:本文為CSDN博主「叁有三分之一」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
            原文鏈接:https://blog.csdn.net/iME_cho/article/details/105654633


          【CSS基礎學習】行內元素,塊級元素,行內塊級元素

          前端達人

          文章目錄

            • 元素的顯示方式和轉換


            • 元素的顯示方式和轉換

              塊級元素

              塊級元素(inline):
              塊級元素可以包含行內元素和其它塊級元素,且占據父元素的整個空間,可以設置 width 和 height 屬性,瀏覽器通常會在塊級元素前后另起一個新行。
              常見塊級元素:

              header,form,ul,ol,table,article,div,hr,aside,figure,canvas,video,audio,footer
              特點:

              塊級元素會獨占一行
              高度,行高,外邊距和內邊距都可以單獨設置
              寬度默認是容器的100%
              可以容納內聯元素和其他的塊級元素
              例如:





              <!DOCTYPE html>
              <html lang="en">
              <head>
                  <meta charset="UTF-8">
                  <meta name="viewport" content="width=device-width, initial-scale=1.0">
                  <title>Document</title>
                  <style>
                      div{
                          width: 150px;
                          height: 150px;
                          background-color: cadetblue;
                      }
                  </style>
              </head>
              <body>
                  <div>塊級元素1</div>
                  <div>塊級元素2</div>
              </body>
              </html>
              



               

              分析:
              塊級元素的高和寬可以被修改,而且塊級元素會在一個塊級元素之后另起一行。

              行級元素
              行級元素(block):
              一般情況下,行內元素只能包含內容或者其它行內元素,寬度和長度依據內容而定,不可以設置,可以和其它元素和平共處于一行。
              常見行級元素:
              a,b,strong,span,img,label,button,input,select,textarea
              特點:

              和相鄰的行內元素在一行上
              高度和寬度無效,但是水平方向上的padding和margin可以設置,垂直方向上的無效
              默認的寬度就是它本身的寬度
              行內元素只能容納純文本或者是其他的行內元素(a標簽除外)
              例如:

              <!DOCTYPE html>
              <html lang="en">
              <head>
                  <meta charset="UTF-8">
                  <meta name="viewport" content="width=device-width, initial-scale=1.0">
                  <title>Document</title>
                  <style>
                      span{
                          width: 150px;
                          height: 150px;
                          font-size: 40px;
                          background-color: cadetblue;
                      }
                  </style>
              </head>
              <body>
                  <span>行級元素1</span>
                  <span>行級元素2</span>
              </body>
              </html>
              


              分析:
              對他的高和寬進行修改,但是沒有發生改變,對他的字體大小進行修改卻發生了整體大小的改變,所以得出結論行級元素的寬高是與內容有關的,且不可修改高寬的屬性,只能對內容修改。

              行內塊級元素
              行內塊級元素(inline-block):
              他包含了行級元素與塊級元素的特點,在同一行顯示,可以設置元素寬度和高度,可以將塊級元素和行級元素轉化為行內塊級元素。他不屬于基本的元素,是通過修改獲得的。
              特點:

              和其他行內或行內塊級元素元素放置在同一行上
              元素的高度、寬度、行高以及頂和底邊距都可設置
              舉例:
              <!DOCTYPE html>
              <html lang="en">
              <head>
                  <meta charset="UTF-8">
                  <meta name="viewport" content="width=device-width, initial-scale=1.0">
                  <title>Document</title>
                  <style>
                      span{
                          width: 150px;
                          height: 150px;
                          font-size: 20px;
                          background-color: cadetblue;
                          display: inline-block;
                      }
                  </style>
              </head>
              <body>
                  <span>以前我是行級元素,</span>
                  <span>現在我只想做行內塊級元素。</span>
              </body>
              </html>
              


              分析:
              他可以進行修改寬高,也屬于同一行,包含著行級元素和塊級元素的特點,他就是行!內!塊!級!元!素!

              顯示方式之間的轉化
              想要轉成什么顯示方式 格式
              塊級元素 display:inline;
              行級元素 display: block;
              行內塊級元素 display: inline-block;
              這些直接在元素里面添加就可以了,就會轉換成相對應的格式。
              舉例:


              <!DOCTYPE html>
              <html lang="en">
              <head>
                  <meta charset="UTF-8">
                  <meta name="viewport" content="width=device-width, initial-scale=1.0">
                  <title>Document</title>
                  <style>
                      div{
                          width: 150px;
                          height: 150px;
                          font-size: 30px;
                          background-color: cadetblue;
                          display: inline;
                      }
                  </style>
              </head>
              <body>
                  <div>我以前是塊級元素,</div>
                  <div>現在我是行級元素!</div>
              </body>
              </html>
              






              分析:
              在VSC中,修改寬高的代碼已經出現了波浪線,證明他是錯誤的,所以現在的div已經變成了行級元素。






              ————————————————
              版權聲明:本文為CSDN博主「董小宇」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
              原文鏈接:https://blog.csdn.net/lolly1023/article/details/105715892



          帶你快速了解VSCode的10個特性,極大提高開發效率

          前端達人

          其實VSCode編輯器本身自帶了一個功能(Interactive Editor Playground :可以讓你快速了解VSCode的特性,并且是可以交互的),



          但很可惜它的內容是全英文的(將VSCode設置為中文也沒用哦~),



          我將每一部分截圖下來,并為你說明關鍵內容,教你學會使用 Interactive Editor Playground



          還有一些顯而易見的特性,我不會再用文字敘述一遍(它們都是潛移默化的)

          在下文中會涉及到大量快捷鍵的介紹,如果看不懂快捷鍵請自行百度

          鼠標 = 文本光標 = 光標

          本文成于2020年4月22日,隨著VSCode的版本更迭,此部分內容可能會略有差異(小更改不影響觀看,有較大影響的更新請在評論區告之,我會及時更新的)



          打開VSCode > Help > Interactive Playground

          點擊查看原圖

          你將會打開 Interactive Editor Playground 頁面

          互動式編輯游樂場

          點擊查看原圖

          VS代碼中的核心編輯器包含許多特性。此頁高亮顯示了10個特性,每個特性介紹中都提供了代碼行供你編輯

          接下來的10行內容(你可以理解為目錄,對應10個特性)

          多光標編輯(Multi-Cursor Editing)- 選擇一塊區域,選擇所有匹配項,添加其余光標等
          智能感應(intelliSense)- 獲取代碼和外部模塊的代碼幫助和參數建議
          行操作(Line Actions )- 快速移動行以重新排序代碼
          重命名重構(Rename Refactoring)- 快速重命名代碼庫中的符號(比如變量名、函數名)
          格式化(Formatting)- 使用內置文檔和選擇格式使代碼看起來很棒
          代碼折疊(Code Folding) - 通過折疊其他代碼區域,關注代碼中最相關的部分
          錯誤和警告(Errors and Warnings)- 寫代碼時請參閱錯誤和警告
          片段(Snippets)- 花更少的時間輸入片段
          Emmet - 只需要敲一行代碼就能生成你想要的完整HTML結構等(極大方便前端開發)
          JavaScript Type Checking- 使用零配置的TypeScript對JavaScript文件執行類型檢查。
          Multi-Cursor Editing

          點擊查看原圖

          使用多光標編輯可以同時編輯文檔的多個部分,極大地提高了工作效率

          框式選擇
          鍵盤同時按下 Shift + DownArrow(下鍵)、Shift + RightArrow(右鍵)、Shift + UpArrow(上鍵)、Shift + LeftArrow(左鍵) 的任意組合可選擇文本塊
          也可以用鼠標選擇文本時按 Shift + Alt 鍵
          或使用鼠標中鍵拖動選擇(可用性很高)
          添加光標
          按 Ctrl + Alt + UpArrow 在行上方添加新光標
          或按 Ctrl + Alt + DownArrow 在行下方添加新光標
          您也可以使用鼠標和 Alt + Click 在任何地方添加光標(可用性很高)
          在所有出現的字符串上創建光標
          選擇字符串的一個實例,例如我用鼠標選中所有background,然后按 Ctrl + Shift + L,文本中所有的background都將被選中(可用性很高)
          IntelliSense

          點擊查看原圖

          Visual Studio Code 預裝了強大的JavaScript和TypeScript智能感知。

          在代碼示例中,將文本光標放在錯誤下劃線的上面,會自動調用IntelliSense


          這只是智能提示的冰山一角,還有懸停在函數名上可以看到參數及其注釋(如果有)等等,它會潛移默化的帶給你極大幫助

          其他語言在安裝對應插件后,會附帶對應語言的IntelliSense

          Line Actions

          點擊查看原圖

          分別使用 Shift + Alt + DownArrow 或 Shift + Alt + UpArrow 復制光標所在行并將其插入當前光標位置的上方或下方
          分別使用 Alt + UpArrow 和 Alt + DownArrow 向上或向下移動選定行(可用性很高)
          用 Ctrl + Shift + K 刪除整行(可用性很高)
          通過按 Ctrl + / 來注釋掉光標所在行、切換注釋(可用性很高)
          Rename Refactoring

          點擊查看原圖

          重命名符號(如函數名或變量名)

          1. 將光標選中符號,按F2鍵
          2. 或者 選中該符號,鼠標右鍵 > Rename Symbol

          重命名操作將在項目中的所有文件中發生可用性很高

          Formatting

          點擊查看原圖

          代碼如果沒有良好的編寫格式,閱讀起來是一個折磨

          Formatting可以解決編寫格式問題:無論你的代碼的格式寫的有多么糟糕,它可以將代碼格式化為閱讀性良好的格式

          格式化整個文檔 Shift + Alt + F (可用性很高)
          格式化當前行 Ctrl + K Ctrl + F(即先按Ctrl,再按K,最后按F)
          鼠標右鍵 > Format Document (格式化整個文檔)
          將格式化操作設置為自動化(保存時自動格式化整個文檔):Ctrl + , 輸入 editor.formatOnSave

          點擊查看原圖

          Code Folding

          點擊查看原圖

          鼠標操作,自己嘗試一下,秒懂

          快捷鍵:

          • 折疊 Ctrl + Shift + [
          • 展開 Ctrl + Shift + ]

          折疊代碼段是基于基于縮進

          Errors and Warning

          點擊查看原圖

          錯誤和警告將在你出現錯誤時,高亮該代碼行

          在代碼示例中可以看到許多語法錯誤(如果沒有,請你隨便修改它,讓它出現錯誤)

          按F8鍵可以按順序在錯誤之間導航,并查看詳細的錯誤消息(可用性很高)

          Snippets

          通過使用代碼片段,可以大大加快編輯速度

          在代碼編輯區,你可以嘗試輸入try并從建議列表中選擇try catch,

          然后按Tab鍵或者Enter,創建try->catch塊

          你的光標將放在文本error上,以便編輯。如果存在多個參數,請按Tab鍵跳轉到該參數。

          Emmet

          Emmet將代碼片段的概念提升到了一個全新的層次(前端開發的大寶貝)

          你可以鍵入類似Css的可動態解析表達式,并根據在abrevision中鍵入的內容生成輸出

          比如說:

          然后Enter

          JavaScript Type Checking

          點擊查看原圖



          ————————————————
          版權聲明:本文為CSDN博主「索兒呀」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
          原文鏈接:https://blog.csdn.net/Zhangguohao666/article/details/105676173

          規范git commit的提交記錄

          seo達人

          隨著項目體積的增加,參與到項目中的同學越來越多,每個人都有自己的打 git log 的習慣:

          • 格式 1: add: 添加...
          • 格式 2: [add]: 添加...
          • 格式 3: Add 添加...

          為了形成統一的規范,達成共識,從而降低協作開發成本,需要對 git commit 記錄進行規范。

          規范 git commit 記錄

          規范 git commit 記錄,需要做兩件事情:

          • 通過交互式命令行,自動生成符合指定規范的 commit 記錄
          • 提交記錄后,在 git hooks 中進行 commit 記錄格式檢查
          問:既然已經交互式生成了規范記錄,為什么需要在 hooks 進行檢查?

          交互式生成 commit 記錄,需要用戶調用自定義的 npm scripts,例如npm run commit。但還是可以直接調用原生 git 命令 git commit 來提交記錄。而檢查是在正式提交前進行的,因此不符合要求的記錄不會生效,需要重新 commit。

          調研:交互式 commit log 規范方案

          前期調研結果,關于 commit 提示有兩種做法:

          1. 直接使用 commitizen 中常用的 adapter
          2. 根據團隊的需要,自定義 adapter

          方法 1 的優缺點:

          優點 1: 直接安裝對應的 adapter 即可

          優點 2: 無開發成本

          缺點 1: 無法定制,不一定滿足團隊需要

          方法 2 的優缺點:

          優點 1: 可定制,滿足開發需求

          優點 2: 單獨成庫,發布 tnpm,作為技術建設

          缺點 1: 需要單獨一個倉庫(但開發成本不高)

          代碼實現

          在實際工作中,發現方法 1 中的常用規范,足夠覆蓋團隊日常開發場景。所以,選擇了方法 1.

          step1: 安裝 npm 包

          npm i --save-dev commitizen cz-conventional-changelog @commitlint/cli @commitlint/config-conventional husky

          添加 package.json 的配置:

          "scripts": { "commit": "git-cz" }, "husky": { "hooks": { "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" }
          }, "config": { "commitizen": { "path": "./node_modules/cz-conventional-changelog" }
          }

          在項目根目錄下創建commitlint.config.js

          module.exports = { extends: ["@commitlint/config-conventional"]
          };

          使用方法:不再使用git commit -m ...,而是調用npm run commit。

          <img src="https://tva1.sinaimg.cn/large/006tNbRwly1gbjcfr3xb5j30cw00tjrd.jpg" style="width: 100% !important;"/>

          使用scss開發小程序(各種小程序平臺通用)

          seo達人

          微信小程序的wxss、阿里旗下淘寶、支付寶小程序的acss等等語法很類似原生css,但是在web開發里用慣了動態css語言,再寫回原生css很不習慣,尤其是父子樣式的嵌套寫法非常繁瑣。

          因此,我希望能有一個自動化構建方案,能夠簡單地將scss轉換成小程序的樣式語言。

          方案1

          以前寫微信小程序的依賴庫時用過,使用gulp編譯,將源碼和編譯后的代碼分別放到src和dist兩個目錄。gulp會處理src下面的所有文件,將其中的scss轉換成css,并將其他所有文件原封不動挪到dist下相應位置。

          這里就不詳細說了,代碼參考Wux。

          方案2

          非常簡單直接,使用Webstorm/IDEAFile Watchers功能實時轉換。

          安裝Ruby和sass

          確保命令行輸入sass -v能出現版本號,安裝過程略。

          安裝File Watchers

          到插件市場上搜索并安裝(已安裝則跳過)

          1.png

          添加scss的轉換腳本

          現在安裝完插件打開項目會自動彈出scss轉css的向導,方便了很多。但還需要做一些修改,配置如下:

          2.png

          首先要將生成文件的后綴名改掉,比如這里我的淘寶小程序就得是acss。

          其次,將Arguments改為:

          $FileName$:$FileNameWithoutExtension$.acss --no-cache --sourcemap=none --default-encoding utf-8 --style expanded

          如果不加--no-cache,scss文件同目錄下會出現一個.sass-cache目錄。

          如果不加--sourcemap=none, scss文件同目錄下會出現一個.map文件。

          如果不加--default-encoding utf-8, scss文件如果有中文注釋轉換就會報錯。

          style可不加,這里用的是無縮進和壓縮的風格,反正小程序打包發布時還會壓,這里保持可讀性。

          現在這個scss轉換是單獨作用于項目的,如果新建一個小程序項目,就需要重新添加(不建議設置成global,容易誤傷)。

          注意到File Watchers列表的右側操作欄下方有導入導出按鈕,可以將現在配好的設置導出保存,將來新建項目時只要導入一下就行了。


          之后還有一個問題,如果我手動將編譯后的css(即wxss或者acss,下略)文件刪除,scss文件不改動的話,就不會重新編譯出css文件。
          或者萬一監聽失效或者不夠及時,css還有可能是舊的。
          所以還需要一個命令,用來將整個目錄下的scss文件統一轉換,確保沒有遺漏和保持代碼。

          不過我看了半天sasssass-convert的文檔,沒有找到一個可用的寫法,能讓命令行遍歷指定目錄下的所有scss文件,將其轉換成css放到源文件所在目錄,并且將后綴名改為wxss或者acss。

          所以遍歷這個行為只能交給nodejs來實現,代碼如下:

          創建編譯腳本build/scss-convert.js

          var path = require("path") var fs = require("fs") const { exec } = require('child_process') const basePath = path.resolve(__dirname, '../') function mapDir(dir, callback, finish) {
            fs.readdir(dir, function(err, files) { if (err) { console.error(err) return }
              files.forEach((filename, index) => { let pathname = path.join(dir, filename)
                fs.stat(pathname, (err, stats) => { // 讀取文件信息 if (err) { console.log('獲取文件stats失敗') return } if (stats.isDirectory()) {
                    mapDir(pathname, callback, finish)
                  } else if (stats.isFile()) { if (!['.scss'].includes(path.extname(pathname))) { return }
                    callback(pathname)
                  }
                }) if (index === files.length - 1) {
                  finish && finish()
                }
              })
            })
          }
          
          mapDir(
            basePath, function (file) { const newFileWithoutExt = path.basename(file, '.scss') if (newFileWithoutExt.startsWith('_')) { return // 按照scss規則,下劃線開頭的文件不會生成css } // exec可以讓nodejs執行外部命令 exec(`sass --no-cache --sourcemap=none --default-encoding utf-8 --style expanded ${file}:${newFileWithoutExt}.acss`, { cwd: path.dirname(file) // 不寫這個會導致生成的文件出現在根目錄 }, (err, stdout, stderr) => { if (err) { console.log(err) return } console.log(`stdout: ${stdout}`)
              })
            }, function() { // console.log('xxx文件目錄遍歷完了') }
          )

          package.json里添加一條script:

           "scripts": { "scss": "node build/scss-convert",
            },

          ES6數據的解構賦值使用及應用

          前端達人


          定義


          ES6 允許按照一定模式,從數組和對象中提取值,對變量進行賦值,這被稱為解構(Destructuring)



          本質上,這種寫法屬于“模式匹配”,只要等號兩邊的模式相同,左邊的變量就會被賦予對應的值

          如果解構不成功,變量的值就等于undefined

          解構賦值的規則是,只要等號右邊的值不是對象或數組,就先將其轉為對象。由于undefined和null無法轉為對象,所以對它們進行解構賦值,都會報錯、



          解構賦值的用途:

          交換變量的值

          例如:let x=1,y=2;[x,y] = [y,x]



          從函數返回多個值

          函數只能返回一個值,如果要返回多個值,只能將它們放在數組或對象里返回。有了解構賦值,取出這些值就非常方便



          函數參數的定義

          解構賦值可以方便地將一組參數與變量名對應起來



          提取 JSON 數據,很多接口數據只需要其中某部分

          例如aa.axios.get(res=>{let {data:result}=res;}),則res.data.result = result了



          函數參數的默認值

          指定參數的默認值,就避免了在函數體內部再寫var foo = config.foo || ‘default foo’;這樣的語句



          遍歷 Map 結構

          Map 結構原生支持 Iterator 接口,配合變量的解構賦值,獲取鍵名和鍵值就非常方便



          輸入模塊的指定方法

          加載模塊時,往往需要指定輸入哪些方法。解構賦值使得輸入語句非常清晰。* const { SourceMapConsumer, SourceNode } = require(“source-map”);


          1、數組的解構賦值


          左右兩側數據解構須得吻合,或者等號左邊的模式,只匹配一部分的等號右邊的數組(屬于不完全解構)



          特殊情況使用…擴展運算符,無值是空數組



          左右兩邊等式的性質要相同,等號的右邊不是數組(或者嚴格地說,不是可遍歷的結構),那么將會報錯,只要某種數據結構具有 Iterator



          接口,都可以采用數組形式的解構賦值,例如Set結構



          解構賦值允許指定默認值,當一個數組成員嚴格等于undefined,默認值才會生效,否則取賦值的值;如果默認值是一個表達式,那么這個表達式是惰性求值的,即只有在用到的時候,才會求值;默認值可以引用解構賦值的其他變量,但該變量必須已經聲明



          // 數組的解構賦值
           let [a,b] = [1,2];
           console.log([a,b],a);//[1, 2] 1
           let [aa] = [11,22];
           console.log(aa)//11
           let [aaa,bbb] = [111];
           console.log(aaa,bbb)//111 undefined
           let [head, ...tail] = [1, 2, 3, 4];
           console.log(head,tail)//1,[2,3,4]
           let [x, y, ...z] = ['a'];
           console.log(x,y,z)//a undefined []
           // 等號右邊不是數組會報錯
           // let [ab] = 121;
           // conosle.log(ab)//TypeError: 121 is not iterable
           // let [abc] = {}
           // conosle.log(abc)//TypeError: {} is not iterable
           // 默認值賦值
           let [zz = 1] = [undefined];
           console.log(zz)//1
           let [zzz = 1] = [null];
           console.log(zzz)//null
           let [foo = true] = [];
           console.log(foo)// true
           let [xxx, yyy = 'b'] = ['a'];
           console.log(xxx,yyy)//a,b
           let [xxxx, yyyy = 'b'] = ['a', undefined]; 
           console.log(xxxx,yyyy)//a,b
           function f() {
             console.log('aaa');
           }
           let [xx = f()] = [1];
           console.log(xx)//1
           let [qq=ww,ww=11] = [23,44];
           console.log(qq,ww)//23,44,因為ww申明比qq晚所以是undefined;
          

          2、對象的解構賦值
          對象的解構賦值的內部機制,是先找到同名屬性,然后再賦給對應的變量。真正被賦值的是后者,而不是前者

          數組是按照位置區分,對象則是按照鍵名區分的,同樣的解構失敗則為undefine
          可將已有方法對象解構賦值
          嵌套賦值,注意是變量是否被賦值是模式還是鍵值
          對象的解構賦值可以取到繼承的屬性
          如果要將一個已經聲明的變量用于解構賦值,必須非常小心
          let xx; // {xx} = {xx: 1}這樣會報錯,

          解構賦值允許等號左邊的模式之中,不放置任何變量名。因此,可以寫出非常古怪的賦值表達式
          ({} = [true, false]);//可執行

          由于數組本質是特殊的對象,因此可以對數組進行對象屬性的解構

          objFuc(){
                      // 對象解構賦值
                      let {b,a} = {a:1}
                      console.log(a,b)//1 undefined
                      // 已有對象解構賦值
                      let { sin, cos } = Math;//將Math對象的對數、正弦、余弦三個方法,賦值到對應的變量上
                      console.log(sin);//log() { [native code] }
                      const { log } = console;
                      log('hello') // hello
                      // 
                      let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
                      console.log(baz);//aaa
                      // 嵌套賦值
                      let obj = {
                        p: [
                          'Hello',
                          { y: 'World' }
                        ]
                      };
                      let { p,p:[x, { y }] } = obj;
                      console.log(x,y,p)//Hello World p: ['Hello',{ y: 'World' }]
                      //繼承賦值
                      const obj1 = {};
                      const obj2 = { foo: 'bar' };
                      Object.setPrototypeOf(obj1, obj2);//obj1繼承obj2
                      const { foo } = obj1;
                      console.log(foo) // "bar"
                      // 默認值
                      // 錯誤的寫法
                      let xx;
                      // {xx} = {xx: 1};// SyntaxError: syntax error,Uncaught SyntaxError: Unexpected token '='
                      ({xx} = {xx: 1});//正確寫法
                      console.log(xx)
                      // 古怪的,等式左邊可為空
                      // ({} = [true, false]);
                      // 對象可解構數組
                      let arr = [1, 2, 3];
                      let {0 : first, [arr.length - 1] : last} = arr;
                      console.log(first,last)//1 3
                  },
          


          3、字符串的解構賦值

          • 字符串賦值
          • 類似數組的對象都有一個length屬性,因此還可以對這個屬性解構賦值
          strFuc(){
                      // str:'yan_yan'
                      let [a,b,c,d,e,f,g] = this.str;
                      console.log(a,b,c,d,e,f,g)//y a n _ y a n
                      // 對數組屬性解構賦值
                      let {length} = this.str;
                      console.log(length)//7
                  },
          

              

          4、數值和布爾值的解構賦值

          • 解構賦值時,如果等號右邊是數值和布爾值,則會先轉為對象
          • 解構賦值的規則是,只要等號右邊的值不是對象或數組,就先將其轉為對象。由于undefined和null無法轉為對象,所以對它們進行解構賦值,都會報錯
          
          
          let {toString: s} = 123;
          console.log(s === Number.prototype.toString,s)//true ? toString() { [native code] }
          let {toString: ss} = true;
          console.log(ss === Boolean.prototype.toString,ss)// true ? toString() { [native code] }
          // 右側必須是數組或對象,undefined和null無法轉為對象,所以對它們進行解構賦值,都會報錯
          // let { prop: x } = undefined; // TypeError
          // let { prop: y } = null; // TypeError
          

          
          
              

          5、函數參數的解構賦值

          • 也可使用默認值,注意默認值是指實參的默認值而不是形參的默認值
          // 函數的解構賦值可使用默認值,注意默認值是指實參的默認值而不是形參的默認值
                      function move({x=1, y=1}={}) {
                        return [x, y];
                      }
                      function move1({x, y} = { x: 0, y: 0 }) {
                        return [x, y];
                      }
                      function move2({x, y=1} = { x: 0, y: 0 }) {
                        return [x, y];
                      }
                      console.log(move({x: 3, y: 8})); // [3, 8]
                      console.log(move({x: 3})); // [3, 1]
                      console.log(move({})); // [1, 1]
                      console.log(move()); // [1,1]
                      console.log(move1({x: 3, y: 8})); // [3, 8]
                      console.log(move1({x: 3})); // [3, 1]
                      console.log(move1({})); // [undefined, 1]
                      console.log(move1()); // [0,0]
                      console.log(move2({x: 3, y: 8})); // [3, 8]
                      console.log(move2({x: 3})); // [3, 1]
                      console.log(move2({})); // [undefined, 1]
                      console.log(move2()); // [0,0]
          
          
          
          6、圓括號問題
          解構賦值雖然很方便,但是解析起來并不容易。對于編譯器來說,一個式子到底是模式,還是表達式,沒有辦法從一開始就知道,必須解析到(或解析不到)等號才能知道。
          由此帶來的問題是,如果模式中出現圓括號怎么處理。ES6 的規則是,只要有可能導致解構的歧義,就不得使用圓括號。
          可以使用圓括號的情況只有一種:賦值語句的非模式部分,可以使用圓括號
          總結:
          不管是哪一類的解構賦值,等式右邊的數據必須是對象形式(數組也是一種對象形式)
          ————————————————
          版權聲明:本文為CSDN博主「Yan_an_n」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
          原文鏈接:https://blog.csdn.net/weixin_44258964/article/details/105643553
          

          日歷

          鏈接

          個人資料

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

          存檔

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