Vuejs技術棧知識點小結


前言

上家公司的項目主要是使用jQuery和Angular1,然后自己學了React,沒想到來到這家公司突然開始做vue,不過vue還是挺容易上手的。下面是vue技術棧的一些總結,都是來自官網,主要是自己對vue技術棧知識點的一些整理,因此此文很水,建議閱讀我的上一篇文章Vuejs技術棧從CLI到打包上線實戰全解析

Vue

獨立構建和運行時構建

有兩種構建方式,獨立構建和運行構建。它們的區別在於前者包含模板編譯器而后者不包含。

模板編譯器的職責是將模板字符串編譯為純JavaScript的渲染函數。如果你想要在組件中使用template選項,你就需要編譯器。

生命周期

具體查看官網的流程圖,要注意的是created和mounted區別,created是vm實例已創建但未掛載,因此一些DOM操作應該放在mounted中。異步請求放在created或者mounted暫時沒發現什么區別,如您知道有什么區別,請評論指出。

計算(computed)屬性

模板內的表達式不應該包含太多的邏輯,對於任何復雜邏輯,都應當使用計算屬性

computed屬性和methods不同的是計算屬性是基於它們的依賴進行緩存的。

computed屬性和computed屬性,通常更好的想法是使用computed屬性而不是命令式的watch回調。雖然計算屬性在大多數情況下更合適,但有時也需要一個自定義的watcher。當你想要在數據變化響應時,執行異步操作或開銷較大的操作,這是很有用的。

數組更新檢測

數組的變異方法(mutation method,會改變被這些方法調用的原始數組)會觸發視圖更新,有以下七個:

push()
pop()
shift()
unshift()
splice()
sort()
reverse()

當使用非變異方法時,可以用新數組替換舊數組,或者使用Vue.set方法。

對象更新

可以用新對象替換舊對象,或者使用Vue.set方法

Vue.set(vm.someObject, 'foo', 'bar')

this.someObject = Object.assign({}, this.someObject, { a:1, b:2 })

事件處理器

Vue.js為v-on提供了事件修飾符和按鍵修飾符

表單控件綁定

可以用v-model指令在表單控件元素上創建雙向數據綁定。常見修飾符有.lazy、.number、.trim。

也可以使用自定義事件的表單輸入組件。

組件

Vue組件的API來自三部分:props,events和slots:

  • Props允許外部環境傳遞數據給組件
  • Events允許組件觸發外部環境的副作用
  • Slots允許外部環境將額外的內容組合在組件中。

1)組件的data屬性必須是函數

2)父子組件

在Vue.js中,父子組件的關系可以總結為 props down, events up 。父組件通過props向下傳遞數據給子組件,子組件通過events給父組件發送消息。

prop是單向綁定的:當父組件的屬性變化時,將傳導給子組件,但是不會反過來。這是為了防止子組件無意修改了父組件的狀態——這會讓應用的數據流難以理解。

另外,每次父組件更新時,子組件的所有prop都會更新為最新值。這意味着你不應該在子組件內部改變prop。如果你這么做了,Vue會在控制台給出警告。

為什么我們會有修改prop中數據的沖動呢?通常是這兩種原因:

1.prop作為初始值傳入后,子組件想把它當作局部數據來用;

2.prop作為初始值傳入,由子組件處理成其它數據輸出。

對這兩種原因,正確的應對方式是:

1.定義一個局部變量,並用prop的值初始化它:

props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}

2.定義一個計算屬性,處理prop的值並返回。

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

注意在JavaScript中對象和數組是引用類型,指向同一個內存空間,如果prop是一個對象或數組,在子組件內部改變它會影響父組件的狀態。

3)非父子組件

有時候兩個組件也需要通信(非父子關系)。在簡單的場景下,可以使用一個空的Vue實例作為中央事件總線。在復雜的情況下,我們應該考慮使用專門的狀態管理模式。

