vue组件传值

父组件向子组件传值,下发指令

  • 使用情景:需要复用的,我们都可以做成一个组件。比如有一个弹出框,很多页面都会用到,此时我们可以把这个弹出框做成一个组件,其他页面需要用时,直接调用即可。

  • 关键字:父组件向子组件传值主要使用prop。

  • 实现原理:子组件中使用prop声明变量名,通过prop声明的变量名,在父组件中就可以调用,并且给这些变量赋值。

实例:

第一步:我们来创建一个组件。

在components文件夹里面创建一个名为confirm.vue的文件。
在这里插入图片描述
此时,弹出框的组件已经创建完成,“标题,内容,按钮”我们把它写成动态变量,方便不同的页面调用组件传递不同的值,显示不同的内容。

第二部:现在有一个页面user.vue需要调用上面创建的组件confirm.vue。

由于有很多页面都会调用上面这个组件,所以我们可以进行全局注册。
(1)在main.js中进行全局注册(注意区分大小写):
在这里插入图片描述
(2)在user.vue中进行调用:

此时问题来了,我们要怎么给组件confirm.vue传递“标题,内容,按钮”动态数据呢?
解决方法:通过 Prop 向子组件传递数据

Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property。
注:父组件通过 props 向下传递数据给子组件;子组件通过 events 给父组件发送消息。

那么我们就得在confirm.vue中使用props把这些自定义的属性声明一下,如下。
在这里插入图片描述
然后在user.vue中调用如下:
在这里插入图片描述
最终效果如下:
在这里插入图片描述



prop使用详解

(1)命名规则

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

比如我们在子组件中定义了驼峰写法如下:

<h3>{{ postTitle }}</h3>
 props: ['postTitle']

在父组件中使用时,驼峰写法必须改为短横线写法,因为html对大小写不明感,如果把大写字母改成小写并在前面加一个短斜杠,vue是可以识别到的,写法如下:

<blog-post post-title="hello"></blog-post>

(2)Prop 类型

我们通常以字符串数组形式列出的 prop,如下:

props: ['title', 'likes', 'isPublished', 'commentIds', 'author']

但是,如果通常你希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop,这些 property 的名称和值分别是 prop 各自的名称和类型:

props: {
  title: String,
  likes: Number,
  isPublished: Boolean,
  commentIds: Array,
  author: Object,
  callback: Function,
  contactsPromise: Promise // or any other constructor
}

这不仅为你的组件提供了文档,还会在它们遇到错误的类型时从浏览器的 JavaScript 控制台提示用户。你会在这个页面接下来的部分看到类型检查和其它 prop 验证。

我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。

prop类型验证方式:
为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:

props: {
   // 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
    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
      }
    }
}

type类型检查

type 可以是下列原生构造函数中的一个:

  • String
  • Number
  • Boolean
  • Array
  • Object
  • Date
  • Function
  • Symbol
    额外的,type 还可以是一个自定义的构造函数,并且通过 instanceof 来进行检查确认。例如,给定下列现成的构造函数:
function Person (firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}

使用的时候如下,来验证 author prop 的值是否是通过 new Person 创建的:

  props: {
    author: Person
  }

非 Prop 的 Attribute(子组件没有定义在prop中的属性)

一个非 prop 的 attribute 是指传向一个组件,但是该组件并没有相应 prop 定义的 attribute。
举个例子:
现在有一个子组件,没有定义任何prop:

<template>
    <button>按钮</button>
</template>

先有一个父组件,调用上面的子组件,并且给子组件加了"aa,class"属性:

 <my-button aa="haha" class="btnstyle"></my-button>

此时我们预览看一下代码:
在这里插入图片描述
综上所述:父组件给子组件定义了非的prop属性,新属性会被自动添加到子组件的根元素上面。

合并或替换已有的属性:
对于绝大多数 attribute 来说,从外部提供给组件的值会替换掉组件内部设置好的值。

注:只有class和style是可以被合并的,如下例子:
子组件中已有一个class属性:

<template>
    <button class="mybtn1">按钮</button>
</template>

父组件中调用子组件,然后又给它定义了一个class属性:

<my-button class="mybtn2"></my-button>

此时,父组件中定义的class会和子组件中已有的class同时存在,如下:
在这里插入图片描述
注意:class和style都会被合并。
其他的会被替换,如下父组件会替换子组件中的属性:

