前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue3.0 不畏惧祖传代码的 Composition API

Vue3.0 不畏惧祖传代码的 Composition API

原创
作者头像
用户1890129
修改2020-12-16 14:41:46
5050
修改2020-12-16 14:41:46
举报
文章被收录于专栏:前端学习之路

Hello,大家好,我是李白~~

昨晚写这篇文章的时候,隔壁在聚餐,几位女生欢聚一堂,整个楼层充满了欢声笑语的味道,就好像早上刷牙刷一半就跑去吃了个鸡蛋。

隐隐约约传来了菜刀与菜板的碰撞声,这刀切的技术似乎略输我一筹。

可就算再怎么样,她们也是一群人吃饭啊。而我只能吃两桶泡面,且还能吃出优越感来~~

可叹可叹,心里还是挺羡慕的,羡慕有一起说说笑笑、一起吃饭的人。

也有点心酸,心酸自己,啥也不是,啥也没有,代码写得再6又有何用、有何用、有何用!!!

但我相信,厨艺肯定没有我好!!!!写代码也没我厉害!!!!身高也是我最高!!!(对着电脑,含泪写的文章 ε(┬┬﹏┬┬)3

还请阁下高抬贵手,点个赞~~ 还请大佬口下留情,勿喷我~~

## 使用 Composition API

> Composition API 构建于响应式 API 之上,实现了类似于 `React hook` 的逻辑组成与复用,相较于 2.x 基于对象的 API 方式来说,拥有更加灵活的代码组织模式,以及更为可靠的类型推断能力。可解决 `Vue` 在大规模应用场景中的痛点。

例如:以往写代码的时候,每一个功能会有n个变量和n个方法,分散在各个地方,维护起来苦不堪言,而它的出现就是为了解决这个问题。

开始王炸,简洁明了的对比图献上~~(素材来源[@蜗牛老湿_大圣](https://juejin.im/user/1556564194370270),加上我**李白精通PS**二次优化的图)

![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bf6d436df9fb46848b4bdc5a468604f4~tplv-k3u1fbpfcp-zoom-1.image)

![](https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/5bb5b09f64e7425ba918df3f91c1eb79~tplv-k3u1fbpfcp-zoom-1.image)

![](https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/cec6ec0da61d446c819b338d8d38d6a9~tplv-k3u1fbpfcp-zoom-1.image)

看不懂??没关系

我们再来看一下代码,以示区别,先实现一个经典的“计时器功能”:

```html

<template>

<div>{{count}}: {{double}}</div>

<button @click="increment">+1</button>

</template>

```

```js

// Vue2 写法

export default {

data(){

return {

count: 0

}

},

methods: {

increment() {

this.count++;

}

},

computed: {

double() {

return this.count * 2;

}

}

}

```

上面这种写法,想必大家再熟悉不过了,在组件中实现一个功能,最少得包含这么多的代码块。

这种碎片化使得难以理解和维护复杂的组件。如果需要查找某个功能的逻辑,就得在这个组件里面不断滚动查看代码,看完这个逻辑,忘记前面那个逻辑,来来回回就差砸电脑了。

```js

// Vue3 Composition API

import { ref, computed } from 'vue'

export default {

setup() {

let count = ref(0)

let double = computed(() => count.value * 2)

function increment() {

count.value++

}

return {

count,

double,

increment

}

}

}

```

这样是不是简单多了,没有像`vue2`那么多函数块的规矩,直接就是一把梭哈。不过还有更简洁的,有请往下看~~

**代码+图片**,这要是再看不懂,就别怪我口下不留人了。(我转行了,你们自个玩去吧~)

## 代码封装、复用

`Composition API` 最核心的,就是可以把代码提取出来,把整个功能封装成一个单独的函数(模块),随处可用,也不用担心**变量和方法的命名冲突**。

只需在组件中导入模块,并调用它即可(模块返回的是函数),函数将返回我们定义的变量,随后我们可以从 `setup` 函数中使用它们。

```js

// useCount.js

import { ref, computed } from 'vue'

function useCount() {

let count = ref(0)

let double = computed(() => count.value * 2)

function increment() {

count.value++

}

return {

count,

double,

increment

}

}

export default useCount

// app.vue

import useCount from './useCount.js'

export default {

setup() {

let { count, double, increment } = useCount()

return {

count,

double,

increment

}

}

}

```

## 两者并存

`option`和`Composition API`是可以共用的,互不影响。

vue2中`data`、`computed`等选项仍然支持,但使用`setup`时不建议再使用vue2中的`data`等选项。

```js

import { ref, computed } from 'vue'

export default {

setup() {

let count = ref(0)

let double = computed(() => count.value * 2)

function increment() {

count.value++

}

return {

count,

double,

increment

}

},

data() {

return {

a: 2

}

},

mounted() {

// 可使用setup的返回值

console.log(this)

}

}

```

## setup 函数

- 执行机制

`setup`是在创建组件实例并完成`props`初始化之后执行的,也是在`beforeCreate`钩子之前执行,无法访问option(`data`、`comupted`、`methods`等)选项,而option可使用`setup`中返回的变量。

- 没有 `this`:在解析其他组件选项之前就已经调用了 `setup()`

- 接受两个参数:

- props:组件传参

- context:执行上下文,包含三个属性方法:`attrs`、`slots`、`emit`

```js

export default {

props: {

user: {

type: String,

defalut: 'Libai'

}

},

setup(props, context) {

console.log(props.user)

console.log(context)

}

}

```

- 生命周期

其内部使用**生命周期钩子**需要在前面加上**on**

因为 `setup` 是围绕 `beforeCreate` 和 `created` 生命周期钩子运行的,所以不需要显式地定义它们。换句话说,在这些钩子中编写的任何代码都应该直接在 `setup` 函数中编写。

```js

import { onMounted } from 'vue'

export default {

setup() {

// mounted

onMounted(() => {

console.log('Component is mounted!')

})

}

}

```

钩子函数 | stup使用

------------- | -------------

beforeCreate | 不支持

created | 不支持

beforeMount | onBeforeMount

mounted | onMounted

beforeUpdate | onBeforeUpdate

updated | onUpdated

beforeUnmount | onBeforeUnmount

unmounted | onUnmounted

errorCaptured | onErrorCaptured

renderTracked | onRenderTracked

renderTriggered | onRenderTriggered

- 渲染函数

`setup` 还可以返回一个渲染函数,该函数可以直接使用在同一作用域中声明的响应式状态:

```js

// MyBook.vue

import { h, ref, reactive } from 'vue'

export default {

setup() {

const readersNumber = ref(0)

const book = reactive({ title: 'Vue 3 Guide' })

// Please note that we need to explicitly expose ref value here

return () => h('div', [readersNumber.value, book.title])

}

}

```

## provide & inject

类似于vue2中`provide`与`inject`, vue3提供了对应的`provide`与`inject` API,实现组件传参。

provide 函数允许你通过两个参数定义 property:

- property 的 name (`<String>` 类型)

- property 的 value

```html

<!-- src/components/MyMap.vue -->

<template>

<MyMarker />

</template>

<script>

import { provide } from 'vue'

import MyMarker from './MyMarker.vue'

export default {

components: {

MyMarke

},

setup() {

provide('location', 'North Pole')

provide('geolocation', {

longitude: 90,

latitude: 135

})

}

}

</script>

```

`inject` 函数有两个参数:

- 要注入的 `property` 的名词

- 一个默认的值 (可选)

```html

<!-- src/components/MyMarker.vue -->

<script>

import { inject } from 'vue'

export default {

setup() {

const userLocation = inject('location', 'The Universe')

const userGeolocation = inject('geolocation')

return {

userLocation,

userGeolocation

}

}

}

</script>

```

## watch & computed

- watch:侦听器,接受三个参数

- 一个响应式引用或我们想要侦听的 getter 函数

- 一个回调

- 可选的配置选项

```js

import { ref, watch } from 'vue'

export default {

setup() {

const counter = ref(0)

watch(counter, (newValue, oldValue) => {

console.log('The new counter value is: ' + counter.value)

})

},

// setup中的相当于以下

data() {

return {

counter: 0

}

},

watch: {

counter(newValue, oldValue) {

console.log('The new counter value is: ' + this.counter)

}

}

}

```

`watch`的第三个参数,可配置选项:

```js

{

deep: true, // 深度监听

lazy: true, // vue中的immediate,默认挂载后执行

flush: '', // 三个值:'post'(默认), 'pre', 'sync'

// 'pre': 表示在状态更新时同步调用

// 'sync':表示在组件更新之前调用

onTrack(){}, // 在reactive属性或ref被追踪为依赖时调用。

onTrigger(){} // 在watcher的回调因依赖改变而触发时调用。

}

```

- computed

与vue2中`computed`功能一致,它接收一个函数并返回一个`value`为`getter`返回值的不可改变的响应式`ref`对象。

```js

const count = ref(1)

const plusOne = computed(() => count.value + 1)

console.log(plusOne.value) // 2

plusOne.value++ // 错误,computed不可改变

// 同样支持set和get属性

onst count = ref(1)

const plusOne = computed({

get: () => count.value + 1,

set: val => { count.value = val - 1 }

})

plusOne.value = 1

console.log(count.value) // 0

```

## 总结

任何事物都有两面性,再完美的背后也会有黑暗存在。暂时还不知道`Composition API`有何弊端,先告辞了~~

小白写文,如写得不好,还请给个建议~~ 如果对你有帮助的话,还请点个赞~~

如果有下一篇文章的话,应该就是响应式了。

更多信息分享:

- [全面分析toString与valueOf,并随手解决掉几道大厂必备面试题](https://juejin.im/post/6873215243804213262)

- [不会写作的程序猿不是一个好程序猿](https://raindays.cn/)

- [一个基于vuepress的前端学习笔记,记录,只是为了更好的摸鱼](https://github.com/wsydxiangwang/Note)

- [Vue、Nuxt服务端渲染、NodeJS全栈项目~面向小白的完美系统~](https://juejin.im/post/6845166890436788232)

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档