本文適合前端新手入門,閱讀人羣最好是前端新手或者後臺開發人員,由於我不敢保證對前端老司機有太多收穫。javascript
經過閱讀本文,你將會大體瞭解前端這些年發生的事情,以及一些前端當前主流技術的簡單原理介紹。全部涉及的內容,都是儘量的讓你捅破這層窗戶紙,知道其大體的玩法。css
本節知識點:html
Web1.0 到 Web2.0過渡的標誌,就是Ajax的出現(2005年)。前端
AJAX 即 Asynchronous JavaScript and XML(異步的 JavaScript 與 XML 技術)。vue
var request = new XMLHttpRequest();
request.open('GET', '/my/url', true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var data = JSON.parse(request.responseText);
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
複製代碼
$.ajax({
type: 'GET',
url: '/my/url',
data: data,
success : function(result){
//TODO RESULT
}
});
複製代碼
let getData = function (url) {
return new Promsie(function (resolve, reject) {
$.ajax({
type: 'GET',
url: url,
success: function (data) {
resolve(data);
},
error: function (err) {
reject(err);
}
});
});
};
var data = getData('/my/url').then(function (data) {
//TODO DATA
});
複製代碼
let it = null;
let ajax = function(url,data){
$.ajax({
type: 'GET',
url: url,
data: data || {},
success : function(result){
it.next(result);
}
});
};
function *getData(){
var data = yield ajax('/my/url');
console.log('data=',data);
};
it = getData();
it.next();
複製代碼
let ajax = function(url,data){
return $.ajax({
type: 'GET',
url: url,
data: data || {}
});
};
async function getData(){
var data = await ajax('/my/url');
console.log('data=',data);
};
getData();
複製代碼
Ajax的相關背景資料:java
1999年,微軟公司發佈IE瀏覽器5.0版,第一次引入新功能:容許JavaScript腳本向服務器發起HTTP請求。這個功能當時並無引發注意,直到2004年Gmail發佈和2005年Google Map發佈,才引發普遍重視。node
2005年2月,AJAX這個詞第一次正式提出,指圍繞這個功能進行開發的一整套作法。今後,AJAX成爲腳本發起HTTP通訊的代名詞,W3C也在2006年發佈了它的國際標準。jquery
本節知識點:webpack
什麼是SPA? SPA 即單頁面,就是頁面總體不刷新,不一樣的頁面只改變局部的內容的一種實現方式。git
一個完整的URI有如下幾部分組成:
scheme:[//[user[:password]@]host[:port]][/path][?query][#fragment]
複製代碼
瀏覽器的URL也遵循以上規則,而對於以上規則中,只有 #
後面的 fragment
發生改變時,頁面不會從新請求,其它參數變化,均會引發頁面的從新請求,而在Js中偏偏還有事件 window.onhashchange
能監聽到 fragment
的變化,因而就利用這個原理來達到一個修改局部內容的操做。
#fragment
部分就是對應到Js中的 location.hash
的值。
直接上代碼描述:
<!DOCTYPE html>
<head>
<script type="text/javascript"> window.onhashchange = function(){ var page = location.hash; if(page === '#home'){ document.getElementById('main').innerHTML = '這是首頁'; return; }; if(page === '#help'){ document.getElementById('main').innerHTML = '這是幫助頁面'; return; }; document.getElementById('main').innerHTML = '404'; } </script>
</head>
<body>
<header>
<a href="#home">首頁</a>
<a href="#help">幫助</a>
</header>
<article id="main"></article>
</body>
</html>
複製代碼
以上代碼直接在HTML上面有2個連接,點擊後在頁面的部分區域直接顯示這2個連接對應的不一樣的頁面內容。
服務器上如何應用Js呢?這句話能夠理解爲:在非網頁狀況下如何運行Js程序(或者命令行如何運行)。
與Java在服務器上運行須要按照JDK同樣,Js要運行也須要安裝Node環境,安裝之後就能夠運行了,具體的能夠對照着Java程序來解釋說明。
用過Java的人必定對 FreeMarker
不陌生,其工做原理:
對於Node.js來講也是同樣,只是使用的框架不是FreeMarker罷了!究其原理無非都是:
Template + Data = Output
只是如今前端說的這個SSR,其實就是指後臺渲染好數據,直接返回到瀏覽器,瀏覽器就直接顯示了,下面咱們作一個對比,用來講明傳統的AJax操做和SSR之間的區別。
<!DOCTYPE html>
<head>
<script type="text/javascript" src="lib/jquery.min.js"></script>
<script type="text/javascript"> /** * 使用jQuery將後臺接口返回的數據顯示到頁面上 */ function renderData(){ $.post(url,param,function(result){ //假設返回的是是一個List,咱們追加到頁面的ul中 $.each(result,function(i,d){ $('#list').append('<li>' + d.name + '</li>'); }) }); }; renderData(); </script>
</head>
<body>
<ul id="list"></ul>
</body>
</html>
複製代碼
主要流程以下:
下面示例咱們以Vue框架後臺直出方案爲例:
const Vue = require('vue')
const server = require('express')()
const renderer = require('vue-server-renderer').createRenderer()
server.get('*', (req, res) => {
//vue對象包含了template+data
const app = new Vue({
data: {
list: [{
name : 'lilei'
},{
name : 'hanmeimei'
}]
},
template: `<ul><li v-for="item in list">{{item.name}}</li></ul>`
})
//將vue對象傳入最終返回output結果html
//再將html經過reponse對象返回給前端瀏覽器
renderer.renderToString(app, (err, html) => {
res.end(` <!DOCTYPE html> <html> <body>${html}</body> </html> `)
})
})
server.listen(8080)
複製代碼
主要流程以下:
若是有人對這個vue示例的完整構建流程感興趣,能夠按照以下流程快速搭建環境並容許起來:
什麼是MVC?什麼是MVVM?
經過上圖能夠清晰的看到,MVVM相比MVC來講,缺乏了 Controller
一層,傳統 Controller
作的事情就是處理一堆複雜的邏輯,而後將數據輸出到 View
上面。那麼如今缺乏了這一層之後,View
和 ViewModel
之間如何進行雙向自動關聯數據綁定的呢?
也就是說,頁面上數據發生變化,Js中的數據如何跟着也變化;相反,Js中數據變化了,頁面如何自動跟着變化?
舉個例子來進一步闡明這個問題,下面的效果如何實現?
經過給頁面元素添加 onchange
或者 oninput
事件,在事件中獲取表單的值,而後賦值給Js對應的對象上便可。
好比:示例中的輸入框就能夠添加oninput事件
<input type="text" oninput="evtInput" />
複製代碼
而後在js中定義這個函數執行相關賦值操做就能夠:
function evtInput(){
vue.name = this.value;
}
複製代碼
JavaScript原生有個方法 Object.defineProperty()
,這個方法能夠從新設置一個js對象中某個元素的一些屬性,同時提供了 get
和 set
方法,容許用戶對元素進行從新賦值和取值操做。
簡單分析一下代碼:
正式因爲咱們能夠經過攔截一個屬性的 set
方法。因此,咱們就能夠在 set
方法中講獲取到的新值賦值給頁面元素就能夠了。
Object.defineProperty(data,'name',{
set : function(v){
document.getElementById('input').value = v;
}
});
複製代碼
那麼前端爲何要進行打包呢?前端代碼不是直接就能運行到瀏覽器麼,還打包乾嗎?
要搞清楚這個問題,那麼咱們就以java爲例可能比較恰當,好比:java的工程目錄中有一個源碼目錄:src
它是用來存放java源碼的,可是java實際編譯後確定就沒有src這個目錄了對吧?
那麼 src
源碼的做用是什麼呢?就是用來更好的歸類整理咱們的源代碼,它有多是跟咱們實際運行的代碼結構徹底不同,由於實際運行的是機器能讀懂的,而源碼是給人看的。
因此前端也同樣,因爲當前階段,前端的業務邏輯也變的很是複雜,再不是傳統意義上的一個 html、一個js、一個css就能搞定的。因此咱們要分模塊,分目錄存放源碼,最終經過打包再組裝成瀏覽器能夠讀懂的代碼和目錄結構。
好比:咱們經過vue的腳手架建立一個vue的webpack項目,看看它的默認的源碼目錄(src)的樹結構:
src
├── App.vue
├── assets
│ └── logo.png
├── components
│ └── HelloWorld.vue
├── main.js
└── router
└── index.js
複製代碼
src中除了有3個子目錄 assets
components
router
,還有2個 .vue
結尾的文件。因此,這種目錄結構和文件在瀏覽器中確定是沒法運行的,若是咱們要運行,就必須對它進行編譯,翻譯成瀏覽器能讀懂的html/js/css文件才行。
當咱們打包之後,看到項目的dist目錄下就有了編譯之後的,瀏覽器可執行的代碼結構:
dist
├── index.html
└── static
├── css
│ ├── app.30790115300ab27614ce176899523b62.css
│ └── app.30790115300ab27614ce176899523b62.css.map
└── js
├── app.b22ce679862c47a75225.js
├── app.b22ce679862c47a75225.js.map
├── manifest.2ae2e69a05c33dfc65f8.js
├── manifest.2ae2e69a05c33dfc65f8.js.map
├── vendor.7fed9fa7b7ba482410b7.js
└── vendor.7fed9fa7b7ba482410b7.js.map
複製代碼
因此,當前前端代碼邏輯複雜,各類框架橫行的年代,源碼都是不能直接在瀏覽器訪問的,都須要藉助打包工具,如:gulp、webpack這些工具進行打包翻譯,才能獲得真正的可執行的文件。
一句話歸納Webpack的本質:
webpack 是一個打包模塊化js的工具,能夠經過Loader轉換文件,經過Plugin擴展功能。
Webpack打包的簡易示意圖:
什麼是Sass?就是一種能提升CSS開發效率的工具。
其編譯原理是:
實際在項目中怎麼用Sass呢?
前面在說Webpack的時候說過了,如今前端技術離開打包工具是不能直接運行 ,相似於這種Sass文件也同樣。因此,咱們只須要在Webpack中增長Sass文件的Loader,這樣在代碼編譯環境,就能自動把Sass文件轉換爲Css文件,最後引入到Html中的是Css文件,這樣頁面就能正常渲染了。
Sass有什麼好處?
test.scss文件:
$color-red: #00ff00;
$color-white: #ffffff;
#main p {
color: $color-red;
width: 97%;
.redbox {
background-color: $color-red;
color: $color-white;
}
}
複製代碼
若是用傳統的css寫:
#main p {
color: #00ff00;
width: 97%;
}
#main p .redbox {
background-color: #00ff00;
color: #ffffff;
}
複製代碼
本節知識點:
什麼是TypeScript?
TypeScript 是微軟開源發佈的JavaScript類型的超集,它能夠編譯成純JavaScript。
它是一個Js框架,能夠用來開發前端系統。
之因此說TypeScript是JavaScript的超集,就意味着TypeScript在JavaScript的語法基礎上,又擴展了更多語法,使得開發更加方便。
接下來咱們看看TypeScript的相比JavaScript額外增長的部分:
學Java的同窗不要驚慌,我的看來TypeScript就是把Java用JavaScript從新實現了一遍!
一、強數據類型
//Boolean類型
let isDone: boolean = false;
//數字類型
let decLiteral: number = 6;
//字符串
let name: string = "bob";
//數組
let list: Array<number> = [1, 2, 3];
//函數定義
function add(x: number, y: number): number {
return x + y;
}
複製代碼
二、接口
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
複製代碼
這裏的接口與Java中的接口不同,TypeScript中的接口僅僅是對參數的一種契約約定,即:參數必須是接口定義的結構和參數名等。
三、類
//定義類
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
let greeter = new Greeter("world");
//類的繼承
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}
class Dog extends Animal {
bark() {
console.log('Woof! Woof!');
}
}
//共有、私有變量、方法
class Animal {
private id: number; //僅類內部訪問,實例沒法訪問
public name: string;//類內部和實例均可以訪問
protected pid: number;//僅類內部和子類能夠訪問
public constructor(theName: string) { this.name = theName; }
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
複製代碼
四、泛型
function identity<T>(arg: T): T {
return arg;
}
複製代碼
五、枚舉
enum Direction {
Up = 1,
Down,
Left,
Right
}
複製代碼
什麼是PWA?
Progressive Web App, 簡稱 PWA,是漸進式提高 Web App 的體驗的一種新方法,能給用戶原生應用的體驗。
PWA 本質上是 Web App,就是運行在手機上的App不是純Native的,而是不少頁面都是網頁。
Web App
,咱們都知道就是App中有網頁嘛!可是 Progressive
漸進式
又該怎麼理解?
我的理解,漸進式
的意思就是:按部就班的發展或者改造
。
PWA更直白的意思就是:
第一步:咱們如今要開發一個App,可是開發純原生App的維護和擴展成本過高,因此咱們須要增長一些網頁進去,畢竟網頁好維護嘛!(這部分其實就是混合類App,也叫:Hybrid App)
第二步:可是咱們App中增長網頁不能太暴力,太暴力容易讓用戶以爲很不天然,因此須要使用按部就班的方式進行,那麼如何按部就班的進行才能讓用戶的體驗達到極致(也就是幾乎看不出來某一個頁面是一個網頁!)
第三步:咱們就須要增長一些策略,先保證用戶體驗,好比:爲了保證安全網頁所有使用HTTPS、使用離線緩存來減小用戶打開頁面的等待時間等等。
因此,PWA就是以按部就班的方式,提高混合類APP的用戶體驗,而影響體驗最大的問題就是頁面加載,因此PWA最核心的技術就是:離線緩存
,離線緩存你們廣泛採用的方案就是:Service Worker
在瞭解什麼是GraphQL以前,咱們先了解一下什麼是SQL?
什麼是SQL?
Structured Query Language,一種結構化的查詢語言,它是關係式數據庫管理系統的標準語言。
說白了,SQL是一種特定的語法,也能夠稱之爲是數據庫管理的API,操做數據庫必須經過這個語法進行。
什麼是GraphQL呢?
一種用於API的查詢語言
GraphQL 既是一種用於 API 的查詢語言也是一個知足你數據查詢的運行時。 GraphQL 對你的 API 中的數據提供了一套易於理解的完整描述,使得客戶端可以準確地得到它須要的數據,並且沒有任何冗餘,也讓 API 更容易地隨着時間推移而演進,還能用於構建強大的開發者工具。
用一組圖來講明下:
那你又要說了?沒有GraphQL我如今客戶端和後臺之間不照樣能夠交互嗎?
沒錯!你是這麼交互的:
因此,不是說離開GraphQL咱們就不能活,而是它給咱們提供了一種全新的API查詢交互方式,使得客戶端和後臺的接口通訊更加高效罷了。
那麼GraphQL相比傳統的接口請求,都有哪些優點呢?
一、所見即所得
//查詢條件
{
user(uid:1) {
uid
name
}
}
//返回結果
{
"data": {
"user": {
"uid": "1",
"name": "xxx"
}
}
}
複製代碼
傳統的API是什麼樣子?
//查詢條件
{
uid : 1
}
//返回結果
{
"data": {
"user": {
"uid": "1",
"name": "xxx"
}
}
}
複製代碼
二、減小網絡請求次數
只須要一次網絡請求,就能得到資源和子資源的數據(例如,上文中文章的評論信息)。
//查詢條件
{
article(aid:1) {
title
content
author {
uid
name
}
},
comment {
content,
author {
uid
name
}
}
}
複製代碼
傳統的查詢,通常先查詢Article,再查詢Comment。固然你能夠一次性去查,讓後臺一次性返回來,可是通常沒有後臺會給你設計這樣的一個API:getArticleAndComment
,如何按照Restful的接口標準,你應該須要查詢2次。
三、參數類型強校驗
GraphQL規定了一套數據類型,這就保證接口查詢的時候,字段類型就被明肯定義,而傳統的接口通常很難保證查詢參數的類型。
好比,如下就是GraphQL的語法定義:
type Starship {
id: ID!
name: String!
length(unit: LengthUnit = METER): Float
}
複製代碼
什麼是Flutter?
Flutter是谷歌的移動UI框架,能夠快速在iOS和Android上構建高質量的原生用戶界面。
下圖就是使用Flutter開發一款App的樣子:
相似於 React Native
框架同樣,Flutter也是能夠調用一些App系統級的命令,能讓你快速開發一款混合類App(Hybrid App)。
有興趣的能夠去官網學習:Flutter中文網
本節知識點:
本文的標題是 大前端的技術原理和演變史
,如今給你們解答一下,什麼是:大前端
。
大前端
就是相比 前端
而言變大了,那麼到底傳統意義的前端指什麼?變成大前端又有哪些東西變大了呢?
傳統的意義的前端指是什麼呢?
傳統的前端就是指直接面對客戶的應用或者系統,好比:網頁、手機App。
而開發網頁、搞iOS和Android開發的程序員均可以稱之爲前端工程師。
只是傳統意義來講,前端工程師僅僅指網頁開發的人,而iOS和Android開發的通常指客戶端開發人員,或者歸結到軟件工程師崗位去了。
那麼大前端又指什麼呢?其實通過各類資料考證,並無這麼一個明確的定義,只是隨着技術的進步,你們有了一種默認的約定,大前端之因此稱之爲大前端,主要體如今如下一些方面:
一、大前端 - 先後端分離
隨着先後端職責和技術框架的分離發展,產品對前端的要求愈來愈高,用戶對前端的期待愈來愈高,前端技術發展愈來愈快,致使前端這個崗位並無像JSP時代那種畫畫頁面就完事了。這部分體現的是前端的要求更高,責任越大了。
二、大前端 - Node全棧
先後端分離後,前端要獨立完成一個事情是不行的,由於缺乏後臺的支持。可是隨着Node的出現,前端能夠不用依賴後臺人員,也不用學習新的後臺語言,就能夠輕鬆搞定後臺的這部分事情。這樣,面對一些小的系統,前端工程師就能夠搞定整個系統。這部分體現了前端的全面性和全棧性。
三、大前端 - 應對各類端
傳統的前端工程師,通常指網頁開發工程師,網站通常指運行在PC瀏覽器,慢慢的也要運行在手機上。可是,隨着移動互聯網的發展,忽然冒出來更多的移動設備,好比:手機分爲Android手機和蘋果手機、智能手錶、VR/AR技術支撐的可穿戴設備、眼睛、頭盔、車載系統、智能電視系統等等。而這些設備都須要前端的支撐,這時候對前端的技術要求、能力要求就更高。這部分體現了前端的涉獵範圍變大。
四、大前端 - 微應用
當微信小程序出來之後,你們第一感受是前端又能夠火一把啦,不須要後臺、不須要服務端,只須要在微信平臺上開發網頁就能夠發佈上線了。
而近期又有國內多個手機廠家聯合推出 快應用
, 跟小程序差很少,只是經過簡單的前端開發發佈之後,用戶不須要安裝應用就能夠直接在相似於小米、vivo、oppo等手機上打開這樣的應用。
相似於這些微應用,免後臺、免安裝的形式出現,也促使了前端這個行業也將涉及到這樣的新型領域中,一塊兒推進技術的進步。這部分體現了前端是時代發展的幸運兒。
綜上所述,咱們能夠獲得一個大體的定義:
大前端指前端涉獵範圍愈來愈廣、涉及的端愈來愈多、技術要求愈來愈高、影響範圍愈來愈大的一種體現。
前端工程化的定義:
前端工程化是根據業務特色,將前端開發流程規範化,標準化,它包括了開發流程,技術選型,代碼規範,構建發佈等,用於提高前端工程師的開發效率和代碼質量,最終交付一個穩定性高、擴展性好、易於維護的系統的過程。
通常狀況下,一個符合前端工程化要求的方案應該包含如下要素:
另外,咱們再談到工程化,不能只想着前端工程化,而應該站在整個系統考慮如何進行工程化,也就是說對於一整個項目,咱們談到工程化應該考慮哪些因素呢?
一個系統的工程化建設,應該包含如下因素: