组合式API记录

插件安装 及 注入

# 安装插件
npm install @vue/composition-api  
yarn add @vue/composition-api

# 在 main.js 文件中导入并注册使用
import VueCompositionApi from '@vue/composition-api';
Vue.use(VueCompositionApi);

setup 介绍 及 基础使用

setup 函数是一个新的组件选项,作为在组件内使用 Composition API 的入口
创建组件实例,然后初始化 props,紧接着就调用 setup 函数。
setup 返回一个对象,暴露给模板使用,对象的属性将会被合并到组件模板的渲染上下文
注意:setup 返回的 ref 在模板种会自动解开,不需要写 .value

<script>
<template>
	<div>
		{{ count }} - {{ object.foo }}
	</div>
</template>
// 引入插件
import { ref, reactive } from '@vue/composition-api'

export default {
	setup() {
		const count = ref(0)
		const object = reactive({ foo: 'bar' })
		// 暴露给模板使用
		return {
			count,
			object
		}
	}
}
</script>

参数 props

setup 函数接收 props 作为第一个参数,props 对象是响应式的,watchEffect 或 watch 会观察和响应 props 的更新。
注意:

  1. 不能在 setup 函数的形参内解构 props 对象,否则会失去响应性
  2. 在开发过程种,props 对象的值是不能改变的,否则会触发警告
<script>
export default {
	props: {
		name: String
	},
	// 注意:不能在直接解构第一个参数,可以在函数内部进行解构
	setup(props) {
		watchEffect(() => {
			console.log(props.name)
		})
	}
}
</script>

setup 函数第二个参数 context 上下文对象

setup 函数的第二个参数是一个上下文对象,注意:在 setup() 函数种无法访问到 this

export default {
	setup(props, context) {
		// 注意,context 可以在行上进行结构, 也可以在函数内进行结构  
		const { root, emit, refs, attrs, slots, parent } = context
	}
}

使用 defineComponent 使 setup() 参数获得类型推断的传递

export default defineComponent({
	name: '组件名称',
	props: {}
	setup(props, { root, emit, refs }) {
		return {}
	}
})

响应式系统 API - reactive

import { reactive } from '@vue/composition-api'

export default {
	setup(props, context) {
		// 创建响应式数据对象
		const state = reactive({ count: 0 })
		
		// 返回响应式对象,提供给 template 使用
		// 模板使用方式, <p> state.count: {{state.count}} </p> 
		return state
	}
}

响应式系统 API - ref

ref() 函数用来根据给定的值创建一个响应式的数据对象,返回值是一个对象,这个对象上只包含一个 .value 属性

import { ref } from '@vue/composition-api'

export default {
	setup(props, context) {
		// 创建响应式数据
		const count = ref(0) // 数字类型
		// 在setup 内部使用时候,使用.vaue 进行访问更改 count.value = 100
		const strVal = ref('default') // 字符串
		// strVal.value = 'update'
		const arrVal = ref(['小明', '小米']) // 数组
		// arrVal.value = ['新东西', '新世界']
		const objVal = ref({
			num: 10, title: '结算'
		})
		// objVal.value.name = 100; objVal.value.title = '合计'
		
		# 在reactive 对象种访问 ref创建的响应式数据
		# ref挂载到reactive上时,会自动把响应式数据根据对象展开为原始的值, 不需要通过 .value 就可以直接被访问  
		const state = reactive({ count })
		console.log(state.count) // 输出 0
		state.count++   // 不需要通过 .value 就能直接访问原始值 
		console.log(count) // 输出 1
		
		return {
			count
		}
	}
}

isRef

# 检查某个值是否 ref() 创建出来的对象。
import { isRef } from '@vue/composition-api'
const unerapped = isRef(foo) ? foo.value : foo

toRefs

toRefs() 函数可以将 reactive() 创建出来的响应式对象,转换为普通的对象,只不过,这个对象上的每个属性节点,都是 ref() 类型的响应式数据

import { toRefs } from '@vue/composition-api'

export default {
	setup(props, context) {
		// 定义响应式数据 对象
		const state = reactive({
			count: 0
		})
		
		return {
			// 将 state 上的每一个属性,都转化为 ref 形式的响应式数据  
			...toRefs(state)
		}
	}
}

计算属性 computed

computed() 用来创建计算属性,函数返回值是一个 ref 的实例

const count = ref(1)
# 1. 创建只读的计算属性
// 根据 count 的值,创建一个响应式的计算属性 setOne
// 根据依赖的 ref 自动计算并返回新的 ref
const setOne = computed(() => count.value + 1)
console.log( setOne.value ) // 输出 2
setOne.value++   // 报错, 计算属性不能直接修改

# 2. 创建可读可写的计算属性  
// 在调用 computed() 函数期间, 传入一个包含 get 和 set 函数的对象. 可以得到一个可读写的计算属性  
const setTwo = computed({
	// 取值函数
	get: () => count.value + 1,
	// 赋值函数
	set: val => {
		count.value = val - 1
	}
})

// 为计算属性赋值的操作,会触发 set 函数
setTwo.value = 100 
console.log( count.value ) // 99, 触发set后, count的值会被更新

