理理Vue細節

陳煜侖發表於2019-04-15

1. 動態屬性名:可使用表示式來設定動態屬性名或方法名:

<!-- 屬性name -->
<a :[name]="url"> ... </a>
<!-- 計算屬性sss和s -->
<img :[sss]="/img/test.png"/>  
<!-- 方法change1和change2 -->
<img :[change1()]="change2()"/>

data: {
    name: 'href',
    sss: 'src'
}
複製程式碼

注意:要避免空格和引號等,且需要小寫,可使用計算屬性來應對複雜表示式,都需要使用[]

2. computed/methods/watch

  • computed可使用get/set
   computed: {
       top() {
           return 'top'
       },
       name: {
           get () {
               return this.name
           },
           set (val) {
               this.name = val
           }
       }
   }
複製程式碼
  • computed可快取,但不可傳參,會根據data中的屬性變化而變化,即是根據響應式依賴來變化,而Date不是響應式依賴,即不會變化;method則每次都會進行計算,但可傳參。

  • watch用於處理非同步或開銷較大的操作,如輸入搜尋時。

3. style繫結

  • 直接物件或變數物件
  • 計算屬性
  • 直接style或style物件
<!-- 屬性名可加引號也可不加,屬性小駝峰 -->
<div :style="{ 'color': 'red', fontSize: fontSize + 'px' }">樣式3</div>
複製程式碼
  • 陣列結合三目/陣列結合物件
data: {
  isActive: true,
  activeClass: 'active'
}
<!-- 使用陣列時變數和字串需要通過引號來區分 -->
<div :class="[isActive ? activeClass : '', 'errorClass']"></div>
<!-- 使用物件時類名不加引號可表示變數也可表示字串 -->
<div :class="[{ active: isActive }, 'errorClass']"></div>
複製程式碼

4. v-if條件渲染

  • 可使用template包裹元素,template會被當成不可見的包裹元素
<template v-if="ok">
    <h1>Title</h1>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
</template>
複製程式碼
  • 多條件判斷
<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>
複製程式碼

5. key

  • 新增key防止vue重複利用不想被重複利用的元素,如下的input如果不新增key,則vue會重複使用key,進而inputvalue值在切換後還會被保留,因為vue僅僅替換了placeholder
<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>
複製程式碼

6. v-if和v-show

  • v-if是元件的銷燬和重建,如果初始條件為false,則什麼都不做,直到變為真,所以切換開銷高,執行條件很少改變時適用
  • v-showdisplay:noneblock之間的CSS切換,基於渲染,不管初始條件如何都會渲染,所以初始渲染開銷高,切換頻率高時適用

7. v-for

  • 可使用in或者of
  • 也可遍歷物件:v-for="(value, key, index) in obj"
  • 可根據template渲染多個組合元素:
<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider"></li>
  </template>
</ul>
複製程式碼

8. v-for和v-if

  • v-for優先順序更高,所以v-if會重複執行於每個v-for迴圈中,所以儘量不要一起使用,可先使用計算屬性對資料進行過濾再遍歷。

9. 更改響應式資料

  • Vue.set(object, key, value)
  • this.$set(object, key, value)
  • this.items.splice(index, 1, newValue)
  • 批量新增屬性:
// 不要直接Object.assign(this.items, {age: 18}
this.items = Object.assign({}, this.items, {
  age: 18,
  favoriteColor: 'Vue Green'
})
複製程式碼

10. 事件修飾符

  • .passive:滾動的預設事件會立即出發,即告訴瀏覽器不想阻止預設事件的觸發,可提升移動端效能
<div @scroll.passive="onScroll">...</div>
複製程式碼
  • .capture:新增事件監聽器時使用事件捕獲模式,即元素自身觸發的事件先在此處理,然後才交由內部元素進行處理
  • .self:只當在 event.target 是當前元素自身時觸發處理函式,即事件不是從內部元素觸發的
  • .once:點選事件只會觸發一次
  • 鍵盤修飾符:<input @keyup.enter="submit">

11. v-model

  • 選擇框
<!-- 單選框時,picked為字串 "a",不是布林值 -->
<input type="radio" value="a" v-model="picked">

<!-- 多選框時,toggle預設值設為字串或布林值時得到布林值,設為陣列時得到的是value值-->
<input type="checkbox" value="b" v-model="toggle">

<!-- 當選中第一個選項時,selected為字串value的值 "abc" -->
<select v-model="selected">
  <option value="abc">ABC</option>
</select>
複製程式碼
  • 修飾符.lazy:在change時而非input時更新 <input v-model.lazy="msg" >

注:change事件是在input失去焦點時觸發,即用於單選、多選框和選擇框,而input事件是在value值變化時觸發,但指令碼改變value值時不會觸發,即用於text和textarea

  • 修飾符.number:輸入值轉為數值
  • 修飾符.trim:過濾收尾空白字元

12. Prop

  • 使用v-bind="obj"會將物件的每個屬性都作為一個獨立的prop傳入進去,所以接受時也需要逐個屬性接收。
<test v-bind="obj"></test>
複製程式碼
  • props雖然是單向資料流,但對於引用型別,子元件還是可以改變父元件的狀態。
  • props會在元件例項建立之前進行驗證,所以例項的屬性再defaultvalidator中是不可用的。

