vue構建單頁應用原理
SPA
不是指水療。是 single page web application
的縮寫。中文翻譯爲 單頁應用程序 或 單頁Web應用。更多解釋清參看 百度百科:SPAjavascript
全部的前端人員都應該明白咱們的頁面的 url
構成:css
1 http://www.fengcms.com/index.html?name=fungleo&old=32#mylove/is/world/peace
如上的 url
由如下部分組成:html
http://
規定了頁面採用的協議。www.fengcms.com
爲頁面所屬的域名。index.html
爲讀取的文件名稱。?name=fungleo&old=32
給頁面經過GET
方式傳送的參數#mylove/is/world/peace
爲頁面的錨點區域
前面四個發生改變的時候,會觸發瀏覽器的跳轉亦或是刷新行爲,而更改 url
中的錨點,並不會出現這種行爲,所以,幾乎全部的 spa
應用都是利用錨點的這個特性來實現路由的轉換。以咱們的 vue
項目爲例,它的本地 url
結構通常爲如下格式:前端
1 http://localhost:8080/#/setting/task
能夠明顯的看到咱們所謂的路由地址是在 #
號後面的,也就是利用了錨點的特性。vue
RESTful 風格接口
實際狀況是,咱們在先後端在約定接口的時候,能夠約定各類風格的接口,可是,RESTful
接口是目前來講比較流行的,而且在運用中比較方便和常見的接口。java
雖然它有一些缺陷,目前 github
也在主推 GraphQL
這種新的接口風格,但目前國內來講仍是 RESTful
接口風格比較廣泛。node
而且,在掌握了 RESTful
接口風格以後,會深刻的理解這種接口的優缺點,到時候,你天然會去想解決方案,而且在項目中實行新的更好的理念,因此,我這系列的博文,依然採用 http://cnodejs.org/
網站提供的 RESTful
接口來實戰。jquery
瞭解程序開發的都應該知道,咱們所作的大多數操做都是對數據庫的四格操做 「增刪改查」 對應到咱們的接口操做分別是:linux
post
插入新數據delete
刪除數據put
修改數據get
查詢數據
注意,這裏是咱們約定,並不是這些動做只能幹這件事情。從表層來講,除
get
外的其餘方法,沒有什麼區別,都是同樣的。從深層來講包括get
在內的全部方法都是如出一轍的,沒有任何區別。可是,咱們約定,每種動做對應不一樣的操做,這樣方便咱們統一規範咱們的全部操做。webpack
假設,咱們的接口是 /api/v1/love
這樣的接口,採用 RESTful
接口風格對應操做是以下的:
get
操做 /api/v1/love
獲取 /api/v1/love
的分頁列表數據,獲得的主體,將是一個數組,咱們能夠用數據來遍歷循環列表
post
操做 /api/v1/love
咱們會往 /api/v1/love
插入一條新的數據,咱們插入的數據,將是JOSN
利用對象傳輸的。
get
操做 /api/v1/love/1
咱們獲取到一個 ID 爲 1 的的數據,數據通常爲一個對象,裏面包含了 1 的各項字段信息。
put
操做 /api/v1/love/1
咱們向接口提交了一個新的信息,來修改 ID 爲 1 的這條信息
delete
操做 /api/v1/love/1
咱們向接口請求,刪除 ID 爲 1 的這一條數據
由上述例子可知,咱們實現了5種操做,但只用了兩個接口地址, /api/v1/love
和 /api/v1/love/1
。因此,採用這種接口風格,能夠大幅的簡化咱們的接口設計。
1、安裝 nodejs 環境
你能夠在 https://nodejs.org/
nodejs 官方網站下載安裝包,而後進行安裝。若是是 linux
或者 mac
命令行的用戶,也可使用命令行安裝。
在安裝好了 nodejs
以後,咱們在終端中輸入如下兩個命令:
node -v
npm -v
可以獲得版本號信息,則說明你的 nodejs 環境已經安裝完成了。
2、安裝 vue-cli VUE的腳手架工具
咱們首先安裝全局vue-cil
腳手架,用於幫助搭建所需的模板框架,命令以下:
npm install -g vue-cli
# 回車,等待安裝...
vue
# 回車,若出現vue信息說明表示成功
這個命令只須要運行一次就能夠了。安裝上以後,之後就不用安裝了。
下面,咱們來用vue-cil構建一個項目。
首先,咱們在終端中把當前目錄定位到你準備存放項目的地方。如我是準備放在~/Sites/MyWork/
這個目錄下面,那麼個人命令以下:
cd ~/Sites/MyWork
(也能夠直接在目錄內打開終端)進入到目錄以後,咱們按照下面的代碼逐條輸入,新建一個本身的vue
項目,vuedemo是本身起的項目名稱
vue init webpack vuedemo
# 這裏須要進行一些配置,默認回車便可
? Project name vuedemo
? Project description A Vue.js project
? Author
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Set up unit tests Yes
? Pick a test runner jest
? Setup e2e tests with Nightwatch? Yes
? Should we run `npm install` for you after the project has been created? (reco
mmended) npm
vue-cli · Generated "vuedemo".
# Project initialization finished!
# ========================
To get started:
cd vuedemo
npm install
npm run dev
Documentation can be found at https://vuejs-templates.github.io/webpack如上圖所示,就說明咱們的項目構建成功了。而且,給出了下面要執行的命令,咱們進入項目,安裝並運行:
#在cmd輸入項目名
cd vuedemo
#回車,進入到具體項目文件夾
npm install
#回車,等待一小會兒
#回到項目文件夾,會發現項目結構裏,多了一個node_modules文件夾(該文件裏的內容就是以前安裝的依賴)
最後,執行下面一句,把項目跑起來
npm run dev
DONE Compiled successfully in 4388ms
> Listening at http://localhost:8080
成功執行以上命令後訪問 http://localhost:8080/,輸出結果
進入項目文件夾後
vue init webpack vuedemo
新建一個項目進入項目
cd vuedemo
建立項目
npm install
運行項目
npm run dev
固然,這個名字你是能夠隨便起的,根據你的實際項目來定。
經過上面的這些命令,咱們就實現了新建一個vue+webpack
的項目。在運行了npm run dev
以後,會自動打開一個瀏覽器窗口,就能夠看到實際的效果了。
JavaScript Standard
在建立項目時咱們有開啓了一個standard語法效驗,JavaScript 代碼規範,自帶 linter & 代碼自動修正。
官網:https://standardjs.com/readme-zhcn.html
主要的語法規則有:
- 使用兩個空格 – 進行縮進
- 字符串使用單引號 – 須要轉義的地方除外
- 再也不有冗餘的變量 – 這是致使 大量 bug 的源頭!
- 無分號 – 這沒什麼很差。不騙你!
- 行首不要以
(
,[
, or`
開頭- 這是省略分號時惟一會形成問題的地方 – 工具裏已加了自動檢測!
- 詳情
- 關鍵字後加空格
if (condition) { ... }
- 函數名後加空格
function name (arg) { ... }
- 堅持使用全等
===
摒棄==
一但在須要檢查null || undefined
時可使用obj == null
。 - 必定要處理 Node.js 中錯誤回調傳遞進來的
err
參數。 - 文件末尾留一空行
- 使用瀏覽器全局變量時加上
window
前綴 –document
和navigator
除外- 避免無心中使用到了這些命名看上去很普通的全局變量,
open
,length
,event
還有name
。
- 避免無心中使用到了這些命名看上去很普通的全局變量,
- 查看更多 – 爲什麼不試試
standard
規範呢!
3、
1 ├── README.md // 項目說明文檔 2 ├── node_modules // 項目依賴包文件夾 3 ├── build // 編譯配置文件,通常不用管 4 │ ├── build.js 5 │ ├── check-versions.js 6 │ ├── dev-client.js 7 │ ├── dev-server.js 8 │ ├── utils.js 9 │ ├── vue-loader.conf.js 10 │ ├── webpack.base.conf.js 11 │ ├── webpack.dev.conf.js 12 │ └── webpack.prod.conf.js 13 ├── config // 項目基本設置文件夾 14 │ ├── dev.env.js // 開發配置文件 15 │ ├── index.js // 配置主文件 16 │ └── prod.env.js // 編譯配置文件 17 ├── index.html // 項目入口文件 18 ├── package-lock.json // npm5 新增文件,優化性能 19 ├── package.json // 項目依賴包配置文件 20 ├── src // 咱們的項目的源碼編寫文件 21 │ ├── App.vue // APP入口文件 22 │ ├── assets // 初始項目資源目錄,回頭刪掉 23 │ │ └── logo.png 24 │ ├── components // 組件目錄 25 │ │ └── Hello.vue // 測試組件,回頭刪除 26 │ ├── main.js // 主配置文件 27 │ └── router // 路由配置文件夾 28 │ └── index.js // 路由配置文件 29 └── static // 資源放置目錄
如上圖所示,咱們的目錄結構就是這樣的了。
咱們絕大多數的操做,就是在 src
這個目錄下面。默認的 src
結構比較簡單,咱們須要從新整理。
另外 static
資源目錄,咱們也須要根據放置不一樣的資源,在這邊構建不一樣的子文件夾。
咱們來配置 src 目錄
先不要管這些文件的內容,咱們先創建這些空的文件在這邊。而後咱們後面去完善它。
咱們的這個項目是要作兩個頁面,一個是 cnodejs
的列表頁面,一個是詳情頁面。
因此,我把項目文件夾整理成以下的結構
1 ├── App.vue // APP入口文件 2 ├── api // 接口調用工具文件夾 3 │ └── index.js // 接口調用工具 4 ├── components // 組件文件夾,目前爲空 5 ├── config // 項目配置文件夾 6 │ └── index.js // 項目配置文件 7 ├── frame // 子路由文件夾 8 │ └── frame.vue // 默認子路由文件 9 ├── main.js // 項目配置文件 10 ├── page // 咱們的頁面組件文件夾 11 │ ├── content.vue // 準備些 cnodejs 的內容頁面 12 │ └── index.vue // 準備些 cnodejs 的列表頁面 13 ├── router // 路由配置文件夾 14 │ └── index.js // 路由配置文件 15 ├── style // scss 樣式存放目錄 16 │ ├── base // 基礎樣式存放目錄 17 │ │ ├── _base.scss // 基礎樣式文件 18 │ │ ├── _color.scss // 項目顏色配置變量文件 19 │ │ ├── _mixin.scss // scss 混入文件 20 │ │ └── _reset.scss // 瀏覽器初始化文件 21 │ ├── scss // 頁面樣式文件夾 22 │ │ ├── _content.scss // 內容頁面樣式文件 23 │ │ └── _index.scss // 列表樣式文件 24 │ └── style.scss // 主樣式文件 25 └── utils // 經常使用工具文件夾 26 └── index.js // 經常使用工具文件
由於咱們刪除了一些默認的文件,因此這個時候項目必定是報錯的,先無論他,咱們根據咱們的需求,新建如上的項目結構。這些都是在 src
目錄裏面的結構。
4、調整app.vue和設置路由
1.調整 App.vue 文件
咱們先把默認項目裏面沒用的東西先刪除掉,把代碼調整爲下面的樣子。
1 <template> 2 <div id="app"> 3 <router-view></router-view> 4 </div> 5 </template> 6 7 <script> 8 export default { 9 name: 'app' 10 } 11 </script> 12 13 <style lang="css"> 14 @import "./style/index.css"; 15 </style>
入口,只有一個空的路由視窗,咱們的項目的全部內容,都基於這個視窗來展示。由於scss文件容易出現語法錯誤,這裏先用css文件替代。後期熟悉以後再更改
咱們的樣式,都將從 src/style/index.css
這個文件中引用,若是沒有請按路徑新建!
2.調整 index.vue 和 content.vue 文件
昨天,咱們在 page
文件夾下面創建了兩個空文本文件 index.vue
和 content.vue
文件,是咱們準備用來放列表和內容的。
這裏,咱們先去填寫一點基礎內容在裏面。
index.vue
1 <template> 2 <div>index page</div> 3 </template>
content.vue
1 <template> 2 <div>content page</div> 3 </template>
好,寫上如上的代碼就行,咱們後面再豐富這些內容。
3.調整 router 路由文件
如今,這個項目還跑不起來呢,若是你運行 npm run dev
仍是會出錯的。由於咱們尚未配置路由。
1 import Vue from 'vue' 2 import Router from 'vue-router' 3 import Hello from '@/components/Hello' 4 5 Vue.use(Router) 6 7 export default new Router({ 8 routes: [ 9 { 10 path: '/', 11 name: 'Hello', 12 component: Hello 13 } 14 ] 15 })
以上,是默認的路由文件,引用了一個 Hello
的組件,這個組件被咱們昨天的博文中整理文件結構的時候刪除掉了。因此,這裏就報錯啦。
咱們根據咱們的須要,來調整這個路由文件,以下:
1 import Vue from 'vue' 2 import Router from 'vue-router' 3 import Index from '@/page/index' 4 import Content from '@/page/content' 5 6 Vue.use(Router) 7 8 export default new Router({ 9 routes: [ 10 { 11 path: '/', 12 component: Index 13 }, { 14 path: '/content/:id', 15 component: Content 16 } 17 ] 18 })
默認,咱們的首頁,就是咱們的 index.vue 組件,這裏,你可能要問 :id
是什麼意思?
由於咱們的內容頁面是要展現N條內容的,咱們如何來區分這些內容呢,就是根據ID來進行區分。因此,這裏使用了動態路由匹配。
更多內容,能夠參考官方文檔《動態路由匹配》
好,咱們如今,項目應該是沒有任何錯誤,能夠跑起來了。忘記跑起來的命令了?以下:
npm run dev
五。配置axios api接口調用文件
咱們經過配置基本的信息,已經讓咱們的項目可以正常的跑起來了。可是,這裏尚未涉及到 AJAX
請求接口的內容。
vue
自己是不支持 ajax
接口請求的,因此咱們須要安裝一個接口請求的 npm
包,來使咱們的項目擁有這個功能。
這實際上是一個重要的
unix
思想,就是一個工具只作好一件事情,你須要額外的功能的時候,則須要安裝對應的軟件來執行。若是你之前是一個jquery
重度用戶,那麼可能理解這個思想必定要深刻的理解。
支持 ajax
的工具備不少。一開始,我使用的是 superagent
這個工具。可是我發現近一年來,絕大多數的教程都是使用的 axios
這個接口請求工具。其實,這原本是沒有什麼差異的。可是爲了防止大家在看了個人博文和其餘的文章以後,產生理念上的衝突。所以,我也就改用 axios
這個工具了
自己, axios
這個工具已經作了很好的優化和封裝。可是,在使用的時候,仍是略顯繁瑣,所以,我從新封裝了一下。固然,更重要的是,封裝 axios
這個工具是爲了和我之前寫的代碼的兼容。不過我封裝得很好,也推薦你們使用。
1.封裝 axios 工具,編輯 src/api/index.js 文件
首先,咱們要使用 axios
工具,就必須先安裝 axios
工具。執行下面的命令進行安裝
npm install axios -D
這樣,咱們就安裝好了 axios 工具了。
還記得咱們在第三篇博文中整理的系統結構嗎?咱們新建了一個 src/api/index.js 這個空文本文件,就那麼放在那裏了。這裏,咱們給它填寫上內容。
// 配置API接口地址 var root = 'https://cnodejs.org/api/v1' // 引用axios var axios = require('axios') // 自定義判斷元素類型JS function toType (obj) { return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase() } // 參數過濾函數 function filterNull (o) { for (var key in o) { if (o[key] === null) { delete o[key] } if (toType(o[key]) === 'string') { o[key] = o[key].trim() } else if (toType(o[key]) === 'object') { o[key] = filterNull(o[key]) } else if (toType(o[key]) === 'array') { o[key] = filterNull(o[key]) } } return o } /* 接口處理函數 這個函數每一個項目都是不同的,我如今調整的是適用於 https://cnodejs.org/api/v1 的接口,若是是其餘接口 須要根據接口的參數進行調整。參考說明文檔地址: https://cnodejs.org/topic/5378720ed6e2d16149fa16bd 主要是,不一樣的接口的成功標識和失敗提示是不一致的。 另外,不一樣的項目的處理方法也是不一致的,這裏出錯就是簡單的alert */ function apiAxios (method, url, params, success, failure) { if (params) { params = filterNull(params) } axios({ method: method, url: url, data: method === 'POST' || method === 'PUT' ? params : null, params: method === 'GET' || method === 'DELETE' ? params : null, baseURL: root, withCredentials: false }) .then(function (res) { if (res.data.success === true) { if (success) { success(res.data) } } else { if (failure) { failure(res.data) } else { window.alert('error: ' + JSON.stringify(res.data)) } } }) .catch(function (err) { let res = err.response if (err) { window.alert('api error, HTTP CODE: ' + res.status) } }) } // 返回在vue模板中的調用接口 export default { get: function (url, params, success, failure) { return apiAxios('GET', url, params, success, failure) }, post: function (url, params, success, failure) { return apiAxios('POST', url, params, success, failure) }, put: function (url, params, success, failure) { return apiAxios('PUT', url, params, success, failure) }, delete: function (url, params, success, failure) { return apiAxios('DELETE', url, params, success, failure) } }
有關 axios
的更多內容,請參考官方 github
: https://github.com/mzabriskie/axios ,中文資料自行百度。
但就是這樣,咱們還不能再 vue
模板文件中使用這個工具,還須要調整一下 main.js
文件。
2.調整 main.js 綁定 api/index.js 文件
此次呢,咱們沒有上來就調整 main.js
文件,由於原始文件就配置得比較好,我就沒有刻意的想要調整它。
原始文件以下:
1 import Vue from 'vue' 2 import App from './App' 3 import router from './router' 4 5 Vue.config.productionTip = false 6 7 /* eslint-disable no-new */ 8 new Vue({ 9 el: '#app', 10 router, 11 template: '<App/>', 12 components: { App } 13 })
咱們插入如下代碼:
1 // 引用API文件 2 import api from './api/index.js' 3 // 將API方法綁定到全局 4 Vue.prototype.$api = api
也就是講代碼調整爲:
import Vue from 'vue' import App from './App' import router from './router' // 引用API文件 import api from './api/index.js' // 將API方法綁定到全局 Vue.prototype.$api = api Vue.config.productionTip = false /* eslint-disable no-new */ new Vue({ el: '#app', router, template: '<App/>', components: { App } })
好了,這樣,咱們就能夠在項目中使用咱們封裝的 api
接口調用文件了。
3.測試一下看看能不能調通
咱們來修改一下 src/page/index.vue
文件,將代碼調整爲如下代碼:
1 <template> 2 <div>index page</div> 3 </template> 4 <script> 5 export default { 6 created () { 7 this.$api.get('topics', null, r => { 8 console.log(r) 9 }) 10 } 11 } 12 </script>
好,這裏是調用 cnodejs.org
的 topics
列表接口,而且將結果打印出來。
咱們在瀏覽器中打開控制檯,看看 console
下面有沒有輸出入下圖同樣的內容。若是有的話,就說明咱們的接口配置已經成功了。
好,若是你操做正確,代碼沒有格式錯誤的話,那麼如今應該獲得的結果是和我同樣的。若是出錯或者怎麼樣,請仔細的檢查代碼,看看有沒有什麼問題。
6、將接口用webpack代理到本地
咱們已經很是順利的調用到了 cnodejs.org
的接口了。可是,咱們能夠注意到咱們的 src/api/index.js
的第一句,就是:
1 // 配置API接口地址 2 var root = 'https://cnodejs.org/api/v1'
這裏,咱們將接口地址寫死了。
固然,這並非最重要的事情,而是 cnodejs.org
幫咱們把接口處理得很好,解決了跨域的問題。而咱們的實際項目中,不少接口都是不容許咱們這樣跨域請求的。
而咱們的開發環境下,不可能跑到服務器上直接開發,或者在本地直接搞一個服務器環境,這樣就違背了咱們先後端分離開發的初衷了。
如何解決這個問題呢?其實很是好辦,要知道 跨域不是接口的限制 而是瀏覽器爲了保障數據安全作的限制。所以,一種方法能夠解決,那就是打開瀏覽器的限制,讓咱們能夠順利的進行開發。可是無奈的是,最新的 chrome
瀏覽器好像已經關閉了這個選項,那麼咱們只能採用另一種方法了——將接口代理到本地。
1.配置 webpack 將接口代理到本地
好在,vue-cli
腳手架工具,已經充分的考慮了這個問題,咱們只要進行簡單的設置,就能夠實現咱們的目的。
咱們打開 config/index.js
文件,找到如下代碼:
1 dev: { 2 env: require('./dev.env'), 3 port: 8080, 4 autoOpenBrowser: true, 5 assetsSubDirectory: 'static', 6 assetsPublicPath: '/', 7 proxyTable: {}, 8 cssSourceMap: false 9 }
其中,proxyTable: {},
這一行,就是給咱們配置代理的。
根據 cnodejs.org
的接口,咱們把這裏調整爲:
1 proxyTable: { 2 '/api/v1/**': { 3 target: 'https://cnodejs.org', // 你接口的域名 4 secure: false, 5 changeOrigin: false, 6 } 7 }
OK,咱們這樣配置好後,就能夠將接口代理到本地了。
更多接口參數配置,請參考 https://github.com/chimurai/http-proxy-middleware#options
webpack
接口配置文檔 https://webpack.js.org/configuration/dev-server/#devserver-proxy
2.從新配置 src/api/index.js 文件
好,上面已經代理成功了,可是咱們的 src/api/index.js
文件,仍是直接調用的人家的地址呢,咱們要調整爲咱們的地址,調整以下:
1 // 配置API接口地址 2 var root = '/api/v1'
以前我有一篇博文,說過如何配置開發接口地址和生產接口地址,當時是利用了 webpack
的不一樣的配置文件來進行配置的。若是咱們採用這種代理模式呢,那麼就沒有必要那麼作了。由於咱們的系統放到生產環境的時候,通常是沒有這個跨域問題的。這個問題通常僅僅是存在於咱們的開發環境下面。
值得注意的事情是,配置完成後,是不會當即生效的,咱們須要重啓咱們的項目。
咱們按 ctrl + c
中止掉以前的服務,而後從新輸入命令 npm run dev
重啓項目,就能夠了。
如上圖所示,咱們能夠清晰的看到,咱們跑的服務,先開啓了一個代理。
從新跑起來以後,咱們看下咱們的項目在瀏覽器中的表現:
咱們打開瀏覽器控制檯,切換到 network
選項卡中,選中咱們調用的接口 topics
接口,咱們能夠清晰的看到,咱們讀取的接口地址是咱們的本地代理過來的地址。
狀態碼爲 304
表明這個數據沒有發生變化,直接讀取本地緩存了。關於 http 狀態碼
的部分,請參考 百度百科 http 狀態碼,這裏不作過多的說明。
咱們再看一下數據是否是正常的過來了。切換到 Previdw
選項卡查看:
沒有問題,數據過來了。
好,到這裏,咱們已經順利的將接口代理到本地,而且數據讀取出來了。咱們開始準備下面的工做吧!
7.初識*.vue文件,即VUE組件
*.vue
文件,是一個自定義的文件類型,用類 HTML
語法描述一個 Vue
組件。每一個 .vue
文件包含三種類型的頂級語言塊 <template>
, <script>
和 <style>
。這三個部分分別表明了 html
,js
,css
。
其中 <template>
和 <style>
是支持用預編譯語言來寫的。好比,在咱們的項目中,咱們能夠用 scss
預編譯,咱們能夠這樣寫的:
1 <style lang="scss">
html
也有本身的預編譯語言, vue
也是支持的,不過通常來講,咱們前端人員仍是比較中意 html
原生語言,因此,我就不過多闡述了。
另外,我在
App.vue
文件中,已經用一句@import "./style/style";
將咱們的樣式給寫到指定的地方去了。因此,在後面全部的個人文章中,是不會出現這個部分的內容的。全部樣式,都會在src/style/
文件夾中對應的位置去寫。
我這樣作的好處是,不須要重複的引入各類scss
基礎文件,而且作到了項目的樣式代碼的可管控
1.一個常見的 *.vue 文件代碼解析
首先,咱們來簡單看一下:
1 <template> 2 <div> 3 <Header></Header> 4 <div class="article_list"> 5 <ul> 6 <li></li> 7 </ul> 8 </div> 9 <Footer></Footer> 10 </div> 11 </template> 12 <script> 13 import Header from '../components/header.vue' 14 import Footer from '../components/footer.vue' 15 export default { 16 components: { Header, Footer }, 17 data () { 18 return { 19 list: [] 20 } 21 }, 22 created () { 23 this.getData() 24 }, 25 methods: { 26 getData () { 27 this.$api.get('topics', null, r => { 28 console.log(r) 29 }) 30 } 31 } 32 } 33 </script> 34 <style> 35 .article_list {margin: auto;} 36 </style>
好,以上就是一個簡單的 *.vue
文件的基本結構。咱們一部分一部分的來解釋。
如下,我再也不稱呼它爲 *.vue
文件了。改爲爲 vue
組件。
2.template 部分
首先,一個 vue
組件,他的 template
則表明它的 html
結構,相信你們能夠理解了。可是須要注意的是,咱們不是說把代碼包裹在 <template></template>
中就能夠了,而是必須在裏面放置一個 html
標籤來包裹全部的代碼。 本例子中,咱們採用了 <div></div>
標籤。vue2.x
開始,就必須這樣去寫。這是規定
你們看到 <Header></Header>
這個代碼的時候確定很奇怪,這是個什麼玩意兒。其實,這是一個自定義組件。咱們在其餘地方寫好了一個組件,而後就能夠用這種方式引入進來。
一樣 <Footer></Footer>
也是一個組件。再也不累述。
其餘的內容,咱們就想這麼寫就怎麼寫了。和寫咱們的 html
代碼沒有什麼太大的區別。
3.script 部分
首先,咱們須要兩個自定義組件,咱們先引用進來。以下格式,比較好理解吧。
1 import Header from '../components/header.vue' 2 import Footer from '../components/footer.vue'
其次,除了引用的文件,咱們將全部的代碼包裹於以下的代碼中間:
1 export default { 2 // 這裏寫你的代碼,外面要包起來。 3 }
4.style 部分
這裏比較簡單,就是針對咱們的 template
裏內容出現的 html
元素寫一些樣式。如上,個人代碼:
1 <style> 2 .article_list {margin: auto;} 3 </style>
就是給咱們的 .article_list
元素隨便加了一個樣式。
參考資料:《vue 模板語法》
8、渲染列表
1.製做 header.vue 和 footer.vue 組件文件。
不是本篇文章的重點,可是仍是有比較講一下。在第三篇博文中,咱們規劃了咱們的項目文件結構,當時保留了一個 components
的空文件夾。這裏,就是準備放咱們的自定義組件的。
首先,咱們去建立兩個空文本文件,分別是 header.vue
文件和 footer.vue
文件。
而後,往裏面輸入下面的內容:
header.vue
1 <template> 2 <header class="header"> 3 <h1 class="logo">Vue Demo by DEMO</h1> 4 </header> 5 </template>
footer.vue
1 <template> 2 <footer class="copy"> 3 Copy © DEMO
4 </footer> 5 </template>
很是簡單的兩個文件,表示咱們的組件已經弄好了
2.編寫 src/page/index.vue 文件
1 <template> 2 <div> 3 <Header></Header> 4 <div class="article_list"> 5 <ul> 6 <li v-for="i in list" :key="i.id"> 7 <time v-text="i.create_at"></time> 8 <router-link :to="'/content/' + i.id"> 9 {{ i.title }} 10 </router-link> 11 </li> 12 </ul> 13 </div> 14 <Footer></Footer> 15 </div> 16 </template> 17 <script> 18 import Header from '../components/header.vue' 19 import Footer from '../components/footer.vue' 20 export default { 21 components: { Header, Footer }, 22 data () { 23 return { 24 list: [] 25 } 26 }, 27 created () { 28 this.getData() 29 }, 30 methods: { 31 getData () { 32 this.$api.get('topics', null, r => { 33 this.list = r.data 34 }) 35 } 36 } 37 } 38 </script>
如上,代碼,我就把頁面渲染出來了。咱們看下實際的效果:
如上,我先用了一個 v-for
的循環,來循環數據。這裏能夠參考:https://cn.vuejs.org/v2/api/#v-for 文檔。
在 time
標籤中,我使用了 v-text="i.create_at"
來渲染時間數據。參考文檔: https://cn.vuejs.org/v2/api/#v-text
router-link
是 VueRouter2
「聲明式導航」的寫法,在實際轉換爲 html
標籤的時候,會轉化爲 <a></a>
,裏面的 to
屬性,就至關於 a
的 href
屬性。參考文檔:https://router.vuejs.org/zh-cn/essentials/getting-started.html
3.編寫 src/utils/index.js 文件
如上面的圖片所示,因爲拿到的數據是一個標準的時間格式,直接渲染在頁面上,這個效果不是很理想。所以,咱們能夠把時間給處理一下,而後再渲染出來。
這裏,咱們能夠直接在 getData () {...}
後面再寫一個方法便可。可是,在一個項目中,若是全部的地方都是這樣的時間格式,咱們在每個組件中都來寫這樣的處理方法,很顯然就顯得咱們比較愚蠢了。
所以,咱們能夠獨立出來寫一個方法,而後在全部的地方均可以使用,這樣就比較方便了。
還記得咱們在第三篇博文中,咱們創建了一個 src/utils/index.js
的空文本文件嗎?這裏,咱們要用上了。
直接給代碼以下:
1 export default { 2 goodTime (str) { 3 let now = new Date().getTime() 4 let oldTime = new Date(str).getTime() 5 let difference = now - oldTime 6 let result = '' 7 let minute = 1000 * 60 8 let hour = minute * 60 9 let day = hour * 24 10 let month = day * 30 11 let year = month * 12 12 let _year = difference / year 13 let _month = difference / month 14 let _week = difference / (7 * day) 15 let _day = difference / day 16 let _hour = difference / hour 17 let _min = difference / minute 18 19 if (_year >= 1) { 20 result = '發表於 ' + ~~(_year) + ' 年前' 21 } else if (_month >= 1) { 22 result = '發表於 ' + ~~(_month) + ' 個月前' 23 } else if (_week >= 1) { 24 result = '發表於 ' + ~~(_week) + ' 周前' 25 } else if (_day >= 1) { 26 result = '發表於 ' + ~~(_day) + ' 天前' 27 } else if (_hour >= 1) { 28 result = '發表於 ' + ~~(_hour) + ' 個小時前' 29 } else if (_min >= 1) { 30 result = '發表於 ' + ~~(_min) + ' 分鐘前' 31 } else { 32 result = '剛剛' 33 } 34 return result 35 } 36 }
好,代碼噁心了點,我拿我之前寫的代碼改的,沒有深刻優化,你們就隨便看看,大概就是這麼個東西。
寫好代碼以後,咱們保存文件。可是此時,咱們還不能使用咱們的這個方法函數。咱們必須在 main.js
中將咱們的方法函數給綁定上。以下代碼:
1 // 引用工具文件 2 import utils from './utils/index.js' 3 // 將工具方法綁定到全局 4 Vue.prototype.$utils = utils
好了,這樣,咱們寫的這個函數,就能夠隨便被咱們調用了。咱們再來修改一下咱們上面的 index.vue
中的代碼,將 time
調整爲:
1 <time v-text="$utils.goodTime(i.create_at)"></time>
而後,咱們再來看一下實際的效果:
好,咱們已經看到,時間已經搞的挺好的了。
9、把內容頁面渲染出來
前面咱們從文章中留下的引子 <router-link :to="'/content/' + i.id">
應該知道,咱們仍是要作內容頁面的。
1.編寫內容頁面
1 <template> 2 <div> 3 <myHeader></myHeader> 4 <h2 v-text="dat.title"></h2> 5 <p v-if="dat.author">做者:{{dat.author.loginname}}發表於:{{$utils.goodTime(dat.create_at)}}</p> 6 <hr> 7 <article v-html="dat.content"></article> 8 <h3>網友回覆:</h3> 9 <ul> 10 <li v-for="i in dat.replies"> 11 <p>評論者:{{i.author.loginname}}評論於:{{$utils.goodTime(i.create_at)}}</p> 12 <article v-html="i.content"></article> 13 </li> 14 </ul> 15 <myFooter></myFooter> 16 </div> 17 </template> 18 <script> 19 import myHeader from "../components/header.vue"; 20 import myFooter from "../components/footer.vue"; 21 export default { 22 components: { myHeader, myFooter }, 23 data() { 24 return { 25 id: this.$route.params.id, 26 dat: {} 27 }; 28 }, 29 created() { 30 this.getData(); 31 }, 32 methods: { 33 getData() { 34 this.$api.get("topic/" + this.id, null, r => { 35 this.dat = r.data; 36 }); 37 } 38 } 39 }; 40 </script>
好,咱們這邊把代碼寫進 src/page/content.vue
文件。而後保存,我在咱們先前的列表頁面隨便點開一篇文章,而後咱們看下結果:
10、打包項目併發布到子目錄
咱們已經完成了咱們設想的項目的開發。可是,咱們作好的這套東西,是基於 nodejs
開發的。而咱們最終但願,咱們開發的項目,生成好一堆文件,而後隨便經過任何一個 http
服務就能跑起來,也就是,還原成咱們熟悉的 html+css+js
的模式。
1.打包項目
們進入到終端,而且進入到咱們的開發目錄:
cd ~/Site/MyWork/vue-demo-cnodejs
而後運行以下代碼,進行打包:
npm run build
運行結果以下:
好,咱們已經打包好了。文件打包位置於項目目錄裏面的 dist
文件夾內。
可是,咱們從上圖能夠看到,咱們生成了一些 .map
的文件。這就有點噁心了。當咱們的項目變得比較大的時候,這些文件,第一個是,很是大,第二個,編譯時間很是長。因此,咱們要把這個文件給去掉。
咱們編輯 /config/index.js
文件,找到其中的
1 productionSourceMap: true,
修改成:
1 productionSourceMap: false,
而後咱們從新運行打包命令:
npm run build
沒用的 map
文件已經沒有了。
好,咱們能夠從上圖中看出,有一個 tip
。它告訴咱們,打包出來的文件,必須在 http
服務中運行,不然,不會工做。
2.安裝 http-server 啓動 http 服務
咱們進入 dist
文件夾,而後啓動一個 http
服務,來看看能夠不能夠訪問。
你可能不知道如何啓動這樣一個 http
服務,或者,你如今已經到 apache
裏面去進行配置去了。不用那麼麻煩,咱們有 nodejs
環境,只要全局安裝一個 http-server
服務就行了呀。
npm install http-server -g
好,經過這個命令,咱們就安裝好了。安裝好了以後正常咱們就可以使用 http-server
命令來跑服務了。可是,這個世界不正常的時候是不少的嘛!
在終端裏面輸入,
http-server
看可否正常啓動,仍是爆 -bash: http-server: command not found
錯誤,這裏,是說沒有找到這個命令,沒有關係,這是表示,咱們的 nodejs
的程序執行路徑,沒有添加到環境變量中去。
首先,如上圖所示,咱們的 http-server
安裝到了 /usr/local/Cellar/node/7.6.0/bin/
這個目錄下面,咱們只要把這個目錄,添加到環境變量便可。
請注意,你的安裝路徑可能和個人是不一致的,請注意調整。
咱們在終端內執行下面兩個命令,就能夠了。
echo 'export PATH="$PATH:/usr/local/Cellar/node/7.6.0/bin/"' >> ~/.bash_profile
. ~/.bash_profile
第一條命令是追加環境變量,第二個命令是,使咱們的追加當即生效。
固然,你也能夠直接編輯 ~/.bash_profile
文件,把上面命令中的單引號裏面的內容插入到文件最後面,而後執行第二個命令生效。隨便。
好,一個插曲結束。咱們要把咱們打包出來的東西跑起來呀!
cd dist
http-server -p 3000
若是你是嚴格按照個人教程來的,那麼如今已經能夠順利的跑起來了。咱們在瀏覽器中輸入 http://127.0.0.1:3000
就應該能夠訪問了。
固然,會報錯,說是接口找不到,404錯誤。由於咱們把接口給經過代理的方式開啓到了本地,可是這裏咱們並無開啓代理,因此就跑不起來了。很正常的。
這是由於示例的接口的問題。實際開發你還要按照個人這個作。只不過,最終代碼放到真實的服務器環境去和後端接口在一個 http
服務下面的話,就不存在這個問題了。
好,咱們就跑起來了。
3.將項目打包到子目錄
剛剛,咱們是將文件,打包爲根目錄訪問的。也就是說,必須在 dist
文件夾下面啓動一個服務,才能把項目跑起來。
可是咱們開發的大多數項目,多是必須跑在二級目錄,甚至更深層次的目錄的。怎麼作呢?
咱們編輯 config/index.js
文件,找到:
assetsPublicPath: '/',
把 '/'
修改成你要放的子目錄的路徑就好了。這裏,我要放到 /dist/
目錄下面。因而,我就把這裏修改成
1 assetsPublicPath: '/dist/',
而後,從新運行
npm run build
進行打包。
很快,就打包好了。
還記得,咱們在項目文件夾中用 npm run dev
就能夠開啓一個 http
服務嗎?而且那裏,咱們還代理了接口的。
好,咱們就這麼作。
而後咱們訪問二級目錄 /dist/
咱們就能夠看到效果了。
注意,我訪問的不是根目錄,而是 /dist/
這個子目錄哦,這裏是訪問的咱們打包的文件的。
1 ├── index.html 2 └── static 3 ├── css 4 │ └── app.d41d8cd98f00b204e9800998ecf8427e.css 5 └── js 6 ├── app.8ffccad49e36e43a4e9b.js 7 ├── manifest.7a471601ff5a8b26ee49.js 8 └── vendor.057dd4249604e1e9c3b5.js
好,到這裏,咱們的打包工做,就講完了。
實際開發中,你只須要把 dist
文件夾中打包好的文件,給運維他們,讓他們去部署到真實的服務器環境就行了。
11、打包項目圖片等資源的處理
1.在 vue 文件中,引用圖片
例如,咱們將一張圖片放到資源目錄 /static/image/lyf.jpg
咱們在 vue
文件中用下面的代碼來使用這張圖片。
1 <img src="static/image/lyf.jpg" alt="劉亦菲">
注意,最前面不要加 /
若是是這樣操做的話,會變成相對根目錄調用圖片。若是你的項目要打包到子目錄的話,這樣作就會出現問題。
2.在 css 文件中,引用圖片的處理
仍是上面那張圖片,咱們須要在 css
中來引用,如何來寫呢?
.love { background-image: url('../static/image/lyf.jpg'); }
好,這裏爲何要加上 ../
呢?
若是是最終打包到根目錄的話,可使用 /
這種路徑。這個是徹底能夠理解的。
但,若是是打包到子目錄,咱們必須看下生成的最終路徑:
├── index.html └── static ├── css │ └── app.a7a745952a8ca7f8c9413d53b431b8c8.css ├── image │ └── lyf.jpg ├── img │ └── lyf.9125a01.jpg └── js ├── app.39ccc604caeb34166b49.js ├── manifest.b1ad113c36e077a9b54d.js └── vendor.0b8d67613e49db91b787.js
如上,咱們能夠看到這個 css
相對 圖片
的路徑的地址。
你要疑問了,這樣的相對路徑,咱們可使用 ../image/lyf.jpg
來進行調用呀。嗯,看上去能夠,可是,若是是這樣的話,在開發模式中又會出錯了。
因此,仍是要用 '../static/image/lyf.jpg'
這樣的路徑方式來調用圖片。
字體圖標,js 文件等,都是這樣的路數。不在贅述。