• Vue学习笔记(七) 组件


    0、入门

    在正式开始讲解组件之前,我们先来看一个简单的例子:

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    </head>
    
    <body>
        <div id="app">
            <button-counter></button-counter>
        </div>
    
        <script>
            Vue.component('button-counter', {
                data: function () {
                    return {
                        count: 0
                    }
                },
                template: '<button v-on:click="count++">{{ count }} times</button>'
            })
            new Vue({
                el: '#app'
            })
        </script>
    </body>
    
    
    </html>
    

    下面我们详细解读一下上面这份代码:

    Vue.component('button-counter', {
        data: function () {
            return {
                count: 0
            }
        },
        template: '<button v-on:click="count++">{{ count }} times</button>'
    })
    

    我们首先通过全局方法 Vue.component() 创建了一个名为 button-counter 的全局组件

    该方法的第一个参数是组件名,第二个参数是选项对象,对象中包含两个属性,datatemplate

    属性 data 是一个 返回对象的函数,用于储存动态变化的数据

    之所以定义为函数,是因为组件可能被用来创建多个实例,若定义为对象,则所有实例将会共享同一份数据对象

    属性 template 是一个 模板字符串,用于定义组件的 HTML 代码

    需要注意的是,组件必须是单根元素,也就是说模板的内容必须包裹在一个父元素内

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

    然后,我们就可以在一个通过 new Vue() 创建的根实例中,把这个组件当作自定义元素使用

    好,在对组件有了一个初步的理解之后,下面我们再来进行详细的学习

    1、组件注册

    组件是可复用的 Vue 实例,在使用组件前,我们首先要对组件进行注册,以便于 Vue 能够识别出来

    (1)组件注册的参数有两个,分别是 组件名选项对象

    • 组件名

    定义组件名的方式有两种,分别是 kebab-case(短横线分隔命名)和 PascalCase(首字母大写命名)

    kebab-case:在引用时,需要使用 kebab-case

    PascalCase:在模板中使用时,两种命名法都可用;在 DOM 中使用时,只有 kebab-case 是有效的

    • 选项对象

    该对象接收的选项与 new Vue() 接收的选项类似,仅有的例外是像 el 这样的根实例特有的选项

    (2)组件注册的方式有两种,分别是 全局注册局部注册

    • 全局注册

    我们可以使用全局方法 Vue.component() 进行全局注册,该方法的第一个参数是组件名,第二个参数是选项对象

    全局注册的组件可以在任何新创建的根实例中使用

    Vue.component('component-a', { /* ... */ })
    Vue.component('component-b', { /* ... */ })
    
    new Vue({ el: '#app' })
    
    • 局部注册

    我们可以在创建根实例时使用选项 components 进行局部注册,它是一个对象,键是组件名,值是选项对象

    局部注册的组件不可以在其子组件中使用,也就是说,在下例中的两个组件不可以在各自内部相互调用

    var ComponentA = { /* ... */ }
    var ComponentB = { /* ... */ }
    
    new Vue({
        el: '#app',
        components: {
            'component-a': ComponentA,
            'component-b': ComponentB
        }
    })
    

    如果希望 ComponentAComponentB 中可用,我们需要换一种写法:

    var ComponentA = { /* ... */ }
    
    var ComponentB = {
      components: {
        'component-a': ComponentA
      },
      // ...
    }
    

    2、向子组件传递数据 —— prop

    prop 是在组件注册的一些自定义特性,当一个值传递给一个 prop 特性时,它就变成那个组件实例的一个属性

    (1)传递静态 prop

    在下例中,我们给 prop 传递了一个静态的值,Title Here

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    </head>
    
    <body>
        <div id="app">
            <title-item title="Title Here"></title-item>
        </div>
    
        <script>
            Vue.component('title-item', {
                props: ['title'],
                template: '<h3>{{ title }}</h3>'
            })
            new Vue({
                el: '#app'
            })
        </script>
    </body>
    
    
    </html>
    

    (2)传递动态 prop

    在下例中,我们通过 v-bind 给 prop 绑定了一个动态的对象,content

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    </head>
    
    <body>
        <div id="app">
            <title-item v-bind:title="content.title"></title-item>
        </div>
    
        <script>
            Vue.component('title-item', {
                props: ['title'],
                template: '<h3>{{ title }}</h3>'
            })
            new Vue({
                el: '#app',
                data: {
                    content: {
                    	'title': 'Title Here'
                    }
                }
            })
        </script>
    </body>
    
    
    </html>
    

    (3)prop 类型与 prop 验证

    在上面的两个例子中,props 都是一个字符串数组,其中的每一个 prop 都是一个字符串

    但事实上,prop 还可以是其它类型

    这时我们可以用对象列出 prop,其中对象的键是 prop 的名称,对象的值是 prop 的类型

    Vue.component('my-component', {
        props: {
            propA: String,
            propB: Number,
            propC: Boolean,
            propD: Array,
            propE: Object,
            propF: Function
            // ...
        },
        // ...
    })
    

    既然 prop 有了类型,就要判断 prop 是否符合类型,我们可以定制 prop 的验证方式(以下是官方文档中的一个例子)

    Vue.component('my-component', {
      props: {
        // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
        propA: Number,
        // 多个可能的类型
        propB: [String, Number],
        // 必填的字符串
        propC: {
          type: String,
          required: true
        },
        // 带有默认值的数字
        propD: {
          type: Number,
          default: 100
        },
        // 带有默认值的对象
        propE: {
          type: Object,
          // 对象或数组默认值必须从一个工厂函数获取
          default: function () {
            return { message: 'hello' }
          }
        },
        // 自定义验证函数
        propF: {
          validator: function (value) {
            // 这个值必须匹配下列字符串中的一个
            return ['success', 'warning', 'danger'].indexOf(value) !== -1
          }
        }
      }
    })
    

    当 prop 验证失败时,(开发环境构建版本的) Vue 将会产生一个控制台的警告

    3、向父组件传递数据 —— 自定义事件

    prop 是一个单向下行绑定,即父级 prop 的更新会向下流动到子组件中,但反过来不行

    如果子组件要把数据传递给父组件,则需要使用自定义事件

    父组件可以通过 v-on 监听子组件实例的任意事件,而子组件可以通过 $emit() 触发事件

    (1)监听子组件事件

    <!DOCTYPE html>
    <html>
    
    <head>
        <title>Demo</title>
        <script src="https://cdn.jsdelivr.net/npm/vue"></script>
    </head>
    
    <body>
        <div id="app">
            <p>{{ total }}</p>
            <button-counter v-on:increment="incrementTotal"></button-counter>
        </div>
    
        <script>
            Vue.component('button-counter', {
                template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
                data: function () {
                    return {
                        counter: 0
                    }
                },
                methods: {
                    incrementHandler: function () {
                        this.counter += 1
                        this.$emit('increment')
                    }
                },
            })
            new Vue({
                el: '#app',
                data: {
                    total: 0
                },
                methods: {
                    incrementTotal: function () {
                        this.total += 1
                    }
                }
            })
        </script>
    </body>
    
    
    </html>
    

    下面让我们来详细解读一下上面这段代码:

    Vue.component('button-counter', {
        template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
        data: function () {
            return {
                counter: 0
            }
        },
        methods: {
            incrementHandler: function () {
                this.counter += 1
                this.$emit('increment')
            }
        },
    })
    

    首先,我们定义了一个名为 button-counter 的组件

    子组件 button-counter 使用 v-on 监听原生事件 click,该事件的处理函数是 incrementHandler()

    incrementHandler() 中,首先将 counter(子组件中的数据)的值加 1,然后触发自定义事件 increment

    <div id="app">
        <p>{{ total }}</p>
        <button-counter v-on:increment="incrementTotal"></button-counter>
    </div>
    
    new Vue({
        el: '#app',
        data: {
            total: 0
        },
        methods: {
            incrementTotal: function () {
                this.total += 1
            }
        }
    })
    

    根组件同样是通过 v-on 监听自定义事件 increment,该事件的处理函数是 incrementTotal()

    incrementTotal() 中,将 total(根组件中的数据)的值加 1

    (2)通过事件抛出一个值

    我们可以在 $emit() 函数的第二个参数中抛出一个值

    Vue.component('button-counter', {
        template: '<button v-on:click="incrementHandler">{{ counter }}</button>',
        data: function () {
            return {
                counter: 0
            }
        },
        methods: {
            incrementHandler: function () {
                this.counter += 1
                this.$emit('increment', 2)
            }
        },
    })
    

    并在事件处理函数的第一个参数中接收该值

    new Vue({
        el: '#app',
        data: {
            total: 0
        },
        methods: {
            incrementTotal: function (value) {
                this.total += value
            }
        }
    })
    

    【 阅读更多 Vue 系列文章,请看 Vue学习笔记

    版权声明:本博客属于个人维护博客,未经博主允许不得转载其中文章。
  • 相关阅读:
    【转】嵌入式程序员应该知道的16个问题
    GetMemory()函数
    Some good questions
    [转]永远做一个有计划的人
    内存分配管理
    c语言面试题(感觉比较好的题目)
    const char*, char const*, char*const的区别
    《论语》《中庸》《大学》经典语录
    洗脑
    python基础之函数参数,名称空间,以及函数嵌套
  • 原文地址:https://www.cnblogs.com/wsmrzx/p/11210400.html
Copyright © 2020-2023  润新知