一、父组件给子组件传递数据
1.使用props属性,父组件向子组件传递数据
const cpn = { template: "#cpn", props: { cmessage: { type: String, default: 'zzzzz', required: true //在使用组件必传值 } } }
2.向cmessage对象传值
<div id="app"> <cpn :cMessage="message"></cpn> </div> <script> const app = new Vue({ el: "#app", data: { message: "你好", movies: ["复仇者联盟", "钢铁侠", "星际穿越", "哪吒传奇"] }, components: { cpn } }) </script>
2. props属性使用
1.数组写法
props: ['cmovies', 'cmessage']
2.对象写法
props: { cmessage: { type: String, default: 'zzzzz', required: true //在使用组件必传值 } }
3.props属性的类型限制
//1.类型限制(多个类使用数组) cmovies:Array,//限制为数组类型 cmessage:String,//限制为Strin类型 cmessage:['String','Number']//限制为String或Number类型
4.props属性的默认值
// 2.提供一些默认值,以及必传值 cmessage: { type: String, default: 'zzzzz',//默认值 }
5.props属性的必传值
cmessage: { type: String, default: 'zzzzz', required: true //在使用组件必传值 }
6.类型是Object/Array,默认值必须是一个函数
//类型是Object/Array,默认值必须是一个函数 cmovies: { type: Array, default () { return [1, 2, 3, 4] } },
7.自定义验证函数
vaildator: function (value) { //这个传递的值必须匹配下列字符串中的一个 return ['zzzzz', 'ttttt', 'yyy'].indexOf(value) !== -1 }
8.自定义类型
function Person(firstName,lastName) { this.firstName = firstName this.lastName = lastName } cmessage:Person//限定了cmeessage必须是Person类型
二、组件通信
1 父传子
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <!-- <cpn1 :msg="message"></cpn1> --> <!-- <cpn1 :msg="message2"></cpn1> --> <cpn1 :msgab="add"></cpn1> <h2>{{count}}</h2> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { /* message: ['蔡英文', '吴钊燮'] */ /* message2:{ name:'蔡英文', age:56, sex:'女' } */ count:0 }, methods: { add:function(){ return this.count++ } }, computed: { }, components: { cpn1: { /* template: ` <div>我是中国人{{msg.name}}{{msg.sex}}</div> `, */ template: ` <div> <div @click="sum">+</div> </div> `, props: { /* msg:{ type: Array } */ /* msg:{ type: Object } */ msgab:{ type:Function }, }, methods:{ sum(){ this.msgab() } } } } }) </script> </body> </html>
2.子传父
子组件向父组件传值,使用自定义事件$emit。
<!-- 父组件 --> <div id="app"> <!-- 不写参数默认传递btnClick的item --> <cpn @itemclick="cpnClcik"></cpn> </div> <!-- 子组件 --> <template id="cpn"> <div> <button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{{item.name}}</button> </div> </template> <script src="../js/vue.js"></script> <script> const cpn = { template: "#cpn", data() { return { categoties: [{ id: 'aaa', name: '热门推荐' }, { id: 'bbb', name: '手机数码' }, { id: 'ccc', name: '家用家电' }, { id: 'ddd', name: '电脑办公' }, ] } }, methods: { btnClick(item) { this.$emit('itemclick', item) } }, }; const app = new Vue({ el: "#app", data() { return { } }, methods: { cpnClcik(item) { console.log('cpnClick'+item.name); } }, components: { cpn }, }) </script>
1.在子组件中定义一个方法btnClick(item),使用$emit,'itemclick'是事件名,item是传过去的值。
methods: { btnClick(item) { this.$emit('itemclick', item) } },
2.在子组件中监听点击事件并回调此方法
<div> <button v-for="(item, index) in categoties" :key="index" @click="btnClick(item)">{{item.name}}</button> </div>
3.在父组件中定义一个方法cpnClcik(item)
methods: { cpnClcik(item) { console.log('cpnClick'+item.name); } },
4.并在父组件(vue实例)中调用(不写参数默认传递btnClick的item ),父组件监听事件名为itemclick的子组件传过来的事件。
三、父访问子(children、ref)
1.children、ref基本用法
父组件访问子组件,有时候需要直接操作子组件的方法,或是属性,此时需要用到$children和$ref。
使用this.$children直接获取**当前实例的直接子组件,需要注意 $children 并不保证顺序,也不是响应式的。**如果你发现自己正在尝试使用 $children 来进行数据绑定,考虑使用一个数组配合 v-for 来生成子组件,并且使用 Array 作为真正的来源。
<!-- 父组件 --> <div id="app"> <cpn></cpn> <cpn></cpn> <cpn ref="aaa"></cpn> <button @click="btnClick" >按钮</button> </div> <!-- 子组件 --> <template id="cpn"> <div> 我是子组件 </div> </template> <script src="../js/vue.js"></script> <script> // 父传子:props const cpn = { template: "#cpn", data() { return { name:"我是子组件的name" } }, methods: { showMessage(){ console.log("showMessage"); } }, }; const app = new Vue({ el: "#app", data() { return { message:"hello" } }, methods: { btnClick(){ // 1.children // console.log(this.$children[0].showMessage) // for (let cpn of this.$children) { // console.log(cpn.showMessage) // } // 2.$ref console.log(this.$refs.aaa.name) } }, components: { cpn }, }) </script> $children方式 // 1.children console.log(this.$children[0].showMessage) for (let cpn of this.$children) { console.log(cpn.showMessage) }
$refs方式:ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
2.ref的基本使用 用在元素上
ref的基本使用 用在元素上
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <p ref="p" @click="handelClick" id="ppp">hello</p> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> <script> const app = new Vue({ el: "#app", data: { }, methods: { handelClick(){ console.log(this.$refs.p); const ppp = document.querySelector('#ppp') console.log(ppp); } }, computed:{ } }) </script> </body> </html>
3.ref在子组件上的使用
1. ref可以调用组件中的数据
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <counter ref="one" @change="handelChange"></counter> <counter ref="two" @change="handelChange"></counter> <div>total:{{total}}</div> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> <script> Vue.component('counter',{ template:'<div @click="handelclick">{{number}}</div>', data(){ return { number:0 } }, methods:{ handelclick(){ this.number++; this.$emit('change'); } } }) const app = new Vue({ el: "#app", data: { total:0 }, methods: { handelChange(){ this.total = this.$refs.one.number + this.$refs.two.number } }, computed:{ } }) </script> </body> </html>
2.ref可以调用组件中的方法
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <helloworld ref="hello"></helloworld> <button @click="getHello">获取helloworld组件中的值</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> <script> Vue.component('helloworld',{ template:'<div></div>', data(){ return { number:0 } }, methods:{ handelclick(){ console.log('被调用了'); } } }) const app = new Vue({ el: "#app", data: { }, methods: { getHello(){ this.$refs.hello.handelclick(); console.log(this.$refs.hello.number); console.log(this.$refs.hello.$el.innerHTML); } }, computed:{ } }) </script> </body> </html>
四、动态组件(is、component)
1.is用于动态组件且基于 DOM 内模板的限制来工作。
基于 DOM 内模板的限制来工作
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <table> <tr is="row"> </tr> </table> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script> <script> Vue.component('row',{ template:'<tr><td>111</td></tr>' }) const app = new Vue({ el: "#app", data() { return {} }, methods: { }, computed:{ } }) </script> </body> </html>
2.动态组件component
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <div id="app"> <!-- <child-one></child-one> <child-two></child-two> --> <component :is="type"></component> <button @click="handerClick">点击</button> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> Vue.component('child-one',{ template:'<div>child-one</div>' }) Vue.component('child-two',{ template:'<div>child-two</div>' }) const app = new Vue({ el:'#app', data(){ return { type:'child-one' } }, methods:{ handerClick(){ console.log('111'); this.type=this.type==='child-one'?'child-two':'child-one'; } } }) </script> </body> </html>
3.动态组件官网案例
这是动态组件官网案例
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style> .tab-button { padding: 6px 10px; border-top-left-radius: 3px; border-top-right-radius: 3px; border: 1px solid #ccc; cursor: pointer; background: #f0f0f0; margin-bottom: -1px; margin-right: -1px; } .tab-button:hover { background: #e0e0e0; } .tab-button.active { background: #e0e0e0; } .tab { border: 1px solid #ccc; padding: 10px; } </style> </head> <body> <div id="app"> <button v-for="(tab,index) in tabs":key="index" @click="handelclick(tab)" :class="getStyle(tab)">{{tab}}</button> <component :is="currentTabComponent"></component> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> Vue.component('tab-home',{ template:'<div>child-one</div>' }) Vue.component('tab-posts',{ template:'<div>child-two</div>' }) Vue.component('tab-archive',{ template:'<div>child-three</div>' }) const app = new Vue({ el:'#app', data(){ return { currentTab: "Home", tabs: ["Home", "Posts", "Archive"] } }, methods:{ handelclick(tab){ this.currentTab = tab }, getStyle(tab){ return ['tab-button',{active:this.currentTab===tab}] } }, computed:{ currentTabComponent(){ /* return `tab-${this.currentTab}`.toLowerCase() */ return "tab-"+this.currentTab.toLowerCase() }, } }) </script> </body> </html>