- 1. 一个页面是否可以创建多个
Vue
实例 - 2. 当
el
匹配多个元素时,Vue
实例会不会分别在每个元素上渲染 - 3. 多个
Vue
实例挂载到同一个元素上,最终会显示哪一个 - 4.
Vue
可以用来实例化,那组件可不可以实例化 - 5. 一个组件是否可以注册为多个组件名
- 6. 多个
Vue
实例是否可以共用一个Vue Router
实例 - 7. 多个
Vue
实例是否可以共用一个Store
实例
近期项目需要用到
Vue
,但又不是整个项目都用Vue
的那种,只是部分功能需要使用,这个时候,就需要单独引入Vue
的js
文件来完成,官方文档虽然有使用说明,但是相对于整个项目都用Vue
来写的文档,单独引用vuejs
文件的使用说明相对来说要少一些,这个时候就需要对Vue
有深入的理解,才能够正确使用,本人也是在此次摸索的过程中,对Vue
有了更深入的理解。不再是之前整个项目都用Vue
脚手架去搭建,只是会用,却不知道内部原理。
首先我们思考几个问题:
- 一个页面是否可以创建多个
Vue
实例; - 当
el
匹配多个元素时,Vue
实例会不会分别在每个元素上渲染; - 多个
Vue
实例挂载到同一个元素上,最终会显示哪一个; -
Vue
可以用来实例化,那组件可不可以实例化; - 不同标签是否可以引用同一个组件,即:一个组件是否可以命名多个
name
; - 多个
Vue
实例是否可以共用一个Vue Router
实例 - 多个
Vue
实例是否可以共用一个Store
实例
1. 一个页面是否可以创建多个Vue
实例
- 我们用vue脚手架搭建项目的时候,只会创建一个
Vue
实例,那实际情况到底是Vue
只能创建一个实例,还是可以多个,话不多说,我们看代码:
<body>
<div class="app1">
{{message}}
</div>
<div id="html">
非vue代码
</div>
<div class="app1 app2">
{{message}}
</div>
<script>
<!-- 初始化第一个实例-->
var vm1 = new Vue({
el:".app1",
data:{
message: "vue第一个实例",
commont:"公用data"
}
});
<!-- 初始化第二个实例-->
var vm2 = new Vue({
el:".app2",
data:{
message: "vue第二个实例",
}
});
</script>
</body>
- 打开页面,我们看到的效果如下所示:
结果验证:一个页面是可以实例化多个
Vue
实例,因为每一个Vue
都对应一个自己的el
,它的作用就是指定在html
的哪个元素中插入Vue
渲染的DOM树,这样不但可以保证Vue
代码正常解析,还能保证一个页面有多个Vue
实例的时候,数据不会互相影响。
2. 当el
匹配多个元素时,Vue
实例会不会分别在每个元素上渲染
-
Vue
的官方文档描述,el
的值传的都是id选择器,那如果我们给el
传普通的选择器,比如:类选择器,当这个选择器能够匹配到页面中的多个元素时,Vue
实例会不会分别在每个元素上渲染,我们来测试一下,代码如下:
<body>
<div class="app1">{{message}}</div>
<div id="html">非vue代码</div>
<div class="app1">{{message}}</div>
<script>
//初始化第一个实例
var vm1 = new Vue({
el:".app1",
data:{
message: "vue第一个实例",
}
});
</script>
</body>
- 打开页面,我们看到的效果如下所示:
根据页面解析情况,我们得出如下结论:当
el
匹配到多个元素时,它并不会在每个元素上都渲染,而是在匹配到的第一个元素上渲染。所以这样的结果正好也说明了官方文档上为什么给el
传的都是id
选择器而不是类选择器了。
3. 多个Vue
实例挂载到同一个元素上,最终会显示哪一个
- 当对同一个元素多次进行实例化的时候,最终会显示哪一个,测试代码如下:
<body>
<div class="app1">{{message}}</div>
<div id="html">非vue代码</div>
<script>
//初始化第一个实例
new Vue({
el:".app1",
data:{
message: "第一个Vue实例",
}
});
//初始化第二个实例
new Vue({
el:".app1",
data:{
message: "第二个Vue实例",
}
});
</script>
</body>
- 打开页面,效果如下:
- 在没有测试之前,我认为多个
Vue
实例是可以挂载到同一个元素上的,并且最终展示的是最后一次挂载的Vue
实例的效果,而结果看起来好像是显示的第一个实例的效果,这和我的预期不符,我想知道出现这样的结果的原因?经过调试发现,造成上述问题的原因是:当第一个Vue
实例化以后,{{message}}
已经被解析替换,这个时候app1
的内容变为<div class = "app1">第一个Vue实例</div>
,当第二个Vue
实例再挂载到app1
的时候,数据绑定语句{{message}}
已经不存在,所以第二个Vue
实例的数据message
的值不会被渲染,所以页面也不会如我们预期的会显示:<div class = "app1">第二个Vue实例</div>
,同样我们也不能依赖这个结果而判定,当多个实例挂载到同一个元素上时,只会显示第一个实例的效果。为了避免由于其他原因而影响测试结果,我又进行了第二次测试,利用template
的模板特性(Vue
实例化的时候,如果配置了template
选项,那这个template
的值,会作为内容替换掉el
选择的元素及其子元素)而我们刚好可以通过查看template
模板是否生效来作为判定的依据,但是我们得考虑一个问题,如果第一次实例化的时候我们配置template
模板,当第二次实例化的时候,可能el
选择的元素已经不存在了(被模板替换了)这个时候也会影响结果,即使我们可以将第一个实例的模板的根元素设置成与el
相同的标签和属性,以保证el
元素即使被template
替换,仍然也会存在。
但是这个时候,el
选择的元素和最初的el
所选择的元素已经不是同一个元素,这样也难免会影响判断结果。所以,经过一番考虑以后,我决定第一个Vue
实例不配置template
模板,这样可以保证第二次和第一次实例化的时候,el
选择的是同一个元素,同时,第二个实例配置template
模板,这样可以通过页面的显示效果来判断,实例化是否成功。测试代码如下:
<body>
<div class="app1">{{message}}</div>
<div id="html">非vue代码</div>
<script>
//初始化第一个实例
new Vue({
el:".app1",
data:{
message: "第一个Vue实例",
}
});
//初始化第二个实例
new Vue({
el:".app1",
template:"<div>第二个Vue实例</div>"
});
</script>
</body>
- 打开页面,效果如下:
很显然,最终显示的是第二个
Vue
实例的效果,到此我们才可以判断多个Vue
实例是可以挂载到同一个元素上的,并且最终展示的是最后一个被挂载的Vue
实例的效果。
4. Vue
可以用来实例化,那组件可不可以实例化
- 通常我们写vue项目,都是把一个
app
作为一个组件,然后再通过Vue
实例化,把这个组件当成一个根组件来用,代码如下:
<body>
<div id="app">
<app></app>
</div>
<script>
var APP={
template: '<div>我是组件-----{{compontentData}}</div>',
data:function () {
return{
compontentData:"组件的数据"
}
}
} ;
var Component = Vue.component('app',APP);
new Vue({
el:"#app",
})
</script>
</body>
- 打开页面,我们看到的效果如下所示:
- 虽然看起来页面没有什么问题,但是我们会不会觉得,这样写的话,页面结构有点冗余,因为
APP
组件是被包在根组件(Root)里面,那我们可不可以直接把APP
组件做为根组件呢?要想实现这个效果,除非组件也能进行实例化才可以,于是我们来大胆尝试一下,实例化组件,看是否可行。
代码如下:
<body>
<div id="app">
<dyx></dyx>
</div>
<script>
var Dyx={
template: '<div>我是组件-----{{compontentData}}</div>',
data:function () {
return{
compontentData:"组件的数据"
}
}
} ;
var DyxComponent = Vue.component('dyx',Dyx);
new DyxComponent({
el:"#app",
})
</script>
</body>
- 打开页面,我们看到的效果如下所示:
测试证明:
Vue
组件是可以被实例化的,并且也可以作为根组件来渲染到元素上,这样就少一层组件的嵌套,效果是实现了,那组件可以被实例化的原理是什么呢?这就需要我们去查一下官网API
,官网文档是这样描述组件注册的:
// 注册组件,传入一个扩展过的构造器
Vue.component('my-component', Vue.extend({ /* ... */ }))
// 注册组件,传入一个选项对象 (自动调用 Vue.extend)
Vue.component('my-component', { /* ... */ })
// 获取注册的组件 (始终返回构造器)
var MyComponent = Vue.component('my-component')
那我们在看一下extend
构造器又是什么?
看完官方的
API
我们深刻理解了:Vue
的组件就是Vue
的子类,那类有继承的概念,Vue
是一个类,Vue
的组件是Vue
的子类,所以Vue
所具有的特性,Vue
组件也都具有,Vue
能被实例化且渲染到元素上,Vue
组件也能被实例化且渲染到元素上,这就是Vue
组件可以被实例化的本质。
5. 一个组件是否可以注册为多个组件名
- 首先我们看一下
Vue
是如何定义组件的,官方文档如下:
- 其实这部分代码,包含了两个步骤,组件的定义和组件的注册:
- 我们先定义一个组件,代码如下:
var Dyx={
template: '<div>我是组件dyx</div>',
data:function () {
return{
compontentData:"组件的数据"
}
}
} ;
- 然后给这个组件全局注册两个名字(
dyx
,gby
),代码如下:
Vue.component('dyx',Dyx);
Vue.component('gby',Dyx);
- 然后在页面里面使用,代码如下:
<div id="app">
<dyx></dyx>
<gby></gby>
</div>
- 打开浏览器,我们来看一下页面的效果:
结果证明,一个组件是可以注册多个名字的,为什么可以呢?因为组件最重要的是定义,而名字只是起到一个映射的作用,以便让解析器可以通过名字找到对应的组件的定义。
6. 多个Vue
实例是否可以共用一个Vue Router
实例
- 首先我们看一下代码:
<body>
<!--第1个vue-->
<div id="routerele1">
<p>第<span class="vue1">1</span>个vue实例</p>
<div>
<p><router-link to="/foo">GO to foo</router-link></p>
<p><router-link to="/bar">GO to bar</router-link></p>
</div>
<p>第<span class="vue1">1</span>个路由显示的地方</p>
<div class="routerView"><router-view></router-view></div>
</div>
<!--第2个vue-->
<div id="routerele2">
<p>第<span class="vue2">2</span>个vue实例</p>
<div>
<p><router-link to="/foo">GO to foo</router-link></p>
<p><router-link to="/bar">GO to bar</router-link></p>
</div>
<p>第<span class="vue2">2</span>个路由显示的地方</p>
<div class="routerView"><router-view></router-view></div>
</div>
<script src="vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
<script>
// 定义路由
var Foo = {template: '<div>foo路径</div>'};
var Bar = {template: '<div>bar路径</div>'};
var routes = [
{path: '/foo', component: Foo},
{path: '/bar', component: Bar}
];
var router = new VueRouter({routes: routes});
//初始化第1个vue
new Vue({
router: router
}).$mount('#routerele1');
//初始化第2个vue
new Vue({
router: router
}).$mount('#routerele2');
</script>
</body>
- 打开浏览器,我们点击第1个
Vue
的路由foo
来看一下页面的效果:
3.然后我们点击第2个Vue
的bar
路由,来看一下页面的效果:
结果证明,多个
Vue
实例可以共用一个路由Vue Router
实例的。这也说明了,Vue Router
底层实现中,是支持多个Vue
实例作为监听者的。
7. 多个Vue
实例是否可以共用一个Store
实例
- 上面我们已经验证,多个
Vue
实例可以共用一个路由实例,那我不禁又想到另外一个问题,多个Vue
实例是否也可以共用一个Store
实例呢?检验方法如下:
- 首先我们看一下代码:
<body>
<div class="app1" @click="changeStore()">{{count1}}</div>
<div id="html">非vue代码</div>
<div class="app2">{{count2}}</div>
<script>
var store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}
});
//初始化第一个实例
new Vue({
el:".app1",
store:store,
computed: {
count1:function () {
return this.$store.state.count
}
},
methods:{
changeStore:function () {
store.commit('increment') ;
}
},
});
//初始化第二个实例
new Vue({
el:".app2",
store:store,
computed: {
count2:function () {
return this.$store.state.count
}
},
});
</script>
</body>
-
打开页面,效果如下:
共用store
改变其中一个store的值我们初始化一个
Store
实例,然后给两个Vue
实例配置同一个Store
实例,页面显示,两个实例都可以获取Store
里面的count
,哪如果我们手动修改(触发@click
事件)其中一个Vue
实例里面的Store
里面的值,另外一个Vue
实例的Store
值又会是什么样的结果呢?测试页面效果如下:
结果显示,两个
Vue
实例显示的Store
里的count
的值是一样的,这样也就证明了,多个Vue
实例是可以共用一个Store
实例的。
虽然以上的测试和想法,在实际项目中我们可能不会去应用,但是经过我们的思考、测试、验证,起码可以让我们对
Vue
框架有一个更深层次的理解,从而也能更好的应用框架。
以上就是本人对Vue
的理解及研究,有判断不对的地方,欢迎大家留言指正。
网友评论