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 周五
#骨架屏研究
- 一種自動化生成骨架屏的方案 https://blog.csdn.net/sinat_17775997/article/details/83443744
- 教你實現(xiàn)超流行的骨架屏預加載動態(tài)效果 http://www.dxcu.com/news/show-531569.html
- repeating-linear-gradient 線性漸變研究TODO
<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í)行順序
- 先執(zhí)行請求攔截(特意在攔截中加了一個阻塞5s的await)
- 向后端發(fā)送請求
- 觸發(fā)響應攔截(這里也可能存在等待時間)
- 最后才會執(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