1. // 1
    2. interface Config {
    3. name: string;
    4. }
    5. props: {
    6. config: Object as PropType<Config>,
    7. required: true
    8. }
    9. // 2 readonly
    10. const PropType = {
    11. msg: string,
    12. age: {
    13. type: Number,
    14. required: true
    15. }
    16. } as const
    17. export default defineComponent({
    18. name: '',
    19. props: PropType
    20. })
    1. // 需要加上 eslint 忽略
    2. const image = require("./assets/logo.png") // eslint-disable-line
    1. const numRef = ref(1)
    2. setInterval(() => {
    3. numRef.value += 1
    4. })
    5. // setup 只会执行一次, 此处 num 不会新增
    6. const num = numRef.value
    7. setup(){
    8. // 注意,应该写在这
    9. const num = numRef.value
    10. return () => {
    11. h('div', num)
    12. }
    13. }
    1. const yourRef = ref({})
    2. onMounted(() => {
    3. yourRef.value.doValidate()
    4. })
    5. <JSONSchemaForm contextRef={yourRef} />

    css in js :vue-jss

    1. <script setup lang="ts">
    2. import { defineEmits, defineProps, watchEffect } from 'vue'
    3. const props = defineProps<{ msg: string }>()
    4. const emit = defineEmits<{
    5. (e: 'change', id: number): void
    6. (e: 'update', value: string): void
    7. }>()
    8. watchEffect(() => console.log(props.msg))
    9. </script>
    1. // context.ts
    2. export const uniqueKey = Symbol()
    3. // 父组件
    4. <script setup lang="ts">
    5. import { provide, reactive } from 'vue'
    6. const data = reactive({ data: { a: 1 } })
    7. provide(uniqueKey, data)
    8. </script>
    9. // 子组件
    10. <script setup lang="ts">
    11. import { inject, watchEffect } from 'vue'
    12. const data = inject(uniqueKey)
    13. watchEffect(() => {
    14. // 此时 data 是响应式的,可以监听到
    15. console.log(data)
    16. })
    17. </script>
    1. setup () {
    2. const context: { a: number; } | undefined = {a: 1}
    3. if(!context) {
    4. throw Error('should not be undefined')
    5. }
    6. return () => (<div>1</div>)
    7. }
    1. // ctx 在生产环境里拿不到
    2. const { ctx } = getCurrentInstance()
    3. // 可以
    4. const { proxy } = getCurrentInstance()
    1. // 纯函数
    2. function sum(a: number, b: number) {
    3. return a + b
    4. }
    5. sum(1, 2)
    6. // 接收 Ref 作为函数参数,返回响应式结果
    7. function sum1(a: Ref<number>, b: Ref<number>) {
    8. return computed(() => a.value + b.value)
    9. }
    10. const a = ref(1)
    11. const b = ref(2)
    12. const c = sum1(a, b)
    13. c.value // 3
    14. // 同时传入 ref 和 number 类型
    15. function sum2(a: Ref<number> | number, b: Ref<number> | number) {
    16. return computed(() => unref(a) + unref(b))
    17. }
    18. const a = ref(1)
    19. const c = sum2(a, 5)
    20. c.value // 6
    1. // 例子
    2. import { computed, unref, Ref } from 'vue'
    3. // 类型
    4. type MaybeRef<T> = Ref<T> | T
    5. export function useTimeAgo(
    6. time: MaybeRef<Date | number | string>,
    7. ) {
    8. return computed(() => someFormating(unref(time)))
    9. }
    1. import { useTitle } from '@vueuse/core'
    2. const title = useTitle()
    3. title.value = 'Hello World'
    4. // 网页的标题随 Ref 改变
    5. // -----------------------------
    6. import { ref, computed } from 'vue'
    7. import { useTitle } from '@vueuse/core'
    8. const name = ref('Hello')
    9. const title = computed(() => {
    10. return `${name.value} - World`
    11. })
    12. useTitle(title) // Hello - World
    13. name.value = 'Hi' // Hi - World
    1. const foo = ref(1) // Ref<1>
    2. const bar = ref(foo) // Ref<1>
    3. foo === bar // true
    4. function useFoo(foo: Ref<string> | string) {
    5. // 不需要额外操作
    6. const bar = isRef(foo) ? foo : ref(foo)
    7. // 与上面的代码等效
    8. const bar = ref(foo)
    9. /* ... */
    10. }

    这个技巧在编写不确定参数类型的函数时十分有用。

    1. import { ref, reactive } from 'vue'
    2. function useMouse() {
    3. return {
    4. x: ref(0),
    5. y: ref(0)
    6. }
    7. }
    8. const { x, y } = useMouse()
    9. // reactive 包装
    10. const mouse = reactive(useMouse())
    11. mouse.x === x.value // true

    可以直接使用 ES6 解构其中的 Ref 使用根据使用方式,当想要自动解包的功能时,可以使用 reactive 将其转换为对象

    1. // context.ts
    2. import { InjectionKey } from 'vue'
    3. export interface UserInfo {
    4. id: number
    5. name: string
    6. }
    7. export const injectKeyUser: InjectionKey<UserInfo> = Symbol()
    8. // parent.vue
    9. import { provide } from 'vue'
    10. import { injectKeyUser } from './context'
    11. export default {
    12. setup() {
    13. provide(injectKeyUser, {
    14. id: '7', // 类型错误
    15. name: 'Anthony'
    16. })
    17. }
    18. }
    19. // child.vue
    20. import { inject } from 'vue'
    21. import { injectKeyUser } from './context'
    22. export default {
    23. setup() {
    24. const user = inject(injectKeyUser)
    25. // UserInfo | undefined
    26. if (user)
    27. console.log(user.name) // Anthony
    28. }
    29. }
    1. // shared.ts
    2. import { reactive } from 'vue'
    3. export const state = reactive({
    4. foo: 1,
    5. bar: 'Hello'
    6. })
    7. // A.vue
    8. import { state } from './shared.ts'
    9. state.foo += 1
    10. // B.vue
    11. import { state } from './shared.ts'
    12. console.log(state.foo) // 2

    不兼容 SSR

    useVModel

    1. export default defineComponent({
    2. setup(props) {
    3. const value = useVModel(props, 'value')
    4. return { value }
    5. }
    6. })
    7. <template>
    8. <input v-model="value" />
    9. </template>
    1. // Vue2.x
    2. Vue.prototype.$api = axios
    3. Vue.prototype.$eventBus = eventBus
    4. // Vue3.x
    5. app.config.globalProperties.$api = axios
    6. app.config.globalProperties.$eventBus = eventBus
    7. // 使用
    8. <script setup lang="ts">
    9. import { ref, onMounted, getCurrentInstance } from "vue";
    10. onMounted(() => {
    11. const instance = <any>getCurrentInstance();
    12. const { $api, $eventBus } = instance.appContext.config.globalProperties;
    13. // do something
    14. })
    1. // main.ts
    2. app.config.errorHandler = (err, vm, info) => {
    3. console.log('[全局异常]', err, vm, info)
    4. }

    控制台输出直观 ref 方法:
    image.png
    这里还有另一种方式,就是在控制台的设置面板中开启 「Enable custom formatters」选项。image.png
    这时候你会发现,控制台输出的 ref的格式发生变化了:
    image.png