前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vue3 -- 通过简单示例,聊一聊Composition API

vue3 -- 通过简单示例,聊一聊Composition API

作者头像
奋飛
发布2021-08-30 09:44:58
4980
发布2021-08-30 09:44:58
举报
文章被收录于专栏:Super 前端

在 vue3 版本之前,我们复用组件(或者提取和重用多个组件之间的逻辑),通常有以下几种方式:

  • Mixin:命名空间冲突 & 渲染上下文中暴露的 property 来源不清晰。例如在阅读一个运用了多个 mixin 的模板时,很难看出某个 property 是从哪一个 mixin 中注入的。
  • Renderless Component:无渲染组件需要额外的有状态的组件实例,从而使得性能有所损耗
  • Vuex:就会变得更加复杂,需要去定义 Mutations 也需要去定义 Actions

上述提到的几种方式,也是我们项目中正在使用的方式。对于提取和重用多个组件之间的逻辑似乎并不简单。我们甚至采用了 extend 来做到最大化利用已有组件逻辑,因此使得代码逻辑依赖严重,难以阅读和理解。

Vue3 中的 Composition API 便是解决这一问题;且完美支持类型推导,不再是依靠一个简单的 this 上下文来暴露 property(比如 methods 选项下的函数的 this 是指向组件实例的,而不是这个 methods 对象)。其是一组低侵入式的、函数式的 API,使得我们能够更灵活地「组合」组件的逻辑。

使用 Vue2 和 Vue3 开发组件有很大的差异性:

  • Vue2 开发组件,我们往往通过选项类型组织代码;props => ui state => 事件
  • Vue3 Composition Api 开发组件,基于逻辑关注点组织代码;(响应式)参数 => 生命周期绑定 => 响应式数据(ref、reactive)

下面,通过一个示例代码,结合 Vue2 和 Vue3 来聊聊 Composition Api 。

代码语言:javascript
复制
<template>
  <div>
    <p>当前系统的主题色为 -- {{color}}p>
    <p>当前viewport的宽高比为16:9 -- {{is16than9}}p>
  div>
template>

WEB API

说明

示例

Window.matchMedia()

回一个新的MediaQueryList 对象,表示指定的媒体查询字符串解析后的结果

window.matchMedia(mediaQueryString)

prefers-color-scheme

检测用户是否有将系统的主题色设置为亮色或者暗色

window.matchMedia('(perfers-color-scheme: dark)')

aspect-ratio

可以用来测试 viewport 的宽高比

①:主题色相关 ②:宽高比检测相关

vue2 实现

代码语言:javascript
复制
export default {
    name: 'SystemColor',
    data () {
      return {
        color: '',	// ①
        is16than9: false	// ②
      }
    },
    methods: {
      // ①
      perfersColorSchemeUpdate () {
        this.perfersColorSchemeMedia = window.matchMedia('(perfers-color-scheme: dark)')
        this.color = this.perfersColorSchemeMedia.matches ? 'dark': 'light'
      },
      // ②
      aspectRatioUpdate () {
        this.aspectRatioMedia = window.matchMedia('(aspect-ratio: 16/9)')
        this.is16than9 =  this.aspectRatioMedia.matches
      }
    },
    created () {
      // ①
      this.perfersColorSchemeUpdate()
      this.perfersColorSchemeMedia.addEventListener('change', this.perfersColorSchemeUpdate)
			// ②
      this.aspectRatioUpdate()
      this.aspectRatioMedia.addEventListener('change', this.aspectRatioUpdate)
    },
    destroyed () {
      // ①
    	this.perfersColorSchemeMedia.removeEventListener('change', this.perfersColorSchemeUpdate)
      // ② 
      this.aspectRatioMedia.removeEventListener('change', this.aspectRatioUpdate)
    } 
}

现在的诉求,又有一个新组件我们需要复用 「主题色相关」内容,我们需要对其进行抽离。

在 vue2 中,我们优先想到的是采用 mixins 方式

