2019-10 前端技術(shù)匯總

2019/10/31 周四

#HTML注釋的重要性

當看別人代碼時會有大用,

<!-- 每個功能模塊前必須加注釋 -->
...

<!-- 如果涉及隱藏的必須加end_其他可不加end_start -->
...
<!-- 如果涉及隱藏的必須加end_其他可不加end_end -->

#2019/10/30 周三

#svn拉取代碼

# checkout svn,注意如果密碼錯誤,會不提示重新輸入,如果403forbidden,就是沒權(quán)限
svn checkout http://倉庫地址 --username=用戶名

#如果mac沒有裝xcode,怎么安裝svn

最簡單的方法:安裝idea或webstorm等工具,在里面chenckout svn項目,會提示安裝,按照提示來即可。

#2019/10/28 周一

#nginx默認超時時間為60s

需要注意,前端就算超時設置為2分,但如果前端代碼部署到了nginx上,也會導致1分鐘超時

location / {
  root d:/test/;
  fastcgi_connect_timeout 600; # set timeout
  fastcgi_send_timeout 600; 
  fastcgi_read_timeout 600;
}

#常用的組件函數(shù)整理

  • 發(fā)布訂閱模式代碼
  • 文件大小默認為B,轉(zhuǎn)為合適的函數(shù)
  • 當前時間獲取函數(shù)

#JS到底是解釋型語言還是編譯型語言

Is JavaScript really interpreted or compiled language ? https://segmentfault.com/a/1190000013126460

Js是一種解釋型語言,令人困惑的地方:

  • —般解釋型語言是逐行解釋執(zhí)行的,為什么JS會有変曩提升(hoisting)的能力?
  • 執(zhí)行JS時會用到JIT, JIT(just in time compilers 及時編譯)會做代碼優(yōu)化(同時也會創(chuàng)建代碼的編譯版本),解釋型語言無法做到這些

#變量提升問題

在函數(shù)作用域內(nèi)的任何變量聲明都會被提升到頂部,且值為undefined,JS處理聲明語句的過程:

  • 一旦v8引擎進入一個執(zhí)行具體代碼的執(zhí)行上下文(函數(shù)),會對代碼進行詞法分析或分詞(lexing and tokenizing the code), 會將代碼切分為原子性的令牌(atomic token) , 比 如foo = 10
  • 在分析完當前作用域后,它會將翻譯后的版本解析為AST(抽象語法樹)
  • 每次遇到聲明都會將其發(fā)送到作用域,并創(chuàng)建綁定,每次聲明都會為變量分配內(nèi)存,只是分配內(nèi)存,并不會通過修改源代碼來將變最聲明語句提升,在JS中分配內(nèi)存,意味著將變量默認設置為undefined
  • 在這之后,引擎每次遇到賦值或者取值,都會通過作用域(scope)查找綁定。如果當前作用域中沒有找到,就接著向上級作用域中查找,直到找到為止
  • 接著引擎生成CPU可執(zhí)行的機器碼
  • 最后,代碼執(zhí)行完畢

#JIT是什么

JS start out slow, but then got faster thanks to something colled the JIT, but how does the JiT work ? 通俗一點說:瀏覽器在解釋執(zhí)行JS時,如果遇到某些語句多次執(zhí)行,會將對應的語句編譯,并存儲。下次再執(zhí)行相同的語句時,不用再重新編譯,而是直接執(zhí)行之前存儲的該語句編譯的版本。當然里面不止這么簡單,還有很多優(yōu)化, 詳情參考: A crash course in just-in-time (JIT) compilers

#總結(jié)

  • JS需要有JS引擎解析才能執(zhí)行。這是解釋型語需要的,編譯型語言程序你能直接運行。
  • 變量提升只是JS解釋器處理事情的方式導致的,
  • JIT 是唯一一點可以對JS是否是解釋型語言提出疑問的理由。但JIT不是完整的編譯器,它僅在執(zhí)行前編譯,且JIT只是Mozilla 和 Google開發(fā)人員為了提升瀏覽器性能才引入的,JS或TC39從沒有強制要求使用JIT, 綜上:JS是解釋型語言或混合型語言(編譯型型和解釋型的混合),而不是編譯型語畝。

#2019/10/26 周六

#原生JS實現(xiàn)遮罩動畫

只需引入一個JS,即可載入該動畫,demo地址: https://github.com/zuoxiaobai/fedemo/tree/master/src/DebugDemo/%E9%81%AE%E7%BD%A9%E5%8A%A8%E7%94%BB%E6%95%88%E6%9E%9C

