创建
创建应用
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-model
和 v-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
:先前的值,仅在beforeUpdate
和updated
中可用。值是否已更改都可用。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
上一个虚拟节点,仅在 beforeUpdate
和 updated
钩子中可用。
动态指令参数
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
指令扩展为 modelValue
和 onUpdate: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
返回对象的响应式副本
ref
ref
会返回一个可变的响应式对象,只包含一个名为 value
的 property
展开
Ref 展开仅发生在被响应式 Object
嵌套的时候:可以省略value
当从 Array
或原生集合类型如 Map
访问 ref 时,不会进行展开
解构
普通的解构会使property的响应性丢失
let { author, title } = book
转换为一组ref后保留响应式关联:
let { author, title } = toRefs(book)
使用 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
函数的第二个参数是 context
。context
是一个普通的 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:
- property 的 name (
<String>
类型) - property 的 value
inject
函数有两个参数:
- 要注入的 property 的名称
- 一个默认的值 (可选)
…
https://vue3js.cn/docs/zh/guide/change-detection.html#声明响应式-property???