Composition组合API在setup函数中的使用
为什么需要Vue对组合API
目前在Vue世界中,最热门的话题是Composition API,这是Vue 3.0中引入的基于函数的API。 在本文中,我们将学习这个新API的需求,然后学习如何使用基于函数的API。
在我们深入探讨之前,无需担心组合API将彻底改变Vue。 Composition API是现有组件附加的功能,因此Vue 3.0中没有重大更改此外,Vue团队还创建了一个与Vue 2.x兼容的插件(vue-composition)。
随着Vue的日益普及,人们也开始在大型和企业级应用程序中采用Vue。 由于这种情况,在很多情况下,此类应用程序的组件会随着时间的推移而逐渐增长,并且有时使用单文件组件人们很难阅读和维护。 因此,需要以逻辑方式制动组件,而使用Vue的现有API则不可能。
代替添加另一个新概念,提议使用Composition API,该API基本将Vue的核心功能(如创建响应式数据)公开为独立功能,并且该API有助于在多个组件之间编写简洁且可复用的代码。
组合API在vue组件中的应用
比如有一个组件,使用了组合API,文件结构如下:
注意文件命名规则,使用组合API时,在组件目录下的JS文件命名为use-xxxx.js
通过ref拿到DOM元素
具体请参见:Vue3-setup在渲染函数中通过ref访问Dom元素
向逻辑中传入props
<index-list :data="singers"></index-list>
// 在index-list.vue中
import useFixed from './use-fixed'
props: {
data: {
type: Array,
default () {
return []
}
}
},
setup(props) {
const { ... } = useFixed(props);
return {....]
}
在use-fixed.js中使用props中data的数据:
export default function useFixed (props) {
const group = props.data[...]
}
在逻辑中使用computed、watch和nextTick,并与模板中映射
注意在组合API中,许多属性都需要手动的进行引入。
在index-list.vue中:
<div class="fixed" v-show="fixedTitle">...</div>
import useFixed from './use-fixed'
setup(props) {
// 因为可能返回多个属性或方法,这里使用解构赋值
const { fixedTitle } = useFixed(props)
// 要想让属性在模板中生效,必须要在setup中返回!
return {
fixedTitle
}
}
在use-fixed.js中:
import { ref, watch, computed, nextTick } from 'vue'
export default function useFixed (props) {
// 使用ref创建响应式的数据
const scrollY = ref(0)
// 计算属性注意也需要引入
const fixedTitle = computed(() => {
return '...'
})
// 使用watchAPI也需要引入,vue3的watch要监听一个getter函数
// () => props.data就是监听的数据,后面就是监听到变化后执行的函数
watch(() => props.data, async () => {
// 因为监听到数据的变化后,DOM不一定会立即发生变化
// 这是一个异步过程 所以等nextTick DOM更新完后再进行计算
await nextTick()
// do...
})
// 监听某个值的变化 也可以用getter函数
watch(scrollY, (newY) => {
// do...
})
return {
fixedTitle
}
}
获取ref对象真正的值
import { ref } from 'vue'
// 初始化ref对象
const groupRef = ref(null)
// ref对象为一个整数
const scrollY= ref(0)
// 要获取ref对象中的值 记得使用ref_obj.value
if (scrollY.value < 0) { return '' }
模板中应用逻辑文件中的方法
在index-list.vue中:
<div @touchstart.stop.prevent="onShortcutTouchStart">...</div>
import useShortcut from './use-shortcut'
setup(props) {
const { groupRef } = useFixed(props)
// 还可以将其他逻辑文件中返回的对象,当作参数传入其他逻辑处理中
const { onShortcutTouchStart } = useShortcut(props, groupRef)
// 必须在setup中返回才能生效
return {
groupRef,
onShortcutTouchStart,
}
}
在use-shortcut.js中:
export default function useShortcut(props, groupRef) {
function onShortcutTouchStart (e) {
// do...
}
// 模板中要用到的属性与方法一定要返回出去!
return {
onShortcutTouchStart
}
}
获取其他组件、注册事件和使用钩子函数
在scroll.vue中:
<div ref="rootRef">
<!-- 内容插槽 -->
<slot></slot>
</div>
// 注册向外派发的事件
emits: ['scroll'],
props: {
click: {
type: Boolean,
default: true
},
// 决定是否可以监听到向外派发的滚动事件 3就是只要滚动就派发
probeType: {
type: Number,
default: 0
}
},
setup(props, { emit }) {
const rootRef = ref(null)
// 接收到返回的scroll实例,并将返回的实例再暴漏(return)出去
// 之后就可以通过scroll组件的实例,就可以访问到这个scroll变量了
// 并通过这个变量拿到BS的实例了 通过在组件上添加ref拿到组件实例
const scroll = useScroll(rootRef, props, emit)
// 一定要return一个对象包含这个ref才会有效
return {
rootRef,
scroll
}
}
在use-scroll.js中:
import BScroll from '@better-scroll/core/'
import { onMounted, onUnmounted, ref } from 'vue'
export default function useScroll(wrapperRef, options, emit) {
// 闭包中注册一个局部变量
const scroll = ref(null)
onMounted(() => {
// scroll也是一个ref对象,所以他的值要存在value上,才会被数据响应
scroll.value = new BScroll(wrapperRef.value, {
...options
})
scroll.value.on('scroll', (pos) => {
// 向外派发scroll事件 让引用的组件接收
emit('scroll', pos)
})
})
// 对scroll实例卸载逻辑
onUnmounted(() => {
scroll.value.destroy()
})
// 将scroll实例暴漏出去
return scroll
}
在index-list.vue中:
<scroll
@scroll="组件派发的scroll滚动事件"
ref="scrollRef"
>
...
</scroll>
import Scroll from '@/components/base/scroll/scroll'
import useShortcut from './use-shortcut'
setup(props) {
const { scrollRef } = useShortcut(props)
// 一定要记得在setup中返回
return {
scrollRef
}
}
在use-shortcut.js中:
import { ref } from 'vue'
export default function useShortcut(props, groupRef) {
const scrollRef = ref(null)
// scrollRef.value对应的就是scroll组件的实例
// .scroll就是返回的scroll对象 具体操作的话 请console.log打印后查看对象
const scroll = scrollRef.value.scroll
// 这个是better-scroll自带的滚动到元素的方法
scroll.scrollToElement('某个元素', 0)
// 因为可能会返回更多东西,所以使用对象方式
return {
scrollRef
}
}
定义一个ref属性,修改或者使用其值
在setup钩子中,如果定义了一个ref,并想通过它进行判断,必须使用.value。
<audio @canplay="ready"
:data-ok="songReady ? '1' : '2'"
></audio>
setup() {
// 定义一个ref并赋予初始值false
const songReady = ref(false)
function ready() {
// 在js中取值必须使用.value,但是在模板中的话就不需要了
if (songReady.value) {
return
}
// 因为定义了一个ref所以如果要修改它的值必须使用.value
songReady.value = true
}
return {
// 模板中要使用 必须return
songReady,
ready
}
}