子组件:

<template>
    <button data="bb">按钮</button>
</template>

父组件:

<my-button data="aa"></my-button>

显示结果如下,button只显示了父组件中赋值的属性:
在这里插入图片描述
如下例子:禁用 Attribute 继承
如果你不希望组件的根元素继承 attribute,你可以在组件的选项中设置 inheritAttrs: false。

注意 inheritAttrs: false 选项不会影响 style 和 class 的绑定。

子组件:

<template>
    <button data="bb">按钮</button>
</template>
<script>
export default {
    inheritAttrs:false
}
</script>

父组件:

<my-button data="aa"></my-button>

结果如下,父组件无法覆盖子组件的属性。
在这里插入图片描述

传递静态或动态 Prop

(1)传入一个静态的值

<blog-post title="这是一个静态标题"></blog-post>

(2)传入一个动态的值,需要使用v-bind动态赋值。
动态赋予一个变量的值:

<blog-post v-bind:title="mytitle"></blog-post>

动态赋予一个复杂的表达式:

<blog-post v-bind:title="mytitle + ' by ' + myname"></blog-post>

注1:在上述两个示例中,我们传入的值都是字符串类型的,但实际上任何类型的值都可以传给一个 prop。

一、传入一个数字:

如果我们要传入一个静态数字,也需要添加v-bind,因为数组要看作是一个表达式而不是字符串。使用如下:

<blog-post v-bind:mysum="42"></blog-post>

二、传入一个布尔值:

(1)prop 没有值的情况在内,都意味着 true,下面例子,isMyshow没有赋值,默认是true

<blog-post isMyshow></blog-post>

(2)如果要给赋值为false,我们需要使用v-bind

<blog-post v-bind:isMyshow="false"></blog-post>

三、传入一个数组:

即使传入的是一个静态数组,我们也需要添加v-bind

<blog-post v-bind:myArray="[234, 266, 273]"></blog-post>

四、传入一个对象:

即使对象是静态的,我们也需要使用v-bind,如下例子:

<blog-post
  v-bind:author="{
    name: 'Veronica',
    company: 'Veridian Dynamics'
  }"
></blog-post>

五、传入一个对象的所有属性 property

如果你想要将一个对象的所有 property 都作为 prop 传入,你可以使用不带参数的 v-bind (取代 v-bind:prop-name)。例如,对于一个给定的对象 post:
如下有一个对象:

post: {
  id: 1,
  title: 'My Journey with Vue'
}

使用方法:

<blog-post v-bind="post"></blog-post>

上面方法等价于:

<blog-post
  v-bind:id="post.id"
  v-bind:title="post.title"
></blog-post>

单向数据流

所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外变更父级组件的状态,从而导致你的应用的数据流向难以理解。

额外的,每次父级组件发生变更时,子组件中所有的 prop 都将会刷新为最新的值。这意味着你不应该在一个子组件内部改变 prop。如果你这样做了,Vue 会在浏览器的控制台中发出警告。



子组件

祖孙组件传值

目的:1、父子组件之间可以相互修改数据。

自定义组件v-model
一个组件上的v-model默认会利用名为value的prop和名为input的事件,但是像单选框,复选框等类型的输入控件可能会将value特性用于不同的目的。

v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后做了两个操作:
1.v-bind绑定一个value属性
2.v-on指令给当前元素绑定input事件
例如,在原生表单元素中:

相当于:

v-model用于自定义组件中,应该使用以下操作:
1.接收一个value prop。
2.触发input事件,并传入新值。
例如,在自定义组件中:

相当于

注:这个时候,inputValue接受的值就是input事件的回调函数的第一个参数,所以在自定义组件中,要实现数据绑定,还需要$emit去触发input的事件。
this. $emit(‘input’,value)
v-model主要针对表单实现数据双向绑定,如果要对组件实现双向绑定,可以想象把子组件变成表单,所以此时使用input关键字。
v-model是vue2中唯一支持双向绑定的指令,用于表单控件绑定,v-model其实是个语法糖。
如:

<input v-model="something">
//这不过是一下示例的语法糖:
<input v-bind:value="something" v-on:input="something=$event.target.value">
//简写
<input :value="something" @input="something=$event.target.value">

