찾다
웹 프론트엔드View.jsVue2의 Composition API 구현 원리 분석

Vue2의 Composition API 구현 원리 분석

Jan 13, 2023 am 08:30 AM
프런트 엔드vue.js

Vue2의 Composition API 구현 원리 분석

Vue3 출시 이후 Vue를 작성하는 학생들 사이에서 composition API라는 단어가 떠오른 것 같습니다. 항상 들었죠. composition API는 이제 @vue/composition-api의 출시로 인해 이전 options API보다 훨씬 강력해졌습니다. code> 플러그인을 사용하여 Vue2 학생들도 버스에 탑승할 수 있습니다. 다음으로 반응형 refreactive를 주로 사용하여 어떻게 버스에 탑승할 수 있는지 심층적으로 분석하겠습니다. 이 플러그인은 이 기능을 구현합니다. Vue3 发布之后,composition API 这个词走入写 Vue 同学的视野之中,相信大家也一直听到 composition API 比之前的 options API 有多好多强,如今由于 @vue/composition-api 插件的发布,Vue2 的同学也可以上车咯,接下来我们主要以响应式的 refreactive 来深入分析一下,这个插件是怎么实现此功能的。

如何使用

// 入口文件引入并注册
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'

Vue.use(VueCompositionAPI)
// vue文件使用
import { defineComponent, ref, reactive } from '@vue/composition-api'

export default defineComponent({
  setup () {
     const foo = ref('foo');
     const obj = reactive({ bar: 'bar' });
     
     return {
        foo,
        obj
     }
  }
})

怎么样,看完是不是感觉和 vue3 一模一样,你可能会想:

  • 这是 vue2 啊,我之前的 datamethods 里面也有变量和方法,怎么做到跟 setup 返回值打通合并在一起的。【相关推荐:vuejs视频教程web前端开发

  • vue2 不是只有定义在 data 里面的数据才会被处理成响应式的吗? refreactive 是怎么做到的呢?

  • vue2 响应式数据定义的约束(添加赋值原对象没有的属性,数组下标修改等),改用 refreactive 就没问题吗?

当然还有很多的疑惑,因为插件提供的 API 相当多,覆盖了绝大部分 Vue3 所拥有的,这里主要从这几个问题来分析一下是如何做到的。

原理解析

得益于 Vue 的插件系统,@vue/composition-apivue-routervuex 一样也是通过官方提供的插件式来注入。

// 这里只贴跟本章要讲的相关代码

funciton mixin (Vue) {
    Vue.mixin({
      beforeCreate: functionApiInit
   }
}

function install (Vue) {
    mixin(Vue);
}

export const Plugin = {
  install: (Vue: VueConstructor) => install(Vue),
}

Vue 插件就是向外面暴露一个 install 的方法,当调用 use 的时候会调用该方法,并把 Vue 构造函数作为参数传入,然后调用 Vue.mixin 混入对应钩子时要处理的函数。

接下来主要看下 functionApiInit 做了什么

function functionApiInit(this: ComponentInstance) {
  const vm = this
  const $options = vm.$options
  const { setup, render } = $options
  
  // render 相关
  
  
  const { data } = $options
  
  $options.data = function wrappedData() {
    initSetup(vm, vm.$props)
    return isFunction(data)
     ? (
        data as (this: ComponentInstance, x: ComponentInstance) => object
      ).call(vm, vm)
     : data || {}
  }

因为 VuebeforeCreatedcreated 生命周期之间,会 initState 对数据进行处理,其中对 data的处理时就会调用 $options.data拿到定义的数据,所以这里重新对该函数其包裹一层,这也是为什么要选择 beforeCreate

사용방법

rreee
function initSetup(vm: ComponentInstance, props: Record<any, any> = {}) {
  const setup = vm.$options.setup!
  const ctx = createSetupContext(vm)
  const instance = toVue3ComponentInstance(vm)
  instance.setupContext = ctx
  
  def(props, &#39;__ob__&#39;, createObserver())
  resolveScopedSlots(vm, ctx.slots)

  let binding: ReturnType<SetupFunction<Data, Data>> | undefined | null
  activateCurrentInstance(instance, () => {
    binding = setup(props, ctx)
  })

   // setup返回是函数的情况 需要重写render函数

  const bindingObj = binding

  Object.keys(bindingObj).forEach((name) => {
    let bindingValue: any = bindingObj[name]

    // 数据处理
    
    asVmProperty(vm, name, bindingValue)
  })
  return
  }
}
initSetup都做了什么
export function asVmProperty(
  vm: ComponentInstance,
  propName: string,
  propValue: Ref<unknown>
) {
  const props = vm.$options.props
  if (!(propName in vm) && !(props && hasOwn(props, propName))) {
    if (isRef(propValue)) {
      proxy(vm, propName, {
        get: () => propValue.value,
        set: (val: unknown) => {
          propValue.value = val
        },
      })
    } else {
      proxy(vm, propName, {
        get: () => {
          if (isReactive(propValue)) {
            ;(propValue as any).__ob__.dep.depend()
          }
          return propValue
        },
        set: (val: any) => {
          propValue = val
        },
      })
    }
}

这个函数比较长,不在本次要讲解的主线上代码逻辑都删除了,这个函数主要是创建了 ctx 和把 vm 实例转换成 Vue3 数据类型定义的 instance ,然后执行 setup 函数得到返回值,然后遍历每个属性,调用 asVmProperty 挂载到 vm 上面,当然这里的挂载不是直接通过把属性和值添加到 vm 上面,这么做会有一个问题,就是后续对该属性的修改不能同步到 vm 中,这里采用的还是 Vue 最常见的数据代理。

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),
  })
}

看到这里,相信你已经明白了在 setup 中定义返回的为什么能够在 templatedatamethods 等之中去使用了,因为返回的东西都已经被代理到 vm 之上了。

响应式( ref  reactive 的实现)

接下来我们来说说响应式相关的,为什么 refreactive 也可以让数据成为响应式的。

ref 的实现其实是对 reactive 再次封装,主要用来给基本类型使用。

const value = reactive({
  "composition-api.refKey": row
})

因为 reactive 接受的必须是一个对象,所有这里使用了一个常量作为 refkey읽고 나면 vue3과 똑같은 느낌이 드시나요? code>라고 생각할 수도 있습니다:

  • 🎜이것은 vue2입니다. 이전 datamethods에도 변수와 메서드가 있습니다. . 어떻게 해야 하나요? setup의 반환 값과 병합됩니다. [관련 권장사항: vuejs 비디오 튜토리얼, 웹 프론트엔드 개발]🎜
  • 🎜vue2 code> <code>data에 정의된 데이터만 응답적으로 처리된다는 것이 사실이 아닌가요? refreactive는 어떻게 수행하나요? 🎜
  • 🎜vue2 반응형 데이터에 의해 정의된 제약 조건(원본 객체에 할당되지 않은 속성 추가, 배열 첨자 수정 등)의 경우 ref를 사용하세요. code> 및 <code>reactive가 괜찮나요? 🎜
🎜물론 플러그인이 Vue3의 대부분을 다루는 꽤 많은 API를 제공하기 때문에 여전히 많은 의심이 있습니다. > has, here 이러한 질문을 중심으로 어떻게 이루어지는지 분석해 보겠습니다. 🎜

원리 분석

🎜Vue의 플러그인 시스템 덕분에 @vue/ <code>vue-routervuex와 같은 Composition-api도 공식적으로 제공되는 플러그인을 통해 주입됩니다. 🎜
export function createRef<T>(
  options: RefOption<T>,
  isReadonly = false,
  isComputed = false
): RefImpl<T> {
  const r = new RefImpl<T>(options)

  const sealed = Object.seal(r)
  if (isReadonly) readonlySet.set(sealed, true)
  return sealed
}

export class RefImpl<T> implements Ref<T> {
  readonly [_refBrand]!: true
  public value!: T
  constructor({ get, set }: RefOption<T>) {
    proxy(this, &#39;value&#39;, {
      get,
      set,
    })
  }
}
🎜Vue 플러그인은 install 메소드를 외부 세계에 노출합니다. use가 호출되면 이 메소드가 호출되고 Vue 생성자를 매개변수로 전달한 뒤 Vue.mixin을 호출하여 해당 Hook이 믹싱될 때 처리할 함수를 믹싱합니다. 🎜🎜다음 단계는 functionApiInit가 무엇을 하는지 살펴보는 것입니다🎜
export function reactive<T extends object>(obj: T): UnwrapRef<T> {
    const observed = observe(obj)
    setupAccessControl(observed)
    return observed as UnwrapRef<T>
}


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

  return observed
}
🎜 VuebeforeCreatedcreated에 있기 때문입니다 > 수명 주기 그 사이에 initState가 데이터를 처리하고, data를 처리할 때 정의된 데이터를 가져오기 위해 $options.data가 호출됩니다. 따라서 이 함수는 여기서 다시 래핑됩니다. 이것이 beforeCreate 후크 삽입이 선택된 이유 중 하나입니다. 다음으로 initSetup이 하는 일을 살펴보겠습니다🎜rrreee🎜이 함수는 상대적으로 길며, 이번에 설명할 메인라인에 없는 코드 로직은 주로 를 생성하는 함수입니다. ctx 그리고 vm 인스턴스를 Vue3 데이터 유형으로 정의된 instance로 변환한 후 setup을 실행합니다. code> 함수를 사용하여 반환 값을 가져온 다음 각 속성을 반복하고 asVmProperty를 호출하여 vm에 마운트합니다. 물론 여기서 마운트하는 것은 속성과 속성을 직접 추가하는 것이 아닙니다. 위에서는 이 속성에 대한 후속 수정 사항을 vm에 동기화할 수 없다는 문제가 있습니다. 여기서는 Vue가 사용됩니다. 🎜rrreee🎜 이걸 보시면 setup에서 정의한 반환 값이 template, data, 에서 사용될 수 있는 이유를 이해하셨으리라 믿습니다. >methods 는 반환된 항목이 vm으로 프록시 처리되었기 때문에 기다리는 동안 사용됩니다. 🎜

반응형(ref 반응형 구현)

🎜다음으로 이야기해 보겠습니다. 응답성에 대해, 왜 refreactive가 데이터를 반응형으로 만들 수 있는지 알아보세요. 🎜🎜 ref의 구현은 실제로 주로 기본 유형에 사용되는 reactive를 다시 캡슐화한 것입니다. 🎜rrreee🎜reactive는 객체를 허용해야 하기 때문에 여기서는 상수가 refkey로 사용됩니다. 즉 🎜
const value = reactive({
  "composition-api.refKey": row
})
export function createRef<T>(
  options: RefOption<T>,
  isReadonly = false,
  isComputed = false
): RefImpl<T> {
  const r = new RefImpl<T>(options)

  const sealed = Object.seal(r)
  if (isReadonly) readonlySet.set(sealed, true)
  return sealed
}

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

通过 new RefImpl 实例,该实例上有一个 value 的属性,对 value 做代理,当取值的时候返回 value[RefKey],赋值的时候赋值给 value[RefKey], 这就是为什么 ref 可以用在基本类型,然后对返回值的 .value 进行操作。调用 object.seal 是把对象密封起来(会让这个对象变的不能添加新属性,且所有已有属性会变的不可配置。属性不可配置的效果就是属性变的不可删除,以及一个数据属性不能被重新定义成为访问器属性,或者反之。但属性的值仍然可以修改。)

我们主要看下 reactive 的实现

export function reactive<T extends object>(obj: T): UnwrapRef<T> {
    const observed = observe(obj)
    setupAccessControl(observed)
    return observed as UnwrapRef<T>
}


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

  return observed
}

我们通过 ref 或者 reactive 定义的数据,最终还是通过了变成了一个 observed 实例对象,也就是 Vue2 在对 data 进行处理时,会调用 observe 返回的一样,这里在 Vue2.6+observe 函数向外暴露为 Vue.observable,如果是低版本的话,可以通过重新 new 一个 vue 实例,借助 data 也可以返回一个 observed 实例,如上述代码。

因为在 reactive 中定义的数据,就如你在 data 中定义的数据一样,都是在操作返回的 observed ,当你取值的时候,会触发 getter 进行依赖收集,赋值时会调用 setter 去派发更新, 只是定义在 setup 中,结合之前讲到的 setup 部分,比如当我们在 template 中访问一个变量的值时,vm.foo -> proxysetup 里面的 foo -> observedfoo ,完成取值的流程,这会比直接在 data 上多代理了一层,因此整个过程也会有额外的性能开销。

因此使用该 API 也不会让你可以直接规避掉 vue2 响应式数据定义的约束,因为最终还是用 Object.defineProperty 去做对象拦截,插件同样也提供了 set API 让你去操作对象新增属性等操作。

总结

通过上面的了解,相信你一定对于 Vue2 如何使用 composition API 有了一定的了解,因为 API 相当多, 响应式相关的就还有 toRefs、toRef、unref、shallowRef、triggerRef 等等,这里就不一一分析,有兴趣的可以继续看源码的实现。

Vue2 的同学也可以不用羡慕写 Vue3 的同学了,直接引入到项目就可以使用起来,虽然没有 vue3 那么好的体验,但是绝大部分场景还是相同的,使用时注意 README 文档最后的限制章节,里面讲了一些使用限制。

(学习视频分享:vuejs入门教程编程基础视频

위 내용은 Vue2의 Composition API 구현 원리 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
이 기사는 掘金社区에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제
React vs. Vue : Netflix는 어떤 프레임 워크를 사용합니까?React vs. Vue : Netflix는 어떤 프레임 워크를 사용합니까?Apr 14, 2025 am 12:19 AM

NetflixusesAcustomFrameworkCalled "Gibbon"BuiltonReact, NotreactorVuedirectly.1) TeamExperience : 2) ProjectComplexity : vueforsimplerProjects, 3) CustomizationNeeds : reactoffersmoreflex.4)

프레임 워크의 선택 : Netflix의 결정을 이끌어내는 것은 무엇입니까?프레임 워크의 선택 : Netflix의 결정을 이끌어내는 것은 무엇입니까?Apr 13, 2025 am 12:05 AM

Netflix는 주로 프레임 워크 선택의 성능, 확장 성, 개발 효율성, 생태계, 기술 부채 및 유지 보수 비용을 고려합니다. 1. 성능 및 확장 성 : Java 및 SpringBoot는 대규모 데이터 및 높은 동시 요청을 효율적으로 처리하기 위해 선택됩니다. 2. 개발 효율성 및 생태계 : React를 사용하여 프론트 엔드 개발 효율성을 향상시키고 풍부한 생태계를 활용하십시오. 3. 기술 부채 및 유지 보수 비용 : Node.js를 선택하여 유지 보수 비용과 기술 부채를 줄이기 위해 마이크로 서비스를 구축하십시오.

Netflix의 프론트 엔드의 반응, vue 및 미래Netflix의 프론트 엔드의 반응, vue 및 미래Apr 12, 2025 am 12:12 AM

Netflix는 주로 VUE가 특정 기능을 위해 보충하는 프론트 엔드 프레임 워크로 React를 사용합니다. 1) React의 구성 요소화 및 가상 DOM은 Netflix 애플리케이션의 성능 및 개발 효율을 향상시킵니다. 2) VUE는 Netflix의 내부 도구 및 소규모 프로젝트에 사용되며 유연성과 사용 편의성이 핵심입니다.

프론트 엔드의 vue.js : 실제 응용 프로그램 및 예제프론트 엔드의 vue.js : 실제 응용 프로그램 및 예제Apr 11, 2025 am 12:12 AM

vue.js는 복잡한 사용자 인터페이스를 구축하는 데 적합한 점진적인 JavaScript 프레임 워크입니다. 1) 핵심 개념에는 반응 형 데이터, 구성 요소화 및 가상 DOM이 포함됩니다. 2) 실제 응용 분야에서는 TODO 응용 프로그램을 구축하고 Vuerouter를 통합하여 시연 할 수 있습니다. 3) 디버깅 할 때 VuedeVtools 및 Console.log를 사용하는 것이 좋습니다. 4) 성능 최적화는 V-IF/V- 쇼, 목록 렌더링 최적화, 구성 요소의 비동기로드 등을 통해 달성 할 수 있습니다.

vue.js and React : 주요 차이점 이해vue.js and React : 주요 차이점 이해Apr 10, 2025 am 09:26 AM

vue.js는 중소형 프로젝트에 적합하지만 REACT는 크고 복잡한 응용 프로그램에 더 적합합니다. 1. Vue.js의 응답 형 시스템은 종속성 추적을 통해 DOM을 자동으로 업데이트하여 데이터 변경을 쉽게 관리 할 수 ​​있습니다. 2. 반응은 단방향 데이터 흐름을 채택하고 데이터 흐름에서 하위 구성 요소로 데이터가 흐르고 명확한 데이터 흐름과 곤란하기 쉬운 구조를 제공합니다.

vue.js vs. React : 프로젝트 별 고려 사항vue.js vs. React : 프로젝트 별 고려 사항Apr 09, 2025 am 12:01 AM

vue.js는 중소형 프로젝트 및 빠른 반복에 적합한 반면 React는 크고 복잡한 응용 프로그램에 적합합니다. 1) vue.js는 사용하기 쉽고 팀이 불충분하거나 프로젝트 규모가 작는 상황에 적합합니다. 2) React는 더 풍부한 생태계를 가지고 있으며 고성능 및 복잡한 기능적 요구가있는 프로젝트에 적합합니다.

태그를 vue로 점프하는 방법태그를 vue로 점프하는 방법Apr 08, 2025 am 09:24 AM

VUE에서 태그의 점프를 구현하는 방법에는 다음이 포함됩니다. HTML 템플릿의 A 태그를 사용하여 HREF 속성을 지정합니다. VUE 라우팅의 라우터 링크 구성 요소를 사용하십시오. javaScript 에서이. $ router.push () 메소드를 사용하십시오. 매개 변수는 쿼리 매개 변수를 통해 전달 될 수 있으며 동적 점프를 위해 라우터 옵션에서 경로가 구성됩니다.

VUE의 구성 요소 점프를 구현하는 방법VUE의 구성 요소 점프를 구현하는 방법Apr 08, 2025 am 09:21 AM

VUE에서 구성 요소 점프를 구현하는 방법은 다음과 같습니다. 라우터 링크 및 & lt; router-view & gt; 하이퍼 링크 점프를 수행하고 대상 경로로 속성을 지정합니다. & lt; router-view & gt; 현재 라우팅 된 렌더링 된 구성 요소를 표시하는 구성 요소. 프로그래밍 방식 탐색을 위해 router.push () 및 router.replace () 메소드를 사용하십시오. 전자는 역사를 구하고 후자는 기록을 떠나지 않고 현재 경로를 대체합니다.

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
4 몇 주 전By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
1 몇 달 전By尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

SecList

SecList

SecLists는 최고의 보안 테스터의 동반자입니다. 보안 평가 시 자주 사용되는 다양한 유형의 목록을 한 곳에 모아 놓은 것입니다. SecLists는 보안 테스터에게 필요할 수 있는 모든 목록을 편리하게 제공하여 보안 테스트를 더욱 효율적이고 생산적으로 만드는 데 도움이 됩니다. 목록 유형에는 사용자 이름, 비밀번호, URL, 퍼징 페이로드, 민감한 데이터 패턴, 웹 셸 등이 포함됩니다. 테스터는 이 저장소를 새로운 테스트 시스템으로 간단히 가져올 수 있으며 필요한 모든 유형의 목록에 액세스할 수 있습니다.

ZendStudio 13.5.1 맥

ZendStudio 13.5.1 맥

강력한 PHP 통합 개발 환경

Atom Editor Mac 버전 다운로드

Atom Editor Mac 버전 다운로드

가장 인기 있는 오픈 소스 편집기

PhpStorm 맥 버전

PhpStorm 맥 버전

최신(2018.2.1) 전문 PHP 통합 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)