Vue组件基础

一、定义

组件 (Component) 是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些情况下,组件也可以表现为用 is 特性进行了扩展的原生 HTML 元素。所有的 Vue 组件同时也都是 Vue 的实例,所以可接受相同的选项对象 (除了一些根级特有的选项) 并提供相同的生命周期钩子。


二、全局组件

在很多 Vue 项目中,我们使用 Vue.component 来定义全局组件,紧接着用 new Vue({ el: '#container '}) 在每个页面内指定一个容器元素。
全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。
注册组件:
Vue.component( id, [definition] )
参数:

  • {string} id
  • {Function | Object} [definition]

data 必须是一个函数

当我们定义这个 组件时,你可能会发现它的 data 并不是像这样直接提供一个对象:

data:{
       aaa:"h1"
},

取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

data(){
       return {
              aaa:"h1"
          }
 },

基本示例

(一、)定义一个名为con-a 的新组件

Vue.component("con-a",{
            //这里的data要用return
            data(){
                return {
                    aaa:"h1"
                }
            },
            template:"<h1>我是{{aaa}}里面的内容</h1>"//{{aaa}}是前面定义的东西
            })

组件是可复用的 Vue 实例,且带有一个名字:在这个例子中是 <con-a>。我们可以在一个通过 new Vue 创建的 Vue 根实例中,把这个组件作为自定义元素来使用:

<div id="all">
        <con-a></con-a>
    </div>
 new Vue({
            el:"#all",
        })

结果
在这里插入图片描述


三、局部组件

Vue实例里面的component是:{}。局部组建无法被其他实例对象使用

示例

例:

    <div id="all">
        <con-a></con-a>
        <con-b></con-b>
        <con-a></con-a>
        <con-b></con-b>
    </div>
    <script>
        new Vue({
            el:"#all",
            components:{
                "con-a":{template:"<h1>我是h1里面的内容</h1>"},
                "con-b":{template:"<h2>我是h2里面的内容</h2>"}

            }
        })
    </script>

结果
在这里插入图片描述


四、Vue组件的其他写法

使用template标签

<template> 元素 是一种用于保存客户端内容的机制,该内容在页面加载时不被渲染,但可以在运行时使用JavaScript进行实例化。
在此处的用法


    <template id="conAB">
        <h3>我是用template标签写的</h3>//多内容输出必须有一个根元素
    </template>

全局组件

Vue.component("con-a-b",{template:"#conAB"})

局部组件

 new Vue({
        el:"#tem",
        components:{
            "com-a-b":{template:"#conAB"}
        }
 })

显示

<div id="tem">
        <com-a-b></com-a-b>
        <con-a-b></con-a-b>
    </div>

结果
在这里插入图片描述

使用script标签

跟前一个仅仅在标签使用的不同,调用方法相同

   <div id="tem">
        <com-a-b></com-a-b>
        <con-a-b></con-a-b>
    </div>
    <script type="text/template" id="conAB">
    <h3>我是用template标签写的</h3>//多内容输出必须有一个根元素
    </script>
    <script>
        Vue.component("con-a-b",{template:"#conAB"})
        new Vue({
            el:"#tem",
            components:{
                "com-a-b":{template:"#conAB"}
            }
        })
    </script>

结果
在这里插入图片描述


五、组件的复用

你可以将组件进行任意次数的复用:

 <div id="all">
        <con-a></con-a>
        <con-a></con-a>
        <con-a></con-a>
    </div>

在这里插入图片描述


六、通过 Prop 向子组件传递数据

props单向数据流,父组件向子组件传递数据
vue实例

 new Vue({
            el:"#co",
            data:{
                msg:"parent msg"
            }
        })

利用props获取父级中的数据
props可以是一个数据类型也可以是一个数组,也可以是对象,对象下的数据有3个属性type,default,require。其中default,require值都是布尔类型值。type有Number,String,Boolean,Array,Object,Function,Symbol。

 <template id="comAB">
     <h3>我是父级传递过来的数据->{{aaa}}</h3>
 </template>
Vue.component("comAB",{
            // props:["aaa"],
            props:{
                "aaa":String,
            },
            template:"#comAB"
        })
 <div id="co">
        <com-a-b :aaa="msg">   </com-a-b>// 
 </div>

