一.实现子组件与父组件双向绑定的sync
修饰符
一般来说,我们实现父子组件值的传递通常使用的是props
和自定义事件$emit
。父组件通过props
将值传给子组件,子组件通过$emit
将值传给父组件,父组件通过$on
事件获取子组件传过来的值,如果说想要实现子组件修改父组件传过来的值,最容易的就是这种方法了:
//父组件向子组件传值
<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
获取子组件的值:
<template>
<div>
<child-com @getChildValue = "getValue"></child-com>
</div>
</template>
<script>
export default{
methods:{
getValue(child_value){
this.text = child_value;
}
}
}
</script>
复制代码
这样,就可以实现子组件修改父组件的值。不过,这种方法有一个弊端——子组件修改父组件的值需要一个传递的过程,或者说,两个值并不是同步的。熟悉Vue1.0的朋友应该知道一个叫.sync
的修饰符,它可以实现父子组件的双向绑定,不过在Vue2.0被移除了,直到2.3.0版本发布后才重新回归,所以一些和我一样从2.0开始使用Vue的朋友很有可能不清楚,事实上,.sync
可以很轻松的实现子组件同步修改父组件的值:
//父组件
<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>
复制代码
我们可以看到,对于子组件来说,仅仅是自定义事件名做了一点改变,但是就代码底层逻辑来说,子组件和父组件真正实现了同步的双向绑定。
当然,正如文档所说:
.sync修饰符很方便,但也会导致问题,因为破坏了单向数据流。由于子组件改变 prop 的代码和普通的状态改动代码毫无区别,当光看子组件的代码时,你完全不知道它何时悄悄地改变了父组件的状态。这在 debug 复杂结构的应用时会带来很高的维护成本
二.自定义指令directives
关于自定义指令文档其实介绍的比较详细了,而且还举了一个非常详细的例子:自定义指令自定义指令其实就是Vue为我们提供直接操作dom的一些列方法,虽然大部分开发时间都会面向数据,但说不准什么时候确实需要操作dom本身。就我而言,自定义指令最大的用处就是可以引用一些第三方的代码插入到Vue项目中,比如有一个操作dom的函数:
//当然,真实情况第三方的代码要复杂的多
function changeColor(dom){
dom.style.backgroundColor = "red";
}
复制代码
//当然,真实情况第三方的代码要复杂的多
Vue.directives('color',{
bind:function(el){
changeColor(el)
}
})
复制代码
这样,如果需要这个dom改变颜色的话,只需要这样即可:
<div v-color>改变颜色</div>
复制代码
当日常开发遇到跟dom有关的问题却一筹莫展时,可以想想自定义指令是否有功能可以解决为题。
三.inheritAttrs
和attrs
前面我已经提到过了,父组件通过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>
复制代码
这样,子组件的子组件也可以获取这个值了。
四.mixins
其实这个功能有些类似于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
首先感谢评论区大佬们的提醒,provide/inject
方法要比`inheritAttrs/attrs更适合用来做父组件给子组件或孙组件传值,先发一个文档的链接:[provide/inject][1]
//父组件使用provide
<template>
<div class="parent">
<child-component></child-component>
</div>
</template>
<script>
export default {
......
provide: {
parent: "父组件的值"
},
components:{
child-component,
},
......
</script>
//此时可以在子组件通过这种方式获取父组件中“parent”的值:
//子组件中
export default {
mounted(){
console.log(this.parent); //"父组件的值"
},
inject: ['parent'],
}
复制代码
需要注意的是provide
和inject
的绑定并不是响应的,但是如果我们provide的是一个对象,那么这个对象的属性仍是可响应的。我们可以用以下方法同样可以解决上面三中的问题
//父组件使用provide
<script>
export default {
provide () {
return {
parent: this
}
},
data () {
return {
name: ''
}
}
}
</script>
//此时可以在子组件通过这种方式获取父组件中所有parent所有响应数据:
//此时在子组件中this.parent.name是响应式的,即父组件的name修改,子组件获取的name也会做出响应的变化
//子组件中
export default {
mounted(){
console.log(this.parent.name); //"父组件某个属性的值"
},
inject: ['parent'],
}
复制代码
转载声明:
作者:陈杰夫
链接:https://juejin.im/post/5adc99f56fb9a07abd0d3ee7
来源:掘金
声明:著作权归作者所有,谢绝商业转载。如需转载请联系原作者或者按照其原文声明进行操作。
承诺:本站除原创以外所有的转载内容均是获得其作者授权或者声明可转载的。并只是将其作为学习和交流目的,杜绝一切商业盈利行为。如若侵权,请联系我们删除。
复制代码
91Code-就要编码,关注公众号获取更多内容!