基础知识学习
组合式API reactive和ref函数
reactive函数
传入对象类型的参数 变量接收
<script setup>
import {reactive} from 'vue'
const state=reactive({
count:0
})
const setCount = ()=>{
state.count++
}
</script>
<template>
<div>
<button @click="setCount">{{ state.count }}</button>
</div>
</template>
ref函数
接受简单类型和对象类型 返回响应式数据
<script setup>
import { ref } from 'vue';
const count=ref(0)
console.log(count);
const setCount = ()=>{
//脚本区域修改ref产生响应式数据 必须通过.value属性进行++
count.value++
}
</script>
<template>
<div>
<button @click="setCount">{{ count }}</button>
</div>
</template>
组合式API computed函数
核心步骤:
1.导入computed函数
2.执行函数 在回调参数中return基于响应式数据作计算的值,用于变量的接收
<script setup>
import {ref} from 'vue'
import { computed } from 'vue';
const list = ref([1,2,3,4,5,6])
const computedList = computed(()=>{
return list.value.filter(item => item>2)
})
setTimeout(() => {
list.value.push(9,10)
}, 3000);
</script>
<template>
<div>
原始数据-{{ list }}
</div>
<div>
计算后的数据-{{ computedList }}
</div>
</template>
组合式API watch函数
watch侦听单个数据源
两个参数,第一个参数是响应式数据,第二个参数是回调
<script setup>
import { ref,watch } from 'vue'
const count=ref(0)
const setCount = ()=>{
count.value++
}
// watch侦听单个数据源
// 在watch中ref对象不需要加.value
watch(count,(newValue,oldValue)=>{
console.log('count变化了',newValue,oldValue);
})
</script>
<template>
<div>
<button @click="setCount">+{{ count }}</button>
</div>
</template>
watch侦听多个数据源
传参的时候变为数组的多个参数
<script setup>
import {ref,watch} from 'vue'
const count=ref(0)
const setCount = ()=>{
count.value++
}
const name=ref('cp')
const changeName = ()=>{
name.value = 'pc'
}
//watch侦听多个数据源
watch([count,name],(
[newCount,newName],
[oldCount,oldName]
)=>{
console.log('count或name变化了',[newCount,newName],
[oldCount,oldName]);
})
</script>
<template>
<div>
<button @click="setCount">修改count--{{ count }}</button>
</div>
<div>
<button @click="changeName">修改name--{{name}}</button>
</div>
</template>
immediate
在侦听器创建时立即触发回调,响应式数据变化之后继续执行回调
<script setup>
import { ref,watch } from 'vue'
const count=ref(0)
const setCount = ()=>{
count.value++
}
// watch侦听单个数据源
// 在watch中ref对象不需要加.value
watch(count,()=>{
console.log('count变化了');
},{
immediate:true
})
</script>
<template>
<div>
<button @click="setCount">+{{ count }}</button>
</div>
</template>
watch中三个参数,增加immediate后,先执行回调函数一次。
deep
默认机制:通过watch监听的ref对象默认是浅层侦听的,直接修改嵌套的对象属性不会触发回调执行,需要开启deep选项。
<script setup>
import {ref,watch} from 'vue'
const state=ref({count:0})
const changeStateByCount = ()=>{
state.value.count++
}
// watch深度监听
watch(state,()=>{
console.log('count变化了');
},{
deep:true
})
</script>
<template>
<div>
<button @click="changeStateByCount">{{state.count}}--修改count</button>
</div>
</template>
deep有性能损耗 尽量不开启deep
精确侦听
<script setup>
import {ref,watch} from 'vue'
const state=ref({
name:'zhangsan',
age:20
})
const ChangeName = ()=>{
state.value.name = 'lisi'
}
const ChangeAge = ()=>{
state.value.age=18
}
//精确侦听某个具体属性
watch(
()=>state.value.age,
()=>{
console.log('age变化了');
}
)
</script>
<template>
<div>
<div>
<div>当前姓名{{ state.name }}</div>
<div>当前年龄{{ state.age }}</div>
</div>
<div>
<button @click="ChangeName">修改name</button>
<button @click="ChangeAge">修改age</button>
</div>
</div>
</template>
不开启deep,想在某个层次比较深的属性变化时执行回调:
可以把第一个参数写成函数的写法,返回要监听的具体属性。
组合式API 生命周期函数
vue3的生命周期API(选项式 VS 组合式)
选项式API | 组合式API | ||
beforeCreate/created | setup | ||
beforeMount | onBeforeMount | ||
mounted | onMounted | ||
beforeUpdate | onBeforeUpdate | ||
updated | onUpdated | ||
beforeUnmount | onBeforeMount | ||
unmounted | onUnmounted |
<script setup>
import {onMounted} from 'vue'
onMounted(()=>{
console.log('组件挂在完毕1');
// 好多逻辑
})
onMounted(()=>{
console.log('组件挂在完毕2');
// 补充逻辑
})
</script>
<template>
</template>
组合式API 父子通信
父传子
基本思想:
1.父组件给子组件绑定属性
2.子组件内部通过props选型接收
vue3中子组件内部通过编译器宏函数接收:defineProps(传入对象类型的数据)
App.vue
<script setup>
// setup语法糖下局部组件无需注册即可使用
import {ref} from 'vue'
import SonCom from './son-com.vue'
const count = ref(100)
setTimeout(()=>{
count.value=200
},3000)
</script>
<template>
<div class="father">
<h2>父组件App</h2>
<!--1.绑定属性 -->
<SonCom :count='count' message="father message"/>
</div>
</template>
<style scoped>
</style>
son-com.vue
<script setup>
// 2. defineProps接收数据
const props = defineProps({
message:String,
count:Number
})
console.log(props);
</script>
<template>
<div class="son">
<h3>子组件Son</h3>
<div>
父组件传入数据-{{ message }}-{{ count }}
</div>
</div>
</template>
<style scoped>
</style>
子传父
基本思想:
1.父组件中给子组件标签通过@绑定事件
2.子组件内部通过$emit方法触发事件
vue3中通过defineEmits编译器宏生成emit方法
App.vue
<script setup>
// 引入子组件
import sonComVue from './son-com.vue'
const getMessage = (msg)=>{
console.log(msg);
}
</script>
<template>
<!-- 1.绑定自定义事件 -->
<sonComVue @get-message = "getMessage"/>
</template>
son-com.vue
<script setup>
// 2.通过 defineEmits编译器宏生成emit方法
const emit=defineEmits(['get-message']) //传入数组格式的参数,原因是要求将当前组件触发的所有的自定义事件都放过来
const sendMsg = ()=>{
// 3.触发自定义事件,并传递参数
emit('get-message','this is son msg')
}
</script>
<template>
<button @click="sendMsg">sendMsg</button>
</template>
组合式API 模板引用
模板引用的概念:
通过ref标识获取真实的dom对象或组件实例对象
如何使用(以获取dom为例 组件同理)
1.调用ref函数生成一个ref对象
2.通过ref标识绑定ref对象到标签
<script setup>
import { onMounted } from 'vue'
import {ref} from 'vue'
// import TestCom from './test-com.vue'
// 1.调用ref函数 -> ref对象(可以把它看作容器)
const h1Ref = ref(null)
// 组件挂载完毕之后才能获取
onMounted(()=>{
console.log(h1Ref.value);
})
</script>
<template>
<!-- 2.通过ref标识绑定ref对象 -->
<h1 ref="h1Ref">我是dom标签h1</h1>
<!-- 已经将h1 dom对象存入到h1Ref.value -->
<!-- <TestCom/> -->
</template>
defineExpose()
默认情况下在<script setup>语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过defineExpose编译宏指定哪些属性和方法允许访问
test-com.vue
<script setup>
import { ref } from 'vue';
const name = ref('test name')
const setName = ()=>{
name.value = 'test new name'
}
defineExpose({
name,
setName
})
</script>
<template>
<div>我是test组件</div>
</template>
总结问题:
1.获取模板引用的时机是什么?
组件挂载完毕
2.defineExpose编译宏的作用是什么?
显示暴露组件内部的属性和方法
组合式API provide和inject
作用和场景:
顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信
跨层传递普通数据
1.顶层组件通过provide函数提供数据
2.底层组件通过inject函数获取数据
App.vue
<script setup>
import RoomMsgItem from './room-msg-item.vue'
import roomMsgComment from './room-msg-comment.vue';
import roomPage from './room-page.vue';
// 组件嵌套关系
// RoomPage -> RoomMsgItem -> RoomMsgComment
</script>
<template>
<div>
<roomPage />
</div>
</template>
<style scoped>
</style>
room-page.vue
<script setup>
import { provide,ref } from 'vue';
import RoomMsgItem from './room-msg-item.vue'
// 组件嵌套关系
// RoomPage -> RoomMsgItem -> RoomMsgComment
// 1.顶层组件提供数据
provide('data-key','this is room data')
// 传递响应式对象
const count = ref(0)
provide('count-key',count)
setTimeout(()=>{
count.value=100
},3000)
</script>
<template>
<div class="page">
顶层组件
<RoomMsgItem />
</div>
</template>
<style scoped>
</style>
room-message-item.vue
<script setup>
import roomMsgComment from './room-msg-comment.vue';
</script>
<template>
<div class="item">
中间组件
<roomMsgComment />
</div>
</template>
<style scoped>
</style>
room-msg-comment.vue
<script setup>
import { inject } from 'vue';
// 2.接收数据
const roomData = inject('data-key')
const countData = inject('count-key')
</script>
<template>
<div class="comment">
底层组件
<div>
来自顶层组件中的数据为:{{ roomData }}
</div>
<div>
来自顶层组件中的响应式数据:{{ countData }}
</div>
</div>
</template>
<style scoped>
</style>
跨层传递方法:
顶层组件可以向底层组件传递方法 底层组件调用方法修改顶层组件中的数据
在顶层组件通过传递方法,在底层组件调用这个方法。目的是不破坏单向数据流的前提下,在底层组件中可以修改顶层组件中的数据。
在开发过程中需要遵守的一条原则:
谁的数据谁负责修改