HTML
-
HTML5新增加的內容或者API
-
API層
- canvas: 用來寫游戲還是很不錯的,推薦開源游戲框架:pixi.js
- 離線: 想起 Cache Manifest , 和 Cache APIs 。再加上 Service Worker 的特性,用戶體驗能提升不少。
- 拖放: Drag & Drop , 對用戶體驗也有很大的提升。推薦開源庫:dragula
- 歷史: 簡而言之就是可以使用history對象控制地址了,一般會被單頁應用用作路由控制,如果不支持,然后降級為hash。
- 網絡存儲: sessionStorage & localStorage,這個應該不陌生,保存一些稍大的數據,或者不適合放在Cookie的,就用網絡存儲。 類似的還有 IndexedDB 和 WebSQL。 推薦開源庫:localForage。
-
元素與屬性
- section 文檔中的節(section、區段)。比如章節、頁眉、頁腳或文檔中的其他部分。寫文章的時候經常會用到
- <video> 和 <audio>: 視頻和音頻。相關開源庫:video.js。
- <footer> 和 <header>: 之前<div class='footer OR header'></div>的寫法換成標簽<footer> 和 <header>就行了,為了語義化,推薦。
- <mark> 標記高亮一個詞。
- <datalist> 提醒用戶可以輸入哪些,查看 w3school 的 demo。
- <nav>表示導航等等,還要更多的標簽,目的是為了寫出更好語義化的HTML。
-
-
input與textarea的區別
- input
- 可以指定 type 為 url, email, 可以方便地檢測用戶輸入。還是指定為 file, submit, button, checkbox, radio, datetime, color等,改變input的樣式和行為。
- 可以通過 value 屬性指定初始值
- 寬高只能通過 CSS 指定
- textarea
- 可以輸入多行文字
- 輸入值初始化需要用標簽對包裹,并可以夾雜 HTML 代碼,而不會被瀏覽器解析
<textarea><h1>h1</h1></textarea>
- 寬高能用 CSS 或 rows, cols 指定
- 相同點
- 都可以使用 maxlength, minlength等限制輸入
- input
-
用一個div模擬textarea的實現
- 加個 contenteditable 屬性就行
- 在項目中如果需要用到富文本,在 Github 中搜索 rich editor 就行了,或者搜索 WYSIWYG (what you see is what you get), 百度的 ueditor 也是不錯的
-
忽略頁面中的電話號碼
<meta name="format-detection" content="telephone=no" />
-
左右布局:左邊定寬、右邊自適應
- absolute + padding
<style> .example-1 { position: relative; height: 100px; width: 60%; padding-left: 100px; } .example-1 .left { position: absolute; width: 100px; left: 0; height: 100%; background: #0f0; } .example-1 .right { background: #f00; width: 100%; height: 100%; } </style> <div class='example-1 auto-width'> <div class='left'>left</div> <div class='right'>right</div> </div>
- flex布局未來趨勢
- table (內容過多時 會出問題)
<style> .example-3 { display: table; height: 100px; width: 60%; } .example-3 .left { width: 100px; height: 100%; background: #0f0; display: table-cell; } .example-3 .right { background: #f00; height: 100%; display: table-cell; } </style> <div class='example-3 auto-width'> <div class='left'>left</div> <div class='right'>right</div> </div>
- float解決方案
<style> .example-4 { height: 100px; width: 60%; } .example-4 .left { float: left; width: 100px; height: 100%; background: #0f0; } .example-4 .right { background: #f00; overflow: hidden; height: 100%; } </style> <div class='example-4 auto-width'> <div class='left'>left</div> <div class='right'>right</div> </div>
- absolute + padding
-
BFC、IFC
- BFC: ‘Block Formatting Context’, BFC 表現原則: 內部子元素再怎么翻江倒海,翻云覆雨都不會影響外部的元素,自成一方天地。
- IFC: Inline Formatting Contexts, 直譯為”內聯格式化上下文”,個人理解為行內盒子模型。
-
圖片懶加載
核心代碼時檢測當前元素是否在當前視圖中:function elementInViewport(el) { var rect = el.getBoundingClientRect() // For invisible element. 對于不可見元素 if (rect.top + rect.bottom + rect.left + rect.right + rect.height + rect.width === 0) { return false; } return ( rect.top >= 0 // Pre load. && rect.top <= ((window.innerHeight || document.documentElement.clientHeight) + 100) && rect.left >= 0 // Hide carousel except the first image. Do not add equal sign. && rect.left < (window.innerWidth || document.documentElement.clientWidth) ) }
-
實現頁面加載進度條
- AJAX
- Elements
- Document
- Event Lag
-
事件委托
利用事件冒泡和e.target來確定事件和元素。在jQuery中有$.delegate方法去代理事件。使用委托代理的原因:- 需要綁定事件的元素很多,且處理邏輯類似。
- 元素是動態創建,或頻繁增加、刪除,導致元素綁定事件過于復雜的。
// 參考 https://github.com/zenorocha/delegate/blob/master/src/delegate.js const delegate = (element, selector, type, callback) => { element.addEventListener(type, (e) => { let target = e.path.find(ele => ele.matches(selector)) if (target) { callback.call(element, e); } }); };
-
實現 extend 函數
淺拷貝使用 Object.assign 就夠了,大多數情況下,使用該方法。
直接 Clone 一個 Nested Object 的簡便方法:var origin = {"a": "a"} var copy = JSON.parse(JSON.stringify(origin));
-
跨域的問題以及解決方式
-
解決方式:
- JSONP(JSON with Padding): 利用加載 JS 文件不需要遵循同源策略的原理。
- CORS(Cross-Origin Resource Sharing): 在服務器端返回允許跨域訪問的頭。
- WebSockt:利用 WebSocket 不需要遵循同源策略的原理。
-
JSONP
JSONP 原理是加載一個 script,并執行一段回調 JS ,因為加載 JS 不需要遵循同源策略。但由此也帶來了JSONP的一些問題:- 無法發送特定的頭部
- 只能是 GET 請求
- 無法發送 body
-
-
拖拽功能
<ul id='drag'> <li draggable="true">1</li> <li draggable="true">2</li> <li draggable="true">3</li> <li draggable="true">4</li> <li draggable="true">5</li> </ul> <script> var ele; document.querySelector('#drag').addEventListener('dragstart', function (e) { ele = e.target; ele.classList.add('draging'); }) document.querySelector('#drag').addEventListener('dragover', function (e) { e.preventDefault(); if (e.target.nodeName === 'LI') { e.target.parentNode.insertBefore(ele, e.target); } }) document.querySelector('#drag').addEventListener('drop', function (e) { ele.classList.remove('draging'); }) </script>
-
手寫parseInt的實現
- const parseInt = str => str - 0;
- const parseInt = str => str / 1;
- const parseInt = str => str * 1;
- const parseInt = str => +str;
- 復雜寫法
const parseInt = str => { let n = 0; let i = 1; str.split('').reverse().map(s => { n += i * (s.charCodeAt(0) - 48); i *= 10; }); return n; }
-
分頁器組件
為了減少服務端查詢次數,點擊“下一頁”怎樣能確保還有數據可以加載(請求數據不會為空)?- 服務器需要返回總數,當前偏移量,根據總數和偏移量判斷是否是最后一頁。
- 參考微信的接口,給一個下一頁的起始項的id,如果當前頁最后一個id和下一頁起始id相同,就是最后一頁。
-
require.js的實現原理
與webpack相比,兩者打包的異同及優缺點- 同:
都以模塊化方式組織代碼 - 異:
requirejs 只能加載JS文件
webpack 可以打包JS,CSS,甚至是圖片
- 同:
-
項目中使用過哪些優化方法
- 頁面靜態化,(如:Jada, Pug在靜態編譯后部署)
- CDN加速, 多地緩存
- 前端渲染 (Data + View) / 后端渲染( SSR, SEO 等), 視具體情況選擇,如:
- 前端渲染,適合大流量的場景
- 后端渲染,適合SEO優化,用戶體驗提升等場景
- 縮減域名,以減少DNS解析時間,(可采用<link rel="dns-prefetch" >進行優化)
- 如果遇到域名解析的問題,可嘗試HTTPDNS方案
- Combo服務器合并CSS,JS請求,減少第一屏網絡請求。(如果采用HTTP2.0方案,資源合并可省略)
- 異步加載非核心業務和邏輯資源
- 資源和請求緩存,可參考緩存的答案
- Cache-Control/Expires 前端緩存
- Last-Modified/Etag 服務器端緩存,304
- 如果是和Native混合開發的,還可以使用Native緩存
- DNS就近解析應用服務器,需要和CDN配合使用
-
輸入一個URL,Enter之后發生了什么
- 瀏覽器解析URL, 如: https://www.google.com.hk/#newwindow=1&q=hello
- 協議:http, https等
- 域名:www.google.com.hk
- 資源路徑: /
- 參數查詢:q=hello, 關鍵詞hello
- DNS
- 瀏覽器 DNS 緩存
- HOSTS 查詢
- DNS 服務器查詢
- ARP 查詢
- TCP 握手, TLS 握手
- HTTP(s), (或SPDY, 或HTTP2.0)
- Header
- Domain
- Body
- Gateway / Nginx,網關和負載均衡服務器
- 查詢本地緩存
- 請求上游應用服務器
- 瀏覽器解析HTML,并請求資源
- CSS
- JS
- 圖片
- 生成 DOM-Tree,結合CSS進行渲染
- 瀏覽器解析URL, 如: https://www.google.com.hk/#newwindow=1&q=hello
-
頁面的渲染過程
- 解析整個HTML,得到DOM樹和樣式樹
- DOM樹和樣式樹,經過渲染,得到一顆渲染樹
- 根據渲染樹,開始布局,計算各個節點寬度,位置,高度等
- 然后開始繪制整個頁面并顯示
- 在渲染過程中如果使用了GPU,還可以進行GPU渲染
-
靜態資源或者接口等如何做緩存優化
- redis/memcache 做數據緩存
- SQL 查詢做緩存
- 指定 Cache-Control/Expires 緩存時間
- Last-Modified/Etag 緩存 ( 304 ) 方案
- 網關服務器做緩存,需要更新時,再回源到應用服務器
- CDN多機房,多網關緩存
-
頁面DOM節點太多,會出現什么問題?如何優化?
- 頁面卡頓,幀率下降
- 優化:
- 采用Virtual Dom技術,可參考: virtual-dom
- 多次操作DOM,改為批量一次操作DOM
- 及時移走頁面不用的DOM
- 避免不必要的DIV嵌套
前端安全問題 CSRF和XSS
-
CSRF Cross-site request forgery 跨站請求偽造
-
簡單描述:
跨站請求偽造(英語:Cross-site request forgery),也被稱為 one-click attack 或者 session riding,通常縮寫為 CSRF 或者 XSRF, 是一種挾制用戶在當前已登錄的Web應用程序上執行非本意的操作的攻擊方法。[1] 跟跨網站腳本(XSS)相比,XSS 利用的是用戶對指定網站的信任,CSRF 利用的是網站對用戶網頁瀏覽器的信任
-
防御措施
- 檢查referer, X-Requested-With, Orign頭
- 使用POST代替GET
- 添加校驗Token至表單中
- 添加驗證碼或其他人機驗證手段,如 Google 的 recaptcha
- 把Token放到自定義的HTTP Header, Cookie-to-Header Token
-
-
XSS: Cross-site_scripting
- 簡單描述:
跨站腳本(英語:Cross-site scripting,通常簡稱為:XSS)是一種網站應用程序的安全漏洞攻擊,是代碼注入的一種。它允許惡意用戶將代碼注入到網頁上,其他用戶在觀看網頁時就會受到影響。這類攻擊通常包含了HTML以及用戶端腳本語言。
- 防御措施
- 過濾特殊字符串 ( encoding / escaping )
- 保護Cookie
- 使用HttpOnly字段防止被JS獲取,(因為攻擊通常會采集敏感信息)
- 使用HTTPs代替HTTP,(運營商經常會通過注入廣告)
- 禁用JS,(這個不太現實)
- 推薦!設置CSP: Content_Security_Policy 介紹,Content-Security-Policy 文檔。這個在Github有使用:
Content-Security-Policy:default-src 'none'; base-uri 'self'; block-all-mixed-content; child-src render.githubusercontent.com; connect-src 'self' uploads.github.com status.github.com collector.githubapp.com api.github.com www.google-analytics.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com wss://live.github.com; font-src assets-cdn.github.com; form-action 'self' github.com gist.github.com; frame-ancestors 'none'; img-src 'self' data: assets-cdn.github.com identicons.github.com collector.githubapp.com github-cloud.s3.amazonaws.com *.githubusercontent.com; media-src 'none'; script-src assets-cdn.github.com; style-src 'unsafe-inline' assets-cdn.github.com
- 設置 X-XSS-Protection 頭
-
HTTP 安全頭
- Strict-Transport-Security: Strict-Transport-Security: max-age=31536000 ; includeSubDomains
- Public-Key-Pins: Public-Key-Pins: pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="; report-uri="http://example.com/pkp-report"; max-age=10000; includeSubDomains
- X-Frame-Options: X-Frame-Options: deny
- X-XSS-Protection: X-XSS-Protection: 1; mode=block
- X-Content-Type-Options: X-Content-Type-Options: nosniff
- Content-Security-Policy: Content-Security-Policy: script-src 'self'
- X-Permitted-Cross-Domain-Policies: X-Permitted-Cross-Domain-Policies: none
- Referrer-Policy: Referrer-Policy: no-referrer
跨域
跨域請求的含義
瀏覽器的同源策略,出于防范跨站腳本的攻擊,禁止客戶端腳本(如JavaScript)對不同域的服務進行跨站調用。
一般的,只要網站的 協議名protocol、 主機host、 端口號port 這三個中的任意一個不同,網站間的數據請求與傳輸便構成了跨域調用。
跨域請求并非是瀏覽器限制了發起跨站請求,而是請求可以正常發起,到達服務器端,但是服務器返回的結果會被瀏覽器攔截。
利用 JSONP 實現跨域調用
JSONP 是 JSON 的一種使用模式,可以解決主流瀏覽器的跨域數據訪問問題。其原理是根據XmlHttpRequest 對象受到同源策略的影響,而<script>標簽元素卻不受同源策略影響,可以加載跨域服務器上的腳本,網頁可以從其他來源動態產生JSON資料。用JSONP獲取的不是 JSON 數據,而是可以直接運行的 JavaScript 語句。
如果理解 JSONP 的原理的話就不難理解為什么只能使用 GET 請求方法了。
由于是通過 script 標簽進行請求,所以上述傳輸過程根本上是以下的形式:
<script src = 'http://localhost:3001/ajax/deal?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032'></script>-
JSONP總結:
- 只能使用 GET 方法發起請求,這是由于 script 標簽自身的限制決定的。
- 不能很好的發現錯誤,并進行處理。
- 與 Ajax 對比,由于不是通過 XmlHttpRequest 進行傳輸,所以不能注冊 success、 error 等事件監聽函數。
<script> // function success_jsonpCallback(data) { // console.log("in success_jsonpCallback ") // console.log(data) // } $.ajax({ type:'get', dataType:'jsonp', url:'http://localhost:3000/users/list', jsonp:"callback123", jsonpCallback:"success_jsonpCallback", success:function(res) { console.log(res) }, error:function(err,status) { console.log(err) console.log(status) } }) </script> <!-- 后臺拿到的 req.query 對象 { callback123: 'success_jsonpCallback', _: '1498535014927' } 發送的ajax請求是: /users/list?callback123=success_jsonpCallback&_=1498535569911 -->
服務器端 (需要返回函數的調用形式)
router.get('/list', function(req, res, next) { console.log(req.query) var users = [ {id:1, name:"F"}, {id:2, name:"Z"}, {id:3, name:"X"}, {id:4, name:"M"}, {id:5, name:"N"}, {id:6, name:"A"}, {id:7, name:"B"}, {id:8, name:"D"}, {id:9, name:"C"}, {id:10, name:"L"}, ]; var data = req.query.callback123+"("+JSON.stringify(users)+")"; res.send(data); });
使用 CORS 實現跨域調用
1 什么是 CORS?
Cross-Origin Resource Sharing(CORS)
跨域資源共享是一份瀏覽器技術的規范,提供了 Web 服務從不同域傳來沙盒腳本的方法,以避開瀏覽器的同源策略,是 JSONP 模式的現代版。與 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以讓網頁設計師用一般的 XMLHttpRequest,這種方式的錯誤處理比 JSONP 要來的好。另一方面,JSONP 可以在不支持 CORS 的老舊瀏覽器上運作?,F代的瀏覽器都支持 CORS。
-
服務器端控制
res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "X-Requested-With"); res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS"); res.header("X-Powered-By", ' 3.2.1') res.header("Content-Type", "application/json;charset=utf-8");
-
CORS 與 JSONP 的對比
- CORS 除了 GET 方法外,也支持其它的 HTTP 請求方法如 POST、 PUT 等。
- CORS 可以使用 XmlHttpRequest 進行傳輸,所以它的錯誤處理方式比 JSONP 好。
- JSONP 可以在不支持 CORS 的老舊瀏覽器上運作。
一些其它的跨域調用方式
- window.name
window對象有個name屬性,該屬性有個特征:即在一個窗口 (window)的生命周期內,窗口載入的所有的頁面都是共享一個window.name的,每個頁面對 window.name 都有讀寫的權限,window.name是持久存在一個窗口載入過的所有頁面中的,并不會因新頁面的載入而進行重置。
- window.postMessage()
這個方法是 HTML5 的一個新特性,可以用來向其他所有的 window 對象發送消息。需要注意的是我們必須要保證所有的腳本執行完才發送 MessageEvent,如果在函數執行的過程中調用了他,就會讓后面的函數超時無法執行。