Vue.js基础---组件

Vue.js基础—组件

组件,就是网页上面分割出来的一部分,一部分的内容,小到甚至一个购物车,一个输入框都可以看成是一个组件
在这里插入图片描述
1、创建父组件和子组件
创建一个父组件和一个子组件

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        //创建一个Vue实例
        const app = Vue.createApp({
            template: `
                <div>
                   <div>hello</div>
                   <div>word</div>

                </div>
            `
        });

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述

把刚刚创建的父组件拆分为两个子组件

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        //创建一个Vue实例,同时也是一个父组件
        const app = Vue.createApp({
            template: `
                <div>
                   <hello /> <word />
                </div>
            `
        });

        //子组件1
        app.component('hello', {
            template: `
             <div> hello </div>
            `
        })

        //子组件2
        app.component('word', {
            template: `
             <div> word </div>
            `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述

2、创建全局组件和局部组件
全局组件:
①只要定义了,处处可以使用,也就是说在父组件里面可以用,在子组件里面也可以用,但是性能不高,因为你不用时候,组件依然挂载在app下面,会占用app的内存
②名字可以小写字母单词,中间用短横线隔开
局部组件:
①定义了,要注册才能使用,性能比较高,使用较麻烦
②名字建议大写字母开头,驼峰命名
③组件使用时候,要做一个名字和组件之间的映射对象,若不写映射,Vue底层也会尝试帮你自动做映射

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        //定义局部组件1
        const Counter = {
            data() {
                return {
                    count: 1
                }
            },

            template: `<div @click='count += 1'> {{count}} </div>`
        };

        //定义局部组件2
        const HelloWord = {

            template: `<div> hello word </div>`
        };

        const app = Vue.createApp({

            //注册组件,并且映射
            components: {
                //省略映射,Vue会尝试自动帮你映射
                // 'counter': Counter,
                // 'hello-word': HelloWord
                HelloWord, Counter
            },

            template: `
                <div>
                    <counter />
                    <hello-word />
                </div>
            `
        });


        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述

定义局部组件,并放到Vue实例后面,会报:无法在初始化前访问“计数器” 的错误

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({

            //注册组件,并且映射
            components: { counter: Counter },

            template: `
                <div>
                   <counter />
                </div>
            `
        });

        //定义局部组件,并放到Vue实例后面
        const Counter = {
            data() {
                return {
                    count: 1
                }
            },

            template: `<div @click='count += 1'> {{count}} </div>`
        };

        const vm = app.mount('#root');

    </script>
</body>

运行结果:报错
在这里插入图片描述
3、父组件数据传递给子组件
在子组件使用props属性接收从父组件传过来的属性名,属性名通常会携带数据
①动态传参,使用v-bind绑定属性,数据从data里面提供,灵活
②静态传参,直接context=‘num’,其中num的类型为字符串,容易写死

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return { num: 123 }
            },

            template: ` 
                <div> <test1 context='num'  /> </div>
                <div> <test2 :content='num' /> </div>
             `
        });

        app.component('test1', {
            props: ['context'],

            template: ` 
               <div>  {{context}}---{{typeof context}} </div>
              
                `
        })

        app.component('test2', {
            props: ['content'],

            template: ` 
              
               <div>  {{content}}---{{typeof content}} </div>
                `
        })
        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
③校验父组件传过来的数据,这时候不是数组,而是用对象
type:String、Boolean、Object、Array、Function、symbol
required:true(要你传) 、false(不要你传)
default:默认值/fn —>1、当你传,不会展示默认值,当你不传,会展示默认值
validator:fn —>对传过来参数内容做限制


<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return { num: 123 }
            },

            template: ` 
                <div> <test :content='num'/> </div>
             `
        });

        app.component('test', {
            props: {
                content: {
                    type: Number,
                    required: false,
                    default: function () {
                        return 888
                    },
                    validator: function (value) {
                        return value < 124
                    }
                }
            },

            template: `               
               <div>  {{content}} </div>
                `
        })
        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
4、当父组件中数据有很多时候,可以在父组件template使用v-bind来处理渲染多个参数

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return {
                    params: {
                        content: 1234,
                        a: 123,
                        b: 234,
                        c: 345,
                    }
                }
            },

            template: ` 
                <div> <test v-bind='params'/> </div>
             `
        });

        app.component('test', {
            props: ['content', 'a', 'b', 'c'],

            template: `               
               <div>  {{content}}--{{a}}--{{b}}--{{c}} </div>
                `
        })
        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
