vue知識(shí)點(diǎn)

1. VUE特點(diǎn)

  • 輕量
    使用gzip最小壓縮后有20kb,react有35kb,angular有60kb

  • 漸進(jìn)式框架
    你不需要完全了解他,就可以用,各取所需,只是個(gè)輕量視圖而已

  • 響應(yīng)式的更新機(jī)制
    數(shù)據(jù)改變后,視圖會(huì)自動(dòng)更新,而不像react那樣用shouldComponentUpdate進(jìn)行性能優(yōu)化

  • 學(xué)習(xí)成本低
    模板語法是基于html,容易上手

2. 生命周期

Vue 實(shí)例生命周期(來源官網(wǎng))

Vue的所有生命周期函數(shù)都是自動(dòng)綁定到this的上下文上,所以不需要用到箭頭函數(shù)。
頁面加載大致過程:

  • beforeCreate:無法獲取到propdata
  • created: 經(jīng)過數(shù)據(jù)初始化,此時(shí)可以獲取prop和data,但是組件尚未掛載;
  • beforeMount: 開始創(chuàng)建虛擬dom,如果組件中有子組件,先遞歸掛載子組件,再掛載根組件的
  • mounted: 將虛擬dom渲染為真實(shí)dom。
  • 數(shù)據(jù)更新
    更新前:beforeUpdates
    更新后: updated
  • 頁面銷毀
    銷毀前:beforeDestory
    銷毀后: destoryed

4. Vue 的父組件和子組件生命周期鉤子函數(shù)執(zhí)行順序

(1)加載渲染過程
beforeCreated(父) ->>created(父)->> beforeMounted(父) ->>
子組件渲染:beforeCreated(子) ->> created(子)->> beforeMounted(子) ->> mounted(子)
--> mounted(父)
(2)子組件更新
beforeUpdate(父) --> beforeUpdate(子) -> updated( 子) -> updated(父)
(3)父組件更新
beforeUpdate(父) --> updated(父)
(4)銷毀
beforeDestroy(父) -> beforeDestroy (子)-> destroyed(子) -> destroyed(父)

3. vue基本指令

  • v-show
    當(dāng)條件為true時(shí)候display: block,否則是display: none;無論什么條件都會(huì)被渲染出來,渲染之后只是css屬性的切換,渲染時(shí)候有一定的開銷,適合頻繁切換的場景。

  • v-if
    根據(jù)條件來渲染,如果是false,那一開始就不會(huì)渲染,但是切換條件時(shí)會(huì)觸發(fā)銷毀和掛載,所以在切換時(shí)候開銷比較大,不適合頻繁切換的場景

  • v-for

<li v-for="(item, index) in items" :key="item.message">
    {{index}} {{ item.message }}
 </li>
  • v-model

v-model其實(shí)是一個(gè)語法糖

v-model 會(huì)忽略所有表單元素的 valuechecked、selected attribute 的初始值而總是將 Vue 實(shí)例的數(shù)據(jù)作為數(shù)據(jù)來源。你應(yīng)該通過 JavaScript 在組件的 data 選項(xiàng)中聲明初始值。

<input v-model="name"></input>
//等價(jià)于
<input 
    v-bind:value="name"
    v-bind:input="name = arguments[0]"
></input>

就是一種雙向綁定的過程,視圖影響數(shù)據(jù),數(shù)據(jù)影響視圖,說明視圖是可交互的,一般和表單有關(guān)系

  • v-on簡寫@ 綁定事件
  • v-bind:簡寫: 綁定屬性
  • v-text顯示文本
  • v-pre不編譯雙花括號,直接顯示字符串
  • v-html可以顯示html字符串

4. 組件的三大核心概念

(1)屬性

? ① 自定義屬性props,表示組件props中聲明的屬性
? ②原生屬性,比如<Test title="測試"></Test>,默認(rèn)在組件中的根元素上就會(huì)有title="測試"的屬性;
? 在Test組件中設(shè)置inheritAttrs: false就可以關(guān)閉自動(dòng)掛載
? ③特殊屬性,style, class掛載到組件根元素上

(2)事件

? ①普通事件

- @click
- @change
- @input
- @xxx

子組件通過this.$emit("xxx", 參數(shù)1, 參數(shù)2, 參數(shù)...)

? ②修飾符事件

  • @input.trim (去掉兩端空格)

  • @click.stop(阻止冒泡事件或者在事件中使用e.stopPropagation)

  • @submit.prevent(去除默認(rèn)事件)

    一般用于原生html的行為

