美文网首页
Vue的深入理解

Vue的深入理解

作者: 代艳霞 | 来源:发表于2020-03-11 22:39 被阅读0次

    近期项目需要用到Vue,但又不是整个项目都用Vue的那种,只是部分功能需要使用,这个时候,就需要单独引入Vuejs文件来完成,官方文档虽然有使用说明,但是相对于整个项目都用Vue来写的文档,单独引用vuejs文件的使用说明相对来说要少一些,这个时候就需要对Vue有深入的理解,才能够正确使用,本人也是在此次摸索的过程中,对Vue有了更深入的理解。不再是之前整个项目都用Vue脚手架去搭建,只是会用,却不知道内部原理。

    首先我们思考几个问题:

    1. 一个页面是否可以创建多个Vue实例;
    2. el匹配多个元素时,Vue实例会不会分别在每个元素上渲染;
    3. 多个Vue实例挂载到同一个元素上,最终会显示哪一个;
    4. Vue可以用来实例化,那组件可不可以实例化;
    5. 不同标签是否可以引用同一个组件,即:一个组件是否可以命名多个name
    6. 多个Vue实例是否可以共用一个Vue Router实例
    7. 多个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实例,因为每一个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匹配到多个元素时,它并不会在每个元素上都渲染,而是在匹配到的第一个元素上渲染。所以这样的结果正好也说明了官方文档上为什么给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>
    
    • 打开页面,效果如下:
    template

    很显然,最终显示的是第二个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是如何定义组件的,官方文档如下:
    组件定义
    • 其实这部分代码,包含了两个步骤,组件的定义和组件的注册:
    1. 我们先定义一个组件,代码如下:
    var Dyx={
            template: '<div>我是组件dyx</div>',
            data:function () {
                return{
                    compontentData:"组件的数据"
                }
            }
        } ;
    
    
    1. 然后给这个组件全局注册两个名字(dyx,gby),代码如下:
    Vue.component('dyx',Dyx);
    Vue.component('gby',Dyx);
    
    1. 然后在页面里面使用,代码如下:
    <div id="app">
        <dyx></dyx>
        <gby></gby>
    </div>
    
    1. 打开浏览器,我们来看一下页面的效果:
    两个组件页面效果

    结果证明,一个组件是可以注册多个名字的,为什么可以呢?因为组件最重要的是定义,而名字只是起到一个映射的作用,以便让解析器可以通过名字找到对应的组件的定义。

    6. 多个Vue实例是否可以共用一个Vue Router实例

    1. 首先我们看一下代码:
    <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. 打开浏览器,我们点击第1个Vue的路由foo来看一下页面的效果:
    foo路由

    3.然后我们点击第2个Vuebar路由,来看一下页面的效果:

    bar路由

    结果证明,多个Vue实例可以共用一个路由Vue Router实例的。这也说明了,Vue Router底层实现中,是支持多个Vue实例作为监听者的。

    7. 多个Vue实例是否可以共用一个Store实例

    • 上面我们已经验证,多个Vue实例可以共用一个路由实例,那我不禁又想到另外一个问题,多个Vue实例是否也可以共用一个Store实例呢?检验方法如下:
    1. 首先我们看一下代码:
    <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实例,然后给两个Vue实例配置同一个Store实例,页面显示,两个实例都可以获取Store里面的count,哪如果我们手动修改(触发@click事件)其中一个Vue实例里面的Store里面的值,另外一个Vue实例的Store值又会是什么样的结果呢?测试页面效果如下:

    改变其中一个store的值

    结果显示,两个Vue实例显示的Store里的count的值是一样的,这样也就证明了,多个Vue实例是可以共用一个Store实例的。

    虽然以上的测试和想法,在实际项目中我们可能不会去应用,但是经过我们的思考、测试、验证,起码可以让我们对Vue框架有一个更深层次的理解,从而也能更好的应用框架。

    以上就是本人对Vue的理解及研究,有判断不对的地方,欢迎大家留言指正。

    相关文章

      网友评论

          本文标题:Vue的深入理解

          本文链接:https://www.haomeiwen.com/subject/enqodhtx.html