vue-composition-api 解读(1)

@vue/composition-api 解读1

vue-composition-api 是 vue 官方出得, 基于vue3的RFC来兼容Vue2.x的增强api,具体API和vue-next 是差不多的, 具体的API详见 vue-composition-api-rfc, 本系列文章是基于你对vue2有所了解的情况

proxy

vue2的响应式是基于Object.definePropertysetget方法来实现的,具体的在源码中的实现, 这也是组合式API响应式的基础

// src/utils/utils.ts
export function proxy(
  target: any,
  key: string,
  { get, set }: { get?: Function; set?: Function }
) {
  sharedPropertyDefinition.get = get || noopFn
  sharedPropertyDefinition.set = set || noopFn
  Object.defineProperty(target, key, sharedPropertyDefinition)
}

其中sharedPropertyDefinition存在getset方法

reactive

reactive是组合式API提供的一个实现对象响应式的API, 使用方法也很简单,就是传入一个object

setup() {
    const state = reactive({
        foo: 'foo'
    })

    return {
        state
    }
}

源码中的实现我们一一来看

export function reactive<T extends object>(obj: T): UnwrapRef<T> {
  if (__DEV__ && !obj) {
    warn('"reactive()" is called without provide an "object".')
    // @ts-ignore
    return
  }

  if (
    !isPlainObject(obj) || // 非原始对象
    isReactive(obj) || // 已是响应式
    isRaw(obj) || // 
    !Object.isExtensible(obj) // 对象不可扩展
  ) {
    return obj as any
  }

  const observed = observe(obj)
  // def(obj, ReactiveIdentifierKey, ReactiveIdentifier);
  markReactive(obj)
  setupAccessControl(observed)
  return observed as UnwrapRef<T>
}

其中 observe是实现响应式的关键, 我们打开看一看


function observe<T>(obj: T): T {
  const Vue = getVueConstructor()
  let observed: T
  if (Vue.observable) {
    observed = Vue.observable(obj)
  } else {
    const vm = defineComponentInstance(Vue, {
      data: {
        $$state: obj,
      },
    })
    observed = vm._data.$$state
  }

  return observed
}

你没看错,就这么简单, 实际上就是用vue2现成的api来实现的 Vue.observable, else下面是用来兼容以前老版本vue没有observable

markReactive 标记 reactive中的对象, 实现方式其实也是使用Object.defineProperty来写入标记值,
其中标记都是用Symbol来标识唯一性的

ref

ref 是组合式API中另一个响应式api,传入一个基本类型参数

使用

setup() {
    const state = ref(1/"hello world"/false/null)

    return {
        state
    }
}

取值方式state.value, 如果使用模版方式就不需要使用.value方式,模版已经做了这个工作,如果使用jsxrender函数,就只能手加了

具体实现

export function ref(raw?: unknown) {
  if (isRef(raw)) {
    return raw
  }

  const value = reactive({ [RefKey]: raw })
  return createRef({
    get: () => value[RefKey] as any,
    set: (v) => ((value[RefKey] as any) = v),
  })
}

其中在内部实现了组装了一个对象,还是用的reactive实现逻辑
关键在createRef

class RefImpl<T> implements Ref<T> {
  readonly [_refBrand]!: true
  public value!: T
  constructor({ get, set }: RefOption<T>) {
    proxy(this, 'value', {
      get,
      set,
    })
  }
}

export function createRef<T>(options: RefOption<T>) {
  // seal the ref, this could prevent ref from being observed
  // It's safe to seal the ref, since we really shouldn't extend it.
  // related issues: #79
  return Object.seal(new RefImpl<T>(options))
}

其中Object.seal 封闭了一个RefImpl对象,使其对象不能添加其他任何属性,已有属性可以更改,具体的去查Object.seal的文档

RefImpl中 用我们上面写的响应式方法proxy, 传入getset来重写他的getset方法

官方用ref的方式来获得dom实例

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

<script>
  import { ref, onMounted } from 'vue'

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

      onMounted(() => {
        // 在渲染完成后, 这个 div DOM 会被赋值给 root ref 对象
        console.log(root.value) // <div/>
      })

      return {
        root,
      }
    },
  }
</script>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值