vue学习笔记(三)

一、组件

(一)什么是组件

组件(Component)是 Vue.js最强大的功能之一。组件可以扩展 HTML元素,封装可重用的代码组件是自定义元素(对象)。

(二)创建组件的两种方式

官方推荐组件标签名是使用-连接的组合词,例如:<my-hello></my-hello>

1、使用构造器创建组件

使用这种方式创建组件首先需要使用Vue.extend()创建一个组件构造器,然后使用Vue.component(标签名,组件构造器),根据组件构造器来创建组件。

//1.创建构造器
var MyComponent=Vue.extend({
    template:'<h3>Hello World</h3>'
});
//2.创建组件
Vue.component('my-hello',MyComponent);

//3.使用组件
<div id="app">
    <my-hello></my-hello>
</div>

这种创建组件的方式比较麻烦,使用的较少。

2、直接创建组件

使用Vue.component(标签名,组件模板),根据组件构造器来创建组件。

//1.创建组件
 Vue.component('my-world', {
    template: '<h2>hello vue.js</h2>'
 });
 
//2.使用组件
<div id="app">
    <my-world></my-world>
</div>

(三)组件的分类

组件分为全局组件和局部组件。

1、全局组件

使用Vue.component()创建的组件都是全局组件。这样的组件在任何组件内都能使用。上面我们创建就是全局组件。

2、局部组件

局部组件一般都是定义在实例的选项中,称为实例的子组件。相应的,实例也被称为父组件。

//1.定义组件
 new Vue({
    el: '#app',
    components: {
        dawei: {
            template: '<h2>my name is dawei</h2>'
        }
    }
});
//2.使用组件
<div id="app">
    <dawei></dawei>
</div>

(四)引用模板

很多时候我们的template模板中需要存放很多标签内容,这样的话写起来会很麻烦。这时候我们可以使用template标签。

用法如下:

<template id="wbs">    //使用template标签
    <div>
        <h2>hello {{msg}}</h2>
        <ul>
            <li v-for="value in arr">
                {{value}}
            </li>
        </ul>
    </div>
</template>
    
    new Vue({
        el: '#app',
        components: {
            'my-dawei': {
                template: '#wbs',  //选择template标签
                data() {
                    return {
                        msg: 'vue.js',
                        arr: ["a", "b", "c", "d"]
                    }
                }
            }
        }
    });

这里涉及到的几个知识点得着重提一下:

  • template模板中,所有的元素必须放置在一个根元素中,要不然会报错。例子中我们将元素放置在了<div>标签中。

  • 组件中的data选项必须是一个函数类型,使用return返回所有的数据。

(五)动态组件

很多时候项目中需要在某一个地方动态的使用不同的组件,这时候就需要使用动态组件。
动态组件的使用需要绑定is属性:

<component :is="flag"></component>

简单示例:

//点击按钮显示不同的组件
 <div id="app">
    <button type="button" @click="flag='my-a'">显示a组件</button>
    <button type="button" @click="flag='my-b'">显示b组件</button>

    <component :is="flag"></component>  //传入flag
</div>

new Vue({
    el: '#app',
    data: {
        flag: 'my-a'   //给flag赋值
    },
    components: {
        'my-a': {
            template: '<p>我是a组件</p>',
        },
        'my-b': {
            template: '<p>我是b组件</p>'
        }
    }
});

(六)keep-alive组件

使用keep-alive组件缓存非活动组件,可以保留状态,避免重新渲染,默认每次都会销毁非活动组件并重新创建。

使用范例:

<keep-alive>
     <component :is="flag"></component>
</keep-alive>

 <div id="app">
    <button type="button" @click="flag='my-x'">x</button>
    <button type="button" @click="flag='my-y'">y</button>
    <keep-alive>
        <component :is="flag"></component>
    </keep-alive>
 </div>
 
 new Vue({
    el: '#app',
    data: {
        flag: 'my-x'
    },
    components: {
        'my-x': {
            template: '<p>{{x}}</p>',
            data() {
                return {
                    x: Math.random()
                }
            }
        },
        'my-y': {
            template: '<p>{{y}}</p>',
            data() {
                return {
                    y: Math.random()
                }
            }
        }
    }
 });

这样的话,第一次产生的随机数就会被缓存,再次切换的时候也不会发生改变。

二、 组件间数据传递

(一)父子组件

在一个组件内部定义另一个组件,那么这对组件称为父子组件。子组件只能在父组件内部使用。默认情况下,每个组件实例的作用域是独立的,子组件无法访问父组件中的数据,同样,父组件也无法访问子组件中的数据。


<div id="app">
    <my-a></my-a>
        <!-- 父组件 -->
</div>

<template id="a">
    <div>
        <p>{{msg}}</p> 
        <my-b></my-b>    <!-- 在父组件中调用子组件 -->
    </div>
</template>

<template id="b">
    <div>
        <p>{{mydata}}</p>
    </div>
</template>

<script>
    new Vue({   //根组件
        el: '#app',
        components: {     //子组件写在components选项中
            "my-a": {     //b组件的父组件
                template: "#a",
                data() {
                    return {
                        msg: '我是父组件',
                    }
                },
                components: { //子组件写在父组件的components选项中
                    "my-b": {
                        template: "#b",
                        data() {
                            return {
                                mydata: "我是子组件"
                            }
                        }
                    }
                }
            }
        }
    });
</script>

(二)组件间数据传递(通信)

1、子组件访问父组件的数据

步骤:

  • a、调用子组件时,绑定想要获取的父组件中的数据
  • b、在子组件内部,使用props选项声明获取的数据,即接收来自父组件的数据

