vue-component

本文深入探讨Vue.js中的组件,包括全局与局部组件的创建、父子组件的交互。介绍了组件的语法糖,模板分离写法,强调data必须是函数以确保组件数据独立。详细阐述了父子组件间的通信,如通过props传递数据,使用$emit触发事件,以及正确的v-model使用方法。还讨论了通过$parent、$children和refs进行组件访问。
摘要由CSDN通过智能技术生成

组件Component

  • vue.extend():调用vue.extend()创建的是一个组件构造器
    通常在创建组件构造器时,传入template嗲表我们自定义组件的模板
    该模板就是在使用到组件的地方,需要显示的HTML代码。
  • 当我们通过调用Vue.component()注册组件时,组件的注册是全局的,这就意味着该组件可以在任意vue示例下使用
  • 如果我们注册的组件挂载在某个实例中,那么就是一个局部组件
<body>
    <div id="app">
        <p>Hell vue</p>
        <my-cpn></my-cpn>
        <test></test>

    </div>
    <script>
        //全局组件
        let cpn = Vue.extend({
            template:`
            <div>
                <h2>我是标题</h2>
                <p>哈哈哈哈</p>
            </div>
            `

        });
        Vue.component("my-cpn",cpn);//注册组件为全局组件
        
        //局部组件
        var app = new Vue({
            el: "#app",
            components:{
                //局部组件
                test:cpn,
            }

        })
    </script>
</body>

全局组件的引入

main.js

import Vue from 'vue';
import MyCpn from '@/components/MyCpn.vue'; // 导入自己写的组件文件
 
Vue.use(MyComponent); // 需要调用Vue.use(),跟使用插件一样
Vue.component('my-component', MyComponent); //初始化组件
 
new Vue({
  el: '#app',
  router,
  components: {
    App,
    MyCpn 
  },
  template: '<App/>',
});

父子组件

<body>
    <div id="app">
        <p>Hell vue</p>
        <parentcpn></parentcpn>

    </div>
    <script>
        //创建第一个组件构造器
        const chidcpn = Vue.extend({
            template:`
            <div>
                <h2>我是标题</h2>
                <p>哈哈哈哈</p>
            </div>
            `

        });
        //创建第二个组件构造器
        const parentcpn = Vue.extend({
            template:`
            <div>
                <h2>我是标题</h2>
                <p>我是第二个组件构造器</p>
                <chidcpn></chidcpn>
            </div>
            `,
            components:{
                chidcpn:chidcpn

            }

        });

        var app = new Vue({
            el: "#app",
            components:{
                //局部组件
                parentcpn:parentcpn,
            }

        })
    </script>
</body>
组件的语法糖

Vue为了简化这个过程,提供了注册的语法糖
主要省去了调用vue.extend()的步骤,而是可以直接使用一个对象来替代

<body>
    <div id="app">
        <p>Hell vue</p>
        <cpn></cpn>
    </div>
    <script>
        // 方式一
        Vue.component("my-cpn",{
            template:`
            <div>
                <h2>我是标题</h2>
                <p>哈哈哈哈</p>
            </div>
            `
        });
        //方式二
        const cpn = {
            template:`
            <div>
                <h2>我是标题</h2>
                <p>哈哈哈哈</p>
            </div>
            `
        };
        var app = new Vue({
            el: "#app",
            components: {
                cpn,
            }
        })
    </script>
</body>

模板的分离写法

Vue提供了两种方案:

  • 使用
<body>
    <div id="app">
        <p>Hell vue</p>
        <my-cpn></my-cpn>

    </div>
    <!-- 方法一 -->
    <!-- <script type="text/x-template" id="cpntemplate">
        <div>
            <h2>我是标题</h2>
            <p>哈哈哈哈</p>
        </div>
    </script> -->
    <!-- 方法二 -->
    <template id="cpntemplate">
        <div>
            <h2>我是标题</h2>
            <p>哈哈哈哈</p>
        </div>
    </template>
    <script>
        //全局组件
        Vue.component("my-cpn",{
            template:"#cpntemplate"
        })
        var app = new Vue({
            el: "#app",

        })
    </script>
