feat(runtime-dom): support using mount target innerHTML as template

This commit is contained in:
Evan You 2019-10-24 21:58:34 -04:00
parent ed29af7bea
commit 6a92bbd9c0
3 changed files with 47 additions and 27 deletions

View File

@ -18,7 +18,7 @@ export interface App<HostElement = any> {
directive(name: string, directive: Directive): this directive(name: string, directive: Directive): this
mount( mount(
rootComponent: Component, rootComponent: Component,
rootContainer: HostElement, rootContainer: HostElement | string,
rootProps?: Data rootProps?: Data
): ComponentPublicInstance ): ComponentPublicInstance
provide<T>(key: InjectionKey<T> | string, value: T): void provide<T>(key: InjectionKey<T> | string, value: T): void
@ -141,7 +141,7 @@ export function createAppAPI<HostNode, HostElement>(
mount( mount(
rootComponent: Component, rootComponent: Component,
rootContainer: string | HostElement, rootContainer: HostElement,
rootProps?: Data rootProps?: Data
): any { ): any {
if (!isMounted) { if (!isMounted) {

View File

@ -123,7 +123,7 @@ export interface RendererOptions<HostNode = any, HostElement = any> {
export type RootRenderFunction<HostNode, HostElement> = ( export type RootRenderFunction<HostNode, HostElement> = (
vnode: VNode<HostNode, HostElement> | null, vnode: VNode<HostNode, HostElement> | null,
dom: HostElement | string dom: HostElement
) => void ) => void
/** /**
@ -1858,19 +1858,12 @@ export function createRenderer<
} }
} }
function render(vnode: HostVNode | null, rawContainer: HostElement | string) { const render: RootRenderFunction<
let container: any = rawContainer HostNode,
if (isString(container)) { HostElement & {
container = hostQuerySelector(container) _vnode: HostVNode | null
if (!container) {
if (__DEV__) {
warn(
`Failed to locate root container: ` + `querySelector returned null.`
)
}
return
}
} }
> = (vnode, container) => {
if (vnode == null) { if (vnode == null) {
if (container._vnode) { if (container._vnode) {
unmount(container._vnode, null, null, true) unmount(container._vnode, null, null, true)

View File

@ -1,27 +1,54 @@
import { createRenderer } from '@vue/runtime-core' import { createRenderer, warn } from '@vue/runtime-core'
import { nodeOps } from './nodeOps' import { nodeOps } from './nodeOps'
import { patchProp } from './patchProp' import { patchProp } from './patchProp'
// Importing from the compiler, will be tree-shaken in prod // Importing from the compiler, will be tree-shaken in prod
import { isHTMLTag, isSVGTag } from '@vue/compiler-dom' import { isHTMLTag, isSVGTag } from '@vue/compiler-dom'
import { isFunction, isString } from '@vue/shared'
const { render, createApp } = createRenderer<Node, Element>({ const { render, createApp: baseCreateApp } = createRenderer<Node, Element>({
patchProp, patchProp,
...nodeOps ...nodeOps
}) })
const wrappedCreateApp = () => { const createApp = () => {
const app = createApp() const app = baseCreateApp()
// inject `isNativeTag` dev only
Object.defineProperty(app.config, 'isNativeTag', { if (__DEV__) {
value: (tag: string) => isHTMLTag(tag) || isSVGTag(tag), // Inject `isNativeTag`
writable: false // this is used for component name validation (dev only)
}) Object.defineProperty(app.config, 'isNativeTag', {
value: (tag: string) => isHTMLTag(tag) || isSVGTag(tag),
writable: false
})
}
const mount = app.mount
app.mount = (component, container, props): any => {
if (isString(container)) {
container = document.querySelector(container)!
if (!container) {
__DEV__ &&
warn(`Failed to mount app: mount target selector returned null.`)
return
}
}
if (
__RUNTIME_COMPILE__ &&
!isFunction(component) &&
!component.render &&
!component.template
) {
component.template = container.innerHTML
}
// clear content before mounting
container.innerHTML = ''
return mount(component, container, props)
}
return app return app
} }
const exportedCreateApp = __DEV__ ? wrappedCreateApp : createApp export { render, createApp }
export { render, exportedCreateApp as createApp }
// DOM-only runtime helpers // DOM-only runtime helpers
export { export {