vue

Vue学习笔记(三)之Vue组件化和父子通信

Posted by weite122 on 2018-08-21
  • 本次博客介绍的是vue的组件化思想和父子组件通信,并且将沿用上次todolist例子进行阐述。

  • 首先,引入一个全局组件,代替之前的li标签

    • 效果
    • 代码:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      <!DOCTYPE html>
      <html>
      <head>
      <script src="http://vuejs.org/js/vue.js"></script>
      <meta charset="utf-8">
      <title>JS Bin</title>
      </head>
      <body>
      <div id="app">
      <input type="text" v-model="inputValue">
      <button v-on:click="handleBtnClick">submit</button>
      <ul>
      <!-- <li v-for="item in list">{{item}}</li> -->
      <todo-item v-for="item in list"></todo-item>
      </ul>
      </div>
      <script>

      Vue.component("TodoItem", {
      template: "<li>todo item</li>"
      })
      //创建一个Vue的全局组件,代替之前的<li>
      var app = new Vue({
      el: '#app',
      data: {
      list: [],
      inputValue: ''
      },
      methods: {
      handleBtnClick: function () {
      this.list.push(this.inputValue)
      this.inputValue = ''
      }
      }
      })
      </script>
      </body>
      </html>
  • 接着我们通过父子组件通信,将输入的内容传入到子组件,然后通过子组件呈现到待办列表中。

    • 效果

    • 代码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      <!DOCTYPE html>
      <html>
      <head>
      <script src="http://vuejs.org/js/vue.js"></script>
      <meta charset="utf-8">
      <title>JS Bin</title>
      </head>
      <body>
      <div id="app">
      <input type="text" v-model="inputValue">
      <button v-on:click="handleBtnClick">submit</button>
      <ul>
      <todo-item v-bind:content="item" v-for="item in list"></todo-item>
      </ul>
      </div>
      <script>
      Vue.component("TodoItem", {
      props: ['content'],
      template: "<li>{{content}}</li>"
      })
      var app = new Vue({
      el: '#app',
      data: {
      list: [],
      inputValue: ''
      },
      methods: {
      handleBtnClick: function () {
      this.list.push(this.inputValue)
      this.inputValue = ''
      }
      }
      })
      </script>
      </body>
      </html>
    • v-for="item in list"是将用户输入的每一项内容都传入到item中,v-bind:content="item"是将item的值绑定到content中,然后传入到todo-item中,那么子组件就需要一个props来接收传入的content,最后通过template插值表达式来显示内容。这就是父组件向子组件传值。

  • 上面是全局组件,现在用局部组件实现

    • 效果

    • 代码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      <!DOCTYPE html>
      <html>
      <head>
      <script src="http://vuejs.org/js/vue.js"></script>
      <meta charset="utf-8">
      <title>JS Bin</title>
      </head>
      <body>
      <div id="app">
      <input type="text" v-model="inputValue">
      <button v-on:click="handleBtnClick">submit</button>
      <ul>
      <todo-item v-bind:content="item" v-for="item in list"></todo-item>
      </ul>
      </div>
      <script>
      var TodoItem = {
      props: ['content'],
      template: "<li>{{content}}</li>"
      }
      //创建局部组件,并注册
      var app = new Vue({
      el: '#app',
      components: {
      TodoItem: TodoItem
      },
      data: {
      list: [],
      inputValue: ''
      },
      methods: {
      handleBtnClick: function () {
      this.list.push(this.inputValue)
      this.inputValue = ''
      }
      }
      })
      </script>
      </body>
      </html>
    • PS: 这里有个key值问题,之后的博客会提到这个。

  • 现在实现点击列表内容,自动删除的功能。这里就要用到父组件向子组件传值的方法。

    • 效果
    • 代码:
      <!DOCTYPE html>
      <html>
      
      <head>
          <script src="http://vuejs.org/js/vue.js"></script>
          <meta charset="utf-8">
          <title>JS Bin</title>
      </head>
      
      <body>
      <div id="app">
          <input type="text" v-model="inputValue">
          <button v-on:click="handleBtnClick">submit</button>
          <ul>
              <todo-item :content="item"
                      :index="index"
                      v-for="(item, index) in list"
                      @delete="handleItemDelete">
              </todo-item>
              <!--父组件delete会监听handleItemDelete事件。父组件将删除的列表的index通过v-bind传入到子组件-->
          </ul>
      </div>
      <script>
          var TodoItem = {
              props: ['content', 'index'],
              //子组件接收父组件的index
              template: "<li @click='handleItemClick'>{{content}}</li>",
              methods: {
                  handleItemClick: function () {
                      this.$emit("delete", this.index)
                  }
                  // 当点击子组件时,向上一层触发事件delete去监听父组件事件,并且把参数一并传入到父组件
              }
          }
          var app = new Vue({
              el: '#app',
              components: {
                  TodoItem: TodoItem
              },
              data: {
                  list: [],
                  inputValue: ''
              },
              methods: {
                  handleBtnClick: function () {
                      this.list.push(this.inputValue)
                      this.inputValue = ''
                  },
                  handleItemDelete: function (index) {
                      this.list.splice(index, 1)
                  }
                  //父组件接收子组件传入的index
              }
          })
      </script>
      </body>
      
      </html>
      
    • 子组件向父组件通信时,使用$emit方法派发一个事件和参数,通过delete监听handleItemDelete,然后父组件通过v-bind将数据传入到子组件中,子组件通过props接收数据,最后渲染到页面上。