[TOC] >[success] # 父传子 ~~~ 1.组件实例的作用域是孤立的,不能在子组件直接用父组件的数据,下面图做了详 细解释 2.想将父作用域的值传入,子组件需要在子组件定义'props',用来接受父组件传来的 值。 ~~~ * 父作用域说明 ![](https://box.kancloud.cn/7ec9f131854b3f0f744ff65e9070fbc0_710x416.png) * 父子作用域说明 ![](https://box.kancloud.cn/871ae7d314809673e0726a1af8370a0d_556x508.png) >[info] ## 父传子详解 ~~~ 1.子组件中,默认无法访问到 父组件中的 data 上的数据 和 methods 中的方法 2.组件中的 所有 props 中的数据,都是通过 父组件传递给子组件的 3.props 中的数据,都是只读的,无法重新赋值 4.props 中的变量名不应该和子组件中data名相同 ~~~ >[danger] ##### props -- 属性校验 ~~~ 1.props不仅可以向下面案例中用数组的形式,也可以用对象来做校验类型 2.官网的案例: Vue.component('my-component', { props: { // 基础的类型检查 (`null` 匹配任何类型) propA: Number, // 多个可能的类型 propB: [String, Number], // 必填的字符串 propC: { type: String, required: true }, // 带有默认值的数字 propD: { type: Number, default: 100 }, // 带有默认值的对象 propE: { type: Object, // 对象或数组默认值必须从一个工厂函数获取 default: function () { return { message: 'hello' } } }, // 自定义验证函数 propF: { validator: function (value) { // 这个值必须匹配下列字符串中的一个 return ['success', 'warning', 'danger'].indexOf(value) !== -1 } } } }) ~~~ >[danger] ##### 案例 ~~~ 1.下面案例就可以分析一下首先原本父组件作用域的内容是无法传递给子组件的, 但是在子组件定义了一个'props' 用来当做传递的桥梁 2.我们可以吧 parent-title="title"当做赋值运算,其中parent-title相当于子组件的定 义变量,title相当于接受父组件数据,给子组件的parent-title赋值 3.但是注意props 中的数据,都是只读的,无法重新赋值 4.在组件接受时候使用v-bind,在使用的时候可以用大胡子语法,或者v-bind绑定 ~~~ ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script> </head> <body> <div id="app"> <!--使用组件,title 是父组件的作用域值,parent-title是子组件props定义接受值--> <my-Com2 :parent-title="title"></my-Com2> </div> <script> let myCom2 = { template:'<h4>{{parentTitle}}</h4>', props:['parentTitle'], data(){ return { // title:'测试' } } }; var vm = new Vue({ el: '#app', data:{ title:"父组件", }, components:{ // 在外部声明变量,使用代码简洁 myCom2, } }); </script> </body> </html> ~~~ >[info] ## 抛弃思维定式组件也可以循环 ~~~ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script> </head> <body> <div id="app"> <!--使用组件--> <ul > <my-Com v-for="item in items" :item ='item'></my-Com> </ul> </div> <script> // 创建全局组件 var com = Vue.extend({ template:'<li>{{item}}</li>', props: ['item'] }); // 注册全局组件 Vue.component('myCom',com); var vm = new Vue({ el: '#app', data(){ return{ items:['123','456'] } } }); </script> </body> </html> ~~~ >[danger] ##### $emit -- 也能父传子 ~~~ 1.'$emit' 的返回值是当前 'this' 2.可以在不使用'prop' 父传子,仅通过在'$emit' 增加一个回调函数,也可以实现 从父组件传值给子组件 3.下面案例如果你是一个已经使用vue 一段时间的人可以直接看,如果不是请先看完子传父,再来 看这个父传子的内容 ~~~ * 子组件的写法 ~~~ <template> <div> name: {{ name || "--" }} <input :value="name" @change="handleChange" /> </div> </template> <script> export default { name: "EventDemo", props: { name: String }, methods: { handleChange(e) { // 这里用了回调 const res = this.$emit("change", e.target.value, val => { // 打印结果hello console.log(val); }); // 打印结果为true console.log(res, res === this); }, } }; </script> ~~~ * 父组件写法 ~~~ <template> <div> <Event :name="name" @change="handleEventChange" /> </div> </template> <script> import Event from "./Event"; import Proxy from "./Proxy.vue"; import Slot from "./Slot"; export default { components: { Event, SlotDemo: Slot, Proxy }, data: () => { return { name: "", }; }, methods: { // 使用回调将值传递给子组件 handleEventChange(val, callback) { this.name = val; callback("hello"); } } }; </script> ~~~ * 直接复制粘贴运行版本 ~~~html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.22/dist/vue.js"></script> </head> <body> <div id="app"> <h1>{{parentTitle}}</h1> <!-- 这是一个语法糖 --> <com1 @fun="appectChildern"/> </div> <!-- 组件一号 --> <template id="com1"> <div> <h1 @click="changeTitle">{{msg}}</h1> </div> </template> <script> // 创建组件一号 const com1 = { template:'#com1', data () { return { msg:'我是组件一号' } }, methods: { changeTitle(){ this.msg = '我真的是一个组件' // 不同过Prop的父传子写法 this.$emit('fun',val=>{ console.log(val) }) } }, // 父传子过来的内容 props:{ appectParent:{ type:String, default:'默认值' }, } } // 创建vue const vm = new Vue({ el:'#app', data:{ parentTitle:'我是父组件标题', }, methods: { appectChildern(params){ params(this.parentTitle) } }, // 自定义vue组件 components: { com1 } }) </script> </body> </html> ~~~ >[danger] ##### 有时候只想改变父组件传入的值,但不影响父组件 ~~~ 1.在子组件的 data 中拷贝一份 prop,data 是可以修改的,但 prop 不能 ~~~ ~~~ export default { props: { value: String }, data () { return { currentValue: this.value } } } ~~~ >[info] ## 结论 ~~~ 1.父传子 有两种一种是同props 直接传递,一种是通过事件 利用this.$emit 间接触发 ~~~ >[info] ## 一定要读的官方Prop系列帮助很大 [https://cn.vuejs.org/v2/guide/components-props.html](https://cn.vuejs.org/v2/guide/components-props.html)