vue $mount 和 el的区别说明
两者在使用效果上没有任何区别,都是为了将实例化后的vue挂载到指定的dom元素中。
如果在实例化vue的时候指定el,则该vue将会渲染在此el对应的dom中,反之,若没有指定el,则vue实例会处于一种“未挂载”的状态,此时可以通过$mount来手动执行挂载。
注:如果$mount没有提供参数,模板将被渲染为文档之外的的元素,并且你必须使用原生DOMAPI把它插入文档中。
例如:
varMyComponent=Vue.extend({
template:'Hello!'
})
//创建并挂载到#app(会替换#app)
newMyComponent().$mount('#app')
//同上
newMyComponent({el:'#app'})
//或者,在文档之外渲染并且随后挂载
varcomponent=newMyComponent().$mount()
document.getElementById('app').appendChild(component.$el)
补充知识:Vue实例挂载方法($mount)的实现
在Vue的_init方法中已经回调了beforeCreate和created这两个生命周期钩子,在此之后就进行了实例的挂载
if(vm.$options.el){//挂载实例
vm.$mount(vm.$options.el);
}
在挂载函数中,将要进行beforeMount和mounted的回调。
在不同的平台下对于$mount函数的实现是有差异的,下面考虑web平台的runtime-with-compiler版本,其在web平台下的定义如下(src/platforms/web/runtime/index.js)
import{mountComponent}from'core/instance/lifecycle';
Vue.prototype.$mount=function(
el?:string|Element,
hydrating?:boolean
):Component{
el=el&&inBrowser?query(el):undefined;
returnmountComponent(this,el,hydrating);
};
在$mount函数的参数中,第一个为我们属性的el,第二个参数为服务端渲染有关,在patch函数中用到,这里可以忽略。
但是在调用这个$mount函数的时候,首先调用的是不同版本下的$mount函数,然后在该函数中再调用相应平台的$mount函数,如下在runtime-with-compiler版本中$mount函数如下(src/platforms/web/entry-runtime-with-compiler.js)
importVuefrom'./runtime/index';
constmount=Vue.prototype.$mount;//缓存上面的$mount方法
Vue.prototype.$mount=function(
el?:string|Element,
hydrating?:boolean
):Component{
el=el&&query(el);
//不能挂载到body和html上
if(el===document.body||el===document.documentElement){
returnthis;
}
constoptions=this.$options;
if(!options.render){//如果没有render函数
//...将render函数添加到options上
const{render,staticRenderFns}=compileToFunctions(template,{
outputSourceRange:process.env.NODE_ENV!=='production',
shouldDecodeNewlines,
shouldDecodeNewlinesForHref,
delimiters:options.delimiters,
comments:options.comments,
},this);
options.render=render;
options.staticRenderFns=staticRenderFns;
//...
}
returnmount.call(this,el,hydrating);
};
可知该函数主要干了三件事
1、由于挂载之后会替换被挂载的对象,所以限制不能挂载到body和html上
2、如果当前Vue实例没有render()函数(写template等),则通过编译等手段,将render函数添加到options上
3、调用在代码开头我们先缓存的$mount方法,该方法就是web平台下的方法。
在web平台下的$mount方法里面主要就是调用了mountComponent()方法,接下来我们的核心就是该方法了
在'core/instance/lifecycle.js文件中我们找到了该方法的定义,删掉一些非重点代码后如下
exportfunctionmountComponent(
vm:Component,
el:?Element,
hydrating?:boolean
):Component{
vm.$el=el;
if(!vm.$options.render){
//不是重点,该处主要是用来对没有render函数下的一些错误提示
}
callHook(vm,'beforeMount');//回调beforeMount,开始准备挂载实例
//声明更新组件的函数(源代码中有关performance配置不是重点,故省略)
constupdateComponent=updateComponent=()=>{
vm._update(vm._render(),hydrating);
};
//new一个Watcher[isRenderWatcher]
newWatcher(vm,updateComponent,noop,{
before(){
if(vm._isMounted&&!vm._isDestroyed){
callHook(vm,'beforeUpdate');
}
},
},true/*isRenderWatcher*/);
hydrating=false;
//Vue的根实例的mounted回调在这里执行
if(vm.$vnode==null){
vm._isMounted=true;
callHook(vm,'mounted');
}
returnvm;
}
上面的代码中主要干了如下三件事
1、回调beforeMount
2、生成updateComponent方法,该方法将vnode渲染为真实的DOM
3、new一个Watcher,并在该Watcher在调用updateComponent方法
4、回调mounted
对于updateComponent方法较为复杂,其内部主要调用_update()将vnode渲染为浏览器上显示的真实DOM
我们考虑如下两个问题
1.Watcher中如何调用updateComponent方法
Watcher函数的构造函数接受如下的参数
constructor( vm:Component, expOrFn:string|Function, cb:Function, options?:?Object, isRenderWatcher?:boolean )
在上面的代码中,updateComponent()方法作为第二个参数传递过来,即构造函数中的expOrFn
往下看会看到
if(typeofexpOrFn==='function'){
this.getter=expOrFn;
}
也就是说updateComponent()方法被设置为了getter()方法
看到构造函数的最后
this.value=this.lazy ?undefined :this.get();
其中lazy属性的值在前面被设置为了false
this.lazy=!!options.lazy;//我们options中没有lazy属性
这也就是说,咋i构造函数的末尾会调用this.get(),而在this.get()中
constvm=this.vm;
try{
value=this.getter.call(vm,vm);
}
我们看到调用了getter()方法,也就是调用了updateComponent()方法。
2.为什么根实例的$vnode为空
在initRender()函数中有如下代码
constparentVnode=vm.$vnode=options._parentVnode;
也就是说当前实际的$vnode值为其父节点的vnode值
而根实例没有父节点,故其$vnode值就为空了,所以会执行
if(vm.$vnode==null){
vm._isMounted=true;
callHook(vm,'mounted');
}
那么子节点的mounted回调是在那里执行的呢?
在path()(core/vdom/patch.js)函数中有如下代码
functioninvokeInsertHook(vnode,queue,initial){
if(isTrue(initial)&&isDef(vnode.parent)){
vnode.parent.data.pendingInsert=queue;
}
else{
for(leti=0;i
在循环queue的时候,调用了insert()方法,该方法为VNodeHooks,其在componentVNodeHooks(core/vdom/create-component.js)中声明,代码如下
constcomponentVNodeHooks={
insert(vnode:MountedComponentVNode){
const{context,componentInstance}=vnode;
if(!componentInstance._isMounted){
componentInstance._isMounted=true;
callHook(componentInstance,'mounted');//这里
}
if(vnode.data.keepAlive){
if(context._isMounted){
queueActivatedComponent(componentInstance);
}
else{
activateChildComponent(componentInstance,true/*direct*/);
}
}
},
}
由于path()方法在_update()函数中调用,这部不再重点说明。
下节我们将来说说render()和_update()方法的实现
以上这篇vue$mount和el的区别说明就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。