vue——组件

组件是什么?

组件是可复用的 Vue 实例,且带有一个名字。

组件的注册与使用

组件与vue实例一样,需要注册,才可以使用,注册有全局注册和局部注册俩种方式

1、全局注册
// 使用组件
2、局部注册

以上代码渲染后的结果都为:

我是组件的内容

3、组件的嵌套

渲染后的结果为:

hello tom

4、组件中定义数据

组件中,也可以使用vue实例中的那些选项,只是这里data的定义方式有一点点不同。

组件的通信

组件不仅仅是要把模板的内容进行复用,更重要的是组件间要进行通信。

1.1、props——父组件向子组件传递数据

通常父组件的模板中包含子组件,父组件要正向的向子组件传递数据或者参数,子组件接收到后根据参数的不同来渲染不同的内容或者执行操作,这个正向传递数据的过程就是通过props来实现的。

// 使用 ':message'的形式传递父组件中的data,不加冒号,就是传递字符串message
1.2、props的实际使用方式

通过props传递数据是单向的,也就是说,父组件的数据变化了,子组件跟着变化,这没问题,但是呢,反过来,则不可以,vue不推荐直接修改prop的值(尽管可以实现子组件数据的变化),以下俩种使用方式比较常见。

1.2.1、使用data保存

第一种就是父组件传递初始值进来,子组件将它作为初始值保存起来,在自己的作用域下可以随意使用和修改,这时可以在组件data内再声明一个数据,引用父组件的prop。

1.2.2、使用computed保存

这种情况就是prop作为需要被转变的原始值传入,可以用计算属性。

1.3 prop的验证

上面所说的props选项的值都是一个数组,其实当prop需要验证时,就需要使用对象写法。一般,当你的组件需要提供给别人使用时,推荐都使用数据验证,比如某个数据必须是数字类型,否则在控制台弹出警告(必须引入的是vue包为开发版本)。

Vue.component('my-component',{
        ...,
        props: {
            propA: Number,   // 必须是数字类型
            propB: [String, Number],   // 必须是字符串或者数字类型
            propC: {   // 必须是布尔值,如果没传的话默认为true
                type: Boolean,
                default: true
            },
            propD: {    // 必须是数字类型,且必传
                type: Number,
                required: true
            },
            propE: {   // 如果是数组或者对象,必须以一个函数来返回
                type: Array,   
                default: function () {
                    return [];
                }
            },
            propF: {   // 自定义一个验证函数
                validator: function (value) {
                    return value > 10;
                }
            }

        }
    })

例子:

以上代码虽然可以渲染,但会在控制台报错。

2.1、$emit 子组件向父组件传递数据

props是不能把数据传递给父组件的,这里有一种方法,就是,子组件用on()来监听子组件的事件。

{{total}}

// 2、父组件根据子组件的事件名来接收,并做出响应

效果:


2.2、$emit的语法糖

{{total}}

// 直接用v-model绑定一个父组件的数据

仍然是点击减一的效果,这里简洁了许多。

2.3、v-model实现自定义的双向绑定的表单输入组件

{{total}}

效果:



按钮点击,和子组件文本框输入都可以使父子组件的数据同时变化。

3.1、中央事件总线(bus) —— 非父子组件的通信

这种方式巧妙而轻量的实现了任何组件间的通信,包括父子,兄弟,跨级。比如兄弟组件间通信:

4.1、父链和子组件索引

除了中央事件总线bus外,还有俩种方法可以实现组件间通信:父链和子组件索引。

4.2、父链

在子组件中,使用this.parent可以直接访问该组件的父实例或组件,父组件也可以通过this.children访问它所有的子组件,而且可以递归向上或向下无限访问。

{{message}}

还是推荐使用props或者$emit()的方式通信。

4.3、子组件索引

当子组件较多时,通过this.$children来一一遍历出我们需要的一个组件实例是比较困难的,Vue提供了子组件索引的方法,用特殊的属性ref来为子组件指定一个索引名称:

// 在父组件模板中子组件标签上,使用ref指定一个名称

slot —— 分发内容

1、单个slot

在子组件内使用特殊的元素就可以为这个子组件开启一个slot(插槽),在父组件模板里,插入在子组件标签内的所有内容将替代子组件的标签及它的内容。

hello

world

// 渲染后

hello

world

子组件my-component的模板内定义了一个slot元素,并且用一个

作为默认的内容,在父组件没有使用slot时,会渲染这段默认的文本,如果写入了slot,那就会替换整个

2、具名slot

给slot元素指定一个name后可以分发多个内容,具名slot可以与单个slot共存:

我是头部内容

我是导航内容

我是主体内容

我是底部内容

// 渲染后

我是头部内容

我是导航内容

我是主体内容

子组件内声明了3个slot元素,其中在

内的slot没有使用name特性,它将作为默认slot出现,父组件没有slot特性的元素与内容都将出现在这里。如果没有指定默认的匿名slot元素,父组件内多余的内容片断都将被抛弃。

3、作用域插槽

作用域插槽是一种特殊的slot,使用一个可以复用的模板替换已渲染元素。基本用法:

// 渲染后

123

作用域插槽最具代表性的例子就是列表组件,比如:

效果:



作用域插槽的使用场景是既可以复用子组件的slot,又可以使用slot内容不一致。

其他

1、$nextTick —— 异步更新队列

现在有一个需求,有一个div ,默认用v-if 将它隐藏,点击一个按钮后,改变v-if 的
值,让它显示出来,同时拿到这个div 的文本内容。如果v-if 的值是false ,直接去获取div 的内容
是获取不到的, 因为此时div 还没有被创建出来,那么应该在点击按钮后,改变v -if 的值为true,
div 才会被创建,此时再去获取,示例代码如下:

这是一段文本内容

然而,在点击按钮之后,控制台却报错了,Cannot read property 'innerHTML' of null,意思就是获取不到div元素,这里就涉及Vue一个重要的概念,异步更新队列。

Vue 在观察到数据变化时并不是直接更新DOM,而是开启一个队列,并缓冲在同一事件循环
中发生的所有数据改变。在缓冲时会去除重复数据,从而避免不必要的计算和DOM 操作。然后,
在下一个事件循环tick 中, Vue 刷新队列井执行实际(己去重的)工作。所以如果你用一个for 循
环来动态改变数据100次,其实它只会应用最后一次改变,如果没有这种机制, DOM 就要重绘100
次,这固然是一个很大的开销。

知道了Vue 异步更新DOM 的原理,上面示例的报错也就不难理解了。事实上,在执行
this.flag = true时, div 仍然还是没有被创建出来,直到下一个Vue 事件循环时,才开始创建。
$nextTick 就是用来知道什么时候DOM 更新完成的,所以上面的示例代码需要修改为:

这是一段文本内容
2、x-Templates

这个功能就是如果组件模板内容太过于复杂,不想拼接字符串,所以提供了一种方法,具体使用如下:

// 渲染后

123

456

789

3、watch —— 监听

watch选项用来监听某个prop或者data的改变,当它们发生改变时,就会触发watch配置的函数,从而完成我们的业务逻辑。

{{message}}

实战

1、数字输入框组件

你可能感兴趣的:(vue——组件)