4).sync修飾符

在一些情況下,我們可能會需要對一個prop進行『雙向綁定』。

2.0中移除了.sync,Vue2.3.0+又將其添加回來了,但是這次它只是作為一個編譯時的語法糖存在,它會被擴展為一個自動更新父組件屬性的v-on偵聽器。如下代碼

<comp :foo.sync="bar"></comp>

會被擴展為:

<comp :foo="bar" @update:foo="val => bar = val"></comp>

當子組件需要更新foo的值時,它需要顯式地觸發一個更新事件:

this.$emit('update:foo', newValue)

5)使用slot進行內容分發

作用域插槽:接收從子組件中傳遞的prop對象。作用域插槽更具代表性的用例是列表組件,允許組件自定義應該如何渲染列表每一項

6)動態組件、is特性和keep-alive指令

7)子組件索引

盡管有props和events,但是有時仍然需要JavaScript中直接訪問子組件。為此可以使用ref為子組件指定一個索引ID。

異步更新隊列

雖然 Vue.js 通常鼓勵開發人員沿着“數據驅動”的方式思考,避免直接接觸 DOM,但是有時我們確實要這么做。為了在數據變化之后等待 Vue 完成更新 DOM ,可以在數據變化之后立即使用 Vue.nextTick(callback) 。這樣回調函數在 DOM 更新完成后就會調用。

過渡效果

Vue在插入、更新或者移除DOM時,提供多種不同方式的應用過渡效果。包括以下工具:

  • 在CSS過渡和動畫中自動應用class
  • 可以配合使用第三方CSS動畫庫,如Animate.css
  • 在過渡鈎子函數中使用JavaScript直接操作DOM
  • 可以配合使用第三方JavaScript動畫庫,如Velocity.js

1)單元素/組件的過渡

Vue提供了transition的封裝組件,在下列情形中,可以給任何元素和組件添加過渡

  • 條件渲染(使用v-if)
  • 條件展示(使用v-show)
  • 動態組件
  • 組件根節點

2)多個元素的過渡

對於原生標簽可以使用 v-if/v-else

3)多個組件的過渡

多個組件的過渡我們可以使用動態組件。

4)列表過渡

Render函數和JSX

自定義指令

和Angular的指令類似,主要操作DOM,下面是一個滾動加載的指令,holder暫時沒想到什么更好的處理方法:

let scrollCallback = function (callback) {
  let windowH = window.innerHeight
  let getDocumentHeight = function () {
    var body = document.body
    var html = document.documentElement
    return Math.max(
      body.offsetHeight,
      body.scrollHeight,
      html.clientHeight,
      html.offsetHeight,
      html.scrollHeight
    )
  }
  let scrollH = document.documentElement.scrollTop || document.body.scrollTop
  if (windowH + scrollH >= getDocumentHeight() - (this.holder || 20)) {
    callback()
  }
}

let callBackWarpped

export default {
  bind (el, binding, vnode) {
    let holder
    if (vnode.data && vnode.data.attrs && vnode.data.attrs['scroll-placeholder']) {
      holder = parseInt(vnode.data.attrs['scroll-placeholder'])
    } else {
      holder = 20
    }
    callBackWarpped = scrollCallback.bind({el, holder}, binding.value)
    window.addEventListener('scroll', callBackWarpped, false)
  },

  unbind: function () {
    window.removeEventListener('scroll', callBackWarpped, false)
  }
}

混合

混合是一種靈活的分布式復用Vue組件的方式。混合對象可以包含任意組件選項。以組件使用混合對象時,所有混合對象的選項將被混入該組件本身的選項。

插件

1)創建插件

Vue.js的插件應當有一個公開方法install。這個方法的第一個參數是Vue構造器 , 第二個參數是一個可選的選項對象。

2)使用插件

通過全局方法Vue.use()使用插件:

// 調用 `MyPlugin.install(Vue)`
Vue.use(MyPlugin)