代码语言:javascript
复制
/* perfersColorSchemeMixin.js */
export default {
  methods: {
    perfersColorSchemeUpdate () {
      this.perfersColorSchemeMedia = window.matchMedia('(perfers-color-scheme: dark)')
      this.color = this.perfersColorSchemeMedia.matches ? 'dark': 'light'
    }
  }
}
代码语言:javascript
复制
import perfersColorSchemeMixin from './perfersColorSchemeMixin.js'
import aspectRatioMixin from './aspectRatioMixin.js'
export default {
  name: 'SystemColor',
  mixins: [perfersColorSchemeMixin, aspectRatioMixin],
  data () {
    return {
      color: '',
      is16than9: false
    }
  },
  created () {
    this.perfersColorSchemeUpdate()
    this.perfersColorSchemeMedia.addEventListener('change', this.perfersColorSchemeUpdate)

    this.aspectRatioUpdate()
    this.aspectRatioMedia.addEventListener('change', this.aspectRatioUpdate)
  },
  destroyed () {
    this.perfersColorSchemeMedia.removeEventListener('change', this.perfersColorSchemeUpdate)
    this.aspectRatioMedia.removeEventListener('change', this.aspectRatioUpdate)
  } 
}

当然我们也可以把 data 以及 created 中的内容也抽离到 mixins 中。但这样会导致模板中使用的变量不知道来自哪个 mixins,且可能存在命名冲突等问题。此时如果我们想再增加第3个新增功能,需要各个地方增加,阅读性变差、难以维护。

正是这种碎片化使得理解和维护一个复杂的组件变得非常困难。选项的强行分离为展示背后的逻辑关注点设置了障碍。此外,在处理单个逻辑关注点时,我们必须不断地在选项代码块之间“跳转”,以找到与该关注点相关的部分。

vue3 composition api

当我们在组件间提取并复用逻辑时,组合式(@vue/runtime-core) API 是十分灵活的。一个组合函数仅依赖它的参数和 Vue 全局导出的 API,而不是依赖其微妙的 this 上下文。你可以将组件内的任何一段逻辑导出为函数以复用它。

  • 基于响应式
  • 提供 vue 的生命周期钩子
  • 组件销毁时自动销毁依赖监听
  • 可复用的逻辑

组件可以变得如此清爽

代码语言:javascript
复制
import { reactive, toRefs } from 'vue'
import usePrefersColorScheme from './usePrefersColorScheme.js'
import useAspectRatio from './useAspectRatio.js'
export default {
  name: 'SystemColor',
  setup () {
    let color = usePrefersColorScheme()	// ① 仅此一处
    let is16than9 = useAspectRatio()		// ② 仅此一处
    return {
      color,
      is16than9
    }
  }
}

下述可组合式函数,建议使用 use 作为函数名的开头,以表示它是一个组合函数

代码语言:javascript
复制
/* ① usePrefersColorScheme.js */
import { ref, onUnmounted, onMounted } from 'vue'
export default function usePrefersColorScheme () {
  let media 
  let color = ref(null)

  const update = () => {
    media = window.matchMedia('(perfers-color-scheme: dark)')
    color.value = media.matches ? 'dark': 'light'
  }
  
  update()
  media.addEventListener('change', update)
  onUnmounted(() => {
    media.removeEventListener('change', update)
  })

  return color
}
代码语言:javascript
复制
/* ② useAspectRatio.js */
import { ref, onUnmounted, onMounted } from 'vue'
export default function usePrefersColorScheme () {
  let media
  let is16than9 = ref(null)

  const update = () => {
    media = window.matchMedia('(aspect-ratio: 16/9)')
    is16than9.value = media.matches
  }
  
  update()
  media.addEventListener('change', update)
  onUnmounted(() => {
    media.removeEventListener('change', update)
  })

  return is16than9
}

这些组合函数里面他都可以使用生命周期的钩子,可以自动更新和自动注销。在使用的时候也就没有了负担,只需要去留意每一个 ref 对应什么样的功能,其更好的提高代码的复用度、可读性、可维护性。

相比而言,组合式 API:

  • 暴露给模板的 property 来源十分清晰,因为它们都是被组合逻辑函数返回的值
  • 不存在命名空间冲突,可以通过解构任意命名
  • 不再需要仅为逻辑复用而创建的组件实例

其他

Vue 3 已经可以使用的有两个主要的逻辑的组件库,vueusevue-composable

  • vueuse:提供了更加细粒度的 Web API 以及工具分装
  • vue-composable:提供了更多常用的逻辑封装。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/11/20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • vue2 实现
  • vue3 composition api
  • 其他
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档