做app+的模板下載網(wǎng)站短視頻精準(zhǔn)獲客
vue基礎(chǔ)回顧+進(jìn)階
課程內(nèi)容
- VUE 基礎(chǔ)回顧
- 路由 Vue-Router
- 狀態(tài)管理 vuex
- TypeScript
1. VUE 基礎(chǔ)回顧
1.1 基于腳手架創(chuàng)建前端工程
1.1.1 環(huán)境要求
要想基于腳手架創(chuàng)建前端工程,需要具備如下環(huán)境要求:
- ? node.js 前端項(xiàng)目的運(yùn)行環(huán)境
- 學(xué)習(xí)web階段已安裝
- ? npm JavaScript的包管理工具
- 安裝完node.js之后自帶了npm這個(gè)命令
- ? Vue CLI 基于Vue進(jìn)行快速開(kāi)發(fā)的完整系統(tǒng),實(shí)現(xiàn)交互式的項(xiàng)目腳手架
- 需要通過(guò)npm命令來(lái)安裝
安裝完node.js后,可以通過(guò)命令行來(lái)查看版本號(hào),如下:
安裝 Vue CLI,命令如下:
1.1.2 操作過(guò)程
使用 Vue CLI 創(chuàng)建前端工程的方式:
- 方式一:vue create 項(xiàng)目名稱
-
管理員的方式打開(kāi)Dos窗口,之后進(jìn)入到一個(gè)非中文目錄(這個(gè)目錄當(dāng)做我們的VScode工作空間),輸入命令
vue create vue-demo-1
-
上下鍵選擇vue的版本,這里以vue2為例
-
可以看到vue項(xiàng)目創(chuàng)建成功
-
- ? 方式二:vue ui(推薦)
重點(diǎn)介紹使用 vue ui 命令創(chuàng)建前端工程的過(guò)程:
第一步:同樣首先以管理員的方式打開(kāi)命令行窗口,之后切換到一個(gè)非中文的目錄(這個(gè)目錄當(dāng)做我們的VScode工作空間),在命令行輸入命令 vue ui
,在瀏覽器ui界面中選擇前端工程存放的位置
第二步:點(diǎn)擊“在此創(chuàng)建新項(xiàng)目”按鈕,跳轉(zhuǎn)到創(chuàng)建新項(xiàng)目設(shè)置頁(yè)面。填寫項(xiàng)目名稱、選擇包管理器為npm,點(diǎn)擊“下一步”按鈕
第三步:選擇 Default(Vue 2),點(diǎn)擊"創(chuàng)建項(xiàng)目"按鈕,完成項(xiàng)目的創(chuàng)建
1.1.3 工程結(jié)構(gòu)
工程目錄結(jié)構(gòu):
1.1.4 啟動(dòng)前端服務(wù)
使用VS Code打開(kāi)創(chuàng)建的前端工程,啟動(dòng)前端工程:
訪問(wèn)前端工程:
注:要停止前端服務(wù),可以在命令行終端使用 ctrl + C
前端項(xiàng)目啟動(dòng)后,服務(wù)端口默認(rèn)為8080,很容易和后端tomcat端口號(hào)沖突。如何修改前端服務(wù)的端口號(hào)?
可以在vue.config.js中配置前端服務(wù)端口號(hào):
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,devServer: {port: 7070 //指定前端服務(wù)端口號(hào)}
})
1.2 vue基本使用方式
本章節(jié)從如下幾個(gè)方面進(jìn)行vue回顧:
- vue 組件
- 文本插值
- 屬性綁定
- 事件綁定
- 雙向綁定
- 條件渲染
- axios
1.2.1 vue 組件
Vue 的組件文件以 .vue
結(jié)尾,每個(gè)組件由三部分組成:
- 結(jié)構(gòu)
<template>
- 樣式
<style>
- 邏輯
<script>
1.2.2 測(cè)試準(zhǔn)備工作
說(shuō)明:
- 當(dāng)前頁(yè)面比較亂它自帶了很多的數(shù)據(jù),為了方便測(cè)試效果把數(shù)據(jù)給它清理一下。
- 可以看到頁(yè)面上還顯示一個(gè)圖片,這是因?yàn)楫?dāng)前展示的這個(gè)頁(yè)面并不是直接來(lái)自于HelloWorld.Vue組件而是這個(gè)App.vue,App.vue組件才是真正的項(xiàng)目入口頁(yè)面,App.vue頁(yè)面中又引入了HelloWorld.Vue組件,這個(gè)圖片是設(shè)置在App.vue組件中,此時(shí)不想要圖片需要到App.vue組件中進(jìn)行刪除。
- 效果
1.2.3 文本插值
作用:用來(lái)綁定 data 方法返回的對(duì)象屬性
用法:{{插值表達(dá)式}}
示例:
測(cè)試:
代碼:
<template><div class="hello">{{name}}{{age > 60 ? '老年' : '青年'}}</div>
</template><script>
export default {name: 'HelloWorld',props: {msg: String},data() {return {name: '張三',age: 22}},}
</script><!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {margin: 40px 0 0;
}
ul {list-style-type: none;padding: 0;
}
li {display: inline-block;margin: 0 10px;
}
a {color: #42b983;
}
</style>
效果:
1.2.4 屬性綁定
作用:為標(biāo)簽的屬性綁定 data 方法中返回的屬性
用法:v-bind
:xxx,簡(jiǎn)寫為 :xxx
示例:
測(cè)試:
代碼
效果
1.2.5 事件綁定
作用:為元素綁定對(duì)應(yīng)的事件
用法:v-on:
xxx,簡(jiǎn)寫為 @
xxx
示例:
測(cè)試:
代碼
效果
1.2.6 雙向綁定
作用:表單輸入項(xiàng)和 data 方法中的屬性進(jìn)行綁定,任意一方改變都會(huì)同步給另一方
用法:v-model
示例:
測(cè)試:
代碼
效果:修改輸入框的值name會(huì)發(fā)生變化,點(diǎn)擊事件方法修改name的值輸入框的值會(huì)跟著改變
1.2.7 條件渲染
作用:根據(jù)表達(dá)式的值來(lái)動(dòng)態(tài)渲染頁(yè)面元素
用法:v-if、v-else、v-else-if
示例:
測(cè)試:
代碼
效果
1.2.8 axios
Axios 是一個(gè)基于 promise 的 網(wǎng)絡(luò)請(qǐng)求庫(kù)
,作用于瀏覽器和 node.js 中。使用Axios可以在前端項(xiàng)目中發(fā)送各種方式的HTTP請(qǐng)求。
安裝axios的命令:npm install axios
(以管理員的方式打開(kāi)VScode)
導(dǎo)入:import axios from 'axios'
axios 的 API 列表:[ ]代表可選參數(shù),可以有可以沒(méi)有。
參數(shù)說(shuō)明:
- url:請(qǐng)求路徑
- data:請(qǐng)求體數(shù)據(jù),最常見(jiàn)的是JSON格式數(shù)據(jù)
- config:配置對(duì)象,可以設(shè)置查詢參數(shù)、請(qǐng)求頭信息
注:在使用axios時(shí),經(jīng)常會(huì)遇到跨域問(wèn)題。為了解決跨域問(wèn)題,可以在 vue.config.js 文件中配置代理:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,devServer: {port: 7070,proxy: {'/api': {target: 'http://localhost:8080',pathRewrite: {'^/api': ''}}}}
})
axios的post請(qǐng)求示例:
axios.post('/api/admin/employee/login',{username:'admin',password: '123456'}).then(res => {console.log(res.data)}).catch(error => {console.log(error.response)})
axios的get請(qǐng)求示例:
axios.get('/api/admin/shop/status',{headers: {token: ‘xxx.yyy.zzz’}})
axios提供的統(tǒng)一使用方式示例一(可以發(fā)送各種方式的請(qǐng)求):
axios提供的統(tǒng)一使用方式示例二(可以發(fā)送各種方式的請(qǐng)求):
axios({url: '/api/admin/employee/login',method:'post',data: {username:'admin',password: '123456'}}).then((res) => {console.log(res.data.data.token)axios({url: '/api/admin/shop/status',method: 'get',params: {id: 100},headers: {token: res.data.data.token}})}).catch((error) => {console.log(error)})
1.2.9 axios 測(cè)試:沒(méi)有配置跨域----post請(qǐng)求
HelloWorld.vue代碼:
<input type="button" value="發(fā)送POST請(qǐng)求" @click="handleSendPOST"/>handleSendPOST() {//通過(guò)axios發(fā)送post請(qǐng)求 提供了url data 沒(méi)有提供config//地址是蒼穹外賣后臺(tái)登錄的接口地址,后臺(tái)項(xiàng)目要先啟動(dòng)axios.post('http://localhost:8080/admin/employee/login',{username: 'admin',password: '123456'}).then(res => { //調(diào)用成功的回調(diào)函數(shù)console.log(res.data)}).catch(error => { //調(diào)用失敗的回調(diào)函數(shù)console.log(error.response)})},
啟動(dòng)后臺(tái)項(xiàng)目,啟動(dòng)前端項(xiàng)目vue-demo-2,點(diǎn)擊按鈕發(fā)送請(qǐng)求發(fā)現(xiàn)前后臺(tái)沒(méi)有任何反應(yīng),f12查看控制臺(tái)發(fā)現(xiàn)報(bào)錯(cuò)(發(fā)生了跨域)
原因:發(fā)生了跨域問(wèn)題,前端的訪問(wèn)端口是7070,后端的是8080,當(dāng)前是在7070服務(wù)中往8080這個(gè)端口發(fā)送,所以產(chǎn)生了跨域。
解決:需要配置代理
1.2.10 axios 測(cè)試:配置跨域----post請(qǐng)求
為了解決跨域問(wèn)題,可以在 vue.config.js 文件中配置代理:
代理的作用:前端發(fā)送的請(qǐng)求先請(qǐng)求到代理上,然后由代理進(jìn)行轉(zhuǎn)發(fā)到我們的后臺(tái)服務(wù),這樣就可以解決跨域問(wèn)題了。
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({transpileDependencies: true,devServer: {port: 7070,proxy: {'/api': {//攔截前端發(fā)送的請(qǐng)求都含有api前綴的地址target: 'http://localhost:8080',//攔截后轉(zhuǎn)發(fā)到的目標(biāo)服務(wù)器地址pathRewrite: {//請(qǐng)求轉(zhuǎn)發(fā)到后端后,后端接口路徑多了個(gè)/api,匹配不上找不到controller,所以需要去掉'^/api': '' //路徑重寫:把/api替換為空串 ^api表示以/api作為開(kāi)頭}}}}
})
修改HelloWorld.vue中發(fā)送的后臺(tái)請(qǐng)求地址:http://localhost:8080—》/api
因?yàn)樾薷牡氖桥渲梦募孕枰貑⑶岸隧?xiàng)目才能生效
再次發(fā)送請(qǐng)求:
1.2.11 axios 測(cè)試:get請(qǐng)求
HelloWorld.vue代碼:
<input type="button" value="發(fā)送GET請(qǐng)求" @click="handleSendGET"/>handleSendGET() {//通過(guò)axios發(fā)送get方式請(qǐng)求 指定了url(店鋪的營(yíng)業(yè)狀態(tài)) 指定configaxios.get('/api/admin/shop/status',{//這個(gè)請(qǐng)求需要攜帶jwt的令牌地址才能正確訪問(wèn),復(fù)制上面發(fā)送post請(qǐng)求調(diào)用登錄接口生成的令牌地址headers: { //指定config,在請(qǐng)求頭里追加參數(shù)tokentoken: 'eyJhbGciOiJIUzI1NiJ9.eyJlbXBJZCI6MSwiZXhwIjoxNzEwNjkyMTgxfQ.WAb2SoElTlJcobDCXUAqKPlm0At68LAexTz1MTwZdz4'}}).then(res => {console.log(res.data)})},
對(duì)應(yīng)的店鋪營(yíng)業(yè)狀態(tài)接口:
首先發(fā)送post請(qǐng)求,復(fù)制返回的token.
刷新頁(yè)面發(fā)送get請(qǐng)求:成功
1.2.12 axios 測(cè)試:通用方式發(fā)送請(qǐng)求
axios 統(tǒng)一使用方式:axios(config)
HelloWorld.vue代碼:
<input type="button" value="統(tǒng)一請(qǐng)求方式" @click="handleSend"/>handleSend() {//使用axios提供的統(tǒng)一調(diào)用方式發(fā)送請(qǐng)求axios({url: '/api/admin/employee/login',method: 'post', //默認(rèn)是getdata: { //data表示通過(guò)請(qǐng)求體傳參 username: 'admin',password: '123456'}}).then(res => {//成功回調(diào)console.log(res.data.data.token) //res.data:返回的result對(duì)象,里面包含data,data中又包含tokenaxios({ //在成功的回調(diào)函數(shù)里又發(fā)送一個(gè)get請(qǐng)求 獲取店鋪的營(yíng)業(yè)狀態(tài)url: '/api/admin/shop/status',method: 'get',headers: {token: res.data.data.token //因?yàn)檫@個(gè)get方法實(shí)際上是在post請(qǐng)求的回調(diào)函數(shù)里面,所以這個(gè)地方可以動(dòng)態(tài)的獲取token}})})}
測(cè)試:2次請(qǐng)求都成功發(fā)送
2. 路由 Vue-Router
2.1 Vue-Router 介紹
vue 屬于單頁(yè)面應(yīng)用,所謂路由,就是根據(jù)瀏覽器路徑不同,用不同的視圖組件替換這個(gè)頁(yè)面內(nèi)容。
單頁(yè)面應(yīng)用:在整個(gè)vue應(yīng)用中,實(shí)際上只有一個(gè)頁(yè)面,我們看到的瀏覽器多個(gè)頁(yè)面其實(shí)是一種假象,它是通過(guò)頁(yè)面切換 切換不同的視圖組件
現(xiàn)實(shí)舉例:一塊黑板,不同的老師上課把之前老師寫的內(nèi)容刪除掉,之后寫上自己課的內(nèi)容。
這個(gè)替換的過(guò)程就是通過(guò)路由來(lái)完成的。
如上圖所示:不同的訪問(wèn)路徑,對(duì)應(yīng)不同的頁(yè)面展示。
基于Vue CLI 創(chuàng)建帶有路由功能的前端項(xiàng)目:
在vue應(yīng)用中使用路由功能,需要安裝Vue-Router:
注:創(chuàng)建完帶有路由功能的前端項(xiàng)目后,在工程中會(huì)生成一個(gè)路由文件,如下所示:
關(guān)于路由的配置,主要就是在這個(gè)路由文件中完成的。
為了能夠使用路由功能,在前端項(xiàng)目的入口文件main.js中,創(chuàng)建Vue實(shí)例時(shí)需要指定路由對(duì)象:
創(chuàng)建完路由項(xiàng)目后自動(dòng)生成
啟動(dòng)項(xiàng)目查看效果:點(diǎn)擊不同的地址會(huì)自動(dòng)切換頁(yè)面
說(shuō)明:
- 什么是路由?
- 根據(jù)瀏覽器訪問(wèn)路徑不同,展示不同的視圖組件
- vue應(yīng)用中如何實(shí)現(xiàn)路由?
- 通過(guò) vue-router 實(shí)現(xiàn)路由功能,需要安裝js庫(kù)(npm install vue-router)
- 剛才之所以沒(méi)有顯示的去安裝是因?yàn)?#xff0c;在頁(yè)面上使用了腳手架構(gòu)建項(xiàng)目并且勾選了路由功能,這樣的話在創(chuàng)建這個(gè)前端工程時(shí),實(shí)際上就會(huì)通過(guò)這個(gè)命令安裝所需要的庫(kù)。
- 如果是一個(gè)老項(xiàng)目使用路由功能,此時(shí)需要執(zhí)行此命令手動(dòng)安裝。
2.2 路由配置
首先了解一下路由組成:
VueRouter
:路由器,根據(jù)路由請(qǐng)求在路由視圖中動(dòng)態(tài)渲染對(duì)應(yīng)的視圖組件- 路由器作用:根據(jù)路由請(qǐng)求來(lái)渲染這個(gè)不同的視圖
- 具體渲染哪一個(gè)視圖組件呢???在路由器中其實(shí)會(huì)維護(hù)一個(gè)路由表,它里面保存了映射關(guān)系,某一個(gè)路由路徑對(duì)應(yīng)的那一個(gè)視圖組件。
<router-link>
:路由鏈接組件,瀏覽器會(huì)解析成<a>
- 作用:生成超鏈接標(biāo)簽的
<router-view>
:路由視圖組件,用來(lái)展示與路由路徑匹配的視圖組件- 展示某一個(gè)視圖組件指定的位置,本質(zhì)是頁(yè)面中的一個(gè)占位符,通過(guò)路由去渲染不同的視圖組件,視圖組件要渲染的就是這個(gè)頁(yè)面
<router-view>
占位符所在的位置。
- 展示某一個(gè)視圖組件指定的位置,本質(zhì)是頁(yè)面中的一個(gè)占位符,通過(guò)路由去渲染不同的視圖組件,視圖組件要渲染的就是這個(gè)頁(yè)面
這三部分之間是如何協(xié)作的:
- 點(diǎn)擊路由鏈接組件(超鏈接)發(fā)起路由請(qǐng)求,這個(gè)請(qǐng)求會(huì)交給路由器處理。
- 路由器會(huì)根據(jù)路由路徑的不同然后去渲染對(duì)應(yīng)的視圖組件
- 具體渲染到這個(gè)路由視圖組件
<router-view>
這個(gè)占位符位置。
具體配置方式:
基于腳手架創(chuàng)建前端項(xiàng)目的時(shí)候勾選了路由功能,此時(shí)工程中路由的代碼已經(jīng)自動(dòng)生成好了。
首先在package.json里面加入vue-router
:此時(shí)就可以在前端項(xiàng)目中使用路由功能了
然后在main.js入口文件中引入router,這個(gè)router來(lái)自于index.js文件
找到router下面有一個(gè)index.js,然后在這個(gè)文件里引入VueRouter,這個(gè)VueRouter來(lái)自于node_modules(保存創(chuàng)建好項(xiàng)目之后所依賴的包)中的vue-router里
- 在路由文件index.js中配置路由路徑和視圖的對(duì)應(yīng)關(guān)系:路由表
import Vue from 'vue'
import VueRouter from 'vue-router'
import HomeView from '../views/HomeView.vue'Vue.use(VueRouter)//維護(hù)路由表,某個(gè)路由路徑對(duì)應(yīng)哪個(gè)視圖組件
const routes = [{path: '/', //對(duì)應(yīng)一個(gè)路由路徑name: 'home', //名字component: HomeView //路徑所對(duì)應(yīng)的視圖組件 方式一:靜態(tài)導(dǎo)入,最終項(xiàng)目上線需要打包,打包會(huì)把這些組件}, // 打到同一個(gè)js文件里面,兩種打包方式不同// 性能稍差:不管你視圖展示不展示都打入到同一個(gè)js文件里面,導(dǎo)致這個(gè)js文件非常大,// 哪怕你這個(gè)視圖從來(lái)沒(méi)有強(qiáng)求過(guò)沒(méi)顯示過(guò),但是這部分資源已經(jīng)加載了,{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.//方式二:動(dòng)態(tài)導(dǎo)入(推薦) 懶加載策略:打包的時(shí)候會(huì)單獨(dú)的把這些組件打到j(luò)s文件里面// 性能更好:按需引入因?yàn)樗菃为?dú)的把這些視圖組件單獨(dú)的打到j(luò)s文件里面,// 只有請(qǐng)求這個(gè)視圖它才會(huì)加載這個(gè)js文件,如果不請(qǐng)求就不會(huì)加載了。component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')}
]const router = new VueRouter({routes
})export default router
- 在視圖組件App.vue入口頁(yè)面文件中配置 router-link標(biāo)簽,用于生成超鏈接
<router-link to="/">Home</router-link> | <!-- 路由鏈接組件生成超鏈接 --><router-link to="/about">About</router-link>
- 在視圖組件匯總配置router-view標(biāo)簽:占位符,視圖渲染到的位置
- 效果:可以來(lái)回切換
要實(shí)現(xiàn)路由跳轉(zhuǎn),可以通過(guò)標(biāo)簽式和編程式兩種:
- 標(biāo)簽式:
<router-link to="/about">About</router-link>
- 通過(guò)router-link標(biāo)簽生成超鏈接實(shí)現(xiàn)跳轉(zhuǎn)
- 編程式:
this.$router.push('/about')
- 通過(guò)js代碼實(shí)現(xiàn)跳轉(zhuǎn)
- 通過(guò)js代碼實(shí)現(xiàn)跳轉(zhuǎn)
測(cè)試編程式:
代碼:
<input type="button" value="編程式路由跳轉(zhuǎn)" @click="jump"/> <!-- 方法不需要參數(shù)的話()可以省略掉 --><script>
export default {methods: {jump() {//使用編程路由的方式跳轉(zhuǎn) 具體的路由路徑(路由表中配置的路徑)this.$router.push('/about',()=> {})}}
}
</script>
效果:點(diǎn)擊按鈕也能跳轉(zhuǎn)到about頁(yè)面
問(wèn)題思考:如果用戶訪問(wèn)的路由地址不存在,該如何處理?
可以通過(guò)配置一個(gè)404視圖組件,當(dāng)訪問(wèn)的路由地址不存在時(shí),則重定向到此視圖組件,具體配置如下:
index.js文件:路由表
/* 只寫這一個(gè)配置的效果:我們?cè)L問(wèn)到404路徑的時(shí)候就可以訪問(wèn)到這個(gè)組件,而我們的需求是 當(dāng)用戶訪問(wèn)一個(gè)不存在的路徑時(shí)才會(huì)跳轉(zhuǎn)到404視圖去展示,所以還需要接著配置重定向*/{path: '/404', //name可以不用配置component: () => import('../views/404View.vue')},/* 配置重定向流程:當(dāng)用戶訪問(wèn)到一個(gè)不存在的路徑就會(huì)重定向到/404,/404路徑對(duì)應(yīng)的就是404頁(yè)面組件 */{path: '*', //上面這些訪問(wèn)的路徑都沒(méi)匹配上才會(huì)走這最后一個(gè)路徑redirect: '/404' //重定向到/404訪問(wèn)路徑,}
App.vue:超鏈接
<router-link to="/test">Test</router-link> | <!-- 沒(méi)有對(duì)應(yīng)的路由路徑/test -->
路由請(qǐng)求路徑不存在,跳轉(zhuǎn)的頁(yè)面組件:
<template><div class="about"><h1>您請(qǐng)求的資源不存在</h1></div>
</template>
效果:
2.3 嵌套路由
嵌套路由:組件內(nèi)要切換內(nèi)容,就需要用到嵌套路由(子路由),效果如下:
在App.vue視圖組件中有<router-view>
標(biāo)簽,其他視圖組件可以展示在此
ContainerView.vue組件可以展示在App.vue視圖組件的<router-view>
位置
ContainerView.vue組件進(jìn)行了區(qū)域劃分(分為上、左、右),在右邊編寫了<router-view>
標(biāo)簽,點(diǎn)擊左側(cè)菜單時(shí),可以將對(duì)應(yīng)的子視圖組件展示在此
總結(jié):
- 原先是不同的vue組件嵌套到App.vue入口視圖組件頁(yè)面中
- 現(xiàn)在是不同的子組件先嵌套到ContainerView.vue組件中,ContainerView.vue組件在嵌套到App.vue入口視圖組件中。
實(shí)現(xiàn)步驟:
第一步:安裝并導(dǎo)入 elementui,實(shí)現(xiàn)頁(yè)面布局(Container 布局容器)—ContainerView.vue
安裝: elementui
npm i element-ui -S
導(dǎo)入: elementui,在 main.js 中寫入以下內(nèi)容:
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';Vue.use(ElementUI);//全局使用ElementUi
實(shí)現(xiàn)頁(yè)面布局(Container 布局容器)—ContainerView.vue
<template><el-container><el-header>Header</el-header><el-container><el-aside width="200px"></el-aside><el-main></el-main></el-container></el-container>
</template><script>
export default {}
</script><style>
.el-header, .el-footer {background-color: #B3C0D1;color: #333;text-align: center;line-height: 60px;}.el-aside {background-color: #D3DCE6;color: #333;text-align: center;line-height: 200px;}.el-main {background-color: #E9EEF3;color: #333;text-align: center;line-height: 160px;}body > .el-container {margin-bottom: 40px;}.el-container:nth-child(5) .el-aside,.el-container:nth-child(6) .el-aside {line-height: 260px;}.el-container:nth-child(7) .el-aside {line-height: 320px;}
</style>
第二步:提供子視圖組件,用于效果展示 —P1View.vue、P2View.vue、P3View.vue
<template><div>這是P1 View</div>
</template><script>
export default {}
</script><style>
.el-header, .el-footer {background-color: #B3C0D1;color: #333;text-align: center;line-height: 60px;}.el-aside {background-color: #D3DCE6;color: #333;text-align: center;line-height: 200px;}.el-main {background-color: #E9EEF3;color: #333;text-align: center;line-height: 160px;}body > .el-container {margin-bottom: 40px;}.el-container:nth-child(5) .el-aside,.el-container:nth-child(6) .el-aside {line-height: 260px;}.el-container:nth-child(7) .el-aside {line-height: 320px;}
</style>
第三步:在 src/router/index.js 中配置路由映射規(guī)則(嵌套路由配置)
{path: '/c',component: () => import('../views/container/ContainerView.vue'),//嵌套路由(子路由),對(duì)應(yīng)的組件會(huì)展示在當(dāng)前組件內(nèi)部children: [//通過(guò)children屬性指定子路由相關(guān)信息(path、component){path: '/c/p1',component: () => import('../views/container/P1View.vue')},{path: '/c/p2',component: () => import('../views/container/P2View.vue')},{path: '/c/p3',component: () => import('../views/container/P3View.vue')}]}
第四步:在ContainerView.vue 布局容器視圖中添加,實(shí)現(xiàn)子視圖組件展示
<el-main><router-view/>
</el-main>
第五步:在ContainerView.vue 布局容器視圖中添加,實(shí)現(xiàn)路由請(qǐng)求
<el-aside width="200px"><router-link to="/c/p1">P1</router-link><br><router-link to="/c/p2">P2</router-link><br><router-link to="/c/p3">P3</router-link><br>
</el-aside>
效果:http://localhost:8080/#/c
點(diǎn)擊超鏈接(http://localhost:8080/#/c/p1)右側(cè)會(huì)進(jìn)行替換組件。
注意:子路由變化,切換的是【ContainerView 組件】中 <router-view></router-view>
部分的內(nèi)容
問(wèn)題思考:
1.對(duì)于前面的案例,如果用戶訪問(wèn)的路由是 /c,會(huì)有什么效果呢?
2.如何實(shí)現(xiàn)在訪問(wèn) /c 時(shí),默認(rèn)就展示某個(gè)子視圖組件呢?
配置重定向,當(dāng)訪問(wèn)/c時(shí),直接重定向到/c/p1即可,如下配置:
redirect :'/c/p1',
效果:
3. 狀態(tài)管理 vuex(待定:P177)
3.1 vuex 介紹
- vuex 是一個(gè)專為 Vue.js 應(yīng)用程序開(kāi)發(fā)的狀態(tài)管理庫(kù)
- vuex 可以在多個(gè)組件之間共享數(shù)據(jù),并且共享的數(shù)據(jù)是響應(yīng)式的,即數(shù)據(jù)的變更能及時(shí)渲染到模板
- vuex 采用集中式存儲(chǔ)管理所有組件的狀態(tài)
每一個(gè) Vuex 應(yīng)用的核心就是 store(倉(cāng)庫(kù))?!皊tore”基本上就是一個(gè)容器,它包含著你的應(yīng)用中大部分的狀態(tài) (state)。Vuex 和單純的全局對(duì)象有以下兩點(diǎn)不同:
- Vuex 的狀態(tài)存儲(chǔ)是響應(yīng)式的。當(dāng) Vue 組件從 store 中讀取狀態(tài)的時(shí)候,若 store 中的狀態(tài)發(fā)生變化,那么相應(yīng)的組件也會(huì)相應(yīng)地得到高效更新。
- 你不能直接改變 store 中的狀態(tài)。改變 store 中的狀態(tài)的唯一途徑就是顯式地提交 (commit) mutation。這樣使得我們可以方便地跟蹤每一個(gè)狀態(tài)的變化,從而讓我們能夠?qū)崿F(xiàn)一些工具幫助我們更好地了解我們的應(yīng)用。
安裝vuex:npm install vuex@next --save
vuex中的幾個(gè)核心概念:
- state:狀態(tài)對(duì)象,集中定義各個(gè)組件共享的數(shù)據(jù)
- mutations:類似于一個(gè)事件,用于修改共享數(shù)據(jù),要求必須是同步函數(shù)
- actions:類似于mutation,可以包含異步操作,通過(guò)調(diào)用mutation來(lái)改變共享數(shù)據(jù)
3.2 使用方式
本章節(jié)通過(guò)一個(gè)案例來(lái)學(xué)習(xí)vuex的使用方式,具體操作步驟如下:
第一步:創(chuàng)建帶有vuex功能的前端項(xiàng)目
注:在創(chuàng)建的前端工程中,可以發(fā)現(xiàn)自動(dòng)創(chuàng)建了vuex相關(guān)的文件(src/store/index.js),并且在main.js中創(chuàng)建Vue實(shí)例時(shí),需要將store對(duì)象傳入,代碼如下:
import Vue from 'vue'
import App from './App.vue'
import store from './store'Vue.config.productionTip = falsenew Vue({store,//使用vuex功能render: h => h(App)
}).$mount('#app')
第二步:在src/store/index.js文件中集中定義和管理共享數(shù)據(jù)
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'Vue.use(Vuex)//集中管理多個(gè)組件共享的數(shù)據(jù)
export default new Vuex.Store({//集中定義共享數(shù)據(jù)state: {name: '未登錄游客'},getters: {},//通過(guò)當(dāng)前屬性中定義的函數(shù)修改共享數(shù)據(jù),必須都是同步操作mutations: {},//通過(guò)actions調(diào)用mutation,在actions中可以進(jìn)行異步操作actions: {},modules: {}
})
第三步:在視圖組件中展示共享數(shù)據(jù)
<template><div class="hello"><h1>歡迎你,{{$store.state.name}}</h1></div>
</template>
注:$store.state為固定寫法,用于訪問(wèn)共享數(shù)據(jù)
第四步:在mutations中定義函數(shù),用于修改共享數(shù)據(jù)
//通過(guò)當(dāng)前屬性中定義的函數(shù)修改共享數(shù)據(jù),必須都是同步操作mutations: {setName(state,newName) {state.name = newName}},
第五步:在視圖組件中調(diào)用 mutations 中定義的函數(shù)
注:mutations中定義的函數(shù)不能直接調(diào)用,必須通過(guò)狀態(tài)對(duì)象的 commit 方法來(lái)調(diào)用
第六步:如果在修改共享數(shù)據(jù)的過(guò)程中有異步操作,則需要將異步操作的代碼編寫在actions的函數(shù)中
//通過(guò)actions調(diào)用mutation,在actions中可以進(jìn)行異步操作actions: {setNameByAxios(context){axios({ //異步請(qǐng)求url: '/api/admin/employee/login',method: 'post',data: {username: 'admin',password: '123456'}}).then(res => {if(res.data.code == 1){//異步請(qǐng)求后,需要修改共享數(shù)據(jù)//在actions中調(diào)用mutation中定義的setName函數(shù)context.commit('setName',res.data.data.name)}})}},
注:在actions中定義的函數(shù)可以聲明context參數(shù),通過(guò)此參數(shù)可以調(diào)用mutations中定義的函數(shù)
第七步:在視圖組件中調(diào)用actions中定義的函數(shù)
注:在actions中定義的函數(shù)不能直接調(diào)用,必須通過(guò) this.$store.dispatch(‘函數(shù)名稱’) 這種方式調(diào)用
4. TypeScript
4.1 TypeScript 介紹
- TypeScript(簡(jiǎn)稱:TS) 是微軟推出的開(kāi)源語(yǔ)言
- TypeScript 是 JavaScript 的超集(JS 有的 TS 都有)
- TypeScript = Type + JavaScript(在 JS 基礎(chǔ)上增加了類型支持)
- TypeScript 文件擴(kuò)展名為 ts
- TypeScript 可編譯成標(biāo)準(zhǔn)的 JavaScript,并且在編譯時(shí)進(jìn)行類型檢查
在前端項(xiàng)目中使用TS,需要進(jìn)行安裝,命令為:npm install -g typescript
查看TS版本:
TS初體驗(yàn):
- 創(chuàng)建 hello.ts 文件,內(nèi)容如下:
//定義一個(gè)函數(shù) hello,并且指定參數(shù)類型為string
function hello(msg:string) {console.log(msg)
}//調(diào)用上面的函數(shù),傳遞非string類型的參數(shù)
hello(123)
- 使用 tsc 命令編譯 hello.ts 文件
可以看到編譯報(bào)錯(cuò),提示參數(shù)類型不匹配。這說(shuō)明在編譯時(shí)TS會(huì)進(jìn)行類型檢查。需要注意的是在編譯為JS文件后,類型會(huì)被擦除。
思考:TS 為什么要增加類型支持 ?
- TS 屬于靜態(tài)類型編程語(yǔ)言,JS 屬于動(dòng)態(tài)類型編程語(yǔ)言
- 靜態(tài)類型在編譯期做類型檢查,動(dòng)態(tài)類型在執(zhí)行期做類型檢查
- 對(duì)于 JS 來(lái)說(shuō),需要等到代碼執(zhí)行的時(shí)候才能發(fā)現(xiàn)錯(cuò)誤(晚)
- 對(duì)于 TS 來(lái)說(shuō),在代碼編譯的時(shí)候就可以發(fā)現(xiàn)錯(cuò)誤(早)
- 配合 VSCode 開(kāi)發(fā)工具,TS 可以提前到在編寫代碼的同時(shí)就發(fā)現(xiàn)代碼中的錯(cuò)誤,減少找 Bug、改 Bug 的時(shí)間
在前端項(xiàng)目中使用TS,需要?jiǎng)?chuàng)建基于TS的前端工程:
4.2 TypeScript 常用類型
TS中的常用類型如下:
類型 | 例 | 備注 |
---|---|---|
字符串類型 | string | |
數(shù)字類型 | number | |
布爾類型 | boolean | |
數(shù)組類型 | number[],string[], boolean[] 依此類推 | |
任意類型 | any | 相當(dāng)于又回到了沒(méi)有類型的時(shí)代 |
復(fù)雜類型 | type 與 interface | |
函數(shù)類型 | () => void | 對(duì)函數(shù)的參數(shù)和返回值進(jìn)行說(shuō)明 |
字面量類型 | “a”|“b”|“c” | 限制變量或參數(shù)的取值 |
class 類 | class Animal |
4.2.1 類型標(biāo)注的位置
基于TS進(jìn)行前端開(kāi)發(fā)時(shí),類型標(biāo)注的位置有如下3個(gè):
- 標(biāo)注變量
- 標(biāo)注參數(shù)
- 標(biāo)注返回值
4.2.2 字符串、數(shù)字、布爾類型
字符串、數(shù)字、布爾類型是前端開(kāi)發(fā)中常用的類型
4.2.3 字面量類型
字面量類型用于限定數(shù)據(jù)的取值范圍,類似于java中的枚舉
4.2.4 interface 類型
interface 類型是TS中的復(fù)雜類型,它讓 TypeScript 具備了 JavaScript 所缺少的、描述較為復(fù)雜數(shù)據(jù)結(jié)構(gòu)的能力。
可以通過(guò)在屬性名后面加上?,表示當(dāng)前屬性為可選,如下:
4.2.5 class 類型
使用 class 關(guān)鍵字來(lái)定義類,類中可以包含屬性、構(gòu)造方法、普通方法等
在定義類時(shí),可以使用 implments 關(guān)鍵字實(shí)現(xiàn)接口,如下:
在定義類時(shí),可以使用 extends 關(guān)鍵字 繼承其他類,如下: