vue 作爲目前前端三大框架之一,對於前端開發者可以說是必備技能。那麼怎麼系統地學習和掌握 vue 呢?爲此,我做了簡單的知識體系體系總結,不足之處請各位大佬多多包涵和指正,如果喜歡的可以點個小贊!
Vue 的優缺點是什麼
優點:
- 低耦合。視圖(View)可以獨立於 Model 變化和修改,一個 ViewModel 可以綁定到不同的 View 上,當 View 變化的時候 Model 可以不變,當 Model 變化的時候 View 也可以不變。
- 可重用性。你可以把一些視圖邏輯放在一個 ViewModel 裏面,讓很多 view 重用這段視圖邏輯。
- 獨立開發。開發人員可以專注於業務邏輯和數據的開發(ViewModel),設計人員可以專注於頁面設計,使用 Expression Blend 可以很容易設計界面並生成 xml 代碼。
- 可測試。界面素來是比較難於測試的,而現在測試可以針對 ViewModel 來寫。
- 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 一起使用。
<!-- 阻止單擊事件繼續傳播 -->
<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
過濾器是對即將顯示的數據做進一步的篩選處理,然後進行顯示,值得注意的是過濾器並沒有改變原來的數據,只是在原數據的基礎上產生新的數據。
- 定義過濾器
全局註冊
Vue.filter('myFilter', function (value1[,value2,...] ) {
// 代碼邏輯
})
局部註冊
new Vue({
filters: {
'myFilter': function (value1[,value2,...] ) {
// 代碼邏輯
}
}
 })
2.使用過濾器
<!-- 在雙花括號中 -->
<div>{{ message | myFilter }}</div><!-- 在 `v-bind` 中 -->
<div v-bind:id="message | myFilter"></div>
計算屬性 computed
依賴其它屬性值,並且 computed
的值有緩存,只有它依賴的屬性值發生改變,下一次獲取 computed
的值時纔會重新計算 computed
的值;
<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 的函數
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 的父組件和子組件生命週期鉤子執行順序是什麼?
- 渲染過程:父組件掛載完成一定是等子組件都掛載完成後,纔算是父組件掛載完,所以父組件的 mounted 在子組件 mouted 之後。
- 父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
- 子組件更新過程:
- 影響到父組件:父 beforeUpdate -> 子 beforeUpdate->子 updated -> 父 updated
- 不影響父組件:子 beforeUpdate -> 子 updated
- 父組件更新過程:
- 影響到子組件:父 beforeUpdate -> 子 beforeUpdate->子 updated -> 父 updted
- 不影響子組件:父 beforeUpdate -> 父 updated
- 銷燬過程:
- 父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
組件註冊
組件(component)
是 Vue.js 最強大的功能之一。組件可以擴展 HTML 元素,封裝可重用的代碼。組件的使用過程包括定義和註冊的過程。
- 定義組件
// 方法一 Vue.extend
var MyComponent = Vue.extend({
template: '<div>A custom component!</div>'
})
// 方法二:新建一個.vue 文件
2.註冊組件
// 全局註冊
Vue.component('my-component', MyComponent)// 局部註冊
new Vue({
el: '#app',
components: {
'my-component': MyComponent
}
})
3.使用組件
<div id="example">
<my-component></my-component>
</div>
組件傳值
1. props 父組件給子組件傳值
props 值可以是一個數組或對象;
// 數組:不建議使用
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 子組件給父組件傳值
觸發子組件觸發父組件給自己綁定的事件,其實就是子傳父的方法
// 父組件
<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 定義的值
// 父組件
<home title="這是標題" width="80" height="80" imgUrl="imgUrl"/>
// 子組件
mounted() {
console.log(this.$attrs) //{title: "這是標題", width: "80", height: "80", imgUrl: "imgUrl"}
}// 相對應的如果子組件定義了 props,打印的值就是剔除定義的屬性
props: {
width: { //在props定義了,在this.$attrs會剔除這個屬性
type: String,
default: ''
}
},
mounted() {
console.log(this.$attrs) //{title: "這是標題", height: "80", imgUrl: "imgUrl"}
}
listeners
:
場景:子組件需要調用父組件的方法。
解決:父組件的方法可以通過 v-on="listeners"
傳入內部組件——在創建更高層次的組件時非常有用
// 父組件
<home @change="change"/>// 子組件
mounted() {
console.log(this.$listeners) //即可拿到 change 事件
}
5. provide 和 inject
provide
和 inject
主要爲高階插件/組件庫提供用例。並不推薦直接用於應用程序代碼中; 並且這對選項需要一起使用; 以允許一個祖先組件向其所有子孫後代注入一個依賴,不論組件層次有多深,並在起上下游關係成立的時間裏始終生效。
//父組件:
provide: { //provide 是一個對象,提供一個屬性或方法
foo: '這是 foo',
fooMethod:()=>{
console.log('父組件 fooMethod 被調用')
}
},// 子或者孫子組件
inject: ['foo','fooMethod'], //數組或者對象,注入到子組件
mounted() {
this.fooMethod()
console.log(this.foo)
}
//在父組件下面所有的子組件都可以利用inject
6. $refs
通常用於父組件調用子組件的方法
// 父組件
<home ref="child"/>mounted(){
console.log(this.$refs.child) //即可拿到子組件的實例,就可以直接操作 data 和 methods
}
7. EventBus
- 就是聲明一個全局 Vue 實例變量 EventBus , 把所有的通信數據,事件監聽都存儲到這個變量上;
- 類似於 Vuex。但這種方式只適用於極小的項目
- 原理就是利用 emit 並實例化一個全局 vue 實現數據共享
// 在 main.js
Vue.prototype.$eventBus = new Vue()// 傳值組件
this.$eventBus.$emit('eventTarget', '這是eventTarget傳過來的值')// 接收組件
this.$eventBus.$on('eventTarget', v => {
console.log('eventTarget', v) //這是eventTarget傳過來的值
})
路由配置和使用
- 配置路由信息
let routes = [
{
path: '/home',
component: home
},
{
path: '/list',
component: list
}
]let router = new VueRouter({
routes: routes
})
let vm = new Vue({
el: '#app',
router
})
在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 中方式:
// 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 提供的導航守衛主要用來通過跳轉或取消的方式守衛導航。有多種機會植入路由導航過程中:全局的, 單個路由獨享的, 或者組件級的。
全局前置守衛 常用於判斷登錄狀態和菜單權限校驗
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 元素。
<keep-alive>
<router-view></router-view>
</keep-alive>
當組件在 keep-alive
內被切換時組件的 activated
、deactivated
這兩個生命週期鉤子函數會被執行
1. 使用參數include/exclude
- include: 字符串或正則表達式。只有匹配的組件會被緩存。
- exclude: 字符串或正則表達式。任何匹配的組件都不會被緩存。
<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
export default new Router({
routes: [
{
path: '/',
name: 'Hello',
component: Hello,
meta: {
keepAlive: false // 不需要緩存
}
},
{
path: '/page1',
name: 'Page1',
component: Page1,
meta: {
keepAlive: true // 需要被緩存
}
}
]
})
在 app.vue 進行區別緩存和不用緩存的頁面
<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
。
Vue如何跳過options請求
// axios 配置
axios.defaults.timeout = 5000;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8';
axios.defaults.baseURL = 'http://localhost:8008'
// POST傳參序列化
axios.interceptors.request.use((config) => {
if(config.method === 'post') {
config.data = qs.stringify(config.data);
}
return config;
}, (error) => {
return Promise.reject(error);
});
// 返回狀態判斷
axios.interceptors.response.use((res) =>{
if(!res.data.success){
return Promise.reject(res);
} return res;
}, (error) => {
//404等問題可以在這裏處理 return Promise.reject(error);
})
摘自:
作者:lzg9527
鏈接:https://juejin.im/post/5e5c5dc5f265da570e39a76b
來源:掘金