Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Jul 5, 2020
1 parent 9468f72 commit c757e32
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 126 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,6 @@ The following APIs introduced in Vue 3 are not available in this plugin.
- `defineAsyncComponent`
- `onRenderTracked`
- `onRenderTriggered`
- `customRef`
- `isProxy`
- `isReadonly`
- `isVNode`
Expand Down
132 changes: 7 additions & 125 deletions src/mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,139 +6,21 @@ import {
Data,
} from './component'
import {
Ref,
isRef,
isReactive,
markRaw,
unwrapRefProxy,
markReactive,
} from './reactivity'
import { getCurrentInstance, setCurrentInstance } from './runtimeContext'
import {
resolveSlots,
createSlotProxy,
hasOwn,
isPlainObject,
assert,
proxy,
warn,
isFunction,
} from './utils'
import { isPlainObject, assert, proxy, warn, isFunction } from './utils'
import { ref } from './apis'
import vmStateManager from './utils/vmStateManager'

function asVmProperty(
vm: ComponentInstance,
propName: string,
propValue: Ref<unknown>
) {
const props = vm.$options.props
if (!(propName in vm) && !(props && hasOwn(props, propName))) {
proxy(vm, propName, {
get: () => propValue.value,
set: (val: unknown) => {
propValue.value = val
},
})

if (__DEV__) {
// expose binding to Vue Devtool as a data property
// delay this until state has been resolved to prevent repeated works
vm.$nextTick(() => {
proxy(vm._data, propName, {
get: () => propValue.value,
set: (val: unknown) => {
propValue.value = val
},
})
})
}
} else if (__DEV__) {
if (props && hasOwn(props, propName)) {
warn(
`The setup binding property "${propName}" is already declared as a prop.`,
vm
)
} else {
warn(`The setup binding property "${propName}" is already declared.`, vm)
}
}
}

function updateTemplateRef(vm: ComponentInstance) {
const rawBindings = vmStateManager.get(vm, 'rawBindings') || {}
if (!rawBindings || !Object.keys(rawBindings).length) return

const refs = vm.$refs
const oldRefKeys = vmStateManager.get(vm, 'refs') || []
for (let index = 0; index < oldRefKeys.length; index++) {
const key = oldRefKeys[index]
const setupValue = rawBindings[key]
if (!refs[key] && setupValue && isRef(setupValue)) {
setupValue.value = null
}
}

const newKeys = Object.keys(refs)
const validNewKeys = []
for (let index = 0; index < newKeys.length; index++) {
const key = newKeys[index]
const setupValue = rawBindings[key]
if (refs[key] && setupValue && isRef(setupValue)) {
setupValue.value = refs[key]
validNewKeys.push(key)
}
}
vmStateManager.set(vm, 'refs', validNewKeys)
}

function resolveScopedSlots(
vm: ComponentInstance,
slotsProxy: { [x: string]: Function }
): void {
const parentVNode = (vm.$options as any)._parentVnode
if (!parentVNode) return

const prevSlots = vmStateManager.get(vm, 'slots') || []
const curSlots = resolveSlots(parentVNode.data.scopedSlots, vm.$slots)
// remove staled slots
for (let index = 0; index < prevSlots.length; index++) {
const key = prevSlots[index]
if (!curSlots[key]) {
delete slotsProxy[key]
}
}

// proxy fresh slots
const slotNames = Object.keys(curSlots)
for (let index = 0; index < slotNames.length; index++) {
const key = slotNames[index]
if (!slotsProxy[key]) {
slotsProxy[key] = createSlotProxy(vm, key)
}
}
vmStateManager.set(vm, 'slots', slotNames)
}

function activateCurrentInstance(
vm: ComponentInstance,
fn: (vm_: ComponentInstance) => any,
onError?: (err: Error) => void
) {
let preVm = getCurrentInstance()
setCurrentInstance(vm)
try {
return fn(vm)
} catch (err) {
if (onError) {
onError(err)
} else {
throw err
}
} finally {
setCurrentInstance(preVm)
}
}
import {
updateTemplateRef,
activateCurrentInstance,
resolveScopedSlots,
asVmProperty,
} from './utils/instance'

export function mixin(Vue: VueConstructor) {
Vue.mixin({
Expand Down
119 changes: 119 additions & 0 deletions src/utils/instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { ComponentInstance } from '../component'
import vmStateManager from './vmStateManager'
import { setCurrentInstance, getCurrentInstance } from '../runtimeContext'
import { Ref, isRef } from '../apis'
import { hasOwn, proxy, warn } from './utils'
import { createSlotProxy, resolveSlots } from './helper'

export function asVmProperty(
vm: ComponentInstance,
propName: string,
propValue: Ref<unknown>
) {
const props = vm.$options.props
if (!(propName in vm) && !(props && hasOwn(props, propName))) {
proxy(vm, propName, {
get: () => propValue.value,
set: (val: unknown) => {
propValue.value = val
},
})

if (__DEV__) {
// expose binding to Vue Devtool as a data property
// delay this until state has been resolved to prevent repeated works
vm.$nextTick(() => {
proxy(vm._data, propName, {
get: () => propValue.value,
set: (val: unknown) => {
propValue.value = val
},
})
})
}
} else if (__DEV__) {
if (props && hasOwn(props, propName)) {
warn(
`The setup binding property "${propName}" is already declared as a prop.`,
vm
)
} else {
warn(`The setup binding property "${propName}" is already declared.`, vm)
}
}
}

export function updateTemplateRef(vm: ComponentInstance) {
const rawBindings = vmStateManager.get(vm, 'rawBindings') || {}
if (!rawBindings || !Object.keys(rawBindings).length) return

const refs = vm.$refs
const oldRefKeys = vmStateManager.get(vm, 'refs') || []
for (let index = 0; index < oldRefKeys.length; index++) {
const key = oldRefKeys[index]
const setupValue = rawBindings[key]
if (!refs[key] && setupValue && isRef(setupValue)) {
setupValue.value = null
}
}

const newKeys = Object.keys(refs)
const validNewKeys = []
for (let index = 0; index < newKeys.length; index++) {
const key = newKeys[index]
const setupValue = rawBindings[key]
if (refs[key] && setupValue && isRef(setupValue)) {
setupValue.value = refs[key]
validNewKeys.push(key)
}
}
vmStateManager.set(vm, 'refs', validNewKeys)
}

export function resolveScopedSlots(
vm: ComponentInstance,
slotsProxy: { [x: string]: Function }
): void {
const parentVNode = (vm.$options as any)._parentVnode
if (!parentVNode) return

const prevSlots = vmStateManager.get(vm, 'slots') || []
const curSlots = resolveSlots(parentVNode.data.scopedSlots, vm.$slots)
// remove staled slots
for (let index = 0; index < prevSlots.length; index++) {
const key = prevSlots[index]
if (!curSlots[key]) {
delete slotsProxy[key]
}
}

// proxy fresh slots
const slotNames = Object.keys(curSlots)
for (let index = 0; index < slotNames.length; index++) {
const key = slotNames[index]
if (!slotsProxy[key]) {
slotsProxy[key] = createSlotProxy(vm, key)
}
}
vmStateManager.set(vm, 'slots', slotNames)
}

export function activateCurrentInstance(
vm: ComponentInstance,
fn: (vm_: ComponentInstance) => any,
onError?: (err: Error) => void
) {
let preVm = getCurrentInstance()
setCurrentInstance(vm)
try {
return fn(vm)
} catch (err) {
if (onError) {
onError(err)
} else {
throw err
}
} finally {
setCurrentInstance(preVm)
}
}

0 comments on commit c757e32

Please sign in to comment.