13. 自定義事件

  • 自定義事件需要注意事件名為小寫或-分隔,因為$emit('BaseEvent')雖然事件名不會變,但在html中該事件名會被轉化為小寫,不會監聽到。

14. slot

  • 具名插槽
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>
<!-- 預設插槽也可不用加上template和v-slot -->
  <template v-slot:default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>
  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>
複製程式碼
  • 作用域插槽
<!-- current-user元件 -->
<span>
  <slot :user="user">
    {{ user.lastName }}
  </slot>
</span>

<!-- 父級元件通過自定義名稱訪問子級作用域 -->
<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

<!-- 支援縮寫和解構 -->
<current-user>
  <template #default="{ user = { firstName: Gust } }">
    {{ user.firstName }}
  </template>
</current-user>
複製程式碼

15. 元件通訊

  • vuex/eventBus
  • prop/$emit
  • $children/$parent
  • provide/inject
  • $refs
// 父或祖先級
provide: function () {
  return {
    getMap: this.getMap
  }
}

// 後代級
inject: ['getMap']
複製程式碼

16. scope

  • scoped 屬性會自動新增一個唯一的屬性 (比如 data-v-21e5b78) 為元件內 CSS 指定作用域,編譯的時候 .list-container:hover 會被編譯成類似 .list-container[data-v-21e5b78]:hover

17. 路由

  • 區分:this.$router指路由器,this.$route指當前路由

  • 萬用字元:捕獲所有路由或 404 Not found路由

  // 含萬用字元的路由都要放在最後,因為優先順序由定義順序決定
{
  // 會匹配所有路徑
  path: '*'
}
{
  // 會匹配以 `/user-` 開頭的任意路徑
  path: '/user-*'
}
複製程式碼
  • 當使用一個萬用字元時,$route.params內會自動新增一個名為 pathMatch 引數。它包含了 URL 通過萬用字元被匹配的部分:
// 給出一個路由 { path: '/user-*' }
this.$router.push('/user-admin')
this.$route.params.pathMatch // 'admin'
// 給出一個路由 { path: '*' }
this.$router.push('/non-existing')
this.$route.params.pathMatch // '/non-existing'
複製程式碼
  • 點選 <router-link :to="..."> 等同於呼叫 router.push(...)方法,因為<router-link>會在內部呼叫該方法,進而在history棧新增一個新的記錄

  • 使用了push時,如果提供的path不完整,則params會被忽略,需要提供路由的 name 或手寫完整的帶有引數的 path

const userId = '123'
router.push({ name: 'user', params: { userId }})  // -> /user/123
router.push({ path: `/user/${userId}` })          // -> /user/123
// 這裡的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
複製程式碼
  • router.push/router.replace/router.go 效仿於 window.history.pushState/window.history.replaceState/window.history.go

  • 命名檢視:router-view可設定名字,如果router-view沒有設定名字,那麼預設為 default

<router-view></router-view>
<router-view name="a"></router-view>
<router-view name="b"></router-view>

const router = new VueRouter({
  routes: [
    {
      path: '/',
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      } 
    }
  ]
})
複製程式碼
  • 路由使用props:可將路由引數設定為元件屬性
const User = {
  props: ['id'],
  template: '<div>User {{ id }}</div>'
}
// 通過布林值設定
const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User, props: true },

    // 對於包含命名檢視的路由,你必須分別為每個命名檢視新增 `props` 選項:
    {
      path: '/user/:id',
      components: { default: User, sidebar: Sidebar },
      props: { default: true, sidebar: false }
    }
  ]
})

// 通過函式設定query 
// URL /search?q=vue 會將 {name: 'vue'} 作為屬性傳遞給 SearchUser 元件
const router = new VueRouter({
  routes: [
    { path: '/search', component: SearchUser, props: (route) => ({ name: route.query.q }) }
  ]
})
複製程式碼
  • beforeRouteEnter:可使用beforeRouteEnter來提前獲取介面資料,同時需要在next後才能訪問到例項:
beforeRouteEnter(to, from, next) {
  axios('/text.json').then(res => {
    next(vm => {
      vm.datas = res
    })
  })
}
複製程式碼
  • 路由設定有引數時,如果跳轉頁面後再通過返回鍵返回時,路由會保留有引數,如果通過push跳轉返回,則不會保留該引數,這在第三方呼叫模組傳參時需要注意。

18. loader

  • Vue Loader編譯單檔案的template塊時,會將所有遇到的URL資源轉為webpack模組請求:
// <img src="../image.png">將會被編譯成為:
createElement('img', {
  attrs: {
    src: require('../image.png') // 現在這是一個模組的請求了
  }
})
複製程式碼
  • 資源URL轉換規則
  1. 如果是絕對路徑,例如 /images/foo.png),則會原樣保留。
  2. 如果路徑以.開頭,將會被看作相對的模組依賴,並按照你的本地檔案系統上的目錄結構進行解析。
  3. 如果路徑以~開頭,其後的部分將會被看作模組依賴。
  4. 如果路徑以 @ 開頭,也會被看作模組依賴。

後續會持續更新,歡迎關注!

理理Vue細節

相關文章