组件通信方式(一)

一、event深入

1、事件注意事项

事件:1、系统事件:点击、双击、鼠标系列等等

           2、自定义事件   

事件源(事件给谁绑定的)、事件类型(单击还是双击还是自定义等)、事件回调

1)原生DOM ----- (eg: button)可以绑定系统事件(单击、双击等等)

2)组件标签 -------  event1可以绑定系统事件(但是不起作用,因为属于自定义事件)

                     -------  在原生事件后加“.native”,可以把自定义事件变为原生DOM事件

注意:给原生DOM绑定自定义事件是没有任何意义的,因为没有办法触发$emit函数

<!-- 原生的DOM绑定系统事件 注意:给原生DOM绑定自定义事件是没有任何意义的,因为没有办法去发$emit函数 -->
<button @click="handler">原生DOM绑定原生事件</button>
<!-- Event组件:Event1 非原生DOM节点,而绑定的click事件并非原生DOM事件,而是自定义事件,加上.native,可以把自定义事件变为原生DOM事件,当前原生DOMclick事件,其实是给子组件的根节点绑定了
点击事件---相当于事件委派 -->
<Event1 @click.native="handler1"></Event1>

二、v-model

v-model它是vue框架中的指令,它主要结合表单元素一起使用(文本框、复选框、单选按钮等等)

它主要的作用是收集表单数据

原生DOM当中是有oninput事件,它经常结合表单元素一起使用,当表单元素文本内容发生变化的时候就会触发一次回调

vue2中:可以通过value与input事件实现v-model的功能( :value是单向绑定)

//v-model方式实现数据双向绑定
<input type="text" v-model="msg">
<span>{{msg}}</span>
<br>

//原生的方式实现数据双向绑定    
//  :value是只能单向绑定
<!-- 原生DOM当中是有oninput事件,它经常结合表单元素一起使用,当表单元素文本内容发生
        变化的时候就会触发一次回调
        vue2中:可以通过value与input事件实现v-model的功能 -->
<input type="text" :value="msg" @input="msg = $event.target.value">
<span>{{msg}}</span>

 data() {
     return {
        msg:''
    }
 }

v-model实现原理:是通过value与input事件实现的,而且还需要注意可以通过v-model实现父子组件数据同步。

v-mode实现父子之间的通信如下:

// 父组件  
// 注意:  :value是props   @input是自定义事件
// 以下两行代码等同
<Inner :value="msg" @input="msg = $event"></Inner>
<Inner v-model="msg"></Inner>

//子组件
<input type="text" :value="value" @input="$emit('input',$event.target.value)">

三、属性修饰符sync

可以实现父子组件数据同步

:money.sync的含义:

1、父组件给字符串传递props (money)

2、给当前子组件绑定了一个自定义事件,而且事件名称即为update:money(update:事件名)

以下两种方式效果一样

// 父组件
<div style="height: 150px; backgroundColor: #9370db;">
    小明的爸爸现在有{{money}}元
    <h2>不使用sync修饰符</h2>
    <Child1 :money='money' @update:money="money=$event"></Child1>
    <h2>使用sync修饰符</h2>
    <!-- 
      1、父组件给字符串传递props (money)
      2、给当前子组件绑定了一个自定义事件,而且事件名称即为update:money
     -->
    <Child2 :money.sync="money"></Child2>
  </div>

//子组件 1
<div>
    <span>小明每次花100元</span>
    <button @click="$emit('update:money',money-100)">花钱</button>
    爸爸还剩 {{money}} 元
  </div>

//子组件2
<div>
    <span>小明每次花100元</span>
    <button @click="$emit('update:money',money-100)">花钱</button>
    爸爸还剩 {{money}} 元
  </div>

四、$attrs与$listeners

他们两者是组件实例的属性,可以获取到父组件给子组件传递的props与自定义事件

具体用法如下:下面案例是对elementUI中的el-button按钮的二次封装

//父组件
<template>
  <div style="height: 150px; backgroundcolor: #aeeeee">
    <h2>自定义带Hover提示的按钮</h2>
    <AttrsChild
      type="success"
      icon="el-icon-delete"
      size="mini"
      title="提示按钮"
      @click="handler"
    ></AttrsChild>
  </div>
</template>

<script>
import AttrsChild from "./AttrsChild";
export default {
  name: "Attr",
  components: {
    AttrsChild,
  },
  methods: {
    handler() {
        alert(111)
    }
  },
};
</script>


//子组件
<template>
    <div>
        <!-- 可以巧妙利用a标签实现按钮带有提示功能 -->
        <a :title="title">
            <!-- 下面这种写法,不能用 : 代替v-bind、 不能用 @ 代替v-on -->
            <el-button v-bind="$attrs" v-on="$listeners"></el-button>
        </a>
    </div> 
</template>

<script>
export default {
    props:['title'],
    mounted() {
        // $attrs属性组件的一个属性,可以获取到父组件传递过来的props数据
        // 对于子组件而言,父组件给的数据可以利用props接收,但是,如果组件通过props接收的属性,在$attrs属性当中是获取不到的
        console.log(this.$attrs)
        console.log(this.$listeners)
    }
}
</script>

五、$children与$parent

ref 可以获取到某一个组件的子组件

$children组件实例的属性 也可以获取到当前组件的全部子组件(返回的是一个数组)