#2019/10/24 周四

#element percentage大于100

element UI報錯 custom validator check failed for prop "percentage",進度大于100或出錯

#2019/10/23 周三

#node res大文件字符串時內(nèi)存溢出

想把buffer數(shù)據(jù)轉(zhuǎn)為stirng,設置為json格式傳到前端,但如文件過大,直接就崩了。

#2019/10/18 周五

#骨架屏研究

<head>
  <style>
    .fast-loading {
      height: 20px;
      margin: 10px 0;
      width: 200px;
      background-color: rgb(245, 245, 245);
      background-image: repeating-linear-gradient(90deg, #eee, #f5f5f5 100%);

      animation-name: fastLoading;
      animation-timing-function: linear;
      animation-duration: 1s;
      animation-iteration-count: infinite;
    }
    @keyframes fastLoading {
      from {
        background-position: 0 0;
      }
      to {
        background-position: 100px 0;
      }
    }
    .w100 { width: 100% }
    .w80 { width: 80% }
    .w60 { width: 60% }
    .w40 { width: 50% }
    .w30 { width: 30% }
  </style>
</head>
<body>
  <div style="width: 50%;margin: 50px auto;">
    <div class="fast-loading"></div>
    <div class="fast-loading w40"></div>
    <div class="fast-loading w80"></div>
    <div class="fast-loading w60"></div>
    <div class="fast-loading w30"></div>
    <div class="fast-loading w30"></div>
    <div class="fast-loading w50"></div>
    <div class="fast-loading w60"></div>
  </div>
</body>

#下載文件帶進度顯示

  • 本地搭建node服務,模擬download接口
// index.js   
// 運行:在控制臺 node index.js
const http = require("http");
const fs = require("fs");

const app = http.createServer((req, res) => {
  const { method, url } = req;
  if (method === "GET" && url === "/api/download") {        
    fs.readFile("./file.pdf", (err, data) => {
        // 這里以pdf為例子
        res.setHeader("Content-Type", "application/pdf");
        const fileName = encodeURI('中文')
        res.setHeader('Content-Disposition' ,`attachment; filename="${fileName}.pdf"`)
        res.end(data);
    });
  }
})
app.listen(3000)

  • 從后端接收文件數(shù)據(jù)時,進度顯示
<!-- 導出按鈕 -->
<div class="title-right">
  <a href="javascript:void(0)" 
    :class="{ 'disabled-a': isShowProgress }" 
    @click="exportExecl">
    全部導出
  </a>
</div>

<!-- 顯示下載進度組件封裝 -->
<download-progress
  :progressEvent="progressEvent"
  :isShowProgress="isShowProgress"
  :cancelDownload="handleWhenPorgresss('end')"
></download-progress>

<script>
import DownloadProgress from './DownloadProgress'
import axios from 'axios'

export default {
  components: { DownloadProgress },
  data() {
    return {
      progressEvent: {}, // 下載進度
      isShowProgress: false, // 是否顯示progress面板, disabled導出按鈕
      axiosCancelTokenSource: '', // axios取消請求
    }
  },

  methods: {
    onDonloadProgress(progressEvent) {
      cosnole.log(progressEvent)
      this.progressEvent = progressEvent
    },

    async exportExecl() {
      if (this.isShowProgess) {
        console.log('導出中,點擊無效')
        return
      }

      try {
        this.handleWhenProgress('start')

        let axiosConfig = {
          onDonloadProgress: this.onDownloadProgess.bind(this),
          cancelToken: this.axiosCancelTokenSource.token,
          timeout: 120000
        }
        let data = await xxx.getFileData(null, axiosConfig)
        console.log(data) 
        // blobdata,在axios配置中 responseType: 'blob' 就會返回Blob類型數(shù)據(jù)
        // 就是是json格式數(shù)據(jù),也會被轉(zhuǎn)Blob,TODO 當為JSON數(shù)據(jù)時特殊處理

        let fileType = "文件的MIME類型"

        if (data.type !=== fileType) {
          throw new Error("服務器返回數(shù)據(jù)類型異常")
        }

        this.handleWhenProgress('end')

        // 下載
        this.downloadFile(data, fileType, '文件名')
      } catch(e) {
        console.log('導出發(fā)生了異常', e)
        axios.isCancel(e) ? console.log('請求已取消') : this.$message.error(e.message)
        this.handleWhenProgress('end')
      }
    },

    hanldeWhenProgress(state) {
      if (state === 'start') {
        this.showProgress = true

        // 創(chuàng)建axios cancelToken
        this.axiosCanelTokenSource = axios.CancelToken.source() 
      } else {
        // 取消axios請求
        this.axiosCancelTokenSource.cancal('請求取消')

        // 初始化
        Object.assign(this, {
          isShowProgress: false,
          progress: {}
        })
      }
    }
  }
}
</script>

<style lang="less“>
  .title-right {
    a {
      color: rgb(36, 156, 211);
      text-decoration: none;
      &:hover {
        text-decoration: underline;
      }
    }
    .disabled-a {
      color: #888;
      &:hover {
        cursor: wait;
        text-decoration: none;
      }
    }
  }
</style>

  • 文件數(shù)據(jù)接收完成后,使用axios配合Vue下載文件
// data 后端返回的文件數(shù)據(jù)
function downloadFile(data, fileType, fileName) {
  // window.open(dataUrl)

  // fileType 文件的MIME類型
  // 參考: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Complete_list_of_MIME_types
  const blobData = new Blob([data], {
    type: fileType 
  })
  console.log(blobData) // 檢查數(shù)據(jù)是否正常

  //如果是IE,特殊處理,防止IE下提提示 "拒絕訪問"
  if (window.navigator.msSaveBlob) {
    try {
      window.navigator.msSaveBlob(blobData, fileName, + '.xlsx')
    } catch(e) {
      console.log('msSaveBlob異常', e)
    }
    return
  }

  // 創(chuàng)建下載鏈接,并觸發(fā)下載
  // https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/a#瀏覽器兼容性
  // <a> download attribute not support IE, iOS safari
  const dataUrl = window.URL.createObjectUrl(blobData)
  const downloadElement = document.createElement('a')
  downloadElement.href = dataUrl
  downloadElement.download = fileName // download文件名

  // 觸發(fā)點擊,下載
  document.body.appendChild(downloadElement)
  documentElement.click()

  // 移除輔助下載DOM及對象URL
  document.body.removeChild(downloadElement)
  window.URL.revokeObjectURL(dataUrl)
}

#2019/10/17 周四

#純前端實現(xiàn)execl文件導出

js-xlsx,github: https://github.com/SheetJS/js-xlsx

#eslint禁止在return中使用賦值

為什么會有這個限制?

function doSomething() {
  return foo = bar + 2
} 

官方的解釋是:對于上面的代碼,很難說明return的意圖

  • 該函數(shù)返回的結(jié)果是bar + 2 為什么要賦值給foo
  • 目的還可能是比較運算符,如 ==

存在歧義,因此最好不要在return語句中使用賦值操作, 解決辦法

  • 鼠標移動到錯誤的位置,知道出現(xiàn)快速修復的按鈕,Disabled no-return-assgin for this line,就會添加異常注釋,// eslint-disabled-next-line on-return-assign
  • 為了增強代碼可讀性有些自動修復去掉的括號可以加上,在配合上面的注釋即可讓eslint忽略

#2019/10/16 周三

#/deep/ 樣式

深度選擇器,Vue單文件組件中scope樣式,對子組件會不生效。如果想讓某些樣式在子組件里面生效,可以使用/deep/

<style lang="less" scoped>
/deep/ .el-checkbox {
  min-width: 180px;
  margin-bottom: 4px;
}  
</style>

#2019/10/15 周二

#滾動條消失的問題

和高度設置有關(guān),如果,注意用 min-height: calc(100vh - top高度)

#遍歷對象優(yōu)雅寫法

let obj = {
  a: 1,
  b: 2
}
Object.keys(obj).forEach(key => {
  cosnole.log(key, obj[key])
})

#2019/10/12 周六

##ffffff 與 #fff 的區(qū)別

3位是6位的縮寫,比如#ccc就是#cccccc的縮寫。并不是所有的都可以縮寫,必須符合一定的格式。注意:與移動端原生交互時,顏色不要使用縮寫,安卓可能會顯示異常。

// 縮寫都是以每兩位為縮寫的單位
// #abc  => #aabbcc
// #1D2  => #11DD22 

#eslint保存時自動fix

vscode默認的autofix只能fix .js的文件,無法fix .vue的文件,加入下面的配置即可

// config
{
  "edit.formatOnSave": false,   // 取消自帶fix,使用eslint自動保存fix
  "eslint.autoFixOnSave": true, // 每次保存的時候?qū)⒋a按eslint格式進行修復
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    {
      "language": "vue",
      "autoFix": true
    },
    "html"
  ]
}