(3)插槽

? ① 普通插槽

//老語法
<template slot="xxx"> ...<template>
//2.6版本語法
<template v-slot:xxx> ...<template>

② 作用域插槽
可以獲取屬性

<template slot="xxx" slot-scope="props">{{props}}</template>
<template v-slot:xxx="props">{{props}}</template>

組件:

<template>
    <div>
        <slot name="xxx" />
        <slot v-bind="{value: 'value'}" />
    </div>
</template>

5. MVVM和MVC模式的區(qū)別

  • MVC

MVC是最經(jīng)典的模型,即Model(模型)、Controller(控制器)、View(視圖)

當(dāng)用戶操作頁面時(shí),view層會(huì)發(fā)出指令到controller,controller去通知model更新數(shù)據(jù)。一旦model發(fā)生改變,就通知視圖更新。

  • MVVM

MVVMModel-View-ViewModel,實(shí)現(xiàn)了view和model的自動(dòng)同步,ViewModel 通過雙向數(shù)據(jù)綁定把 View 層和 Model 層連接了起來。VM起到了雙向綁定的作用,View(視圖) 和 Model(數(shù)據(jù)) 無法直接通訊,在它們之間存在著 ViewModel 中間介充當(dāng)觀察者角色。當(dāng)用戶操作 View(視圖),ViewModel 感知到變化,然后通知 Model 發(fā)生相應(yīng)改變;反之當(dāng) Model(數(shù)據(jù)) 發(fā)生改變,ViewModel 也能感知到變化,使 View 作出相應(yīng)更新。

6. 單向數(shù)據(jù)流和雙向綁定

雙向綁定:
model更新會(huì)觸發(fā)view更新;
view的更新會(huì)觸發(fā)model更新;
單向數(shù)據(jù)流:
model更新會(huì)觸發(fā)view更新;
view的更新和model沒有關(guān)系

vue是單向數(shù)據(jù)流,不是雙向綁定,vue的雙向綁定不過是語法糖,而Object.defineProperty是用來做響應(yīng)式更新的,對屬性設(shè)置set函數(shù),當(dāng)屬性改變時(shí)候,就會(huì)觸發(fā)這個(gè)函數(shù)
實(shí)現(xiàn)過程:

vue自定義v-model

一個(gè)組件的v-model默認(rèn)會(huì)有prop: value,event: input,但是我們可以自定義

//定義子組件
Vue.component('Child', {
    model: {
        prop: 'checked',
        event: 'change'
    },
    props: {
        checked: Boolean
    },
    template: <input type="checkbox" :checked="checked" @change="$emit('change',            $event.target.checked)">
})
//在父組件中使用
<Child v-model="data" />

此時(shí)data的值會(huì)被傳遞到子組件中,為checked屬性

7. vue中sync修飾符

.sync是為了方便父子之間通信,當(dāng)子組件想要改變父組件傳遞進(jìn)來的屬性時(shí),比如一個(gè)控制modal是否顯示的屬性,子組件就要使用$emit('xxx', 'xxx')

vue提供update: propertyName模式觸發(fā)事件

//子組件更改屬性
this.$emit("update:visible", false)
//父組件
<Child :visible="show" @update:visible="val => show = val" />

那么為了簡化寫法,出現(xiàn)了sync修飾符

//子組件更改屬性
this.$emit("update:visible", false)
//父組件
<Child :visible.sync="show" />

父組件不需要定義,默認(rèn)存在@update:visible="val => show = val"

官方文檔

8. 組件更新

組件更新的條件

①屬性需要在data里面聲明,這樣才能做響應(yīng)式
②如果data中聲明一個(gè)對象

data() {
    return {
        info: {}
    }
}
//這種不會(huì)觸發(fā)更新
this.info.name = "a"

修改為:

data() {
    return {
        info: { name: undefined }
    }
}

③如果在模板中沒有用到某個(gè)屬性,那么修改這個(gè)屬性也不會(huì)觸發(fā)組件更新
④如果data中有一個(gè)數(shù)組屬性
直接push也會(huì)觸發(fā)組件更新

那么vue是如何進(jìn)行組件更新的呢?

