组件

组件的注册

vue 中,我们可以通过 new Vue 来创建一个组件,不过通常它是作为整个应用的顶层根组件存在的,我们还可以通过另外的方式来注册一个更为通用的组件

Vue.component()

Vue.component('组件名称', {组件选项})
  • 组件名称遵循自定义组件命名规范:全小写、连字符(虽然驼峰式一般也没问题)
  • 组件选项与 new Vue 选项配置基本一致(也有一些细节的不同)
全局组件与局部组件

通过 Vue.component 注册的组件,我们称为全局组件,因为它可以在任意范围内使用,我们还可以定义局部组件

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

在一个组件内部通过 components 选项注册的组件是局部组件,只能在当前 components 选项所在的组件内部使用

注意:局部注册的组件只能中当前注册的组件中使用,不能在它的子组件中使用

data

在非 new Vue的组件中,data 必须为函数,函数返回值必须是一个对象,作为组件的最终 data

props

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

    <div id="app">
        <kkb-circle :r="n1"></kkb-circle>
        <hr />
        <kkb-circle :r="n2"></kkb-circle>
    </div>
    
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <script>
        
        let app = new Vue({
            el: '#app',
            data: {
                n1: 10,
                n2: 100
            },
            components: {
                'kkb-circle': {
                    props: ['r'],
                    data() {
                        return {pi: 3.14}
                    },
                    template: `<div>r: {{r}} -> {{pi * r * r}}</div>`
                }
            }
        });
    </script>
</body>
</html>
  • 如果传入的 props 值为一个表达式,则必须使用 v-bind
  • 组件中的 data 和 prop 数据都可以通过组件实例进行直接访问
  • data 中的 key 与 props 中的 key 不能冲突

组件通信

注意:不要修改 props 传入的数据

父组件通过 props 传入数据到子组件内部,但是子组件内部不要修改外部传入的 props,vue 提供了一种事件机制通知父级更新,父级中使用子组件的时候监听对应的事件绑定对应的处理函数即可

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <div id="app">
        <p>父组件:{{quantity}}</p>
        <kkb-child :quantity="initQuantity" @increment="appIncrement"></kkb-child>
        <kkb-child :quantity="initQuantity" @increment="appIncrement"></kkb-child>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
        const child = {
            props: ['quantity'],
            data() {
                return {
                    n: this.quantity
                };
            },
            template: `
                <div>
                    <p>子组件:{{n}}</p>
                    <button @click="increment">按钮</button>
                </div>
            `,
            methods: {
                increment() {
                    this.n++;
                    this.$emit('increment', this.n);
                }
            }
        };

        new Vue({
            el: '#app',
            data: {
                quantity: 0,
                initQuantity: 0
            },
            components: {
                'kkb-child': child
            },
            methods: {
                appIncrement(v) {
                    this.quantity++;
                }
            }
        });
    </script>
</body>
</html>
$emit()

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

this.$emit('自定义事件名称', 事件数据)
  • 事件数据就是中触发事件的同时携带传递的数据 - event

  • 父级在使用该组件的过程中,可以通过 @事件名称 来注册绑定事件函数

  • 事件函数的第一个参数就是事件数据

组件双绑的实现

虽然并不推荐在组件内部修改 props ,但是,有的时候确实希望组件内部状态变化的时候改变 props ,我们可以通过子组件触发事件,父级监听事件来达到这个目的,不过过程会比较繁琐,vue 提供了一些操作来简化这个过程

v-model

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .kkb-radio {
            width: 20px;
            height: 20px;
            background-color: #cccccc;
        }
        .kkb-radio.checked {
            background-color: #92beee;
        }
        .plane {
            border: 1px solid #000000;
            width: 300px;
        }
        .plane .header {
            width: 100%;
            height: 30px;
            background: #cccccc;
        }
        .plane .content {
            height: 100px;
            width: 100%;
            display: none;
        }
        .plane.expanded .content {
            display: block;
        }
    </style>
</head>
<body>
    <div id="app">
        <!-- <kkb-radio :checked="val"></kkb-radio> -->
        <kkb-radio v-model="val"></kkb-radio>

        <br /><br /><br />

        <kkb-plane :expanded="val"></kkb-plane>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>

        const kkbRadio = {
            model: {
                prop: 'checked',
                event: 'check'
            },
            props: ['checked'],
            data() {
                return {
                    status: this.checked
                }
            },
            template: `
                <div class="kkb-radio" :class="{'checked': status}" @click="changeStatus"></div>
            `,
            methods: {
                changeStatus() {
                    this.status = !this.status;

                    this.$emit('check', this.status);
                }
            }
        };
        const kkbPlane = {
            props: ['expanded'],
            template: `
                <div class="plane" :class="{'expanded': expanded}">
                    <div class="header"></div>
                    <div class="content"></div>
                </div>
            `
        };
        

        let vm = new Vue({
            el: '#app',
            data: {
                val: true
            },
            components: {
                'kkb-radio': kkbRadio,
                'kkb-plane': kkbPlane
            },
            methods: {
                
            }
        });
    </script>
</body>
</html>
model 选项

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

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

.sync

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .kkb-radio {
            width: 50px;
            height: 50px;
            border: 5px solid #000000;
            background-color: #ffffff;
        }
        .kkb-radio.checked {
            border-color: green;
        }
        .kkb-radio.disabled {
            background-color: #cccccc;
        }
    </style>
</head>
<body>
    <div id="app">

        <p>val1: {{val1}}</p>
        <p>val2: {{val2}}</p>
        <hr>

        <kkb-radio :checked.sync="val1" :disabled.sync="val2"></kkb-radio>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>

        const kkbRadio = {
            props: ['checked', 'disabled'],
            data() {
                return {
                    status: this.checked,
                    dis: this.disabled
                }
            },
            template: `
                <div class="kkb-radio" :class="{'checked': status, 'disabled': dis}" @click="changeDis" @mouseover="setChecked" @mouseout="removeChecked"></div>
            `,
            methods: {
                setChecked() {
                    this.status = true;
                    this.$emit('update:checked', this.status);
                },
                removeChecked() {
                    this.status = false;
                    this.$emit('update:checked', this.status);
                },
                changeDis() {
                    this.dis = !this.dis;
                    this.$emit('update:disabled', this.dis);
                }
            }
        };

        let vm = new Vue({
            el: '#app',
            data: {
                val1: false,
                val2: false
            },
            components: {
                'kkb-radio': kkbRadio
            },
            methods: {
                
            }
        });
    </script>
</body>
</html>
update:[prop]

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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值