</body>
data是函数得原理
  • 组件不可以访问vue实例中的数据,vue应该有自己存放数据的地方
  • 组件也有一个data属性,且必须是有一个函数
  • 这个函数返回一个对象,对象内部保存着数据
    -为什么是一个函数,如果是一个对象的话,当组件多次使用的时候,会造成数据被共用的问题,为了让组件在每次使用的时候,都有独立的data对象,所以必须是函数
<body>
    <div id="app">
        <cpn></cpn>
        <cpn></cpn>
    </div>
    <script>
        const cpn = {
            template:`
            <div>
                <p>个数是{{count}}</p>
                <button @click="increment">+</button>
                <button @click="decrement">-</button>
            </div>
            `,
            data(){
                return{
                    count:0,
                }
            },
            methods: {
                increment(){
                    this.count++;

                },
                decrement(){
                    this.count--;
                }
            },
        }
        var app = new Vue({
            el: "#app",
            data: {

            },

            components:{
                cpn
            }
        })
    </script>
</body>

在这里插入图片描述
当data 为对象时,报一下错误:
在这里插入图片描述

<body>
    <div id="app">
        <cpn></cpn>
        <cpn></cpn>
    </div>
    <script>
        const cpndata = {
            count:0,
        }
        const cpn = {
            template:`
            <div>
                <p>个数是{{count}}</p>
                <button @click="increment">+</button>
                <button @click="decrement">-</button>
            </div>
            `,
            data(){
                return cpndata;//导致多个vue实列返回得到是同一个data对象
            },
            
            methods: {
                increment(){
                    this.count++;
                },
                decrement(){
                    this.count--;
                }
            },
        }
        var app = new Vue({
            el: "#app",
            data: {

            },

            components:{
                cpn
            }
        })
    </script>
</body>

在这里插入图片描述

父子组件的通信

如何进行父子组件间的通信呢

  • 通过prop向子组件传递数据
  • 通过事件向父组件发送消息
<body>
    <div id="app">
        <cpn :cmoives="movies" :cmessage="message"></cpn>
    </div>
    <!-- 子组件template -->
    <template id="cpntemplate">
        <div>
            <p>{{cmessage}}</p>
            <ul>
                <li v-for="item in cmoives">{{item}}</li>
            </ul>
        </div>
    </template>
    <script>

        // 子组件
        const cpn = {
            template:"#cpntemplate",
            data(){
                return {

                };
            },
            // 方式一
            // props:['cmoives','cmessage'],
            //方式二
            // props:{
            //     cmoives:Array,
            //     cmessage:String,
            // }
            //方式三
            props:{
                cmoives:{
                    type:Array,
                    // default:[]
                    //默认值是一个对象或数组时,default是一个函数
                    default(){
                        return [];
                    },
                    validator:function(value){
                        console.log(value);
                        return false;
                    }
                },
                cmessage:{
                    type:String,
                    default:'',
                    required:true,
                },
            }
        }
        //父组件
        var app = new Vue({
            el: "#app",
            data: {
                movies:['ddd','ccccc','eeeee'],
                message:"aaaaa",
            },

            components:{
                cpn
            }
        })
    </script>
</body>

问题
当props中的属性是驼峰命名时,会报错,新版本可以用c-Message解决

子组件向父组件传递事件

this.$emit(‘itemclick’,item); 第一个参数需要传递事件的名字

<body>
    <div id="app">
        <cpn @itemclick="cpnclick"></cpn>
    </div>
    <!-- 子组件template -->
    <template id="cpntemplate">
        <div>
            <button v-for="item in catgories" @click="itemclick(item)">{{item.name}}</button>
        </div>
    </template>
    <script>

        // 子组件
        const cpn = {
            template:"#cpntemplate",
            data(){
                return {
                    catgories:[
                        {id:'aaa',name:'热门推荐'},
                        {id:'bbb',name:'手机数码'},
                        {id:'ccc',name:'家用家电'},
                    ]
                };
            },
            methods:{
                itemclick(item){
                    console.log(item);
                    this.$emit('itemclick',item);
                }
            }
        }
        //父组件
        var app = new Vue({
            el: "#app",
            data: {

            },
            components:{
                cpn
            },
            methods:{
                cpnclick(item){
                    console.log("itemdddd",item);
                }
            }
        })
    </script>
