重学vue3-逻辑复用

239 阅读3分钟

组合式函数

“组合式函数”(Composables) 是一个利用 Vue 的组合式 API 来封装和复用有状态逻辑的函数。

可以更好的复用和改善代码结构

使用异步状态示例进行说明

// fetch.js
import { ref, watchEffect, toValue } from 'vue'

//组合式函数可以接受参数,ref、getter函数都可以
//组合式函数约定用驼峰命名法命名,并以“use”作为开头。
export function useFetch(url) {
  const data = ref(null)
  const error = ref(null)

  const fetchData = () => {
    // reset state before fetching..
    data.value = null
    error.value = null

    // 使用toValue函数 如果 url 是一个 ref 或 getter,
    // 将返回它的规范化值。 
    // 否则原样返回。
    fetch(toValue(url))
      .then((res) => res.json())
      .then((json) => (data.value = json))
      .catch((err) => (error.value = err))
  }

  //可以使用`watch()` 显式地监视 ref 或 getter,或者使用 `watchEffect()` 
  watchEffect(() => {
    fetchData()
  })
  
  //返回一个包含多个 ref 的普通的非响应式对象,这样该对象在组件中被解构为 ref 之后仍可以保持响应性
  return { data, error }
}

在组件中使用的方式如下: 每一个调用 useFetch() 的组件实例会创建其独有的 dataerror 状态拷贝,因此他们不会互相影响。

const url = ref('/initial-url')

//data,error是两个ref
const { data, error } = useFetch(url)

// 这将会重新触发 fetch
url.value = '/new-url'

补充一点computed的缓存结果和惰性求值

这是一个useFetch的示例

image.png

image.png

自定义指令

一个自定义指令由一个包含类似组件生命周期钩子的对象来定义。钩子函数会接收到指令所绑定元素作为其参数。

自定义指令主要是为了重用涉及普通元素的底层 DOM 访问的逻辑

在模版中使用

<script setup>
// 在模板中启用 v-focus
const vFocus = {
  mounted: (el) => el.focus()
}
</script>

<template>
  <input v-focus />
</template>

在组件中使用 始终应用于组件的根节点,和透传 attributes类似,组件有多个根组件时,指令会被忽略并警告,不建议在组件上使用自定义指令

<MyComponent v-demo="test" />
<!-- MyComponent 的模板 -->

<div> <!-- v-demo 指令会被应用在此处 -->
  <span>My component content</span>
</div>

全局注册

// 使 v-focus 在所有组件中都可用
app.directive('focus', { /* ... */ })

指令钩子

const myDirective = {
  // 在绑定元素的 attribute 前
  // 或事件监听器应用前调用
  created(el, binding, vnode, prevVnode) {
    // 下面会介绍各个参数的细节
  },
  // 在元素被插入到 DOM 前调用
  beforeMount(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都挂载完成后调用
  mounted(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件更新前调用
  beforeUpdate(el, binding, vnode, prevVnode) {},
  // 在绑定元素的父组件
  // 及他自己的所有子节点都更新后调用
  updated(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载前调用
  beforeUnmount(el, binding, vnode, prevVnode) {},
  // 绑定元素的父组件卸载后调用
  unmounted(el, binding, vnode, prevVnode) {}
}

钩子参数

  • el:指令绑定到的元素。这可以用于直接操作 DOM。

  • binding:一个对象,包含以下属性。

    • value:传递给指令的值。例如在 v-my-directive="1 + 1" 中,值是 2
    • oldValue:之前的值,仅在 beforeUpdate 和 updated 中可用。无论值是否更改,它都可用。
    • arg:传递给指令的参数 (如果有的话)。例如在 v-my-directive:foo 中,参数是 "foo"
    • modifiers:一个包含修饰符的对象 (如果有的话)。例如在 v-my-directive.foo.bar 中,修饰符对象是 { foo: true, bar: true }
    • instance:使用该指令的组件实例。
    • dir:指令的定义对象。

举例:

<div v-demo="{ color: 'white', text: 'hello!' }"></div>
app.directive('demo', (el, binding) => {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text) // => "hello!"
})
  • vnode:代表绑定元素的底层 VNode。

  • prevNode:代表之前的渲染中指令所绑定元素的 VNode。仅在 beforeUpdate 和 updated 钩子中可用。

简化形式

仅需要在 mounted 和 updated上实现相同的行为

<div v-color="color"></div>
app.directive('color', (el, binding) => {
  // 这会在 `mounted` 和 `updated` 时都调用
  el.style.color = binding.value
})