【Vue】Vue3吐血整理(待更新...)


創建

創建應用

const app = Vue.createApp({ /* 選項 */ })

鏈式

Vue.createApp({})
  .component('SearchInput', SearchInputComponent)
  .directive('focus', FocusDirective)
  .use(LocalePlugin)

加載應用

const vm = app.mount('#app')

生命周期

實例的生命周期

動態綁定js表達式

綁定js表達式,根據表達式的值動態綁定

<a v-on:[js表達式]=""></a>
<a @[event]="doSomething"> ... </a>

約束

如空格和引號,放在 HTML attribute 名里是無效的

<a v-bind:['foo' + bar]="value"> ... </a>

變通的辦法是使用沒有空格或引號的表達式,或用computed替代這種復雜表達式

在 DOM 中使用模板時,避免使用大寫字符來命名鍵名(全部強制轉為小寫,相當於someattr的property

<a v-bind:[someAttr]="value"> ... </a>

data

命名

內置 API:$ 前綴

內部 property: _ 前綴

避免使用這兩個字符開頭的的頂級 data property 名稱。

method

Vue 自動為 methods 綁定 this,以便於它始終指向組件實例
在定義 methods 時應避免使用箭頭函數,因為這會阻止 Vue 綁定恰當的 this 指向

防抖和節流

防抖:對於短時間內連續觸發的事件,使某個時間期限內,事件處理函數只執行一次。(讀條)
節流:函數執行一次后,在某個時間段內暫時失效,過了這段時間后再重新激活(CD)

app.component('save-button', {
  created() {
    // 用 Lodash 的防抖函數
    this.debouncedClick = _.debounce(this.click, 500)
  },
  unmounted() {
    // 移除組件時,取消定時器
    this.debouncedClick.cancel()
  },
  methods: {
      click: _.debounce(function() {
        // ... 響應點擊 ...
      }, 500)
  },
  template: `
    <button @click="debouncedClick">
      Save
    </button>
  `
})

computed

Getter:

與methods的區別:

​ 計算屬性是基於它們的反應依賴關系緩存的。計算屬性只在相關響應式依賴發生改變時它們才會重新求值。

Setter:

​ 默認只有getter,默認時可以提供setter

computed: {
  fullName: {
    // getter
    get() {
      return this.firstName + ' ' + this.lastName
    },
    // setter
    set(newValue) {
      const names = newValue.split(' ')
      this.firstName = names[0]
      this.lastName = names[names.length - 1]
    }
  }
}

watch

使用 watch 選項允許我們執行異步操作 (訪問一個 API),限制我們執行該操作的頻率,並在我們得到最終結果前,設置中間狀態

watch: {
	xxx(new,old){
		...
	}
}

(同樣可以使用vm.$watch API

class

<div
  class="static"
  :class="{ active: isActive, 'text-danger': hasError }"
></div>
也可以綁定一個返回對象的computed
<div :class="classObject"></div>
...
computed: {
  classObject() {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal'
    }
  }
}
//數組,三元表達式同樣允許
<div :class="[activeClass, errorClass]"></div>
<div :class="[isActive ? activeClass : '', errorClass]"></div>

組件中綁定class,可以選擇將傳進來的attr綁定到特定的tag上

app.component('my-component', {
  template: `
    <p :class="$attrs.class">Hi!</p>
    <span>This is a child component</span>
  `
})

style

直接綁定一個樣式對象,當然也可以綁定分散的data,語法類似css

<div :style="styleObject"></div> //數組語法可以將多個樣式對象應用到同一個元素上
data() {
  return {
    styleObject: {
      color: 'red',
      fontSize: '13px'
    }
  }
}

自動添加前綴

在 :style 中使用需要 (瀏覽器引擎前綴) vendor prefixes 的 CSS property 時,如 transform,Vue 將自動偵測並添加相應的前綴。

多重值

<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

只會渲染最后一個被瀏覽器支持的值

v-if & v-show

  • 如果需要非常頻繁地切換,則使用 v-show 較好;
  • 如果在運行時條件很少改變,則使用 v-if 較好。

當 v-if 與 v-for 一起使用時,v-if 具有比 v-for 更高的優先級,不推薦同時使用
修正方法:

<template v-for="todo in todos">
  <li v-if="!todo.isComplete">
    {{ todo }}
  </li>
</template>

v-for

<li v-for="(item, index) in items"></li>  <!-- 可以用 of 替代 in 作為分隔符 -->
<li v-for="(value, name) in myObject"> <!-- 遍歷對象 -->
  {{ name }}: {{ value }}
</li>
<li v-for="(value, name, index) in myObject"> <!-- 第三個參數為索引 -->
  {{ index }}. {{ name }}: {{ value }}
</li>

建議盡可能在使用 v-for 時提供 key attribute

除非遍歷輸出的 DOM 內容非常簡單,或者是刻意依賴默認行為以獲取性能上的提升,用於強制替換元素/組件而不是重復使用它

更變或替換數組

更變:push() pop() shift() unshift() splice() sort() reverse()
替換:filter() concat() slice()
Vue 不會重新渲染整個列表

組件數據傳遞

組件中使用v-for不會將數據自動傳遞到組件里,因為組件有自己獨立的作用域。
為了把迭代數據傳遞到組件里,我們要使用 props:

<my-component
  v-for="(item, index) in items"
  :item="item"
  :index="index"
  :key="item.id"
></my-component>

v-on

$event可以傳入方法,獲得原生DOMevent

  • $event是指當前觸發的是什么事件(鼠標事件,鍵盤事件等)
  • $event.target則指的是事件觸發的目標,即哪一個元素觸發了事件,這將直接獲取該dom元素
  • $event.target.tagName指向事件發生目標的tag
<button @click="one($event), two($event)">
  Submit
</button>
methods: {
  one(event) {
    // first handler logic...
  },
  two(event) {
    // second handler logic...
  }
}

事件修飾符

.stop .prevent .capture .self .once .passive

順序不同產生的效果不同

<!-- 阻止單擊事件繼續傳播 -->
<a @click.stop="doThis"></a>

按鍵、系統、鼠標修飾符

按鍵:.enter .tab .delete .esc .space .up .down .left .right

系統:.ctrl .alt .shift .meta

鼠標:.left .right .middle

.exact

精確控制按下的系統修飾符組合

v-model

v-model 會忽略所有表單元素的 value、checked、selected attribute的初始值而總是將當前活動實例的數據作為數據來源。你應該通過 JavaScript 在組件的 data 選項中聲明初始值。

多選綁定
<select v-model="selected" multiple>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

值綁定
通過:value來綁定v-model的值
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" />

v-model
.lazy 當change而非input
.number 轉換輸入值為數值類型
.trim 過濾首尾空白字符

component

組件可以在Vue根實例中作為自定義元素使用
與new Vue接受相同的選項,例如 data、computed、watch、methods 以及生命周期鈎子等(無el)

<!-- Prop -->
通過 Prop 向子組件傳遞數據,被注冊之后,就可以作為自定義attribute傳遞

<!-- emit -->
$emit 附加參數都會傳給監聽器回調,可以附加額外參數
@click="$emit('enlarge-text')"
@click="$emit('enlarge-text',0.1)"
使用$event來訪問到被拋出的值
@enlarge-text="postFontSize += $event"
如果處理函數是一個方法,那么拋出的值會作為第一個參數來傳入這個方法
emits選項也可以拋出事件
app.component('blog-post', {
  props: ['title'],
  emits: ['enlarge-text']
})
這將允許你檢查組件拋出的所有事件(validate)

<!-- 組件下的v-model -->
<custom-input v-model="searchText"></custom-input>
app.component('custom-input', {
  props: ['modelValue'],
  template: `
    <input
      :value="modelValue"
      @input="$emit('update:modelValue', $event.target.value)"
    >
  `
})
使用computed方法實現:
app.component('custom-input', {
  props: ['modelValue'],
  template: `
    <input v-model="value">
  `,
  computed: {
    value: {
      get() {
        return this.modelValue
      },
      set(value) { this.$emit('update:modelValue', value)
      }
    }
  }
})

<!-- 動態組件 -->
<component :is="currentTabComponent"></component>
組件會在currentTabComponent改變時改變,cTC可以包括已注冊組件的名字,或一個組件選項對象

v-is 可以讓本來渲染出錯(不該出現在特定元素內部或外部的元素,比如ul只可以有li)的tag有了變通方法
<table>
  <tr v-is="'blog-post-row'"></tr>
</table>
值應為js字符串文本

<!-- 命名法 -->
組件命名:(推薦kebab-case,避免與當前以及未來的 HTML 元素發生沖突)
(對於非字符串模板或單文件組件,即對於直接在DOM中使用組件時)
1.全部小寫
2.包含連字符 (及:即有多個單詞與連字符符號連接)

對於PascalCase(首字母大寫命名)
定義一個組件時,你在引用這個自定義元素時兩種命名法都可以使用

HTML 屬性名不區分大小寫,在JavaScript中的駝峰
app.component('blog-post', {
  props: ['postTitle'],
  template: `
    <h3>{{ postTitle }}</h3>
  `
})
在HTML則是橫線字符分割
<blog-post post-title="hello!"></blog-post>

???
需要注意的是如果我們從以下來源使用模板的話,這條限制是不存在的:
字符串模板 (例如:template: '...')
單文件組件
<script type="text/x-template"></script>

<!-- 注冊 -->
全局注冊:
app.component('component-a', {
  /* ... */
})
局部注冊:(局部注冊的組件在其子組件中不可用
const ComponentA = {
  /* ... */
}
const app = Vue.createApp({
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})

Props

-- 字符串數組形式
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

-- 每個Prop指定類型
props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise // 或任何其他構造函數
}

-- 傳遞靜態或動態的 Prop
任何類型的值都可以通過v-bind:的attribute傳給一個prop

-- 單向數據流
父子 prop 之間形成了一個單向下行綁定:
	父級 prop 的更新會向下流動到子組件中,反之不行
每次父級組件發生變更時,子組件中所有的 prop 都將會刷新為最新的值
	--> 不應該在一個子組件內部改變 prop,引用傳入將會影響到父組件的狀態
如果需要改變prop:
1.如果希望作為本地prop使用,最好定義一個本地data property接收父傳遞
2.如果要轉換,可以定義一個計算屬性,對原始的值進行轉換然后保存

<!-- 驗證 -->
propE: {
      type: Object,
      // 對象或數組默認值必須從一個工廠函數獲取
      default: function() {
        return { message: 'hello' }
      }
    },
propF: {
	validator: function(value) {
	// 這個值必須匹配下列字符串中的一個
	return ['success', 'warning', 'danger'].indexOf(value) !== -1
	}
}
注意:prop 會在一個組件實例創建之前進行驗證,所以實例的 property (如 data、computed 等) 在 default 或 validator 函數中是不可用的。
type 可以是String Number Boolean Array Object Date Function Symbol

<!-- 命名 -->
當你使用 DOM 中的模板時,
camelCase (駝峰命名法) 的 prop 名需要使用其等價的 kebab-case (短橫線分隔命名) 命名:
app.component('blog-post', {
  // camelCase in JavaScript
  props: ['postTitle'],
  template: '<h3>{{ postTitle }}</h3>'
})
<!-- kebab-case in HTML -->
<blog-post post-title="hello!"></blog-post>

非 Prop 的 Attribute

一個非 prop 的 attribute 定義:
傳向一個組件,但是該組件並沒有相應 props 或 emits 定義的 attribute
包括 class、style 和 id 等屬性。

<!-- 單個根節點上的 Attribute 繼承 -->
當組件返回單個根節點時,非 prop attribute 將自動添加到根節點的 attribute 中。
app.component('date-picker', {
  template: `
    <div class="date-picker">
      <input type="datetime" />
    </div>
  `
})

<!-- 禁用 Attribute 繼承 -->
如果你不希望組件的根元素繼承 attribute,你可以在組件的選項中設置 inheritAttrs: false

可以訪問組件的 $attrs property獲取

app.component('date-picker', {
  inheritAttrs: false,
  template: `
    <div class="date-picker">
      <input type="datetime" v-bind="$attrs" />
    </div>
  `
})

<!-- 多個根節點上的 Attribute 繼承 -->
有多個根節點的組件不具有自動 attribute 回退行為
如果未顯式綁定 $attrs,將發出運行時警告。

自定義事件

不同於組件和 prop,事件名不存在任何自動化的大小寫轉換。
而是觸發的事件名需要完全匹配監聽這個事件所用的名稱

!觸發一個 camelCase 名字的事件,則監聽這個名字的 kebab-case 版本是不會有任何效果的:

this.$emit('myEvent')
<my-component @my-event="doSomething"></my-component>

推薦你始終使用 kebab-case 的事件名

<!-- 定義自定義事件 -->
通過 emits 選項在組件上定義已發出的事件。
app.component('custom-form', {
  emits: ['in-focus', 'submit']
})
當在 emits 選項中定義了原生事件 (如 click) 時,將使用組件中的事件替代原生事件偵聽器。
建議定義所有發出的事件,以便更好地記錄組件應該如何工作。

-- 驗證拋出的事件
app.component('custom-form', {
  emits: {
    // 沒有驗證
    click: null,

    // 驗證submit 事件
    submit: ({ email, password }) => {
      if (email && password) {
        return true
      } else {
        console.warn('Invalid submit event payload!')
        return false
      }
    }
  },
  methods: {
    submitForm() {
      this.$emit('submit', { email, password })
    }
  }
})

<!-- v-model -->
已在v-model中介紹過,回顧一下:(多個綁定)
<user-name
  v-model:first-name="firstName"
  v-model:last-name="lastName"
></user-name>
app.component('user-name', {
  props: {
    firstName: String,
    lastName: String
  },
  template: `
    <input 
      type="text"
      :value="firstName"
      @input="$emit('update:firstName', $event.target.value)">
    <input
      type="text"
      :value="lastName"
      @input="$emit('update:lastName', $event.target.value)">
  `
})

<!-- 定義自定義修飾符 -->
v-model 有內置修飾符——.trim、.number 和 .lazy
3.x中,添加到組件 v-model 的修飾符將通過 modelModifiers prop 提供給組件

slot

<slot></slot>
組件渲染時替換內容

!template 中沒有包含一個 <slot> 元素,則該組件起始標簽和結束標簽之間的任何內容都會被拋棄

<!-- 作用域 -->
<todo-button action="delete">
  Clicking here will {{ action }} an item
  <!-- `action` 未被定義,因為它的內容是傳遞*到* <todo-button>,而不是*在* <todo-button>里定義的。  -->
</todo-button>
    
規則:
    父級模板里的所有內容都是在父級作用域中編譯的;
    子模板里的所有內容都是在子作用域中編譯的

<!-- 后備內容 --> 
<button type="submit">
  <slot>Submit</slot>
</button>
當slot不顯示時顯示
    
<!-- 具名插槽 -->
-定義:
<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>
一個不帶 name 的 <slot> 出口會帶有隱含的名字“default”。
-使用:
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>

  <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>

!v-slot 只能添加在 <template> 上 (只有一種例外情況:
當被提供的內容只有默認插槽時,組件的標簽才可以被當作插槽的模板來使用)

<!-- 插槽 prop -->
要使 item 可用於父級提供的 slot 內容,我們可以添加一個 <slot> 元素並將其綁定為屬性
<ul>
  <li v-for="( item, index ) in items">
    <slot :item="item"></slot>
  </li>
</ul>
    
-- 重命名
<todo-list v-slot="{ item: todo }">
  <i class="fas fa-check"></i>
  <span class="green">{{ todo }}</span>
</todo-list>
    
-- 后備內容 
<todo-list v-slot="{ item = 'Placeholder' }">
  <i class="fas fa-check"></i>
  <span class="green">{{ item }}</span>
</todo-list>
    
<!-- 動態插槽名 -->
<template v-slot:[dynamicSlotName]>
    
<!-- 縮寫 -->
v-slot: --> #
    <template #header>
    	<h1>Here might be a page title</h1>
  	</template>

提供 / 注入

父組件可以作為其所有子組件的依賴項提供程序,而不管組件層次結構有多深
-- 父組件有一個 provide 選項來提供數據
-- 子組件有一個 inject 選項來開始使用這個數據。

//provide
provide: {
	xxx: 
}
//inject
${this.xxx}

要訪問組件實例 property,我們需要將 provide 轉換為返回對象的函數

//返回對象
provide() {
	return {
    	todoLength: this.todos.length
    }
}
處理響應性

默認情況下,provide/inject 綁定不是被動綁定,無響應性。

-- 增加computed達到響應

​ provide() {
​ return {
​ todoLength: Vue.computed(() => this.todos.length)
​ }
}

-- ref property 或 reactive
import { provide, reactive, ref } from 'vue'

export default {
  components: {
    MyMarker
  },
  setup() {
    const location = ref('North Pole')
    const geolocation = reactive({
      longitude: 90,
      latitude: 135
    })
	provide('location', location)
	provide('geolocation', geolocation)
  }
}

動態組件 & 異步組件

keep-alive
<!-- 失活的組件將會被緩存!-->
<keep-alive>
  <component :is="currentTabComponent"></component>
</keep-alive>
defineAsyncComponent

?

components: {
    AsyncComponent: defineAsyncComponent(() =>
      import('./components/AsyncComponent.vue')
    )
}

模板引用???

返回對象

應該避免在模板或計算屬性中訪問 $refs

處理邊界情況

強制更新

大概率出現錯誤,非常罕見的情況使用$forceUpdate強制更新

低級靜態組件與 v-once

在 Vue 中渲染純 HTML 元素的速度非常快,但有時你可能有一個包含很多靜態內容的組件。在這些情況下,可以通過向根元素添加 v-once 指令來確保只對其求值一次,然后進行緩存

Mixin

// define a mixin object
const myMixin = {
  created() {
    this.hello()
  },
  methods: {
    hello() {
      console.log('hello from mixin!')
    }
  }
}

// define an app that uses this mixin
const app = Vue.createApp({
  mixins: [myMixin]
})

app.mount('#mixins-basic') // => "hello from mixin!"
選項合並
  • 數據對象在內部會進行遞歸合並,並在發生沖突時以組件數據優先
  • 同名鈎子函數將合並為一個數組,因此都將被調用;混入對象的鈎子將在組件自身鈎子之前調用。
自定義選項合並策略
const app = Vue.createApp({})

app.config.optionMergeStrategies.customOption = (toVal, fromVal) => {
  // return mergedVal
}
customOption是沖突值的名字
?
toVal為Mixin提供
fromVal為原參數
合並策略接收在父實例和子實例上定義的該選項的值,分別作為第一個和第二個參數

自定義指令

除了核心功能默認內置的指令 (v-modelv-show),Vue支持自定義指令。

全局指令
const app = Vue.createApp({})
// 注冊一個全局自定義指令 `v-focus`
app.directive('focus', {
  // 當被綁定的元素插入到 DOM 中時……
  mounted(el) {
    // Focus the element
    el.focus()
  }
})
局部指令
directives: {
  focus: {
    // 指令的定義
    mounted(el) {
      el.focus()
    }
  }
}

使用方法:<input v-focus />

鈎子函數

一個指令定義對象可以提供如下幾個鈎子函數 (均為可選):

app.directive('my-directive', {
  // 指令是具有一組生命周期的鈎子:
  // 在綁定元素的父組件掛載之前調用
  beforeMount() {},
  // 綁定元素的父組件掛載時調用
  mounted() {},
  // 在包含組件的 VNode 更新之前調用
  beforeUpdate() {},
  // 在包含組件的 VNode 及其子組件的 VNode 更新之后調用
  updated() {},
  // 在綁定元素的父組件卸載之前調用
  beforeUnmount() {},
  // 卸載綁定元素的父組件時調用
  unmounted() {}
})
el

指令綁定到的元素。這可用於直接操作 DOM。

binding

包含以下 property 的對象。

  • instance:使用指令的組件實例。
  • value:傳遞給指令的值。例如,在 v-my-directive="1 + 1" 中,該值為 2
  • oldValue:先前的值,僅在 beforeUpdateupdated 中可用。值是否已更改都可用。
  • arg:參數傳遞給指令 (如果有)。例如在 v-my-directive:foo 中,arg 為 "foo"
  • modifiers:包含修飾符 (如果有) 的對象。例如在 v-my-directive.foo.bar 中,修飾符對象為 {foo: true,bar: true}
  • dir:一個對象,在注冊指令時作為參數傳遞。例如,在以下指令中
app.directive('focus', {
  mounted(el) {
    el.focus()
  }
})

dir 將會是以下對象 { mounted(el) { el.focus() } }

vnode

上面作為 el 參數收到的真實 DOM 元素的藍圖。

prevNode

上一個虛擬節點,僅在 beforeUpdateupdated 鈎子中可用。

動態指令參數

v-mydirective:[argument]="value"

可以使用 binding.arg 來獲取 argument

可以使用 binding.value 來獲取 value

以此根據組件實例數據進行更新

函數簡寫

去掉 mounted(){}

app.directive('pin', (el, binding) => {
  el.style.position = 'fixed'
  const s = binding.arg || 'top'
  el.style[s] = binding.value + 'px'
})
組件使用

在 3.0 中,有了片段支持,組件可能有多個根節點。如果在具有多個根節點的組件上使用自定義指令,則會產生問題。

Teleport

Teleport允許深度嵌套下直接控制DOM中哪個父節點下呈現HTML,而不必求助於全局狀態或將其拆分為兩個組件。

<teleport to="body">
	...
</teleport>
Vue components 中使用
app.component('parent-component', {
  template: `
    <h2>This is a parent component</h2>
    <teleport to="#endofbody">
      <child-component name="John" />
    </teleport>
  `
})

即使在不同的地方渲染 child-component,它仍將是 parent-component 的子級,並將從中接收 name prop。

在同一目標上使用多個 teleport

多個 <teleport> 組件可以將其內容掛載到同一個目標元素,順序將是一個簡單的追加

渲染函數

當需要可變地渲染 template 的時候,就可以使用 render 函數

app.component('anchored-heading', {
  render() {
    const { h } = Vue

    return h(
      'h' + this.level, // tag name
      {}, // props/attributes
      this.$slots.default() // array of children
    )
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})

h()

h() 函數是一個用於創建 vnode 的實用程序

// @returns {VNode}
h(
  // {String | Object | Function | null} tag
  // 一個 HTML 標簽名、一個組件、一個異步組件,或者 null。
  // 使用 null 將會渲染一個注釋。
  //
  // 必需的。
  'div',

  // {Object} props
  // 與 attribute、prop 和事件相對應的對象。
  // 我們會在模板中使用。
  //
  // 可選的。
  {},

  // {String | Array | Object} children
  // 子 VNodes, 使用 `h()` 構建,
  // 或使用字符串獲取 "文本 Vnode" 或者
  // 有 slot 的對象。
  //
  // 可選的。
  [
    'Some text comes first.',
    h('h1', 'A headline'),
    h(MyComponent, {
      someProp: 'foobar'
    })
  ]
)

render下的v-model

v-model 指令擴展為 modelValueonUpdate:modelValue 在模板編譯過程中,我們必須自己提供這些prop:

props: ['modelValue'],
render() {
  return Vue.h(SomeComponent, {
    modelValue: this.modelValue,
    'onUpdate:modelValue': value => this.$emit('update:modelValue', value)
  })
}

render下的v-on

我們必須為事件處理程序提供一個正確的prop名稱,例如,要處理 click 事件,prop名稱應該是 onClick

render() {
  return Vue.h('div', {
    onClick: $event => console.log('clicked', $event.target)
  })
}

事件修飾符

修飾符 處理函數中的等價操作
.stop event.stopPropagation()
.prevent event.preventDefault()
.self if (event.target !== event.currentTarget) return
按鍵: .enter, .13 if (event.keyCode !== 13) return (對於別的按鍵修飾符來說,可將 13 改為另一個按鍵碼
修飾鍵: .ctrl, .alt, .shift, .meta if (!event.ctrlKey) return (將 ctrlKey 分別修改為 altKey, shiftKey, 或 metaKey)

插槽

props: ['message'],
render() {
  // `<div><slot :text="message"></slot></div>`
  return Vue.h('div', {}, this.$slots.default({
    text: this.message
  }))
}
子組件插槽???
render() {
  // `<div><child v-slot="props"><span>{{ props.text }}</span></child></div>`
  return Vue.h('div', [
    Vue.h('child', {}, {
      // pass `slots` as the children object
      // in the form of { name: props => VNode | Array<VNode> }
      default: (props) => Vue.h('span', props.text)
    })
  ])
}

響應式

reactice

返回對象的響應式副本

響應性基礎 API

ref

ref 會返回一個可變的響應式對象,只包含一個名為 value 的 property

展開

Ref 展開僅發生在被響應式 Object 嵌套的時候:可以省略value

當從 Array 或原生集合類型如 Map訪問 ref 時,不會進行展開

解構

普通的解構會使property的響應性丟失

let { author, title } = book

轉換為一組ref后保留響應式關聯:

let { author, title } = toRefs(book)

Refs API

使用 readonly 防止更改響應式對象
const original = reactive({ count: 0 })
const copy = readonly(original)

Compositional API

setup 組件選項

新的 setup 組件選項在創建組件之前執行,一旦 props 被解析,並充當合成 API 的入口點。

(由於在執行 setup 時尚未創建組件實例,因此在 setup 選項中沒有 this。這意味着,除了 props 之外,你將無法訪問組件中聲明的任何屬性——data computed method

Props

setup 函數中的第一個參數是 props,是響應式的,當傳入新的 prop 時,它將被更新。

context

傳遞給 setup 函數的第二個參數是 contextcontext 是一個普通的 JavaScript 對象,它暴露三個組件的 property,不是響應式的,因此可以安全地對 context 使用 ES6 解構。

// MyBook.vue

export default {
  setup(props, context) {
    // Attribute (非響應式對象)
    console.log(context.attrs)

    // 插槽 (非響應式對象)
    console.log(context.slots)

    // 觸發事件 (方法)
    console.log(context.emit)
  }
}
setup中的生命周期鈎子
選項式 API Hook inside setup
beforeCreate Not needed*
created Not needed*
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered

*Not needed:在這些鈎子中編寫的任何代碼都應該直接在 setup 函數中編寫。

Compositional API的提供/注入

我們也可以在組合式 API 中使用 provide/inject。兩者都只能在當前活動實例的 setup() 期間調用。

  • provide 函數允許你通過兩個參數定義 property:
  1. property 的 name (<String> 類型)
  2. property 的 value
  • inject 函數有兩個參數:
  1. 要注入的 property 的名稱
  2. 一個默認的值 (可選)

https://vue3js.cn/docs/zh/guide/change-detection.html#聲明響應式-property???


免責聲明!

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



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