Mrcdh技术博客 Mrcdh技术博客
首页
  • Html5
  • Javascript
  • Nodejs
  • electron
  • Android
  • 微信公众号
  • 框架
  • 其他
  • Mysql
  • PHP
  • Python
  • java
  • Gulp
  • 其它
  • 网站
  • 资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Mrcdh

全栈开发小学生
首页
  • Html5
  • Javascript
  • Nodejs
  • electron
  • Android
  • 微信公众号
  • 框架
  • 其他
  • Mysql
  • PHP
  • Python
  • java
  • Gulp
  • 其它
  • 网站
  • 资源
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • element-ui

    • 基于 VUE 和 element-ui 的树形穿梭框组件 el-tree-transfer
    • element-ui常见问题
  • vue3

  • vue实现图片文件的显示和上传
  • composition-api
    • 安装
      • NPM
      • CDN
    • TypeScript 支持
      • JSX/TSX
    • SSR
    • 浏览器兼容性
    • 限制
      • Ref 自动展开 (unwrap)
      • 模板 Refs
      • Reactive
      • Watch
      • createApp
      • shallowReadonly
      • readonly
      • props
      • computed().effect
      • 缺失的 API
      • 在 data() 中使用组合式 API
      • emit 选项
      • 性能影响
  • vue常用eslint配置模板
  • vue.config.js常用配置
  • vuepress-theme-vdoing本站使用主题
  • vue常见问题
  • 常用插件

  • 《Vuejs》
mrcdh
2021-12-17
目录

composition-api

# @vue/composition-api

用于提供 组合式 API 的 Vue 2 插件.

npm (opens new window) GitHub Workflow Status (opens new window)

English | 中文 ・ 组合式 API 文档 (opens new window)

# 安装

# NPM

npm install @vue/composition-api
# or
yarn add @vue/composition-api
1
2
3

在使用 @vue/composition-api 前,必须先通过 Vue.use() 进行安装。之后才可使用新的 组合式 API (opens new window) 进行组件开发。

import Vue from "vue";
import VueCompositionAPI from "@vue/composition-api";

Vue.use(VueCompositionAPI);
1
2
3
4
// 使用 API
import { ref, reactive } from "@vue/composition-api";
1
2

💡 当迁移到 Vue 3 时,只需简单的将 @vue/composition-api 替换成 vue 即可。你现有的代码几乎无需进行额外的改动。

# CDN

在 Vue 之后引入 @vue/composition-api ,插件将会自动完成安装。

<script src="https://cdn.jsdelivr.net/npm/vue@2.6"></script>
<script src="https://cdn.jsdelivr.net/npm/@vue/composition-api@1.4.1"></script>
1
2

@vue/composition-api 将会暴露在全局变量 window.VueCompositionAPI 中。

const { ref, reactive } = VueCompositionAPI;
1

# TypeScript 支持

本插件要求使用 TypeScript 4.2 或以上版本

为了让 TypeScript 在 Vue 组件选项中正确地进行类型推导,我们必须使用 defineComponent 来定义组件:

import { defineComponent } from "@vue/composition-api";

export default defineComponent({
  // 类型推断启用
});
1
2
3
4
5

# JSX/TSX

JSX 现已在 vuejs/jsx (opens new window) 中官方支持。你可以根据这篇文档 (opens new window)开启支持。你也可以使用由 @luwanquan (opens new window) 维护的社区版本 babel-preset-vca-jsx (opens new window)。

对于 TSX 支持,请在你的项目中创建如下声明文件:

// file: shim-tsx.d.ts
import Vue, { VNode } from "vue";
import { ComponentRenderProxy } from "@vue/composition-api";

