这次不借助webpack实现。 其实都是比较基础的东西,但是很多小细节也蛮有意思的。
子传父
1. 通过$emit使得父组件可以通过v-on监听子组件中绑定的方法

- 子组件代码:
let ChildComponent = {
data() {
return {
childValue: ''
}
},
methods: {
passValueToFather() {
this.$emit('get-value', this.childValue);
}
},
template: `
<div>
<input v-model="childValue" placeholder="请输入子组件值">
<button @click="passValueToFather">传值给父组件</button>
</div>
`
};
- 父组件代码
let FatherComponent = {
data() {
return {
fatherValue: 'Father'
}
},
methods: {
getValueFromChild(val) {
this.fatherValue = val;
}
},
template: `
<div>
{{ fatherValue }}
<child-component @get-value="getValueFromChild"></child-component>
</div>
`,
components: {
'child-component': ChildComponent
}
};
- Vue实例初始化
var vm = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
},
components: {
'father-component': FatherComponent,
}
});
- HTML引用父组件
<div id="app">
<father-component>
</father-component>
</div>
整个过程如下 1. 修改子组件中的值 2. 子组件中button触发click事件passValueToFather() 3. 子组件中$emit,接收父组件通过v-on绑定的函数,并传入子组件中的value 4. 父组件通过v-on绑定$emit中声明的函数get-value,并绑定到父组件methods中的getValueFromChild()方法,获得子组件传来的参数value
了解这个过程后在此基础上改进就很简单了,比如子组件中无需通过button直接改变父组件的值。 直接在子组件中绑定@change事件,此实现效果为子组件中按回车或失焦父组件值改变
<div>
<input
v-model="childValue" @change="passValueToFather"
placeholder="请输入子组件值"
>
</div>
心更急一点直接通过watch监听子组件的值。
template: `
<div>
<input
v-model="childValue"
placeholder="请输入子组件值"
>
</div> `
,
watch: {
childValue() {
this.passValueToFather();
}
2. 通过this.$refs访问
更加粗暴的一种方式 这次我们通过点击父组件里的button获得子组件的值 
let FatherComponent = {
data() {
return {
fatherValue: 'Father'
}
},
methods: {
getChildValue() {
this.fatherValue = this.$refs.child.$data.childValue;
}
},
template: `
<div>
{{ fatherValue }}
<button @click="getChildValue">获得子组件的值</button>
<child-component ref="child"></child-component>
</div>
`,
components: {
'child-component': ChildComponent
}
};
也可以不借助button在mounted钩子函数里把childValue赋值给fatherValue,在mounted中是因为refs在组件渲染完毕后才可以访问。 $refs并不是响应式的,所以如果想不借助button进行实时响应式传参,可以用下一个方案。
3. 在子组件监听所传的值,通过this.$parent动态赋值父组件
在写父传子的时候突然悟的,这样就能手动实现响应式了。
let ChildComponent = {
data() {
return {
childValue: ''
}
},
template: `
<div>
<input v-model="childValue">
</div>
`,
watch: {
childValue(val) {
this.$parent.$data.fatherValue = val;
}
}
};
let FatherComponent = {
data() {
return {
fatherValue: 'Father'
}
},
template: `
<div>
{{ fatherValue }}
<child-component></child-component>
</div>
`,
components: {
'child-component': ChildComponent
}
};
但所有这样通过监听再通过\$refs或\$parent动态赋值的方法都不会同步第一次的数据,如果想让父子组件初始值就同步的话,还需要在mounted初次渲染的时候赋一次值。 给watch加上immediate也是不行的,因为那时候组件还没渲染完,无法访问\$refs和\$parent。
父传子
遵循单向数据流的父传子相较而言就很友好了 直接在子组件定义props就可以接收父组件传来的值 
1. 通过在子组件设置props传参
在父组件中v-bind绑定子组件中props对应的变量就可以实现响应式绑定,实时同步更新
let ChildComponent = {
template: `
<div>
{{ passedValue }}
</div>
`,
props: {
passedValue: String
}
}
let FatherComponent = {
data() {
return {
fatherValue: 'Father'
}
},
template: `
<div>
<input v-model="fatherValue">
<child-component :passedValue="fatherValue"></child-component>
</div>
`,
components: {
'child-component': ChildComponent
}
};
2. 通过$children或$refs实时改变子组件的值
- 通过$children
因为$children是直接获得所有子组件数组,感觉通过这种方式不是很稳定
let ChildComponent = {
data() {
return {
childValue: ''
}
},
template: `
<div>
{{ childValue }}
</div>
`,
}
let FatherComponent = {
data() {
return {
fatherValue: 'Father'
}
},
template: `
<div>
<input v-model="fatherValue">
<child-component></child-component>
</div>
`,
components: {
'child-component': ChildComponent
},
watch: {
fatherValue(val) {
this.$children[0].$data.childValue = val;
}
}
};
我天,我写到这才明白之前我思路一直错了。我总以为父传子是在子组件里通过$parent获取父亲的值,这样是无法实现响应式的。 而实际上父传子应该在父组件里监听所传的值,然后动态赋值给子组件。 痛哭流涕。顺手把上面父传子也给改了。
- 通过$refs
子组件和上面通过$children实现的一样什么也不用干 也是效果很好的实时响应更新!
let FatherComponent = {
data() {
return {
fatherValue: 'Father'
}
},
template: `
<div>
<input v-model="fatherValue">
<child-component ref="child"></child-component>
</div>
`,
components: {
'child-component': ChildComponent
},
watch: {
fatherValue(val) {
this.$refs.child.$data.childValue = val;
}
}
};
下次补充事件总线哈!
|