#全局修改el菜單樣式不影響其他

.vue單文件組件style元素加上scope后,當前頁面修改el-tree的默認樣式無效需要去掉scope,將樣式暴露到全局,但對全局可能有影響,解決方法是最外層使用特殊的class包裹

<style lang="less">
  .root-menu-left {
    /* el樣式修改 */  
  }
</style>

#axios請求攔截

  • 請求攔截 axios.interceptors.request.use(resolve func, reject func)
  • 響應攔截 axios.interceptors.response.use(resolve func, reject func)
  • 執(zhí)行順序
      1. 先執(zhí)行請求攔截(特意在攔截中加了一個阻塞5s的await)
      1. 向后端發(fā)送請求
      1. 觸發(fā)響應攔截(這里也可能存在等待時間)
      1. 最后才會執(zhí)行axios請求then后面的內(nèi)容
<!-- demo -->
<body>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
  <script>
    // Add a request interceptor
    axios.interceptors.request.use(async function (config) {
      // Do something before request is sent
      console.log('request 攔截: ', config)

      // 打印內(nèi)容格式如下:
      // {
      //   "url": "https://zuo11.com/getList?num=5&start=5",
      //   "data": undefined
      //   "method": "get",
      //   "headers": {
      //     "common": {
      //       "Accept": "application/json, text/plain, */*"
      //     }
      //   },
      //   "timeout": 0,
      //   "xsrfCookieName": "XSRF-TOKEN",
      //   "xsrfHeaderName": "X-XSRF-TOKEN",
      //   "maxContentLength": -1
      // }

      // 為所有請求加一個時間戳參數(shù)
      config.url  += (config.url.includes('?') ? '&' : '?')  + 't=' + (+new Date())
      // Request URL: https://zuo11.com/getList?num=5&start=5&t=1575620590972

      await new Promise((resolve, reject) => {
        console.log('開始等待中...')
        setTimeout(()=> {
          resolve('結(jié)束等待')
        }, 5000)
      })

      return config; // 用來請求的參數(shù)
    }, function (error) {
      // Do something with request error
      return Promise.reject(error);
    });

    // Add a response interceptor
    axios.interceptors.response.use(function (response) {
      // Any status code that lie within the range of 2xx cause this function to trigger
      // Do something with response data
      console.log('響應攔截', response)

      // 如果身份校驗失敗,返回登錄頁
      response.data.code === 111  && (window.location.href = response.data)

      return response.data // 過濾掉除data參數(shù)外的其它參數(shù),響應接收到的值。
      // return response;
    }, function (error) {
      // Any status codes that falls outside the range of 2xx cause this function to trigger
      // Do something with response error
      return Promise.reject(error);
    });

    axios.get('https://zuo11.com/getList?num=5&start=5').then((res) => {
      console.log('請求成功,', res)
    }, (err)=> {
      console.log('請求發(fā)生了錯誤,', err)
    })
  </script>
