1.入口
- 创建实例时,配置setup方法,然后其内部书写组合式API代码,通过组合式API生产的数据和返回,需要暴漏出去才能给HTML使用
<script>
//组合式(解构赋值)
const {createApp,ref} = Vue
var app = Vue.createApp({
//所有的代码写入到steup方法中
setup(){
//创建响应式数据
const title = ref('实例2')
function modifyTitle(){
//在 JavaScript 中需要 .value
title.value = "实例2被修改"
}
//返回定义的数据和方法
return {
title,
modifyTitle
}
}
})
app.mount('#app2')
</script>
- 单文件组件:将setup声明写到script标签中,然后直接组合式API代码
<template>
<div>
<h1>{{ title }}</h1>
</div>
</template>
<script setup>
import { ref } from 'vue'
const title = ref("组件标题")
</script>
<style scoped>
</style>
2.ref()和reactive()
- 官方推荐使用ref()函数来声明响应式状态,可以传入支持传入简单数据和引用类型的数据,返回一个数据代理对象。通过对象的value属性读取数值(再模版中使用时可以忽略value属性)
<h2>{{title}}</h2>
<h3>{{person.name}} - {{person.age}}</h3>
const title = ref('实例2')
const person = ref({
name:"张三", age: 20
})
- Ref 会使它的值具有深层响应性,传入对象或者数组这种应用类型的数据时,修改对象属性或者数组子元素都可以触发视图更新
const person = ref({
name:"张三", age: 20
})
const list = ref([1,2,3])
function modifyTitle(){
//在 JavaScript 中需要 .value
person.value.age++
list.value[0] = 5
}
- reactive() 返回的是一个原始对象的 Proxy,所以他只接受对象类型的数据 (对象、数组和如 Map、Set 这样的集合类型),通过他创建的数据访问时无需通过value属性
const person2 = reactive({
name:"李四", age: 18
})
const list = reactive([1,2,3])
function modifyTitle(){
person2.age++
list[0] = 5
}
- ref和reactive底层都是调用Proxy()来创建响应式数据,因为Proxy()不支持简单数据,所以ref会对传入的数据用对象进行包裹,用value来存放传入原数据,这样再调用Proxy()就可以返回响应式数据,正因为多了一层包裹,所以他支持简单数据类型而reactive不支持,也正因为如此,所以ref返回的数据需要用value进行操作
- 打印对象:
const title = ref('实例2')
const person = ref({
name:"张三", age: 20
})
const list = reactive({
name:"张三", age: 20
})
- 嵌套调用:当ref嵌套到reactive内部使用时,会涉及到ref的解包机制,平时估计用不上,使用时再查看文档
3.计算属性 computed
<body>
<div id="app" v-cloak>
<div class="form-group">
<label>姓:</label>
<input type="text" v-model="person.firstName" class="form-control" placeholder="请输入姓">
</div>
<div class="form-group">
<label>名:</label>
<input type="text" v-model="person.lastName" class="form-control" placeholder="请输入名">
</div>
<div class="form-group">
<label>姓名:</label>
<h2>{{fullName}}</h2>
</div>
</div>
</body>
<script>
//组合式(解构赋值)
const {createApp, ref, reactive,computed} = Vue
var app = Vue.createApp({
//所有的代码写入到steup方法中
setup(){
const person = ref({
firstName: "",
lastName: ""
})
const fullName = computed(()=>{
return person.value.firstName + person.value.lastName
})
//返回定义的数据和方法
return {
person,
fullName
}
}
})
app.mount('#app')
</script>
4.监听器 watch
- 通过watch()来监听数据变化,并执行对应的回调,参数一为需要监听的响应式数据(同时监听多个数据用数组进行包裹),参数二为需要执行的回调函数
<body>
<div id="app" v-cloak>
<input type="text" v-model="title">
</div>
</body>
<script>
//组合式(解构赋值)
const {createApp, ref, reactive,watch} = Vue
var app = Vue.createApp({
//所有的代码写入到steup方法中
setup(){
const title = ref("测试")
//注册监听器
watch(title,(newValue, oldValue)=>{
console.log('title发送变化,最新值为',title.value)
})
//返回定义的数据和方法
return {
title
}
}
})
app.mount('#app')
</script>
- 深度监听:如果监听对象是复杂类型的数据,例如对象,默认不会监听其内部的变化,需要配置deep->true
//注册监听器
watch(person,(newValue, oldValue)=>{
console.log('person发生变化,最新值为',person.value)
},{
deep: true
})
//监听内部某个属性
watch(()=> person.value.age,(newValue, oldValue)=>{
console.log('person.age发生变化,最新值为',person.value.age)
})
- 其他配置:一次性监听(once: true),即时回调(immediate: true),触发时机(flush: 'post'->Dom更新后,flush: 'sync'->Dom更新前,默认)
- watchEffect(): 和计算属性类似,自动识别回调中的依赖对象作为监听,发生改变则触发回调,传入的回调会立即执行一次
<body>
<div id="app" v-cloak>
<input type="text" v-model="name">
<input type="number" v-model="age">
</div>
</body>
<script>
//组合式(解构赋值)
const {createApp, ref, reactive,watchEffect} = Vue
var app = Vue.createApp({
//所有的代码写入到steup方法中
setup(){
const name = ref("张三")
const age = ref(20)
//注册监听器
watchEffect(()=>{
var person = {name: name.value,age:age.value}
console.log('person发生变化',name.value,age.value)
})
//返回定义的数据和方法
return {
name,age
}
}
})
app.mount('#app')
</script>
5.组件数据交互
- 父->子:通过defineProps()方法来定义要接收的参数,这些定义的参数就可以使用了,提供数组语法和对象语法(二选一)
<script setup lang="ts">
//声明要接收的字段,(数组语法,提供属性名即可)
//defineProps(['msg','num'])
//声明要接收的字段,(对象语法,可以限制属性值的类型)
const props = defineProps({
msg: String,
num: Number
})
</script>
- 子->父:用法与vue2.x一致,不过在setup作用域中,需要使用 defineEmits() 对事件进行注册,然后使用返回的emit对象触发事件
<script setup lang="ts">
//声明自定义事件
const emit = defineEmits(['sayHello'])
//触发事件
const handleSayHello = ()=>{
emit('sayHello','someone')
}
</script>
- 父->后代:通过依赖注入的形式,让所有后代组件都可以访问父组件的数据
//全局提供,所有组件都可以使用
import { createApp } from 'vue'
const app = createApp({})
app.provide()
<script setup lang="ts">
//组件提供,只能给后代组件使用
import { ref, provide } from 'vue'
//将数据暴漏给后代组件(参数一:名称,参数二:值,可以是任意类型,包括响应式的状态)
provide('home_title',"Home title")
provide('sayHello',()=>{
console.log("sayHello define in Home")
})
const num = ref(100)
//暴漏ref
provide('home_num', num)
</script>
<script setup lang="ts">
//接收方
import { inject } from 'vue'
//接收祖先组件暴漏的数据(注入)
const home_title = inject('home_title')
const sayHello = inject('sayHello')
const home_num = inject('home_num')
console.log('home_title',home_title)
console.log('sayHello',sayHello)
console.log('home_num',home_num)
//不确定,或者不存在的值给个默认值
const _unknown = inject('_unknown',null)
console.log('_unknown',_unknown)
const setNum = () => {
//不推荐更改祖先数据,如果需要,最好让祖先组件暴漏一个转码修改数据的办法
home_num.value++
}
</script>
6.模版引用
- 通过ref访问Dom:给Dom挂载一个ref属性,值为ref(null)返回的对象,则可通过这个ref对象直接访问dom
<body>
<div id="app" v-cloak>
<h2 ref="h2">{{title}}</h2>
</div>
</body>
<script>
//组合式(解构赋值)
const {createApp, ref, reactive,onMounted} = Vue
var app = Vue.createApp({
//所有的代码写入到steup方法中
setup(){
const title = ref("测试")
const h2 = ref()
onMounted(()=>{
//onMounted 测试
console.log('onMounted',title.value)
console.log(h2.value)
})
//返回定义的数据和方法
return {
title,h2
}
}
})
app.mount('#app')
</script>
- 在使用了 script setup 的组件是默认私有的,一个父组件无法访问到一个使用了 script setup 的子组件中的任何东西,除非子组件在其中通过 defineExpose 宏显式暴露
<script setup>
import { ref } from 'vue'
const a = 1
const b = ref(2)
// 像 defineExpose 这样的编译器宏不需要导入
defineExpose({
a,
b
})
</script>
7.生命周期
- 通过暴漏出来的API,传入生命周期函数,在不同阶段执行对应的代码
<script>
//组合式(解构赋值)
const {createApp, ref, reactive,onMounted} = Vue
var app = Vue.createApp({
//所有的代码写入到steup方法中
setup(){
const title = ref("测试")
onMounted(()=>{
//onMounted 测试
console.log('onMounted',title.value)
})
//返回定义的数据和方法
return {
title,
}
}
})
app.mount('#app')
</script>
- steup执行时机早于beforeCreate,他能用的生命周期API如下
生命周期钩子 |
说明 |
onBeforeMount() |
在组件被挂载之前被调用,此时无法操作Dom |
onMounted() |
在组件挂载完成后执行 |
onBeforeUpdate() |
在组件即将因为响应式状态变更而更新其 DOM 树之前调用 |
onUpdated() |
在组件因为响应式状态变更而更新其 DOM 树之后调用 |
onBeforeUnmount() |
在组件实例被卸载之前调用 |
onUnmounted() |
在组件实例被卸载之后调用 |