在html中,我们学习的单元是标签。 可以把Html中的标签当成最小最小最小的组件。 在vue中,我们学习的单元是组件 组件就是我们自己扩展的 “HTML 元素”,封装可重用的代码。 在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能。 组件(Component)是 Vue.js 最强大的功能之一。 在vue当中,一切都是组件,写项目就是在写组件。 一个组件本质就是一个对象。 区别:
根组件(vue的实例)它有el。而子组件中有templatedata的写法不同。根组件中就是对象,子组件中是函数。子组件中,同样可以也包含子组件
在 let vm = new Vue({}) 我们得到 的vm是一个Vue的一个对象(或者叫实例) 它也可以理解为一个组件,只不过它是一切其它的组件的根组件 一个项目就通常只有一个根组件
组件三步曲:
定义组件 难注册组件 Vue.component(“my-header” ) 全局注册 在所有的根组件中都可以使用使用组件 使用组件就是在使用标签定义组件template 下,data必须是一个函数,而且必须返回一个对象。
全局:所有的vue实例都可以使用 在使用一个组件时,当成自定义标签就OK了 自定义标签默认都是行内的,都是女标签。 可以通过vue.extend与vue.component来定义组件。
<body> <!--是根组件的模板--> <div id="app1"> <!--3)使用子组件--> <my-header></my-header> </div> <div id="app2"> <!--3)使用子组件--> <my-header></my-header> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> // 定义一个全局组件 一个组件就是一个JS对象 // Vue.component();第1个参数是组件的名字,第2个参数代表这个组件 // 组件指的是: /* 一个组件就是一个JS对象 { // tempplate 指定子组件的模板 template:"<div>{{msg}}</div>", data(){ //在自组件中data 必须是函数,必须返回对象 return{ msg:"hello 子组件" } } } */ // Vue.component 表示注册一个组件 Vue.component("my-header",{ // tempplate指定子组件的模板 template:"<div>{{msg}}</div>", data(){ return{ msg:"hello 子组件" } } }); // 1)定义组件 let myComponent = { template: "<div>{{msg}} <button @click='f1'>点击</button></div>", // 当前组件模板 data(){ return { msg:"hello component" } }, // 给当前组件提供数据 methods:{ f1(){console.log("f1....")} }, // 当前组件模板中使用到的方法 } // 2)注册组件 注册分全局注册和局部注册 由于是全局注册,意味着在所有的根组件对应的模板中都可以使用 Vue.component("my-header",myComponent); let vm1 = new Vue({ el:"#app1", }) let vm2 = new Vue({ el:"#app2", }) </script> </body>组件的名字:
组件的定义时的名字组件的注册时的名字组件使用时,使用的是注册时的名字我们很少会用全局组件,因为,在一个页面中,我们只会设置一个vue实例。
局部子组件就是说注册一个组件,这个组件只属于某个根组件 局部组件就是要去配置一下components这个选项。(就和配置 methods,data,filters,computed 一样)
<div id="app1"> <!-- 3)使用子组件--> <my-header></my-header> </div> <script> // 1) 定义子组件 let myComponet = { template:"<div>{{msg}}</div>", data(){ return{ msg:"hello 局部注册子组件" } } } let vm1 = new Vue({ el:"#app1", // 2)局部注册一个子组件 components:{ "my-header":myComponet } }) </script>配置template注意点:
template指令模板时,必须使用根标签包起来,否则报错:Component template should contain exactly one root element.template指定模板常见的方式:
template:后面写字符串 template:"<div><div>div</div><span>span</span></div>" 把模板定义到外面,在template引用 A)<template id="test"> //常用 <div> <div>我是一个div</div> <p>我是一个p标签</p> <h1>我是一个h1</h1> </div> </template> B)<script type="text/html" id="test"> <div> <div>我是一个div</div> <p>我是一个p标签</p> <h1>我是一个h1</h1> </div> </script>使用组件三步曲之名字:
定义组件时,最好使用大驼峰命名
注册时,可以和定义组件时名字一样
目前来说,使用组件时,不要使用大驼峰,但是后面,我们会使用大驼峰
如果说,定义组件和注册组件都是大驼峰,使用组件时,名字换成中划线
与vm实例中的data语法不同: 子组件中的data是一个函数,在其中写return { }。这是固定写法:
let 组件名 = { template:””, data:function(){ return { //数据项 } } }如果你在data中使用到了this,那么,你的data函数不能简写,简写后的箭头函数中没有this。
在一个组件中使用 components 去注册另一个组件,就可以使用注册的那个组件了。
<!--根组件模板--> <div id="app"> <Father></Father> </div> <!--Father组件对应的模板--> <template id="father"> <div> <h1>Father组件 ---》{{fatherData}}</h1> <Son></Son> </div> </template> <!--Son组件对应的模板--> <template id="son"> <div> <h1>Son组件 ---》{{sonData}}</h1> </div> </template> <script> let Son = { // 定义Son组件对象 template:"#son", data(){ return { sonData:"Son组件中的data" } } } let Father = { // 定义Father组件对象 template:"#father", data(){ return { fatherData:"Father组件中的data" } }, components:{ Son // 在Father组件中注册Son组件 // 就可以在Father组件所对应的模板中使用Son组件 } } let vm = new Vue({ el:"#app", components:{ Father, } }) </script>把根组件作为父组件。父子之间不能正常共享数据的,父中的数据在子中是没有办法使用。
一个组件中的数据,默认情况下,只能让本组件所对应的模板使用,其它组件所对应的模板不能使用。但是可能通过一定的段,让子组件也可以使用父组件所对应的数据,也就是说需要把父组件中的数据传递到子组件,让子组件使用。这叫父传子。如果说把子组件中数据,传递给父组件,让父组件使用,那叫做子传父。
<!--根组件模板--> <div id="app"> <Father></Father> </div> <!--Father组件对应的模板--> <template id="father"> <div> <h1>Father组件 ---》{{fatherData}}</h1> <Son :xxx="fatherData"></Son> </div> </template> <!--Son组件对应的模板--> <template id="son"> <div> <h1>Son组件 ---》{{sonData}}</h1> <!--你在SON组件中使用Father组件中数据就报错--> <!--<h2>要Son组件中使用Father组件中的数据 ---》 {{fatherData}}</h2>--> <h2>使用父组件传递过来的数据:{{xxx}}</h2> </div> </template> <script> let Son = { template:"#son", props:{ // fatherData是接收的数据 String是对数据检验 // 我期待父组件传给子组件的数据的类型是String xxx:String }, data(){ return { sonData:"Son组件中的data" } } } let Father = { template:"#father", data(){ return { fatherData:"Father组件中的data" } }, components:{ Son } } let vm = new Vue({ el:"#app", components:{ Father, } }) </script>HTML中标签:
<h1 title="hello"></h1> title="hello" html中自带的属性 <h1 abc="123"></h1> abc="123" html中自定义属性 <Son abc="123"></Son> <Son>不是html中的标签 组件 <Son abc="123"></Son> abc="123" 自定义属性 <Son title="hello"></Son> title="hello" 自定义属性传递数据就靠自定义属性 第一步:在父组件所对应模板中使用子组件,属性位置绑定父组件中的数据
<template id="father"> <div> <h1>Father组件 ---》{{fatherData}}</h1> <Son :xxx="fatherData"></Son> </div> </template>第二步:在子组件中通过props接收数据,如下:
let Son = { template:"#son", rops:{ // fatherData是接收的数据 String是对数据检验 // 期待父组件传给子组件的数据的类型是String xxx:String }, data(){ return { sonData:"Son组件中的data" } } }第三步:在子组件所对应的模板中就可以使用父组件传递过来的数据了
<template id="son"> <div> <h1>Son组件 ---》{{sonData}}</h1> <h2>使用父组件传递过来的数据:{{xxx}}</h2> </div> </template>一个组件的配置项,作用:接收父组件传递过来数据。 如父组件中绑定了一个数据:
props:{ xxx:{ type:String, // 期待父组件传递过来一个String类型的数据 // required:true, // 必须要求父传递数据 default:"lalala", // 配置默认值 } }, //type:[String,Number] 表示string和number都可以单个可以简写:
props:{ xxx:Number }父传子有一个核心 子组件中的props配置项 父子传递,讲究”你情我愿”,父需要绑定数据,子需要接收数据
HTML标签才有自带属性 只要不是HTML标签,里面写的都叫自定义属性
<button title="haha">登录</button> title="haha" 标签自带属性 <Son title="haha"></Son> title="haha" 自定义属性标签的点击事件 给html标签上button按钮绑定一个点击事件,当我们点击时,调用f1方法,不需要写代码,只需要鼠标点击就会触发点击事件
<button @click="f1"></button> html标签 click自带事件非HTML标签的自定义事件 不能说:给Son上绑定一个点击事件 给Son组件上绑定了一个自定义事件, 需要写代码去触发这个自定义事件
<Son @click="f1"></Son> 不是html标签 自定义事件 <Son @Hello="f1"></Son> 不是html标签 @Hello="f1 自定义事件 订阅事件事件分两类:
浏览器自带的事件 click 点击了自定义事件 Hello 需要写代码触发Hello事件 发布订阅发布订阅难点:
<Son hello="ff"></Son> 自定义属性 值是 "ff" 字符串 <Son :hello="ff"></Son> 自定义属性 值是 ff 对应的数据 <Son @hello="ff"></Son> 自定义事件 事件发生时执行 ff 方法在子模板的里面使用点击事件,点击调用方法,然后方法会触法一个自定义事件{ this.$emit(“自定义”)},可以传递参数。这个自定义事件在父模板使用子模板时绑定到子模板上的,这个自定义事件写在父模板的方法里面,形参就是接收的数据。
子组件的模板绑定一个天生点击事件,点击时调用子的方法 ff1
<button @click="ff1">点击</button>在子组件的方法中的 ff1 中使用 this.$emit(“ange”),触发该自定义事件:发布
ff1(){ this.$emit( "ange" ,this.sonData)} 传递数据sonData在父组件的模板中使用子组件,用触发的自定义事件去调用父的方法 ff2 : 订阅
<Son @ange="ff2"></Son> 父模板使用子组件 data(){ dataformson:"") ff2(msg) {console.log(msg); 方法2接收子传递的数据 this.dataformson = msg } 接收的数据赋值给父组件父传子:
在父组件对应的模板中绑定自定义属性在子组件中通过props接收自定义属性(数据)在子组件中就可以使用这些数据子传父:
在父组件对应的模板中子组件上绑定自定义事件在子组件中触发自定义事件,触发自定义事件时,可以携带数据在父组件中,当自定义事件发生时,调用监听器,监听器的形就是接收到的数据vue中组件通信方案:
父传子 绑定自定义属性 + props接收子传子 绑定自定义事件 + this.$emit() 触发自定义事件并携带数据