Vue.js进阶系列(4)--模板抽离和组件数据存放

  通过前面语法糖的介绍,我们简化了组件注册的步骤,但是对于template模块的书写还是比较繁琐,下面小编为大家分享两种方法来实现template模板的抽离并且告诉大家组件能否操作Vue实例中的数据

一、模板抽离

1.使用script标签

使用script标签,直接将原本template的内容直接复制到script下即可。

    <body>
        <div class="warp">
            <cnp></cnp>
        </div>
        <!-- 使用script标签包裹template模板的内容 -->
        <script type="text/x-template" id="cnp1">
            <div>
                <h1>我是标题</h1>
                <p>我是段落</p>
            </div>
        </script>
        <script>
            Vue.component('cnp',{
                template:'#cnp1'
            })
            
            var vm = new Vue({
                el:'.warp'
            })
        </script>
    </body>

image.png

  在这个例子中,声明了全局组件cnp,并且通过script标签包裹了template的内容,内容可以正常的显示,但是要注意以下两点:
  ① script标签的类型: 此时script标签的类型变成了x-template,不在是原来的javascript类型
  ② script标签和template的联系script标签和template之间是没有联系的,为了让script标签的内容传递到template中,需要通过选择器建立起链接。比如本例中就为script声明了id名为cnp1的id选择器,然后在template使用cnp1就可以将cnp1的HTML内容模板传递到template中

2.使用template标签

  template标签的用法和普通标签的用法是一样的,直接将模板的内容赋值到该标签即可。

    <body>
        <div class="warp">
            <cnp></cnp>
        </div>
        <!-- 使用template标签包裹template模板的内容 -->
        <template id="cnp1">
            <div>
                <h1>我是标题</h1>
                <p>我是段落</p>
            </div>
        </template>
        <script>
            Vue.component('cnp',{
                template:'#cnp1'
            })
            
            var vm = new Vue({
                el:'.warp'
            })
        </script>
    </body>

image.png

  可以看到是同样的效果,同理,为了将template标签和组件中的template建立起联系,也需要通过建立选择器来建立关联。比如本例中为template标签声明了id名为cnp1的id选择器,然后在cnp组件的template中使用“cnp1”.
  以上通过使用script标签和template标签就可以将组件中的模板抽离出来让代码有了更强的可读性

二、组件数据存放

  在前面有关组件的知识中可以发现,小编在组件的template是数据都是写死的,那么我们能不能通过使用"{{变量}}"这种形式来访问Vue实例中的数据呢?让我们来看一下下面的例子:

    <body>
        <div class="warp">
            <cnp></cnp>
        </div>
        <template id="cnp1">
            <div>{{message}}</div>
        </template>
        <script>
            Vue.component('cnp',{
                template:'#cnp1'
            })
            
            var vm = new Vue({
                el:'.warp',
                data:{
                    message:"我是标题"
                }
            })
        </script>
    </body>

image.png

  没有显示出mssage的内容,并且说message是未定义的。
结论:
  组件是不能够使用Vue实例中的data数据,说明组件应该有属于自己的数据data。
分析:
  组件是一个单独功能模块的封装,有属于自己的HTML模板,也应该有属于自己的数据data。即使组件可以访问Vue实例中的数据,但是如果将所有数据都放在Vue实例中,Vue实例就会变得非常臃肿【因为前面提到,所有的组件最终会形成一棵组件树】

1.组件数据存放

  按照上面是思路,组件会有自己的data属性,然后我们将message变量放在data属性中,代码如下:

<template id="cnp1">
    <div>{{title}}</div>
</template>
<script>
    Vue.component('cnp',{
        template:'#cnp1',
        data:{
                title:"我是标题"
            }
    })
</script>

image.png

  由结果可以看出,组件中的data并不想Vue实例中的data一样是一个对象,而应该是一个函数,并且返回的是一个实例,所以组件中data的书写应该如下:

<template id="cnp1">
    <h1>{{title}}</h1>
</template>
<script>
    Vue.component('cnp',{
        template:'#cnp1',
        data:function(){
            return {
                    title:"我是标题"
                }
            }
    })
</script>

image.png

因此,对于组件数据的存放总结一下几点:
  ① 组件对象属于自己的data
  ② data是一个函数,并且返回的是一个实例对象
  ③ 对象内部保存着数据
