目录
Vue3核心语法
OptionsAPI 与 CompositionAPI
setup函数
setup 概述
setup 语法糖
ref 创建:基本类型的响应式数据
reactive 创建:对象类型的响应式数据
ref 创建:对象类型的响应式数据
ref 对比 reactive
toRefs 与 toRef
computed
watch
情况一:监视 ref 定义的基本类型数据
情况二:监视 ref 定义的对象类型数据
情况三:监视 reactive 定义的对象类型数据
情况四:监视 ref 或 reactive 定义的对象类型数据中的某个属性
情况五:监视多个数据
watchEffect
标签的 ref 属性
props
Vue3核心语法
OptionsAPI 与 CompositionAPI
Vue.js 是一个流行的前端 JavaScript 框架,它提供了两种不同的 API 风格来编写组件:Options (选项式)API 和 Composition(组合式) API。
1、Options API:
Options API 是 Vue.js 最初提供的 API 风格。在 Options API 中,你通过创建一个包含不同属性的对象来定义组件。这些属性可以包括 data、methods、computed、watch、props 等。每个属性都有其特定的作用,比如 data 用于定义组件的数据,methods 用于定义组件的方法,computed 用于定义计算属性等。
// Options API 示例
export default {
data() {
return {
message: 'Hello, Vue!'
};
},
methods: {
greet() {
alert(this.message);
}
}
};
2、Composition API:
Composition API 是 Vue.js 3.0 引入的新的 API 风格。与 Options API 不同,Composition API 允许你使用函数来组织你的代码,而不是将所有相关逻辑分散在不同的选项中。使用 Composition API,你可以将相关代码放在一起,并且可以更灵活地重用逻辑。
// Composition API 示例
import { ref, computed } from 'vue';
export default {
setup() {
const message = ref('Hello, Vue!');
function greet() {
alert(message.value);
}
return {
message,
greet
};
}
};
主要区别:
- Options API 更适合小型应用程序或者对 Vue.js 不太熟悉的开发者,因为它的语法更直观,易于理解。
- Composition API 更适合复杂的组件或者大型应用程序,因为它更灵活,更容易组织和重用代码。
setup函数
setup 概述
setup 函数是 Vue 3 中的一个新的配置项,它是 Composition API 的入口点,用于配置组件内部所需的数据、方法、计算属性、监视等逻辑。
以下是关于 setup 函数的概述:
- 新配置项:setup 是 Vue 3 中新增加的配置项,与 Options API 中的 data、methods 等相对应,用于组织组件内部的逻辑。
- 函数返回值:setup 函数返回一个对象,对象中包含了组件内部所需的数据、方法、计算属性等,这些内容可以直接在模板中使用。
- 访问 this:在 setup 函数内部,无法直接访问 this,因为在 setup 执行时,组件实例尚未创建,this 是 undefined。取而代之的是通过参数来获取组件的属性和上下文信息。
- 执行时机:setup 函数会在组件实例创建之前调用,在 beforeCreate 生命周期钩子之前执行。因此,它是组件内部逻辑配置的第一个入口点。
- 功能扩展:setup 函数为 Vue 3 提供了更灵活的组件逻辑配置方式,使得代码更易于组织、重用,特别适用于复杂组件或大型应用程序的开发。
总的来说,setup 函数作为 Composition API 的入口点,为 Vue 3 的组件开发提供了更强大的能力和更清晰的代码结构,使得开发者可以更好地管理组件内部的状态和行为。
setup 语法糖
在 Vue 3 中,有一种称为“语法糖”的特性,可以简化使用 setup 函数的过程,这就是 <script setup> 语法糖。
使用 <script setup> 语法糖可以更简洁地定义组件,并且无需显式地编写 setup 函数。Vue 会自动将你的代码转换为等效的 setup 函数形式。
代码如下:
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">年龄+1</button>
<button @click="showTel">点我查看联系方式</button>
</div>
</template>
<script lang="ts">
export default {
name: "Preson",
};
</script>
<script setup lang="ts">
import { ref } from 'vue';
const name = ref('张三');
const age = ref(18);
const tel = '1234567890';
function changeName() {
name.value = '李四';
}
function changeAge() {
age.value +=1;
}
function showTel() {
alert(tel)
}
</script>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
扩展:上述代码,还需要编写一个不写`setup`的`script`标签,去指定组件名字,比较麻烦,我们可以借助`vite`中的插件简化
第一步:npm i vite-plugin-vue-setup-extend -D
第二步:打开vite.config.ts
import { defineConfig } from 'vite'
import VueSetupExtend from 'vite-plugin-vue-setup-extend'
export default defineConfig({
plugins: [ VueSetupExtend() ]
})
第三步:<script setup lang="ts" name="Person">
ref 创建:基本类型的响应式数据
1、作用: 定义响应式变量,这意味着当变量的值发生变化时,相关的视图会自动更新。
2、语法: 使用 let xxx = ref(初始值) 来创建一个响应式变量,其中 xxx 是变量名,初始值 是变量的初始值。
3、返回值: ref 函数返回一个 RefImpl 实例对象,简称为 ref对象 或 ref。该对象具有一个 value 属性,该属性是响应式的,即当 value 发生变化时,相关的视图会进行更新。
4、注意点:
- 在 JavaScript 中,操作响应式数据时需要使用 xxx.value,但在模板中不需要加 .value,直接使用变量名即可。
- 举例来说,如果有 let name = ref('张三') 这样的语句,name 不是响应式的,而 name.value 是响应式的。
扩展一下:推荐一个vscode的一个设置,设置后vscode会自动帮你.value
第一步:打开vscode的设置
第二步:点击扩展,找到volar
第三步:将下图的选项勾选上
例子:
<template>
<div class="person">
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<h2>性别: {{ sex }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">年龄+1</button>
<button @click="sex = '女'">修改性别</button>
</div>
</template>
<script setup lang="ts" name ="Preson">
import { ref } from 'vue';
const name = ref('张三');
const age = ref(18);
const sex = ref('男');
function changeName() {
name.value = '李四';
}
function changeAge() {
age.value +=1;
}
</script>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
reactive 创建:对象类型的响应式数据
1、作用: reactive 函数用于定义一个响应式对象,即当对象的属性发生变化时,相关的视图会自动更新。需要注意的是,应该将 reactive 用于对象类型的数据,而不是基本类型的数据,对于基本类型的数据应该使用 ref。
2、语法: 使用 let 响应式对象 = reactive(源对象) 来创建一个响应式对象,其中 响应式对象 是你想要创建的响应式对象的变量名,源对象 是你想要转换为响应式对象的普通 JavaScript 对象。
3、返回值: reactive 函数返回一个 Proxy 的实例对象,这个实例对象就是我们所说的响应式对象,它会拦截对对象的操作,使得这些操作变得响应式。
4、注意点: 使用 reactive 定义的响应式数据是“深层次”的,这意味着如果对象的嵌套属性发生变化,相关的视图也会更新。
例子:
<template>
<div class="person">
<h2>学生信息</h2>
<p>姓名:{{ student.name }}</p>
<p>年龄:{{ student.age }}</p>
<p>性别:{{ student.gender }}</p>
<button @click="changeInfo">修改信息</button>
</div>
</template>
<script setup lang="ts" name ="Preson">
import { reactive } from 'vue';
// 定义一个普通的 JavaScript 对象
const normalStudent = {
name: '张三',
age: 20,
gender: '男'
};
// 使用 reactive 函数将普通对象转换为响应式对象
const student = reactive(normalStudent);
// 修改学生信息的方法
function changeInfo() {
// 修改响应式对象的属性
student.name = '李四';
student.age += 1;
student.gender = '女';
}
</script>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
ref 创建:对象类型的响应式数据
在 Vue 中,ref 函数不仅可以用于创建基本类型的响应式数据,还可以用于创建对象类型的响应式数据。实际上,如果将对象传递给 ref 函数,内部会自动调用 reactive 函数来将对象转换为响应式对象。
这种用法的好处是,无需手动调用 reactive 函数,而是直接使用 ref 函数来统一管理基本类型和对象类型的响应式数据。
例子:
<template>
<div class="person">
<h2>学生信息</h2>
<p>姓名:{{ student.name }}</p>
<p>年龄:{{ student.age }}</p>
<p>性别:{{ student.gender }}</p>
<button @click="changeInfo">修改信息</button>
</div>
</template>
<script setup lang="ts" name ="Preson">
import { ref } from 'vue';
// 使用 ref 函数创建对象类型的响应式数据
const student = ref({
name: '张三',
age: 20,
gender: '男'
});
// 修改学生信息的方法
function changeInfo() {
// 通过 ref 的 .value 属性修改对象的属性
student.value.name = '李四';
student.value.age += 1;
student.value.gender = '女';
}
</script>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
ref 对比 reactive
用途:
- ref 用于定义基本类型数据和对象类型数据。
- reactive 用于定义对象类型数据。
区别:
- 使用 ref 创建的变量,在访问其值时必须使用 .value,而 reactive 创建的变量不需要。
- 当重新分配一个新对象给 reactive 创建的变量时,会失去响应式,但可以使用 Object.assign 进行整体替换。
使用原则:
- 如果需要一个基本类型的响应式数据,必须使用 ref。
- 如果需要一个响应式对象,且层级不深,ref 和 reactive 都可以使用。
- 如果需要一个响应式对象,且层级较深,推荐使用 reactive。
总的来说,ref 更适合用于管理基本类型的响应式数据以及浅层次的对象类型数据,而 reactive 则更适合用于管理深层次的对象类型数据。
toRefs 与 toRef
toRefs 和 toRef 是 Vue 3 提供的两个工具函数,用于处理响应式对象和 ref 对象之间的转换。
toRefs
- 作用: 将一个响应式对象中的每一个属性,转换为 ref 对象。
- 备注: toRefs 可以批量转换多个属性。
toRef
- 作用: 将一个响应式对象的指定属性,转换为单独的 ref 对象。
- 备注: toRef 用于单个属性的转换。
比较
- toRefs 能够将整个响应式对象的所有属性都转换为 ref 对象,返回一个包含了所有属性的对象。
- toRef 则是将一个响应式对象的指定属性转换为 ref 对象。
使用时,如果需要批量转换多个属性,可以使用 toRefs;如果只需要转换一个属性,可以使用 toRef。
例子:
<template>
<div class="person">
<p>计算: {{ state.count }}</p>
<p>名字: {{ state.name }}</p>
<button @click="increment">增加</button>
<button @click="changeName">修改名字</button>
<button @click="resetCount">重置</button>
</div>
</template>
<script setup lang="ts" name ="Preson">
import { reactive, toRefs, toRef } from 'vue';
// 定义一个响应式对象
const state = reactive({
count: 0,
name: '张三'
});
// 使用 toRefs 将响应式对象的所有属性转换为 ref 对象
const stateRefs = toRefs(state);
// 使用 toRef 将响应式对象的 count 属性转换为单独的 ref 对象
const countRef = toRef(state, 'count');
// 修改 count 的方法
function increment() {
stateRefs.count.value++;
}
// 修改 name 的方法
function changeName() {
stateRefs.name.value = '李四';
}
// 重置 count 的方法
function resetCount() {
countRef.value = 0;
}
</script>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
computed
computed 是 Vue.js 中的一个计算属性(和`Vue2`中的`computed`作用一致),它可以根据响应式数据动态计算出一个新的值,并且在依赖的响应式数据发生变化时自动更新。
例子:
<template>
<div class="person">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
全名:<span>{{ fullName }}</span> <br>
<button @click="changeFullName">全名改为:li-si</button>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
// 使用 ref 创建响应式数据
const firstName = ref('张');
const lastName = ref('三');
// 使用 computed 创建计算属性
const fullName = computed({
// 读取
get(){
return firstName.value + '-' + lastName.value
},
// 修改
set(val){
firstName.value = val.split('-')[0]
lastName.value = val.split('-')[1]
}
})
// 修改全名的方法
function changeFullName() {
// 计算属性 fullName 是只读的,无法直接修改
// 如果需要修改全名,可以直接操作 firstName 和 lastName
firstName.value = '李';
lastName.value = '四';
}
</script>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
watch
watch 在 Vue 3 中用于监视数据的变化,其功能与 Vue 2 中的 watch 类似。在 Vue 3 中,watch 只能监视四种类型的数据:ref 定义的数据、reactive 定义的数据、函数返回的值、以及一个包含上述内容的数组。下面是几种常见的使用情况:
情况一:监视 ref 定义的基本类型数据
监视 ref 定义的【基本类型】数据:直接写数据名即可,监视的是其`value`值的改变。
import { ref, watch } from 'vue';
const count = ref(0);
watch(count, (newValue, oldValue) => {
console.log('count 值发生变化:', newValue, oldValue);
});
情况二:监视 ref 定义的对象类型数据
监视 ref 定义的【对象类型】数据:直接写数据名,监视的是对象的【地址值】,若想监视对象内部的数据,要手动开启深度监视(deep: true)。
注意:
- 若修改的是`ref`定义的对象中的属性,`newValue` 和 `oldValue` 都是新值,因为它们是同一个对象。
- 若修改整个`ref`定义的对象,`newValue` 是新值, `oldValue` 是旧值,因为不是同一个对象了。
import { ref, watch } from 'vue';
const person = ref({ name: 'John', age: 30 });
// 监视对象的地址值
watch(person, (newValue, oldValue) => {
console.log('person 对象的地址值发生变化:', newValue, oldValue);
});
// 监视对象内部属性的变化,手动开启深度监视
watch(person, (newValue, oldValue) => {
console.log('person 对象内部属性发生变化:', newValue, oldValue);
}, { deep: true });
情况三:监视 reactive 定义的对象类型数据
监视 reactive 定义的【对象类型】数据,且默认开启了深度监视。
import { reactive, watch } from 'vue';
const person = reactive({ name: 'John', age: 30 });
// 默认开启了深度监视
watch(person, (newValue, oldValue) => {
console.log('person 对象的地址值发生变化:', newValue, oldValue);
});
情况四:监视 ref 或 reactive 定义的对象类型数据中的某个属性
监视 ref 或 reactive 定义的【对象类型】数据中的 某个属性,注意点如下:
1. 若该属性值不是【对象类型】,需要写成函数形式。
2. 若该属性值是依然是【对象类型】,可直接编,也可写成函数,建议写成函数。
结论:监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视(deep: true)。
import { ref, reactive, watch } from 'vue';
const person = ref({ name: 'John', age: 30 });
// 监视属性值不是对象类型,写成函数形式
watch(() => person.value.age, (newValue, oldValue) => {
console.log('person 对象的 age 属性发生变化:', newValue, oldValue);
});
// 监视属性值仍然是对象类型,可直接编,也可写成函数,建议写成函数
watch(person.value, (newValue, oldValue) => {
console.log('person 对象内部属性发生变化:', newValue, oldValue);
});
// 或者使用深度监视
watch(person, (newValue, oldValue) => {
console.log('person 对象内部属性发生变化:', newValue, oldValue);
}, { deep: true });
情况五:监视多个数据
import { ref, watch } from 'vue';
const count = ref(0);
const name = ref('John');
watch([count, name], ([countValue, nameValue], [oldCountValue, oldNameValue]) => {
console.log('count 和 name 值发生变化:', countValue, nameValue, oldCountValue, oldNameValue);
});
watchEffect
watchEffect 是 Vue 3 中引入的一个新的 API,用于在 Vue 组件中执行副作用代码,并自动追踪其依赖。与 watch 监视特定的响应式数据不同,watchEffect 会自动追踪函数内部使用的响应式数据,并在这些数据发生变化时重新执行函数。
下面是对比 watch 和 watchEffect 的几个关键点:
数据监听方式:
- watch 需要明确指定要监视的响应式数据,当这些数据发生变化时执行回调函数。
- watchEffect 则是自动追踪函数内部使用的响应式数据,无需显式指定要监视的数据,只要函数内部使用了响应式数据,它就会被自动追踪。
参数:
- watch 的第一个参数是要监视的数据,第二个参数是回调函数,回调函数接收新值和旧值。
- watchEffect 接收一个函数作为唯一参数,该函数内部可以访问任何响应式数据,当这些数据变化时,函数会被重新执行。
灵活性:
- watch 在需要监视多个数据或执行一些特定逻辑时更为灵活,因为它可以手动指定要监视的数据,并在数据变化时执行特定的逻辑。
- watchEffect 更适合于简单的副作用场景,不需要手动指定监视的数据,只需编写一个函数,函数内部使用的响应式数据会被自动追踪,当数据变化时函数会被重新执行。
总的来说,watch 更适合于需要精确控制监视逻辑的情况,而 watchEffect 更适合于简单的副作用场景,可以减少编写重复代码的工作量。
示例
<template>
<div class="person">
<p>计算: {{ count }}</p>
<p>双重计算: {{ doubleCount }}</p>
<button @click="increment">增加</button>
</div>
</template>
<script lang="ts" setup name="Person">
import { ref, watch, watchEffect, computed } from 'vue';
const count = ref(0);
// 使用 watch 监听 count 的变化
watch(count, (newCount, oldCount) => {
console.log(`计算从 ${oldCount} 更换到 ${newCount}`);
});
// 使用 watchEffect 自动追踪 count 的变化
watchEffect(() => {
console.log(`watchEffect的计算: ${count.value}`);
});
const doubleCount = computed(() => count.value * 2);
const increment = () => {
count.value++;
};
</script>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
标签的 ref 属性
ref 属性在 Vue 中用于注册模板引用,它的作用是用来获取对应的 DOM 节点或组件实例对象。
- 当 ref 属性用在普通 DOM 标签上时,通过引用可以获取到对应的 DOM 节点。这使得我们可以在 Vue 组件中直接操作 DOM,比如修改样式、获取或设置属性等。
- 当 ref 属性用在组件标签上时,通过引用可以获取到对应的组件实例对象。这允许我们在父组件中直接调用子组件的方法、访问子组件的属性,或者对子组件进行一些操作。
下面是一个简单的示例,演示了 ref 属性在普通 DOM 标签和组件标签上的用法:
<template>
<Preson ref="ren"/>
<h2 ref="title2">我是App组件</h2>
<button @click="showLog">点我打印内容</button>
</template>
<script lang="ts" setup name="App">
import { ref } from 'vue';
import Preson from './components/Preson.vue';
let title2 = ref();
let ren = ref();
let showLog = () => {
console.log(title2.value);
console.log(ren.value)
}
</script>
<style scoped>
</style>
<template>
<div class="person">
<h1 ref="title1">后端</h1>
<h2 ref="title2">前端</h2>
<h3 ref="title3">Vue</h3>
<input type="text" ref="inpt"> <br><br>
<button @click="showLog">点我打印内容</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {ref} from 'vue'
let title1 = ref();
let title2 = ref();
let title3 = ref();
let inpt = ref();
let showLog = () => {
console.log(title1.value);
console.log(title2.value);
console.log(title3.value);
console.log(inpt.value);
console.log(inpt.value.value);
}
let name = ref('张三')
let age = ref(18)
defineExpose({name, age})
</script>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>
props
props 是 Vue 中用于从父组件向子组件传递数据的一种机制。通过 props,父组件可以向子组件传递任意类型的数据,包括基本数据类型、对象、数组等。
在 Vue 中,当一个组件被创建时,它可能需要接收来自父组件的数据。这些数据通过 props 属性定义在子组件中,然后由父组件通过绑定在子组件标签上的属性来传递。
定义个index.ts
// 定义一个接口,限制每个Person对象的格式
export interface PersonInter {
id?: string;
name?: string;
age?: number;
}
// 定义一个自定义类型Persons
export type Persons = Array<PersonInter>;
<template>
<Person :list="personList"/>
</template>
<script lang="ts" setup name="App">
import Person from './components/Preson.vue';
import { reactive } from 'vue';
import {type Persons} from '@/types';
let personList = reactive<Persons>([
{ id: '001', name: '张三', age: 18 },
{ id: '002', name: '李四', age: 19 },
{ id: '003', name: '王五', age: 20 }
])
</script>
<style scoped>
</style>
<template>
<div class="person">
<ul>
<li v-for="item in list" :key="item.id">
{{ item.name }}--{{ item.age }}
</li>
</ul>
</div>
</template>
<script lang="ts" setup name="Person">
import { type Persons } from '@/types'
// 只接收list
// defineProps(['list'])
// 接收list + 限制类型
// defineProps<{list:Persons}>()
// 接收list + 限制类型 + 限制必要性 + 指定默认值(当父组件不传值才启用)
withDefaults(defineProps<{ list?: Persons }>(), {
list: () => [{ id: 'ausydgyu01', name: '康师傅·王麻子·特仑苏', age: 19 }]
})
</script>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
button {
margin: 0 5px;
}
</style>