Vue 的组件最核心的选项有以下几个:
模板(template)
初始数据(data)
接受的外部参数(props)
方法(methods)
生命周期钩子函数(lifecycle hooks)
组件 props
组件中更重要的是组件间进行通信,选项props是组件中非常重要的一个选项,起到父子组件间桥梁的作用。
1.静态props
子组件使用父组件的数据
<!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"/> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <my-componet message="来至父组件的数据!!"></my-componet> </div> <script type="text/javascript"> Vue.component('my-componet', { // 声明 props props: ['message'], // 就像 data 一样,prop 可以用在模板内 // 同样也可以在 vm 实例中像 “this.message” 这样使用 template: '<span>{{ message }}</span>' }) new Vue({ el:'#app' }); </script> </body> </html>
动态 props 动态接收父组件数据到子组件 <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"/> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <input type="text" v-model="parentMessage"> <my-componet :message="parentMessage"></my-componet> </div> <script type="text/javascript"> Vue.component('my-componet', { props: ['message'], template: '<span>{{ message }}</span>' }) new Vue({ el:'#app', data:{ parentMessage:'' } }); </script> </body> </html>
这里使用 v-model 绑定了父组件数据 parentMessage,当在输入框中输入数据时,子组件接收到的 props“'message'”也会实时响应,并更新组件模板。 如果你在父组件中直接传递数字、布尔值、数组、对象时, 它所传递默认值字符串。如果想传递一个实际的数值,需要使用 v-bind ,从而让它的值被当作 JavaScript 表达式计算,代码如下: <div id="app"> <my-componet message="1+1"></my-componet><br> <my-componet :message="1+1"></my-componet> </div> <script type="text/javascript"> Vue.component('my-componet', { props: ['message'], template: '<span>{{ message }}</span>' }) new Vue({ el:'#app' }); </script>
props 验证 当组件给其他人使用时,推荐进行数据验证。 验证的type类型可以是:String、Number、Boolean、Function、Object、Array等。 如果传入子组件的 message 不是数字,则抛出警告 <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"/> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="example"> <parent></parent> </div> <script> var childNode = { template: '<div>{{message}}</div>', props:{ 'message':Number } } var parentNode = { template:'<div class="parent"><child :message="msg"></child></div>', components: { 'child': childNode }, data(){ return{ msg: '123' } } }; // 创建根实例 new Vue({ el: '#example', components: { 'parent': parentNode } }) </script> </body> </html>
单项数据流 所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。之所以这样设计,是尽可能将父子组件解耦,避免子组件无意中修改了父组件的状态。 <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"/> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="example"> <parent></parent> </div> <script> var childNode = { template: '<div class="child"><div><span>子组件数据</span>' + ' <input v-model="childMsg"> </div> <p>{{childMsg}}</p></div>' , props:['childMsg'] } var parentNode = { template: '<div class="parent"><div><span>父组件数据</span>' + ' <input v-model="msg"> </div> <p>{{msg}}</p> <child :child-msg="msg"></child></div>', components: { 'child': childNode }, data(){ return { 'msg':'match' } } }; // 创建根实例 new Vue({ el: '#example', components: { 'parent': parentNode } }) </script> </body> </html>
组件通信
组件关系有下面三种:父-->子、子-->父、非父子。
自定义事件 当子组件需要向父组件传递数据时,就要用到自定义事件。 <!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"/> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <my-component v-on:myclick="onClick"></my-component> </div> <script> Vue.component('my-component', { template:'<div>' + '<button type="button" @click="childClick">点击我触发自定义事件</button></div>' , methods: { childClick () { this.$emit('myclick', '这是我暴露出去的数据', '这是我暴露出去的数据2') } } }) new Vue({ el: '#app', methods: { onClick () { console.log(arguments) } } }) </script> </body> </html>
$emit/$on
这种方法通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案vuex
var Event=new Vue();
Event.$emit(事件名,数据);
Event.$on(事件名,data => {});
<!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8"/> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> </head> <body> <div id="app"> <my-a></my-a> <my-b></my-b> <my-c></my-c> </div> <template id="a"> <div> <h3>A组件:{{name}}</h3> <button @click="send">将数据发送给C组件</button> </div> </template> <template id="b"> <div> <h3>B组件:{{age}}</h3> <button @click="send">将数组发送给C组件</button> </div> </template> <template id="c"> <div> <h3>C组件:{{name}},{{age}}</h3> </div> </template> <script> var Event = new Vue();//定义一个空的Vue实例 var A = { template: '#a', data() { return { name: 'beixi' } }, methods: { send() { Event.$emit('data-a', this.name); } } } var B = { template: '#b', data() { return { age: 18 } }, methods: { send() { Event.$emit('data-b', this.age); } } } var C = { template: '#c', data() { return { name: '', age: "" } }, mounted() {//在模板编译完成后执行 Event.$on('data-a',name => { this.name = name;//箭头函数内部不会产生新的this,这边如果不用=>,this指代Event }) Event.$on('data-b',age => { this.age = age; }) } } var vm = new Vue({ el: '#app', components: { 'my-a': A, 'my-b': B, 'my-c': C } }); </script> </body> </html>