</body>

參考文檔: https://github.com/axios/axios#interceptors

#2019/10/11 周五

#eltree 懶加載問題

懶加載每次加載數(shù)據(jù)都是從后臺搜索而來,對于復雜的邏輯,建議用文字來整理,按步驟分解,不管邏輯多復雜,條理都會很清晰。

#eltree highlight 屬性

加上后,當前選中的背景色會稍微深一點

#v-cloak 指令

防止由于網(wǎng)絡原因vue.js未渲染時,頁面顯示 的問題

// 當編譯完成后,v-cloak屬性會被自動移除。
[v-cloak] {
  display: none;
}
<div v-cloak>
  {{message/}}
</div>

#2019/10/10 周四

#URLSearchParams() 查詢字符串處理

https://developer.mozilla.org/zh-CN/docs/Web/API/URLSearchParams

var searchParams = new URLSearchParams()
searchParams.append('a', 1212)
searchParams.append('b', 'xxx')
searchParams.toString()   // "a=1212&b=xxxx"

// 結(jié)合fromEntries函數(shù),將查詢字符串轉(zhuǎn)對象
// https://www.yuque.com/guoqzuo/js_es6/rxu7ms#e6a375d4
Object.fromEntries(new URLSearchParams('foo=bar&baz=qux'))

#前端ajax請求時,設置Cookie請求頭無效。

W3c規(guī)定,當請求的header匹配以下不安全的字符時,將被終止

...
Cookie
Host
Referer
User-Agent
...

