参考文章
Vue3相对Vue2新增的特性
Vue3和Vue2的区别
Vue3中文文档
值得注意的新特性
组合式 API
Teleport
片段
触发组件选项
createRenderer API 来自 @vue/runtime-core 创建自定义渲染器
单文件组件组合式 API 语法糖 (< script setup>) 实验性
单文件组件状态驱动的 CSS 变量 (< style vars>) 实验性
单文件组件
合成型API(Composition)
1、data
Vue2采用了选项类型API(Options API),而Vue3采用的是合成型API。
旧的选项型API在代码里分割了不同的属性(properties):data,computed属性,methods,等等。新的合成型API能让我们用方法(function)来分割,相比于旧的API使用属性来分组,这样代码会更加简便和整洁。
import { reactive } from 'vue'
export default {
props: {
title: String
},
setup () {
const state = reactive({
username: '',
password: ''
})
return { state }
}
}
为了可以让开发者对反应型数据有更多的控制,我们可以直接使用到 Vue3 的反应API(reactivity API)。
使用以下三步来建立反应性数据:
1、从vue引入reactive
2、使用reactive()方法来声明我们的数据为反应性数据
3、使用setup()方法来返回我们的反应性数据,从而我们的template可以获取这些反应性数据
这里构造的反应性数据就可以被template使用,可以通过state.username和state.password获得数据的值。
2、methods
export default {
props: {
title: String
},
setup () {
const login = () => {
// 登陆方法
}
return {
login
}
}
}
Vue3 的合成型API里面的setup()方法也是可以用来操控methods的。创建声明方法其实和声明数据状态是一样的。— 我们需要先声明一个方法然后在setup()方法中返回(return), 这样我们的组件内就可以调用这个方法了。
3、生命周期
生命周期也可以声明在setup函数里,但是Vue3的生命周期钩子不是全局可调用的了,需要单独引入。另外setup在beforeCreated内调用,没有this。
import { reactive, onMounted } from 'vue'
export default {
props: {
title: String
},
setup () {
// ..
onMounted(() => {
console.log('组件已挂载')
})
// ...
}
}
注意destroy那一对生命周期变成了unmount,同时每个生命周期都增加了"on"
<template>
子组件
{{stu}}
</template>
<script>
import { onBeforeMount, onBeforeUnmount, onBeforeUpdate, onMounted, onUnmounted, onUpdated, ref } from '@vue/runtime-core'
export default {
props: {
list: {
type: String,
default: '1'
}
},
setup (props) {
const stu = ref(props.list)
onBeforeMount(() => {
console.log('DOM渲染前onBeforeMount', document.querySelector('.container'))
})
onMounted(() => {
console.log('DOM渲染后1onMounted', document.querySelector('.container'))
})
onMounted(() => {
console.log('DOM渲染后2onMounted', document.querySelector('.container'))
})
onBeforeUpdate(() => {
console.log('更新组件前,onBeforeUpdate')
})
onUpdated(() => {
console.log('更新组件后,onUpdated')
})
onBeforeUnmount(() => {
console.log('销毁组件前,onBeforeUnmount')
})
onUnmounted(() => {
console.log('销毁组件后,onUnmounted')
})
return { stu }
},
}
</script>
4、计算属性
Vue3 的设计模式给予开发者们按需引入需要使用的依赖包。这样一来就不需要多余的引用导致性能或者打包后太大的问题。Vue2就是有这个一直存在的问题(比如小项目中生命周期很少用全,还有一些其他的特性也很少用到)
注意computed的写法变了。
import { reactive, onMounted, computed } from 'vue'
export default {
props: {
title: String
},
setup () {
const state = reactive({
username: '',
password: '',
lowerCaseUsername: computed(() => state.username.toLowerCase())
})
// ...
}
5、Props
又出现了一个Vue3和Vue2的重大区别:this在vue3中与vue2代表着完全不一样的东西。
在 Vue2,this代表的是当前组件,不是某一个特定的属性。
但是在 Vue3 中,this无法直接拿到props属性,emit events(触发事件)和组件内的其他属性。不过全新的setup()方法可以接收两个参数:
1、props - 不可变的组件参数
2、context - Vue3 暴露出来的属性(emit,slots,attrs)
就可以使用这两个参数代替this,来访问相应的变量了
6、事件
在 Vue2 中自定义事件是非常直接的,但是在 Vue3 的话,我们会有更多的控制的自由度。
setup (props, { emit }) {
// ...
const login = () => {
emit('login', {
username: state.username,
password: state.password
})
}
// ...
}
7、带 ref 的响应式变量
在 Vue 3.0 中,我们可以通过一个新的 ref 函数使任何响应式变量在任何地方起作用,如下所示:
import { ref } from 'vue'
const counter = ref(0)
console.log(counter) // { value: 0 }
console.log(counter.value) // 0
counter.value++
console.log(counter.value) // 1
ref 接受参数并返回它包装在具有 value property 的对象中,然后可以使用该 property 访问或更改响应式变量的值
在对象中包装值似乎不必要,但在 JavaScript 中保持不同数据类型的行为统一是必需的。这是因为在 JavaScript 中,Number 或 String 等基本类型是通过值传递的,而不是通过引用传递的
在任何值周围都有一个包装器对象,这样我们就可以在整个应用程序中安全地传递它,而不必担心在某个地方失去它的响应性。
换句话说,ref 对我们的值创建了一个响应式引用。使用引用的概念将在整个组合式 API 中经常使用。
8、总结
composition API:
setup():
是composition API 的入口函数
仅初始化时执行一次。(具体是在beforecreate之前执行。此时的this为undefined,所以在setup() 无法使用this获取数据)
所有的compostion API都写在 setup() 中。
参数有props和context,说明如下:
props:作用是 父组件向子组件传递的数据
context:上下文对象。可以解构成{attrs,slot,emit},分别对应vue2中的是:this.$attrs 、 this.$slot 、 this.$emit
返回值为对象,可以在模版中使用。
如果混合了vue2语法,
setup中定义的方法会和method合并,setup中定义的变量会和data合并。
setup中定义的变量和方法优先级更高。
method和data可以使用setup中定义的变量和方法。
Teleport
Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。
<body>
<div style="position: relative;">
<h3>Tooltips with Vue 3 Teleport</h3>
<div>
<modal-button></modal-button>
</div>
</div>
</body>
我们设想这样一个问题——模态是在深度嵌套的 div 中渲染的,而模态的 position:absolute 以父级相对定位的 div 作为引用。
Teleport 提供了一种干净的方法,允许我们控制在 DOM 中哪个父节点下呈现 HTML,而不必求助于全局状态或将其拆分为两个组件。
app.component('modal-button', {
template: `
<button @click="modalOpen = true">
Open full screen modal! (With teleport!)
</button>
<teleport to="body">
<div v-if="modalOpen" class="modal">
<div>
I'm a teleported modal!
(My parent is "body")
<button @click="modalOpen = false">
Close
</button>
</div>
</div>
</teleport>
`,
data() {
return {
modalOpen: false
}
}
})
一旦我们单击按钮打开模式,Vue 将正确地将模态内容渲染为 body 标签的子级。
使用 < teleport>标签,并给其to属性赋值,保证挂在的位置。
片段
在 3.x 中,组件现在可以有多个根节点!但是,这确实要求开发者明确定义属性应该分布在哪里。
<!-- Layout.vue -->
<template>
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
</template>
————————————暂时写到这里