總結vue知識體系之基礎入門篇
阿新 • • 發佈:2021-01-02
### Vue 的優缺點是什麼 優點: 1. 低耦合。檢視(View)可以獨立於 Model 變化和修改,一個 ViewModel 可以繫結到不同的 View 上,當 View 變化的時候 Model 可以不變,當 Model 變化的時候 View 也可以不變。 2. 可重用性。你可以把一些檢視邏輯放在一個 ViewModel 裡面,讓很多 view 重用這段檢視邏輯。 3. 獨立開發。開發人員可以專注於業務邏輯和資料的開發(ViewModel),設計人員可以專注於頁面設計,使用 Expression Blend 可以很容易設計介面並生成 xml 程式碼。 4. 可測試。介面素來是比較難於測試的,而現在測試可以針對 ViewModel 來寫。5. vue 是單頁面應用,使頁面區域性重新整理,不用每次跳轉頁面都要請求所有資料和 dom,這樣大大加快了訪問速度和提升使用者體驗。而且他的第三方 ui 庫很多節省開發時間 缺點:不利於 SEO,社群維護力度不強,相比還不夠成熟 ### vue 常用指令 - ``v-html / v-text``:把值中的標籤渲染出來 - ``v-model``: 放在表單元素上的,實現雙向資料繫結 - ``v-bind``(縮寫 :):用於繫結行內屬性 - ``v-if / v-show`` 是否能顯示,true 能顯示,false 不能顯示 - ``v-cloak``:需要配合 css 使用:解決小鬍子顯示問題- ``v-once`` 對應的標籤只渲染一次 - ``v-for`` :迴圈顯示元素 - ``v-on`` 事件繫結 ### 事件修飾符 ``Vue.js`` 為 ``v-on`` 提供了事件修飾符,修飾符是由點開頭的指令字尾來表示的。 - ``stop``:阻止事件繼續傳播 - ``prevent``:阻止事件預設行為 - ``capture``:新增事件監聽器時使用事件捕獲模式 - ``self``:當前元素觸發時才觸發事件處理函式 - ``once``:事件只觸發一次 - ``passive``:告訴瀏覽器你不想阻止事件的預設行為,不能和.prevent 一起使用。 ```html<!-- 阻止單擊事件繼續傳播 --> <a v-on:click.stop="toDo"></a> <!-- 提交事件不再過載頁面 --> <form v-on:submit.prevent="toSubmit"></form> <!-- 修飾符可以串聯 --> <a v-on:click.stop.prevent="toDo"></a> <!-- 只有修飾符 --> <form v-on:submit.prevent></form> <!-- 新增事件監聽器時使用事件捕獲模式 --> <!-- 即內部元素觸發的事件先在此處理,然後才交由內部元素進行處理 --> <div v-on:click.capture="toDo">...</div> <!-- 只當在 event.target 是當前元素自身時觸發處理函式 --> <div v-on:click.self="toDo">...</div> <!-- 點選事件將只會觸發一次 --> <a v-on:click.once="toDo"></a> <!-- 滾動事件的預設行為 (即滾動行為) 將會立即觸發 --> <div v-on:scroll.passive="onScroll">...</div> ``` ### 表單修飾符 * .lazy 在輸入框輸入完內容,游標離開時才更新檢視 * .trim 過濾首尾空格 * .number 如果先輸入數字,那它就會限制你輸入的只能是數字;如果先輸入字串,那就相當於沒有加.number ### 過濾器 filter 過濾器是對即將顯示的資料做進一步的篩選處理,然後進行顯示,值得注意的是過濾器並沒有改變原來的資料,只是在原資料的基礎上產生新的資料。 1. 定義過濾器 全域性註冊 ```js Vue.filter('myFilter', function (value1[,value2,...] ) { // 程式碼邏輯 }) ``` 區域性註冊 ```js new Vue({ filters: { 'myFilter': function (value1[,value2,...] ) { // 程式碼邏輯 } } }) ``` 2. 使用過濾器 ```html <!-- 在雙花括號中 --> <div>{{ message | myFilter }}</div> <!-- 在 `v-bind` 中 --> <div v-bind:id="message | myFilter"></div> ``` ### 計算屬性 computed 依賴其它屬性值,並且 ``computed`` 的值有快取,只有它依賴的屬性值發生改變,下一次獲取 ``computed`` 的值時才會重新計算 ``computed`` 的值; ```html <div id="example"> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMessage }}"</p> </div> <script> var vm = new Vue({ el: '#example', data: { message: 'Hello' }, computed: { // 計算屬性的 getter reversedMessage: function() { // `this` 指向 vm 例項 return this.message.split('').reverse().join('') } } }) </script> ``` ### 監聽屬性 watch 觀察和響應 Vue 例項上的資料變動。類似於某些資料的監聽回撥 ,每當監聽的資料變化時都會執行回撥進行後續操作。它可以有三個引數 - ``handler``:其值是一個回撥函式。即監聽到變化時應該執行的函式 - ``deep``:其值是 true 或 false;確認是否深入監聽。 - ``immediate``:其值是 true 或 false,確認是否以當前的初始值執行 handler 的函式 ```js watch:{ message:{ handler:function(val, oldVal){ console.log(val, oldVal) }, deep: true, immediate: true } } ``` ### computed 和 watch 的區別 - ``computed``: 是計算屬性,依賴其它屬性值,並且 computed 的值有快取,只有它依賴的屬性值發生改變,下一次獲取 computed 的值時才會重新計算 computed 的值; - ``watch``: 更多的是「觀察」的作用,類似於某些資料的監聽回撥 ,每當監聽的資料變化時都會執行回撥進行後續操作。 **運用場景** - 當我們需要進行數值計算,並且依賴於其它資料時,應該使用 computed,因為可以利用 computed 的快取特性,避免每次獲取值時,都要重新計算; - 當我們需要在資料變化時執行非同步或開銷較大的操作時,應該使用 watch,使用 watch 選項允許我們執行非同步操作 ( 訪問一個 API ),限制我們執行該操作的頻率,並在我們得到最終結果前,設定中間狀態。這些都是計算屬性無法做到的。 ### 生命週期函式 - ``beforeCreate``(建立前) vue 例項的掛載元素\$el 和資料物件 data 都是 undefined, 還未初始化 - ``created``(建立後) 完成了 data 資料初始化, el 還未初始化 - ``beforeMount``(載入前) vue 例項的\$el 和 data 都初始化了, 相關的 render 函式首次被呼叫 - ``mounted``(載入後) 此過程中進行 ajax 互動 - ``beforeUpdate``(更新前) - ``updated``(更新後) - ``beforeDestroy``(銷燬前) - ``destroyed``(銷燬後) **Vue 的父元件和子元件生命週期鉤子執行順序是什麼?** 1. 渲染過程:父元件掛載完成一定是等子元件都掛載完成後,才算是父元件掛載完,所以父元件的 mounted 在子元件 mouted 之後。 - 父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted 2. 子元件更新過程: - 影響到父元件:父 beforeUpdate -> 子 beforeUpdate->子 updated -> 父 updted - 不影響父元件:子 beforeUpdate -> 子 updated 3. 父元件更新過程: - 影響到子元件:父 beforeUpdate -> 子 beforeUpdate->子 updated -> 父 updted - 不影響子元件:父 beforeUpdate -> 父 updated 4. 銷燬過程: - 父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed ### 元件註冊 元件``(component)``是 Vue.js 最強大的功能之一。元件可以擴充套件 HTML 元素,封裝可重用的程式碼。元件的使用過程包括定義和註冊的過程。 1. 定義元件 ```js // 方法一 Vue.extend var MyComponent = Vue.extend({ template: '<div>A custom component!</div>' }) // 方法二:新建一個.vue 檔案 ``` 2. 註冊元件 ```js // 全域性註冊 Vue.component('my-component', MyComponent) // 區域性註冊 new Vue({ el: '#app', components: { 'my-component': MyComponent } }) ``` 3. 使用元件 ```html <div id="example"> <my-component></my-component> </div> ``` ### 元件傳值 #### 1. props 父元件給子元件傳值 props 值可以是一個數組或物件; ```js // 陣列:不建議使用 props:[] // 物件 props:{ inpVal:{ type:Number, //傳入值限定型別 // type 值可為String,Number,Boolean,Array,Object,Date,Function,Symbol // type 還可以是一個自定義的建構函式,並且通過 instanceof 來進行檢查確認 required: true, //是否必傳 default:200, //預設值,物件或陣列預設值必須從一個工廠函式獲取如 default:()=>[] validator:(value) { // 這個值必須匹配下列字串中的一個 return ['success', 'warning', 'danger'].indexOf(value) !== -1 } } } ``` #### 2. \$emit 子元件給父元件傳值 觸發子元件觸發父元件給自己繫結的事件,其實就是子傳父的方法 ```js // 父元件 <v-Header @title="title"> // 子元件 this.$emit('title',{title:'這是title'}) ``` #### 3. vuex 資料狀態管理 - ``state``:定義存貯資料的倉庫 ,可通過 this.\$store.state 或 mapState 訪問 - ``getter``:獲取 store 值,可認為是 store 的計算屬性,可通過 this.\$store.getter 或 mapGetters 訪問 - ``mutation``:同步改變 store 值,可通過 mapMutations 呼叫 - ``action``:非同步呼叫函式執行 mutation,進而改變 store 值,可通過 this.\$dispatch 或 mapActions 訪問 - ``modules``:模組,如果狀態過多,可以拆分成模組,最後在入口通過...解構引入 #### 4. attrs 和 listeners ``attrs`` 獲取子傳父中未在 props 定義的值 ```js // 父元件 <home title="這是標題" width="80" height="80" imgUrl="imgUrl"/> // 子元件 mounted() { console.log(this.$attrs) //{title: "這是標題", width: "80", height: "80", imgUrl: "imgUrl"} } // 相對應的如果子元件定義了 props,列印的值就是剔除定義的屬性 props: { width: { type: String, default: '' } }, mounted() { console.log(this.$attrs) //{title: "這是標題", height: "80", imgUrl: "imgUrl"} } ``` ``listeners``:場景:子元件需要呼叫父元件的方法。 解決:父元件的方法可以通過 ``v-on="listeners"`` 傳入內部元件——在建立更高層次的元件時非常有用 ```js // 父元件 <home @change="change"/> // 子元件 mounted() { console.log(this.$listeners) //即可拿到 change 事件 } ``` #### 5. provide 和 inject ``provide`` 和 ``inject`` 主要為高階外掛/元件庫提供用例。並不推薦直接用於應用程式程式碼中; 並且這對選項需要一起使用; 以允許一個祖先元件向其所有子孫後代注入一個依賴,不論元件層次有多深,並在起上下游關係成立的時間裡始終生效。 ```js //父元件: provide: { //provide 是一個物件,提供一個屬性或方法 foo: '這是 foo', fooMethod:()=>{ console.log('父元件 fooMethod 被呼叫') } }, // 子或者孫子元件 inject: ['foo','fooMethod'], //陣列或者物件,注入到子元件 mounted() { this.fooMethod() console.log(this.foo) } //在父元件下面所有的子元件都可以利用inject ``` #### 6. \$refs 通常用於父元件呼叫子元件的方法 ```js // 父元件 <home ref="child"/> mounted(){ console.log(this.$refs.child) //即可拿到子元件的例項,就可以直接操作 data 和 methods } ``` #### 7. EventBus 1. 就是宣告一個全域性 Vue 例項變數 EventBus , 把所有的通訊資料,事件監聽都儲存到這個變數上; 2. 類似於 Vuex。但這種方式只適用於極小的專案 3.原理就是利用 emit 並例項化一個全域性 vue 實現資料共享 ```js // 在 main.js Vue.prototype.$eventBus = new Vue() // 傳值元件 this.$eventBus.$emit('eventTarget', '這是eventTarget傳過來的值') // 接收元件 this.$eventBus.$on('eventTarget', v => { console.log('eventTarget', v) //這是eventTarget傳過來的值 }) ``` ### 路由配置和使用 1. 配置路由資訊 ```js let routes = [ { path: '/home', component: home }, { path: '/list', component: list } ] let router = new VueRouter({ routes: routes }) let vm = new Vue({ el: '#app', router }) ``` 在html使用 ```html <div id="app"> <router-link to='/home' active-class='current'>首頁</router-link> <router-link to='/list' tag='div'>列表</router-link> <router-view></router-view> </div> ``` 此外,``vue-router``還可以通過一下方式配置動態路由 * ``query``傳參(問號傳參) * ``params``傳參(路徑傳參) ### 路由懶載入 Vue 專案中實現路由按需載入(路由懶載入)的 3 中方式: ```js // 1、Vue非同步元件技術: { path: '/home', name: 'Home', component: resolve => reqire(['path路徑'], resolve) } // 2、es6提案的import() const Home = () => import('path路徑') // 3、webpack提供的require.ensure() { path: '/home', name: 'Home', component: r => require.ensure([],() => r(require('path路徑')), 'demo') } ``` ### 路由守衛 vue-router 提供的導航守衛主要用來通過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程中:全域性的, 單個路由獨享的, 或者元件級的。 **全域性前置守衛** 常用於判斷登入狀態和選單許可權校驗 ```js router.beforeEach((to, from, next) => { let isLogin = sessionStorage.getItem('isLogin') || '' if (!isLogin && to.meta.auth) { next('/login') } else { next() } }) ``` * ``to``: Route: 即將要進入的目標 路由物件 * ``from``: Route: 當前導航正要離開的路由 * ``next``: Function: 一定要呼叫該方法來 resolve 這個鉤子。執行效果依賴 next 方法的呼叫引數。 **元件內的守衛** * ``beforeRouteEnter`` * ``beforeRouteUpdate`` * ``beforeRouteLeave`` ### 路由快取 keepalive ``keep-alive`` 是 Vue 提供的一個抽象元件,用來對元件進行快取,從而節省效能,由於是一個抽象元件,所以在 v 頁面渲染完畢後不會被渲染成一個 DOM 元素。 ```html <keep-alive> <router-view></router-view> </keep-alive> ``` 當元件在 ``keep-alive`` 內被切換時元件的 ``activated``、``deactivated`` 這兩個生命週期鉤子函式會被執行 #### 1. 使用引數include/exclude - include: 字串或正則表示式。只有匹配的元件會被快取。 - exclude: 字串或正則表示式。任何匹配的元件都不會被快取。 ```html <keep-alive include="a,b"> <router-view></router-view> </keep-alive> <keep-alive exclude="c"> <router-view></router-view> </keep-alive> ``` ``include`` 屬性表示只有 name 屬性為 a,b 的元件會被快取,(注意是元件的名字,不是路由的名字)其它元件不會被快取。 ``exclude`` 屬性表示除了 name 屬性為 c 的元件不會被快取,其它元件都會被快取。 #### 2. 使用\$route.meta 的 keepAlive 屬性 需要在 router 中設定 router 的元資訊 meta ```js export default new Router({ routes: [ { path: '/', name: 'Hello', component: Hello, meta: { keepAlive: false // 不需要快取 } }, { path: '/page1', name: 'Page1', component: Page1, meta: { keepAlive: true // 需要被快取 } } ] }) ``` 在 app.vue 進行區別快取和不用快取的頁面 ```html <div id="app"> <router-view v-if="!$route.meta.keepAlive"></router-view> <keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> </div> ``` ### hash 和 history模式 - hash 模式:在瀏覽器中符號“#”,#以及#後面的字元稱之為 hash,用 `window.location.hash` 讀取。特點:hash 雖然在 URL 中,但不被包括在 HTTP 請求中;用來指導瀏覽器動作,對服務端安全無用,hash 不會重載入頁面。 - history 模式:history 採用 HTML5 的新特性;且提供了兩個新方法: `pushState(), replaceState()`可以對瀏覽器歷史記錄棧進行修改,以及`popState`事件的監聽到狀態變更。 - hash 模式中`( http://localhost:8080#home)`,即使不需要配置,靜態伺服器始終會去尋找`index.html`並返回給我們,然後`vue-router`會獲取 #後面的字元作為引數,對前端頁面進行變換。 - history 模式中,我們所想要的情況就是:輸入`http://localhost:8080/home`,但最終返回的也是`index.html`,然後`vue-router`會獲取 home 作為引數,對前端頁面進行變換。那麼在`nginx`中,誰能做到這件事呢?答案就是`try_files`。