Vue学习笔记(七) 组件

简介: 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
        }
    }
})



文章知识点与官方知识档案匹配,可进一步学习相关知识

相关实践学习
Serverless极速搭建Hexo博客
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
目录
相关文章
|
6天前
|
JavaScript 前端开发
如何在 Vue 项目中配置 Tree Shaking?
通过以上针对 Webpack 或 Rollup 的配置方法,就可以在 Vue 项目中有效地启用 Tree Shaking,从而优化项目的打包体积,提高项目的性能和加载速度。在实际配置过程中,需要根据项目的具体情况和需求,对配置进行适当的调整和优化。
|
7天前
|
存储 缓存 JavaScript
在 Vue 中使用 computed 和 watch 时,性能问题探讨
本文探讨了在 Vue.js 中使用 computed 计算属性和 watch 监听器时可能遇到的性能问题,并提供了优化建议,帮助开发者提高应用性能。
|
7天前
|
存储 缓存 JavaScript
如何在大型 Vue 应用中有效地管理计算属性和侦听器
在大型 Vue 应用中,合理管理计算属性和侦听器是优化性能和维护性的关键。本文介绍了如何通过模块化、状态管理和避免冗余计算等方法,有效提升应用的响应性和可维护性。
|
7天前
|
存储 缓存 JavaScript
Vue 中 computed 和 watch 的差异
Vue 中的 `computed` 和 `watch` 都用于处理数据变化,但使用场景不同。`computed` 用于计算属性,依赖于其他数据自动更新;`watch` 用于监听数据变化,执行异步或复杂操作。
|
6天前
|
JavaScript 前端开发 UED
vue学习第二章
欢迎来到我的博客!我是一名自学了2年半前端的大一学生,熟悉JavaScript与Vue,目前正在向全栈方向发展。如果你从我的博客中有所收获,欢迎关注我,我将持续更新更多优质文章。你的支持是我最大的动力!🎉🎉🎉
|
8天前
|
存储 JavaScript 开发者
Vue 组件间通信的最佳实践
本文总结了 Vue.js 中组件间通信的多种方法,包括 props、事件、Vuex 状态管理等,帮助开发者选择最适合项目需求的通信方式,提高开发效率和代码可维护性。
|
6天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,熟悉JavaScript与Vue,正向全栈方向发展。博客内容涵盖Vue基础、列表展示及计数器案例等,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
|
JavaScript
Vue的非父子组件之间传值
全局事件总线 一种组件间通信的方式,适用于任意组件间通信
|
缓存 JavaScript 前端开发
Vue Props、Slot、v-once、非父子组件间的传值....
Vue Props、Slot、v-once、非父子组件间的传值....
84 0
|
JavaScript
Vue中父子组件传值
先在⽗组件中给⼦组件的⾃定义属性绑定⼀个⽗组件的变量