改进上面的例子:

<div id="app">
    <my-a></my-a>
</div>

<template id="a">
    <div>
        <p>{{msg}}</p> 
        <p>这是要传递给子组件的值:{{myname}}</p>
        <my-b :name="myname"></my-b>   <!-- 绑定子组件想要获取的数据 -->
    </div>
</template>

<template id="b">
    <div>
        <p>{{mydata}}</p>
        <p>这是父组件传递过来的数据:{{name}}</p>
    </div>
</template>

<script>
    new Vue({
        el: '#app',
        data: {},
        components: {
            "my-a": {
                template: "#a",
                data() {
                    return {
                        msg: '我是a组件',
                        myname: '子组件b你好,我是父组件a'
                    }
                },
                components: {
                    "my-b": {
                        template: "#b",
                        data() {
                            return {
                                mydata: "我是b组件"
                            }
                        },
                        props: ["name"] //子组件使用props声明想要获取的数据
                    }
                }
            }
        }
    });
</script>

2、父组件访问子组件的数据

步骤:

  • a 在子组件中使用vm.$emit(事件名,数据)触发一个自定义事件,将数据发送给父组件,事件名自定义
  • b 父组件在使用子组件的地方监听子组件触发的事件,并在父组件中定义方法,用来获取数据
//子组件‘my-b’内部
methods:{
    send(){//使用$emit()触发一个事件,发送数据,this指当前子组件实例
        this.$emit('e-world', this.senddata);         
    }
}

//在调用子组件的地方监听子组件触发的事件,调用自己的方法获取数据
<my-b @e-world="getData"></my-b>   


 methods: {
    getData(data) {  //参数是子组件传递过来的数据
        this.revicedata = data;
    }
 }

3、单向数据流

props是单向数据绑定的,当父组件数据发生变化时,将传递给子组件,但是不会反过来。而且不允许子组件直接修改父组件中的数据,强制修改会报错。

解决方案:

  • 如果子组件想把它作为局部数据来使用,可以将数据存入另一个变量中再操作,不影响父组件中的数据
  • 如果子组件想修改数据并且同步更新到父组件,两个方法:
    • 使用.sync显式地触发一个更新事件(1.0版本中支持,2.0版本中不支持,2.3版本又开始支持)
//使用.sync
 <my-b :name.sync="myname"></my-b> 
 
//子组件修改父组件传入的值name,触发update更新事件
this.$emit('update:name', "vuejs"); 
    • 可以将父组件中的数据包装成对象,然后在子组件中修改对象的属性(因为对象是引用类型,指向同一个内存空间),推荐使用这种方式。
 data() {
    return { //将要传递的数据放入message对象中
        message: {
            hello: '子组件b你好,我是父组件a'
        }
    }
}

<my-b :message="message"></my-b>   //传递这个对象给子组件

 methods: {   //在子组件内部修改这个值,这样就会同步传递给父组件。
    edit() {
        this.message.hello = "hahahahh";
    }
 }

4. 非父子组件间的通信

非父子组件间的通信,可以通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现非父子组件间的通信。

var Event = new Vue();    //空vue实例

 methods: {  
    send() {  //触发emit事件
        Event.$emit("hello", this.asmsg);
    }
 }
 
 mounted() {    //在子组件的钩子函数中监听该事件
    Event.$on('hello', data => {   //获取值
        this.bsmsg = data;  
    })
 }

(三)slot内容分发

用来获取组件中的原内容

var vm = new Vue({
    el: '#app',
    components: {
        'my-hello': {
            template: '#hello'
        }
    }
});

<div id="app">
    <my-hello>hello vue.js</my-hello>
</div>


<template id="hello">
    <div>
        <slot>如果没有原内容,则显示该内容</slot>
    </div>
</template>

如果组件标签中没有内容就会显示slot中的内容,这也就是所谓的单个插槽。

还可以对显示的内容进行分组,这就是具名插槽,可以操作标签组中的内容:

<div id="app">
    <my-hello>
        <ul slot="s1">
            <li>aaa</li>
            <li>bbb</li>
            <li>ccc</li>
        </ul>
        <ol slot="s2">
            <li>111</li>
            <li>222</li>
            <li>333</li>
        </ol>
    </my-hello>
</div>

<template id="hello">
    <div>
        <slot name="s2"></slot> //为插槽指定名称  将名为s2的内容放置在这里
        <p>hello vue.js</p>
        <slot name="s1"></slot>  //将名为s1的内容放置在这里
    </div>
</template>

这样,就可以对组件中的内容实时操作。

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

推荐阅读更多精彩内容

  • 1.安装 可以简单地在页面引入Vue.js作为独立版本,Vue即被注册为全局变量,可以在页面使用了。 如果希望搭建...
    Awey阅读 10,986评论 4 129
  • 这篇笔记主要包含 Vue 2 不同于 Vue 1 或者特有的内容,还有我对于 Vue 1.0 印象不深的内容。关于...
    云之外阅读 5,044评论 0 29
  • Vue 实例 属性和方法 每个 Vue 实例都会代理其 data 对象里所有的属性:var data = { a:...
    云之外阅读 2,198评论 0 6
  • 下载安装搭建环境 可以选npm安装,或者简单下载一个开发版的vue.js文件 浏览器打开加载有vue的文档时,控制...
    冥冥2017阅读 6,027评论 0 42
  • 风拂起了长发青丝划过脸暇原来你如此贴近 站在影子里的你睁开双眼已为你挡住阳光 摩天轮的转动模糊了落日的余晖眼中的你...
    狼眼阅读 726评论 3 0