Vue03-组件01:可复用组件

1 可复用组件

  • vue 中,我们可以通过 new Vue 来创建一个组件
  • 不过通常它是作为整个应用的顶层根组件存在的,我们还可以通过另外的方式来注册一个更为通用的组件。
  • 不同于根组件,同一个可复用组件,可以在同一个应用中多次使用。
    在这里插入图片描述

1-1 可复用UI组件的创建

  • 可复用组件在构建选项上与全局组件基本一致
  • 可复用组件可以像标签一些在模板中使用
  • 不能与原生的html标签重名
  • 组件的options里面有一个选项:components,可以通过该选项来定义组件

全局组件

Vue.component('组件名称', {组件选项})

可以在任意位置(多个不同的 Vue 应用中)使用。

局部组件

new Vue({
  ...,
  components: {
  	'组件名称': {组件选项}	
	}
})

局部组件只能在其定义的组件内使用,也不能在其子组件内部使用

    <div id="app">
        <my-component1></my-component1>
        <my-component2>
            <my2></my2>
        </my-component2>
        <!-- <my2></my2> -->
        <my3></my3>
        <my4></my4>
    </div>

    <script src="./js/vue.js"></script>
    <script>
        Vue.component("my-component1", {
            template: `<div>全局组件1</div>`,
        })

        Vue.component('my-component2', {
            template: `<div>全局组件2</div>`,
            components: {
                'my2': {
                    template: `<div>My2</div>`
                }
            }
        });

        new Vue({
            el: '#app',
            components: {
                'my3': {
                    template: `<div>局部组件</div>`
                },
                "my4": {
                    template: `<div>局部组件2</div>`
                }
            }
        });
    </script>

在这里插入图片描述

1-2 组件内部私有数据

可复用组件的 data 必须是函数,且该函数必须返回一个对象作为组件最终的 data
会使得复用的组件数据之间不会相互影响
如下点击事件只会影响点击的对应组件中的数据

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

    <script src="./js/vue.js"></script>
    <script>
        Vue.component("my-component1", {
            template: `<div @click="add">全局组件1 - {{a}} - {{b}}</div>`,
            data: function() {
                return {
                    a: 1,
                    b: 2,
                }
            },
            methods: {
                add(){
                    this.a++;
                }
            },
        })
    </script>

1-3 组件外部传入数据

如同一个函数一样,函数除了可以定义内部私有变量,有时候为了提高函数的复用性,我们通过会通过参数来接收外部传入的数据。组件也可以。

props

组件中内部私有数据存储中组件 data 中,通过外部传入的数据,则通过 props 选项接收。

首先,组件内部通过 props 来定义可以接收的数据名称,就像是函数的形参。

然后,在使用该组件的时候可以通过标签属性的方式进行传参(可配合 v-bind 传入表达式)。

注意事项

  • 如果传入的 props 值为一个表达式,则必须使用 v-bind
  • 组件中的 dataprops 数据都可以通过组件实例进行直接访问
  • data 中的 keyprops 中的 key 不能冲突

案例:做一个分页组件

父级调用组件的时候将父级数据传递给组件
在这里插入图片描述

Vue.component('kkb-pagination', {

    // 类似给函数定义形参,接收父级传来的数据
    props: ['total', 'prepage', 'page'],

    data() {
        // data 中是可以通过this访问到 props 的
        return {
            pages: Math.ceil((this.total / this.prepage))
        };
    },
	
	// template可以直接访问到props里的数据
    template: `
        <div class="pagination">
            <a href="" class="prev">上一页</a>

            <a 
                href="javascript:;" 
                v-for="p of pages"
                :class="{current: p == page}"

                @click="changePage(p)"
            >{{p}}</a>

            <a href="" class="next">下一页</a>
        </div>
    `,

});

1-4 组件通信

1 作用域隔离

为了保证数据安全性(传入的数据通常会在其它组件中也有使用),Vue 不推荐我们在组件内部直接修改传入的数据。

2 父组件到子组件内部的数据传递

父组件通过上述提到的 props 向一个子组件内部传递数据。

3 子组件内部到外部的数据传递

$emit()

vue 为每个组件对象提供了一个内置方法 $emit ,它等同于自定义事件中的 new Event,trigger

this.$emit('自定义事件名称', 事件数据)
  • 子级通过$emit方法通知父级来修改数据
  • 事件数据就是中触发事件的同时携带传递的数据 - event
  • 父级在使用该组件的过程中,可以通过 @事件名称 来注册绑定事件函数
  • 事件函数的第一个参数就是事件数据

