欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

vue组件通信:父与子、子与父

程序员文章站 2022-03-13 08:31:34
父子通信1.vue中提供了很棒的组件化思想,组件提高了代码的复用性。1....

1. 组件通信

1.1 组件嵌套

  • vue中提供了很棒的组件化思想,组件提高了代码的复用性。
  • 组件中可以引入其他的组件

1.2 组件嵌套步骤

  • 创建父、子组件
  • 在父组件引入子组件

1.3 父与子、子与父通信

  • vue.js中,父子组件的关系可以总结为props down ,events up
  • 父组件通过props向下传递数据给子组件,子组件通过events给父组件发送消息(后面结合代码会细说)
  • 父子通信数据传递的示意图:
    vue组件通信:父与子、子与父

1.4 实现案例图示

vue组件通信:父与子、子与父
以下内容都是通过该案例展开的。我们希望实现:

  • 在文本框输入内容后点击 + 时,下面事项列表能够更新;
  • 点击每个事项后的 ×,该事项能够删除。

2. 父组件与子组件通信

2.1 父与子通信

  • 子组件要使用父组件的数据,我们需要通过子组件的props选项。如何理解props选项呢?
    打个比喻:小孩拿着一个大布袋子问大人要糖吃,大人把糖放进了大布袋子中
    props选项就是这个“大布袋子”,父组件把数据放在子组件的props选项中,子组件内部也就有了该数据,这就是上面所说的——props down
  • 当然,子组件要使用父组件的数据,不仅仅需要通过子组件的props选项。
    在父组件的模板中,要动态的绑定父组件的数据到子组件的props,与绑定到任何普通的html特性相类似,就是用v-bind,简写就是冒号( : )。这样每当父组件的数据变化时,该变化也会传导给子组件。

2.2代码实现父与子及详细说明

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>父子通信</title>
  <script src="../js/vue.js"></script>
  <script>
    var todoAdd={
      props:["add_tasks"],
      data(){
        return{task:""}
      },
      template:`
      <div>
        <input type="text" v-model="task"><button @click="add">+</button>
      </div>`,
      methods:{
        add(){
          this.add_tasks.push(this.task);
          this.task="";
        }
      }
    }
    var todoItem={
      props:["t","i","item_tasks"],
      template:`
      <li>
        {{i+1}}-{{t}}<a href="javascript:;" @click="del">×</a>
      </li>`,
      methods:{
        del(){this.item_tasks.splice(this.i,1);}
      }
    };
    var todoList={
      props:["list_tasks"],
      template:`
      <ul>
        <todo-item v-for="(t,i) of list_tasks" :t="t" :i="i" :item_tasks="list_tasks"></todo-item>
      </ul>`,
      components:{todoItem}
    };    
    Vue.component("to-do",{
      data(){
        return{tasks:["吃饭","睡觉","打豆豆"]}
      },
      template:`
      <div>
        <h1>待办事项列表</h1>
        <todo-add :add_tasks="tasks"></todo-add>
        <todo-list :list_tasks="tasks"><todo-list>
      </div>`,    
      components:{todoAdd,todoList}
    })
  </script>
</head>
<body>
  <div id="app">
    <to-do></to-do>
  </div>
  <script>
    new Vue({
      el:"#app"
    })
  </script>
</body>
</html>

为了便于理解,用图的方式解释一下上面代码:
vue组件通信:父与子、子与父

按照上图红色标记序号详细讲一下:

为了方便理解,我们称todo为爷爷组件,todoList为父亲组件,todoItem为儿子组件

  1. 爷爷组件todo中的模板代码(template)中——:list_tasks=“tasks”,引号中的tasks就是爷爷组件的数据tasks,等号左边的list_tasks就是给到父亲组件todoList中数据的名称。用上边的比喻来解释就是,大人把这些糖叫做奶糖,小孩把这些糖叫做大白兔奶糖,虽然叫法不一样,但指的是一个东西!(也可以叫一样的名字,即 :tasks=“tasks”,但需要知道等号两边的tasks意义不同)
  2. 父亲组件todoList中——props:[“list_tasks”],这时父亲组件内部有了list_tasks这个变量。我们需要注意的是:在爷爷组件todo中tasks是一个数组,数组是引用类型,所以tasks变量中存的是一个地址,我们假设这个地址是0x1234,那么我们在父亲组件todoList中拿到的list_tasks也存着一个地址,而且这个地址也是0x1234。这也就表示,我们从爷爷组件中拿到的数据不是副本,tasks和list_tasks指向同一个地址
  3. 父亲组件todoList的模板代码中使用了list_tasks变量
  4. 儿子组件todoItem也需要使用爷爷的tasks,但是他不能问爷爷要啊,他就问他爹要啦,他爹也有啊,但名字叫做list_tasks,儿子把要过来的数据又重新起名叫做item_tasks,就可以通过v-for指令在页面生成我们想要得到的事务列表
  5. 儿子组件todoItem通过props拿到数据item_tasks,item_tasks同样指向地址0x1234
  6. 触发事件后,儿子组件todoItem调用自己的方法del,对item_tasks中的数据进行了删除。因为tasks、list_tasks和item_tasks都指向一个地址,触发事件影响的也就是爷爷组件todo中的数据。