#elementUI 全局觸發(fā)消息

// $message(), $alet()
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(ElementUI)

// 注意:引入方式不是 .use
Vue.prototype.$message = ElementUI.Message
Vue.prototype.$alert = ElementUI.MessageBox.alert

this.$message({
  type: 'error', // warning
  message: '這是一條消息' 
})

this.$message.error(e.message)

#2019/10/09 周三

#Vue中img的src是動態(tài)參數(shù)時不顯示

解決方法:使用require來加載圖片, 參考 Vue中img的src是動態(tài)渲染時不顯示(opens new window)

#滾動相關(guān)問題

進入頁面后,計算某個id的offsetTop,再通過設置documet.documentElement.scrollTop滾動到該位置。這里滾動不了是因為高度是異步加載數(shù)據(jù)后才計算出來,需要在加載數(shù)據(jù)成功后,再執(zhí)行,并使用 this.$nextTick(()=> {})。這里有耦合,可以用到設計模式中的發(fā)布訂閱模式,mounted鉤子函數(shù)訂閱數(shù)據(jù)請求成功的消息,當接收該消息時執(zhí)行dom操作。在異步數(shù)據(jù)請求ok后,發(fā)布數(shù)據(jù)請求成功的消息。另外這里是否不用操作dom,直接使用hash來滾動?直接使用element.scrollIntoView()方法?

#window.scroll(x-coord, y-coord)

滾動到指定位置

#window.scrollTo()

// https://developer.mozilla.org/zh-CN/docs/Web/API/Window/scrollTo
window.scrollTo(x-coord,y-coord )
window.scrollTo(options)
// * x-coord 是文檔中的橫軸坐標。
// * y-coord 是文檔中的縱軸坐標。
// * options 是一個包含三個屬性的對象:
//  1\. top 等同于  y-coord
//  2\. left 等同于  x-coord
//  3\. behavior  類型String,表示滾動行為,支持參數(shù) smooth(平滑滾動),instant(瞬間滾動),默認值auto,實測效果等同于instant

window.scrollTo( 0, 1000 );

// 設置滾動行為改為平滑的滾動
window.scrollTo({ 
    top: 1000, 
    behavior: "smooth" 
});

#window.scrollBy() 相對于當前位置

window.scrollBy(x-coord, y-coord);
window.scrollBy(options)
// * x是水平滾動的偏移量,單位:像素。
// * Y 是垂直滾動的偏移量,單位:像素。
// 正數(shù)坐標會朝頁面的右下方滾動,負數(shù)坐標會滾向頁面的左上方。

window.scrollBy(0, window.innerHeight);  // 向下滾動 一頁(瀏覽器可視高度)

#Element.scrollTop

Element.scrollTop 屬性可以獲取或設置一個元素的內(nèi)容垂直滾動的像素數(shù)。返回文檔在垂直方向已滾動的像素值。

window.scrollY
document.documentElement.scrollTop = 100 頁面滾動

#Element.scrollIntoView()

參數(shù)是一個布爾值,默認為true,滾動到元素位置

document.getElementById('注意').scrollIntoView(true)
// https://developer.mozilla.org/zh-CN/docs/Web/API/Element/scrollIntoView#%E7%A4%BA%E4%BE%8B

#使用hash

url設置hash,可以滾動到對應的id位置

#vue vue-touer 滾動

創(chuàng)建Router實例時,可以提供scrollBehavior方法,來設置對應的滾動效果。參考: vue-router滾動行為

text-overflow: ellipsis
文本溢出處理,在HTML5權(quán)威指南這本書里是沒有講到這個知識點

div.test {
  text-overflow: ellipsis;
}

/* 需要結(jié)合下面的三個屬使用 */
{
  white-space: nowrap;  /* 不換行 */
  overflow: hidden;     /* 溢出內(nèi)容隱藏 */
  width: 20em;          /* 指定寬度 */
}

npm run 端口被占用
npm run dev退出后依舊占用端口,vscode的console,有時候可能沒關(guān)閉就開了新的terminal,把vscode整體退出,在打開就可以了,可以不依賴vscode的終端,使用系統(tǒng)自帶的terminal

# mac 查看端口占用情況:
lsof -i :7000
sudo kill -9 716
# -9后面加一個空格,然后加上占用端口的進程PID,就可以殺掉占用端口的進程。最后重啟terminal就ok。
# Mac 查看端口占用情況及殺死進程 http://www.lxweimin.com/p/9216b6127a82
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容