记录一下学习Vue3.x的过程
基本格式
const app = Vue.createApp({
/* TODO */
})
计算属性缓存 VS 方法
计算属性是基于它们的反应依赖关系缓存的,即计算属性中的变量改变才改变,否则多次使用仍旧是上一次的结果。
事件
模板中包含一个特殊变量$event
,同样可以有多个方法,比如:
<button @click="one($event), two($event)"></button>
原来2.x版本是是通过.native
修饰符来指明一个原生事件,现在通过 emits
选项在组件上定义已发出的事件,皆为emit
事件,emit事件可增加验证,比如:
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
的语法糖与2.x版本也有所不同,2.x是propvalue
和事件input
,3.x版本是propmodelValue
和事件update:modelValue
,如果要修改value名称,可以通过向v-model
传递参数,比如:
<my-component v-model:title="bookTitle"></my-component>
子组件修改如下
app.component('my-component', {
props: {
title: String
},
emits: ['update:title'],
template: `
<input
type="text"
:value="title"
@input="$emit('update:title', $event.target.value)">
`
})
利用此特性,通过传递参数,增加多个v-model双向绑定
关于修饰符,3.x版本提供了一个modelModifiers
属性,比如默认的,假设有一个v-model.capitalize="myText"
,那么子组件内的props
属性中将会有modelModifiers
字段,字段值为{ capitalize: true }
。对于带参数的v-model
绑定,子组件内的props
属性中将会有arg + "Modifiers"
,比如,v-model:description.capitalize="myText"
,子组件的props
属性上将会有descriptionModifiers
字段
组件
可通过inheritAttrs: false
来禁用组件属性和事件继承,继承指的是:在模板中引入组件上的属性和事件,会被组件内的根节点继承,比如:
<div id="date-picker" class="demo">
<date-picker @change="showChange" data-status="activated"></date-picker>
</div
<!-- date-picker组件,会继承父级绑定的属性和事件 -->
app.component('date-picker', {
template: `
<select>
<option value="1">Yesterday</option>
<option value="2">Today</option>
<option value="3">Tomorrow</option>
</select>
`
})
当禁用继承后,我们可以将组件的$attrs
属性赋给我们期待的节点上,$attrs
属性包括组件 props
和 emits
property 中未包含的所有属性 (例如,class
、style
、v-on
监听器等)。比如:
app.component('date-picker', {
inheritAttrs: false,
template: `
<div class="date-picker">
<input type="datetime" v-bind="$attrs" />
</div>
`
})
多个根节点需显示指定,vue2.x不支持多个根节点
<custom-layout id="custom-layout" @click="changeValue"></custom-layout>
// 这将发出警告
app.component('custom-layout', {
template: `
<header>...</header>
<main>...</main>
<footer>...</footer>
`
})
// 没有警告,$attrs被传递到<main>元素
app.component('custom-layout', {
template: `
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
`
})
插槽slot
插槽缩写:#
2.x版本通过slot="<slot_name>"
声明使用一个具名插槽,3.x版本通过v-slot:<slot_name>
声明使用
2.x版本通过slot-scope="<attribute>"
来绑定属性,3.x版本通过v-slot:<slot_name>="<attribute>"
来绑定属性
需要注意的是,v-slot
和v-slot:<slot_name>
不能混用,容易导致作用域不明确
支持动态插槽名,v-slot:[dynamicSlotName]
Provide / Inject
跨祖孙组件传递数据时很有用,假设有一个组件继承关系如下,A组件包含B组件,B组件包含C组件,如果有需求需要A组件传值给C组件,可通过以下方式
// A组件
provide: {
user: 'John Doe'
}
// C组件
inject: ['user']
需要注意的是,如果provide了组件实例上的属性,将会抛出异常,但是,如果provide返回了对象的函数,将会可以正常传递
app.component('todo-list', {
data() {
return {
todos: ['Feed a cat', 'Buy tickets']
}
},
provide: {
todoLength: this.todos.length // 将会导致错误 `Cannot read property 'length' of undefined`
},
template: `
...
`
})
app.component('todo-list', {
data() {
return {
todos: ['Feed a cat', 'Buy tickets']
}
},
provide() {
return {
todoLength: this.todos.length // 正常传递
}
},
template: `
...
`
})
默认情况下,传递不是响应式的,即todoLength改变,inject接收到的值不会跟着改变,可以通过传递一个 ref
property 或 reactive
对象给 provide
来改变这种行为。这里通过分配一个组合式 API computed
来保持响应式。
provide() {
return {
todoLength: Vue.computed(() => this.todos.length)
}
}
组合式API
setup
函数接收props
和context
参数,setup返回的内容将暴露给组件其余部分,还可以返回一个渲染函数
context
有三个参数,attrs
,slots
,emit
,
ref
接收参数,内部将其响应式,并返回一个带有value
属性的对象,因为对象是引用传递,而Number
和String
是值传递
toRefs
,响应式对象不能使用ES6解构,因为它会消除响应性,通过toRefs
可以实现ES6解构,比如props
toRef
可以给响应式对象添加一个响应式的属性,比如const title = toRef(props, 'title')
reactive
为JavaScript 对象创建响应式状态
Ref 展开仅发生在被响应式 Object
嵌套的时候。当从 Array
或原生集合类型如 Map
访问 ref 时,不会进行展开:
setup中也可以使用生命周期钩子,结构前缀为 on
,比如onMounted
watch响应式更改,接收3个参数
- 一个响应式引用或
getter
函数 - 一个回调
- 可选的配置选项
执行setup时,组件实例尚未被创建,因此只能访问props
,attrs
,slots
,emit
,无法访问data
,computed
,methods
自定义指令
钩子函数相比2.x版本有所变化
created
:在绑定元素的 attribute 或事件监听器被应用之前调用,在指令需要附加须要在普通的v-on
事件监听器前调用的事件监听器时,这很有用。beforeMount
:当指令第一次绑定到元素并且在挂载父组件之前调用。mounted
:在绑定元素的父组件被挂载后调用。beforeUpdate
:在更新包含组件的 VNode 之前调用。updated
:在包含组件的 VNode 及其子组件的 VNode 更新后调用。beforeUnmount
:在卸载绑定元素的父组件之前调用unmounted
:当指令与元素解除绑定且父组件已卸载时,只调用一次。
teleport
可以自定义挂载到的元素,比如<teleport to="body">
渲染函数
// @returns {VNode}
h(
// {String | Object | Function | null} tag
// 一个 HTML 标签名、一个组件、一个异步组件,或者 null。
// 使用 null 将会渲染一个注释。
//
// 必需的。
'div',
// {Object} props
// 与 attribute、prop 和事件相对应的对象。
// 我们会在模板中使用。
//
// 可选的。
{},
// {String | Array | Object} children
// 子 VNodes, 使用 `h()` 构建,
// 或使用字符串获取 "文本 Vnode" 或者
// 有插槽的对象。
//
// 可选的。
[
'Some text comes first.',
h('h1', 'A headline'),
h(MyComponent, {
someProp: 'foobar'
})
]
)
Proxy
Proxy 是一个包含另一个对象或函数并允许你对其进行拦截的对象。使用语法new Proxy(target, handler)
评论 (0)