5、单向数据流:子组件可以使用父组件传递过来参数,但是绝对不能修改父组件里面的数据

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return { num: 1 }
            },

            template: ` 
                <div> <counter :count='num'  /> </div>
             `
        });

        app.component('counter', {
            props: ['count'],

            template: `               
               <div @click='count += 1 '>  {{count}} </div>
                `
        })
        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
在子组件data对象定义一个自己参数myCount用来接收父组件传递过来的值

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return { num: 1 }
            },

            template: ` 
                <div> <counter :count='num'  /> </div>
             `
        });

        app.component('counter', {
            props: ['count'],

            data() {
                return {
                    //用来接收父组件传递过来值
                    myCount: this.count,
                }
            },
            template: `               
               <div @click='myCount += 1 '>  {{myCount}} </div>
                `
        })
        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
6、在子组件没有写props属性时候,如果需要传递数据该怎么做?这时候就要使用到Non-props属性
①在子组件标签里面使用v-bind=’$attrs’用来接收父组件所有数据
②在子组件标签里面使用:msg1=’ $attrs.msg1 '来接收单个需要传递的数据

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            template: ` 
                <div> <counter msg1='孙悟空' msg2='猪八戒' msg3='沙和尚' /> </div>
             `
        });

        app.component('counter', {
            template: `               
               <div v-bind='$attrs'> hello word </div>
               <div :msg1='$attrs.msg1'> hello word </div>
                `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
③在生命周期函数里面想要传递过来数据,应该使用this.$attrs来获取

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            template: ` 
                <div> <counter msg1='孙悟空' msg2='猪八戒' msg3='沙和尚' /> </div>
             `
        });


        app.component('counter', {
            mounted() {
                console.log(this.$attrs);
            },

            template: `               
               <div v-bind='$attrs'> hello word </div>
               <div :msg1='$attrs.msg1'> hello word </div>
                `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
4、子组件通过 向外暴露事件–$emit 来像父组件传递数据
因为我们知道父组件传递给子组件的数据,在子组件里面修改,Vue是不允许的,那么这时候需要在子组件里面定义 $emit 事件告诉父组件,在父组件里面操作修改数据,然后再传递给子组件进行展示

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return {
                    count: 1
                }
            },

            methods: {
                handleAddOne() {
                    this.count += 1;
                }
            },

            // 绑定'add-one'参数,并进行监听和做加1的处理函数
            template: ` 
               <counter :count='count'  @add-one='handleAddOne' />
             `
        });


        app.component('counter', {
            props: ['count'],
            methods: {
                handleClick() {
                    //$emit-->向父组件暴露'addOne'参数
                    this.$emit('addOne');
                }
            },

            template: `               
                 <div @click='handleClick'> {{count}} </div>
                `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
上面只是传递一个参数,当你想要传递多个参数,应该怎么做呢?可以这样$emit(‘addOne’ ,2 , 4)携带多个参数,同时在父组件里面操作处理函数定义形参param用来接收实参

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return {
                    count: 1
                }
            },

            methods: {
                //定义形参param用来接收实参
                handleAddOne(param) {
                    this.count += param;
                }
            },

            // 绑定'add-one'参数,并进行监听和做加3的处理函数
            template: ` 
               <counter :count='count'  @add-one='handleAddOne' />
             `
        });


        app.component('counter', {
            props: ['count'],
            methods: {
                handleClick() {
                    //$emit-->向父组件暴露'addOne'参数,并进行加3操作
                    this.$emit('addOne', 3);
                }
            },

            template: `               
                 <div @click='handleClick'> {{count}} </div>
                `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
高级用法–>在组件里面使用 v-model 简化代码

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return {
                    count: 1
                }
            },

            template: ` 
               <counter v-model='count' />
             `
        });


        app.component('counter', {
            //'modelValue'是固定的
            props: ['modelValue'],

            methods: {
                handleClick() {
                    //触发事件名字'update:modelValue'固定的
                    //this.modelValue + 3 向外触发值,会自动替换掉父组件count,完成更新
                    this.$emit('update:modelValue', this.modelValue + 3);
                }
            },

            template: `               
                 <div @click='handleClick'> {{modelValue}} </div>
                `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
使用多个 v-model 属性进行绑定
①通过 v-model:count=‘count’ ,可以自定义名字

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return {
                    count: 1,
                    count1: 1
                }
            },

            template: ` 
               <counter v-model:count='count' v-model:count1='count1' />
             `
        });

        app.component('counter', {
            props: ['count', 'count1'],

            methods: {
                handleClick() {
                    this.$emit('update:count', this.count + 3);
                },
                handleClick1() {
                    this.$emit('update:count1', this.count1 + 3);
                }
            },

            template: `               
                 <div @click='handleClick'> {{count}} </div>
                 <div @click='handleClick1'> {{count1}} </div>
                `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
如何在 v-model 绑定修饰符,从而将字符串转换为大写呢?

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return {
                    count: 'a',
                }
            },

            template: ` 
               <counter v-model.uppercase='count'  />
             `
        });

        app.component('counter', {
            props: {
                'modelValue': String,
                //接收修饰符uppercase
                'modelModifiers': {
                    //默认值,不传uppercase,默认给个空对象
                    default: () => ({})
                }
            },

            mounted() {
                console.log(this.modelModifiers);
            },

            methods: {
                handleClick() {
                    let newValue = this.modelValue + 'b';

                    if (this.modelModifiers.uppercase) {
                        newValue = newValue.toUpperCase();
                    }
                    this.$emit('update:modelValue', newValue)
                },
            },

            template: `               
                 <div @click='handleClick'> {{modelValue}} </div>
                 
                `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
console.log(this.modelModifiers)打印结果:
在这里插入图片描述
5、slot插槽和作用域
为什么Vue需要设计slot插槽?
因为使用props属性传递dom节点,标签是非常麻烦,而有了slot插槽,刚好解决这些痛点,因为slot插槽就是用来传递dom节点和标签用的
理解:什么是slot插槽?
当我们调用子组件时候,想要一个是div按钮,一个是button按钮时候,这时候应该如何解决?

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            template: ` 
                <myform />
                <myform />
             `
        });

        app.component('myform', {
            template: `               
                <div> 
                    <input type="text">
                    <button> 提交 </button>
                </div>
                `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
这时候就需要使用 slot插槽 来解决问题

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return {
                    text: '提交'
                }
            },
            //{{text}}使用父模板里面的data数据
            template: ` 
                <myform>
                    <div> {{text}} </div>
                </myform>
                <myform>
                    <button> {{text}} </button>
                </myform>
             `
        });

        app.component('myform', {
            template: `               
                <div> 
                    <input type="text">
                    <slot></slot>
                </div>
                `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述
使用slot插槽还需要注意:
①父模板里调用的数据属性,使用都是父模板里面的数据
②子模板里调用的数据属性,使用都是子模板里面的数据
当我们在调用子组件时候,有个标签里面不用slot插槽,而我们又想它会带上默认值,这时候应该怎么处理?

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            data() {
                return {
                    text: '提交'
                }
            },

            template: ` 
                <myform>
                    <div> {{text}} </div>
                </myform>
                <myform>
                    <button> {{text}} </button>
                </myform>
                <myform>
                    
                </myform>
             `
        });

        app.component('myform', {
            template: `               
                <div> 
                    <input type="text">
                    <slot> default value </slot>
                </div>
                `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:对于前面2个slot插槽有值,不会使用默认值,只有没有值的时候,才会帮你添加上去
在这里插入图片描述
具名插槽的理解
就是把大slot插槽拆分成几个小插槽,并且配上name属性,这样调用时候,更加灵活便捷
有三个layout布局,分别是header、content、footer,现在我想把content放在中间,使用slot插槽是比较难实现的,这时候需要使用具名插槽
①添加一个 < template >占位符,使结构更加清晰,不会渲染成dom节点
②使用冒号:

<body>
    <div id="root"></div>

    <script src="./vue.global.js"></script>
    <script>

        const app = Vue.createApp({
            template: ` 
                <layout>

                    <template v-slot:header>
                        <div> header </div>
                    </template>

                    <template v-slot:footer>
                        <div> footer </div>
                    </template>
                   
                </layout>
             `
        });

        app.component('layout', {
            template: `               
                <div> 
                    <slot name='header'> </slot>
                    <div> content </div>
                    <slot name='footer'></slot>
                   
                </div>
                `
        })

        const vm = app.mount('#root');

    </script>
</body>

运行结果:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值