也可以傳入一個選項對象:

Vue.use(MyPlugin, { someOption: true })

vue-router

兩種導航方式

1)router-link聲明式導航

<router-link to="/foo">Go to Foo</router-link>

router-link對應的路由匹配成功,將自動設置class屬性值.router-link-active。

2)編程式導航

// 字符串
router.push('home')

// 對象
router.push({ path: 'home' })

// 命名的路由
router.push({ name: 'user', params: { userId: 123 }})

// 帶查詢參數,變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})

重命名(redirect)和別名(alias)

兩種路由模式

vue-router默認hash模式,也可以設置為路由的history模式。

導航鈎子

vue-router提供的導航鈎子主要用來攔截導航,讓它完成跳轉或取消。有多種方式可以在路由導航發生時執行鈎子:全局的, 單個路由獨享的, 或者組件級的。

路由meta

一個路由匹配到的所有路由記錄會暴露為$route對象(還有在導航鈎子中的route對象)的$route.matched數組。因此,我們需要遍歷$route.matched來檢查路由記錄中的meta字段。

過渡動效

router-view是基本的動態組件,所以我們可以用transition組件給它添加一些過渡效果。

數據獲取

有時候,進入某個路由后,需要從服務器獲取數據。例如,在渲染用戶信息時,你需要從服務器獲取用戶的數據。我們可以通過兩種方式來實現:

導航完成之后獲取:先完成導航,然后在接下來的組件生命周期鈎子中獲取數據。在數據獲取期間顯示『加載中』之類的指示。

導航完成之前獲取:導航完成前,在路由的enter鈎子中獲取數據,在數據獲取成功后執行導航。

滾動行為(scrollBehavior)

注意: 這個功能只在HTML5 history模式下可用。

路由懶加載

當打包構建應用時,Javascript包會變得非常大,影響頁面加載。如果我們能把不同路由對應的組件分割成不同的代碼塊,然后當路由被訪問的時候才加載對應組件,這樣就更加高效了。

結合Vue的異步組件和Webpack的code splitting功能,輕松實現路由組件的懶加載。

const Foo = resolve => require(['./Foo.vue'], resolve)

const router = new VueRouter({
  routes: [
    { path: '/foo', component: Foo }
  ]
})

可以設置tag、append、active-class、exact等屬性

有時候我們要讓 "激活時的CSS類名" 應用在外層元素,而不是a標簽本身,那么可以用router-link渲染外層元素,包裹着內層的原生a標簽:

<router-link tag="li" to="/foo">
  <a>/foo</a>
</router-link>

在這種情況下,a將作為真實的鏈接(它會獲得正確的 href 的),而"激活時的CSS類名"則設置到外層的li。

Router構造配置

routes、mode、base、linkActiveClass、scrollBehavior

對組件注入

1)注入的屬性

通過在Vue根實例的router配置傳入router實例,下面兩個屬性成員會被注入到每個子組件。

$router:router實例

$route:當前激活的路由信息對象。這個屬性是只讀的,里面的屬性是immutable(不可變)的,不過你可以watch(監測變化)它。

2)允許的額外配置:beforeRouteEnter、beforeRouteLeave

vuex

state

1)單一狀態樹

Vuex使用單一狀態樹--是的,用一個對象就包含了全部的應用層級狀態。至此它便作為一個『唯一數據源(SSOT)』而存在。這也意味着,每個應用將僅僅包含一個store實例。單一狀態樹讓我們能夠直接地定位任一特定的狀態片段,在調試的過程中也能輕易地取得整個當前應用狀態的快照。

2)在Vue組件中獲得Vuex狀態

最好在根實例中注冊store選項,該store實例會注入到根組件下的所有子組件中,且子組件能通過this.$store訪問到。而不是在每個需要使用state的組件中需要頻繁地導入。

3)mapState輔助函數

