组合式api
什么是组合式api
随着项目的扩大,功能越来越复杂,定义的数据以及对其数据的操作被放在不同的地方,如methods,watch,碎片化使得理解和维护复杂组件变得困难。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地“跳转”相关代码的选项块,于是出现了组合式api
使用
组合式api在vue3中是通过setup函数实现的,在这个函数中进行使用,该函数接受 props 和 context 两个参数
在执行setup函数时,还没有创建实例,所以在setup函数中是没有this指向
参数
-
props
export default { props: { title: String }, setup(props) { console.log(props.title) // 如果想使用结构赋值 const { title } = toRefs(props) } } -
context
context 是一个普通的 JavaScript 对象,它暴露组件的三个 property
export default { setup(props, context) { // Attribute (非响应式对象) console.log(context.attrs) // 插槽 (非响应式对象) console.log(context.slots) // 触发事件 (方法) console.log(context.emit) } }
响应式基础
将数据变为响应式数据,现在有ref、reactive
-
ref函数 ,会将基本数据类型变为响应式的数据,本质是变为proxy对象,变为一个引用对象
import { ref } from 'vue' const counter = ref(0) console.log(counter) // Proxy {value: 0} console.log(counter.value) // 0 counter.value++ console.log(counter.value) // 1ref函数还可以获取到模板中的html对象
<div ref='homeDiv'>home</div> setup() { const homeDiv = ref(null) // 挂载之后去获取dom元素 onMounted(() => { console.log(homeDiv.value) }) return { // 要记得将其导出 homeDiv } } -
reactive函数,可以将对象变为响应式数据,返回对象的响应式副本
import { reactive } from 'vue' const person = reactive({ name: '张三', age: 22, languages: ['英语', '汉语'] }) return { // toRefs将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref ...toRefs(person) } -
toRef函数
为源响应式对象上的某个 property 新创建一个 ref。然后,ref 可以被传递,它会保持对其源 property 的响应式连接
const state = reactive({ foo: 1, bar: 2 }) const fooRef = toRef(state, 'foo') fooRef.value++ console.log(state.foo) // 2 state.foo++ console.log(fooRef.value) // 3 -
计算属性
接受一个getter函数,并从 getter 返回的值返回一个不变的响应式 ref 对象
const count = ref(1) const plusOne = computed(() => count.value + 1) console.log(plusOne.value) // 2 plusOne.value++ // error也可以接受get和set函数的对象
const count = ref(1) const plusOne = computed({ get: () => count.value + 1, set: val => { count.value = val - 1 } }) plusOne.value = 1 console.log(count.value) // 0 return { count, plusOne } -
监听属性
可以直接监听一个ref对象,或者是具有返回值的getter函数
// 侦听一个 getter const state = reactive({ count: 0 }) watch( () => state.count, (count, prevCount) => { console.log(count) } ) // 直接侦听一个 ref const count = ref(0) watch(count, (count, prevCount) => { console.log(count) })可以监视多个对象
watch([fooRef, barRef], ([foo, bar], [prevFoo, prevBar]) => { /* ... */ })生命周期
由于setup函数建立时,没有创建组件实例,所以没有beforeCreate 和 created 生命周期钩子,在这两个生命周期内进行的操作都可以在setup函数中进行
onBeforeMount(() => { console.log('onBeforeMount') }) onMounted(() => { console.log('mounted!') }) onBeforeUpdate(() => { console.log('onBeforeUpdate!') }) onUpdated(() => { console.log('updated!') }) onUnmounted(() => { console.log('unmounted!') })provide和inject
在组件之间传值时会使用到
- provide 函数允许你通过两个参数定义 property,name和value
provide: { location: 'North Pole', geolocation: { longitude: 90, latitude: 135 } }- inject函数允许接受两个参数,一个是要 inject 的 property 的名称,另一个是默认值
可以将其变为响应式的,如果想让传递的值不被改变,可以使用readonly来进行修饰
const location = ref('North Pole') const geolocation = reactive({ longitude: 90, latitude: 135 }) provide('location', readonly(location)) provide('geolocation', geolocation)实例
做了一个tosdolist的组件,该组件是输入一个值,在下面的列表中进行显示,可以将其逻辑单处抽离出去,使得整个逻辑比较清楚
<ul> <li v-for="(item, index) in list" :key="index"> <div v-if="item.edit" style="margin-right: 10px">{{ item.val }}</div> <el-input style="width: 300px" v-else v-model="item.val" @blur="item.edit = !item.edit" /> <div> <el-button @click="edit(index)" type="primary">编辑</el-button> <el-button @click="remove(index)" type="primary">删除</el-button> </div> </li> </ul> setup() { const {state, handleChange, edit, remove} = useState() return { ...toRefs(state), handleChange, edit, remove, } }import { reactive} from "vue"; import Home from "@/model/home"; type stateType = { state: Home, handleChange: () => void, edit: (val: number) => void, remove: (val: number) => void } export function useState(): stateType { const state: Home = reactive({ input: "", list: [], }); const handleChange = () => { state.list.push({ edit: true, val: state.input, }); state.input = ""; }; const edit = (index: number) => { state.list[index].edit = false; }; const remove = (index: number) => { state.list.splice(index, 1); }; return { state, handleChange, edit, remove } }