【Vue】快乐学习第三篇 组件及组件通信

举报
周棋洛 发表于 2022/05/25 22:29:22 2022/05/25
【摘要】 写在前面 Vue快乐学习第三篇,本节主要学习 Vue 组件化和父子组件通信,通过学习,你应该了解组件化相关概念,学习和使用 Vue 全局组件和局部组件注册,以及父子组件通信...


写在前面

Vue快乐学习第三篇,本节主要学习 Vue 组件化和父子组件通信,通过学习,你应该了解组件化相关概念,学习和使用 Vue 全局组件和局部组件注册,以及父子组件通信等知识,干就完了 🎨

在这里插入图片描述

什么是组件化 ❓

组件化是指解耦复杂系统时将多个功能模块拆分、重组的过程,有多种属性、状态反映其内部特性。

组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:
在这里插入图片描述

组件化目的 📇

为了解耦:把复杂系统拆分成多个组件,分离组件边界和责任,便于独立升级和维护。

组件使用3步骤 🕒

♦️ 创建组件构造器
♦️ 注册组件
♦️ 使用组件

调用 Vue.extend() 插件的是一个组件构造器,通常在创建组件构造器时,传入 template 代表自定义组件的模板,这个模板就是要显示的 HTML 代码,事实上,这种写法实际上基本不使用,但这是基础

调用 Vue.component() 是将刚创建的组件构造器注册成为一个组件,并且给它起一个组件标签名,所以传递了两个参数,1.注册组件的标签名2.组件构造器

组件必须挂载在某个 Vue 实例下,否则是不会生效的
在这里插入图片描述

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

    <script src="./vue.js"></script>

    <script>
        // 1.插件组件构造器
        const hello = Vue.extend({
            template:  `<div>
                            <h1>
                                Hello World
                            </h1>
                        </div>`
        })
        // 2.注册组件
        Vue.component('hello',hello)

        const vm = new Vue({
            el: '#app'
        })
    </script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

全局组件和局部组件 🍓

全局注册

全局注册是通过 Vue.component 注册,它可以被所有 vue 实例使用
在这里插入图片描述

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

    <script src="./vue.js"></script>

    <script>
        // 1.插件组件构造器
        const hello = Vue.extend({
            template:  `<div>
                            <h1>
                                Hello World
                            </h1>
                        </div>`
        })
        // 2.注册组件(全局注册,意味着可以在多个vue实例下使用)
        Vue.component('hello',hello)

        const vm = new Vue({
            el: '#app'
        })
        const vm1 = new Vue({
            el:'#app1'
        })
    </script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

局部注册

局部注册实在某个vue实例内部,通过配置项 components 配置,局部组件只能在注册它的 vue 实例下才可以使用
在这里插入图片描述

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

    <script src="./vue.js"></script>

    <script>
        // 1.插件组件构造器
        const hello = Vue.extend({
            template:  `<div>
                            <h1>
                                Hello World
                            </h1>
                        </div>`
        })
        // 2.注册组件(全局注册,意味着可以在多个vue实例下使用)


        const vm = new Vue({
            el: '#app',
            // 局部注册,只能在当前 vue 实例下使用
            components:{
                hello:hello
            }
        })
        const vm1 = new Vue({
            el:'#app1'
        })
    </script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

父子组件 🎨

组件和组件之间存在关系,最常见的就是父子组件的关系

<body>
<div id="app">
    <c2></c2>
</div>

<script src="./vue.js"></script>
<script>
    // 创建第一个组件
    const c1 = Vue.extend({
        template: `
        <div>
            <p>我是p1</p>
        </div>
        `
    })
    // 创建第二个组件
    const c2 = Vue.extend({
        template: `
          <div>
          <p>我是p2</p>
          <c1></c1>
          <c1></c1>
          </div>
        `,
        components: {
            c1: c1
        }
    })
    new Vue({
        el: '#app',
        data: {
            message: 'Hello World'
        },
        components: {
            c2: c2
        }
    })
