安装
- 下载脚手架 npm install -g @vue/cli
- 创建项目 vue create vue3-test
- 项目根目录创建 vue.config.js 并进行配置
module.exports = {
lintOnSave: false, // 关闭语法检查避免折磨
}
常用的 Composition (组合式) API
setup函数
- 可以把所有的组合式API放到 setup 函数中去
- 组件中使用的数据、方法等都可以配置在 setup 函数中
- setup 函数如果返回一个对象,则对象中的属性、方法都可以在模板中使用
<template>
<h1>我是APP组件</h1>
<p>{{name}} --- {{age}}</p>
<button @click="sayName">btn</button>
</template>
<script>
export default {
name: 'App',
setup() {
// 数据
let name = 'zs'
let age = 18
// 方法
function sayName() {
alert(`我叫${name}, 今年${age}岁`)
}
return {
name,
age,
sayName,
}
}
}
</script>
- setup 如果返回一个渲染函数,则可以自定义渲染内容
- setup 函数内部 this 是 undefined
- setup 函数不能是一个 async 函数,因为 async 函数会将返回值包装成一个 promise
- setup 是在 beforeCreate 之前执行的
- setup 接收2个参数 props 和 context 上下文对象
- props 值为对象,组件外部传递过来的且组件内部声明接收了的属性
- context 上下文对象,其中有3个属性。 attrs 值为对象,组件外部传递过来的数据没有接收,相当于 this.$attrs 。 slots 收到的插槽内容,相当于 this.$slots 。 emit 分发自定义事件的函数,相当于 this.$emit
ref函数
- ref 函数主要的作用是给 基本类型数据 添加响应式功能
- ref 函数的返回值是一个 RefImpl 对象 (reference implement 引用实现对象),通过该对象的 value 属性可以取到值,在模块中使用数据不用写 value 属性取值, vue 会自动帮我们调用 value 取值
- ref 函数内部通过 Object.definePropty 函数实现响应式功能
<template>
<h1>我是APP组件</h1>
<p>{{name}} --- {{age}}</p>
<button @click="changeInfo">修改人的信息</button>
</template>
<script>
import {ref} from 'vue'
export default {
name: 'App',
setup() {
// 数据
let name = ref('zs') // 通过ref函数添加响应功能
let age = ref(18)
// 方法
function changeInfo() {
name.value = 'ls'
age.value = 66
console.log(name, age)
}
return {
name,
age,
changeInfo,
}
}
}
</script>
- 也可以传递对象给 ref 函数, ref 函数内部通过 reactive 函数实现响应式
<template>
<h1>我是APP组件</h1>
<p>{{name}} --- {{age}}</p>
<p>{{job.type}} --- {{job.salary}}</p>
<button @click="changeInfo">修改人的信息</button>
</template>
<script>
import {ref} from 'vue'
export default {
name: 'App',
setup() {
// 数据
let name = ref('zs')
let age = ref(18)
let job = ref({ // ref 函数也可以给对象类型数据添加响应式
type: '前端',
salary: '3000块'
})
// 方法
function changeInfo() {
name.value = 'ls'
age.value = 66
job.value.type = 'web前端'
job.value.salary = '3100块'
}
return {
name,
age,
job,
changeInfo,
}
}
}
</script>
reactive函数
- 将对象变成响应式数据,内部通过 ES6 的 proxy 实现的
- reactive 函数将对象添加为响应式数据,在使用的过程中不需要 .value 来取值
<template>
<h1>我是APP组件</h1>
<p>{{name}} --- {{age}}</p>
<p>{{job.type}} --- {{job.salary}}</p>
<button @click="changeInfo">修改人的信息</button>
</template>
<script>
import {ref, reactive} from 'vue'
export default {
name: 'App',
setup() {
// 数据
let name = ref('zs')
let age = ref(18)
let job = reactive({ // reactive定义的响应式数据可以直接使用(无必通过 .value 取值)
type: '前端',
salary: '3000块'
})
// 方法
function changeInfo() {
name.value = 'ls'
age.value = 66
job.type = 'web前端'
job.salary = '3200块'
}
return {
name,
age,
job,
changeInfo,
}
}
}
</script>
- ref 用来定义基本类型的数据,定义复杂类型的数据内部借助了 reactive 。 reactive 只能定义复杂类型的数据
- ref 通过 Object.defineProperty() 的 get 和 set 来实现响应式。 reactive 通过 Proxy 来实现响应式,并通过 Reflect 操作源对象内部的数据
- ref 操作数据需要 .value ,模板使用数据则不用 .value 。 reactive 操作数据和读取均不用 .value
computed 函数
- 与 vue2 中的计算属性配置一样,可以接收一个回调函数(仅使用计算属性的 get 方法),也可以接收一个配置对象(内含 get / set 方法)
<template>
<div>姓:<input type="text" v-model="person.firstName"></div>
<div>名:<input type="text" v-model="person.lastName"></div>
<span>全名:{{fullName}}</span>
<div>全名:<input type="text" v-model="fullName"></div>
</template>
<script>
import {reactive, computed, } from 'vue'
export default {
name: 'Demo',
setup() {
// 数据
let person = reactive({
firstName: '张',
lastName: '三'
})
// 计算属性 (简写没有考虑计算属性的set)
// let fullName = computed(() => {
// return person.firstName + '-' + person.lastName
// })
// 计算属性
let fullName = computed({
get() {
return person.firstName + '-' + person.lastName
},
set(newValue) {
const [firstName, lastName] = newValue.split('-')
person.firstName = firstName
person.lastName = lastName
}
})
return {
person,
fullName,
}
}
}
</script>
watch函数
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">自增</button>
</template>
<script>
import {ref, watch, } from "vue";
export default {
name: 'Demo',
setup() {
let sum = ref(0)
// 监听
watch(sum, (newValue, oldValue) => {
console.log(`sum的值发生了改变以前的值是${oldValue} 现在的值是${newValue}`);
})
return {
sum
}
}
}
</script>
- 当 watch 的第一个参数发生变化后,会自动执行第二个参数的回调函数
- 监听多个 ref 所定义的数据
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="sum++">自增</button>
<h2>当前信息为 {{msg}}</h2>
<button @click="msg+= '!'">修改信息</button>
</template>
<script>
import {ref, watch, } from "vue";
export default {
name: 'Demo',
setup() {
let sum = ref(0)
let msg = ref('一个消息')
// 监听多个ref定义的数据
watch([sum, msg], (newValue, oldValue) => {
console.log(`以前的数据`, oldValue) //以前的数据 [sum, msg]
console.log(`现在的数据`, newValue)
}, {
immediate: true, // 立即执行一次监听
})
return {
sum,
msg,
}
}
}
</script>
- watch 函数的第三个参数可以配置 immediate: true 表示立即执行一次监听
- 使用 watch 监听 reactive 定义的数据
<template>
<div>{{person.name}} --- {{person.age}} ---- {{person.job.j1.salary}}</div>
<div>
<button @click="person.name+='~'">修改姓名</button>
<button @click="person.age++">增加年龄</button>
<button @click="person.job.j1.salary++">增加工资</button>
</div>
</template>
<script>
import {reactive, watch} from 'vue'
export default {
name: 'Demo',
setup() {
let person = reactive({
name: '张三',
age: 18,
job: {
j1: {
salary: 666
}
}
})
// 监视reactive所定义的数据
watch(person, (newValue, oldValue) => {
console.log(`以前的数据`, oldValue); // 无法正确获取oldValue
console.log(`现在的数据`, newValue);
}, {
deep: false, // 配置深度监听无效(默认是深度监听)
})
return {
person
}
}
}
</script>
- 这块有2个问题,无法正确获取 oldValue 以前的旧值,配置深度监听无效(默认是开启深度监听)
- 使用 watch 监听 reactive 定义的数据中的某一个属性的变化
<template>
<div>{{person.name}} --- {{person.age}} ---- {{person.job.j1.salary}}</div>
<div>
<button @click="person.name+='~'">修改姓名</button>
<button @click="person.age++">增加年龄</button>
<button @click="person.job.j1.salary++">增加工资</button>
</div>
</template>
<script>
import {reactive, watch} from 'vue'
export default {
name: 'Demo',
setup() {
let person = reactive({
name: '张三',
age: 18,
job: {
j1: {
salary: 666
}
}
})
// 监视reactive所定义的数据
watch(() => person.age, (newValue, oldValue) => {
console.log(`以前的年龄是`, oldValue)
console.log(`现在的年龄是`, newValue)
}, {
deep: false, // 配置深度监听无效(默认是深度监听)
})
return {
person
}
}
}
</script>
- 监听 reactive 定义的数据中的某一个属性变化时, watch 函数的第一个参数需要是函数并返回监听的内容
- 监听 reactive 定义的数据中的某一些属性的变化
<template>
<div>{{person.name}} --- {{person.age}} ---- {{person.job.j1.salary}}</div>
<div>
<button @click="person.name+='~'">修改姓名</button>
<button @click="person.age++">增加年龄</button>
<button @click="person.job.j1.salary++">增加工资</button>
</div>
</template>
<script>
import {reactive, watch} from 'vue'
export default {
name: 'Demo',
setup() {
let person = reactive({
name: '张三',
age: 18,
job: {
j1: {
salary: 666
}
}
})
// 监视reactive所定义的数据
watch([() => person.age, () => person.name], (newValue, oldValue) => {
console.log(`以前的年龄和姓名是`, oldValue)
console.log(`现在的年龄和姓名是`, newValue)
}, {
deep: false, // 配置深度监听无效(默认是深度监听)
})
return {
person
}
}
}
</script>
watchEffect 函数
- 监听的是回调函数中用到了哪些属性,如果回调中的属性发生了变化自动执行回调
<template>
<div>{{sum}}</div>
<button @click="sum++">自增</button>
</template>
<script>
import {ref, watchEffect, } from 'vue'
export default {
name: 'Demo',
setup() {
let sum = ref(0)
watchEffect(() => {
// 使用到了 ref 函数定义的 sum 变量
const x1 = sum.value; // 该sum变量发生改变立即执行该回调
console.log('watchEffect所指定的回调执行了', x1);
})
return {
sum,
}
}
}
</script>
- 立即执行传入的一个函数,同时响应式追踪其依赖,并在其依赖变更时重新运行该函数