此外呢,组件对象也有像Vue实例一样拥有method等属性,只有data属性必须是一个函数,其余的和Vue实例中的保持一致

接下来我们讨论一个很严肃的问题:

为什么组件中的data是一个函数而不是对象?

这个缘由我们的先从函数说起。先来看下面的代码:

const obje= {
            name:'why',
            age:18,
        }   
function abc(){
    return obje
}   
    let obje1 = abc();
    let obje2 = abc();
    let obje3 = abc();

    obje1.name='Hello'
    console.log('obje1.name:'+ obje2.name);
    console.log('obje2.name:'+ obje2.name);
    console.log('obje3.name:'+ obje3.name);

image.png

  由图可知他们是同一个对象。其实可以这样子理解:声明的obje对象就代表了一块内存地址(假设内存地址为0x110),函数abc返回obje对象时其实就是返回了0x110,不管调用多少次,返回的内存地址都是一样的。当obje1修改的那么值时,其实就相当于修改了内存地址存储的name值,所以obje2和obje3的值也会发生改变。具体如下图:
函数.png

接下来我们再来看一段代码:

function abc(){
    return {
            name:'why',
            age:18,
            }
    }
    let obje1 = abc();
    let obje2 = abc();
    let obje3 = abc();

  在上面的代码中,定义了一个名字为abc的函数,并且返回一个对象,该对象有name属性和age属性,然后调用三次abc函数并以此存储在变量obje1,obje2,obje3中。那我们思考一下,obje1、obje2、obje3是不是同一个对象?
  结论是** 它们并不是同一个对象,因为函数每次被调用的时候,都会在自己的栈空间创建很多的变量。想要验证是不是同一个对象其实很简单,如果是同一个对象,有一个特点:牵一发而动全身**,我们修改obje1的值,如果obje2和obje3的值也跟着改变,说明是同一个对象,否则就不是,让我们来看下面的例子:

obje1.name='Hello'
console.log('obje1.name:'+ obje2.name);
console.log('obje2.name:'+ obje2.name);
console.log('obje3.name:'+ obje3.name);

image.png

  可以发现,obje2和obje3的值么有发生变化,说明他们不是同一个对象,具体分析如下:
  声明的变量obje1会指向abc函数返回的结果,因为每次调用函数时,函数都会在自己的栈空间创建,所以调用三次函数,相当于创建了三块东西,而变量存储的内容就是这三块东西的地址,具体如下图所示:
函数.png

  这也就是为什么组件数据存放是函数而不是属性的原因
  组件是具有特定功能的单独的个体,我们希望在页面1中定义的组件也能在页面2中使用,如果组件的数据存储不是函数,当我们修改页面1中的组件就会导致页面2中的组件也发生改变,这是我们不希望看到的。下面通过例子来为大家讲解:

    <body>
        <div class="warp">
            <cnp></cnp>
            <cnp></cnp>
            <cnp></cnp>
        </div>
        <template id="cnp1">
            <div>
                <h1>{{title}}{{counter}}</h1>
                <button @click='increment'>+</button>
                <button @click='decrement'>-</button>
            </div>
        </template>
        <script>
            Vue.component('cnp',{
                template:'#cnp1',
                data:function(){
                    return {
                        title:"当前数值:",
                        counter:0
                    }
                },
                methods:{
                    increment(){
                        this.counter ++;
                    },
                    decrement(){
                        this.counter --;
                    }
                }
            })
            var vm = new Vue({
                el:'.warp',
            })
        </script>
    </body>
组件.gif

  在这里例子中,我们在组件中用了简单的计数器。这是我们希望看到的效果,当点击第一个计数器,不会影响到下面两个计数器,而如果把组件中的数据代码块换成下面这就写法,就会产生十分恐怖的事情:

const obje = {
            title:"当前数值:",
            counter:0
        }
Vue.component('cnp',{
    template:'#cnp1',
    data:function(){
            return obje
        },
组件.gif

  所以这就是为什么在开发Vue的时候,组件数据存储的data必须是函数而不是属性。

  以上就是小编今天为大家分享的知识,可能后面关于组件数据的存放讲解的不是很到位,希望大家多多包涵。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容