子组件todoAdd的道理也是如此,就不重复说啦~

这里再说一下绿色标记处的代码:

  • 儿子组件todoItem要使用父亲组件todoList的 ti 变量,父亲组件中用代码——:t=“t” :i=“i” 动态的将数据绑定到儿子组件的props中,等号两边的 t 和 i 意义不同,同上面所说。

3. 子组件与父组件通信

学习了以上内容,子组件中内部的方法可以通过以上方式使用到父组件中的数据。但是上面栗子中add()方法、del()方法散落在各个子组件内部,如果有更多的子组件和方法,我们后期是难以维护的。所以,如果我们将所有的方法都放在父组件中,子组件需要使用的话则通过一定方式触发父组件内的方法。这就是子组件与父组件通信。

3.1 子与父通信

  • 父组件是使用props传递数据传递给子组件,但如果子组件要把数据传递回去,应该怎么做?那就是自定义事件!
    • 使用$on(事件名称)监听事件
    • 使用$emit(事件名称)触发时间
  • 注意,不能用$on侦听子组件抛出的事件,而必须在模板里直接使用v-on绑定(v-on简写@)
  • 父组件内:给子组件绑定一个事件
<child @事件名称="方法名称(参数)"></child>
  • 子组件内:在子组件内出发父组件指定的事件
this.$emit("事件名称")

3.2 代码实现子与父及详细说明

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>子父通信</title>
  <script src="../js/vue.js"></script>
</head>
<script>
  var todoAdd={
    template:`
    <div>
      <input type="text" v-model="task"><button @click="add">+</button>
    </div>`,
    data(){
      return{task:""}
    },
    methods:{
      add(){
        this.$emit("add",this.task);
        this.task="";
      }
    }
  }
  var todoItem={
    props:["t","i"],
    template:`
    <li>
      {{i+1}}-{{t}}<a href="javascript:;" @click="del">×</a>
    </li>`,
    methods:{
      del(){this.$emit("del");}
    } 
  };
  var todoList={
    props:["tasks"],
    template:`
      <ul>
        <todo-item @del="del(i)" v-for="(t,i) of tasks" :t="t"  :i="i"></todo-item>
      </ul>`,
    methods:{
      del(i){this.$emit("del",i);}
    },
    components:{
      todoItem
    }   
  };  
  Vue.component("to-do",{
    template:`
    <div>
      <h1>待办事项列表</h1>
      <todo-add @add="add"></todo-add>
      <todo-list @del="del" :tasks="tasks"><todo-list>
    </div>`, 
    data(){
      return{
        tasks:["吃饭","睡觉","打豆豆"]
      }
    },  
    methods:{
      add(task){
        this.tasks.push(task);
      },
      del(i){
        this.tasks.splice(i,1);
      }
    }, 
    components:{
      todoAdd,
      todoList
    }
  })
</script>
<body>
  <div id="app">
    <to-do></to-do>
  </div>
  <script>
    new Vue({
      el:"#app"
    })
  </script>
</body>
</html>

同样先用图解释一下上述代码:
vue组件通信:父与子、子与父
先看红色标记:

  1. 当点击button按钮时,子组件todoAdd触发自己的方法add()
  2. 子组件todoAdd可以使用$emit触发父组件todo的自定义事件,自定义事件名称为add,this.task是参数
  3. 父组件todo的模板代码(template)中定义了自定义事件(@add=“add”),等号左边是事件名,右边引号中是所触发的父组件中的方法名
  4. 父组件todo中的add方法被执行,页面上添加了新的事物

再看蓝色标记:
为了方便理解,我们称todo为爷爷组件,todoList为父亲组件,todoItem为儿子组件

  1. 当点击×时,儿子组件todoItem触发了自己的方法del()
  2. 儿子组件todoItem使用$emit触发父亲组件todoList的自定义事件,自定义事件名称为del
  3. 父亲组件todoList的模板代码(template)中定义了自定义事件(@del=“del(i)”),等号左边是事件名,右边引号中是所触发的父亲组件todoList中的方法名。
  4. 父亲组件todoList中的方法del(i)中有一个参数i,i为当前要删除的tasks数组中元素的下标(tasks数组在爷爷组件的data属性中),该方法同样使用$emit触发了爷爷组件todo的自定义事件,自定义事件名称为del,i为参数(注意:不是this.i)
  5. 爷爷组件todo的模板代码(template)中定义了自定义事件(@del=“del”),等号左边是事件名,右边引号中是所触发的爷爷组件中的方法名
  6. 爷爷组件todo中的del方法被执行,选中的事务将被删除

本文地址:https://blog.csdn.net/weixin_44410783/article/details/113960268