也就是说,你只需要在组件中声明一个name为value的props,并且通过触发input事件传入一个值,就能修改这个value.
例如:
在这里插入图片描述
父组件代码:

<template>
  <div class="mydiv">
    父组件中的title显示内容:{{title}}
    <BR v-model="title"></BR><!--在这里可以把当前的组件当做一个input控件更容易理解-->
  </div>
</template>
<script>
  import BR from '@/components/B.vue';
  export default {
    components: {
      BR
    },
    data() {
      return {
        title: ''
      }
    },
    methods: {
  
    }
  }
</script>

子组件代码:

<template>
  <div>
    子组件中的title显示内容:{{value}}<!--必须使用value关键字-->
    <button @click="handleInput">点击</button>
  </div>
</template>
<script>
  export default {
    props: ['value'],//必须使用value关键字
    data() {
      return {}
    },
    methods: {
      handleInput() {
        this.$emit('input', '111111');//必须使用input关键字,触发input事件
      }
    }
  }
</script>

实例3,当子组件值改变时,父组件的值同时改变,实现双向绑定,
在这里插入图片描述
父组件内容:

<template>
  <div class="mydiv">
    父组件中的title显示内容:{{title}}
    <BR v-model="title"></BR>
  </div>
</template>
<script>
  import BR from '@/components/B.vue';
  export default {
    components: {
      BR
    },
    data() {
      return {
        title: 0
      }
    },
    methods: {
  
    }
  }
</script>

子组件内容:

<template>
  <div>
    子组件中的title显示内容:{{value}}
    <button @click="handleInput">点击</button>
  </div>
</template>
<script>
  export default {
    props: ['value'],
    data() {
      return {
        i: 0
      }
    },
    methods: {
      handleInput() {
        this.i += 1;
        this.$emit('input', this.i)
      }
    }
  }
</script>

使用.sync及update实现父子双向绑定

例如,父子键中有一个按钮可以改变父组件中的值同时也可以改变子组件的值,子组件中有一个按钮既可以改变子组件中的值也可以改变父组件中的值,实现子父组件双向绑定:
在这里插入图片描述
父组件代码:

<template>
  <div>
     外面的值:{{parentsTest}}
    <button @click="fn">外面改变里面</button>
    <B :childTest.sync="parentsTest"></B><!--此处使用了.sync修饰符-->
  </div>
</template>
<script>
  import B from '@/components/B.vue';//导入子组件
  export default {
    components: { B },//注册子组件
    data() {
      return {
        parentsTest: 0
      }
    },
    methods: {
      fn() {
        this.parentsTest += 1;
      }
    }
  }
</script>

子组件代码:

<template>
  <div>
    里面的值:{{childTest}}
    <button @click="fn2">里面改变外面</button>
  </div>
</template>
<script>
  export default {
    props: {
      childTest: 0
    },
    data() {
      return {
      }
    },
    methods: {
      fn2() {
      //这是关键update:childTest自定义事件会告诉父组件将父组件的parentsTest的值改为this.childTest+1,并传回给子组件。
        this.$emit('update:childTest', this.childTest + 1);
      }
    }
  }
</script>

.sync修饰符

该修饰符被扩展为一个自动更新父组件属性的v-on监听器。
如下代码:

<template>
  <div>
    <B :show.sync="valueP"></B>
    <button @click="changeVal">点击切换</button>
  </div>
</template>
<script>
  import B from '@/components/B.vue';
  export default {
    components: {
      B
    },
    data() {
      return {
        valueP: true
      }
    },
    methods: {
      changeVal() {
        this.valueP = !this.valueP;
      }
    }
  }
</script>

子组件代码:

<template>
  <div v-if="show"><!--根据show是true或false来决定是否显示当前内容-->
    <p>默认初始值是{{show}},所以是显示的</p>
    <button @click.stop="closeDiv">关闭</button>
  </div>
</template>
<script>
  export default {
    props: ['show'],
    data() {
      return {}
    },
    methods: {
      closeDiv() {
        this.$emit('update:show', false);//更新show的值及父组件valueP的值,并传值为false
      }
    }
  }
</script>

总结:
vue修饰符.sync的功能是:当一个子组件改变了一个prop的值时,这个变化也会同步到父组件中所绑定。


