工做也有一段時間了,平時忙於業務代碼的編寫中,發現身邊的一些人以及本身,對一些基本概念理解有所誤差,可能鬧出笑話,會問出下面這些常識性錯誤的奇怪問題:javascript
2333,怎麼都是關於Vue的問題。。。我真沒黑Vue開發者,不過也能夠看出,Vue的小白受衆的確比較多。css
博客原文html
如今基於Vue,React的SPA單頁應用開發,都傾向於採用webpack的模塊化構建方案。可能大多數人,開發一個項目,會使用腳手架工具(vue-cli, create-react-app)
咱們本地開發時,運行命令行npm run dev
,而後就開始編寫業務邏輯了,對於其中發生了什麼,大多數人可能不太關心。其實運行了該命令,就是運行了webpack-dev-server
前端
webpack-dev-server是webpack官方提供的一個小型Express服務器,正是由於webpack-dev-server本身開啓了一個服務器,咱們纔可以先後端分離開發(咱們不須要關心後端的代碼)。前端啓動的這個服務器,是用來構建和渲染頁面,並提供了自動刷新和熱替換功能。vue
簡單來講:
webpack只是構建(npm run build
)
webpack-dev-server除了構建,還提供web服務(npm run dev
)java
什麼是路由?
簡單來講:/about/deepred
/home/
這些就是路由python
在web開發中,路由分爲前端路由和後臺路由
其實在單頁應用尚未流行前,路由基本指的是後臺路由。若是你熟悉傳統的後臺web開發,可能對下面的代碼很熟悉:react
app.get('/about', function (req, res) { res.render('about', { title: 'Hey', message: 'Hello there!'}); }); app.get('/', function (req, res) { res.render('index'); });
傳統的web網站,全部的路由都是由後臺定義的。當咱們想訪問一個頁面http://anata.me/about/
,首先向後臺發送一個請求,後臺根據定義好的路由,決定渲染哪一個頁面。webpack
然而單頁應用的出現,改變了這個模式。若是你是前端開發,應該對這段代碼更加熟悉:web
routes: [ { path: '/user/:userId', name: 'user', component: User }, { path: '/about/', name: 'about', component: About } ]
前端路由是將頁面的渲染權交給了js控制,不經過請求服務器來判斷渲染頁面。前端通常利用histroy和hash來控制,達到不刷新頁面可使顯示內容發生變化,這樣速度更快,用戶體驗更好。前端路由解放了服務端,專心提供接口數據服務。
腳手架生成的項目,通常運行npm run build
以後,會在項目根目錄生成一個dist目錄,這就是咱們打包好後的靜態資源文件。
注意的是:
npm run dev
啓動項目。npm run dev
啓動的服務器只是爲了開發而使用的,真正線上的服務器,是由後臺提供的(好比PHP,Java, python, Node...)部署的方式有不少,好比能夠把dist文件和後臺代碼放在一塊兒,後臺把dist文件當作靜態資源讀取便可。不過由於採用了前端路由的方案,後臺還須要配置一下,以Express舉例:
// 訪問靜態資源文件 這裏是訪問全部dist目錄下的靜態資源文件 app.use(express.static(path.resolve(__dirname, '../dist'))) // 由於是單頁應用 全部請求都走/dist/index.html // 這一句要放在全部其餘路由的後面 app.get('*', function(req, res) { const html = fs.readFileSync(path.resolve(__dirname, '../dist/index.html'), 'utf-8') res.send(html) })
也能夠把dist靜態文件和後臺代碼分開,經過Nginx部署
server { listen 80; server_name 127.0.0.1; location / { root /data/deered/dist; #前端打包後的dist文件位置 try_files $uri $uri/ /index.html; #防止頁面刷新404 index index.html; } }
由於webpack-dev-server啓動了一個服務器,因此在開發時,前端去請求真正的後臺接口,是存在跨域問題的。webpack提供了跨域的解決方案,原理就是讓服務器反向代理請求真正的接口
vue-cli配置跨域
proxyTable: { '/api': { target: 'http://localhost:8089/api/', changeOrigin: true, pathRewrite: { '^/api': '' } } },
前端請求/api/xxxx
時,webpack-dev-server啓動的服務器會幫咱們請求http://localhost:8089/api/xxxx
,同時返回數據。
有些人就會有疑惑,那打包後的文件,是否是也能跨域。前面咱們說了,線上部署就不是運行npm run dev
,因此,前端是否是跨域要看你怎麼部署了。
若是你把打包後的dist文件和後端代碼放在一塊兒,那麼根本就不存在跨域問題!
若是前端靜態文件和後端不在一塊兒,那麼能夠用Nginx作轉發
server { listen 80; server_name 127.0.0.1; location / { root /data/deered/dist; #前端打包後的dist文件位置 index index.html; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://127.0.0.1:8089 #後臺地址 } }
Vue的指令和模板語言讓開發者能夠很簡潔的完成一個複雜的功能,而React的JSX語法,則讓開發者擁有更多的自主權。
從Vue轉向React的開發者,一開始可能會很是不適應,畢竟v-for
v-if
v-model
這些最基本的功能,React居然全都要咱們本身去實現。
咱們其實能夠從本質上來看:
一個Vue的組件:
<template> <div class="hello" @click="say"> <h1>{{ msg }}</h1> <h2 v-if="show">show me</h2> </div> </template> <script> export default { name: 'Hello World', data () { return { msg: 'Welcome to Your Vue.js App', show: false } } methods: { say() { console.log('hi') } } } </script> <style scoped> h1, h2 { font-weight: normal; } </style>
一個React的組件
const styles = { fontWeight: 'normal' } export default class Hello extends Component { constructor(props) { super(props); this.state = { msg: 'Welcome to Your React App', show: false }; } say() { console.log('hi') } render() { return ( <div class="hello" onClick={this.say}> <h1 className={styles}>{this.state.msg}</h1> {this.state.show ? <h2>show me</h2> : null} </div> ) } }
從兩個組件對比就能看見:
React組件徹底就是一個Class類,你一直在寫各類類方法,甚至你的css也是個對象,因此React要求開發者有較好的ES6基礎,由於你無時無刻不在寫JS
而Vue就不同了,Vue組件其實就是個普通的對象,你只是在修改這個對象的屬性:name
data
methods
components
,說的通俗點,你根本就是在配置對象,例如:你配置了這個對象的components
屬性,因而就能夠在模板中使用自定義組件
所以,React本質上是不可能給你提供相似v-for
的API,由於JS已經有了for循環,數組也有map方法,你寫React就是在寫JS,爲啥還須要額外的遍歷方法呢?而Vue就不一樣了,它提供的指令,其實就是在內部幫你寫JS,因此從React轉向Vue的開發者,一開始會以爲,Vue的代碼更簡潔了。不過,這是靠犧牲自由度換來的,畢竟在React裏,怎麼實現遍歷,徹底由你本身決定