</script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

在这里插入图片描述
注意如果在vue实例下写标签 c1 是不正确的,因为我们既没有全局注册 c1 组件,也没有在 vue 实例中进行注册,而是在 c2 组件内部进行了注册,作用域在 c2 组件,所以可以在 c2 的模板中使用,这一点需要注意


注册组件语法糖 🍬

Vue为简化书写组件的过程,提供了注册的语法糖
省去了 Vue.extend() 这个步骤,而是直接使用一个对象来代替

全局注册组件语法糖,直接使用 Vue.component ,第一个配置组件名,第二个是template模板,底层还是extend的形式

<body>
<div id="app">
    <hello></hello>
</div>

<script src="./vue.js"></script>
<script>
    // 全局注册,语法糖,底层还是 extend
    Vue.component('hello',{
        template:`
        <div>
            <h1>Hello World</h1>
        </div>
        `
    })
    new Vue({
        el: '#app'
    })
</script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在这里插入图片描述

局部注册组件语法糖,使用 components 配置项,组件名后跟模板,省去了 Vue.extend()

<body>
<div id="app">
    <hello></hello>
</div>

<script src="./vue.js"></script>
<script>
    new Vue({
        el: '#app',
        components:{
            hello:{
                template:`
                    <div>
                        <h1>Hello World</h1>
                    </div>
                    `
            }
        }
    })
</script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在这里插入图片描述

组件模板抽离的写法 ✍🏼

<body>

    <div id="app">
        <hello></hello>
        <world></world>
    </div>

    <!-- 1. 模板在script标签中写,但是类型必须是 text/x-template 类型 -->
    <script type="text/x-template" id="hello">
        <div>
            <h2>Hello Vue</h2>
        </div>
    </script>

    <!-- 2. 使用template标签 -->
    <template id="world">
        <div>
            <h2>Hello World</h2>
        </div>
    </template>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        Vue.component('hello',{
            template:'#hello'
        })
        Vue.component('World',{
            template:'#world'
        })
        new Vue({
            el: '#app',
        })
    </script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

在这里插入图片描述


为什么组件data必须是函数 ❓

因为以函数形式返回,当多次调用组件,每个组件都会有自己的一份data,彼此互不影响

组件时一个单独模块的封装,这个模块有属于自居的 HTML 模板,也应该有自己的数据 data……
组件是不可以直接访问 Vue 实例的data的
Vue组件应该有自己保存数据的地方

组件对象也有一个 data 属性,也可以有 method 等属性
只是这个 data 属性必须是一个函数
而且这个函数返回一个对象,对象内部保存着数据

<body>

    <div id="app">
        <hello></hello>
    </div>

    <template id="hello">
        <div>
            <h2>{{hello}}</h2>
        </div>
    </template>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        Vue.component('hello', {
            template: '#hello',
            data() {
                return {
                    hello: 'Hello World,Hello Vue.js'
                }
            }
        })

        new Vue({
            el: '#app',
        })
    </script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

在这里插入图片描述

这个计数器案例就很好的解释了,为什么vue组件但会data要使用函数的形式
在这里插入图片描述

<body>

    <div id="app">
        <counter></counter>
        <counter></counter>
        <counter></counter>
    </div>

    <template id="counter">
        <div>
            <button @click="sub">-</button>
            {{count}}
            <button @click="add">+</button>
        </div>
    </template>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        Vue.component('counter', {
            template: '#counter',
            data() {
                return {
                    count: 0
                }
            },
            methods: {
                add() {
                    this.count++;
                },
                sub() {
                    this.count--;
                }
            },
        })

        new Vue({
            el: '#app',
        })
    </script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

如果我们调用多次组件去操作的是一个对象,那就会引起连锁反应,像这样
在这里插入图片描述