</body>
父子组件通信案例

props中的属性不要直接v-model
在这里插入图片描述
错误实现方法

<body>
    <div id="app">
        <cpn :cnumber1="dnumber1" :cnumber2="dnumber2"></cpn>
    </div>
    <!-- 子组件template -->
    <template id="cpntemplate">
        <div>
            <p>{{cnumber1}}</p>
            <input type="text" v-model="cnumber1">
            <p>{{cnumber2}}</p>
            <input type="text" v-model="cnumber2">
        </div>
    </template>
    <script>
        // 子组件
        const cpn = {
            template:"#cpntemplate",
            data(){
                return {        

                };
            },
            props:{
                cnumber1:Number,
                cnumber2:Number,
            }
        }
        //父组件
        var app = new Vue({
            el: "#app",
            data: {
                dnumber1:1,
                dnumber2:2,
            },
            components:{
                cpn
            },
        })
    </script>
</body>

正确实现方法

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>

<body>
    <div id="app">
        <cpn :cnumber1="dnumber1" :cnumber2="dnumber2" @num1change="num1change" @num2change="num2change"></cpn>
        <p>dnumber1: {{dnumber1}}</p>
        <p>dnumber2: {{dnumber2}}</p>
    </div>
    <!-- 子组件template -->
    <template id="cpntemplate">
        <div>
            <p>{{dcnumber1}}</p>
            <input type="text" v-model="dcnumber1" >
            <p>{{dcnumber2}}</p>
            <input type="text" v-model="dcnumber2">
        </div>
    </template>
    <script>
        // 子组件
        const cpn = {
            template:"#cpntemplate",
            data(){
                return {   
                    //通过data对象中的属性去接受从父组件中传来的数据
                    dcnumber1:this.cnumber1,
                    dcnumber2:this.cnumber2,     
                };
            },
            props:{
                cnumber1:Number,
                cnumber2:Number,
            },
            watch:{
            //监听值是否发生变化,dcnumber1需要和data中的属性名一致,也需要v-model绑定
                dcnumber1(newValue){
                    this.dcnumber1 = newValue;
                    this.$emit('num1change',newValue);

                },
                dcnumber2(newValue){
                    this.dcnumber2= newValue;
                    this.$emit('num2change', newValue);
                }
            }
        }
        //父组件
        var app = new Vue({
            el: "#app",
            data: {
                dnumber1:1,
                dnumber2:2,
            },
            components:{
                cpn
            },
            methods:{
                num1change(value){
                    this.dnumber1=parseInt(value)
                },
                num2change(value){
                    this.dnumber2=parseInt(value);
                }
            }
        })
    </script>
</body>

</html>

注意:

  • 1 需要用data对象中的属性去接受从父组件中传来的数据
  • 2 v-model绑定data中的属性
  • 3 watch监听v-model绑定的属性值是否发生变化
父子组件的访问方式
  • 父组件访问子组件,使用 c h i l d r e n 或 children或 childrenrefs
  • 子组件访问父组件,使用$parent
  • $refs 可以通过在子组件中加上ref指定名字,获取指定的子组件对象

this.$children是一个数组类型,它包含所有子组件对象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../vue.js"></script>
</head>

<body>
    <div id="app">
        <cpn ref="bbb"></cpn>
        <cpn ref="aaa"></cpn>
        <button @click="testclick">点我</button>
    </div>
    <!-- 子组件template -->
    <template id="cpntemplate">
        <div>
            <p>Hello world</p>
        </div>
    </template>
    <script>
        // 子组件
        const cpn = {
            template:"#cpntemplate",
            data(){
                return {   
                
                };
            },
            methods:{
                show(){
                    console.log("我是子组件");
                }
            }
        }
        //父组件
        var app = new Vue({
            el: "#app",
            data: {

            },
            components:{
                cpn
            },
            methods:{
                testclick(){
                    console.log(this.$children);
                    console.log(this.$refs);
                    console.log(this.$refs["aaa"])
                
                }
            }
        })
    </script>
</body>

</html>
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值