當(dāng)vue進(jìn)行實(shí)例化時(shí)候,會(huì)使用Object.defineProperty對data中的屬性設(shè)置set和get方法,相當(dāng)于代理層;
將模板中需要用到的屬性放到watch,如果修改了屬性,在set函數(shù)中會(huì)去通知watch,然后watch去觸發(fā)組件的更新。


9. compute和watch屬性的區(qū)別

計(jì)算屬性compute

作用:
① 減少模板中計(jì)算邏輯
② 緩存數(shù)據(jù)
③ 依賴固定的數(shù)據(jù)類型,不會(huì)重新再計(jì)算,只有在數(shù)據(jù)變化時(shí)候才會(huì)計(jì)算
對比:

<p>{{reverseStr}}</p>
<p>{{reverseStr2}}</p>
computed: {
    reverseStr: function() {
        this.str.split("").reverse.join("")
    }
}
data() {
    reverseStr2: function() {
        this.str.split("").reverse.join("")
    }
}

$forceUpdate刷新頁面,str沒變化時(shí)候,reverseStr不會(huì)執(zhí)行計(jì)算,reverseStr2會(huì)被調(diào)用

監(jiān)聽屬性watch

監(jiān)聽數(shù)據(jù)的變化

data() {
    a:1,
    b: {
        c: 2
    },
    d: {
        e: {
            f: 3
        }
    }
}
//各個(gè)屬性監(jiān)聽方式,
watch: {
    a(val, old) {}, 
    "b.c": function(val, old),
    // d及以下的所有屬性都會(huì)被監(jiān)聽,deep表示深度監(jiān)聽;immediate表示是否在第一次渲染就執(zhí)行這個(gè)監(jiān)聽
    d: {
        handler: function(val, old) {},
        deep: true,
        immediate: true
    }
}

如果一個(gè)數(shù)據(jù)需要經(jīng)過復(fù)雜計(jì)算就用 computed;
如果一個(gè)數(shù)據(jù)需要被監(jiān)聽并且對數(shù)據(jù)做一些操作就用 watch

10. vue組件通信方式

①props和$emit父子組件通信

這個(gè)是最基礎(chǔ)的組件通信,父組件通過v-bind:xxx="xx"傳遞屬性,v-on:xxx="xx"綁定事件;
子組件通過props獲取,$emit觸發(fā)父組件傳遞的事件。

//父組件
<template>
  <div>
    <Child :msg="message" @changeStates="change"></child>
  </div>
</template>

//子組件
<template>
  {{msg}}
  <button @click="clickHandle">點(diǎn)擊</button>
</template>
<script>
  import Child from "./Child";
  export default {
    name: "Child",
    props: ["msg"],
    components:{
        Child
    },
    methods: {
      clickHandle() {
        this.$emit("changeStates", "變了");
      }
    }
  };
</script>

②ref

ref如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子組件上,引用就指向組件實(shí)例。

//父組件
<template>
  <div>
    <child ref="son"></child>
  </div>
</template>
//子組件
<template>
  <div> 
    <input ref="inputRef" type="text" value="hi"></child>
  </div>
</template>
// 獲取子組件的屬性和方法
//獲取子組件input框的內(nèi)容
this.$refs.son.$refs.inputRef.value

parent,children
直接使用,但是建議少用
父組件:

<template>
  <div>
    <child></child>
  </div>
</template>
<script>
    export default {
     name: 'parent',
     data: () => ({
       msg: "Hi, I am your father"
     }),
     mounted() {
        console.log(this.$children[0].msg)
     }
    }
</script>

子組件:

<template>
  <div>Hello Boy</div>
</template>

<script>
  export default {
    name: "child",
    data: () => ({
      msg: "hi"
    }),
    mounted() {
      console.log(this.$parent.msg); //
    }
  };
</script>

④EventBus中央數(shù)據(jù)總線,emit/on

通過創(chuàng)建一個(gè)空的vue實(shí)例作為中央事件總線,用于觸發(fā)和監(jiān)聽事件,類型于addListener

attrs和listeners隔代組件通信

$attrs 里存放的是父組件中綁定的非 Props 屬性;

$listeners里存放的是父組件中綁定的非原生事件;

// 父組件
<template>
  <div>
    <child-a
      :name="name"
      :age="age"
      :job="job"
      title="This is a title"
      @click="post"
    ></child-a>
  </div>
</template>

// 子組件child-a中
<template>
  <div>
    <child-b v-bind="$attrs" v-on="$listeners"></child-b>
  </div>
</template>
this.$attrs 
// {name: "name", age: "28", job: "worker", title: "This is a title"}
this.$listeners.click()
// hello