<body>

    <div id="app">
        <counter></counter>
        <counter></counter>
        <counter></counter>
    </div>

    <template id="counter">
        <div>
            <button @click="sub">-</button>
            {{obj.count}}
            <button @click="add">+</button>
        </div>
    </template>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        const obj = {
            count: 0
        }
        Vue.component('counter', {
            template: '#counter',
            data() {
                return {
                    obj
                }
            },
            methods: {
                add() {
                    this.obj.count++;
                },
                sub() {
                    this.obj.count--;
                }
            },
        })

        new Vue({
            el: '#app',
        })
    </script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

父子组件通信 父传子props ✉️

实际开发,往往一些数据需要从上层传递到下层
Vue中通过 props 向子组件传递数据,通过事件向父组件发送消息
在这里插入图片描述

<body>

    <div id="app">
        <child :cmessage="message" :cmovies="movies"></child>
    </div>

    <template id="child">
        <div>
            <p>我是子组件</p>
            <p>{{cmessage}}</p>
            <ul>
                <li v-for="item in cmovies">{{item}}</li>
            </ul>
        </div>
    </template>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        const child = {
            template: '#child',
            // 数组写法
            // props: ['cmessage']
            // 对象写法,还可以指定类型,
            props: {
                cmessage: {
                    // 类型
                    type: String,
                    // 默认值
                    default: '哈哈',
                    // 必须传值,否则报错
                    required: true
                },
                cmovies: {
                    type: Array,
                    default() {
                        return [];
                    }
                }
            }
        }

        new Vue({
            el: '#app',
            data: {
                message: '你好啊,子组件',
                movies: ['天气之子', '你的名字', '千与千寻']
            },
            components: {
                child
            }
        })

    </script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

在这里插入图片描述


父子组件通信 props驼峰标识 🛑

在未使用单文件组件,即以.vue为后缀的文件时,可能会遇到父组件传子组件时驼峰命名的问题,你可以使用-来解决
在这里插入图片描述

<body>
    <div id="app">
        <npm :c-npm="person"></npm>
    </div>

    <template id="npm">
        <div>
            <p>{{cNpm.width}}</p>
            <p>{{cNpm.height}}</p>
        </div>
    </template>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        const npm = {
            template: '#npm',
            props: {
                cNpm: {
                    type: Object
                }
            }
        }

        new Vue({
            el: '#app',
            components: {
                npm
            },
            data: {
                person: {
                    height: 1.8,
                    width: 1.5
                }
            }
        })
    </script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

父子组件通信 子传父自定义事件 🥳

当子组件需要向父组件传递时,就要用到自定义事件了,之前学习的 v-on 不仅可以用于监听 DOM 事件,也可以监听组件间的自定义事件
在子组件使用 $emit()来触发事件,在父组件中使用 v-on 来监听子组件事件
在这里插入图片描述

<body>
    <!-- 父组件模板 -->
    <div id="app">
        <!-- 监听自定义事件,接收到事件触发后调用aa函数 -->
        <hello @cclick="aa"></hello>
    </div>
    <!-- 子组件模板 -->
    <template id="zi">
        <div>
            <button v-for="item in shoppings" @click="btnClick(item.name)">{{item.name}}</button>
        </div>
    </template>

    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
        // 子组件
        const hello = {
            template: '#zi',
            data() {
                return {
                    shoppings: [
                        { id: 'a', name: '热门推荐' },
                        { id: 'b', name: '家用电器' },
                        { id: 'c', name: '数码办公' }
                    ]
                }
            },
            methods: {
                btnClick(name) {
                    // 自定义事件 cclick
                    this.$emit('cclick', name)
                }
            },
        }
        // 父组件
        new Vue({
            el: '#app',
            components: {
                hello
            },
            methods: {
                aa(name) {
                    console.log(name);
                }
            }
        })
    </script>
</body>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

在这里插入图片描述

文章来源: blog.csdn.net,作者:周棋洛ყ ᥱ ᥉,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/m0_53321320/article/details/124167929

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。