4 数据双向绑定

v-model

v-modelvue 提供的一个用于实现数据双向绑定的指令,用来简化 props 到 datadata 到 props 的操作流程。

model 选项

prop 指定要绑定的属性,默认是 value

event 指定要绑定触发的事件,默认是 input 事件

案例:使用v-model 实现分页点击修改

子组件写上$emit事件

    methods: {
        changePage(p) {
            this.$emit('change', p);
        }
    }

model配置里绑定page数据与change方法
当组件 emit 的事件名称是 event 指定,那么就根据上面的prop指定属性去更改对应的值

    model: {
        // v-model的数据是绑定到 props 中 page 属性,默认是value
        prop: 'page',
        // event,当组件 emit 的事件名称是 event 指定,那么就根据上面的prop指定属性去更改对应的值
        event: 'change'
    },

在这里插入图片描述
点击成功修改

.sync

通过 v-model 来进行双向绑定,会给状态维护带来一定的问题,因为修改比较隐蔽,
同时只能处理一个 prop 的绑定,我们还可以通过另外一种方式来达到这个目的。

update:[prop]

这里事件名称要使用 update 加上 prop 名称 的格式

案例:通过.sync 改写分页组件的数据双绑

先给v-bind加上修饰符.sync
在这里插入图片描述
触发一个update事件,使用p去更新page(page必须是通过 .sync 来进行绑定的)

    methods: {
        changePage(p) {
            // 触发一个update事件,使用p去更新page(page必须是通过 .sync 来进行绑定的)
            this.$emit('update:page', p);
        },
		// 将每页数据量大小改为5
        changePrepage(e) {
            e.preventDefault();

            this.$emit('update:prepage', 5);
        }
    }

在这里插入图片描述
成功修改

1-5 ref 与 $refs

  • ref 被用来给元素或子组件注册引用信息。
  • 引用信息将会注册在父组件的 $refs 对象上。
  • 如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;
  • 如果用在子组件上,引用就指向组件。

1-6 插槽

默认情况下,组件模板解析后会替换整个组件内容,
如果我们想在组件引用被包含的内容,可以通过 vue 提供的内置组件 slot 来获取。

slot

  • Vue 提供了一个内置的组件 <slot>,用于在组件模板内定义插槽。
  • 解析过程中,会被该组件嵌套的子组件(元素)对应的内容所替换。

默认替换

<slot></slot>

具名插槽

使用内置组件 templatev-slot 指令进行配置,用来命名插槽
在组件模板中,通过 <标签 v-slot:插槽名称> 来使用。

  • 插槽名称默认为 default ,可以省略。

给插槽命名<slot name="left"...

<slot name="left" :pages="pages" a="1"></slot>

父组件使用v-slot:left

<template v-slot:left="data">
    <span>一共有{{cartItems.length}}条数据,一共{{data.pages}}页,当前{{cPage}}页</span>
</template>

作用域插槽

组件内部与组件包含的内容属于不同的作用域(被包含的内容是组件父级下的作用域)。

组件到父级作用域下的子级通信。

  • 组件内部通过 slotattributes 进行数据传递。
  • 子级通过 v-slot 指令的值进行接收。
// 组件内部
<slot v-for="user of users" :user="user"></slot>

// 组件外部子级
<template v-slot:default="data">
  <p>用户的姓名: {{data.user.username}}</p>
</template>

1-7 props 验证

组件的 props 就是组件的参数,为了确保传入的数据在可控的合理范围内,
我们需要对传入的 props 的值类型进行必要的验证。

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
      }
    }
  }
})

1-8 其它 props 相关知识点

非 prop 特性

一个非 prop 特性是指传向一个组件,但是该组件并没有相应 prop 定义的特性,这些 props 会被自动添加到组件的根元素上。

替换/合并已有的特性

默认情况下,非prop 特性的属性会覆盖组件根元素上同名的内容,但是针对 styleclass 有特殊的处理,它们会合并(同名样式还是会覆盖)。
比如父组件设置样式
在这里插入图片描述
子组件也设置样式
在这里插入图片描述
父组件就会覆盖子组件相同的样式,
会保留父组件没有的样式

inheritAttrs 禁用特性继承

如果不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false,我们可以通过组件的 this.$attrs 来获取这些属性。

注意 inheritAttrs: false 选项不会影响 styleclass 的绑定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值