文章目录
前言
- setup、ref、reactive、toRefs、computed、watch、props、watchEffect、hooks。
一、setup
1.定义
- 组合式API核心函数。它是组件逻辑的入口点,替代了vue2中的data,methods等分散的选项式API。
2.作用
- 在组件中可以写在script标签里面表示逻辑入口,自动返回值。
关键问题1:在setup中能否读到以前data选项或methods选项里面的数据?
不能,浅显的理解一下就是。因为setup没有维护this对象,无法调用。
关键问题2:在data选项或methods选项中可以读到setup中的数据?
可以,需要使用this进行调用。
setup示例:
export default {
name:'Person', // 组件名
// 1.setup能和methods data共存
// 2.data里面能不能读到setup里面的数据?
// >>可以,使用this.变量进行读取
// 3.但是setup不可以读到data里面的数据
// 4.setup是一个全新的配置项 它的优先级比vue2中的beforeCreate的优先级更高
// 5.它不存在this,没有维护this对象
setup(){
// 1.数据 ---> data选项
let name = '张三'
let age = 18
let tel = '1388888888'
// 2.方法
function changeName () {
// 注意:此时的数据不是响应式的
// 虽然改了但是页面不会有变化
name = 'zhang-san'
}
function changeAge () {
age += 1
}
function showTel () {
alert(tel)
}
// 2.通过返回值进行返回数据 可交可不交
return {
name,age,
changeName,changeAge,showTel
}
// return ()=>'哈哈' 直接返回 setup的返回值也可以是个渲染函数
}
}
语法糖:
- 可以直接写在script标签里,自动返回变量。以上的写法等价于下面的写法。
关键问题3:如果说需要自定义命名组件名需要单独设置,但是默认是与文件名一致。
关键问题4:如果说要想基本数据类型是响应式的,需要导入ref,将响应式数据用ref()框起来,需要在改变的时候使用.value进行修改。因为在标签里的变量返回值是一个RefImpl实例对象,也就是返回的数据用对象封装起来了,里面的数据就需要.value来进行调用。
<!-- 需要单独设置组件名的话可以在这里设置 就不使用插件了 -->
<script lang="ts">
export default {
name:'Person123', // 组件名
}
</script>
<script lang="ts" setup>
import {ref} from 'vue'
let name = ref('张三')
let age = ref(18)
let tel = '1388888888'
function changeName () {
name.value = 'zhang-san'
}
function changeAge () {
age.value += 1
}
function showTel () {
alert(tel)
}
</script>
3.响应式数据
1.ref
- ref是一个响应式的API,用于创建一个响应式的引用,通常用于响应式基本数据类型,也可以用于对象类型的响应。
- 使用的时候将需要响应式的数据导入ref,然后用ref()包裹起来,然后在需要进行修改的时候调用数据.value进行修改。以上示例已经展示了ref的基本数据类型响应。
- 返回的是一个Proxy代理对象。
ref对象类型响应:
<template>
<div class="car">
<h2>品牌:{{ car.brand }}</h2>
<h2>价格:{{ car.price }}</h2>
<ul>
<li v-for="c in cars" :key="c.name">车名:{{ c.name }},价格:{{ c.price }}</li>
</ul>
<button @click="changePrice">修改价格</button>
</div>
</template>
<script lang="ts">
export default {
name:'Car',
}
</script>
<script lang="ts" setup>
// 1.导入ref
import {ref} from 'vue'
// 2.用ref包裹起来
let car = ref({
brand:'保时捷',
price:100,
})
// 对象数组
let cars = ref([
{name:'奔驰',price:100},
{name:'法拉利',price:1000},
])
// 3.直接修改
function changePrice() {
car.value.price += 10
}
console.log(car)
</script>
<style scoped>
.car {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
.button {
margin: 0 5px;
}
</style>
- 它的外层使用ref包裹起来的,内部是reactive处理的。需要先用value读到对象后再进行操作才可以,包括ref里面包含了数组对象,需要用value去读到数组对象后在进行索引等其他操作。
<template>
<div class="car">
<h2>品牌:{{ car.brand }}</h2>
<h2>价格:{{ car.price }}</h2>
<ul>
<li v-for="c in cars" :key="c.name">车名:{{ c.name }},价格:{{ c.price }}</li>
</ul>
<button @click="changePrice">修改价格</button>
</div>
</template>
<script lang="ts">
export default {
name:'Car',
}
</script>
<script lang="ts" setup>
// 1.导入reactive
import {ref} from 'vue'
// 2.用ref包裹起来
let car = ref({
brand:'保时捷',
price:100,
})
// 对象数组
let cars = ref([
{name:'奔驰',price:100},
{name:'法拉利',price:1000},
])
// 3.直接修改
function changePrice() {
car.value.price += 10
}
console.log(car)
</script>
<style scoped>
.car {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
.button {
margin: 0 5px;
}
</style>
2.reactive
- reactive也是响应式API,只能用于创建一个响应式对象。
- 使用的时候需要导入reactive,然后用reactive包裹起来,然后直接修改即可。
返回的也是一个Proxy代理对象。
注意不用.value。
reactive响应对象类型:
<template>
<div class="car">
<h2>品牌:{{ car.brand }}</h2>
<h2>价格:{{ car.price }}</h2>
<button @click="changePrice">修改价格</button>
</div>
</template>
<script lang="ts" setup>
// 1.导入reactive
import {reactive} from 'vue'
// 2.用reactive包裹起来
let car = reactive({
brand:'保时捷',
price:100,
})
// 3.直接修改
function changePrice() {
// 4.不用加.value了
car.price += 10
}
</script>
<style scoped>
.car {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
.button {
margin: 0 5px;
}
</style>
3.ref与reactive的区别
区别1:ref用来生成响应式数据的时候,需要用.value来访问。
区别2:ref能够修饰基本类型、对象类型的响应式数据。
总结:基本类型用ref,层级不深的对象使用ref。
总结:层级深的使用reactive。
4.toRefs
作用:能够将reactive包裹的对象响应式数据解构,能够将它的每一个字段变成ref对象。
实质:将某个对象的字段结构,将该字段与对象里的字段变成一摸一样的数据,意思是调用toRefs后我们可以修改对象的字段了。
<template>
<div class="person">
<h2>{{ name }}</h2>
<h2>{{ age }}</h2>
<button @click="changeAge">修改年龄</button>
<button @click="changeName">修改名字</button>
</div>
</template>
<script lang="ts">
export default {
name:'ToRefs',
}
</script>
<script lang=ts setup>
import {ref,reactive,toRefs} from 'vue'
let person = reactive({
name:"kkk",
age:999,
})
let {name, age} = toRefs(person)
function changeName() {
name.value = name.value + "k"
}
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>
5.computed
定义:计算属性,基于响应式数据计算响应值。
使用:需要get和set方法。像jv里的getter和setter。
v-model:数据双向绑定。
const:明确声明不可变数据。
const [str1,str2] = val.split(‘’-‘’) :数组也能解构定义。
<template>
<div class="person">
姓:<input type="text" v-model="firstName"> <br>
名:<input type="text" v-model="lastName"> <br>
<!-- v-model 是 Vue 提供的双向数据绑定指令,主要用于 <input>、<select>、<textarea> 等表单元素,实现数据与视图的自动同步。 -->
全名:<span>{{ fullname }}</span> <br>
修改:<button @click="changeFullName"></button>
</div>
</template>
<script lang="ts">
export default {
name:"Compute",
}
</script>
<script setup lang="ts">
import {ref,reactive, computed} from 'vue'
let firstName = ref("jo")
let lastName = ref("ny")
// 变成一个可读可写的计算属性
let fullname = computed({
get(){
return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + "-" + lastName.value
},
set(val){
// 数组也能解构赋值
const [str1,str2] = val.split("-")
firstName.value = str1
lastName.value = str2
}
})
function changeFullName() {
fullname.value = "gy-ro"
}
</script>
<style scoped>
.person {
background-color: skyblue;
box-shadow: 0 0 10px;
border-radius: 10px;
padding: 20px;
}
.button {
margin: 0 5px;
}
</style>
二、Watch
- 它能够监视数据.。
注意1:需要监视的值不需要加.value,因为自动解包。
注意2:调用watch返回值是一个监视停止器,再次调用就会停止监视。
注意3:它只监视4种数据。函数返回值,ref、reactive和它们的数组。
1.监视ref:基本数据
<template>
<div class="person">
<h1>监视数据</h1>
<h1>当前数据求和为:{{ sum }}</h1>
<button @click="changeSum"></button>
</div>
</template>
<script lang="ts">
export default { // 实际上这里要缩进这个大括号一下才不会报错
name:"Watch",
}
</script>
<script lang="ts" setup>
import {ref, watch} from 'vue'
// 需要用ref或reactive包裹起来
let sum = ref(0)
function changeSum(){
sum.value += 1
}
// 监视
const stopWatch = watch(sum, (nv,ov)=>{
console.log("sum变化了", nv, ov)
if(nv >= 10) {
stopWatch() // 如果newValue大于等于10就停止监视 stopWatch()表示停止监视
}
})
</script>
2.监视ref:对象数据
- 监视用ref包裹的对象数据需要手动开启深度监视。
- 监视的是地址,整个对象,只有整个对象改变的时候才会触发监视器。
- 如果想要深度监视,需要手动添加深度监视。
- {immediate:true}:添加在深度监视后面。表示不管你改没改,先执行一次箭头函数。它提醒的是旧的引用,如果没改变,那就还是新的那个对象,已经改了。
- 实际上开发不管旧值。
参数1:被监视的数据。
参数2:监视的回调函数。
参数3:配置对象。
实质:改的是它的引用。
<template>
<div class="person">
<h1>情况二:监视【ref】定义的【对象类型】数据</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改整个人</button>
</div>
</template>
<script lang="ts">
export default {
name:"Watch2",
}
</script>
<script lang="ts" setup>
import {ref,watch} from 'vue'
// 数据
let person = ref({
name:'张三',
age:18,
})
// 方法
function changeName(){
person.value.name += '~'
}
function changeAge(){
person.value.age += 1
}
function changePerson(){
person.value = {name:'李四', age:90}
}
/*
监视,情况一:监视【ref】定义的【对象类型】数据,监视的是对象的地址值,若想监视对象内部属性的变化,需要手动开启深度监视
watch的第一个参数是:被监视的数据
watch的第二个参数是:监视的回调
watch的第三个参数是:配置对象(deep、immediate等等.....)
*/
watch(person,(nv,ov)=>{
console.log('person变化了',nv,ov)
}, {deep:true})
</script>
3.监视reactive:对象数据。
- 默认开启深度监视。且关不掉哦。
修改对象: Object.assign(person,{name:‘李四’,age:80})。
第一个参数是要改的对象,第二个参数是要改的内容。
实质:没改变原引用,只覆盖了值。
<template>
<div class="person">
<h1>情况三:监视【reactive】定义的【对象类型】数据</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changePerson">修改整个人</button>
<hr>
<h2>测试:{{obj.a.b.c}}</h2>
<button @click="test">修改obj.a.b.c</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {reactive,watch} from 'vue'
// 数据
let person = reactive({
name:'张三',
age:18
})
let obj = reactive({
a:{
b:{
c:666
}
}
})
// 方法
function changeName(){
person.name += '~'
}
function changeAge(){
person.age += 1
}
function changePerson(){
Object.assign(person,{name:'李四',age:80})
}
function test(){
obj.a.b.c = 888
}
// 监视,情况三:监视【reactive】定义的【对象类型】数据,且默认是开启深度监视的
watch(person,(nv,ov)=>{
console.log('person变化了',nv,ov)
})
watch(obj,(nv,ov)=>{
console.log('Obj变化了',nv,ov)
})
</script>
4.监视ref或reactive中某个属性
- 当我们直接修改的时候直接把原对象的地址改了,在watch传入的第一个参数传递的时候就要看地址到底是谁的,可能是原对象的可能是已经改了的。
- 总之一句话,如果我们只想监听对象的其中某个属性,将他写成箭头函数形式,并开启深度监听,记住就行。
<template>
<div class="person">
<h1>情况四:监视【ref】或【reactive】定义的【对象类型】数据中的某个属性</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<h2>汽车:{{ person.car.c1 }}、{{ person.car.c2 }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changeC1">修改第一台车</button>
<button @click="changeC2">修改第二台车</button>
<button @click="changeCar">修改整个车</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {reactive,watch} from 'vue'
// 数据
let person = reactive({
name:'张三',
age:18,
car:{
c1:'奔驰',
c2:'宝马'
}
})
// 方法
function changeName(){
person.name += '~'
}
function changeAge(){
person.age += 1
}
function changeC1(){
person.car.c1 = '奥迪'
}
function changeC2(){
person.car.c2 = '大众'
}
function changeCar(){
person.car = {c1:'雅迪',c2:'爱玛'}
}
// 监视,情况四:监视响应式对象中的某个属性,且该属性是基本类型的,要写成函数式
/* watch(()=> person.name,(newValue,oldValue)=>{
console.log('person.name变化了',newValue,oldValue)
}) */
// 监视,情况四:监视响应式对象中的某个属性,且该属性是对象类型的,可以直接写,也能写函数,更推荐写函数
watch(()=>person.car,(newValue,oldValue)=>{
console.log('person.car变化了',newValue,oldValue)
},{deep:true})
</script>
5.监视多个属性
- 多个属性放数组里,说白了如果是单纯的监听某一个属性,写成箭头函数形式,如果监听某一个对象,那就直接写就行了。
<template>
<div class="person">
<h1>情况五:监视上述的多个数据</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<h2>汽车:{{ person.car.c1 }}、{{ person.car.c2 }}</h2>
<button @click="changeName">修改名字</button>
<button @click="changeAge">修改年龄</button>
<button @click="changeC1">修改第一台车</button>
<button @click="changeC2">修改第二台车</button>
<button @click="changeCar">修改整个车</button>
</div>
</template>
<script lang="ts" setup name="Person">
import {reactive,watch} from 'vue'
// 数据
let person = reactive({
name:'张三',
age:18,
car:{
c1:'奔驰',
c2:'宝马'
}
})
// 方法
function changeName(){
person.name += '~'
}
function changeAge(){
person.age += 1
}
function changeC1(){
person.car.c1 = '奥迪'
}
function changeC2(){
person.car.c2 = '大众'
}
function changeCar(){
person.car = {c1:'雅迪',c2:'爱玛'}
}
// 监视,情况五:监视上述的多个数据
watch([()=>person.name,person.car],(newValue,oldValue)=>{
console.log('person.car变化了',newValue,oldValue)
},{deep:true})
</script>
6.watchEffect
- watch需要明确指出要监视的数据。
- watchEffect不需要,在箭头函数里用到了什么就自动注入什么。
- 相对于性能来说,watch会更好。
<template>
<div class="person">
<h1>需求:水温达到50℃,或水位达到20cm,则联系服务器</h1>
<h2 id="demo">水温:{{temp}}</h2>
<h2>水位:{{height}}</h2>
<button @click="changePrice">水温+1</button>
<button @click="changeSum">水位+10</button>
</div>
</template>
<script lang="ts">
export default {
name : "WatchEffect",
}
</script>
<script lang="ts" setup>
import {ref,watch,watchEffect} from 'vue'
// 数据
let temp = ref(0)
let height = ref(0)
// 方法
function changePrice(){
temp.value += 10
}
function changeSum(){
height.value += 1
}
// 方法1:通过watch
const stopWatch_1 = watch([temp, height], (v)=>{
const [newTemp, newHeight] = v
if(newTemp >= 50 || newHeight >= 20) {
console.log("正在发出警告...")
stopWatch_1()
}
})
// 方法2:通过watchEffect
const stopWatch_2 = watchEffect(()=>{
if(temp.value >= 50 || height.value >= 50){
console.log("正在联系服务器...")
}
if(temp.value === 100 || height.value === 50) {
stopWatch_2()
}
})
</script>
三、标签中的ref属性
- 这个属性是vue的特有的,用来动态获取DOM的响应式API,能够方便获取DOM,从而进行一系列操作。
1.DOM节点
- 通过vue的组合式响应API来获得ref的属性。
- 就是通过ref()来一一对应。
- 获得后就可以当作普通的DOM来操作了。
<template>
<div class="person">
<h1 ref="title1" id="title1">通过vue获得DOM节点</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>
import {ref} from 'vue'
let title1 = ref() // 对应title1
let title2 = ref() // 对应title2
let title3 = ref() // 对应title3
function showLog(){
// 1.传统的DOM操作获取ref属性的DOM节点
// 通过id获取元素
const t1 = document.getElementById('title1')
// 2.通过vue的ref响应式获得ref属性节点
// 通过ref获取元素
console.log(title1.value)
console.log(title2.value)
console.log(title3.value)
// 获得后就可以当作普通的DOM来操作
console.log(t1?.textContent)
console.log(title1.value?.textContent)
}
</script>
2.组件标签
步骤1:子组件需要上传数据。
步骤2:其他组件可以通过ref读取并访问。
App.vue
<template>
<!-- 写html结构 -->
<!-- 允许多标签 vue2不允许 -->
<RefAtrributeComps ref="ren"/>
<button @click="test">点一下</button>
</template>
<script lang="ts" setup>
import RefAtrributeComps from './components/RefAtrribute-comps.vue';
import {ref} from 'vue'
let ren = ref() // 获得了这个组件 拿到这个组件后就可以访问里面组件上传的数据了
function test() {
console.log(ren.value.name)
console.log(ren.value.age)
console.log(ren.value.name.textContent)
console.log(ren.value.age.textContent)
}
</script>
<style>
/* 写样式 */
</style>
RefAttribute-comps
<template>
<div class="person">
<h1 ref="name">乔尼</h1>
<h1 ref="age">19</h1>
</div>
</template>
<!-- 子组件Person.vue中要使用defineExpose暴露内容 -->
<script lang="ts" setup>
import {ref,defineExpose} from 'vue'
// 数据
let name = ref()
let age = ref()
// 要使用defineExpose将组件中的数据交给外部
defineExpose({name,age})
</script>
3.接口与泛型
- Java理解:export表示public,定义一个接口interface,里面包含的属性可以作为泛型的属性从而形成规范,再将一个自定义的数组对象Persons传入接口泛型,在其他组件里面就可以直接调用了。
types文件夹里面的index.ts
// 定义一个接口
export interface IPerson {
id:string,
name:string,
age:number,
}
// 定义一个自定义类型 传入接口泛型
export type Persons = Array<IPerson>
components文件夹里面的Person.vue
<template>
<div class="Person">
</div>
</template>
<script lang="ts" setup>
// @符号表示可以直接无脑引入
import {type Persons} from '@/types'
let personList:Persons = [
{id:"1", name:"乔尼", age:19},
{id:"2", name:"杰洛", age:24}
]
</script>
四、props
- props属性是父组件向子组件传递数据的一种机制,它允许父组件能够向子组件传递数据,使得子组件能够接收并使用这些数据,但是不能直接修改它们,它是单向数据流。
1.父组件
<template>
<Person :list="persons"/>
// 向子组件传一个类型为Persons的数组的数据
// 第一个冒号:表示解引用(c++) 表示不再是普通的字符串
// js专业术语是数据绑定,表示不再是普通的字符串
</template>
<script lang="ts" setup name="App">
import Person from './components/Person.vue'
import {reactive} from 'vue'
import {type Persons} from './types'
// 用reactive包裹是响应式数据
// 指定泛型是这个数组的类型 之前我们已经定义了
let persons = reactive<Persons>([
{id:'e98219e12',name:'张三',age:18},
{id:'e98219e13',name:'李四',age:19},
{id:'e98219e14',name:'王五',age:20}
])
</script>
2.子组件
<template>
<div class="person">
<ul>
// 1.ul和li循环,list是从父组件接收过来的数组
// 2.item表示每一项
// 3.:key表示能够确定每一item的标识
// 4.同理,不是单纯的字符串引用
<li v-for="item in list" :key="item.id">
{{item.name}}--{{item.age}}
</li>
</ul>
</div>
</template>
<script lang="ts" setup name="Person">
import {defineProps} from 'vue'
import {type Persons} from '@/types/index'
// 第一种写法:仅接收 是defineProps()
// const props = defineProps(['list'])
// 第二种写法:接收+限制类型
// let props = defineProps<{list:Persons}>()
// 第三种写法:接收+限制类型+指定默认值+限制必要性。
// 1.withDedaults表示接收后需要设置默认值。
// 2.defineProps表示从父组件接收数据。
// 3.<{list?:Persons}>表示接收一个list类型,?表示不必要,:Persons表示list中元素的类型,需要提前定义泛型。
// 4.{list:()=>[{id:'asdasg01',name:'乔尼',age:19}]}表示没有接收时的默认值。
// 5.返回的props就是最终子组件接收到的数据。
let props = withDefaults(defineProps<{list?:Persons}>(),{
list:()=>[{id:'asdasg01',name:'乔尼',age:19}]
})
console.log(props)
</script>
五、组件生命周期
挂载的含义:将vue组件关联到真实的DOM元素上,并完成初始渲染的过程,表示组件从虚拟DOM转换到了实际的页面中了。
生命周期含义:组件从创建、挂载、更新、卸载的整个过程称之为vue组件的生命周期,但是有一些新的钩子,目前还没学到。
Vue3的生命周期
创建阶段:
setup
挂载阶段:
onBeforeMount
、onMounted
更新阶段:
onBeforeUpdate
、onUpdated
卸载阶段:
onBeforeUnmount
、onUnmounted
- 常用的钩子:
onMounted
(挂载完毕)、onUpdated
(更新完毕)、onBeforeUnmount
(卸载之前)
<template>
<div class="person">
<h2>当前求和为:{{ sum }}</h2>
<button @click="changeSum">点我sum+1</button>
</div>
</template>
<!-- vue3写法 -->
<script lang="ts" setup name="Person">
import {
ref,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from 'vue'
// 数据
let sum = ref(0)
// 方法
function changeSum() {
sum.value += 1
}
console.log('setup')
// 生命周期钩子
onBeforeMount(()=>{
console.log('挂载之前')
})
onMounted(()=>{
console.log('挂载完毕')
})
onBeforeUpdate(()=>{
console.log('更新之前')
})
onUpdated(()=>{
console.log('更新完毕')
})
onBeforeUnmount(()=>{
console.log('卸载之前')
})
onUnmounted(()=>{
console.log('卸载完毕')
})
</script>
六、自定义钩子
- 很像我们的类。把数据和函数对应为属性和方法。
1.Hooks
- 与组件包同级。
useDog
import {reactive,onMounted} from 'vue'
import axios,{AxiosError} from 'axios'
export default function(){
// 括号里面有个数组括号是初始值是空数组
let dogList = reactive<string[]>([])
// 方法
async function getDog(){
try {
// 发请求
let result = await axios.get('https://dog.ceo/api/breed/pembroke/images/random')
// 维护数据
dogList.push(result.data.message)
} catch (error) {
// 处理错误
const err = <AxiosError>error
console.log(err.message)
}
}
// 挂载钩子
onMounted(()=>{
getDog()
})
//向外部暴露数据
return {dogList,getDog}
}
useSum
import {ref,onMounted} from 'vue'
export default function(){
let sum = ref(0)
const increment = ()=>{
sum.value += 1
}
const decrement = ()=>{
sum.value -= 1
}
onMounted(()=>{
increment()
})
//向外部暴露数据
return {sum,increment,decrement}
}
2.Components
- 聚合hooks的组件类。
hooksTest
<template>
<h2>当前求和为:{{sum}}</h2>
<button @click="increment">点我+1</button>
<button @click="decrement">点我-1</button>
<hr>
<img v-for="(item,index) in dogList" :key="index" :src="item">
<button @click="getDog">再来一只狗</button>
</template>
<script lang="ts">
export default {
name : "HooksTest",
}
</script>
<script setup lang="ts">
import useSum from '../../hooks/useSum'
import useDog from '../../hooks/useDog'
// 通过hooks解构获得数据
let {sum,increment,decrement} = useSum()
let {dogList,getDog} = useDog()
</script>
<style>
img {
height: 100px;
}
</style>
3.App
<template>
<Hookstest />
</template>
<script lang="ts" setup>
import Hookstest from './components/HooksTest/hookstest.vue';
</script>
4.与Components的区别
- 在Hooks里面主要是一些逻辑,不涉及UI,在Components里面主要是一些html结构、css样式、如果要具体的逻辑可以拆分为hooks进行调用,然后进行拼接成一个完整的组件。