通常来讲,咱们实现父子组件值的传递一般使用的是【props】和自定义事件【$emit】。父组件经过【props】将值传给子组件,子组件经过【$emit】将值传给父组件,父组件经过【$on】事件获取子组件传过来的值,若是说想要实现子组件修改父组件传过来的值,最容易的就是这种方法了:
javascript
//父组件向子组件传值
<template>
<div> <child-com :value="text"></child-com> </div> </template>
<script>
export default{
data(){
return{
text:"父组件的值",
}
}
}
</script> 复制代码
//子组件向父组件传值
<template>
<div @click="post"></div>
</template>
<script>
export default{
methods:{
post(){
this.$emit('getChildValue',"子组件的值")
}
}
}
</script>复制代码
此时父组件能够经过【$on】获取子组件的值:
html
<template>
<div> <child-com @getChildValue = "getValue"></child-com> </div> </template>
<script>
export default{
methods:{
getValue(child_value){
this.text = child_value;
}
}
}
</script>复制代码
这样,就能够实现子组件修改父组件的值。vue
不过,这种方法有一个弊端——子组件修改父组件的值须要一个传递的过程,或者说,两个值并非同步的。java
熟悉Vue1.0的朋友应该知道一个叫【.sync】的修饰符,它能够实现父子组件的双向绑定,不过在Vue2.0被移除了,直到2.3.0版本发布后才从新回归,因此一些和我同样从2.0开始使用Vue的朋友颇有可能不清楚,事实上,【.sync】能够很轻松的实现子组件同步修改父组件的值:es6
//父组件
<template>
<div>
<child-com :value.sync="text" ></child-com>
</div>
</template>
<script>
export default{
data(){
return {
text:"父组件的值",
}
},
}
</script>
==============================================================================================================
//子组件修改父组件的值
<template>
<div @click="post"></div>
</template>
<script>
export default{
methods:{
post(){
this.$emit('update:value',"子组件的值")
}
}
}
</script>复制代码
(感谢@糖小面儿 ,@asuishi ,@李佳毅 指出文中this.$emit('update:data',"子组件的值")
的错误。)vuex
咱们能够看到,对于子组件来讲,仅仅是自定义事件名作了一点改变,可是就代码底层逻辑来讲,子组件和父组件真正实现了同步的双向绑定。api
固然,正如文档所说:浏览器
.sync修饰符很方便,但也会致使问题,由于破坏了单向数据流。因为子组件改变 prop 的代码和普通的状态改动代码毫无区别,当光看子组件的代码时,你彻底不知道它什么时候悄悄地改变了父组件的状态。这在 debug 复杂结构的应用时会带来很高的维护成本。
关于自定义指令文档其实介绍的比较详细了,并且还举了一个很是详细的例子:自定义指令bash
自定义指令其实就是Vue为咱们提供直接操做dom的一些列方法,虽然大部分开发时间都会面向数据,但说不许何时确实须要操做dom自己。dom
就我而言,自定义指令最大的用处就是能够引用一些第三方的代码插入到Vue项目中,好比有一个操做dom的函数:
//固然,真实状况第三方的代码要复杂的多
function changeColor(dom){
dom.style.backgroundColor = "red";
}复制代码
咱们能够注册一个全局的指令来为须要执行changeColor方法的dom提供指令:
Vue.directives('color',{
bind:function(el){
changeColor(el)
}
})复制代码
这样,若是须要这个dom改变颜色的话,只须要这样便可:
<div v-color>改变颜色</div>复制代码
当平常开发遇到跟dom有关的问题却束手无策时,能够想一想自定义指令是否有功能能够解决为题。
前面我已经提到过了,父组件经过props能够向子组件传值,但在平常的开发中,还有一种状况很常见,就是父组件给子组件传值,这个值还要从子组件传给它的子组件,因此,咱们可能会看到这样的代码:
//父组件
<div>
<child :text="text"></child>
</div>
//子组件
<div>
<my-child :text="text"></my-child>
</div>
//子组件的子组件
<div>
<div>{{text}}</div>
</div>复制代码
这样作是很是麻烦并且不易于维护的,一般状况下,咱们可使用vuex来解决。不过,不复杂的项目中若是仅仅为这一个问题就引入vuex其实是不必的,Vue提供了【inheritAttrs】和【attrs】两个功能来解决这样的问题:
//父组件
<template>
<div>
<child :text="text" :count="count"></child>
</div>
</template>
<script>
export default{
data(){
return {
text:"父组件的值",
count:123456,
}
}
}
</script>复制代码
//子组件
<template>
<div>{{text}}</div>
</template>
<script>
export default{
props:["text"]
}
</script>复制代码
注意,这里父组件的count属性仅仅挂在子组件上,并无使用。此时咱们打开浏览器,能够看到子组件的dom上显示的展现了count="123456"。
此时,咱们能够经过设置inheritAttrs: false来取消这种默认行为:
data(){
return{
......
}
}
inheritAttrs: false,
mounted(){
console.log(this.$attrs); //{count:123456}
}复制代码
这时再看dom上就没有count属性了。而后,我还打印了this.$attrs的值,值为一个包含着count键值对的Object。
也就是说,父组件没有props的属性值会被保存在一个名为$attrs中供子组件使用,然而这并无解决开头子组件的子组件获取值的问题。别急,咱们只须要在子组件上加个东西就能够了:
<template>
<div class="child"> <my-child v-bind="$attrs"></my-child> </div> </template>复制代码
这样,子组件的子组件也能够获取这个值了。
其实这个功能有些相似于es6中的Object.assign()方法。根据必定的规则合并两个配置,具体的混入策略能够看官方文档:mixins混入策略
混入最大的用处是把一些经常使用的data或者methods等抽出来,好比在个人项目中有许多个模态框,而关闭模态框的代码逻辑是如出一辙的,为此我没有必要在多个组件中重复把关闭模态框的逻辑写入methods中,只须要在外面定义一个mixins,在须要的组件中经过:mixins: [myMin]写入便可。
var mixin = {
methods: {
close: function () {
this.showModal = false; //关闭模态框
},
}
}
var vm = new Vue(
mixins: [mixin],
.......
})
复制代码
首先感谢评论区大佬们的提醒,provide/inject
方法要比inheritAttrs/attrs
更适合用来作父组件给子组件或孙组件传值,先发一个文档的连接:provide/inject
//父组件使用provide
<template> <div class="parent"> <child-component></child-component> </div> </div></template>
<script>export default { ...... provide: { parent: "父组件的值" }, components:{ child-component, }, ......</script>
//此时能够在子组件经过这种方式获取父组件中“parent”的值:
//子组件中
export default { mounted(){ console.log(this.parent); //"父组件的值" }, inject: ['parent'],}复制代码
这块儿内容我也是刚看文档,感兴趣的朋友能够仔细看看文档,本身敲一遍看看。