如何通過 Vue-Cli3 - Vuex 完成一個 TodoList
昨天大概粗糙的瞭解了一下Vue的概況之後,並沒有從框架、語法的細節來進一步學習。那今天通過一個簡單的例項來繼續完善一下Vue這方面的空白,用一些看得見的效果摸的著的程式碼在不斷完成小目標的過程中慢慢消化一下相關的知識點。當然用一個簡單的例項來完全掌握Vue也不太現實,只是通過這樣一個例子來樹立學習的信心,瞭解Vue基礎知識點。
Vue-cli-todolist
,是一個用vue-cli3工具初始化專案,然後在此基礎上完成todolist的案例,相關的技術棧:Vue-cli3, Vue,VueRouter,Vuex
。Element-ui,IView, Vux
等UI元件為輔助。
先看一下我們完成的效果:
- vue-cli-todolist
- 參考自:所有前端技術實現的todomvc.com
- 尤大vue-totolist
1. 安裝Vue-cli
分享前的約定: 以下大部分命令步驟基於Mac系統,Windows系統差異點也會提到。
1.1 先在Github建立倉庫
為了保持程式碼能夠長期有效,也方便麵試時展示,建議將程式碼以Git的方式存放,比如:http://github.com
,http://gitee.com
,https://bitbucket.org/
等等。選擇任意一款新建倉庫:vue-cli-todolist
,git clone
倉庫到本地(Windows
系統建議非桌面的碟符路徑儲存,比如D:/vue-todolist),然後cd ..
iTerm
新建一個 tab 準備進行安裝Vue-cli
,留存當前的tab等安裝完成之後執行npm run serve
。
1.2 Vue-cli的作用
- 本地生成檔案和配置,減少繁瑣的配置,以最短的時間最小的檔案結構讓專案先跑起來,讓更多的精力關注開發本身。vue-cli3中vue.config.js不是必須,新建之後自動覆蓋預設設定。
- 那如果不使用vue-cli那怎麼辦?就是手動在本地創始化package.json,然後其它相應檔案手動建立手寫配置,效率低,出錯可能大。
1.3 Vue-cli的全域性安裝
如果有舊版vuecli先得解除安裝,然後才能安裝新版。
npm uninstall -g vue-cli vue -V
輸出:vue不是內外部命令時說明解除安裝成功,同樣,新版安裝成功通過這個命令來驗證。
- 安裝前提必須安裝nodejs,安裝完之後通過
node -v
來確定是否安裝成功,如果輸出類似v10.15.3
字樣表示安裝成功。//同時也安裝了npm
,輸入以下命令來確認npm -v
,如果輸入6.4.1
字樣表示安裝成功。 call:node - 通過
npm install -g @vue/cli
命令安裝最新版,其中-g
的意思是安裝到全域性,就像一個全域性變數一樣,以後在任何一個目錄都可以執行建立命令vue create
。
PS: 如果是使用Mac的同學此處可能需要增加sudo,完整的命令就是這樣:sudo npm install --global vue-cli
,否則會報這樣的錯誤Error: EACCES: permission denied, access '/usr/local/lib/node_modules'
,如果是Windows同學注意在右鍵用管理員方式開啟cmd。 vue create vue-cli-todolist
通過此命令在原來git clone專案的Tab中來建立一個專案。
這時會有三個選項選擇,
- Overwrite
- Merge
- Cancel
建議選擇Merge,如果是Overwrite會刪除.git隱藏檔案,導致不能進行git commit,安裝完成後通過vue -V
來驗證是否安裝成功,如果輸出3.7.0
這樣的字樣,就說明安裝成功了。
$ cd vue-test
$ npm run serve
根據命令列中提示的埠號,就可以預覽到一個基礎的專案頁面。
然後刪除根目錄下.gitignore檔案中的dist目錄,說明以後dist目錄也需要提交上傳,git提交程式碼,推送到遠端,在github倉庫重新整理頁面看到程式碼結構,說明程式碼遠端推送成功。
npm i vue-router -S
通過此命令來安裝路由元件,很多朋友剛開始不太會區分-S,-D的區別,這個-S表示上線依賴,是--save
縮寫,表示上線之後還需要存在的程式碼塊,比如Vue.js,對應package.json中的dependencies: {}
,-D表示開發依賴,是--save-dev
縮寫,表示只是在開發階段使用,上線之後只使用他的結果檔案就可以了,比如sass-loader, babel,對應package.json中的devDependencies: {}
。npm i sass-loader -D
通過此命令來安裝我們後面用到的scss,也可以通過一個命令用空格分隔安裝多個元件,比如:npm i sass-loader vue-loader -D
。
ps: call:npm
2. 路由的配置
增加路由的目的還是為了讓我們更方便的進行程式設計,比如:有些頁面需要使用者登入之後才能訪問?比如有些頁面進入之後後退就不讓他進入這個頁面?等等這樣的場景都可以通過路由來實現。
- 在
src
目錄下新建router.js
,引入相關的物件,然後use
,最後export
。
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'home',
component: () => import('@/views/home'),
}
],
})
- 這樣router路由我們就建好了,但是他還沒有被使用,所以還需要在main.js中引入之後被使用,這樣配置的路由才會起作用,根據路由訪問時才會跳轉到期望的畫面。
import router from './router'
new Vue({
router,
render: h => h(App),
}).$mount('#app')
- 然後重新整理頁面,多了一個
/#/
,最後顯示為http://localhost:8080/#/
,且顯示畫面沒有報錯,說明我們的路由配置檔案新增成功。
3. Sass-loader
加入scss的目的是讓我們更快更方便的方式編寫css
,瞭解一下。
需要在專案中使用scss
,只需要在.vue元件中的style中新增lang="scss",就可以使用了:
<style lang="scss">
</style>
//node-sass包比較難安裝,需要多次重新安裝。
- 但是新增之後命令工具報錯
Can't resolve 'sass-loader'
,這時候就需要我們通過命令npm i sass-loader -D
來安裝依賴。他主要的功能就是負責把scss編譯為css。 安裝完成之後,還是會報
Cannot find module 'node-sass'
,我們繼續npm i node-sass -D
安裝依賴。
安裝完成之後重新整理頁面還是報錯,這時候需要重新啟動服務了。具體步驟為先:ctrl+c
停止服務,然後輸入命令npm run serve
啟動,再重新整理頁面,畫面重現。- 因為這次的重點是Vue-cli,所以相關Html, CSS直接複用,剛好todo相關css已經有npm包,我們直接安裝相關css模組,
npm i todomvc-common todomvc-app-css -S
,然後在main.js中引入:
import 'todomvc-common/base.css'
import 'todomvc-app-css/index.css'
那到這一步我們前期的準備工作已經完成了,下面就是根據頁面特點進行元件的拆分了。
4. 元件
拆分元件的難點在於,組織結構上趨於分散,但資料處理上趨於集中,集中的資料便於管理或驅動頁面檢視。
元件是Vue開發當中最小的組成單元,以.vue副檔名結尾,他包括:Html結構, JS, CSS,資料流,監聽處理子元件觸發事件,引用子元件(ref)。
如何拆分是一個開發習慣,並沒有一個準確的原則,細拆可以拆分一個按鈕為一個元件單元,但拆的越細壞處是會造成頁面維護的困難,好處是頁面元件的複用性更好。如果拆的少,元件結構關係比較簡單,但是頁面元件複用性不高,最終要達到期望效果還是要平衡和取捨。
根據當前頁面的特點,大體拆分為以下四個部分,分別為:Header, List, Footer, Copyright,新建對應的*.vue檔案並且放置在vue-cli-todolist/src/components
目錄下,然後相應的元件在vue-cli-todolist/src/views/home.vue
中引入,然後在增加:
components:{ Header, List, Footer }
需要注意的是Copyright
在整個操作容器外部,所以放在App.vue
中。
4.1 home.vue
由於Vue單資料流的限制規則,此元件頁面是操作整個Todolist資料來源的總頁面,所有對資料的操作方法都彙總在此元件來實現,包括子元件對資料來源的操作。父級 prop 值的更新會向下傳遞,但不能反向傳遞,也不能在子元件直接修改 prop。這樣做的目的是為了防止從子元件意外改變父級元件的狀態,從而導致資料流向難以理解。其實對Todolist的操作,就是常說的是增刪改查,只是少了一個查詢而已,頁面上的常規操作就是對Todolist資料來源物件的的增加刪除修改,那對應的程式碼其實就是資料的push, splice, forEach
等方法。需要注意的是這些操作資料的結果都是基於瀏覽器的,重新整理之後並不存在,解決辦法後端介面儲存和本地儲存,本案例中通過localStorage儲存在本地。
然後我們找一行有特徵引入元件的方式來分析一下,比如:
<main-view :todos="filteredTodos" @del-todo="delTodo" @all-done="allDone"></main-view>
- main-view表示元件名稱,如果是全域性元件那名稱是唯一的。
- :todos="filteredTodos",冒號表示變數是動態的,如果不是冒號預設是String,todos表示子元件接受資料的變數名稱,filteredTodos表示當前頁面的變數名稱。子元件中通過props屬性來接受父元件傳來的資料,通過$emit的方法觸發事件然後在父元件修改資料,整個的資料即能靈活的傳下去,也能有效的迴轉回來。
- @del-todo="delTodo",@表示事件處理,del-todo為子元件$emit方法名,delTodo為當前元件事件處理方法名。元件資料通過
:todos="filteredTodos"
傳下去,然後通過@del-todo="delTodo" @all-done="allDone"
進行捕獲處理。
4.2 Header.vue
home.vue
中輸入<header>....</header>
,重新整理頁面之後發現並沒有達到期望的效果,只有<header>....</header>
的程式碼片段。這時候就發現元件名稱不能與HTML的原有標籤名稱重複,否則當普通的html標籤解析。修改Header.vue為HeaderView.vue之後重新整理頁面,得到期望結果頁面。另外的一個辦法就是大寫,比如:<Header>....</Header>
。
4.3 Main.vue
此頁面雖然Html元素不多,但需要處理的東西還是挺多,包括點選進行中處理,雙擊進入編輯狀態,.enter.blur事件退出編輯狀態,基本每個Html元素上都需要js程式碼的處理,這裡邊大概有這幾點分享:
4.3.1 template
- v-model
擴充套件為:
<input v-model="field" />
<input :value="field" @input="field = $event.target.value" />
每當輸入框內容發生變化時,就會觸發 oninput ,把最新的value傳遞給 field。
:class
- 物件語法 { active: isActive, 'text-danger': hasError },通過Boolean值控制是否有值
- 陣列語法 [activeClass, errorClass],通過變數合併顯示
文件:https://cn.vuejs.org/v2/guide/class-and-style.html
- @dblclick,@click
繫結事件的縮寫形式,完整的為:v-on:click="handle"
文件:https://cn.vuejs.org/v2/guide/events.html - {{ item.title }}
基礎變數顯示,原始html需要v-html="rawHtml"指令。
https://cn.vuejs.org/v2/guide/syntax.html - @keyup.enter.prevent
通過事件修飾符連寫,達到處理冒泡,阻止自定義事件等等的目的
https://cn.vuejs.org/v2/guide/events.html computed -> set || get
一般計算屬性預設都是getter,全選的處理需要主動的修改資料來源。
https://cn.vuejs.org/v2/guide/computed.html
4.3.2 script
- props接受資料,data初始化變數
- computed中allDone通過進行中的數量是否為零來有效的在初始化時得到全選的狀態。
- util方法就是對跨元件程式碼塊複用的封裝export然後import之後使用。
4.3.3 style
- vh
css3新單位,相對於視口的高度的百分比,視口被均分為100單位的vh,1vh = 視口高度的1%。
h1 {
font-size: 8vh;
}
如果視口的高度是200px,那麼上述程式碼中h1元素的字號將為16px,即(8x200)/100=16
4.4 Footer.vue
點選狀態每次切換需要切換畫面,畫面的變化依賴於路由,所以需要記錄路由名稱 this.current
,在home.vue中通過watch來實現:
'$route' (to) {
this.current = to.name
},
4.5 Copyright.vue
版權頁面佈局採用Flex形式佈局。擴充套件認識:Flex垂直水平居中對齊
5. main.js
如果說App.vue是專案的元件入口檔案的話那麼main.js就是專案的程式碼入口,所有相關js的初始化以及npm包的引用都在此檔案處理。ES6規定,import必須放在首行,有的元件需要Vue.use,有的則不需要。
Vue全家桶相關的Router, Vuex都需要在此檔案繫結。
6. package.json
- dependencies 上線依賴,npm i -S moduleName
- devDependencies 開發依賴 npm i -D moduleName
同時習慣於vue-cli2 npm run dev方式的同學,也可以在package.json中增加:
"scripts": {
"dev": "npm run serve",
"serve": "vue-cli-service serve"
}
可以用npm run dev繼續運行當前專案。
7. package-lock.json
記錄當前狀態下實際安裝的各個npm package的具體來源和版本號,package.json檔案只能鎖定大版本,也就是版本號的第一位,並不能鎖定後面的小版本你每次npm install都是拉取的該大版本下的最新的版本,為了穩定性考慮幾乎是不敢隨意升級依賴包的,這將導致多出來很多工作量,所以package-lock.json安裝一個依賴的時候就鎖定在你安裝的這個版本。
8. npm run build
在根目錄增加vue.config.js,css,js預設訪問根目錄,而我們釋出之後的目錄是http://www.host.com/dist/,多了一層dist,所以需要配置publicPath,否則控制檯報找不到資源的錯誤:
module.exports = {
publicPath: './',
productionSourceMap: false
}
至此為止,今天階段性的學習就到此告一段落了。學習到此處有疑問的同學,加QQ群:364912432
,Vue交流微信群需要加入QQ群之後邀請。
原始碼在這,vue-cli-todolist
如果還想進一步學習,那可以看我們這些分支:
帶m的移動端,由此可以發現,這個專案不但是可以學習入手的專案,也是可以做為相關其它UI元件Demo場地,再加個路由就可以自由的玩耍了:
dev-base
: 是基礎版,沒有Vuex的版本dev-vuex
: 是Vuex版本dev-element-ui
: 是element-ui版本dev-m-vux
: 是移動端vux版本,帶m的移動端dev-base
: 是基礎版gh-paes
: 線上預覽頁面分支