结果
在这里插入图片描述

问题:单项数据里,所以子级修改父级数据一般是不允许的

解决方法:父级传递一个对象或数组给子级
因为对象或数组是引用类型,指向的是同一个内存空间所以当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">
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
   <title>prop父级向子级传递数据</title>
</head>
<body>
    <div id="co">
       我是父级中的数据 {{msg.a}}
        <com-a-b :aaa="msg">   </com-a-b>

    </div>
    <template id="comAB">
        <h3 @click="change">我是父级传递过来的数据->{{aaa.a}}</h3>
    </template>
    <script>
        Vue.component("comAB",{
            props:["aaa"],
            template:"#comAB",
            methods:{
                change(){
                    this.aaa.a="zzz";
                }
            }
        })
        new Vue({
            el:"#co",
            data:{
                msg:{a:"parent msg"}
            }
        })
    </script>
</body>
</html>

还有一个注意项:Prop 的大小写
HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
例如:

   <div id="co">
       我是父元素中数据-> {{msg.a}}
        <com-a-b :aa-a="msg">   </com-a-b>//此处讲aaA改为aa-a

    </div>
    <template id="comAB">
        <h3 @click="change">我是父级传递过来的数据->{{aaA.a}}</h3>//此处利用驼峰式命名
    </template>
    <script>
        Vue.component("comAB",{
            props:["aaA"], //此处利用驼峰式命名
            template:"#comAB",
            methods:{
                change(){
                    this.aaA.a="changes";//此处利用驼峰式命名
                }
            }
        })
        new Vue({
            el:"#co",
            data:{
                msg:{a:"parent msg"}
            }
        })
    </script>

七、父级获取子级数据

Vue 实例提供了一个自定义事件的系统来解决这个问题。
子组件通过this.$emit()派发事件,父组件利用v-on对事件进行监听,实现参数的传递
调用 $emit 方法并传入事件的名字,来向父级组件触发一个事件:

    <template id="ch">
        <h3 @click="send()">子级数据->{{cmsg}}</h3>
    </template>
        <script>
        Vue.component("com",{
            data(){
                return {
                    cmsg:"cMsg"
                }
            },
            template:"#ch",
            methods:{
                send(){
                    this.$emit("child-say",this.cmsg)
                }
            }
	 })
    </script>	 

然后我们可以用 v-on 监听这个事件,就像监听一个原生 DOM 事件一样:

    <div id="co">
        <h3 >父级数据->{{pmsg}}</h3>
        <com @child-say="show"></com>
    </div>
 <script>
      new Vue({
            el:"#co",
            data:{
                pmsg:"pMsg"
            },
            methods:{
                show(msg){
                    this.pmsg=msg;
                }
            }
        })
</script>

结果:点击自己元素,父级元素获得子级元素


八、子级与子级间数据传递

<!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">
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <title>子级与子级间数据传递</title>
</head>
<body>
    <div id="co">
        <coma></coma>
        <comb></comb>
    </div>
    <template id="cha">
        <h3 @click="send()">子级A数据->{{cmsga}}</h3>
    </template>
    <template id="chb">
        <h3 @click="send()">子级B数据->{{cmsgb}}</h3>
    </template>
    <script>
        let ev=new Vue();
        Vue.component("coma",{
            data(){
                return {cmsga:"cMsgA"}
            },
            template:"#cha",
            methods:{
                send(){
                    ev.$emit("a-say",this.cmsga)
                }
            },
            mounted(){//此处是mounted()挂载结束后执行
                ev.$on("b-say",msg=>{
                    this.cmsga=msg;
                })
            }
        })
        Vue.component("comb",{
            data(){
                return {cmsgb:"cMsgB"}
            },
            template:"#chb",
            methods:{
                send(){
                    ev.$emit("b-say",this.cmsgb)
                }
            },
            mounted(){//此处是mounted()挂载结束后执行
                ev.$on("a-say",msg=>{
                    this.cmsgb=msg;
                })
            }
            
        })
        new Vue({
            el:"#co"
        })
    </script>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值