$parent组件实例的属性 可以获取到当前子组件的父组件,进而可以操作父组件的数据与方法

案例如下:

父组件代码

<template>
  <div style="height: 150px; backgroundColor: #f0fff0">
    <h2>爸爸有存款:{{ money }}</h2>
    <button @click="fromM(100)">找小明借钱100</button>
    <button @click="fromH(150)">找小红借钱150</button>
    <button @click="fromAll(200)">找所有孩子借钱200</button>
    <br />
    <!-- ref:相当于原生的id,获取节点 -->
    <Son ref="xm" />
    <br />
    <Daughter ref="xh"></Daughter>
  </div>
</template>

<script>
import Son from "./Son";
import Daughter from "./Daughter";
export default {
  components: { Daughter, Son },
  data() {
    return {
        money:1000
    }
  },
  methods: {
    // 向小明借
    fromM(money) {
        this.money += money
        // console.log(this.$refs.xm.money)
        this.$refs.xm.money -= money
    },
    // 向小红
    fromH(money) {
        this.money += money
        this.$refs.xh.money -= money
    },
    // 找全部孩子借200
    fromAll(money) {
        this.money += 2*money
        console.log(this.$children)
        // 组件实例自身拥有一个属性$children,可以获取当前组件当中全部子组件
        this.$children.forEach(item => {
            item.money -= 200
        })
    }
  }
};
</script>

<style>
</style>

子组件Son

<template>
  <div>
    <h3>儿子小明有存款:{{money}}</h3>
    <button @click="giveMoney(50)">给爸爸:50</button>
  </div>
</template>

<script>
export default {
    name:'Son',
    data() {
        return {
            money:30000
        }
    },
    methods: {
        giveMoney(money) {
            this.money -= money
            // 通过$parent属性获取到某一个组件的父组件,可以操作父组件的数据与方法
            this.$parent.money += money
        }
    }
}
</script>

<style>

</style>

子组件Daughter

<template>
  <div>
    <h3>女儿小红有存款:{{ money }}</h3>
    <button @click="giveMoney(100)">给爸爸:100</button>
  </div>
</template>

<script>
//引入需要混入的文件
//import myMixin from "@/pages/Communication/ChildrenParent/myMixin/myMixin";
export default {
  name: "Daughter",
//使用
 // mixins: [myMixin],
  data() {
    return {
      money: 20000,
    };
  },
  methods: {
    giveMoney(money) {
      this.money -= money;
      this.$parent.money += money;
    },
  },
};
</script>

<style>
</style>

六、混入mixin

如果项目当中出现很多结构类似功能,要想到组件复用

如果项目当中很多的组件JS业务逻辑相似,要想到mixin。

案例:就拿上面的案例来说道说道,把相同的代码封装到一起,然后引用,引用这里我就直接在上面的案例引入了,只需要两部:

1、import myMixin from "@/pages/Communication/ChildrenParent/myMixin/myMixin";

2、mixins: [myMixin],

下面是封装好的js文件。

export default {
    methods: {
        giveMoney(money) {
          this.money -= money;
          this.$parent.money += money;
        },
      },
}

七、插槽

可以实现父子组件通信(通信的是结构),插槽有三种:

1、默认插槽

2、具名插槽

3、作用域插槽:子组件的数据来源于父组件,但是子组件决定不了自身的结构与外观

案例如下(此案例为作用域插槽,其他的后续再补充):

父组件:

<template>
  <div style="height:200px;backgroundColor:#87CEFF;">
    <h2>效果一:显示TODO列表时,已完成TODO为绿色</h2>
    <!-- 子组件:数据来源于父组件 -->
    <List :todos="todos">
        <!-- 子组件决定不了结构与外观 -->
        <template slot-scope="todo">
            <span :style="{color:todo.todo.isComplete? 'green' : 'red'}">{{todo.todo.text}}</span>
        </template>
    </List>
    <hr>
    <h2>效果二:显示TODO列表时,带序号,TODO的颜色为蓝绿搭配</h2>
    <List1 :todos="todos">
        <template slot-scope="{todo,$index}">
            <span :style="{color:todo.isComplete? 'green' : 'blue'}">{{$index}} ---  {{todo.text}}</span>
        </template>
    </List1>
  </div>
</template>

<script>
import List from './List'
import List1 from './List1'
export default {
  components: { List,List1 },
  data() {
    return {
        todos: [
            {id:1,text:'AAA',isComplete:false},
            {id:2,text:'BBB',isComplete:true},
            {id:3,text:'CCC',isComplete:false},
            {id:4,text:'DDD',isComplete:false},
        ]
    }
  }

}
</script>

<style>

</style>

子组件List:

<template>
  <div>
    <ul>
        <li v-for="(item,index) in todos" :key="index">
            <!-- 作用域插槽 -->
            <slot :todo="item"></slot>
        </li>
    </ul>
  </div>
</template>

<script>
export default {
    props: {
        todos:Array
    }
}
</script>

<style>

</style>

子组件List1:

<template>
  <div>
    <ul>
        <li v-for="(item,index) in todos" :key="index">
            <!-- 作用域插槽 -->
            <slot :todo="item" :$index='index'></slot>
        </li>
    </ul>
  </div>
</template>

<script>
export default {
    props: {
        todos:Array
    }
}
</script>

<style>

</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值