1 template
可以有多个节点
2 setup语法
替代原来的data函数,可以接收两个参数,props,context。
我们从 setup
返回的所有内容都将暴露给组件的其余部分 (计算属性、方法、生命周期钩子等等) 以及组件的模板。
由于在执行 setup
时,组件实例尚未被创建,因此在 setup
选项中没有 this
。这意味着,除了 props
之外,你将无法访问组件中声明的任何属性——本地状态、计算属性或方法。
可以省略不写,只执行一次
props
因为 props
是响应式的,你不能使用 ES6 解构,因为它会消除 prop 的响应性。
Context
传递给 setup
函数的第二个参数是 context
。context
是一个普通的 JavaScript 对象,它暴露三个组件的 proper。
context
是一个普通的 JavaScript 对象,也就是说,它不是响应式的,这意味着你可以安全地对 context
使用 ES6 解构。
export default {
setup(props, context) {
// Attribute (非响应式对象)
console.log(context.attrs)
// 插槽 (非响应式对象)
console.log(context.slots)
// 触发事件 (方法)
console.log(context.emit)
}
}
export default {
setup(props, { attrs, slots, emit }) {
...
}
}
当在执行setup时,组件实例尚未被创建,所以只能访问一下property:
props attrs slots emit
换句话说,无法访问以下组件选项:
data computed methods
结合模板使用
setup返回一个对象,则可以在组件的,模板中像传递给setup的props property一样访问该对象的property:
<template>
<div>{{ readersNumber }} {{ book.title }}</div>
</template>
<script>
import { ref, reactive } from 'vue'
export default {
setup() {
const readersNumber = ref(0)
const book = reactive({ title: 'Vue 3 Guide' })
// expose to template
return {
readersNumber,
book
}
}
}
</script>
从setup返回的refs在模板中访问时是被自动解开的,所以不应在模板中使用.value
渲染函数
setup还可以返回一个渲染函数,该函数可以直接使用在同一作用域中声明的响应式状态:
import { h, ref, reactive } from 'vue'
export default {
setup() {
const readersNumber = ref(0)
const book = reactive({ title: 'Vue 3 Guide' })
return () => h('div', [readersNumber.value, book.title])
}
}
this
在setup()内部,this不会是该活跃实例的引用,因为setup()是在解析其他组件选项之前被调用的,所以setup()内部的this的行为与其他选项中的this完全不同,这在和其它选项式API一起使用 setup() 时可能会导致混淆
3 ref
ref
为我们的值创建了一个响应式引用。在整个组合式 API 中会经常使用引用的概念。
ref
接受参数,并将其包裹在一个带有 value
property 的对象中返回,然后可以使用该 property 访问或更改响应式变量的值:
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(0)
RefImpl可以理解为 代理对象 。比如vue2中的data的数据是通过Object.defineProperty来进行拦截的
,从而来达到数据响应式的目的,而vue3是利用Es6中的proxy,相对于object.defineProperty来说,能拦截的方式更多,功能也更加强大。
ref
ref是一个函数,接收一个参数,返回的就是一个响应式对象
4 Reactive
创建一个Javascript对象 反应式状态,就要使用reactive方法
<template>
<div>
{{ data }}
<h1>
count:{{ data.count }}
</h1>
<h1>
double:{{ data.double }}
</h1>
</div>
<button @click="data.increase">加1</button>
</template>
<script lang="ts">
import { reactive, computed } from 'vue'
export default {
name: 'App',
setup () {
const data = reactive({
count: 0,
increase: () => {
data.count++
},
double: computed(() => data.count * 2)
})
return {
data
}
}
}
</script>
为什么不直接返回一个解构后的data呢 return {…data} 这是因为解构会破坏代理。不会导致数据变化 ,这里可以用toRefs
toRefs
toRefs 从组合函数返回反应对象时,此函数很有用,以便使用组件可以对返回的对象进行解构/扩展 而不会失去反应性
<template>
<div>
<h1>
count:{{ count }}
</h1>
<h1>
double:{{ double }}
</h1>
</div>
<button @click="increase">加1</button>
</template>
<script lang="ts">
import { reactive, computed, toRefs } from 'vue'
export default {
name: 'App',
setup () {
const data = reactive({
count: 0,
increase: () => {
data.count++
},
double: computed(() => data.count * 2)
})
return {
...toRefs(data)
}
}
}
</script>
5 生命周期改变
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered
由于setup是围绕beforeCreate和created生命周期挂钩运行的,因此无需显式定义他们,换句话说,将在这些挂钩中编写的任何代码都应该直接在setup函数中编写。
这些函数接受一个回调函数,当钩子被组件调用时将会被执行:
export default {
setup() {
onMounted(() => {
console.log('Component is mounted!')
})
}
}
6 watch
// watch 基本使用 记得引入
watch(data, () => {
document.title = '更新过后 ' + data.count
})
// watch 的两个参数,代表新的值和旧的值
watch(data, (newValue, oldValue) => {
console.log('old', oldValue)
console.log('new', newValue)
document.title = '更新过后 ' + data.count
})
// watch 多个值,返回的也是多个值的数组
watch([greetings, data], (newValue, oldValue) => {
console.log('old', oldValue)
console.log('new', newValue)
document.title = '更新过后' + greetings.value + data.count
})
// 使用函数 getter写法
watch([greetings, () => data.count], (newValue, oldValue) => {
console.log('old', oldValue)
console.log('new', newValue)
document.title = '更新过后' + greetings.value + data.count
})
特别注意,data是一个对象。要取里面的值
7 computed
使用方法与vue2一样,可以写在reactive内部,也可以写在外部
setup () {
const data = reactive({
count: 0,
increase: () => {
data.count++
},
double: computed(() => data.count * 2)
})
const conComputed = computed(() => data.count * 2)
const number = ref(0)
watch(data, () => {
console.log(data)
document.title = 'updated ' + data.count
})
watch(number, () => {
console.log(number)
})
return {
number,
conComputed,
...toRefs(data)
}
}
新增标签
8 teleport 瞬间移动
平时我们的遮罩层都存在于某个多级标签下面,这样其实是不合理的
teleport出现可以让我们组件移动到指定标签下面。to是要移动到哪个标签下,支持选择器
9 Suspense异步请求
解决了在异步请求中,图片返回过慢导致的空白
// App
<template>
<Suspense>
<template #default>
<pic-show />
</template>
<template #fallback>
<h1>Loading !...</h1>
</template>
</Suspense>
</template>
<script lang="ts">
import ShowPic from './components/ShowPic.vue'
export default {
name: 'App',
components: {
ShowPic
}
}
</script>
10 自定义Hooks
11 结合ts开发组件
12 vite是一个由原生ESM驱动的Web开发构建工具。在开发环境下基于浏览器原生ES imports开发,在生产环境下基于Rollup打包。
具有以下特点
快速的冷启动
即时的模块热更新
真正的按需编译
原理:Vite的实现是个基于浏览器原生支持的模块功能
当 script.type
为 module
时,通过 src
及 import
导入的文件会发送 http
请求。
通过发送请求,来获取文件,当需要用到的使用,才会过去请求,真正的按需加载