使用Vue CLI生成的项目,有个地方不理解,
在项目默认生成的App.vue中定义的组件,在main.js中加载,为什么在index中没有进行引用(没有相应的标签对),但是还是加载了呢?
App.vue中默认定义的组件如下:
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
template>
通过main.js进行挂载:
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
首页(index.html)的代码如下(body部分):
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.strong>
noscript>
<div id="app">div>
body>
1)按理说根元素App不应该包含template
2)id为app的元素里面没有引用某个组件啊(里面没有元素内容),但是渲染之后装载了App.vue定义的组件模板
这两个问题求解释,谢谢
第一个问题:首先template只是一种声明式的模板语法,关于组件的写法,可以不使用template,你可以使用h渲染函数或jsx都ok。template的写法会更接近html,而且在编译时,会进行一些编译优化。那么App可以不包含template吗?可以,如果App根组件不是函数式组件或不存在template和渲染函数,那么会将#app的innerHTML属性作为template。下面是mount过程的部分源码
const component = app._component
if (!isFunction(component) && !component.render && !component.template) {
// 将container.innerHTML作为根组件的template属性
component.template = container.innerHTML
//...
}
第二个问题:#app为什么没有显示引用组件。在main.js中会执行一个mount方法,这个mount方法会将App渲染出来的dom整个挂在到#app上。下面是mount方法的源码,其中的render就是渲染dom并挂载到#app的核心
mount(
rootContainer: HostElement,
isHydrate?: boolean,
isSVG?: boolean
): any {
if (!isMounted) {
if (__DEV__ && (rootContainer as any).__vue_app__) {
warn(
`There is already an app instance mounted on the host container.\n` +
` If you want to mount another app on the same host container,` +
` you need to unmount the previous app by calling \`app.unmount()\` first.`
)
}
const vnode = createVNode(
rootComponent as ConcreteComponent,
rootProps
)
vnode.appContext = context
if (__DEV__) {
context.reload = () => {
render(cloneVNode(vnode), rootContainer, isSVG)
}
}
if (isHydrate && hydrate) {
hydrate(vnode as VNode<Node, Element>, rootContainer as any)
} else {
render(vnode, rootContainer, isSVG)
}
isMounted = true
app._container = rootContainer
;(rootContainer as any).__vue_app__ = app
if (__DEV__ || __FEATURE_PROD_DEVTOOLS__) {
app._instance = vnode.component
devtoolsInitApp(app, version)
}
return getExposeProxy(vnode.component!) || vnode.component!.proxy
} else if (__DEV__) {
warn(
`App has already been mounted.\n` +
`If you want to remount the same app, move your app creation logic ` +
`into a factory function and create fresh app instances for each ` +
`mount - e.g. \`const createMyApp = () => createApp(App)\``
)
}
}
如果你对vue3源码感兴趣,可以关注我,目前我正在更新vue3源码系列文章