最近我们项目是 vue2,但是要使用 jsx + composition ,所以来学习一下这个 vue/composition-api
(一)安装
- npm install @vue/composition-api
- # or
- yarn add @vue/composition-api
(二)注册
在 main.ts 中
- import VueCompositionAPI from '@vue/composition-api'
-
- Vue.use(VueCompositionAPI)
(三)使用
最基本的组件:
- <template>
- <div>HelloWorld</div>
- </template>
-
- <script>
- import { defineComponent } from '@vue/composition-api'
-
- export default defineComponent({
- setup() {
-
- },
- })
- </script>
-
- <style scoped>
-
- </style>
defineComponent 本身的功能很简单,但是最主要的功能是为了 ts 下的类型推导~
1. setup 函数
setup 在 create 实例在初始化之前调用(setup 函数中不存在 this)。页面上的 属性、方法要从 setup 中拿,需要 setup 中这些属性方法都 return 出去。
- <template>
- <div>
- <div>{{ name }}</div>
- <div @click="sayHello">打招呼</div>
- <div @click="sayGoodBye">说再见</div>
- </div>
- </template>
-
- <script>
- import { defineComponent } from '@vue/composition-api'
-
- export default defineComponent({
- setup() {
- // 先注册
- const sayGoodBye = () => {
- console.log('sayGoodBye')
- }
- return {
- name: 'zfb',
- sayHello: () => {
- console.log(`hello,`)
- },
- sayGoodBye,
- }
- },
- })
- </script>
-
- <style scoped>
-
- </style>
2. 相应式 ref,reactive
使用 ref、reactive 可以使数据变化时,触发页面的更新。ref 处理基础类型数据,是单一的
改变的时候 改变 .value
在 @vue/composition-api 中,ref 页面模版渲染是需要 .value 的,reactive 不用
- <template>
- <div>
- <div>{{ name.value }}</div>
- <div @click="changeName">改变name</div>
- </div>
- </template>
-
- <script>
- import { defineComponent, ref } from '@vue/composition-api'
-
- export default defineComponent({
- setup () {
- // 把 name 变成 响应式的 defineObjectProperty
- let name = ref('zfb')
-
- // 改变的时候改变 监听的 value
- const changeName = () => {
- name.value = 'zfb hello'
- }
-
- return {
- name,
- changeName,
- }
- },
- })
- </script>
-
- <style scoped>
-
- </style>
reactive 处理集合
- <template>
- <div>
- <div>{{person.name}}</div>
- <div>{{person.age}}</div>
- <div>{{person.sex}}</div>
- </div>
- </template>
-
- <script>
- import { defineComponent, reactive } from '@vue/composition-api'
-
- export default defineComponent({
- setup () {
- // 把 person 变成 响应式的 defineObjectProperty
- let person = reactive({
- name: 'lyf',
- sex: '女',
- age: '35'
- })
-
- setTimeout(() => {
- person.sex = '男'
- }, 2000)
-
- return {
- person,
- }
- },
- })
- </script>
-
- <style scoped>
-
- </style>
对于数组:
- <template>
- <div>
- <div>{{arr.value}}</div>
- <div>{{arr1.value}}</div>
- <div>{{arr2.value}}</div>
- <div>{{arr3.data}}</div>
- </div>
- </template>
-
- <script>
- import { defineComponent, ref, reactive } from '@vue/composition-api'
-
- export default defineComponent({
- setup () {
- // 把 person 变成 响应式的 defineObjectProperty
- let arr = ref(['123','456','789'])
- let arr1 = ref([1])
- let arr2 = ref([1, 2, 3])
- let arr3 = reactive({
- data: [3, 4, 5]
- })
- setTimeout(() => {
- arr.value = ['000','456','789']
- arr1.value.push(2)
- arr2.value.splice(0, 1, 4)
- arr3.data.push(7)
- }, 2000)
-
- return {
- arr,
- arr1,
- arr2,
- arr3
- }
- },
- })
- </script>
-
- <style scoped>
-
- </style>
readonly 只读:
- <script>
- import { defineComponent, ref, reactive, readonly } from '@vue/composition-api'
-
- export default defineComponent({
- setup () {
- const original = reactive({
- countA: 0,
- foo: {
- countB: 0,
- }
- })
- const copy = readonly(original);
-
- original.countA++;
- copy.countA++; // 警告
- original.foo.countB++;
- copy.foo.countB++; // 警告
-
- console.log(original.countA); // 2
- console.log(copy.countA); // 2
- console.log(original.foo.countB); // 2
- console.log(copy.foo.countB); // 2
- }
- })
- </script>
-
- <style scoped>
能修改 但是会警告
3. toRefs
- <template>
- <div>
- <!-- 变成了 ref 需要.value
- 但是如果在 vue3 中不用 -->
- <div>{{ name.value }}</div>
- <div>{{ age.value }}</div>
- <div>{{ sex.value }}</div>
- </div>
- </template>
-
- <script>
- import { defineComponent, reactive, toRefs } from '@vue/composition-api'
-
- export default defineComponent({
- setup () {
- // 把 person 变成 响应式的 defineObjectProperty
- let person = reactive({
- name: 'lyf',
- sex: '女',
- age: '35'
- })
-
- setTimeout(() => {
- person.sex = '男'
- }, 2000)
-
- // 解构的时候都转换成 ref 的形式
- // 不然不具备响应式
- const { name, sex, age } = toRefs(person)
-
- return {
- name, sex, age
- }
- },
- })
- </script>
-
- <style scoped>
-
- </style>
4. toRef
toRefs 改变的时候,对象上面是有属性的,但是不排除对象上面一开始没有这个属性的情况,这个时候就需要用到 toRef
没有使用 toRef 的时候:
- <template>
- <div>
- <!-- 变成了 ref 需要.value
- 但是如果在 vue3 中不用 -->
- <div>{{ name.value }}</div>
- <div>{{ age.value }}</div>
- <div>{{ sex.value }}</div>
- <div>{{ sex.hobby }}</div>
- </div>
- </template>
-
- <script>
- import { defineComponent, reactive, toRefs } from '@vue/composition-api'
-
- export default defineComponent({
- setup () {
- // 把 person 变成 响应式的 defineObjectProperty
- let person = reactive({
- name: 'lyf',
- sex: '女',
- age: '35'
- })
-
- // 解构的时候都转换成 ref 的形式
- const { name, sex, age, hobby } = toRefs(person)
-
- // 刚开始没有 hobby 但是后来又有了
- // 这个时候发现页面上 2s 之后是不会出现hobby的
- setTimeout(() => {
- person.hobby = 'ch'
- }, 2000)
-
-
- return {
- name, sex, age, hobby
- }
- },
- })
- </script>
-
- <style scoped>
-
- </style>
使用 toRef
- <template>
- <div>
- <!-- 变成了 ref 需要.value
- 但是如果在 vue3 中不用 -->
- <div>{{ name.value }}</div>
- <div>{{ age.value }}</div>
- <div>{{ sex.value }}</div>
- <div>{{ hobby.value }}</div>
- </div>
- </template>
-
- <script>
- import { defineComponent, reactive, toRef, toRefs } from '@vue/composition-api'
-
- export default defineComponent({
- setup () {
- // 把 person 变成 响应式的 defineObjectProperty
- let person = reactive({
- name: 'lyf',
- sex: '女',
- age: '35'
- })
-
- // 解构的时候都转换成 ref 的形式
- const { name, sex, age, } = toRefs(person)
-
- // 针对原本对象上没有的情况
- let hobby = toRef(person, 'hobby')
-
- // 刚开始没有 hobby 但是后来又有了
- // 这个时候发现页面上 2s 之后会出现hobby的
- setTimeout(() => {
- hobby.value = 'ch'
- }, 2000)
-
-
- return {
- name, sex, age, hobby
- }
- },
- })
- </script>
-
- <style scoped>
-
- </style>
但是还是建议,初始化的时候,给一个空的
- let person = reactive({
- name: 'lyf',
- sex: '女',
- age: '35',
- hobby: ''
- })