1.父组件可以调用子组件通过props导出的数据。 2.子组件可以使用$emit触发父组件的自定义事件。

$emit语法:
vm. $emit(eventName,[…args]);
参数说明:第一个参数eventName,表示自定义事件名称。
第二个参数[…args],表示要传给父组件的参数,附加参数都会传给监听器回调。

不带参数$emit用法:
子组件:

<template>
    <div>
       <span @click="myCli">点击</span>
    </div>
</template>
<script>
    export default {
        data() {
            return {};
        },
        methods: {
           myCli(){
               this.$emit('clickWo');//同个$emit自定义一个可以传给父组件的方法
           }
        }
    };
</script>

父组件:

<template>
    <div>
        <!-- 通过$emit传过来的方法clickWO来触发父组件中的事件 -->
        <myB @clickWo='hoho'></myB>
    </div>
</template>
<script>
    import myB from "./myB"; //导入子组件
    export default {
        //注册子组件
        components: {
            myB
        },
        data() {
            return {
            };
        },
        methods: {
           hoho(){
               alert("子组件点击了我")
           }
        }
    };
</script>

带参数的$emit:
在子组件中:

<template>
    <div>
       <span @click="giveMsg">点击</span>
    </div>
</template>
<script>
    export default {
      
        data() {
            return {
                // 定义一个数组
                postMsg:['Yes','No','Maybe']
            };
        },
        methods: {
           giveMsg(){
            //    通过Math.random()生成一个随机数,乘以当前数组postMsg的长度,然后通过Math.floor()向下四舍五入取整
               var r=Math.floor(Math.random()*this.postMsg.length);
            //    通过$emit自定义一个事件sendClick,取数组postMsg随机一个下标
               this.$emit('sendClick',this.postMsg[r]);
           }
        }
    };
</script>

在父组件中:

<template>
    <div>
        <!-- 把$emit自定义的事件名sendClick绑定到子组件上,给定一个方法showMsg -->
        <myB @sendClick='showMsg'></myB>
    </div>
</template>
<script>
    import myB from "./myB"; //导入子组件
    export default {
        //注册子组件
        components: {
            myB
        },
        data() {
            return {
            };
        },
        methods: {
        //    注:如果$emit传过来的事件有参数,在父组件中也必须有参数 
           showMsg(a){
               alert(a)
           }
        }
    };
</script>

示例2:
在子组件中

<template>
    <div>
        从父组件取数据:{{sendData}}
        <!-- 通过@click设置点击事件,点击事件中设置了一个对象data,设置了$emit自定义事件,点击触发父组件信息 -->
        <span @click="childSendData('北京')">点击</span>
    </div>
</template>
<script>
    export default {
        //通过props导出sendData
        props: ["sendData"],
        data() {
            return {};
        },
        methods: {
            // 定义一个方法,
            childSendData(val) {
                // 定义一个对象
                let data = {
                    cityname: val
                };
                // 使用$emit定义一个自定义事件,然后参数是变量data对象
                this.$emit("showCityName", data);
            }
        }
    };
</script>

在父组件中

<template>
    <div>
        <!-- 通过@把子组件中使用$emit导出的事件绑定在子组件上,给子组件赋值一个事件updateData,senData是子组件的变量来获取父组件的值 -->
        <myB @showCityName="updateData" :sendData="toCity"></myB>
    </div>
</template>
<script>
    import myB from "./myB"; //导入子组件
    export default {
        //注册子组件
        components: {
            myB
        },
        data() {
            return {
                toCity: '上海'
            };
        },
        methods: {
            // 父组件中定义了一个updateData方法
            updateData(data) {
                this.toCity = data.cityname;
            }
        }
    };
</script>

我们在vue的父子组件传值的时候,我们先在需要的子组件上用props注册一些属性,然后父组件调用的时候当属性来传值。 如果我们给child传props没有注册的属性,我们就要用$attrs来取了。

现有父组件A和子组件B:
组件A的内容如下:

<template>
    <div>我是父组件
        <B :w1="hello" :w2="world" :w3="lisa"></B>
    </div>
</template>
<script>
import B from './myB'
export default {
    components:{B},
    data(){
        return{
            hello:'hello',
            world:"world",
            lisa:"myname"
        }
    }
}
</script>

