文章目錄
- VUE 基礎
- MVVM設計
- VUE系結原理設計
- 虛擬DOM樹分析
- VUE編程步驟實踐
- 系結與指令應用
- 系結樣式分析(了解):
- 計算屬性應用實踐
- 生命周期函式應用
- Axios方式的Ajax請求
- Get請求
- Post請求
- VUE 組件化開發
- 組件設計
- 基本步驟
- 運行分析
- 組件型別
- 組件間傳參
- 單頁應用實踐(SPA)
- 基本步驟
- 頁頭等全域組件:
- 路由跳轉
- 路由傳參
- 安裝vue腳手架
- 腳手架檔案夾結構:
- 懶加載應用實踐
- 異步延遲加載:
- 徹底懶加載:
- http-proxy方式跨域:
- vue.config.js設定
- main.js
- 避免組件間樣式沖突
- watch+事件修飾符+防抖:
- 插槽技術應用
- Vuex 資料管理
- 應用場景
- 構成分析(3部分)
- 組件中使用state中的變數
- 組件中修改state中的變數值
- 組件中先發ajax請求再修改state中變數值
- TypeScript 基本語法
- 變數:
- 函式:
- class 新規定
- 模塊化開發:
- Vue3 新特性介紹
- 原理
- ES6 Proxy代理物件:
- main.ts 中實踐
- 頁面/組件
- 新宣告周期鉤子函式
- 總結(Summary)
VUE 基礎
MVVM設計
MVVM: 界面View+模型Model+視圖模型ViewModel
VUE系結原理設計
訪問器屬性+虛擬DOM樹
變數被修改時: 訪問器屬性發出通知,虛擬DOM樹掃描并僅更新受影響的元素
虛擬DOM樹分析
虛擬DOM樹優點:
(1). 小: 只包含可能變化的元素,
(2). 遍歷查找快
(3). 修改效率高: 只修改受影響的元素,
(4). 避免重復編碼: 已封裝DOM增刪改查代碼
VUE編程步驟實踐
Vue功能3步:
(1). 先創建增強版的界面:
a. 整個界面必須包含在一個唯一的父元素下:
通常是
b. 可能變化的元素內容用{{自定義變數名}}標記
c. 觸發事件的元素用@click="自定義處理函式名"標記
(2). 再創建new Vue()物件,其中el:指向new Vue()要監控的頁面區域
(3). 在new Vue()物件內定義模型物件data和methods
a.界面所需的所有變數都放在data中
b.界面所需的所有事件處理函式都放在methods中
系結與指令應用
(1). 如果元素的內容需要隨變數自動變化: {{}}
(2). 如果元素的屬性值需要隨變數自動變化: :
(3). 控制一個元素顯示隱藏: v-show //使用display:none隱藏元素
(4). 控制兩個元素二選一顯示: v-if v-else //使用洗掉元素方式隱藏元素
(5). 多個元素多選一顯示: v-if v-else-if v-else
(6). 只要反復生成多個相同結構的元素組成串列時: v-for :key=“唯一標識”
強調: 為什么必須加:key=“i”?給每個元素副本添加唯一標識,修改陣列中某個元素值時,避免重建整個串列,只需要修改一個DOM元素副本即可!提高修改效率,
(7). 只要系結事件: @ $event
(8). 防止用戶短暫看到{{}}: v-cloak和v-text
(9). 只要系結原始HTML代碼片段內容: v-html
(10). 如果元素的內容只在首次加載時系結一次,之后都不會改變: v-once
優化: 減少虛擬DOM樹中元素個數,
(11). 保護內容中的{{}}不被編譯: v-pre
(12). 今后只要想獲得表單元素的值或狀態: v-model
系結樣式分析(了解):
(1). 需要精確修改某一個css屬性,就系結style:
a. <元素 style=“固定樣式” :style="{css屬性:變數名, …}"
data:{
變數名:css屬性值
... : ...
}
b. <元素 style=“固定樣式” :style=“變數名”
data:{
變數名:{
css屬性名: 屬性值,
... : ...
}
}
(2). 只要批量修改一個元素的多個css屬性就系結class
a. <元素 class=“固定class” :class="{class名:變數名, …}"
data:{
變數名:true或false,
... : ...
}
b. <元素 class=“固定class” :class=“變數名”
data:{
變數名:{
class名:true或false,
... : ...
}
}
計算屬性應用實踐
今后只要根據其他變數的值動態計算出一個屬性值就用計算屬性:
<元素>{{計算屬性}}</元素>
new Vue({
el:"#app",
data:{...},
methods:{...},
computed:{
計算屬性名(){
計算程序
return 計算結果
}
}
})
生命周期函式應用
vue生命周期4個階段 8個鉤子函式
(1). 創建(create)
created(){ ... }
beforeMount(){ ... }
(2). 掛載(mount)
mounted(){ ... 經常在這里發送ajax請求 ... }
beforeUpdate(){ ... }
(3). 更新(update)
updated(){ ... }
beforeDestroy(){ ... }
(4). 銷毀(destroy)
destroyed(){ ... }
Axios方式的Ajax請求
只要在vue中發送ajax請求,就用axios
axios.defaults.baseURL=“服務器端介面的公共基礎地址部分”
Get請求
GET請求:
axios.get(
"服務器端介面地址的相對路徑",
{
params:{ 引數名: 引數值, ... }
}
).then(result=>{
... result.data...
})
Post請求
POST請求:
axios.post(
"服務器端介面地址的相對路徑",
"引數名1=引數值1&引數名2=引數值2&..."
).then(result=>{
... result.data...
})
強調: 在vue內使用axios,then中必須用箭頭函式,保持then內this與外部this一致,都指向當前new Vue()物件
VUE 組件化開發
組件設計
只要希望重用一塊獨立的功能區域就用組件:
(1). 定義組件
Vue.component(組件標簽名,{
template:HTML內容片段,
data(){ return { 變數 } },
//其余和new Vue()完全相同
})
(2). 在HTML中使用自定義組件
<組件標簽名/>或雙標記也行
(3). 原理: new Vue()掃描到自定義組件標簽,
a.組件的template中的HTML內容代替頁面中<組件標簽>位置,
b. 并為這個小區域專門創建一個縮微版的vue型別物件,
1). 呼叫組件的data()函式為當前組件副本創建一個專屬資料物件副本,
2). 引入組件物件中的methods等其他內容到當前組件物件副本中
基本步驟
a. 拿到頁面先劃分功能區域
1). 從上到下,按功能不同劃磁區域
2). 按是否重用劃分
b. 為每個組件創建獨立的.js檔案,其中包含一個組件物件及其內容
c. 將所有組件引入唯一完整的html頁面中,并在
運行分析
a. new Vue()掃描
b. 父組件掃描自己內部的template內容,創建并替換子組件
組件型別
a. 根組件: new Vue()
b. 全域組件: Vue.component(…)
c. 子組件: 3步
1). var 子組件物件名={
內容必須符合組件的要求
}
子組件物件名必須是駝峰命名
2). 父組件物件中:{
… …
components{ 子組件物件名, … ,… }
}
子組件物件名必須是駝峰命名
3). 父組件template中用<子組件標簽名/>引入子組件內容
components會將子組件物件名的駝峰命名自動翻譯為-分隔
所以, 使用子組件標簽時,要用-分隔多個單詞
組件間傳參
a. 父組件給子組件
<子組件 :自定義屬性名=“父組件變數”>
b. 子組件取:
props:[“自定義屬性名”]
結果: 在子組件內,props中的"自定義屬性名"與子組件自己data中的變數用法完全相同!
單頁應用實踐(SPA)
基本步驟
第一步: 先創建唯一完整的HTML頁面
1). 包含vue基本的頁面結構
<div id="app"> new Vue({el:"#app"})
2). 引入所有必要的檔案和組件
vue-router.js, 其它頁面或組件檔案, router.js路由器物件所在檔案
3).
第二步: 再為每個頁面組件創建獨立的檔案,每個頁面組件其實都是一個子組件
第三步: 創建router.js檔案,例如:
1)創建路由字典物件
var routes=[
{path:"/", component:首頁組件物件名},
{path:"/相對路徑" , component: 其它頁面組件物件名},
{path:"*", component: 404頁面組件物件 }
]
2). 創建路由器物件,并將路由字典物件轉入路由器物件中
var router=new VueRouter({ routes })
3). 將router物件加入到new Vue()中
new Vue({ el:"#app", router })
頁頭等全域組件:
a. 創建獨立的檔案保存頁頭組件的內容
b. 使用Vue.component(“my-header”,{ … })將頁頭創建為全域組件
c. 在唯一完整的HTML頁面中引入頁頭組件檔案
d. 使用頁頭組件標簽: 2種:
1). 如果所有頁面都有統一的頁頭:
就放在唯一完整的html頁面中外部上方
2). 如果有的頁面有頁頭,有的頁面沒有頁頭:
就只放在需要頁頭的組件中的template中
路由跳轉
a. html中: 文本
b. js中: this.$router.push("/相對路徑")
路由傳參
a. 修改路由字典:
{path:"/相對路徑/:自定義引數名", component:頁面組件物件, props:true}
b. 跳轉時:
<router-link to="/相對路徑/引數值"
或
this.$router.push("/相對路徑/引數值")
c. 下一個頁面接:
1). props:[ '自定義引數名' ]
2). 可將"自定義引數名"用作系結或程式中都行
安裝vue腳手架
(1). 設定npm默認使用國內淘寶鏡像倉庫:
npm config set registry http://registry.npm.taobao.org
備選: npm i -g cnpm --registry=http://registry.npm.taobao.org
(2). 安裝可反復生成專案腳手架代碼的工具:
npm i -g @vue/cli
備選: cnpm i -g @vue/cli
(3). 啟動vue腳手架專案
npm run serve
(4). 打開瀏覽器,地址欄輸入:
http://localhost:8080
腳手架檔案夾結構:
(1). 唯一完整的HTML頁面: 一分為三:
a. public檔案夾
1). 圖片img檔案夾放在public檔案夾下
2). 第三方css的壓縮版和第三方js的壓縮版都放在public檔案夾下
3). 唯一完整的HTML檔案index.html中,head中引入第三方的css和js
b. src/App.vue
1). 下只包含公共的頁頭組件和
2).
1). import引入App.vue,router,axios,以及其他全域組件
2). 將全域組件物件轉為真正的全域組件: Vue.component( “組件標簽名”, 全域組件物件 )
3). 配置axios并放入原型物件中:
axios.defaults.baseURL=“服務器端基礎路徑”
Vue.prototype.axios=axios;
(2). 為每個頁面創建.vue組件檔案,都放在src/views檔案夾下,每個.vue檔案中:
a. 標簽內,包含這個頁面的HTML內容
b. 中的js內容,和前四天將的是完全一樣的寫法,系結,指令,函式,生命周期,axios請求等都一樣,前四天怎么用,這里就怎么用,
(3). 路由字典和路由器物件,在src/router/index.js檔案中
a. 僅import首頁組件物件,不要過早引入其它頁面組件
b. 路由字典中首頁組件: { path:"/", component:首頁組件物件}
c. 其余頁面組件都做成懶加載:
{
path: ‘/相對路徑’,
component: () => import(/* webpackChunkName: “組件名” */ ‘…/views/其它頁面組件.vue’)
}
(4). 全域組件都放在src/components檔案夾下,每個全域組件.vue檔案中,
全域組件必須在main.js引入,并用Vue.component()轉化,為真正的全域組件,才能在其它組件的HTML中使用,
(5). 運行時, 路由器router物件監視瀏覽器地址欄路徑變化,
查找對應的頁面組件內容,先代替App.vue中的,然后main.js再將包含要加載的頁面內容的App.vue組件內容,替換到唯一完整的index.html中空
懶加載應用實踐
異步延遲加載:
src/router/index.js
//不要import Details from "../views/Details"
const routes=[
...
{
path:"/details/:lid",
component: () => import(
/* webpackChunkName: "details" */
'../views/Details.vue'
),
props:true
]
徹底懶加載:
專案根目錄創建vue.config.js
module.exports={
chainWebpack:config=>{
config.plugins.delete("prefetch")
//洗掉index.html開頭的帶有prefetch屬性的link,不要異步下載暫時不需要的頁面組件檔案
},
}
http-proxy方式跨域:
vue.config.js設定
module.exports={
... ,
devServer: {
proxy: {
'/': {
target: `服務器端介面地址公共基礎路徑`,
changeOrigin: true
}
}
}
}
main.js
axios.defaults.baseURL="服務器端公共基礎路徑"
(3).參考 this.axios.get(“/介面地址相對路徑”).then(result=>{…})
避免組件間樣式沖突
(1)方案1
<style scoped>
(2)方案2
<template>
<組件父元素 class="組件名">
</template>
<style>
.組件名>子元素選擇器{ ... }
</style>
watch+事件修飾符+防抖:
(1). 希望變數一變化就自動執行一項操作時:
data(){
return { 變數: 值 }
},
watch:{
變數(){
要執行的操作
}
}
(2). 事件修飾符:
@事件.13 按回車時才執行
@事件.stop 阻止冒泡
@事件.prevent 阻止默認行為
(3). 防抖:
data(){
return {
... ,
timer:null
}
},
methods:{
查找方法(){
if(this.timer!=null){
clearTimeout(this.timer)
}
this.timer=setTimeout(()=>{
正式的查找操作
},等待時間)
}
}
插槽技術應用
(1). 只要多個組件擁有相同的結構,只是區域的內容不同,都可用插槽實作
(2). 如何:
a. 先額外創建一個帶插槽的外殼組件,保存其它多個組件相同部分的HTML+CSS+JS,但是,外殼組件中將來可能變化的位置,用標記
b. 再定義其它使用外殼組件的組件:
1). 引入帶插槽的外殼組件:
import 外殼組件名 from "./外殼組件.vue"
export default {
components:{ 外殼組件名 },
...
}
2). 在其它組件中:
<template>
<外殼組件 :外殼組件所需屬性="變數">
<當前組件自有的個性化內容>
</外殼組件>
</template>
(3). 具名插槽:
a. 如果一個外殼組件中,多個部位將來都會被更換,就可用具名插槽
b. 如何:
1). 外殼組件中:
<template>
...公共部分...
<slot name="插槽名1"></slot>
...公共部分...
<slot name="插槽名2"></slot>
...公共部分...
<template>
2). 其它使用外殼組件的組件:
<template>
<外殼組件...>
<template #插槽名1>
第一部分要更換的內容
</template>
...
<template #插槽名2>
第二部分要更換的內容
</template>
</外殼組件>
</template>
Vuex 資料管理
應用場景
今后只要多個組件都需要共用一批資料時,都可用vuex
構成分析(3部分)
state部分:
state:{ //保存共用的變數
變數:初始值,
... : ...
}
mutations部分:
mutations:{ //保存專門修改變數的方法
set變數名(state, 新值){
state.變數名=新值
}
...
}
actions部分:
actions:{ //保存專門先發送ajax請求,再修改變數的方法
方法名(context, 發給服務器的引數值){
axios.get或post(
"介面地址",
發給服務器端的引數值
).then(result=>{
...
context.commit("mutations中某個方法名", 新值)
...
})
}
}
組件中使用state中的變數
a. import { mapState } from “vuex”
b. export default {
computed:{
…mapState([ “state中某變數名”, … ]),
其它計算屬性
}
}
c. 中可用state中某變數名用于系結和指令
d. js中可this. state中某變數名來讀取變數值
組件中修改state中的變數值
a. import { mapMutations } from “vuex”
b. export default {
methods:{
…mapMutations ([ “Mutations中某方法名”, … ]),
其它方法
}
}
c. js中可用this. Mutations中某方法名(實參值)修改state中變數值
組件中先發ajax請求再修改state中變數值
a. import { mapActions } from “vuex”
b. export default {
methods:{
…mapActions ([ “Actions中某方法名”, … ]),
其它方法
}
}
c. js中可用this. Actions中某方法名(實參值)發送ajax請求并修改state中變數值,
TypeScript 基本語法
變數:
var或let或const 變數名:資料型別=值;
函式:
(1).定義:
function 函式名(形參:資料型別, …):回傳值型別{
… …
}
(2). 不確定引數個數:
a. 單個引數不確定有沒有
function 函式名(形參1:資料型別, 形參2?:資料型別)...
或
function 函式名(形參1: 資料型別, 形參2:資料型別=默認值)...
b. 多個引數不確定有沒有
function 函式名(形參1:資料型別, ...形參2:資料型別[])...
(3). 多載:
a. 先定義空的函式宣告,列舉所有多載的可能:
function 函式名():回傳值型別;
function 函式名(形參1: 資料型別):回傳值型別;
function 函式名(形參1: 資料型別, 形參2:資料型別):回傳值型別;
b. 正式實作功能的函式:
function 函式名(){
根據arguments中的元素個數,決定具體執行何種邏輯
}
class 新規定
(1). class 型別名{ //必須提前宣告屬性,才能使用
屬性1: 資料型別=初始值
屬性2: 資料型別=初始值
...
//建構式必須定義資料型別
constructor(形參1:資料型別, 形參2:資料型別,...){
this.屬性1=形參1;
this.屬性2=形參2;
...
}
/*方法定義...*/
}
(2). 訪問修飾符: 今后,只要想控制一個class中屬性的使用范圍時,
class 父{
public 公有屬性:資料型別=值
protected 受保護的屬性:資料型別=值
private 私有屬性:資料型別=值
父的函式(){
以上三種屬性都能用
}
}
class 子 extends 父{
子的函式(){
只能用父的公有屬性和父的受保護的屬性
不能用父的私有屬性
}
}
除父子class以外的程式區域:
只能用父class的物件的公有屬性
(3). 介面: 保證開發人員按照要求實作類的成員
a. 先定義介面:
interface I介面名{
屬性名:資料型別
...
方法名(形參:資料型別, ...):回傳值型別;
}
b. 定義class實作介面的要求:
class 型別名 implements I介面名{
屬性名:資料型別=值
...
方法名(形參:資料型別, ...):回傳值型別{
方法實作
}
}
模塊化開發:
(1). 模塊中只拋出一個東西:
export default 一個東西
import 別名 from "相對路徑"
(2). 模塊中同時拋出多個東西:
export { 多個東西用逗號分隔 }
import { 想要的個別東西用逗號分隔 } from "相對路徑"
Vue3 新特性介紹
原理
系結原理:ES6 Proxy代理物件+虛擬DOM樹
ES6 Proxy代理物件:
新生成的代理物件 = new Proxy(要保護或監視的原物件, {
//當有人試圖獲取陣列中任何一個元素值時自動觸發
get(當前物件, 屬性名) {
console.log(`有人試圖讀取arr物件的${屬性名}成員`)
return 當前物件[屬性名];
},
//當有人試圖修改陣列中任何一個元素值時自動觸發
set(當前物件, 屬性名, 新值) {
console.log(`有人試圖修改arr物件的${屬性名}成員`)
當前物件[屬性名] = 新值;
return true; //必須: 回傳修改成功!
}
});
//今后,都使用新代理物件,代替使用原物件,但是用法上和使用普通物件完全一樣!
main.ts 中實踐
a. 默認:
createApp(App).use(store).use(router).mount('#app’)
b. 全域組件:
import 組件物件 from “組件檔案相對路徑”
var app= createApp(App);
app.component('組件標簽名', 組件物件名)
app..use(store).use(router).mount('#app’)
c. 全域指令:
app.directive ("my-focus",{
mounted(DOM元素){
DOM操作
}
})
d. axios: //axios物件是單例模式,整個專案中只有一個axios物件,哪里使用都一樣,
import axios from “axios”
axios.defaults.baseURL=”服務器端介面基礎路徑”
//單例模式,不用放到原型物件中,也能在任意組件內參考——Vue2也可以這樣用,
頁面/組件
a. 里和
import { defineComponent, ref, reactive, toRefs, watch, computed, onMounted } from 'vue’;
import axios from “axios” //axios物件是單例模式,整個專案中只有一個axios物件,哪里使用都一樣,
import 子組件物件 from “子組件相對路徑”
export default defineComponent({
components:{ 子組件物件 },
directives:{
“自定義指令名”:{
mounted(DOM元素){
DOM操作
}
}
},
setup(){ //
const data=reactive({
界面所需變數
});
//專門解構原始型別的變數
let { 原始型別的變數, … } = toRefs(data);
//專門解構參考型別的變數
let {參考型別的變數, ...} = data;
const methods={
界面所需方法(){ … 使用data中變數,不用加this!但要加.value才能用 }
計算屬性:computed(()=>{ //vue3中沒有過濾器了,計算屬性兼顧過濾器職能
//計算程序
return 回傳值
})
}
watch(要監控的變數, ,(newVal, oldVal)=>{
console.log(`變數變了,新值為${newVal}, 舊值為${oldVal}`)
//變數變化時要執行的操作
})
//宣告周期必須自己先import,再在setup內部呼叫!
onMounted(){ //原mounted生命周期鉤子函式
//axios請求不用加this.
axios.get(…).then(result=>{ … })
}
return {
…toRefs(data.value),
…methods
}
},
})
新宣告周期鉤子函式
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
總結(Summary)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/300489.html
標籤:其他
