Vue3選項式風格-基礎部分篇
- 簡介
- 模板語法
- 文本插值
- 原始HTML
- Attribute 綁定
- 使用 JavaScript 表達式
- 調用函數
- 全局組件調用
- 內置指令
- 動態參數注意事項
- data()
- data()深度響應
- methods
- 有狀態的methods(防抖)
- DOM更新時機
- 計算屬性
- class和style綁定
- 條件渲染
- 列表渲染
- 數組變換偵聽
- 事件處理
- 表單輸入綁定
- 生命周期鉤子
- 偵聽器watch
- 模板引用ref
- 組件基礎
- 組件注冊
- 項目文件結構
- RootApp.vue
- main.js
- ChildApp.vue
- ChildApp1.vue
- ChildApp2.vue
- 其他注意事項
簡介
本篇知識點主要來自Vue官網,是對基礎部分知識的學習總結,適用于對vue稍微了解的人群,可以更加規范的使用Vue相關語法,本次代碼是腳手架搭建后修改根組件后的代碼,具體內容看最后的截圖,最后會附上修改和編輯后文件的全部代碼。
模板語法
我們先對一個SFC(單文件組件)的組成部分做一個了解。
<template><!-- 組件模板內容 -->
</template>
<script>export default(){//當前組件實例}
</script>
<style>組件模板樣式
</style>
文本插值
<template><!-- 1.雙花括號語法,里面是javascript表達式,組件的data數據發生變化時也會動態改變 --><h1>{{ msg + ":" + name }}</h1>
</template>
原始HTML
<template><!-- 2.html動態語言 -->{{htmls}}:<span v-html="htmls"></span>
</template>
Attribute 綁定
<template><!-- 3.1 Attribute 綁定 一般的Attribute如果綁定的為假值,則id 被移除--><!-- <div v-bind:id="id"> --><!-- v-bind:id簡寫成:id <div:id="id"> --><!-- 3.3 v-bind不指定Attribute可用接收Attribute對象 --><div v-bind="attributes"></div>
</template>
使用 JavaScript 表達式
<template><!-- 4.更加復雜的javascript表達式 --><div :id="`list-${id}`">{{number + 1}}{{ok ? "是":"否"}}{{msg.split("").reverse().join("")}}</div>
</template>
調用函數
<template><!-- 5.直接調用函數時,當頁面重新渲染,就會再次被調用函數,有幾個直接調用函數就會調用幾次,當頁面中的數據發生變化時,就會重新渲染 --><div>{{getNumber()}}</div>
</template>
全局組件調用
import { createApp } from 'vue'
import App from './RootApp.vue'let name = "呂懿洋"
// createApp(組件,組件的props對象)
let app = createApp(App, { name: name })// 6.設置全局變量,可被任意組件調用
app.config.globalProperties.rootObj = {author: 'lvyy'
}
app.mount('#app')
<template><!-- 6.全局組件可用直接調用 -->{{rootObj.author}}
</template>
內置指令
<!-- 7.1 v-text --><span v-text="msg"></span><span>{{msg}}</span><br /><!-- 7.2 v-html --><span v-html="htmls"></span><span><font color="red">紅色文字</font></span><br /><!-- 7.3 v-show --><span v-show="false">測試v-show</span><span style="display:none;">測試等價v-show</span><!-- 7.4 v-if v-else v-else-if --><span v-if="number == 1">number == 1</span><span v-else-if="number == 2">number == 2</span><span v-else>number != 1 且 number != 2</span><!-- 7.5 v-for key用于指定排序,key要求時字符串,且不要重復--><!-- 7.5.1 v-for = (value, index) in array --><div v-for="(peo,index) in forList" :key="index"><!-- 7.5.2 v-for = (value, key, index) in obj --><span v-for="(value,key,index1) in peo" :key="index + key + index1">{{`${index1} ${key} : ${value}`}}<br /></span><br /></div><!-- 7.6 v-on: --><!-- 7.6.1 v-on:的縮寫是@,如下是基本用法 --><button v-on:click="sayHello">hello1</button><br /><button @click="sayHello">hello2</button><br /><!-- 7.6.2 []可以賦予動態參數的事件類型, 注意動態參數應該只可能時字符串或者null,為null將移除該事件 --><button v-on:[event]="sayHello">hello3</button><br /><button @[event]="sayHello">hello4</button><br /><!-- 7.6.3 $event是內聯聲明的參數,按照個人理解:$event就是事件觸發時,這個綁定這個事件的標簽的各種信息,包括了觸發的方式鼠標還是鍵盤 --><button v-on:[event]="getMsg('hello',$event)">hello5</button><br /><button @[event]="getMsg('hello',$event)">hello6</button><br /><!-- 7.6.4 事件修飾符 --><!-- 7.6.4.1 stop 暫無應用場景 --><button v-on:[event].stop="getMsg('hello',$event)">hello7</button><br /><button @[event].stop="getMsg('hello',$event)">hello8</button><br /><!-- 7.6.4.2 prevent 暫無應用場景 --><button v-on:[event].prevent="getMsg('hello',$event)">hello9</button><br /><button @[event].prevent="getMsg('hello',$event)">hello10</button><br /><!-- 7.6.4.3 capture 暫無應用場景 --><button v-on:[event].capture="getMsg('hello',$event)">hello11</button><br /><button @[event].capture="getMsg('hello',$event)">hello12</button><br /><!-- 7.6.4.4 self 暫無應用場景 --><button v-on:[event].self="getMsg('hello',$event)">hello13</button><br /><button @[event].self="getMsg('hello',$event)">hello14</button><br /><!-- 7.6.4.5 once 應用場景只需要點擊一次的事件 --><button v-on:[event].once="getMsg('hello',$event)">hello15</button><br /><button @[event].once="getMsg('hello',$event)">hello16</button><br /><!-- 7.6.4.6 left,right,middle 經測試,在IE瀏覽器點擊沒有效果 --><button v-on:[event].left="getMsg('hello',$event)">hello17</button><br /><button @[event].left="getMsg('hello',$event)">hello18</button><br /><button v-on:[event].right="getMsg('hello',$event)">hello19</button><br /><button @[event].right="getMsg('hello',$event)">hello20</button><br /><button v-on:[event].middle="getMsg('hello',$event)">hello21</button><br /><button @[event].middle="getMsg('hello',$event)">hello22</button><br /><!-- 7.6.4.7 鍵盤按鍵指定觸發:keyup.鍵盤字母或其他 --><button v-on:keyup.x.once="getMsg('hello',$event)">hello23</button><br /><button @keyup.y="getMsg('hello',$event)">hello24</button><br /><!-- 7.6.4.8 子組件事件 --><ChildApp v-on:myEvent="getMsg('hello',$event)"></ChildApp><br /><ChildApp @myEvent="getMsg('hello',$event)"></ChildApp><br /><!-- 7.7 v-bind: --><!-- 7.7.1 綁定 靜態attribute --><img v-bind:src="imageSrc" /><!-- 7.7.2 綁定 動態attribute --><img v-bind:[attribute1]="imageSrc" /><!-- 7.7.3 綁定縮寫 --><img :[attribute1]="imageSrc" /><!-- 7.7.4 內聯字符串拼接 --><div :id="app4+'4'"></div><!-- 7.7.5 class 綁定 --><!-- 7.7.5.1 {靜態class名:boolean...} --><div :class="{red:isRed}">文字1</div><!-- 7.7.5.2 [動態class1,動態class2...] --><div :class="[className1,className2]">文字2</div><!-- 7.7.5.3 2混用1 --><div :class="[className1,{className2:true}]">文字3</div><!-- 7.7.6 style 綁定 --><!-- 7.7.6.1 {靜態style樣式:值...} --><div :style="{fontSize: 28 + 'px'}">文字1</div><!-- 7.7.6.2 [動態style樣式obj1,...] --><div :style="[style1,style2]">文字2</div><!-- 7.7.7 綁定對象形式的attribute --><div v-bind="attributes1">測試綁定ObjAttribute</div><!-- 7.7.8 單個prop 綁定 要求id,name都在子組件聲明--><ChildApp1 :id="id" :name="name"></ChildApp1><!-- 7.7.8 整個props 綁定 --><ChildApp1 v-bind="{id:'app6',name:name}"></ChildApp1>
動態參數注意事項
<!-- 8 動態參數的語法限定 --><!-- 8.1 參數數據類型應當是字符串或者為null,null是將事件移除,其他情況會報警告--><!-- 8.2 復雜的參數表達式類型應當用計算屬性來代替--><!-- 8.3 參數名應當全部小寫,如果大寫也會被識別為小寫 -->
data()
<script>data(){return {...}}</script><!-- 9.1 data選項的格式是一個函數,該函數返回一個obj數據 --><!-- 9.2 當組件被創建時,會調用data函數,返回的obj中的頂層屬性都會被代理到組件實例中,通過this調用,動態的渲染數據 --><!-- 9.3 需要被代理的屬性應該一開始就要放在data中,一開始不確認默認值時,可以賦null、undefined或其他值 --><!-- 9.4 vue暴露出來的內置api會以$開頭,暴露出來的內置屬性以_開頭,因此我們自定義的屬性和方法不要以符號開頭 -->
注意: 當一個obj賦值給this.obj時,賦值后this.obj是響應式狀態,而obj不是,因此他們兩個===比較為false
data()深度響應
<!-- 12.1 data中obj中的obj的屬性發生變化,也可以進行響應渲染 --><!-- 12.2 data中obj中的arr的發生變化,也可以進行響應渲染 -->
methods
<!-- 11 methods:{} methods是一個包含所有方法的對象--><!-- 11.1 methods中的方法永遠指向組件實例的this --><!-- 11.2 methods定義方法的時候,不可以用箭頭函數,因為箭頭函數沒有自己this上下文 -->
有狀態的methods(防抖)
<!-- 14 預置防抖的事件處理器 --><!-- 14.4 防抖函數調用 --><button @click="sayDelayHello1">防抖響應</button>
// 14.1 引入防抖函數(需要npm i lodash)import { debounce } from "lodash";export default(){data(){return{}},methods:{// 14.2 引入防抖函數(需要npm i lodash)sayHello1() {console.log("防抖函數2");},},created(){// 14.3 created中自定義的屬性,貌似不用再data中聲明,為了遵循規范還是再data中定義一下this.sayDelayHello1 = debounce(this.sayHello1, 1000);}}
DOM更新時機
<!-- 13.1 當響應式狀態發生變化,DOM就會更新 --><!-- 13.2 DOM更新不是同步的,而是進行周期渲染,到下一個周期前把響應式狀態改變的存入緩存隊列,到下一個周期后更新緩存隊列 --><!-- 13.3 周期執行完畢,可以再次執行回調函數 -->
計算屬性
<!-- 15.1 計算屬性的應用場景: 一個復雜的javascript表達式再組件中被多處使用,應該定義在計算屬性中代替顯示,簡化代碼,增加復用性 -->{{ reverseMsg }}<!-- 15.2 計算屬性和方法的區別調用的時機不同 --><!-- 15.2.1 計算屬性調用的情況發生在里面依賴的數據改變的時候,在多處使用的情況下,只會調用一次,更新緩存空間數據,頁面調用的是緩存中的數據--><!-- 15.2.2 非事件類型的方法調用,是一旦頁面重新渲染時,就會調用,調用的次數和顯示的次數一致--><!-- 15.2.3 因此,當我們可以用計算屬性代替方法的時候,優先使用計算屬性的方式 --><!-- 15.2.4 get方法里面不要有副作用,計算屬性一般不直接修改 -->
export default(){data(){return{msg1:'hello'}},computed: {// 計算屬性看上去像一個方法,其實他是一個屬性,如果里面只寫get方法,可以簡寫成這樣reverseMsg() {return this.msg1.split("").reverse().join("");},}
class和style綁定
<!-- 16.1 class靜態 --><span class="err">結果</span><!-- 16.2 class動態,是否綁定err --><span :class="{err:!isSuccess}">結果</span><!-- 16.3 class數組, 是否綁定errClass對應的class值 --><span :class="[errClass]">結果</span><!-- 16.4 計算屬性應用 --><button @click="isSuccess = !isSuccess">{{buttonName}}</button><span v-bind:class="spanClass">結果</span><!-- 16.5 組件元素使用class 單個根元素直接綁定,多個根元素可以在$attrs.class,接收父組件傳入的class --><ChildApp1 :class="{success:isSuccess}"></ChildApp1><!-- 16.6 style靜態 --><span style="color: red; font-size: 28px;">結果</span><!-- 16.7 style動態obj --><span :style="{color: 'red','font-size': 28+'px'}">結果</span><!-- 16.8 style動態obj數組 --><span :style="[{color: 'red'},{'font-size': 28+'px'}]">結果</span>
條件渲染
<!-- 17.1 v-if v-else v-else-if判斷是否渲染當前元素 --><!-- 17.2 切換多個元素,可以用template元素 --><!-- 17.3 切換多個元素,可以用template元素 --><!-- 17.4 v-show 相當于display:none; 不可以用于修飾template元素,沒有v-else --><!-- 17.5 v-if是真實的,也是惰性的,true才渲染元素,初始若false,則不會渲染元素,而v-show則是一開始就渲染元素,只是設置是否可見 -->
列表渲染
<!-- 18.1 數組: v-for="(item[,index]) in items" --><!-- 18.2 對象數組: v-for="({prop1, prop2}[,index]) in items" --><spanv-for="({id,name,age}, index) in forList":key="id+name+index">{{id + "-" + name + "-" + age + "\t"}}</span><!-- 18.3 對象: v-for="(value [,key ,index]) in obj" --><!-- 18.4 數值: v-for="n in number" n從1開始--><!-- 18.5 原則上v-for修飾的元素和內部都是可以直接使用v-for里面的數據,原因是v-for的優先級要高于其他attribute,但是因為v-for的優先級低于v-if,則v-if用不了v-for的數據,不建議v-if和v-for一個元素并用--><!-- 18.6 key是特殊的attribute, 可用于重用和排序元素,如果沒有key修飾,則是就地更新,key的值一般是字符串或者數值,不重復的 --><!-- 18.7 在for循環中建議加入key值 --><!-- 18.8 for循環作用于組件時, 數據不會自動傳入給組件,需要手動將數據指定給props, 我們需要注意傳入給組件的obj或數組類型的數據,組件里發生變化,父組件也會跟著變化,我們要子組件和父組件明確我們是否要共用數據(非常不建議)-->
數組變換偵聽
<!-- 19.1 Vue可以數據偵聽的變更方法 --><!-- 19.1.1 push(data1[,data2,data3...]) -> length: 尾部追加一條或多條數據,返回新長度 --><button @click="pushDatas">尾部追加</button><!-- 19.1.2 pop() -> data: 尾部移除一條數據,返回移除數據 --><button @click="popData">尾部刪除</button><!-- 19.1.3 shift() -> data:頭部移除一條數據,返回移除數據 --><button @click="shiftData">頭部刪除</button><!-- 19.1.4 unshift() -> length: 頭部追加一條或多條數據,返回新長度 --><button @click="unshiftDatas">頭部追加</button><!-- 19.1.5 splice(index,deleteLen[,addData]) -> deleteData: 從指定下標開始刪除,刪除指定的數目,刪除后替換指定數據 --><button @click="spliceDatas">替換</button><!-- 19.1.6 sort((a,b)=>{return a.xxx-b.xxx}) -> 排序,排序的方法前者大于后者時,排序為正序(從小到大排列),排序的方法后者大于前者時,排序為逆序(從大到小排列) --><button @click="sortAscDatas">正序</button><button @click="sortDescDatas">逆序</button><!-- 19.1.7 reverse(): 數組反轉 --><button @click="reverseDatas">反轉</button><!-- 19.1.8 filter(item=>{return ...}) -> newArray: 過濾符合條件的數據,返回新的數組,舊的數組不發生變化 --><!-- 19.1.9 concat(array) -> newArray: 合并兩個數組,返回新的數組,舊的數組不發生變化 --><!-- 19.1.10 slice(startIndex, endIndex) -> newArray: 截取指定下標范圍的數組,不包括endIndex,舊的數組不發生變化 --><!-- 19.2 如果我們要對現有列表進行過濾,不應該考慮v-for+v-if,而是創建一個計算屬性過濾現有的列表,v-for遍歷計算屬性解決,如果計算屬性無法解決,用于方法替換計算屬性 -->
事件處理
<!-- 20.1 內聯監聽事件時一個表達式就可處理簡單的事情 --><!-- 20.2 方法事件處理,有個$event參數,記錄事件觸發元素的詳細信息--><!-- 20.3 省略部分:事件修飾符,鍵盤修飾符,鼠標按鍵修飾符(實際業務開發應用較少) -->
表單輸入綁定
<!-- 21.1 常規方式 --><input :value="text" @input="event => text = event.target.value" /><!-- 21.2 v-model 是當輸入框內容變動時,text也會跟著改變--><input v-model="text" /><!-- 21.2.1 v-model.lazy 是輸入框內容輸入完畢,失焦后,text才會改變--><input v-model.lazy="text" /><!-- 21.2.2 v-model.number 如果text可以被parseFloat,則會轉換成number類型的數據,否則保留原樣--><input v-model.number="text" /><!-- 21.2.3 v-model.trim 輸入框自動去除前后空格--><input v-model.trim="text" /><!-- 21.3 textarea --><textarea :value="text" @input="event => text=event.target.value"></textarea><textarea v-model="text"></textarea><!-- 21.4 checkbox input checkbox v-model單個情況--><!-- 21.4.1 value默認情況是true/false,可以自定義true-value和false-value attribute自定義選中和不選中的value值 -->{{checked}}<input type="checkbox" v-model="checked" true-value="yes" false-value="no" /><!-- 21.5 checkbox input checkbox v-model相同情況,定義成數組-->{{names}}<input type="checkbox" v-model="names" :value="name1" /><input type="checkbox" v-model="names" :value="name2" /><input type="checkbox" v-model="names" :value="name3" /><!-- 21.6 radio單選 -->{{radioValue}}<input type="radio" v-model="radioValue" value="one" /><input type="radio" v-model="radioValue" value="two" /><!-- 21.7 selected選擇框 單選 -->{{selected}}<select v-model="selected"><option value disabled="true">請選擇</option><option>A</option><option>B</option><option>C</option></select><!-- 21.8 selected選擇框 多選 -->{{selected1}}<select v-model="selected1" multiple><option value="A">A.上班</option><option value="B">B.吃飯</option><option value="C">C.睡覺</option></select><!-- 21.9 selected選擇框的option中value可以綁定obj,v-model獲取的也就是obj -->{{selectObj}}<select v-model="selectObj"><optionv-for="option in selectedOptions":value="option":key="option.number">{{option.number}}</option></select>
生命周期鉤子
<!-- 22 生命周期鉤子執行順序:beforeCreate() created() beforeMount() mounted() beforeUpdate() updated() beforeUnmount() unmounted() -->
偵聽器watch
<!-- 23.1 偵聽器相比較于計算屬性,計算屬性里面不希望有DOM數據的變動或者異步請求,偵聽器則是處理需要有DOM數據變動或者異步請求的發送 -->
模板引用ref
<!-- 24.1 refs在mounted()生命周期函數之后使用,之前都是為null的 --><!-- 24.2 this.$refs.refName 表示當前的底層DOM -->聚焦輸入框:<input ref="input" v-model="userId1" /><!-- 24.3 組件上應用ref時,子組件可以通過expose:["data屬性名",...] 暴露出子組件的屬性,父組件可以通過 this.$refs.refName.屬性名 獲取到--><ChildApp1 ref="childApp1"></ChildApp1>
export default(){data(){return{userId:""}},watch: {userId: {handler(newValue, oldValue) {// this.searchDelayUserId();this.searchUserId();},// 23.2 immediate的觸發時機是在created生命周期鉤子之前,所以created中定義的有狀態的方法不能被調用immediate: true}},}
// 聚焦輸入框this.$refs["input"].focus();// 組件上應用ref時,子組件可以通過expose:["data屬性名",...] 暴露出子組件的屬性,// 父組件可以通過this.$refs.refName.屬性名 獲取到console.log(this.$refs.childApp1.childName);console.log(this.$refs.childApp1.childId);
組件基礎
<!-- 25.1 創建一個SFC --><!-- 25.2 引入SFC import xxx from "xxx.vue" --><!-- 25.3 注冊SFC components:{xxx} --><!-- 25.4 如果在SFC中使用模板,標簽建議使用駝峰命名方式,prop和屬性用是xxx-xxx, 元素可以使用閉合標簽 --><!-- 25.5 如果在HTML文件中使用模板, 都應該使用xxx-xxx, 元素不可以使用閉合標簽 --><!-- 25.6 監聽事件 this.$emit("事件名",參數...) --><!-- 25.7 emits:["事件名"] 可以暴露要監聽的事件--><!-- 25.8 插槽 <slot/> --><!-- 26.9 動態組件適用于來回切換組件的情況 --><!-- 26.10 不用keep-alive修飾時,切換注銷組件,用keep-alive修飾,暫存組件 --><button @click="componentName = componentName == 'ChildApp'?'ChildApp1':'ChildApp'">切換</button><keep-alive><component :is="componentName"></component></keep-alive>
組件注冊
<!-- 27.1 在根組件App注冊組件,可以全局使用 --><ChildApp2></ChildApp2><!-- 27.2 在SFC中注冊組件,后代組件不能使用 --><!-- 27.3 Props應當是向下傳遞,因此當傳遞的是對象或數組時,應當注意不應該直接改變,影響父組件的數據值,可以選擇事件回調,交由父組件操作 -->
項目文件結構
黃色截圖就是修改和新增的相關文件
RootApp.vue
<template><!-- 3.1 Attribute 綁定 一般的Attribute如果綁定的為假值,則id 被移除--><!-- <div v-bind:id="id"> --><!-- v-bind:id簡寫成:id <div:id="id"> --><!-- 3.3 v-bind不指定Attribute可用接收Attributes對象 --><div v-bind="attributes"><!-- 1.雙花括號語法,里面是javascript表達式,組件的data數據發生變化時也會動態改變 --><h1>{{ msg + ":" + name }}</h1><!-- 2.html動態語言 -->{{htmls}}:<span v-html="htmls"></span><br /><!-- 3.2 對于接收真假值的Attribute 不會被移除 --><button v-bind:disabled="disabled" @click="setNumber">不可點擊按鈕</button><!-- 4.更加復雜的javascript表達式 -->{{number + 1}}{{ok ? "是":"否"}}{{msg.split("").reverse().join("")}}<div :id="`list-${id}`"><!-- 5.直接調用函數時,當頁面重新渲染,就會再次被調用函數,有幾個直接調用函數就會調用幾次,當頁面中的數據發生變化時,就會重新渲染 -->{{getNumber()}}{{getNumber()}}<br /><!-- 6.全局組件可用直接調用 -->{{rootObj.author}}<br /><!-- 7.內置指令 --><!-- 7.1 v-text --><span v-text="msg"></span><span>{{msg}}</span><br /><!-- 7.2 v-html --><span v-html="htmls"></span><span><font color="red">紅色文字</font></span><br /><!-- 7.3 v-show --><span v-show="false">測試v-show</span><span style="display:none;">測試等價v-show</span><!-- 7.4 v-if v-else v-else-if --><span v-if="number == 1">number == 1</span><span v-else-if="number == 2">number == 2</span><span v-else>number != 1 且 number != 2</span><!-- 7.5 v-for key用于指定排序,key要求時字符串,且不要重復--><!-- 7.5.1 v-for = (value, index) in array --><div v-for="(peo,index) in forList" :key="index"><!-- 7.5.2 v-for = (value, key, index) in obj --><span v-for="(value,key,index1) in peo" :key="index + key + index1">{{`${index1} ${key} : ${value}`}}<br /></span><br /></div><!-- 7.6 v-on: --><!-- 7.6.1 v-on:的縮寫是@,如下是基本用法 --><button v-on:click="sayHello">hello1</button><br /><button @click="sayHello">hello2</button><br /><!-- 7.6.2 []可以賦予動態參數的事件類型, 注意動態參數應該只可能時字符串或者null,為null將移除該事件 --><button v-on:[event]="sayHello">hello3</button><br /><button @[event]="sayHello">hello4</button><br /><!-- 7.6.3 $event是內聯聲明的參數,按照個人理解:$event就是事件觸發時,這個綁定這個事件的標簽的各種信息,包括了觸發的方式鼠標還是鍵盤 --><button v-on:[event]="getMsg('hello',$event)">hello5</button><br /><button @[event]="getMsg('hello',$event)">hello6</button><br /><!-- 7.6.4 事件修飾符 --><!-- 7.6.4.1 stop 暫無應用場景 --><button v-on:[event].stop="getMsg('hello',$event)">hello7</button><br /><button @[event].stop="getMsg('hello',$event)">hello8</button><br /><!-- 7.6.4.2 prevent 暫無應用場景 --><button v-on:[event].prevent="getMsg('hello',$event)">hello9</button><br /><button @[event].prevent="getMsg('hello',$event)">hello10</button><br /><!-- 7.6.4.3 capture 暫無應用場景 --><button v-on:[event].capture="getMsg('hello',$event)">hello11</button><br /><button @[event].capture="getMsg('hello',$event)">hello12</button><br /><!-- 7.6.4.4 self 暫無應用場景 --><button v-on:[event].self="getMsg('hello',$event)">hello13</button><br /><button @[event].self="getMsg('hello',$event)">hello14</button><br /><!-- 7.6.4.5 once 應用場景只需要點擊一次的事件 --><button v-on:[event].once="getMsg('hello',$event)">hello15</button><br /><button @[event].once="getMsg('hello',$event)">hello16</button><br /><!-- 7.6.4.6 left,right,middle 經測試,在IE瀏覽器點擊沒有效果 --><button v-on:[event].left="getMsg('hello',$event)">hello17</button><br /><button @[event].left="getMsg('hello',$event)">hello18</button><br /><button v-on:[event].right="getMsg('hello',$event)">hello19</button><br /><button @[event].right="getMsg('hello',$event)">hello20</button><br /><button v-on:[event].middle="getMsg('hello',$event)">hello21</button><br /><button @[event].middle="getMsg('hello',$event)">hello22</button><br /><!-- 7.6.4.7 鍵盤按鍵指定觸發:keyup.鍵盤字母或其他 --><button v-on:keyup.x.once="getMsg('hello',$event)">hello23</button><br /><button @keyup.y="getMsg('hello',$event)">hello24</button><br /><!-- 7.6.4.8 子組件事件 --><ChildApp v-on:myEvent="getMsg('hello',$event)"></ChildApp><br /><ChildApp @myEvent="getMsg('hello',$event)"></ChildApp><br /><!-- 7.7 v-bind: --><!-- 7.7.1 綁定 靜態attribute --><img v-bind:src="imageSrc" /><!-- 7.7.2 綁定 動態attribute --><img v-bind:[attribute1]="imageSrc" /><!-- 7.7.3 綁定縮寫 --><img :[attribute1]="imageSrc" /><!-- 7.7.4 內聯字符串拼接 --><div :id="app4+'4'"></div><!-- 7.7.5 class 綁定 --><!-- 7.7.5.1 {靜態class名:boolean...} --><div :class="{red:isRed}">文字1</div><!-- 7.7.5.2 [動態class1,動態class2...] --><div :class="[className1,className2]">文字2</div><!-- 7.7.5.3 2混用1 --><div :class="[className1,{className2:true}]">文字3</div><!-- 7.7.6 style 綁定 --><!-- 7.7.6.1 {靜態style樣式:值...} --><div :style="{fontSize: 28 + 'px'}">文字1</div><!-- 7.7.6.2 [動態style樣式obj1,...] --><div :style="[style1,style2]">文字2</div><!-- 7.7.7 綁定對象形式的attribute --><div v-bind="attributes1">測試綁定ObjAttribute</div><!-- 7.7.8 單個prop 綁定 要求id,name都在子組件聲明--><ChildApp1 :id="id" :name="name"></ChildApp1><!-- 7.7.8 整個props 綁定 --><ChildApp1 v-bind="{id:'app6',name:name}"></ChildApp1><!-- 8 動態參數的語法限定 --><!-- 8.1 參數數據類型應當是字符串或者為null,null是將事件移除,其他情況會報警告--><!-- 8.2 復雜的參數表達式類型應當用計算屬性來代替--><!-- 8.3 參數名應當全部小寫,如果大寫也會被識別為小寫 --><!-- 9 data(){} --><!-- 9.1 data選項的格式是一個函數,該函數返回一個obj數據 --><!-- 9.2 當組件被創建時,會調用data函數,返回的obj中的頂層屬性都會被代理到組件實例中,通過this調用,動態的渲染數據 --><!-- 9.3 需要被代理的屬性應該一開始就要放在data中,一開始不確認默認值時,可以賦null、undefined或其他值 --><!-- 9.4 vue暴露出來的內置api會以$開頭,暴露出來的內置屬性以_開頭,因此我們自定義的屬性和方法不要以符號開頭 --><!-- 10 當一個obj賦值給this.obj時,注意:賦值后this.obj是響應式狀態,而obj不是,因此他們兩個===比較為false --><!-- 11 methods:{} methods是一個包含所有方法的對象--><!-- 11.1 methods中的方法永遠指向組件實例的this --><!-- 11.2 methods定義方法的時候,不可以用箭頭函數,因為箭頭函數沒有自己this上下文 --><!-- 12 深度響應 --><!-- 12.1 data中obj中的obj的屬性發生變化,也可以進行響應渲染 --><!-- 12.2 data中obj中的arr的發生變化,也可以進行響應渲染 --><!-- 13 DOM更新時機 --><!-- 13.1 當響應式狀態發生變化,DOM就會更新 --><!-- 13.2 DOM更新不是同步的,而是進行周期渲染,到下一個周期前把響應式狀態改變的存入緩存隊列,到下一個周期后更新 --><!-- 13.3 周期執行完畢,可以再次執行回調函數 --><!-- 14 預置防抖的事件處理器 --><!-- 14.3 防抖函數調用 --><button @click="sayDelayHello">防抖響應</button><!-- 14.4 在methods里設置有防抖狀態的函數,如果有多處調用,會相互影響 --><!-- 14.4.1 再面對一個函數,多處調用,且并不是每處調用都需要防抖時,需要如下設置 --><!-- 14.4.2 methods里定義沒有狀態的邏輯處理函數 --><!-- 14.4.3 防抖函數再created鉤子中聲明 --><!-- 14.4.4 這樣防抖函數和沒有狀態的邏輯處理函數就分開了,需要防抖調用,就用created中的防抖函數,不需要則使用methods中的函數 --><button @click="sayDelayHello1">防抖響應</button><button @click="sayHello1">非防抖響應</button><!-- 15. 計算屬性 --><!-- 15.1 計算屬性的應用場景: 一個復雜的javascript表達式再組件中被多處使用,應該定義在計算屬性中代替顯示,簡化代碼,增加復用性 -->{{ reverseMsg }}{{ reverseMsg }}<br />{{ reverseMsg }}{{ reverseMsg }}<br /><!-- 15.2 計算屬性和方法的區別調用的時機不同 --><!-- 15.2.1 計算屬性調用的情況發生在里面依賴的數據改變的時候,在多處使用的情況下,只會調用一次,更新緩存空間數據,頁面調用的是緩存中的數據--><!-- 15.2.2 非事件類型的方法調用,是一旦頁面重新渲染時,就會調用,調用的次數和顯示的次數一致--><!-- 15.2.3 因此,當我們可以用計算屬性代替方法的時候,優先使用計算屬性的方式 --><!-- 15.2.4 get方法里面不要有副作用,計算屬性一般不直接修改 -->{{ reverseMsg1 }}{{ reverseMsg1 }}<br />{{ reverseMsg1 }}{{ reverseMsg1 }}<br /><!-- 16. class和style綁定 --><!-- 16.1 class靜態 --><span class="err">結果</span><!-- 16.2 class動態,是否綁定err --><span :class="{err:!isSuccess}">結果</span><!-- 16.3 class數組, 是否綁定errClass對應的class值 --><span :class="[errClass]">結果</span><!-- 16.4 計算屬性應用 --><button @click="isSuccess = !isSuccess">{{buttonName}}</button><span v-bind:class="spanClass">結果</span><!-- 16.5 組件元素使用class 單個根元素直接綁定,多個根元素可以在$attrs.class,接收父組件傳入的class --><ChildApp1 :class="{success:isSuccess}"></ChildApp1><!-- 16.6 style靜態 --><span style="color: red; font-size: 28px;">結果</span><!-- 16.7 style動態obj --><span :style="{color: 'red','font-size': 28+'px'}">結果</span><!-- 16.8 style動態obj數組 --><span :style="[{color: 'red'},{'font-size': 28+'px'}]">結果</span><!-- 17. 條件渲染 --><!-- 17.1 v-if v-else v-else-if判斷是否渲染當前元素 --><!-- 17.2 切換多個元素,可以用template元素 --><!-- 17.3 切換多個元素,可以用template元素 --><!-- 17.4 v-show 相當于display:none; 不可以用于修飾template元素,沒有v-else --><!-- 17.5 v-if是真實的,也是惰性的,true才渲染元素,初始若false,則不會渲染元素,而v-show則是一開始就渲染元素,只是設置是否可見 --><!-- 18 列表渲染 --><!-- 18.1 數組: v-for="(item[,index]) in items" --><!-- 18.2 對象數組: v-for="({prop1, prop2}[,index]) in items" --><spanv-for="({id,name,age},index) in forList":key="id+name+index">{{id + "-" + name + "-" + age + "\t"}}</span><br /><!-- 18.3 對象: v-for="(value [,key ,index]) in obj" --><!-- 18.4 數值: v-for="n in number" n從1開始--><!-- 18.5 原則上v-for修飾的元素和內部都是可以直接使用v-for里面的數據,原因是v-for的優先級要高于其他attribute,但是因為v-for的優先級低于v-if,則v-if用不了v-for的數據,不建議v-if和v-for一個元素并用--><!-- 18.6 key是特殊的attribute, 可用于重用和排序元素,如果沒有key修飾,則是就地更新,key的值一般是字符串或者數值,不重復的 --><!-- 18.7 在for循環中建議加入key值 --><!-- 18.8 for循環作用于組件時, 數據不會自動傳入給組件,需要手動將數據指定給props, 我們需要注意傳入給組件的obj或數組類型的數據,組件里發生變化,父組件也會跟著變化,我們要子組件和父組件明確我們是否要共用數據--><!-- 19 數組變換偵聽 --><!-- 19.1 Vue可以數據偵聽的變更方法 --><!-- 19.1.1 push(data1[,data2,data3...]) -> length: 尾部追加一條或多條數據,返回新長度 --><button @click="pushDatas">尾部追加</button><!-- 19.1.2 pop() -> data: 尾部移除一條數據,返回移除數據 --><button @click="popData">尾部刪除</button><!-- 19.1.3 shift() -> data:頭部移除一條數據,返回移除數據 --><button @click="shiftData">頭部刪除</button><!-- 19.1.4 unshift() -> length: 頭部追加一條或多條數據,返回新長度 --><button @click="unshiftDatas">頭部追加</button><!-- 19.1.5 splice(index,deleteLen[,addData]) -> deleteData: 從指定下標開始刪除,刪除指定的數目,刪除后替換指定數據 --><button @click="spliceDatas">替換</button><!-- 19.1.6 sort((a,b)=>{return a.xxx-b.xxx}) -> 排序,排序的方法前者大于后者時,排序為正序(從小到大排列),排序的方法后者大于前者時,排序為逆序(從大到小排列) --><button @click="sortAscDatas">正序</button><button @click="sortDescDatas">逆序</button><!-- 19.1.7 reverse(): 數組反轉 --><button @click="reverseDatas">反轉</button><!-- 19.1.8 filter(item=>{return ...}) -> newArray: 過濾符合條件的數據,返回新的數組,舊的數組不發生變化 --><!-- 19.1.9 concat(array) -> newArray: 合并兩個數組,返回新的數組,舊的數組不發生變化 --><!-- 19.1.10 slice(startIndex, endIndex) -> newArray: 截取指定下標范圍的數組,不包括endIndex,舊的數組不發生變化 --><!-- 19.2 如果我們要對現有列表進行過濾,不應該考慮v-for+v-if,而是創建一個計算屬性過濾現有的列表,v-for遍歷計算屬性解決,如果計算屬性無法解決,用于方法替換計算屬性 --><!-- 20 事件處理 --><!-- 20.1 內聯監聽事件時一個表達式就可處理簡單的事情 --><!-- 20.2 方法事件處理,有個$event參數,記錄事件觸發元素的詳細信息--><!-- 20.3 省略部分:事件修飾符,鍵盤修飾符,鼠標按鍵修飾符(實際業務開發應用較少) --><!-- 21 表單輸入綁定 --><!-- 21.1 常規方式 --><input :value="text" @input="event => text = event.target.value" /><!-- 21.2 v-model 是當輸入框內容變動時,text也會跟著改變--><input v-model="text" /><!-- 21.2.1 v-model.lazy 是輸入框內容輸入完畢,失焦后,text才會改變--><input v-model.lazy="text" /><!-- 21.2.2 v-model.number 如果text可以被parseFloat,則會轉換成number類型的數據,否則保留原樣--><input v-model.number="text" /><!-- 21.2.3 v-model.trim 輸入框自動去除前后空格--><input v-model.trim="text" /><!-- 21.3 textarea --><textarea :value="text" @input="event => text=event.target.value"></textarea><textarea v-model="text"></textarea><!-- 21.4 checkbox input checkbox v-model單個情況--><!-- 21.4.1 value默認情況是true/false,可以自定義true-value和false-value attribute自定義選中和不選中的value值 -->{{checked}}<input type="checkbox" v-model="checked" true-value="yes" false-value="no" /><!-- 21.5 checkbox input checkbox v-model相同情況,定義成數組-->{{names}}<input type="checkbox" v-model="names" :value="name1" /><input type="checkbox" v-model="names" :value="name2" /><input type="checkbox" v-model="names" :value="name3" /><!-- 21.6 radio單選 -->{{radioValue}}<input type="radio" v-model="radioValue" value="one" /><input type="radio" v-model="radioValue" value="two" /><!-- 21.7 selected選擇框 單選 -->{{selected}}<select v-model="selected"><option value disabled="true">請選擇</option><option>A</option><option>B</option><option>C</option></select><!-- 21.8 selected選擇框 多選 -->{{selected1}}<select v-model="selected1" multiple><option value="A">A.上班</option><option value="B">B.吃飯</option><option value="C">C.睡覺</option></select><!-- 21.9 selected選擇框的option中value可以綁定obj,v-model獲取的也就是obj -->{{selectObj}}<select v-model="selectObj"><optionv-for="option in selectedOptions":value="option":key="option.number">{{option.number}}</option></select><!-- 22 生命周期鉤子:beforeCreate() created() beforeMount() mounted() beforeUpdate() updated() beforeUnmount() unmounted() --><!-- 23 偵聽器watch --><!-- 23.1 偵聽器相比較于計算屬性,計算屬性里面不希望有DOM數據的變動或者異步請求, 偵聽器則是處理需要有DOM數據變動或者異步請求的發送 -->工號:<input v-model="userId" /><!-- 24 模板引用ref --><!-- 24.1 refs在mounted()周期函數之后使用,之前都是為null的 --><!-- 24.2 this.$refs.refName 表示當前的底層DOM -->聚焦輸入框:<input ref="input" v-model="userId1" /><!-- 24.3 組件上應用ref時,子組件可以通過expose:["data屬性名",...] 暴露出子組件的屬性,父組件可以通過 this.$refs.refName.屬性名 獲取到--><ChildApp1 ref="childApp1"></ChildApp1><!-- 25 組件基礎 --><!-- 25.1 創建一個SFC --><!-- 25.2 引入SFC import xxx from "xxx.vue" --><!-- 25.3 注冊SFC components:{xxx} --><!-- 25.4 如果在SFC中使用模板,元素建議使用駝峰命名方式,prop和元素可以是xxx-xxx, 元素可以使用閉合標簽 --><!-- 25.5 如果在HTML文件中使用模板,prop, prop和元素應該使用xxx-xxx, 元素不可以使用閉合標簽 --><!-- 25.6 監聽事件 this.$emit("事件名",參數...) --><!-- 25.7 emits:["事件名"] 可以暴露要監聽的事件--><!-- 25.8 插槽 <slot/> --><!-- 26.9 動態組件適用于來回切換組件的情況 --><!-- 26.10 不用keep-alive修飾時,切換注銷組件,用keep-alive修飾,暫存組件 --><button @click="componentName = componentName == 'ChildApp'?'ChildApp1':'ChildApp'">切換</button><keep-alive><component :is="componentName"></component></keep-alive><!-- 27.1 在根組件App注冊組件,可以全局使用 --><ChildApp2></ChildApp2><!-- 27.2 在SFC中注冊組件,后代組件不能使用 --><!-- 27.3 Props應當是向下傳遞,因此當傳遞的是對象或數組時,應當注意不應該直接改變,影響父組件的數據值,可以選擇事件回調,交由父組件操作 --><!-- 27.4 組件標簽采用駝峰命名,組件中的Attribute采用xxx-xxx方式使用,命名使用駝峰命名 --></div></div>
</template><style scoped>
.red {font-size: 28px;
}
.className1 {font-size: 28px;
}
.className2 {color: red;
}
.success {color: green;
}
.err {color: red;
}
</style><script>
// 引入一個子組件
import ChildApp from "./components/ChildApp.vue";
import ChildApp1 from "./components/ChildApp1.vue";
// 引入一張圖片
import img1 from "./img/1.png";
// 14.1 引入防抖函數(需要npm i lodash)
import { debounce } from "lodash";
export default {// 父組件傳入的數據props: {name: String},// 子組件components: { ChildApp: ChildApp, ChildApp1: ChildApp1 },// 本組件定義的數據data() {return {id: "app2",msg: "hello world",htmls: "<font color='red'>紅色文字</font>",disabled: false,attributes: {id: "app3",name: "div1"},number: 1,ok: true,forList: [{id: 1,name: "張三",age: 18},{id: 2,name: "李四",age: 20}],event: "click",imageSrc: img1,attribute1: "src",app4: "app",isRed: true,className1: "className1",className2: "className2",style1: {fontSize: "28px"},style2: {color: "red"},attributes1: {id: "app5","other-attr": "hello"},name: "美少女",sayDelayHello1: null,msg1: "i love you",submit: "提交",revert: "還原",isSuccess: false,errClass: "err",text: "hello",checked: "no",name1: "張三",name2: "李四",name3: "王五",names: [],radioValue: "",selected: "",selected1: [],selectedOptions: [{ number: 1 }, { number: 2 }, { number: 3 }],selectObj: "",userId: "",userId1: "",componentName: "ChildApp"};},created() {// created中自定義的屬性,貌似不用再data中聲明,為了遵循規范還是再data中定義一下this.sayDelayHello1 = debounce(this.sayHello1, 1000);console.log(this.sayDelayHello1);this.user = "name";console.log(this.user);this.searchDelayUserId = debounce(this.searchUserId, 1000);},computed: {// 計算屬性看上去像一個方法,其實他是一個屬性,如果里面只寫get方法,可以簡寫成這樣reverseMsg() {console.log("hello");return this.msg1.split("").reverse().join("");},// 非簡寫形式reverseMsg1: {get() {return this.msg1.split("").reverse().join("");},set(newValue) {console.log("改變了");}},// 復雜的表達式寫在計算屬性中spanClass: {get() {return {success: this.isSuccess,err: !this.isSuccess};}},buttonName: {get() {return this.isSuccess ? this.revert : this.submit;}}},watch: {userId: {handler(newValue, oldValue) {// this.searchDelayUserId();this.searchUserId();},// 23.2 immediate的觸發時機是在created之前,所以created中定義的有狀態的方法不能被調用immediate: true}},mounted() {this.$refs["input"].focus();console.log(this.$refs.childApp1.childName);console.log(this.$refs.childApp1.childId);},// 本組件定義的方法methods: {setNumber() {this.number = this.number + 1;},getNumber() {console.log("msg改變就會觸發事件");return this.number;},sayHello() {console.log("hello world!");console.log(this.user);},getMsg(param1, event) {console.log(param1);console.log(event);},// 14.2 設置防抖函數 調用函數名:debounce(業務處理函數, 防抖毫秒數)sayDelayHello: debounce(function() {console.log("防抖函數");}, 1000),sayHello1() {console.log("防抖函數2");},// 尾部追加多個數據pushDatas() {let data1 = { id: 3, name: "王五", age: 22 };let data2 = { id: 4, name: "秦六", age: 33 };let length = this.forList.push(data1, data2);console.log("追加后長度為:" + length);},// 尾部刪除一個數據popData() {let data = this.forList.pop();console.log("刪除尾部數據:", data);},// 頭部追加一條或多條數據unshiftDatas() {let data1 = { id: 3, name: "王五", age: 22 };let data2 = { id: 4, name: "秦六", age: 33 };let length = this.forList.unshift(data1, data2);console.log("頭部追加后長度為:" + length);},// 頭部刪除數據shiftData() {let data = this.forList.shift();console.log("頭部刪除數據為:", data);},// 替換數據spliceDatas() {let data1 = { id: 3, name: "王五", age: 22 };let data2 = { id: 4, name: "秦六", age: 33 };let data = this.forList.splice(0, 1, data1, data2);console.log("替換前的數據為:", data);},// 正序sortAscDatas() {this.forList.sort((a, b) => a.id - b.id);},// 逆序sortDescDatas() {this.forList.sort((a, b) => b.id - a.id);},// 反轉reverseDatas() {this.forList.reverse();},searchUserId() {console.log("檢索userId");}}
};
</script>
main.js
import { createApp } from 'vue'import App from './RootApp.vue'
import ChildApp2 from './components/ChildApp2.vue'let name = "呂懿洋"
// createApp(組件,組件的props對象)
let app = createApp(App, { name: name })// 貌似沒有效果
app.config.errorHandler = (err) => {/* 處理錯誤 */console.log(err)
}// 6.設置全局變量,可被任意組件調用
app.config.globalProperties.rootObj = {author: 'lvyy'
}app.component("ChildApp2",ChildApp2)app.mount('#app')
ChildApp.vue
<template><div><input v-model="data" /><button @click="childClick">子組件按鈕</button></div>
</template><script>
export default {name: "ChildApp",data() {return {data: ""};},methods: {childClick() {this.$emit("myEvent");}}
};
</script>
ChildApp1.vue
<template><div><input v-model="data" /><div :class="$attrs.class">{{id + "-" + name}}</div></div>
</template><script>
export default {name: "ChildApp1",props: {id: String,name: String},data() {return {childName: "ChildApp1",childId: "ChildApp1",data: ""};},expose: ["childName"]
};
</script>
ChildApp2.vue
<template><div><input v-model="data" /></div>
</template><script>
export default {name: "ChildApp2",data() {return {childName: "ChildApp2",childId: "ChildApp2",data: ""};},expose: ["childName"]
};
</script>
其他注意事項
- 圖片自行填充
- 需要執行命令
npm i lodash
再執行npm install
,最后npm run dev
,主要是為了下載防抖函數的插件