组件B的内容如下:

<template>
    <div>
        我是子组件{{w1}}
    </div>
</template>
<script>
export default {
    props:["w1"],
    inheritAttrs:false,
    data(){
        return{

        }
    },
    mounted(){
        console.log(this.$attrs)
    }
}
</script>

组件B只导出了w1,在组件A中调用时,多了几个属性w2,w3,在组件B中可以使用console.log(this.$attrs)查看非prop属性,结果为一个对象{w2: “world”, w3: “myname”}
但是在控制台看到B组件的根元素div上出现了这两个属性,显示结果为:
<div w2=“world” w3=“myname”>
如果想要去除这两个属性,可以在子组件中添加inheritAttrs:false
格式如下:

export default {
    props:["w1"],
    inheritAttrs:false,
    data(){
			return{}
		}
    }

inheritAttrs

inheritAttrs:false,如果你不希望组件的根元素继承特性,你可以在组件的选项中设置,这尤其适合配合实例的 $ attrs 属性使用,该属性包含了传递给一个组件的特性名和特性值。
1.inheritAttrs默认为true,即允许继承的意思,如果设为false,即禁止继承。
2.$attrs为组件标签内没有在组件内用props声明的属性(除了style和class)

小结:
$ attrs
$ attrs存储非prop特性,$attrs继承所有的父组件属性,但是除了prop传递的属性,style和class
inheritAttrs
inheritAttrs控制vue对非prop特性的默认行为。默认为true,继承所有的父组件属性(除props的特定绑定)作为普通的HTML特性应用在子组件的根元素上,如果你不希望组件的根元素继续特性设置inheritAttrs:false,但是class属性会继承。

多级组件传递数据

现有A,B,C三个组件依次嵌套,示例:
在这里插入图片描述

A到B可以通过props的方式向子组件传递值,如果A组件与C组件之间通过怎么办呢?
A和C之间属于跨多级的组件嵌套关系,要解决这一问题可以使用 $ attrs解决。

在组件C中,代码如下:

<template>
<!-- 有两个值,c1是去A组件中获取值,bb是去B组件中获取值 -->
  <div>我是组件C,我要说"{{c1}}",我给B发消息{{bb}}</div>
</template>
<script>
export default {
  // 通过props到处变量bb,c1
  props: ["bb", "c1"],
  data() {
    return {};
  }
};
</script>

在组件B中代码如下:

<template>
  <div>
    我是B组件,我要说“{{b1}}”
    <!-- 给组件C的bb赋值 -->
    <C :bb="bb"></C>
  </div>
</template>
<script>
// 导入组件C
import C from "./C";
export default {
  inheritAttrs: false,//禁止继承父组件的非prop属性
  props: ["b1"],//导出变量b1
  components: { C },//注册组件C
  data() {
    return {
      bb: "你好"
    };
  }
};
</script>

在组件A代码中:

<template>
  <div>
    我是组件A的内容
    <!-- 调用组件B 使用$attrs绑定非prop属性,并给属性赋值-->
    <B :c1="c1" :b1="b1" v-bind="$attrs"></B>
  </div>
</template>
<script>
import B from "./B";//导入组件B
export default {
  components: { B },//注册组件B
  data() {
    return {
      c1: "我是c",
      b1: "我是b"
    };
  }
};
</script>

1.父组件调用子组件

子组件children.vue代码如下:

 <template>
   <div>我是子组件</div>
</template>

父组件parent.vue代码如下:

<template>
  <div>
     <myChild></myChild>
  </div>
</template>
<script>
  import myChild from './child'; //第一步导入子组件
  export default {
            name: 'parent',
            components: {
                myChild
            }, //第二步注册子组件
            data() {
                return {
        
                }
            }
        }
</script>

此时在子组件中的内容会显示在组件中,总结:父组件调用子组件
(1)在父组件中通过import导入子组件。
(2)在父组件中使用components:{}注册子组件。

2.父组件向子组件传值

在子组件中,写入一个动态数据message,然后通过props把数据导出去,为外部父组件调用提供一个接口:

子组件代码如下:

    <template>
        <div>
        我是子组件,显示来自父组件的消息{{message}}
        </div>
    </template>
    <script>
        export default {
            props:["message"],
            data() {
                return {
        
                }
            }
        }
    </script>

