Vue Composition API重点

Vue Composition API重点汇总

1.1 小例子

<template>
  <button @click="increment">
    Count is: {{ state.count }}, double is: {{ state.double }}
  button>
template>

<script>
import { reactive, computed } from 'vue'

export default {
  setup() {
    const state = reactive({
      count: 0,
      double: computed(() => state.count * 2)
    })

    function increment() {
      state.count++
    }

    return {
      state,
      increment
    }
  }
}
script>

示例来源

1.2 目标

目前存在的问题

经验所得,Vue当前API会带来以下两类编程模型的限制:

  1. 复杂组件的代码逻辑较为难以推理,代码可读性不高。在某些情况下,通过逻辑考虑来组织代码更有意义。
  2. 缺少用于多个组件之间的提取和重用逻辑的简洁机制。

所以为在组织代码时给用户提供更大的灵活性,有以下目标:

  1. 可以将代码组织为每个函数都处理特定功能的函数,而不必总是通过选项来组织代码。
  2. API使在组件之间,甚至外部组件之间,提取和重用逻辑变得更加简单。

1.3 详细设计

API介绍
  • Reactive State and Side Effects
    声明一些变量
import { reactive } from 'vue'

// reactive state
const state = reactive({
  count: 0
})

reactive与Vue.observable()2.x 中的当前API 等效,返回的state是所有Vue用户都应该熟悉的反应性对象。

Vue中反应状态的基本用例是我们可以在渲染期间使用它。由于依赖关系跟踪,当反应状态更改时,视图会自动更新。
在DOM中渲染某些内容被视为“副作用”:我们的程序正在修改程序本身(DOM)外部的状态。要应用并基于反应状态自动重新应用副作用,我们可以使用watchAPI:

import { reactive, watch } from 'vue'

const state = reactive({
  count: 0
})

watch(() => {
  document.body.innerHTML = `count is ${state.count}`
})
  • Computed State and Refs
    • 有时我们需要依赖于其他状态的状态-在Vue中,这是通过计算属性来处理的。
// 要直接创建一个计算值,我们可以使用computedAPI
import { reactive, computed } from 'vue'

const state = reactive({
  count: 0
})

const double = computed(() => state.count * 2)

// 猜想 computed
function computed(getter) {
  let value
  watch(() => {
    value = getter()
  })
  return value
}

而我们知道value如果是原始类型number,computed一旦返回,其内部更新逻辑的连接将丢失,将值分配给对象作为属性时,也会发生相同的问题。
为了确保我们始终可以读取计算的最新值,我们需要将实际值包装在一个对象中,然后返回该对象:

// 简化代码
function computed(getter) {
  const ref = {
    value: null
  }
  watch(() => {
    ref.value = getter()
  })
  return ref
}

const double = computed(() => state.count * 2)

watch(() => {
  console.log(double.value)
}) // -> 0

state.count++ // -> 2

这double是一个我们称为“ ref”的对象,因为它用作对其持有的内部值的反应性引用。

除了计算的引用外,我们还可以使用refAPI 直接创建普通的可变引用:

const count = ref(0)
console.log(count.value) // 0

count.value++
console.log(count.value) // 1

Ref 是此提案中引入的唯一“新”概念。引入它是为了将反应性值作为变量传递,而不必依赖对的访问 this

  • Ref Unwrapping
  • Usage in Components
  • Lifecycle Hooks
    参考
代码组织
  • 保持代码井井有条的最终目的应该是使代码更易于阅读和理解。

  • “理解”代码,在于理解它运用数据、逻辑,最终解决的逻辑功能问题。

  • 示例
    VueClIUI文件浏览器
    该组件必须处理许多不同的逻辑问题:

    • 跟踪当前文件夹状态并显示其内容
    • 处理文件夹导航(打开,关闭,刷新…)
    • 处理新文件夹的创建
    • 仅切换显示收藏夹
    • 切换显示隐藏文件夹
    • 处理当前工作目录更改
      而在具体代码实现的整个文件的代码组织中,单一逻辑功能的实现过程被分散在文件各个不同部分,导致组件可读性差、难以维护。

Composition API为我们提供了更为灵活并且模块化的代码组织结构。
可以通过以下方式编写“创建新文件夹”功能:
每个逻辑功能点的代码在组合函数中并置在一起。当在大型组件上工作时,这大大减少了对恒定“跳跃”的需求。合成功能也可以在编辑器中折叠,以使组件更易于扫描:

export default {
  setup() { // ...
  }
}

function useCurrentFolderData(networkState) { // ...
}

function useFolderNavigation({ networkState, currentFolderData }) { // ...
}

function useFavoriteFolder(currentFolderData) { // ...
}

function useHiddenFolders() { // ...
}

function useCreateFolder(openFolder) { // ...
}

setup() 现在,该函数主要用作调用所有组合函数的入口点:

export default {
  setup () {
    // Network
    const { networkState } = useNetworkState()

    // Folder
    const { folders, currentFolderData } = useCurrentFolderData(networkState)
    const folderNavigation = useFolderNavigation({ networkState, currentFolderData })
    const { favoriteFolders, toggleFavorite } = useFavoriteFolders(currentFolderData)
    const { showHiddenFolders } = useHiddenFolders()
    const createFolder = useCreateFolder(folderNavigation.openFolder)

    // Current working directory
    resetCwdOnLeave()
    const { updateOnCwdChanged } = useCwdUtils()

    // Utils
    const { slicePath } = usePathUtils()

    return {
      networkState,
      folders,
      currentFolderData,
      folderNavigation,
      favoriteFolders,
      toggleFavorite,
      showHiddenFolders,
      createFolder,
      updateOnCwdChanged,
      slicePath
    }
  }
}
逻辑提取和重用

当涉及跨组件提取和重用逻辑时,Composition API非常灵活地提供了依赖于其参数和全局导入Vue API的功能。

  • 跟踪鼠标位置示例
// 导出文件中
import { ref, onMounted, onUnmounted } from 'vue'

export function useMousePosition() {
  const x = ref(0)
  const y = ref(0)

  function update(e) {
    x.value = e.pageX
    y.value = e.pageY
  }

  onMounted(() => {
    window.addEventListener('mousemove', update)
  })

  onUnmounted(() => {
    window.removeEventListener('mousemove', update)
  })

  return { x, y }
}

// 导入文件中
import { useMousePosition } from './mouse'

export default {
  setup() {
    const { x, y } = useMousePosition()
    // other logic...
    return { x, y }
  }
}
插件开发
  • Vue插件都将属性注入this。例如,Vue Router注入this. r o u t e 和 t h i s . route和this. routethis.router,Vuex注入this.$store。由于每个插件都要求用户增加注入属性的Vue类型,这使得类型推断变得棘手。

  • 使用Composition API时,没有this。相反,插件将充分利用provide并inject在内部和公开的组成功能

参考:插件开发

APIReference

你可能感兴趣的:(前端,Vue,JavaScript)