watch 监听

可以实现在一个属性变更的时候,去执行我们想要的行为。
比如:

  1. 当ID改变的时候,从数据库里面获取新的数据
  2. 当属性变换的时候执行一个动画
  3. 当搜索条件变更的时候,更新查询到的数据
const state = reactive({ count: 0, title: 'xiaoming' })
const count = ref(0)
const title = ref('xiaoming')
# 监听指定的数据源  
watch(
	() => state.count, // 监听 reactive 类型的数据源
	count, // 监听 ref 类型的数据源
	(val, oldVal) => {
		/* ... */
	}
)

# 监听多个数据源 ------
watch(
	// 监听 reactive 类型的数据源
	[() => state.count, () => state.title], 
	// 监听 ref 类型的数据源
	[count, title],  
	([count, title], [oldCount, oldTitle]) => {
		console.log(count) // 新的 count 值
		console.log(title) // 新的 title 值
		console.log('-----------')
		console.log(oldCount) // 旧的 count 值
		console.log(oldTitle) // 旧的 title 值
	},
	{
		lazy: true // 在 watch 被创建的时候,不执行回调函数中的代码
	}
)

# 清除监听  
// 在 setup 含税内创建的 watch 监听,会在当前组件被销毁的时候自动停止。 如果想要明确地停止某个监听, 可以调用 watch 函数的返回值即可  
// 创建监听,并得到 停止函数
const stopWatch = watch(() => {})
// 调用停止函数,清除对应的监听
stopWatch()

# 在 watch 中清除无效的异步任务  
// 有时候,当被 watch 监听的值发生变化时,或 watch 本身被 stop 之后,我们期望能够清除哪些无效的异步任务,此时,watch 回调函数中提供了一个 cleanup registrator function 函数来执行清除的工作。这个清除函数会在如下情况下被调用: 1. watch 被重复执行了 2. watch 被强制 stop 了 
const keyVal = ref('')
// 异步任务
const asyncPrint = val => {
	return setTimeout(() => {
		console.log(val)
	}, 1000)
}

watch(keyVal, (val, oldVal, onCleanup) => {
	// 执行异步任务,并得到关闭异步任务的 函数
	const timeId = asyncPring(val)
	
	// 如果 watch 监听被重复执行了,则会先清除上次未完成的异步任务
	onCleanup(() => clearTimeout(timeId))
}, {
	lazy: true // watch 刚被创建的时候不执行
})

watchEffect 特点 及 原理

  1. 不需要指定监听的属性,会自动收集依赖,只要我们在回调中引用到了响应式的属性,那么当这些属性变更的时候,回调都会执行。而 watch 只能监听指定的属性而做出变更
  2. watch 可以获取到新值和旧值(更新前的值), 而watchEffect 是拿不到的
  3. watchEffect 如果存在的话,在组件初始化的时候就会执行一次用来收集依赖(与computed同理), 而后收集的依赖发生变化,这个回调才会再次执行,而watch不需要,因为一开始就指定了依赖。
import { watchEffect, ref } from 'vue'
setup () {
	const userID = ref(0)
	watchEffect(() => console.log(userID))
	setTimeout(() => {
		userID.value = 1
	}, 1000)
	
	return { userID }
}

停止监听

watchEffect 会返回一个用于停止这个监听的函数
如果 watchEffect 是在 setup 或者 生命周期里面注册的话,在组件取消挂载的时候会自动的停止掉

const stop = watchEffect(() => {
	// ...
})
stop()

新版本的生命周期函数 - 且只能在 setup 函数中使用

import { onMounted, onUpdated, onUnmounted } from '@vue/composition-api' 

export default {
	setup(props, context) {
		onMounted(() => {
			console.log('mounted')
		})
		onUpdated(() => {
			console.log('updated')
		})
		onUnmounted(() => {
			console.log('unmounted')
		})
	}
}

模板 refs

通过 ref() 还可以引用页面上的元素或组件

<template>
<div>
	<h1 ref="titleRef">通过ref() 函数来引用元素</h1>
</div>
</template>
<script>
import { ref, onMounted } from '@vue/composition-api'
export default {
	setup() {
		// 创建一个 DOM 引用
		const titleRef = ref(null)
		
		// 在 DOM 首次加载完毕之后,才能获取到元素的引用
		onMounted(() => {
			// titleRef.value 是原生DOM对象
			titleRef.value.style.color = 'red'
		})
		return {
			titleRef
		}
	}
}
</script>

createComponent

这个函数不是必须的,除非你想要完美结合 TypeScript 提供的类型推断来进行项目的开发。
函数仅仅提供了类型推断,方便在结合 TypeScript 书写代码时,能为 setup 中的 props 提供完整的类型推断

import { createComponent } from '@vue/composition-api'

export default createComponent({
	props: {
		foo: String
	},
	setup(props, context) {
		props.foo // type: string
	}
})

学习资源地址

  1. 组合式API
  2. vue3.x新特性
posted @ 2020-12-19 20:18  yuxi2018  阅读(292)  评论(0编辑  收藏  举报