参数
el
- 类型:
string | Element
- 限制:只在用
new
创建实例时生效。 详细:
提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTMLElement 实例。
在实例挂载之后,元素可以用vm.$el
访问。
如果在实例化时存在这个选项,实例将立即进入编译过程,否则,需要显式调用vm.$mount()
手动开启编译。
提供的元素只能作为挂载点。不同于 Vue 1.x,所有的挂载元素会被 Vue 生成的 DOM 替换。因此不推荐挂载 root 实例到<html>
或者<body>
上。
如果render
函数和template
属性都不存在,挂载 DOM 元素的 HTML 会被提取出来用作模板,此时,必须使用 Runtime + Compiler 构建的 Vue 库。template
类型:
string
详细:
一个字符串模板作为 Vue 实例的标识使用。模板将会 替换 挂载的元素。挂载元素的内容都将被忽略,除非模板的内容有分发插槽。
如果值以#
开始,则它将被用作选择符,并使用匹配元素的 innerHTML 作为模板。常用的技巧是用<script type="x-template">
包含模板。
出于安全考虑,你应该只使用你信任的 Vue 模板。避免使用其他人生成的内容作为你的模板。
如果 Vue 选项中包含渲染函数,该模板将被忽略。render
类型:
(createElement: () => VNode) => VNode
- 详细:
字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个createElement
方法作为第一个参数用来创建VNode
。
如果组件是一个函数组件,渲染函数还会接收一个额外的context
参数,为没有实例的函数组件提供上下文信息。
Vue 选项中的render
函数若存在,则 Vue 构造函数不会从template
选项或通过el
选项指定的挂载元素中提取出的 HTML 模板编译渲染函数。
对不同构建版本的解释
- 完整版:同时包含编译器和运行时的版本。
- 编译器:用来将模板字符串编译成为 JavaScript 渲染函数的代码。
- 运行时:用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码。基本上就是除去编译器的其它一切。
源码入口文件
完整版(编译器+运行时) | 编译器 | 运行时 |
---|---|---|
entry-runtime-with-compiler.js | entry-compiler.js | entry-runtime.js |
区别
运行时(entry-runtime.js)
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
完整版(entry-runtime-with-compiler.js)
const idToTemplate = cached(id => {
const el = query(id)
return el && el.innerHTML
})
/**
* Get outerHTML of elements, taking care
* of SVG elements in IE as well.
*/
function getOuterHTML (el: Element): string {
// 从注释来看,svg是没有outerHTML的,
// 想要获取html字符串要做兼容
if (el.outerHTML) {
return el.outerHTML
} else {
const container = document.createElement('div')
container.appendChild(el.cloneNode(true))
return container.innerHTML
}
}
const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
el?: string | Element,
hydrating?: boolean
): Component {
el = el && query(el)
/* istanbul ignore if */
if (el === document.body || el === document.documentElement) {
// el 不能为body和html
process.env.NODE_ENV !== 'production' && warn(
`Do not mount Vue to <html> or <body> - mount to normal elements instead.`
)
return this
}
const options = this.$options
// resolve template/el and convert to render function
if (!options.render) {
// 没有render函数,如果 Vue 选项中包含渲染函数,该模板将被忽略。
let template = options.template
if (template) {
// 使用了模版语法
if (typeof template === 'string') {
if (template.charAt(0) === '#') {
// 如果值以 # 开始,则它将被用作选择符,并使用匹配元素的 innerHTML 作为模板。
template = idToTemplate(template)
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !template) {
warn(
`Template element not found or is empty: ${options.template}`,
this
)
}
}
} else if (template.nodeType) {
// 判断这是一段html
template = template.innerHTML
} else {
if (process.env.NODE_ENV !== 'production') {
warn('invalid template option:' + template, this)
}
return this
}
} else if (el) {
// 使用了el的情况
template = getOuterHTML(el)
}
if (template) {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile')
}
const { render, staticRenderFns } = compileToFunctions(template, {
outputSourceRange: process.env.NODE_ENV !== 'production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters: options.delimiters,
comments: options.comments
}, this)
// 用compile方法,将template转换成render
options.render = render
options.staticRenderFns = staticRenderFns
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
mark('compile end')
measure(`vue ${this._name} compile`, 'compile', 'compile end')
}
}
}
return mount.call(this, el, hydrating)
}
从源码来看,完整版多了针对template的处理,使用compile方法将template转换成了render函数。