// 子組件child-b中
<template>
  <div>
    <p>B-listeners: {{ this.$listeners.click() }}</p>
  </div>
</template>
<script>
  export default {
    props: ["name"], // name 作為props屬性綁定
    inheritAttrs: false, // 可以關(guān)閉自動(dòng)掛載到組件根元素上的沒有在props聲明的屬性
    created() {
      console.log(this.$attrs);
      // {age: "28", job: "worker", title: "This is a title"}
      console.log(this.$listeners.click()); // hello
    }
  };
</script>

⑥provide和inject

祖先組件中通過 provider 來提供變量,然后在子孫組件中通過 inject 來注入變量。

provide 和 inject 主要在開發(fā)高階插件/組件庫時(shí)使用

除此之外,還有vuex狀態(tài)管理,如下所示

參考資料

11. Vuex狀態(tài)管理

vuex類似于react的redux,當(dāng)開發(fā)大型單頁應(yīng)用,多個(gè)視圖組件依賴同一個(gè)狀態(tài),比如登錄狀態(tài),用戶信息等。當(dāng)狀態(tài)更新時(shí)候,這些使用過狀態(tài)的組件都要更新。針對這種情況,可以使用vuex來解決。

特點(diǎn):

(1)狀態(tài)存儲(chǔ)是響應(yīng)式的,組件從store中讀取狀態(tài),如果狀態(tài)發(fā)生變化,則會(huì)自動(dòng)更新到組件
(2)不能直接修改store中的狀態(tài)

使用方式:

import vue from 'vue';
import vuex from 'vuex';

const store = new Vuex.Store({
    state: {},
    getters: {}
    mutations: {},
    actions: {}
})
// 通過根組件直接注入,這樣所有的組件都可以使用store
new Vue({
    e1: "#app",
    store
})

組成部分:

  • state

作為模塊唯一數(shù)據(jù)源,包含了所有的狀態(tài),訪問state方式:

this.$store.state.xxx

mapState簡化方式訪問:

import { mapState } from 'vuex';
export default {
    computed: mapState({
        count: state => state.count,
        myCount: 'count',
        // 和當(dāng)前的數(shù)據(jù)操作
        add(state) {
            return state.count + this.nowCount
        }
    })
}

store中的變量名和當(dāng)前組件中要使用的變量名相同

import { mapState } from 'vuex';
export default {
    computed: mapState([
        'count'
    ])
}

最常用的就是對象展開符的方式:

import { mapState } from 'vuex';
export default {
    computed: {
        ...mapState([
            'count'
        ])
        other(){}
    }
}
  • getters

當(dāng)我們不滿足直接使用store中state數(shù)據(jù),比如篩選計(jì)算等處理,如果多個(gè)組件都需要這種,那么最好的方式是在store中定義:

getters: {
    toDo : state => {
        return state.toDo.filter(i => i.toDoThings) 
    }
}

視圖中訪問方式:

this.$store.getters.toDo

mapGetters簡化的方式:

import { mapGetters } from 'vuex'

export default {
  computed: {
    ...mapGetters([
      'tODo',
    ])
  }
}
//訪問方式: this.tODo
  • mutation

這個(gè)用于修改state屬性,調(diào)用的必須是同步的事件

mutations: {
    increment(state, num) {
        state.count = state.count + num
    }
}

調(diào)用方式:

this.$store.commit('increment', 10)

mapMutations簡化方式:

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapMutations([
      'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`
    ]),
    ...mapMutations({
      add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
    })
  }
}
  • action

類似于mutation,可以提交mutation修改state

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {
      context.commit('increment')
    }
  }
  //或者通過參數(shù)解構(gòu)
  actions: {
      increment ({ commit }) {
        commit('increment')
      }
  }
})

處理異步的業(yè)務(wù)

actions: {
      increment ({ commit, state }, payload) {
        // ...
      }
  }

觸發(fā):

this.$store.dispatch('increment')

mapAtions簡化方式

import { mapMutations } from 'vuex'

export default {
  // ...
  methods: {
    ...mapActions([
      'increment', // 將 `this.increment()` 映射為 `this.$store.commit('increment')`
    ]),
    ...mapActions({
      add: 'increment' // 將 `this.add()` 映射為 `this.$store.commit('increment')`
    })
  }
}

11.前端路由控制的兩種方式以及區(qū)別

參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容