在父组件中给message赋值:

      <template>
            <div>
                <myChild :message="mymsg"></myChild>
            </div>
        </template>
        <script>
            import myChild from './child';
            export default {
                name: 'parent',
                components: {
                    myChild
                },
                data() {
                    return {
                        mymsg: '向子组件发送消息:Happy'
                    }
                }
            }
        </script>

在父组件中,在子组件上为:message赋值。
总结,父组件给子组件传值:子组件中要通过props把变量导出来,然后在父组件中使用该变量,为该变量赋值。
注:如果父组件传值为一个静态的值,也需要使用v-bind来告诉vue,v-bind简写为":"

例如:
<myChild v-bind:message="123"></myChild>
简写为:
<myChild :message="123"></myChild>

3.为子组件重命名

在父组件中为子组件重命名,可以在components中为子组件重命名,格式如下:

    <template>
        <div>
            <my-child-newname></my-child-newname>
        </div>
    </template>
    <script>
        import myChild from './child';
        export default {
            name: 'parent',
            components: {
                'my-child-newname':myChild
            },
            data() {
                return {
                }
            }
        }
    </script>

4.props用法

props通常是以字符串数组的形式列出,例如:

    props:["name","age","color","job","adress"],

如果希望每个字符串都有指定值类型,可以为它定义属性:

    props:{
                name:String,
                age:Number,
                color:Boolean,
                job:Array,
                adress:Object
            },

当父组件赋值类型不对时,浏览器控制台会提示错误信息。

5.让一个对象的属性作为prop传入

传入一个对象的所有属性,如果想让一个对象的属性作为prop传入:
子组件代码如下:

    <template>
      <div>我是子组件,显示来自父组件的消息{{id}}{{title}}</div>
    </template>
    <script>
    export default {
      props: ["id","title"],
      data() {
        return {};
      }
    };
    </script>

父组件中定义一个对象post,它有两个属性,id和title,父组件代码如下:

    <template>
      <div>
        <blog-post v-bind="post"></blog-post>
      </div>
    </template>
    <script>
    import myChild from "./child";
    export default {
      components: {
        "blog-post": myChild
      },
      data() {
        return {
          post: {
            id: 1,
            title: "My Journey with Vue"
          }
        };
      }
    };
    </script>

注释:

     <blog-post v-bind="post"></blog-post>
 等价于
     <blog-post v-bind:id="post.id" v-bind:title="post.title"></blog-post>

6.传递静态或动态prop

传入一个静态的值:

<blog-post title="我是标题"></blog-post>

动态赋值:

<!-- 动态赋予一个变量的值 -->
<blog-post :childtitle="post.title"></blog-post>
<!-- 动态赋予一个复杂的表达式的值 -->
<blog-post :childtitle="post.title+'hello'+post.id"></blog-post>

任何类型的值都可以传给prop,

	<!-- 传入一个数字 -->
    <blog-post :childtitle1="123"></blog-post>
    <!-- 传入一个布尔值 -->
    <blog-post :childtitle2="false"></blog-post>
    <!-- 传入一个数组 -->
    <blog-post :childtitle3="[1,2,3,4,5]"></blog-post>
    <!-- 传入一个对象 -->
    <blog-post :childtitle4="{name:'lisa',age:12}"></blog-post>

7.单向数据流

所有的prop都使得其父子prop之间形成了一个单向下绑定:父级prop的更新会向下流动到子组件中,但是反过来则不行,这样会防止从子组件意外改变父组件的状态。
每次父级组件发生更新时,子组件中所有的prop都将会刷新为最新的值,这意味着你不应该在一个子组件内部改变prop,如果这样会在浏览器控制台报错。
这里有两中常见的试图改变一个prop的情形:
(1)这个prop用来传递一个初始值,这个子组件接下来希望将其作为一个本地的prop数据来使用,在这种情况下,最好定义一个本地的data属性并将这个prop用作其初始值。
在子组件中,有两个变量,childtitle和mycount,把childtitle导出从父组件获取值,然后传给mycount:

<template>
  <div>
    title数据:{{childtitle}}
    <br>
    count数据:{{mycount}}
  </div>
</template>
<script>
export default {
  props: ["childtitle"],
  data() {
    return {
      mycount: this.childtitle
    };
  }
};
</script>

