09-组合式API

响应式

概念

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>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值