vue- Vue-Cli腳手架工具安裝 -創建項目-頁面開發流程-組件生命周期- -03
- 2019 年 10 月 11 日
- 筆記
本部落格環境
如果這些環境過時了,那就不用浪費時間看這部落格了
Vue-Cli 項目環境搭建
npm (就類似於手機的應用商城,python 中的 pip 也一樣)
與 python 基礎環境對比
- node ~ python 解釋器
- node 是 js 的解釋器,用 c++ 寫的
- npm ~ pip python 的庫管理工具(第三方模組下載的應用商店)
- npm 就類似於 pip ,也要換源(常用淘寶源 cnpm),下載才快
- vue ~ django
- 類似於 django 是一個大框架
環境搭建
- 安裝 node
node 官網下載安裝包,傻瓜式安裝:https://nodejs.org/zh-cn/
下面的命令都是在 命令行中 執行(-g
參數代表全局(global),會自動配置環境變數)
- 安裝 cnpm (使用淘寶鏡像源)
npm install -g cnpm --registry=https://registry.npm.taobao.org
- 安裝腳手架工具 vue/cli
cnpm install -g @vue/cli
- 清空快取處理(前兩步出錯了再執行這個(把那些下載錯誤的文件刪除掉))
npm cache clean --force
創建啟動 vue 項目
一定要注意當前命令行的目錄位置
可以用 webstorm 來編寫 vue 程式碼, 專門用來開發前端的,pycharm 的提示及便捷性不如它(自行了解)
命令創建項目(步驟小多)
先進入到存放項目的目錄下
cd /d E:PyCharm 2019.1.3ProjectFileday010day066
(項目將會放在 day66 這個文件夾下)
創建項目
vue create v-proj(項目名)
,輸入完後會進入到下面的介面
介面操作方式:鍵盤 上下(↑↓)箭頭 選擇要用那個模板,回車選中(進入下面的介面同樣用 上下箭頭 移動游標,按空格選取,回車確認)
我們選擇下面這個 Manually select features
來到下面這個頁面,來看看這些選項都啥意思
各選項
- Babel
- 把 ES6 語法轉換成 ES5 讓瀏覽器可以解析
- TypeScript
- 是 JavaScript 的超集(學起來會比 JavaScript 難一些)
- Progressive Web App (PWA) Support
- 有很多優化前台項目的組件(後期再用到)
- Router
- vue 前台的路由管理
- Vuex
- 相當於一個全局 單例,頁面未刷新有效,一刷新就沒了
- CSS Pre-processors
- less、sass –> 預編譯語言,寫的也是 css,但它可以寫邏輯,必須瀏覽器解析成原生 css 才有用,相對來說 less 會好學一點,兩個小時左右就能學會了
- Linter / Formatter
- 限制(團隊)程式碼風格(縮進空格個數之類的) ESLint 更嚴格
- Unit Testing
- 測試用的
- E2E Testing
- 測試用的
我們選擇下面的這幾個(空格選取)
回車下一步(再一路選大寫的就行)
history 讓 vue 的當頁面應用可以至此跳轉(其他的暫時默認即可)
默認配置如下
然後就會自動進行安裝
至此,vue 項目創建完成
啟動 vue 項目(命令行方式)
在命令行下,進入項目根目錄,執行 npm run serve
啟動項目
等待載入後,出現下面的頁面即可在瀏覽器上輸入 localhost:8080
訪問(vue 項目默認埠是 8080)
在瀏覽器上訪問
啟動 vue 項目(pycharm 方式)
命令行方式啟動有著諸多不便,所以我們還是選擇採用 pycharm 來啟動吧(其實 webstorm 對 vue 的支援會更好,但不是這裡的重點),下面是 pycharm 啟動需要做的一些配置
先右鍵項目文件夾,用 pycharm 打開
配置 pycharm 啟動
用 pycharm 的綠色的啟動按鈕啟動 vue 項目
頁面效果(至此,pycharm 即可啟動項目)
Vue 項目目錄結構分析
├── v-proj | ├── node_modules // 當前項目所有依賴,一般不可以移植給其他電腦環境(版本控制、備份程式碼 等等,這個文件一般都排除在外),在新環境下執行 cnpm install 即可重新安裝下載這個文件里的內容 | ├── public | | ├── favicon.ico // 瀏覽器標籤頁圖標(public/index.html 中的 <link rel="icon" href="<%= BASE_URL %>favicon.ico">) | | └── index.html // 當前項目唯一的頁面 | ├── src | | ├── assets // 用來存放靜態資源,如:img、css、js | | ├── components // 存放小組件(再老一些的版本 components 和 views 是一個文件夾) | | ├── views // 存放頁面組件(一般是路由跳轉的組件) | | ├── App.vue // 根組件 | | ├── main.js // 全局腳本文件(項目的入口) | | ├── router.js // 路由腳本文件(配置路由 url鏈接 與 頁面組件的映射關係) | | └── store.js // 倉庫腳本文件(vuex插件的配置文件,數據倉庫) | ├── README.md └ └── **配置文件... // "├" 輸入法 "v9" 可以找到這個符號
pycharm 支援 vue 語法
安裝 vue 插件
雙擊 App.vue 可以看到,沒有任何語法高亮,.vue 文件被識別成了普通文件,那麼我們可以通過安裝 vue 插件來解決這個問題
可以點圖中的 install plugins 來安裝 vue 插件(按提示安裝即可)
也可以在 pycharm 的 settings 里下載,下載完成重啟 pycharm 即可
重啟 pycharm 後, pycharm 就能識別 .vue 文件了,並且能夠為我們提供語法高亮(眼前又瞬間充滿了色彩)
部分 vue 文件剖析
自定義組件並渲染到頁面上
組件文件放在 components 下面,通常首字母大寫
組件通常由以下三部分組成
- template
- 裡面有且只有一個根標籤
- script
- 必須將
{}
導出(導出了外界才能導入)export default
- 外界導入時,將
{}
賦值給前面的變數(進行關聯)
- 必須將
- style
- style 標籤必須明確 scoped 屬性,代表該樣式只在組件內部起作用(樣式的組件化)
組件的導入與導出
寫程式碼的時候有些地方紅色波浪線可能是 ESLint 報錯,某個變數未被使用就會這樣,接著寫下去就好,不要太緊張
將組件導出(暴露出來)
組件需要將 實例?(內容豐富了長得很像 vue 實例)導出,外界才能使用
src/components/Test.vue
<template> <!-- template 里只能有一個根標籤(作為一個組件)--> <div class="test"> <p>Test 組件</p> </div> </template> <script> // 需要將其導出,外界才能導入,這個括弧相當於一個 vue 實例 export default { name: "Test" } </script> <style scoped> /* style 裡面的這個 scoped 可以用來限制樣式的控制範圍(僅對這個組件生效)(讓樣式局部化,避免造成 css 衝突)*/ p { color: red } </style>
父級組件導入(暴露出來的)組件
src/views/TestViews.vue
<template> <div class="home"> <!-- 3. 直接在頁面上渲染自定義標籤(在 .vue 結尾的文件中標籤可以區分大小寫(不像 html 文件,不能區分標籤的大小寫))--> <T></T> <!-- 到時候子組件會直接把這個替換掉 --> </div> </template> <script> // 1. 將組件導入,並賦值給 T (把子組件 export default 那個實例? 跟 變數T ? 關聯起來,在本(父)組件中就可以直接用 T 來當 Test 組件操作了) import T from '@/components/Test' // 這個 @ 就等價於 src 文件夾的絕對路徑 export default { // 2.註冊組件 components: { T, // 註冊 T 組件 } } </script>
在 routers.js 里配置路由
src/router.js
沒有 history 地址欄就會有 # 標識(localhost:8080/#/路由
)
import Vue from 'vue' import Router from 'vue-router' import Home from './views/Home.vue' // ****** 1. 先導入 ****** import Test from './views/TestViews' Vue.use(Router) export default new Router({ mode: 'history', // 讓 vue 這種單頁面應用也支援 瀏覽器的前進後退(← →) (可以展開搜索下) base: process.env.BASE_URL, routes: [ { path: '/', name: 'home', component: Home }, { path: '/about', name: 'about', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ './views/About.vue') }, // ****** 2. 註冊一條路由 ****** { path: '/test', // ****** 3. 一會兒直接訪問這個路由即可 localhost:8080/test ****** name: 'test', component: Test } ] })
瀏覽器訪問
localhost:8080/test
為什麼頁面上會有 Home | About 呢?我們剛剛又沒寫
為什麼頁面上會有 Home | About 呢? – 其實是根組件 App.vue
裡面寫了
src/App.vue (看裡面的 Home、| 、 About)
<template> <div id="app"> <div id="nav"> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> </div> <router-view/> </div> </template> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; } #nav { padding: 30px; } #nav a { font-weight: bold; color: #2c3e50; } #nav a.router-link-exact-active { color: #42b983; } </style>
全局腳本文件 main.js 解析(項目入口)
一般導入的時候會省略後綴,所以 同一文件夾下面盡量不要重名(導入可以忽略後綴)
默認寫法(創建 vue 項目自動生成的)
import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' // 新手教程的 使用提示 (要點 next next 的動畫) Vue.config.productionTip = false new Vue({ router, store, render: h => h(App) }).$mount('#app') // 等同於 el 掛載
解釋性寫法 我們比較能理解的寫法(只是相當於對上面的解釋)
import Vue from 'vue' // 載入vue環境 import App from './App.vue' // 載入根組件 import router from './router' // 載入路由環境 import store from './store' // 載入數據倉庫環境 Vue.config.productionTip = false new Vue({ el: '#app', router, store, render: function (readFn) { return readFn(App); }, });
vue 項目啟動生命周期
載入 mian.js 啟動項目
import Vue from 'vue'
為項目載入vue環境import App from './App.vue'
載入根組件用於渲染替換掛載點import router from './router'
載入路由腳本文件,進入路由相關配置
載入 router.js 文件
為項目提供路由服務,並載入已配置的路由(鏈接與頁面組件的映射關係)
註:不管當前渲染的是什麼路由,頁面渲染的一定是根組件,鏈接匹配到的頁面組件只是替換根組件中的 <router-view></router-view>
監測路由變化來做處理
vue 發生頁面跳轉的原理
如果請求鏈接改變(路由改變),router 里匹配到了,會把路由對應的 組件 拿出來,然後把根組件里的
<router-view></router-view>
標籤替換成 該組件
- 每次路由跳轉都會走一次組件的生命周期
參與文件
main.js 入口文件
該文件內容不變
import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' Vue.config.productionTip = false new Vue({ router, store, render: h => h(App) }).$mount('#app')
App.vue 項目根組件
常見項目的根組件( App.vue)都只寫下面這幾行程式碼
<template> <div id="app"> <!-- url路徑會載入不同的頁面組件 eg:/red => RegPage | /blue => BluePage 來替換router-view標籤,完成頁面的切換 --> <router-view></router-view> </div> </template>
views/RedPage.vue 自定義頁面組件
<template> <div class="red-page"> </div> </template> <script> export default { name: "RedPage", components: { }, } </script> <style scoped> .red-page { width: 100vw; height: 100vh; background-color: red; } </style>
views/BluePage.vue
<template> <div class="blue-page"> </div> </template> <script> export default { name: "BluePage", components: { } } </script> <style scoped> .blue-page { width: 100vw; height: 100vh; background-color: blue; } </style>
router.js 路由文件
import Vue from 'vue' import Router from 'vue-router' import Home from './views/Home.vue' import RedPage from "./views/RedPage"; import BluePage from "./views/BluePage"; Vue.use(Router); export default new Router({ mode: 'history', base: process.env.BASE_URL, routes: [ { path: '/', name: 'home', component: Home }, { path: '/red', name: 'red', component: RedPage }, { path: '/blue', name: 'blue', component: BluePage } ] })
全局樣式文件配置與應用
jQuery、BootStrap 這些外部環境,都需要在 main.js 里配
後期可能把路徑配置這些寫成一個配置文件
assets/css/global.css
/*html, body, h1, h2, ul, p {*/ *{ margin: 0; padding: 0; } ul { list-style: none; } a { color: black; text-decoration: none; }
main.js 中導入,讓它生效
import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' Vue.config.productionTip = false; // ********* 配置全局樣式 ********* import '@/assets/css/global.css' // new Vue({ // router, // store, // render: h => h(App) // }).$mount("#app"); new Vue({ el: '#app', router, store, render: function (readFn) { return readFn(App); }, });
小案例 – 封裝 Nav 導航欄組件
components/Nav.vue 新建子組件
採用 a 標籤會發生頁面跳轉刷新,重新載入了一次項目介面
–> 而 vue 是單頁面應用,通常採用
<router-link to="/路由"> </router-link>
處理跳轉
- 每次路由跳轉都會走一次組件的生命周期
<template> <div class="nav"> <!--採用 vue-router 完成頁面跳轉,不能採用 a 標籤(會發生頁面刷新,本質就是重新載入了一次項目介面)--> <ul> <li> <!--<a href="/">主頁</a>--> <router-link to="/">主頁</router-link> </li> <li> <router-link to="/red">紅頁</router-link> </li> <li> <router-link to="/blue">藍頁</router-link> </li> </ul> </div> </template> <script> export default { name: "Nav", } </script> <style scoped> .nav { width: 100%; height: 60px; background-color: orange; } .nav li { float: left; font: normal 20px/60px '微軟雅黑'; padding: 0 30px; } .nav li:hover { cursor: pointer; background-color: aquamarine; } .nav li.active { cursor: pointer; background-color: aquamarine; } </style>
views/HomePage.vue 新建視圖頁面
RedPage.vue與BluePage都是添加下方三個步驟程式碼
<template> <div class="home"> <!-- 3)使用Nav組件 --> <Nav></Nav> </div> </template> <script> // 1)導入Nav組件 import Nav from '@/components/Nav' export default { // 2)註冊Nav組件 components: { Nav, } } </script>
新增頁面三步驟
- 在views文件夾中創建視圖組件(.vue 文件)
- 在router.js文件中配置路由
- 設置路由跳轉,在指定路由下渲染該頁面組件(替換根組件中的router-view標籤)
- 渲染誰,(router-view)就替換成誰
案例
增加一個 tan 頁面 案例程式碼
views/TanPage.vue
<template> <div class="tan-page"> <Nav></Nav> </div> </template> <script> import Nav from '@/components/Nav' export default { name: "TanPage", components: { Nav } } </script> <style scoped> .tan-page { width: 100vw; height: 100vh; background-color: tan; } </style>
router.js
// ... import TanPage from "./views/TanPage"; export default new Router({ mode: 'history', base: process.env.BASE_URL, routes: [ // ... { path: '/tan', name: 'tan', component: TanPage } ] })
components/Nav.vue
... <li> <router-link to="/tan">土頁</router-link> </li> ...
組件生命周期(鉤子函數剖析)*****
基本概念
詳細的可以看 vue 官方 API (推薦好好看看官方文檔這塊的介紹)
組件的生命周期:一個組件從創建到銷毀的過程,就稱之為組件的生命周期
在組件創建到銷毀的過程中,會出現眾多關鍵的時間節點,如:
- 組件要創建了
- 組件創建完畢了
- 組件數據渲染完畢了
- 組件要被銷毀了
- 組件銷毀完畢了
- …等等 時間節點
每一個時間節點,vue 都為其提供了一個回調函數(在該組件到達該時間節點時,就會觸發對應的回調函數,在函數中就可以完成該節點需要完成的業務邏輯)
生命周期鉤子函數也是 vue 的實例成員
生命周期鉤子函數
vue 官方提供的生命周期鉤子函數
beforeCreate created beforeMount mounted beforeUpdate updated activated deactivated beforeDestroy destroyed errorCaptured
在 vue 組件的 script 的 export default 導出字典中直接寫鉤子函數
重點鉤子函數:created(其他函數根據需求來用)
一般該組件請求後台的數據,都是在該鉤子中完成
- 請求來的數據可以給頁面變數進行賦值(此時實例成員已經載入了)
- 該節點還只停留在虛擬 DOM 範疇,如果數據還需要做二次修改再渲染到頁面
- 可以在 beforeMount、mounted 鉤子中添加邏輯處理
export default { // ... beforeCreate() { console.log('組件創建了,但數據和方法還未提供'); // console.log(this.$data); // console.log(this.$options.methods); console.log(this.title); console.log(this.alterTitle); }, // 該鉤子需要掌握,一般該組件請求後台的數據,都是在該鉤子中完成 // 1)請求來的數據可以給頁面變數進行賦值 // 2)該節點還只停留在虛擬 DOM 範疇,如果數據還需要做二次修改再渲染到頁面, // 可以在beforeMount、mounted鉤子中添加邏輯處理 created() { console.log('組件創建了,數據和方法已提供'); // console.log(this.$data); // console.log(this.$options.methods); console.log(this.title); console.log(this.alterTitle); console.log(this.$options.name); }, destroyed() { console.log('組件銷毀完畢') } }
this.$options
可以拿到所有實例成員,包括自定義成員(好像會讓 vue 提前載入實例成員這些),一堆的屬性這些都在裡面(可以用它來取自定義屬性)vue 實例可以直接
this.屬性/方法
取到 實例成員 data、methods 的內容(做了封裝,可以直接拿到)vue 沒有
this.$method
這個成員屬性
根據請求路徑高亮路由標籤案例
<router-link to="/">主頁</router-link>
- router-link 最終會被解析為 a 標籤,用 to 完成指定路徑跳轉,但是不能添加系統事件(因為是組件標籤)
- 在 js 方法中可以用
this.$router.push('路徑')
完成 邏輯跳轉- 在 js 方法中可以用
this.$route.path
拿到當前請求的頁面路由
components/Nav.vue
this.$route、this.$router
可以好好了解一下(搜一下),一個管理路由數據,一個管理路由跳轉
<template> <div class="nav"> <!--採用vue-router完成頁面跳轉,不能採用a標籤(會發生頁面刷新,本質就是重新載入了一次項目介面)--> <ul> <li @click="changePage('/')" :class="{active: currentPage === '/'}"> <!--<a href="/">主頁</a>--> <!--<router-link to="/">主頁</router-link>--> 主頁 </li> <li @click="changePage('/red')" :class="{active: currentPage === '/red'}"> <!--<router-link to="/red">紅頁</router-link>--> 紅頁 </li> <li @click="changePage('/blue')" :class="{active: currentPage === '/blue'}"> <!--<router-link to="/blue">藍頁</router-link>--> 藍頁 </li> <li @click="changePage('/tan')" :class="{active: currentPage === '/tan'}"> <!--<router-link to="/tan">土頁</router-link>--> 土頁 </li> </ul> </div> </template> <script> export default { name: "Nav", data() { return { // 每渲染一個頁面,都會出現載入 Nav 組件,currentPage 就會被重置, // 1)在點擊跳轉事件中,將跳轉的頁面用 資料庫 保存,在鉤子函數中對 currentPage 進行數據更新 // currentPage: localStorage.currentPage ? localStorage.currentPage: '' // 2)直接在 created 鉤子函數中,獲取當前的 url 路徑,根據路徑更新 currentPage currentPage: '' } }, methods: { changePage(page) { // console.log(page); // 當 Nav 出現渲染,該語句就無意義,因為在 data 中將 currentPage 重置為空 // this.currentPage = page; // 有 bug,用戶不通過點擊,直接修改請求路徑完成頁面跳轉,資料庫就不會更新數據 // localStorage.currentPage = page; // 任何一個標籤的事件中,都可以通過 router 完成邏輯條件 // console.log(this.$route); // 管理路由數據 // console.log(this.$router); // 管理路由跳轉 this.$router.push(page); // 路由的邏輯跳轉 } }, // 當前組件載入成功,要根據當前實際所在的路徑,判斷單選激活標籤 created() { // console.log(this.$route.path); this.currentPage = this.$route.path; } } </script> <style scoped> .nav { width: 100%; height: 60px; background-color: orange; } .nav li { float: left; font: normal 20px/60px '微軟雅黑'; padding: 0 30px; } .nav li:hover { cursor: pointer; background-color: aquamarine; } .nav li.active { cursor: pointer; background-color: aquamarine; } </style>