declare global {
  namespace JSX {
    interface Element extends VNode {}
    interface ElementClass extends ComponentRenderProxy {}
    interface ElementAttributesProperty {
      $props: any; // specify the property name to use
    }
    interface IntrinsicElements {
      [elem: string]: any;
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# SSR

尽管 Vue 3 暂时没有给出确定的 SSR 的 API,这个插件实现了 onServerPrefetch 生命周期钩子函数。这个钩子允许你使用传统 API 中的 serverPrefetch 函数。

import { onServerPrefetch } from "@vue/composition-api";

export default {
  setup(props, { ssrContext }) {
    const result = ref();

    onServerPrefetch(async () => {
      result.value = await callApi(ssrContext.someId);
    });

    return {
      result,
    };
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 浏览器兼容性

@vue/composition-api 支持所有现代浏览器以及 IE11+。对于更低版本的 IE 浏览器你需要安装WeakMap polyfill (例如使用 core-js库)。

# 限制

✅ 支持     ❌ 不支持

# Ref 自动展开 (unwrap)

❌ 不要 在数组中使用含有 ref 的普通对象

const a = {
  count: ref(0),
};
const b = reactive({
  list: [a], // `a.count` 不会自动展开!!
});

// `count` 不会自动展开, 须使用 `.value`
b.list[0].count.value === 0; // true
1
2
3
4
5
6
7
8
9
const b = reactive({
  list: [
    {
      count: ref(0), // 不会自动展开!!
    },
  ],
});

// `count` 不会自动展开, 须使用 `.value`
b.list[0].count.value === 0; // true
1
2
3
4
5
6
7
8
9
10

✅ 在数组中,应该 总是将 ref 存放到 reactive 对象中

const a = reactive({
  count: ref(0),
});
const b = reactive({
  list: [a],
});
// 自动展开
b.list[0].count === 0; // true

b.list.push(
  reactive({
    count: ref(1),
  })
);
// 自动展开
b.list[1].count === 1; // true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

⚠️ set 和 del 添加与刪除响应式属性变通方案

⚠️ 警告: set 和 del 并非 Vue 3 的一部分。由于 Vue 2.x 响应式系统的限制 (opens new window),我们在插件中提供该 API 作为添加响应式属性的一个变通方案。在 Vue 3 中,你只需要直接为属性赋值即可。

import { reactive, set } from "@vue/composition-api";

const a = reactive({
  foo: 1,
});

// 添加新的响应式属性
set(a, "bar", 1);

// 刪除属性并触发响应式更新
del(a, "bar");
1
2
3
4
5
6
7
8
9
10
11

# 模板 Refs

✅ 字符串 ref && 从 setup() 返回 ref

<template>
  <div ref="root"></div>
</template>

<script>
  export default {
    setup() {
      const root = ref(null);

      onMounted(() => {
        // 在初次渲染后 DOM 元素会被赋值给 ref
        console.log(root.value); // <div/>
      });

      return {
        root,
      };
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

✅ 字符串 ref && 从 setup() 返回 ref && 渲染函数 / JSX

export default {
  setup() {
    const root = ref(null);

    onMounted(() => {
      // 在初次渲染后 DOM 元素会被赋值给 ref
      console.log(root.value); // <div/>
    });

    return {
      root,
    };
  },
  render() {
    // 使用 JSX
    return () => <div ref="root" />;
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

❌ 函数 ref

<template>
  <div :ref="el => root = el"></div>
</template>

<script>
  export default {
    setup() {
      const root = ref(null);

      return {
        root,
      };
    },
  };
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

❌ 在 setup() 中的渲染函数 / JSX

export default {
  setup() {
    const root = ref(null);

    return () =>
      h("div", {
        ref: root,
      });

    // 使用 JSX
    return () => <div ref={root} />;
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13

⚠️ $refs 访问的变通方案

⚠️ 警告: SetupContext.refs 并非 Vue 3.0 的一部分, @vue/composition-api 将其暴露在 SetupContext 中只是临时提供一种变通方案。

如果你依然选择在 setup() 中写 render 函数,那么你可以使用 SetupContext.refs 来访问模板引用,它等价于 Vue 2.x 中的 this.$refs:

export default {
  setup(initProps, setupContext) {
    const refs = setupContext.refs;
    onMounted(() => {
      // 在初次渲染后 DOM 元素会被赋值给 ref
      console.log(refs.root); // <div/>
    });

    return () =>
      h("div", {
        ref: "root",
      });

    // 使用 JSX
    return () => <div ref="root" />;
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

如果项目使用了 TypeScript,你还需要扩展 SetupContext 类型:

import Vue from "vue";

declare module "@vue/composition-api" {
  interface SetupContext {
    readonly refs: { [key: string]: Vue | Element | Vue[] | Element[] };
  }
}
1
2
3
4
5
6
7

# Reactive

⚠️ reactive() 会返回一个修改过的原始的对象

此行为与 Vue 2 中的 Vue.observable 一致

💡 在 Vue 3 中,reactive() 会返回一个新的的代理对象

# Watch

❌ 不支持 onTrack 和 onTrigger 选项

watch(
  () => {
    /* ... */
  },
  {
    immediate: true,
    onTrack() {}, // 不可用
    onTrigger() {}, // 不可用
  }
);
1
2
3
4
5
6
7
8
9
10

# createApp

⚠️ createApp() 是全局的

在 Vue3 中,引入了 createApp() 来隔离不同应用实例的上下文(plugin, components 等)。 由于 Vue2 的设计,在这个插件中,我们提供 createApp() 作为一个向前兼容的 API ,它只是全局的一个别名。

const app1 = createApp(RootComponent1);
app1.component("Foo", Foo); // 相当于 Vue.component('Foo', Foo)
app1.use(VueRouter); // 相当于 Vue.use(VueRouter)

const app2 = createApp(RootComponent2);
app2.component("Bar", Bar); // 相当于 Vue.use('Bar', Bar)
1
2
3
4
5
6

# shallowReadonly

⚠️ shallowReadonly() 会返回一个新的浅拷贝对象,在此之后新加的字段将不会获得只读或响应式状态。

💡 在 Vue 3 中,shallowReadonly() 会返回一个新的的代理对象

# readonly

⚠️ readonly() 只提供类型层面的只读。

readonly() 只在类型层面提供和 Vue 3 的对齐。在其返回值或其属性上使用 isReadonly() 检查的结果将无法保证。

# props

⚠️ 当使用 toRefs 访问深层属性对象 (如 toRefs(props.foo) 时将会得到不正确的警告。
     ⚠️ isReactive(props.foo) 将会返回 false。

defineComponent({
  setup(props) {
    const { bar } = toRefs(props.foo) // it will `warn`

    // use this instead
    const { foo } = toRefs(props)
    const a = foo.value.bar

}
})
1
2
3
4
5
6
7
8
9
10

# computed().effect

⚠️ computed() 拥有一个被设置为 true 的 effect 属性,用来代替 ReactiveEffect<T>。

由于实现上的不同, 在 @vue/composition-api 中没有 ReactiveEffect 这种概念。 因此, effect 为 true 只是为了能够区分 computed 和 refs:

function isComputed<T>(o: ComputedRef<T> | unknown): o is ComputedRef<T>
function isComputed(o: any): o is ComputedRef {
  return !!(isRef(o) && o.effect)
}
1
2
3
4

# 缺失的 API

以下在 Vue 3 新引入的 API ,在本插件中暂不适用:

  • onRenderTracked
  • onRenderTriggered
  • isProxy

# 在 data() 中使用组合式 API

❌ 在 data() 中使用 ref, reactive 或其他组合式 API 将不会生效

export default {
  data() {
    return {
      // 在模版中会成为 { a: { value: 1 } }
      a: ref(1),
    };
  },
};
1
2
3
4
5
6
7
8

# emit 选项

❌ emit 仅因在类型定义中对齐 Vue3 的选项而提供,不会有任何效果。

defineComponent({
  emit: {
    // 无效
    submit: (eventOption) => {
      if (...) {
        return true
      } else {
        console.warn('Invalid submit event payload!')
        return false
      }
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13

# 性能影响

由于 Vue 2 的公共 API 的限制,@vue/composition-api 不可避免地引入了额外的性能开销。除非在极端情况下,否则这并不会对你造成影响。

你可以查看这个 跑分结果 (opens new window) 了解更多信息。

#vue
上次更新: 2023/12/22, 10:33:26
vue实现图片文件的显示和上传
vue常用eslint配置模板

← vue实现图片文件的显示和上传 vue常用eslint配置模板→

最近更新
01
uniapp常见问题
03-19
02
Vue3项目搭建
12-25
03
使用pnpm的monorepo组织项目
11-01
更多文章>
Theme by Vdoing | Copyright © 2020-2025 Mrcdh | 苏ICP备2020058908号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×