文章目录
响应式
概念
API:应用程序接口,Application Programming Interface,是一些预先定义的接口或者是软件系统不同组成部分衔接的约定。
响应式:一种允许以声明式的方法去适应变化的编程范例。
- 数据监听式的根据某个数据的变化,跟当前数据有关系的数据自动变化;
- 数据在渲染之后,当数据发生变化,网页上重新渲染新的数据;
实现过程
- 1.定义响应式的状态
- 通常使用reactive方法来实现,该方法是接收一个普通对象,然后返回该普通对象的响应式处理;这个过程可以在渲染器件使用。
- 2.计算属性定义
- 使用computed方法监听说需要使用的数据
- 3.依据Vue3.0中使用的ES6的proxy语法实现响应式数据
- 优点:可以检测到代理对象属性的动态添加和删除、数组的下标和length属性的变更
setup函数
新的组件选项,作为composition()组合式) API的起点。
必须得有返回值,且该函数的返回值就可以在模板中进行使用;当然也可以返回一个渲染函数,该函数可以直接在同一作用域中声明响应式的状态
可以接受两个参数:
- props
- context
props
是一个响应式参数,所以不能使用ES6进行解构;如果需要解构props,可以使用setup函数中的toRefs来实现。
// 正常使用
export default{
props: {
title: string
},
setup(props){
console.log(props.title)
}
}
// 使用toRefs实现解构
import { toRefs } from 'vue'
export default{
props: {
title: string
},
setup(props){
const { title } = toRefs(props)
console.log(title.value)
}
}
// 返回一个渲染函数
import { h, ref, reactive} from 'vue'
export default{
setup(){
const readersNumber = ref(0)
const book = reactive({
title: 'Vue 3 Guide'
})
return () => h('div', [readersNumber.value, book.title ])
}
}
context参数
是一个普通的JavaScript参数,有三个属性:
attrs
:非响应式对象- 有状态对象
- 跟随组件本身的更新而更新
- 最终以
attrs.x
引用属性
slots
:非响应式对象- 有状态对象
- 跟随组件本身的更新而更新
- 最终以
slots.x
引用属性
emit
:触发事件(方法)- 主要用于子组件向父组件传递数据和调用父组件的方法
export default{
setup(props, context) {
console.log(context.attrs)
console.log(context.slots)
console.log(context.emit)
}
}
// 解构
export default{
setup(props, {attrs, slots, emit}) {
}
}
响应式API
ref函数
接收一个参数值并返回一个响应式且可改变的ref对象,该对象有一个指向内部的 单一value属性
const count = ref(0)
console.log(count.value)
当ref作为渲染上下文的属性返回,即在setup
函数中的return对象中到模板时会自动解套,不需要加上value属性,ref函数必须从vue引用才能使用
<template>
<div>{{ count }}</div>
</template>
<script>
import { ref } from 'vue'
export default{
setup(){
return {
count: ref(0)
}
}
}
</script>
reactive函数
类似ref函数使用;将数据变成响应式数据,当数据发生变化,UI也会自动更新;不同于ref函数的是:ref函数作用于基本数据类型,而该函数作用于复杂数据类型,主要有对象和数组两种类型
computed方法
结构一个getter函数,返回一个默认不可手动修改的ref对象
// 基本使用示例
const count = ref(1)
const plusOne = computed(() => count.value + 1)
// 报错
plusOne.value ++
// get和set使用示例
const count = ref(1)
const plusOne = computed({
get: () => count.value +1,
set: (val) => {
count.value = val-1
}
})
// 调用set方法
plusOne.value = 1
// 调用get方法
console.log(plusOne.value)
watchEffect方法
可以响应式追踪其依赖,并在其依赖变更时重新运行该函数。
该方法不需要指定要监听那个属性,其会自动收集回调函数中引用到的响应式属性,并且当组件初始化的时候,会执行一次一次用以收集属性。
停止监听两种方式
- 隐式停止
- 当watchEffect在组件的setup函数或者生命周期函数钩子被调动的时候,侦听器会被衔接到该组件的生命周期,当组件卸载的时候自动停止
- 显式停止
- 使用语句进行调用
import { watchEffect, ref } from 'vue'
export default {
setup(){
const count = ref(0)
// 当count发生变化时,则立即输出
watchEffect(() => console.log(count.value))
setTimeout(() =>{
count.value ++
}, 1000)
return {
count
}
}
}
// 显式调用停止
const stopWE = watchEffect(...)
stopWE.stop();
响应式系统工具集
toRef
可以为一个reactive对象的属性创建一个ref,可以被传递并且保持响应性。
const state = reactvie({
foo: 1,
bar: 2
})
const fooRef = toRef(state, 'foo')
toRefs
将一个响应式对象转换成普通对象,该普通对象的每个属性都是一个ref,和响应式对象的属性一一对应
const state = reactvie({
foo: 1,
bar: 2
})
// foo和bar都是一个ref
const stateAsRefs = toRefs(state)
Provide/Inject
如果父子结构嵌套比较深,那么传递数据很繁琐,可以使用Provide和Inject进行数据传递。
该特性有两个部分:
- 父组件有一个Provide选项用于提供数据
- 子组件有一个Inject选项用于接收这个数据
使用
Provide
在父组件setup函数中使用该方法,从Vue中导入,然后在调用Provide方法时定义每个属性,该方法有两个参数:
- 属性名(
<String>
类型) - 属性值
provide('studentName', '刘同学')
Inject
在子组件setup函数中使用该方法,从Vue中导入,然后在调用Inject方法时定义每个属性,该方法有两个参数:
- 要注入的属性名称
- 一个默认的值(可选)
const studentName = inject('studentName', 'zs')
使用示例
父组件
<template>
<myInject />
</template>
<script>
import { reactive, toRefs, provide } from 'vue'
import myInject from './Inject.vue'
export default{
components: {
myInject
},
setup() {
const state = reactive({
msg: 'Hello Vue World'
})
provide('studentName', 'ls')
provide('grode', {
Vue: 95,
jQuery: 97
})
return {
...toRefs(state)
}
}
}
</script>
子组件
<<template>
学生成绩:{{ studentName }}<br>
vue成绩: {{ grode.Vue }}<br>
jQuery成绩: {{ grode.jQuery }}<br>
</template>
<script>
import { reactive, toRefs, inject } from 'vue'
export default{
setup() {
const state = reactive({
count: 0
})
const studentName = inject('studentName', 'zs')
const grode = inject('grode')
return {
...toRefs(state)
studentName,
grode
}
}
}
</script>
响应式修改Provide和Inject
可以在provide值的时候使用ref或者reactive,可以保持其数据的响应性,如果子组件的数据不需要根据provide传递数据,建议可以使用readonly
方法保护数据
父组件
<<template>
<input type="text" v-model="studentName" /><br>
<children></children>
</template>
<script>
import { reactive, toRefs, provide } from 'vue'
import children from './child1.vue'
export default{
components:{
children
},
setup() {
const studentName = ref('zs')
const grode = reactive({
Vue: 90,
jQuery: 98
})
const updateLoation = () => {
studentName.value = "ls"
grode.Vue = 99
}
provide("studentName", readonly(studentName))
provide("grode", readonly(grode))
provide("updateLoation", updateLoation)
return {
studentName
}
}
}
</script>
子组件
<<template>
学生成绩:{{ studentName }}<br>
vue成绩: {{ grode.Vue }}<br>
jQuery成绩: {{ grode.jQuery }}<br>
<button @click="updateLoation">调用父组件的方法</button>
</template>
<script>
import { reactive, toRefs, inject } from 'vue'
export default{
setup() {
const studentName = inject('studentName', 'zs')
const grode = inject('grode')
const updateLoation = inject("updateLoation")
return {
studentName,
grode,
updateLoation
}
}
}
</script>