Vue3-setup

升级脚手架

1
2
3
npm i @vue/cli -g

vue create 项目名称

composition api (组合API)概念

  • 组合API
  • 框架层面的
  • 把 api 拆分成一个个 hook(钩子) → 最后组合起来形成 → Vue3.0 Composition API 框架设计模式
1
2
import { watch, ref, toRef, onMounted, computed } from 'vue';
// 在 setup 中使用 composition api

setup

存在意义

setup 的存在,就是为了能够在其中使用 Composition API

🌈 调用时机

props 初始化完毕之后,beforeCreate 之前被调用

基本使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<div>{{ count }}</div>
</template>

<script>
export default {
name: 'App',
setup() {
return {
count: 0
}
},
}
</script>

返回值

  • return 一个对象,对象中的属性会被合并到 render 函数的上下文中供 template 使用
  • return 一个render函数,可以渲染模板

render function

  • 可以把 template 删掉,在 setup 中直接 return 一个函数渲染模板
1
2
3
4
5
6
7
8
9
10
11
12
<script>

import { ref, h } from 'vue';

export default {
name: 'App',
setup() {
const count = ref(0);
return () => h('h1', [count.value]);
}
}
</script>

render JSX

1
2
3
4
5
6
7
8
<script>
export default {
name: 'App',
setup() {
return () => <div>123</div>;
}
}
</script>

参数

  • props 接收的属性
    • 不要在 **setup** 中解构 props ,会导致 props 被解构的值丧失响应式
      • setup({ title })
      • const { title } = props
  • context 上下文选项列表
    • attrs
    • slots
    • emit
    • expose
  • 为什么不把 props 和 context 合并在一起当一个参数
    • props 使用比 attrs、emit 更频繁
    • 可以更好的为 props 做类型推断(TS)

props

父组件 App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<template>
<div>
<Test :title="title" />
</div>
</template>

<script>

import { ref, h } from 'vue';
import Test from '@/components/Test';

export default {
name: 'App',
setup() {
const title = ref('Lance');
setTimeout(() => {
title.value = 'Lance233';
}, 1000);
return {
title
};
},
components: {
Test
}
}
</script>

子组件 Test.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<template>
<h1>{{ title }}</h1>
</template>

<script>
import { watch, watchEffect } from 'vue';
export default {
name: 'Test',
props: {
title: String
},
setup(props) {
console.log(props); // Proxy { title: 'Lance' }
watchEffect(() => {
console.log('title:', props.title); // 初始化Lance和变化后Lance233都能监听到
});

watch(() => {
return props.title; // 要监听的值
}, (newVal) => {
console.log('new Title:', newVal); // 只会监听变化后的值
});
}
}
</script>

context

  • 区别于 props ,可以被解构
    • setup(props, { attrs, slots })
    • const { attrs, slots } = context
  • 包含选项列表
    • attrs
    • slots
    • emit
    • expose
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
<h1>{{ title }}</h1>
</template>

<script>
export default {
name: 'Test',
props: {
title: String
},
setup(props, context) {
console.log(context);
}
}
</script>

attrs

  • ctx.attrs
  • return 的时候最好别展开
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<template>
<h1>{{ attrs.title }}</h1>
</template>

<script>
export default {
name: 'Test',
// props: {
// title: String
// },
setup(props, context) {
console.log(context.attrs); // 有 title 了
// 注意得把 props 中的 title 注释掉,才能出现在 attrs 中
return {
attrs: context.attrs
}
}
}
</script>
  • 展开后就没有响应式了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<h1>{{ title }}</h1>
</template>

<script>
export default {
name: 'Test',
setup(props, context) {
return {
...context.attrs // 展开后就没有响应式了
}
}
}
</script>

emit

  • ctx.emit('事件名', 值)
  • 注册: emits: ['事件名']

父组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template>
<div>
<Test :count="count" @plus="plus" />
</div>
</template>

<script>

import { ref } from 'vue';
import Test from '@/components/Test';

export default {
name: 'App',
setup() {
const count = ref(0);
const plus = num => count.value += num;
return { count, plus };
},
components: { Test }
}
</script>

子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<template>
<div>{{ count }}</div>
<button @click="plus">增加</button>
</template>

<script>
export default {
name: 'Test',
props: {
count: Number
},
emits: ['plus'],
setup(props, ctx) {
const plus = () => ctx.emit('plus', 100);
return { plus }
}
}
</script>

setup 中的ctx与getCurrentInstance中的ctx的区别

1
2
3
4
5
6
export default {
setup(props, ctx) {
console.log(ctx); // 当前setup执行的时候的一个上下文
console.log(getCurrentInstance().ctx); // 当前组件实例的执行上下文
}
}

🌈 setup 中 this 为 undefined

  • setup 在组件实例化完成之前,是拿不到当前组件实例的(props之后,beforeCreate之前)