父级组件代码中,给childtitle赋值,此时,当点击按钮时,childtitle的值会变化:

<template>
  <div>
    <span @click="myClick">点击</span>
    <blog-post :childtitle="parcount"></blog-post>
  </div>
</template>
<script>
import myChild from "./child";
export default {
  components: {
    "blog-post": myChild
  },
  data() {
    return {
      parcount: 0
    };
  },
  methods: {
    myClick() {
      this.parcount++;
    }
  }
};
</script>

以上会出现一个问题,当点击按钮时childtitle的值会跟着变化,但是子组件中mycount的值不会变化,这时mycoun需要使用计算属性computed才能使值跟着变化,子组件中的代码更改如下:

<template>
  <div>
    title数据:{{childtitle}}
    <br>
    count数据:{{mycount}}
  </div>
</template>
<script>
export default {
  props: ["childtitle"],
  data() {
    return {};
  },
  computed: {
    mycount: function() {
      return this.childtitle;
    }
  }
};
</script>

8.prop验证

我们可以为组件的prop指定验证要求,例如你知道的这些类型,如果有一个需求没有被满足,则Vue会在浏览器控制台发出警告。
为了定制prop的验证方式,你可以为props中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:

props: {
    //   指定基础类型检查
    proA: Number,
    //   可以设置多个类型,该值符合其中一个即可
    proB: [String, Number],
    //    如果该变量必须存在,必填,可以设置required为true,可以通过type设置该值得类型
    proC: {
      type: Number,
      required: true
    },
    // 可以使用default设置默认的值
    proD: {
      type: Number,
      default: 100
    },
    // 可以设置带有默认值得对象
    proE: {
      type: Object,
      //注:对象或数组默认值必须从一个工厂函数获取
      default: function() {
        return {
          meseage: "hello"
        };
      }
    },
    // 可以自定义验证函数
    proF: {
      validator: function(value) {
        //这个值必须匹配下列字符串中的一个
        return ["success", "warning", "danger"].indexOf(value) !== -1;
      }
    }
  },

当父级组件传过来的值不符合条件,验证失败时,vue控制台会发生警告。
注:prop会在一个组件实例创建之前进行验证,所以实例的属性(如data,computed)在default或validator函数中是不可用的。

type类型包括:
String
Number
Boolean
Array
Object
Date
Function
Symbol
注:type还可以是一个自定义的构造函数,并且通过instanceof来进行检查确认。
例如如下构造函数:

function Person (firstName, lastName) {
  this.firstName = firstName
  this.lastName = lastName
}

可以使用以下方式来验证prop的值是否通过new Person创建的。

Vue.component('blog-post', {
  props: {
    author: Person
  }
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue组件传值Vue.js中非常重要的一个概念,它涉及到父子组件之间的数据传递和通信。下面是一些常见的Vue组件传值面试题及其答案: 1. 请介绍Vue组件之间的父子组件传值方式。 答:Vue组件之间的父子组件传值方式有props和$emit。通过props可以将数据从父组件传递给子组件,子组件通过props接收数据。而$emit则是在子组件中触发一个自定义事件,并通过事件参数将数据传递给父组件。 2. 请介绍Vue组件之间的兄弟组件传值方式。 答:Vue组件之间的兄弟组件传值方式可以通过共享状态管理工具(如Vuex)或者事件总线来实现。使用共享状态管理工具可以在全局定义一个状态,兄弟组件通过读取和修改该状态来进行数据传递。而事件总线则是在Vue实例上定义一个事件中心,兄弟组件通过$emit和$on来进行事件的发布和订阅,从而实现数据传递。 3. 请介绍Vue组件之间的跨级组件传值方式。 答:Vue组件之间的跨级组件传值方式可以通过provide和inject来实现。父级组件通过provide提供数据,然后子孙级组件通过inject来注入数据。这样就可以实现跨级组件之间的数据传递。 4. 请介绍Vue组件之间的非父子组件传值方式。 答:Vue组件之间的非父子组件传值方式可以通过事件总线、Vuex或者localStorage等方式来实现。事件总线和Vuex的方式在前面已经介绍过了,而localStorage则是通过将数据存储在浏览器的本地存储中,然后在其他组件中读取该数据来实现非父子组件之间的数据传递。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值