當一個組件需要獲取多個狀態時候,可以使用mapState輔助函數幫助我們生成計算屬性,這樣可以簡化代碼書寫。mapState函數會返回一個對象,然后可以使用對象展開運算符將它與局部計算屬性混合使用。

4)不要濫用vuex

使用Vuex並不意味着你需要將所有的狀態放入Vuex。雖然將所有的狀態放到Vuex會使狀態變化更顯式和易調試,但也會使代碼變得冗長和不直觀。如果有些狀態嚴格屬於單個組件,最好還是作為組件的局部狀態。你應該根據你的應用開發需要進行權衡和確定。

getters

getters用來從store中的state中派生出一些狀態,例如對列表進行過濾並計數:

computed: {
  doneTodosCount () {
    return this.$store.state.todos.filter(todo => todo.done).length
  }
}

getters可以認為是store的計算屬性。和state類似,有mapGetters輔助函數。

mutations

更改Vuex的store中的狀態的唯一方法是提交mutation。Vuex中的mutations非常類似於事件:每個mutation都有一個字符串的事件類型(type)和一個回調函數(handler)。這個回調函數就是我們實際進行狀態更改的地方,並且它會接受state作為第一個參數

1)提交載荷(Payload)

你可以向store.commit傳入額外的參數,即mutation的載荷(payload):

// ...
mutations: {
  increment (state, n) {
    state.count += n
  }
}
store.commit('increment', 10)

2)Mutations需遵守Vue的響應規則

3)使用常量替代Mutation事件類型

4)mutation必須是同步函數

5)在組件中提交Mutations

你可以在組件中使用this.$store.commit('xxx')提交mutation,或者使用mapMutations輔助函數將組件中的methods映射為store.commit調用(需要在根節點注入store)。

actions

actions類似於mutation,不同在於:

  • actions提交的是mutation,而不是直接變更狀態。
  • actions可以包含任意異步操作。

1)在組件中分發Action

你在組件中使用this.$store.dispatch('xxx')分發action,或者使用mapActions輔助函數將組件的methods映射為store.dispatch調用(需要先在根節點注入store)

2)組合Actions

Action通常是異步的,那么如何知道action什么時候結束呢?更重要的是,我們如何才能組合多個action,以處理更加復雜的異步流程?

首先,你需要明白store.dispatch可以處理被觸發的action的回調函數返回的Promise,並且store.dispatch仍舊返回Promise。

使用async/await會更加簡單:

// 假設 getData() 和 getOtherData() 返回的是 Promise

actions: {
  async actionA ({ commit }) {
    commit('gotData', await getData())
  },
  async actionB ({ dispatch, commit }) {
    await dispatch('actionA') // 等待 actionA 完成
    commit('gotOtherData', await getOtherData())
  }
}

Modules

由於使用單一狀態樹,應用的所有狀態會集中到一個比較大的對象。當應用變得非常復雜時,store對象就有可能變得相當臃腫。

為了解決以上問題,Vuex允許我們將store分割成模塊(module)。每個模塊擁有自己的state、mutation、action、getter、甚至是嵌套子模塊——從上至下進行同樣方式的分割:

const moduleA = {
  state: { ... },
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: { ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

store.state.a // -> moduleA 的狀態
store.state.b // -> moduleB 的狀態

插件

Vuex的store接受plugins選項,這個選項暴露出每次mutation的鈎子。Vuex插件就是一個函數,它接收store作為唯一參數。

嚴格模式

開啟嚴格模式,僅需在創建store的時候傳入strict:true

在嚴格模式下,無論何時發生了狀態變更且不是由mutation函數引起的,將會拋出錯誤。這能保證所有的狀態變更都能被調試工具跟蹤到。

不要在發布環境下啟用嚴格模式!嚴格模式會深度監測狀態樹來檢測不合規的狀態變更--請確保在發布環境下關閉嚴格模式,以避免性能損失。

表單處理

測試

熱重載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM