Vue2의 Composition API 구현 원리 분석
Vue3
출시 이후 Vue
를 작성하는 학생들 사이에서 composition API
라는 단어가 떠오른 것 같습니다. 항상 들었죠. composition API
는 이제 @vue/composition-api
의 출시로 인해 이전 options API
보다 훨씬 강력해졌습니다. code> 플러그인을 사용하여 Vue2
학생들도 버스에 탑승할 수 있습니다. 다음으로 반응형 ref
및 reactive
를 주로 사용하여 어떻게 버스에 탑승할 수 있는지 심층적으로 분석하겠습니다. 이 플러그인은 이 기능을 구현합니다. Vue3
发布之后,composition API
这个词走入写 Vue
同学的视野之中,相信大家也一直听到 composition API
比之前的 options API
有多好多强,如今由于 @vue/composition-api
插件的发布,Vue2
的同学也可以上车咯,接下来我们主要以响应式的 ref
和 reactive
来深入分析一下,这个插件是怎么实现此功能的。
如何使用
// 入口文件引入并注册 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
啊,我之前的data
、methods
里面也有变量和方法,怎么做到跟setup
返回值打通合并在一起的。【相关推荐:vuejs视频教程、web前端开发】vue2
不是只有定义在data
里面的数据才会被处理成响应式的吗?ref
和reactive
是怎么做到的呢?vue2
响应式数据定义的约束(添加赋值原对象没有的属性,数组下标修改等),改用ref
和reactive
就没问题吗?
当然还有很多的疑惑,因为插件提供的 API
相当多,覆盖了绝大部分 Vue3
所拥有的,这里主要从这几个问题来分析一下是如何做到的。
原理解析
得益于 Vue
的插件系统,@vue/composition-api
像 vue-router
、vuex
一样也是通过官方提供的插件式来注入。
// 这里只贴跟本章要讲的相关代码 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 || {} }
因为 Vue
在 beforeCreated
和 created
生命周期之间,会 initState
对数据进行处理,其中对 data
的处理时就会调用 $options.data
拿到定义的数据,所以这里重新对该函数其包裹一层,这也是为什么要选择 beforeCreate
사용방법
rreeefunction 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, '__ob__', 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
中定义返回的为什么能够在 template
、 data
、 methods
等之中去使用了,因为返回的东西都已经被代理到 vm
之上了。
响应式( ref
reactive
的实现)
接下来我们来说说响应式相关的,为什么 ref
和 reactive
也可以让数据成为响应式的。
ref
的实现其实是对 reactive
再次封装,主要用来给基本类型使用。
const value = reactive({ "composition-api.refKey": row })
因为 reactive
接受的必须是一个对象,所有这里使用了一个常量作为 ref
的 key
읽고 나면 vue3</과 똑같은 느낌이 드시나요? code>라고 생각할 수도 있습니다: </p><ul><li>🎜이것은 <code>vue2
입니다. 이전 data
및 methods
에도 변수와 메서드가 있습니다. . 어떻게 해야 하나요? setup
의 반환 값과 병합됩니다. [관련 권장사항: vuejs 비디오 튜토리얼, 웹 프론트엔드 개발]🎜
vue2 </ code> <code>data
에 정의된 데이터만 응답적으로 처리된다는 것이 사실이 아닌가요? ref
및 reactive
는 어떻게 수행하나요? 🎜vue2
반응형 데이터에 의해 정의된 제약 조건(원본 객체에 할당되지 않은 속성 추가, 배열 첨자 수정 등)의 경우 ref</를 사용하세요. code> 및 <code>reactive
가 괜찮나요? 🎜Vue3</code의 대부분을 다루는 꽤 많은 <code>API
를 제공하기 때문에 여전히 많은 의심이 있습니다. > has, here 이러한 질문을 중심으로 어떻게 이루어지는지 분석해 보겠습니다. 🎜원리 분석
🎜Vue
의 플러그인 시스템 덕분에 @vue/ <code>vue-router
및 vuex
와 같은 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, 'value', { 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 }🎜
Vue
가 beforeCreated
및 created</code에 있기 때문입니다 > 수명 주기 그 사이에 <code>initState
가 데이터를 처리하고, data
를 처리할 때 정의된 데이터를 가져오기 위해 $options.data
가 호출됩니다. 따라서 이 함수는 여기서 다시 래핑됩니다. 이것이 beforeCreate
후크 삽입이 선택된 이유 중 하나입니다.
다음으로 initSetup
이 하는 일을 살펴보겠습니다🎜rrreee🎜이 함수는 상대적으로 길며, 이번에 설명할 메인라인에 없는 코드 로직은 주로 를 생성하는 함수입니다. ctx
그리고 vm
인스턴스를 Vue3
데이터 유형으로 정의된 instance
로 변환한 후 setup
을 실행합니다. code> 함수를 사용하여 반환 값을 가져온 다음 각 속성을 반복하고 asVmProperty
를 호출하여 vm
에 마운트합니다. 물론 여기서 마운트하는 것은 속성과 속성을 직접 추가하는 것이 아닙니다. 위에서는 이 속성에 대한 후속 수정 사항을 vm
에 동기화할 수 없다는 문제가 있습니다. 여기서는 Vue
가 사용됩니다. 🎜rrreee🎜 이걸 보시면 setup
에서 정의한 반환 값이 template
, data
, 에서 사용될 수 있는 이유를 이해하셨으리라 믿습니다. >methods
는 반환된 항목이 vm
으로 프록시 처리되었기 때문에 기다리는 동안 사용됩니다. 🎜반응형(ref
반응형
구현)
🎜다음으로 이야기해 보겠습니다. 응답성에 대해, 왜 ref
및 reactive
가 데이터를 반응형으로 만들 수 있는지 알아보세요. 🎜🎜 ref
의 구현은 실제로 주로 기본 유형에 사용되는 reactive
를 다시 캡슐화한 것입니다. 🎜rrreee🎜reactive
는 객체를 허용해야 하기 때문에 여기서는 상수가 ref
의 key
로 사용됩니다. 즉 🎜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, 'value', { 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
-> proxy
到 setup
里面的 foo
-> observed
的 foo
,完成取值的流程,这会比直接在 data
上多代理了一层,因此整个过程也会有额外的性能开销。
因此使用该 API
也不会让你可以直接规避掉 vue2
响应式数据定义的约束,因为最终还是用 Object.defineProperty
去做对象拦截,插件同样也提供了 set API
让你去操作对象新增属性等操作。
总结
通过上面的了解,相信你一定对于 Vue2
如何使用 composition API
有了一定的了解,因为 API
相当多, 响应式相关的就还有 toRefs、toRef、unref、shallowRef、triggerRef
等等,这里就不一一分析,有兴趣的可以继续看源码的实现。
写 Vue2
的同学也可以不用羡慕写 Vue3
的同学了,直接引入到项目就可以使用起来,虽然没有 vue3
那么好的体验,但是绝大部分场景还是相同的,使用时注意 README
文档最后的限制章节,里面讲了一些使用限制。
위 내용은 Vue2의 Composition API 구현 원리 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undress AI Tool
무료로 이미지를 벗다

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

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

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

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

PHP와 Vue: 프론트엔드 개발 도구의 완벽한 조합 오늘날 인터넷이 빠르게 발전하는 시대에 프론트엔드 개발은 점점 더 중요해지고 있습니다. 사용자가 웹 사이트 및 애플리케이션 경험에 대한 요구 사항이 점점 더 높아짐에 따라 프런트 엔드 개발자는 보다 효율적이고 유연한 도구를 사용하여 반응형 및 대화형 인터페이스를 만들어야 합니다. 프론트엔드 개발 분야의 두 가지 중요한 기술인 PHP와 Vue.js는 함께 사용하면 완벽한 도구라고 볼 수 있습니다. 이 기사에서는 독자가 이 두 가지를 더 잘 이해하고 적용할 수 있도록 PHP와 Vue의 조합과 자세한 코드 예제를 살펴보겠습니다.

빠르고 효율적인 프로그래밍 언어인 Go 언어는 백엔드 개발 분야에서 널리 사용됩니다. 그러나 Go 언어를 프런트엔드 개발과 연관시키는 사람은 거의 없습니다. 실제로 프런트엔드 개발에 Go 언어를 사용하면 효율성이 향상될 뿐만 아니라 개발자에게 새로운 지평을 열어줄 수도 있습니다. 이 기사에서는 프런트엔드 개발에 Go 언어를 사용할 수 있는 가능성을 살펴보고 독자가 이 영역을 더 잘 이해할 수 있도록 구체적인 코드 예제를 제공합니다. 전통적인 프런트엔드 개발에서는 사용자 인터페이스를 구축하기 위해 JavaScript, HTML, CSS를 사용하는 경우가 많습니다.

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

프론트엔드 개발 인터뷰에서 일반적인 질문은 HTML/CSS 기초, JavaScript 기초, 프레임워크 및 라이브러리, 프로젝트 경험, 알고리즘 및 데이터 구조, 성능 최적화, 크로스 도메인 요청, 프론트엔드 엔지니어링, 디자인 패턴, 새로운 기술 및 트렌드. 면접관 질문은 후보자의 기술적 능력, 프로젝트 경험, 업계 동향에 대한 이해를 평가하기 위해 고안되었습니다. 따라서 지원자는 자신의 능력과 전문성을 입증할 수 있도록 해당 분야에 대한 충분한 준비를 갖추어야 합니다.

Golang과 프런트엔드 기술의 결합: Golang이 프런트엔드 분야에서 어떤 역할을 하는지 살펴보려면 구체적인 코드 예제가 필요합니다. 인터넷과 모바일 애플리케이션의 급속한 발전으로 인해 프런트엔드 기술이 점점 더 중요해지고 있습니다. 이 분야에서는 강력한 백엔드 프로그래밍 언어인 Golang도 중요한 역할을 할 수 있습니다. 이 기사에서는 Golang이 프런트엔드 기술과 어떻게 결합되는지 살펴보고 특정 코드 예제를 통해 프런트엔드 분야에서의 잠재력을 보여줍니다. 프론트엔드 분야에서 Golang의 역할은 효율적이고 간결하며 배우기 쉬운 것입니다.

vue.js는 특히 JavaScript Foundation을 가진 개발자에게는 배우기가 어렵지 않습니다. 1) 진보적 인 설계와 반응 형 시스템은 개발 프로세스를 단순화합니다. 2) 구성 요소 기반 개발은 코드 관리를보다 효율적으로 만듭니다. 3) 사용 예제는 기본 및 고급 사용을 보여줍니다. 4) vuedevtools를 통해 일반적인 오류를 디버깅 할 수 있습니다. 5) V-IF/V- 쇼 및 주요 속성 사용과 같은 성능 최적화 및 모범 사례는 애플리케이션 효율성을 향상시킬 수 있습니다.

vue.js는 주로 프론트 엔드 개발에 사용됩니다. 1) 사용자 인터페이스 및 단일 페이지 응용 프로그램 구축에 중점을 둔 가볍고 유연한 JavaScript 프레임 워크입니다. 2) vue.js의 핵심은 반응 형 데이터 시스템이며, 데이터가 변경되면 뷰가 자동으로 업데이트됩니다. 3) 구성 요소 개발을 지원하고 UI는 독립적이고 재사용 가능한 구성 요소로 분할 될 수 있습니다.

React의 주요 기능에는 구성 요소화 사고, 상태 관리 및 가상 DOM이 포함됩니다. 1) 구성 요소화에 대한 아이디어를 통해 UI를 재사용 가능한 부품으로 나누기 위해 코드 가독성과 유지 관리 가능성을 향상시킵니다. 2) 상태 관리는 상태 및 소품을 통해 동적 데이터를 관리하고 변경 UI 업데이트를 트리거합니다. 3) 가상 DOM 최적화 성능, 메모리에서 DOM 복제의 최소 작동을 계산하여 UI를 업데이트하십시오.
